diff --git a/.gitignore b/.gitignore index ae8de00a8b9fdb6d730f2fffac31e11ec280dd3b..b0ea5a74111595517a52bb8da1fdebf35e675e25 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ *.elf *.gcno *.gz -*.i +#*.i *.ko *.lex.c *.ll diff --git a/Makefile b/Makefile index ac0a206442c7736214f24d72229d6c59bb9e5a03..7d879aeec9adff669fff410455971d0c249ff015 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,11 @@ export LC_COLLATE LC_NUMERIC # Avoid interference with shell env settings unexport GREP_OPTIONS +IRIS_KERNEL_CONFIG = true +#ifeq ($(IRIS_KERNEL_CONFIG), true) +export CONFIG_PXLW_IRIS=y +#endif + # We are using a recursive build, so we need to do a little thinking # to get the ordering right. # @@ -480,6 +485,10 @@ export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ --exclude CVS --exclude .pc --exclude .hg --exclude .git +# We ignore *.i file for tp module when run clean cmd +export TP_FIND_IGNORE := \( -path "./drivers/input/touchscreen/focaltech_touch_n10" \) \ + -prune -o + # =========================================================================== # Rules shared between *config targets and build targets @@ -1731,7 +1740,7 @@ endif # KBUILD_EXTMOD clean: $(clean-dirs) $(call cmd,rmdirs) $(call cmd,rmfiles) - @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ + @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) $(TP_FIND_IGNORE) \ \( -name '*.[aios]' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '*.ko.*' -o -name '*.dtb' -o -name '*.dtb.S' \ -o -name '*.dwo' -o -name '*.lst' \ diff --git a/arch/arm64/configs/vendor/fp4-mini_defconfig b/arch/arm64/configs/vendor/fp4-mini_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..d2cc6c07c478c016f73c7dfecb0f700adeb26f68 --- /dev/null +++ b/arch/arm64/configs/vendor/fp4-mini_defconfig @@ -0,0 +1,738 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_FHANDLE is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_HOTPLUG_SIZE_BITS=29 +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_LITO=y +CONFIG_ARCH_LAGOON=y +CONFIG_PCI=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_SECCOMP=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +CONFIG_ARM64_SSBD=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +CONFIG_COMPAT=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_ENERGY_MODEL=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_ARM_QCOM_CPUFREQ_HW=y +CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y +CONFIG_MSM_TZ_LOG=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_PANIC_ON_REFCOUNT_ERROR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_IOSCHED_BFQ=y +CONFIG_BFQ_GROUP_IOSCHED=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y +CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_HAVE_USERSPACE_LOW_MEMORY_KILLER=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_DSCP=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_NETEM=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_BPF_JIT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_BTFM_SLIM_WCN3990=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +#CONFIG_NFC_NQ=y +CONFIG_NFC_ST21NFC=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_CACHE is not set +CONFIG_REGMAP_WCD_IRQ=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_ZRAM=y +CONFIG_ZRAM_DEDUP=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +# CONFIG_FPR_FPC is not set +CONFIG_CHIPONE_FINGERPRINT=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_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_VETH=y +CONFIG_RMNET=y +CONFIG_PHYLIB=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS_GENL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_INSPECT=y +CONFIG_TOUCHSCREEN_HIMAX_COMMON=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +# CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE=y +# CONFIG_SECURE_TOUCH_SYNAPTICS_DSX is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY is not set +# CONFIG_TOUCHSCREEN_FTS is not set +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y +CONFIG_TTY_PRINTK=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set +CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_LITO=y +CONFIG_PINCTRL_LAGOON=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_SMB5=y +CONFIG_SMB1390_CHARGE_PUMP_PSY=n +CONFIG_SMB1355_SLAVE_CHARGER=n +CONFIG_QPNP_QG=y +CONFIG_SMB1398_CHARGER=y +CONFIG_THERMAL=y +CONFIG_THERMAL_STATISTICS=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_SENSOR=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_CPU_ISOLATE_COOLING_DEVICE=y +CONFIG_QTI_LMH_CPU_VDD_COOLING_DEVICE=y +CONFIG_QTI_LIMITS_ISENSE_CDSP=y +CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QCOM_RPMH=y +CONFIG_REGULATOR_QCOM_SPMI=y +CONFIG_REGULATOR_QPNP_AMOLED=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_REGULATOR_PM8008=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_SW=y +CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y +CONFIG_DRM=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y +CONFIG_HID_PLANTRONICS=y +CONFIG_HID_SONY=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=n +CONFIG_USB_EHCI_HCD_PLATFORM=n +CONFIG_USB_OHCI_HCD=n +CONFIG_USB_OHCI_HCD_PLATFORM=n +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=n +CONFIG_USB_ISP1760_HOST_ROLE=n +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_HSUSB_PHY=n +CONFIG_USB_QCOM_EMU_PHY=n +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_TYPEC=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQHCI_CRYPTO=y +CONFIG_MMC_CQHCI_CRYPTO_QTI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_PM8XXX=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_ION_POOL_AUTO_REFILL=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_GSI_REGISTER_VERSION_2=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_USB_BAM=y +CONFIG_QCOM_GENI_SE=y +# CONFIG_QCOM_A53PLL is not set +CONFIG_QCOM_CLK_RPMH=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_SM_GCC_LITO=y +CONFIG_SM_VIDEOCC_LITO=y +CONFIG_SM_CAMCC_LITO=y +CONFIG_SM_DISPCC_LITO=y +CONFIG_SM_GPUCC_LITO=y +CONFIG_SM_NPUCC_LITO=y +CONFIG_SM_DEBUGCC_LITO=y +CONFIG_SDM_CAMCC_LAGOON=y +CONFIG_SDM_DEBUGCC_LAGOON=y +CONFIG_SDM_DISPCC_LAGOON=y +CONFIG_SDM_GPUCC_LAGOON=y +CONFIG_SDM_NPUCC_LAGOON=y +CONFIG_SDM_VIDEOCC_LAGOON=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_MEM_OFFLINE=y +CONFIG_OVERRIDE_MEMORY_LIMIT=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_IPCC=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_LITO_LLCC=y +CONFIG_QCOM_LAGOON_LLCC=y +CONFIG_QCOM_LLCC_PERFMON=m +CONFIG_QCOM_MDT_LOADER=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_QMI_RMNET=y +CONFIG_QCOM_QMI_DFC=y +CONFIG_QCOM_QMI_POWER_COLLAPSE=y +CONFIG_QCOM_RPMH=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_SMP2P=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_EUD=n +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_INITIAL_LOGBUF=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QTI_DDR_STATS_LOG=y +CONFIG_QTEE_SHM_BRIDGE=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_QCOM_CDSP_RM=y +CONFIG_QCOM_QHEE_ENABLE_MEM_PROTECTION=y +CONFIG_QCOM_CX_IPEAK=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_ARM_QCOM_DEVFREQ_FW=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_QCOM_PDC=y +CONFIG_PHY_XGENE=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y +# CONFIG_NVMEM_SYSFS is not set +CONFIG_QCOM_QFPROM=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_QCOM_KGSL=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_STATIC_USERMODEHELPER=y +CONFIG_STATIC_USERMODEHELPER_PATH="" +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_LIST=y +CONFIG_IPC_LOGGING=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_CTI_SAVE_DISABLE=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_TGU=y +#[T2MNB_BSP] audio profile for fp4 +CONFIG_SND_SMARTPA_AW882XX=y +CONFIG_T2M_SND_FP4=y +#[T2MNB_BSP] audio end +CONFIG_TCT_CHG_AUTOTEST=y +CONFIG_TCT_PM7250_COMMON=y +CONFIG_USB_PD_LOG_LVL=1 +CONFIG_BATTERY_BQ27541_HDQ=y +CONFIG_AW8695_HAPTIC=y +CONFIG_FP4_BOARD_ID=y +CONFIG_GPIO_NPI_DOWN_STATUS=y +#[Camera]ADD ST TOF +CONFIG_STMVL53L1=y +#zxz add for qnovo qns 3rd part charge algorithm service +CONFIG_BATTERY_QNOVO_CHARGE_ALGO=y +#FP4-263, mount tmpfs on /data with tmpfs in production mode, liquan.zhou.t2m, 20210624 +CONFIG_TMPFS_XATTR=y diff --git a/arch/arm64/configs/vendor/fp4-perf_defconfig b/arch/arm64/configs/vendor/fp4-perf_defconfig index ebd9b748aabbf4c945be2e4c41982796cfa750a9..55df440b173c916a2c496a5096b2755b477006c3 100644 --- a/arch/arm64/configs/vendor/fp4-perf_defconfig +++ b/arch/arm64/configs/vendor/fp4-perf_defconfig @@ -61,8 +61,6 @@ CONFIG_SETEND_EMULATION=y CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y -CONFIG_CMDLINE="cgroup_disable=pressure" -CONFIG_CMDLINE_EXTEND=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y CONFIG_COMPAT=y @@ -259,7 +257,6 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y -CONFIG_QRTR_WAKEUP_MS=500 CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y CONFIG_BPF_JIT=y @@ -270,7 +267,8 @@ CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y -CONFIG_NFC_NQ=y +#CONFIG_NFC_NQ=y +CONFIG_NFC_ST21NFC=y CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y # CONFIG_FW_CACHE is not set @@ -287,7 +285,8 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_FPR_FPC=y +# CONFIG_FPR_FPC is not set +CONFIG_CHIPONE_FINGERPRINT=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -344,10 +343,17 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y -CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y -CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y -CONFIG_TOUCHSCREEN_FTS=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_COMMON=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +# CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE=y +# CONFIG_SECURE_TOUCH_SYNAPTICS_DSX is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY is not set +# CONFIG_TOUCHSCREEN_FTS is not set CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y @@ -379,8 +385,8 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y -CONFIG_SMB1355_SLAVE_CHARGER=y +CONFIG_SMB1390_CHARGE_PUMP_PSY=n +CONFIG_SMB1355_SLAVE_CHARGER=n CONFIG_QPNP_QG=y CONFIG_SMB1398_CHARGER=y CONFIG_THERMAL=y @@ -455,22 +461,22 @@ CONFIG_HID_SONY=y CONFIG_USB_HIDDEV=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_EHCI_HCD=n +CONFIG_USB_EHCI_HCD_PLATFORM=n +CONFIG_USB_OHCI_HCD=n +CONFIG_USB_OHCI_HCD_PLATFORM=n CONFIG_USB_STORAGE=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y -CONFIG_USB_ISP1760=y -CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_ISP1760=n +CONFIG_USB_ISP1760_HOST_ROLE=n CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y CONFIG_MSM_QUSB_PHY=y -CONFIG_MSM_HSUSB_PHY=y -CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_MSM_HSUSB_PHY=n +CONFIG_USB_QCOM_EMU_PHY=n CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y @@ -593,7 +599,7 @@ CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_DCC_V2=y -CONFIG_QCOM_EUD=y +CONFIG_QCOM_EUD=n CONFIG_QCOM_MINIDUMP=y CONFIG_QCOM_FSA4480_I2C=y CONFIG_QCOM_WATCHDOG_V2=y @@ -672,6 +678,7 @@ CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y @@ -712,3 +719,21 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +#[T2MNB_BSP] audio profile for fp4 +CONFIG_SND_SMARTPA_AW882XX=y +CONFIG_T2M_SND_FP4=y +#[T2MNB_BSP] audio end +CONFIG_TCT_CHG_AUTOTEST=y +CONFIG_TCT_PM7250_COMMON=y +CONFIG_USB_PD_LOG_LVL=1 +CONFIG_BATTERY_BQ27541_HDQ=y +CONFIG_AW8695_HAPTIC=y +CONFIG_FP4_BOARD_ID=y +CONFIG_GPIO_NPI_DOWN_STATUS=y +#[Camera]ADD ST TOF +CONFIG_STMVL53L1=y +#zxz add for qnovo qns 3rd part charge algorithm service +CONFIG_BATTERY_QNOVO_CHARGE_ALGO=y +#FP4-263, mount tmpfs on /data with tmpfs in production mode, liquan.zhou.t2m, 20210624 +CONFIG_TMPFS_XATTR=y +CONFIG_NLS_UTF8=y diff --git a/arch/arm64/configs/vendor/fp4_defconfig b/arch/arm64/configs/vendor/fp4_defconfig index e45f42887e4c2ed8c4cf63df7f6fa29c52c1dfc4..93bf7738b24cc9cb5d3dd77829e09c70fd83354d 100644 --- a/arch/arm64/configs/vendor/fp4_defconfig +++ b/arch/arm64/configs/vendor/fp4_defconfig @@ -62,8 +62,6 @@ CONFIG_SETEND_EMULATION=y CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y -CONFIG_CMDLINE="cgroup_disable=pressure" -CONFIG_CMDLINE_EXTEND=y CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y CONFIG_COMPAT=y CONFIG_PM_WAKELOCKS=y @@ -265,7 +263,6 @@ CONFIG_NET_ACT_MIRRED=y CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y -CONFIG_QRTR_WAKEUP_MS=500 CONFIG_QRTR_SMD=y CONFIG_QRTR_MHI=y CONFIG_BPF_JIT=y @@ -276,7 +273,8 @@ CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y -CONFIG_NFC_NQ=y +#CONFIG_NFC_NQ=y +CONFIG_NFC_ST21NFC=y CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y # CONFIG_FW_CACHE is not set @@ -293,7 +291,8 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_FPR_FPC=y +# CONFIG_FPR_FPC is not set +CONFIG_CHIPONE_FINGERPRINT=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -351,10 +350,17 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y -CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y -CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y -CONFIG_TOUCHSCREEN_FTS=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_INSPECT=y +CONFIG_TOUCHSCREEN_HIMAX_COMMON=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +# CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE=y +# CONFIG_SECURE_TOUCH_SYNAPTICS_DSX is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY is not set +# CONFIG_TOUCHSCREEN_FTS is not set CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y @@ -387,8 +393,8 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y -CONFIG_SMB1355_SLAVE_CHARGER=y +CONFIG_SMB1390_CHARGE_PUMP_PSY=n +CONFIG_SMB1355_SLAVE_CHARGER=n CONFIG_QPNP_QG=y CONFIG_SMB1398_CHARGER=y CONFIG_THERMAL=y @@ -463,22 +469,22 @@ CONFIG_HID_SONY=y CONFIG_USB_HIDDEV=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_EHCI_HCD=n +CONFIG_USB_EHCI_HCD_PLATFORM=n +CONFIG_USB_OHCI_HCD=n +CONFIG_USB_OHCI_HCD_PLATFORM=n CONFIG_USB_STORAGE=y CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y -CONFIG_USB_ISP1760=y -CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_ISP1760=n +CONFIG_USB_ISP1760_HOST_ROLE=n CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y CONFIG_MSM_QUSB_PHY=y -CONFIG_MSM_HSUSB_PHY=y -CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_MSM_HSUSB_PHY=n +CONFIG_USB_QCOM_EMU_PHY=n CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y @@ -611,7 +617,7 @@ CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_DCC_V2=y -CONFIG_QCOM_EUD=y +CONFIG_QCOM_EUD=n CONFIG_QCOM_MINIDUMP=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_MSM_GLADIATOR_HANG_DETECT=y @@ -694,6 +700,7 @@ CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y @@ -712,7 +719,8 @@ CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_XZ_DEC=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS=y +#zxz modify for sts :android.security.sts.Poc16_11#testPocCVE_2016_6753 fail +#CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS=y CONFIG_DEBUG_MODULE_LOAD_INFO=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y @@ -779,3 +787,22 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +#[T2MNB_BSP] audio profile for fp4 +CONFIG_SND_SMARTPA_AW882XX=y +CONFIG_T2M_SND_FP4=y +#[T2MNB_BSP] audio end + +CONFIG_TCT_CHG_AUTOTEST=y +CONFIG_TCT_PM7250_COMMON=y +CONFIG_USB_PD_LOG_LVL=1 +CONFIG_BATTERY_BQ27541_HDQ=y +CONFIG_AW8695_HAPTIC=y +CONFIG_FP4_BOARD_ID=y +CONFIG_GPIO_NPI_DOWN_STATUS=y +#[Camera]ADD ST TOF +CONFIG_STMVL53L1=y +#zxz add for qnovo qns 3rd part charge algorithm service +CONFIG_BATTERY_QNOVO_CHARGE_ALGO=y +#FP4-263, mount tmpfs on /data with tmpfs in production mode, liquan.zhou.t2m, 20210624 +CONFIG_TMPFS_XATTR=y +CONFIG_NLS_UTF8=y diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 5d73ab6b62e1df385ff13733b10b6a2e1b0ba632..5b8f0154eacf7b886c05670572c1c4178b5b4f07 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -283,6 +283,7 @@ static void free_fw_priv(struct fw_priv *fw_priv) static char fw_path_para[256]; static const char * const fw_path[] = { fw_path_para, + "/vendor/firmware", "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE, @@ -329,6 +330,24 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv) break; } +#ifdef CONFIG_PXLW_IRIS + if ((!strcmp(buf->fw_id, "iris6_ccf1.fw") || !strcmp(buf->fw_id, "iris6_ccf2.fw")) && i == 1) { + snprintf(path, PATH_MAX, "%s/%s", "/system/etc", buf->fw_id); + } + + if (i == 1) { + if (!strcmp(buf->fw_id, "iris6_ccf1b.fw")) + snprintf(path, PATH_MAX, "%s/%s", "/persist/display", buf->fw_id); + + if (!strcmp(buf->fw_id, "iris6_ccf2b.fw")) + snprintf(path, PATH_MAX, "%s/%s", "/persist/display", buf->fw_id); + + if (!strcmp(buf->fw_id, "iris6_ccf3b.fw")) + snprintf(path, PATH_MAX, "%s/%s", "/persist/display", buf->fw_id); + + } + +#endif fw_priv->size = 0; rc = kernel_read_file_from_path(path, &fw_priv->data, &size, msize, id); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 20466ee72b4cb6af6b8c95a2d2fa6668b0fc4d17..9ed6df5d4cb0ae8daaebb1c0a2485700b590582f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -57,6 +57,11 @@ config DEBUG_GPIO slower. The diagnostics help catch the type of setup errors that are most common when setting up new platforms or boards. +config FP4_BOARD_ID + tristate "FP4_BOARD_ID" + help + Say Y here if you want to get the board id. + config GPIO_SYSFS bool "/sys/class/gpio/... (sysfs interface)" depends on SYSFS @@ -1388,4 +1393,11 @@ config GPIO_VIPERBOARD endmenu +config GPIO_NPI_DOWN_STATUS + bool "NPI Down status" + def_bool y + help + Say 'y' here to include debug support for the Qualcomm + QPNP gpio status. + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index c256aff66a6567e22ff8e80cfc73fffe224ac1d1..188b2d3edd06d574858601adcbbcedb3218e6f02 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -159,3 +159,5 @@ obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o obj-$(CONFIG_GPIO_ZX) += gpio-zx.o obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o +obj-$(CONFIG_FP4_BOARD_ID) += fp4-board-id.o +obj-$(CONFIG_GPIO_NPI_DOWN_STATUS) += gpio-npi-down-status.o diff --git a/drivers/gpio/fp4-board-id.c b/drivers/gpio/fp4-board-id.c new file mode 100644 index 0000000000000000000000000000000000000000..0d5eb8cd4430172731944b95d43feb37517e9c19 --- /dev/null +++ b/drivers/gpio/fp4-board-id.c @@ -0,0 +1,195 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +#include +#include +#include +#include +#include + + +static int board_id0_gpio=-1; +static int board_id1_gpio=-1; +static int board_id2_gpio=-1; +static char hw_version_status =-1; + + +static ssize_t hw_version_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + int id0=-1,id1=-1,id2=-1; + + id0=gpio_get_value(board_id0_gpio); + pr_err(" %s board_id0 return is=%d ", __func__,id0); + id1=gpio_get_value_cansleep(board_id1_gpio); + pr_err(" %s board_id1 return is=%d ", __func__,id1); + id2=gpio_get_value_cansleep(board_id2_gpio); + pr_err(" %s board_id2 return is=%d ", __func__,id2); + + hw_version_status = + (id0 << 0) | + (id1 << 1) | + (id2 << 2); + + + return sprintf(buf, "%u\n", hw_version_status); +} + + +int hw_version_get(void) +{ + int id0=-1,id1=-1,id2=-1; + int hw_version=-1; + + id0=gpio_get_value(board_id0_gpio); + pr_err("board_id0 return is=%d ", id0); + id1=gpio_get_value_cansleep(board_id1_gpio); + pr_err("board_id1 return is=%d ", id1); + id2=gpio_get_value_cansleep(board_id2_gpio); + pr_err("board_id2 return is=%d ", id2); + + hw_version =(id0 << 0) |(id1 << 1) |(id2 << 2); + pr_err("hw_version =%x", hw_version); + + return hw_version; +} + + + +static struct class_attribute board_detect_value = + __ATTR(version, 0665, hw_version_show, NULL); + + +static int board_detect_creat_file(void) +{ + int ret; + struct class *board_detect_class; + + /* board_detect create (//class/board_id) */ + board_detect_class = class_create(THIS_MODULE, "board_id"); + if (IS_ERR(board_detect_class)) { + ret = PTR_ERR(board_detect_class); + printk(KERN_ERR "board_detect_class : couldn't create info\n"); + } + if (class_create_file(board_detect_class, &board_detect_value) ) { + + printk(KERN_ERR " couldn't create version\n"); + } + pr_err("%s success \n",__func__); + + return 0; + +} + + +static int board_detect_probe (struct platform_device * pdev) +{ + + int rc = 0; + struct pinctrl *pinctrl; + struct pinctrl_state *pin_default; + + pr_err("%s start \n",__func__); + board_id0_gpio=of_get_named_gpio(pdev->dev.of_node,"qcom,board-id0-gpio", 0); + rc = gpio_request(board_id0_gpio, "qcom,board-id0-gpio"); + if (rc) { + pr_err(" board_id0_gpio request gpio=%d failed, rc=%d\n", board_id0_gpio,rc); + goto err_board_id0_gpio; + } + + board_id1_gpio=of_get_named_gpio(pdev->dev.of_node,"qcom,board-id1-gpio", 0); + rc = gpio_request(board_id1_gpio, "qcom,board-id1-gpio"); + if (rc) { + pr_err(" board_id1_gpio request gpio=%d failed, rc=%d\n", board_id1_gpio,rc); + goto err_board_id1_gpio; + } + + board_id2_gpio=of_get_named_gpio(pdev->dev.of_node,"qcom,board-id2-gpio", 0); + rc = gpio_request(board_id2_gpio, "qcom,board-id2-gpio"); + if (rc) { + pr_err(" board_id2_gpio request gpio=%d failed, rc=%d\n", board_id2_gpio,rc); + goto err_board_id2_gpio;; + } + + pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("board_detect: Failed to get pinctrl\n"); + return PTR_ERR(pinctrl); + } + pin_default = pinctrl_lookup_state(pinctrl, "default"); + if (IS_ERR_OR_NULL(pin_default)) { + pr_err("board_detect: Failed to look up default state\n"); + return PTR_ERR(pinctrl); + } + rc = pinctrl_select_state(pinctrl, pin_default); + if (rc) { + pr_err("board_detect: Can't select pinctrl state\n"); + return rc; + } + pr_err("%s---id0_gpio=%d---id1_gpio=%d---id2_gpio=%d----\n",__func__,board_id0_gpio,board_id1_gpio,board_id2_gpio); + + rc = gpio_direction_input(board_id0_gpio); + rc = gpio_direction_input(board_id1_gpio); + rc = gpio_direction_input(board_id2_gpio); + + rc=board_detect_creat_file(); + + pr_err("%s finished \n",__func__); + + return rc; + +err_board_id0_gpio: + gpio_free(board_id0_gpio); + return -ENODEV; + +err_board_id1_gpio: + gpio_free(board_id1_gpio); + return -ENODEV; + +err_board_id2_gpio: + gpio_free(board_id2_gpio); + return -ENODEV; +} + + + +static int board_detect_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct of_device_id board_match_table[] = { + { .compatible = "qcom,fp4-board-id",}, + { }, +}; + +static struct platform_driver board_detect_driver = { + .probe = board_detect_probe, + .remove = board_detect_remove, + .driver = { + .owner = THIS_MODULE, + .name = "board_id_detect", + .of_match_table = board_match_table, + }, +}; + +static int __init board_detect_driver_init(void) +{ + int err; + + pr_err("board detect init start \n"); + err = platform_driver_register(&board_detect_driver); + if (err) { + pr_err("platform_driver_register() failed! (err=%d)", err); + return err; + } + + return 0; +} + +static void __exit board_detect_driver_exit(void) +{ + platform_driver_unregister(&board_detect_driver); +} + +module_init(board_detect_driver_init); +module_exit(board_detect_driver_exit); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-npi-down-status.c b/drivers/gpio/gpio-npi-down-status.c new file mode 100644 index 0000000000000000000000000000000000000000..2b06e3d4932bf10d3e753099677ced1b26c4b01b --- /dev/null +++ b/drivers/gpio/gpio-npi-down-status.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2018 Tcl Corporation Limited */ +#include +#include +#include +#include +#include +//#include + +#define REQUEST_NPI_DOWN_GPIO 1 +//npi_down_gpio 902+69 //VDF + +/* add npi down gpio in dtsi file and use function "of_get_named_gpio" get the gpio number, can't use gpio index directly , +because in kener vision 3.10 gpio_number=base(8916 8936 8939 is 902)+gpio_index , the base value we can see in "gpio_lib.conf" file . TCTNB ZXZ add in 2014/12/13 */ + +static int npi_down_gpio; + +static char npi_down_status[4]={0}; + +struct pinctrl *pinctrl; +struct pinctrl_state *pin_default; +struct pinctrl_state *pin_suspend; + +int npi_down_status_detect(void) +{ + int status; + +/* remove gpio_request and gpio_free,GPIO69 is used by usb_otg and npi down status, +so gpio_request will fail here, we not request and get gpio status directly*/ + #if REQUEST_NPI_DOWN_GPIO + int rc = 0; + rc = gpio_request(npi_down_gpio, "npi down status"); + + if (rc) { + pr_err("npi down status request gpio=%d failed, rc=%d\n", npi_down_gpio,rc); + goto err_gpio; + } + + rc = gpio_direction_input(npi_down_gpio); + if (rc) { + pr_err("set_direction for gpio=%d failed, rc=%d\n",npi_down_gpio,rc); + goto err_gpio; + } + #endif + + status=gpio_get_value(npi_down_gpio); + + #if REQUEST_NPI_DOWN_GPIO + gpio_free(npi_down_gpio); + #endif + + if(status) + strcpy(npi_down_status,"1"); + else + strcpy(npi_down_status,"0"); + + return 0; + + + #if REQUEST_NPI_DOWN_GPIO + err_gpio: + gpio_free(npi_down_gpio); + return -ENODEV; + #endif + +} + + +static ssize_t npi_down_status_read(struct class *class, + struct class_attribute *attr, char *buf) +{ + int err; + + err = pinctrl_select_state(pinctrl, pin_default); + if (err) { + pr_err("npi_down_status: Can't select pinctrl state\n"); + return err; + } + + err=npi_down_status_detect(); + + err = pinctrl_select_state(pinctrl, pin_suspend); + if (err) { + pr_err("npi_down_status: Can't select pinctrl state\n"); + return err; + } + + if(err == -ENODEV) { + pr_err("npi down status read error!\n"); + } + return sprintf(buf, "%s\n", npi_down_status); +} + + +/* npi_down_status value attribute (//class/npi_down_status/status) */ +static struct class_attribute npi_down_status_value = + __ATTR(status, 0444, npi_down_status_read, NULL); + + +static int npi_down_status_creat_file(void) +{ + int ret; + struct class *npi_down_class; + + /* npi_down_status create (//class/npi_down_status) */ + npi_down_class = class_create(THIS_MODULE, "npi_down_status"); + if (IS_ERR(npi_down_class)) { + ret = PTR_ERR(npi_down_class); + printk(KERN_ERR "npi_down_class: couldn't create npi_down_status\n"); + } + ret = class_create_file(npi_down_class, &npi_down_status_value); + if (ret) { + printk(KERN_ERR "npi_down_status: couldn't create npi_down_status_value\n"); + } + + return 0; + +} + + +static int npi_down_status_probe(struct platform_device *pdev) +{ + int rc = 0; + + pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("npi_down_status: Failed to get pinctrl\n"); + return PTR_ERR(pinctrl); + } + pin_default = pinctrl_lookup_state(pinctrl, "default"); + if (IS_ERR_OR_NULL(pin_default)) { + pr_err("npi_down_status: Failed to look up default state\n"); + return PTR_ERR(pinctrl); + } + pin_suspend = pinctrl_lookup_state(pinctrl, "suspend"); + if (IS_ERR_OR_NULL(pin_suspend)) { + pr_err("npi_down_status: Failed to look up suspend state\n"); + return PTR_ERR(pinctrl); + } + rc = pinctrl_select_state(pinctrl, pin_default); + if (rc) { + pr_err("npi_down_status: Can't select pinctrl state\n"); + return rc; + } + + + npi_down_gpio=of_get_named_gpio(pdev->dev.of_node, + "qcom,npi-down-gpio", 0); + + rc=npi_down_status_creat_file(); + + return rc; +} + + +static int npi_down_status_remove(struct platform_device *pdev) +{ + #if REQUEST_NPI_DOWN_GPIO + gpio_free(npi_down_gpio); + #endif + + return 0; +} + + +static const struct of_device_id npi_down_dt_match[] = { + {.compatible = "qcom,npi-down-status"}, + {} +}; + +MODULE_DEVICE_TABLE(of, npi_down_dt_match); + +static struct platform_driver npi_down_status_driver = { + .probe = npi_down_status_probe, + .remove = npi_down_status_remove, + .shutdown = NULL, + .driver = { + .name = "npi_down_status", + .of_match_table = npi_down_dt_match, + }, +}; + +static int npi_down_register_driver(void) +{ + return platform_driver_register(&npi_down_status_driver); +} + + + +static int __init npi_down_status_init(void) +{ + + int ret; + + ret = npi_down_register_driver(); + if (ret) { + pr_err("npi_down_register_driver() failed!\n"); + return ret; + } + + return ret; + +} + +module_init(npi_down_status_init); + +static void __exit npi_down_status_exit(void) +{ +} +module_exit(npi_down_status_exit); + +MODULE_DESCRIPTION("Get NPI down status"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index c3f9967b4fe1a0cf47c8bc6d124281888d5470a6..0d8cb542169a3a5f361acfb5c0e8774f036faba6 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -449,8 +449,13 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, return -EINVAL; /* do some minimum sanity checking */ +#if defined(CONFIG_PXLW_IRIS) + if (!mipi_dsi_packet_format_is_short(msg->type & 0x3f) && + !mipi_dsi_packet_format_is_long(msg->type & 0x3f)) +#else if (!mipi_dsi_packet_format_is_short(msg->type) && !mipi_dsi_packet_format_is_long(msg->type)) +#endif return -EINVAL; if (msg->channel > 3) @@ -468,7 +473,11 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, * Short write packets encode up to two parameters in header bytes 1 * and 2. */ +#if defined(CONFIG_PXLW_IRIS) + if (mipi_dsi_packet_format_is_long(msg->type & 0x3f)) { +#else if (mipi_dsi_packet_format_is_long(msg->type)) { +#endif packet->header[0] = (msg->tx_len >> 0) & 0xff; packet->header[1] = (msg->tx_len >> 8) & 0xff; diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index bed6ba63c98329cb73d6c7cbb45a72962245c793..244c13ea7d9c98d10dd83b02eea290099edbad02 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -3,6 +3,7 @@ # Makefile for the i2c core. # +obj-y += i2c-check.o obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o i2c-core-objs := i2c-core-base.o i2c-core-smbus.o diff --git a/drivers/i2c/i2c-check.c b/drivers/i2c/i2c-check.c new file mode 100644 index 0000000000000000000000000000000000000000..3320f8235f91961afaffc9e0b327bd2acaa7b70f --- /dev/null +++ b/drivers/i2c/i2c-check.c @@ -0,0 +1,363 @@ +/* Copyright (C) 2017 Tcl Corporation Limited */ +/* + i2c-check.c - i2c-bus driver, char device interface + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + + +#include +#include +#include +#include +#include + +/* ------------------------------------------------------------------------- */ + +static struct class * i2c_check_class; +static struct device * i2c_dev[10]; +static int status[10]; +static int index = 0; +#define DEVICE_ATTR0(_name, _mode, _show, _store) \ + struct device_attribute dev_attr0_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR1(_name, _mode, _show, _store) \ + struct device_attribute dev_attr1_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR2(_name, _mode, _show, _store) \ + struct device_attribute dev_attr2_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR3(_name, _mode, _show, _store) \ + struct device_attribute dev_attr3_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR4(_name, _mode, _show, _store) \ + struct device_attribute dev_attr4_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR5(_name, _mode, _show, _store) \ + struct device_attribute dev_attr5_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR6(_name, _mode, _show, _store) \ + struct device_attribute dev_attr6_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR7(_name, _mode, _show, _store) \ + struct device_attribute dev_attr7_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR8(_name, _mode, _show, _store) \ + struct device_attribute dev_attr8_##_name = __ATTR(_name, _mode, _show, _store) +#define DEVICE_ATTR9(_name, _mode, _show, _store) \ + struct device_attribute dev_attr9_##_name = __ATTR(_name, _mode, _show, _store) + +static ssize_t i2c_dev0_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[0]); + return ret; +} + +static ssize_t i2c_dev0_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev1_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[1]); + return ret; +} + +static ssize_t i2c_dev1_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev2_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[2]); + return ret; +} + +static ssize_t i2c_dev2_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev3_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[3]); + return ret; +} + +static ssize_t i2c_dev3_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev4_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[4]); + return ret; +} + +static ssize_t i2c_dev4_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev5_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[5]); + return ret; +} + +static ssize_t i2c_dev5_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev6_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[6]); + return ret; +} + +static ssize_t i2c_dev6_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev7_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[7]); + return ret; +} + +static ssize_t i2c_dev7_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev8_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[8]); + return ret; +} + +static ssize_t i2c_dev8_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static ssize_t i2c_dev9_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + ret = snprintf(buf, 50, "%d\n", status[9]); + return ret; +} + +static ssize_t i2c_dev9_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t ret = -EINVAL; + unsigned long val = 0; + ret = kstrtoul(buf, 10, &val); + return size; +} + +static DEVICE_ATTR0(status, 0444, i2c_dev0_status_show, i2c_dev0_status_store); +static DEVICE_ATTR1(status, 0444, i2c_dev1_status_show, i2c_dev1_status_store); +static DEVICE_ATTR2(status, 0444, i2c_dev2_status_show, i2c_dev2_status_store); +static DEVICE_ATTR3(status, 0444, i2c_dev3_status_show, i2c_dev3_status_store); +static DEVICE_ATTR4(status, 0444, i2c_dev4_status_show, i2c_dev4_status_store); +static DEVICE_ATTR5(status, 0444, i2c_dev5_status_show, i2c_dev5_status_store); +static DEVICE_ATTR6(status, 0444, i2c_dev6_status_show, i2c_dev6_status_store); +static DEVICE_ATTR7(status, 0444, i2c_dev7_status_show, i2c_dev7_status_store); +static DEVICE_ATTR8(status, 0444, i2c_dev8_status_show, i2c_dev8_status_store); +static DEVICE_ATTR9(status, 0444, i2c_dev9_status_show, i2c_dev9_status_store); + +int i2c_check_status_create(const char *name,int value) +{ + int rc = 0; + if( name != NULL && index < 10 ){ + if(index == 0){ + i2c_dev[0] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[0])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[0], &dev_attr0_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr0_status.attr.name); + status[0] = value; + }else if(index == 1){ + i2c_dev[1] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[1])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[1], &dev_attr1_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr1_status.attr.name); + status[1] = value; + }else if(index == 2){ + i2c_dev[2] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[2])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[2], &dev_attr2_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr2_status.attr.name); + status[2] = value; + }else if(index == 3){ + i2c_dev[3] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[3])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[3], &dev_attr3_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr3_status.attr.name); + status[3] = value; + }else if(index == 4){ + i2c_dev[4] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[4])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[4], &dev_attr4_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr4_status.attr.name); + status[4] = value; + }else if(index == 5){ + i2c_dev[5] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[5])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[5], &dev_attr5_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr5_status.attr.name); + status[5] = value; + }else if(index == 6){ + i2c_dev[6] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[6])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[6], &dev_attr6_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr6_status.attr.name); + status[6] = value; + }else if(index == 7){ + i2c_dev[7] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[7])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[7], &dev_attr7_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr7_status.attr.name); + status[7] = value; + }else if(index == 8){ + i2c_dev[8] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[8])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[8], &dev_attr8_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr8_status.attr.name); + status[8] = value; + }else if(index == 9){ + i2c_dev[9] = device_create(i2c_check_class, NULL, 0, NULL, name); + if (IS_ERR(i2c_dev[9])) + pr_err("Failed to create device!\n"); + rc = device_create_file(i2c_dev[9], &dev_attr9_status); + if ( rc < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr9_status.attr.name); + status[9] = value; + } + index++; + } + return 0; +} +EXPORT_SYMBOL(i2c_check_status_create); + +void i2c_check_device_register ( void ) +{ + i2c_check_class = class_create(THIS_MODULE, "i2c_check"); + if (IS_ERR(i2c_check_class)) + pr_err("Failed to create class(i2c_check_class)!\n"); +} + +/* + * module load/unload record keeping + */ +static int __init i2c_check_init(void) +{ + //int res; + + printk(KERN_INFO "i2c_check driver\n"); + i2c_check_device_register(); + return 0; +} + +arch_initcall(i2c_check_init); + diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index 8467d0fbddf45e481def4cf1e9c8d20667a5846f..04c3107487075510376142f82db9ae419ef5146b 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -247,6 +247,78 @@ static const struct vadc_map_pt adcmap_batt_therm_100k_6125[] = { * Alium. */ static const struct vadc_map_pt adcmap_batt_therm_30k[] = { +#if defined(CONFIG_TCT_PM7250_COMMON) + {1673, -400}, + {1649, -380}, + {1623, -360}, + {1596, -340}, + {1566, -320}, + {1535, -300}, + {1502, -280}, + {1467, -260}, + {1430, -240}, + {1392, -220}, + {1352, -200}, + {1311, -180}, + {1269, -160}, + {1226, -140}, + {1182, -120}, + {1138, -100}, + {1093, -80}, + {1049, -60}, + {1004, -40}, + {960, -20}, + {917, 0}, + {874, 20}, + {832, 40}, + {791, 60}, + {752, 80}, + {713, 100}, + {676, 120}, + {640, 140}, + {606, 160}, + {573, 180}, + {541, 200}, + {511, 220}, + {483, 240}, + {455, 260}, + {430, 280}, + {405, 300}, + {382, 320}, + {360, 340}, + {340, 360}, + {320, 380}, + {302, 400}, + {285, 420}, + {269, 440}, + {253, 460}, + {239, 480}, + {225, 500}, + {213, 520}, + {201, 540}, + {190, 560}, + {179, 580}, + {169, 600}, + {160, 620}, + {152, 640}, + {143, 660}, + {136, 680}, + {128, 700}, + {122, 720}, + {115, 740}, + {109, 760}, + {104, 780}, + {98, 800}, + {93, 820}, + {89, 840}, + {84, 860}, + {80, 880}, + {76, 900}, + {73, 920}, + {69, 940}, + {66, 960}, + {63, 980} +#else {1864, -400}, {1863, -380}, {1861, -360}, @@ -317,6 +389,7 @@ static const struct vadc_map_pt adcmap_batt_therm_30k[] = { {349, 940}, {332, 960}, {315, 980} +#endif }; /* @@ -1113,6 +1186,7 @@ static int qcom_vadc_scale_hw_calib_batt_therm_30( /* (ADC code * vref_vadc (1.875V)) / full_scale_code */ voltage = (s64) adc_code * adc_vdd_ref_mv * 1000; + voltage = div64_s64(voltage, (data->full_scale_code_volt * 1000)); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 3d7ca037962d8af617ea88a9c0e8d15e03ea8802..dd1390b8abc512c2255cf4d17e65700409897935 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -885,4 +885,15 @@ config INPUT_SC27XX_VIBRA To compile this driver as a module, choose M here. The module will be called sc27xx_vibra. +config STMVL53L1 + tristate "STM VL53L3 Proximity support" + depends on I2C=y + default y + help + Say Y here if you want to use STMicroelectronics's vl53L3 TOF AF sensor + through I2C interface. + + To compile this driver as a module, choose M here: the + module will be called stmvl53l3. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index a99ea9586234e5ccd07437485e538b39527bdfdf..7d75a9aef844110589bc07d048f7b79fe46feb19 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -85,3 +85,4 @@ 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_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o +obj-$(CONFIG_STMVL53L1) += vl53L1/ diff --git a/drivers/input/misc/vl53L1/.gitignore b/drivers/input/misc/vl53L1/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e3228b19b61f366df0e2b890320f8709e127b3a4 --- /dev/null +++ b/drivers/input/misc/vl53L1/.gitignore @@ -0,0 +1 @@ +/doc_out/ diff --git a/drivers/input/misc/vl53L1/Kbuild b/drivers/input/misc/vl53L1/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..fd902663a8e31b3d6f6ba41631249677da583351 --- /dev/null +++ b/drivers/input/misc/vl53L1/Kbuild @@ -0,0 +1,49 @@ +# +# Kbuild for the vl53L1 drivers. +# + +ccflags-y += -I$(src)/inc -I$(src) + + +ccflags-y += -I$(src)/protected/inc +ccflags-y += -DVL53L1_FULL_KERNEL + + + +ccflags-y += -DVL53L3 + + +# define this environment variable if you want to compile driver for an old +# kernel +ifdef OLD_NETLINK_API +ccflags-y += -DOLD_NETLINK_API +endif + +VL53L1_LOG_ENABLE := true +ifdef VL53L1_LOG_ENABLE +ccflags-y += -DVL53L1_LOG_ENABLE +endif + +obj-$(CONFIG_STMVL53L1) += stmvl53l1.o +stmvl53l1-objs := stmvl53l1_module.o stmvl53l1_module-i2c.o + +stmvl53l1-objs += vl53l1_platform_ipp.o +stmvl53l1-objs += protected/src/vl53l1_hist_funcs.o +stmvl53l1-objs += protected/src/vl53l1_xtalk.o +stmvl53l1-objs += protected/src/vl53l1_hist_algos_gen3.o +stmvl53l1-objs += protected/src/vl53l1_hist_core.o +stmvl53l1-objs += protected/src/vl53l1_sigma_estimate.o +stmvl53l1-objs += protected/src/vl53l1_dmax.o +stmvl53l1-objs += protected/src/vl53l1_hist_algos_gen4.o + +stmvl53l1-objs += stmvl53l1_i2c.o stmvl53l1_log.o +stmvl53l1-objs += src/vl53l1_api.o src/vl53l1_api_core.o +stmvl53l1-objs += src/vl53l1_api_strings.o src/vl53l1_error_strings.o +stmvl53l1-objs += src/vl53l1_core.o src/vl53l1_register_funcs.o +stmvl53l1-objs += src/vl53l1_api_preset_modes.o +stmvl53l1-objs += src/vl53l1_api_calibration.o +stmvl53l1-objs += src/vl53l1_silicon_core.o +stmvl53l1-objs += src/vl53l1_zone_presets.o src/vl53l1_nvm.o +stmvl53l1-objs += src/vl53l1_api_debug.o src/vl53l1_core_support.o +stmvl53l1-objs += src/vl53l1_wait.o +stmvl53l1-objs += src/vl53l1_nvm_debug.o diff --git a/drivers/input/misc/vl53L1/Makefile b/drivers/input/misc/vl53L1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e95fe853c86cf33545559d216ee8c3177616524d --- /dev/null +++ b/drivers/input/misc/vl53L1/Makefile @@ -0,0 +1,12 @@ +ifneq ($(KERNELRELEASE),) +include Kbuild + +else +KDIR ?= /lib/modules/`uname -r`/build + +default: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD +clean: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD clean + +endif diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_api.h b/drivers/input/misc/vl53L1/inc/vl53l1_api.h new file mode 100644 index 0000000000000000000000000000000000000000..e61f8a73195bb422976b2b50019633fa536eb378 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_api.h @@ -0,0 +1,1447 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +#ifndef _VL53L1_API_H_ +#define _VL53L1_API_H_ + +#include "vl53l1_api_strings.h" +#include "vl53l1_api_core.h" +#include "vl53l1_preset_setup.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(VL53L1DevDataGet) +#warning "PALDevDataGet is deprecated define VL53L1DevDataGet instead" +#define VL53L1DevDataGet(Dev, field) (Dev->Data.field) +#endif + +#if !defined(VL53L1DevDataSet) +#warning "PALDevDataSet is deprecated define VL53L1DevDataSet instead" +#define VL53L1DevDataSet(Dev, field, data) ((Dev->Data.field) = (data)) +#endif + +/** @defgroup VL53L1_cut11_group VL53L1 cut1.1 Function Definition + * @brief VL53L1 cut1.1 Function Definition + * @{ + */ + +/** @defgroup VL53L1_general_group VL53L1 General Functions + * @brief General functions and definitions + * @{ + */ + +/** + * @brief Return the VL53L1 driver Version + * + * @note This function doesn't access to the device + * + * @param pVersion Rer to current driver Version + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion); + +/** + * @brief Reads the Product Revision for a for given Device + * This function can be used to distinguish cut1.0 from cut1.1. + * + * @param Dev Device Handle + * @param pProductRevisionMajor Pointer to Product Revision Major + * for a given Device + * @param pProductRevisionMinor Pointer to Product Revision Minor + * for a given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor); + +/** + * @brief Reads the Device information for given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVL53L1_DeviceInfo Pointer to current device info for a given + * Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo); + +/** + * @brief Reads the Device unique identifier + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pUid Pointer to current device unique ID + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetUID(VL53L1_DEV Dev, uint64_t *pUid); + +/** + * @brief Human readable Range Status string for a given RangeStatus + * + * @note This function doesn't access to the device + * + * @param RangeStatus The RangeStatus code as stored on + * @a VL53L1_RangingMeasurementData_t + * @param pRangeStatusString The returned RangeStatus string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Human readable error string for driver error status + * + * @note This function doesn't access to the device + * + * @param PalErrorCode The error code as stored on @a VL53L1_Error + * @param pPalErrorString The error string corresponding to the + * PalErrorCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Human readable driver State string + * + * @note This function doesn't access to the device + * + * @param PalStateCode The State code as stored on @a VL53L1_State + * @param pPalStateString The State string corresponding to the + * PalStateCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString); + +/** + * @brief Reads the internal state of the driver for a given Device + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pPalState Pointer to current state of the PAL for a + * given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, + VL53L1_State *pPalState); + + + +/** @} VL53L1_general_group */ + +/** @defgroup VL53L1_init_group VL53L1 Init Functions + * @brief VL53L1 Init Functions + * @{ + */ + +/** + * @brief Set new device address + * + * After completion the device will answer to the new address programmed. + * This function should be called when several devices are used in parallel + * before start programming the sensor. + * When a single device us used, there is no need to call this function. + * + * When it is requested for multi devices system this function MUST be called + * prior to VL53L1_DataInit() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param DeviceAddress The new Device address + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, + uint8_t DeviceAddress); + +/** + * + * @brief One time device initialization + * + * To be called after device has been powered on and booted + * see @a VL53L1_WaitDeviceBooted() + * + * @par Function Description + * When not used after a fresh device "power up", it may return + * @a #VL53L1_ERROR_CALIBRATION_WARNING meaning wrong calibration data + * may have been fetched from device that can result in ranging offset error\n + * If VL53L1_DataInit is called several times then the application must restore + * calibration calling @a VL53L1_SetOffsetCalibrationData() + * It implies application has gathered calibration data thanks to + * @a VL53L1_GetOffsetCalibrationData() after an initial calibration stage. + * This function will change the VL53L1_State from VL53L1_STATE_POWERDOWN to + * VL53L1_STATE_WAIT_STATICINIT. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev); + + +/** + * @brief Do basic device init (and eventually patch loading) + * This function will change the VL53L1_State from + * VL53L1_STATE_WAIT_STATICINIT to VL53L1_STATE_IDLE. + * In this stage all default setting will be applied. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev); + +/** + * @brief Wait for device booted after chip enable (hardware standby) + * This function can be run only when VL53L1_State is VL53L1_STATE_POWERDOWN. + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev); + + +/** @} VL53L1_init_group */ + +/** @defgroup VL53L1_parameters_group VL53L1 Parameters Functions + * @brief Functions used to prepare and setup the device + * @{ + */ + +/** + * @brief Set a new Preset Mode + * @par Function Description + * Set device to a new Operating Mode (High speed ranging, Multi objects ...) + * + * @note This function doesn't Access to the device + * + * @warning This function change the timing budget to 16 ms and the inter- + * measurement period to 1000 ms. Also the VL53L1_DISTANCEMODE_LONG is used. + * + * @param Dev Device Handle + * @param PresetMode New Preset mode to apply + *
Valid values are: + */ +/** + * @li VL53L1_PRESETMODE_MULTIZONES_SCANNING + * @li VL53L1_PRESETMODE_RANGING + * @li VL53L1_PRESETMODE_AUTONOMOUS + * @li VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * @li VL53L1_PRESETMODE_LITE_RANGING + * @li VL53L1_PRESETMODE_OLT + */ +/** + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when PresetMode is + * not in the supported list + */ +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode); + +/** + * @brief Get current Preset Mode + * @par Function Description + * Get actual mode of the device(ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pPresetMode Pointer to current apply mode value + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode is not in the supported list + */ +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode); + + +/** + * @brief Set the distance mode + * @par Function Description + * Set the distance mode to be used for the next ranging.
+ * The modes Short, Medium and Long are used to optimize the ranging accuracy + * in a specific range of distance.
The user select one of these modes to + * select the distance range.
+ * Two additional modes are supported: AUTO and AUTO_LITE the difference between + * these modes is the following.
+ * The mode AUTO take into account both the ranging distance (RangeMilliMeter) + * and the dmax distance (DmaxMilliMeter).
The algorithm uses the ranging + * distance when the range status is ok and uses the dmax distance when the + * range status is not ok.
+ * The AUTO_LITE take into account only the ranging distance, so nothing is done + * in case of range error i.e. the distance mode will not be changed. + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param DistanceMode Distance mode to apply valid values are: + * @li VL53L1_DISTANCEMODE_SHORT + * @li VL53L1_DISTANCEMODE_MEDIUM + * @li VL53L1_DISTANCEMODE_LONG + * @li VL53L1_DISTANCEMODE_AUTO_LITE + * @li VL53L1_DISTANCEMODE_AUTO + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when DistanceMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode); + +/** + * @brief Get the distance mode + * @par Function Description + * Get the distance mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pDistanceMode Pointer to Distance mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode); + + +/** + * @brief Set the output mode + * @par Function Description + * Set the output mode to be used for the next ranging. The output mode is used + * to select, in case of multiple objects, which one will be used in + * function @a VL53L1_GetRangingMeasurementData(). + * VL53L1_SetOutputMode also sets the object used by automatic + * distance mode algorithm when @a VL53L1_SetDistanceMode() is + * set to automatic mode. + * + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param OutputMode Output mode to apply valid values are: + * @li VL53L1_OUTPUTMODE_NEAREST + * @li VL53L1_OUTPUTMODE_STRONGEST + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when OutputMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode); + +/** + * @brief Get the output mode + * @par Function Description + * Get the output mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pOutputMode Pointer to Output mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode); + + +/** + * @brief Set Ranging Timing Budget in microseconds + * + * @par Function Description + * Defines the maximum time allowed by the user to the device to run a + * full ranging sequence for the current mode (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param MeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error timing parameter not + * supported. + * The maximum accepted value for the + * computed timing budget is 10 seconds + * the minimum value depends on the preset + * mode selected. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +/** + * @brief Get Ranging Timing Budget in microseconds + * + * @par Function Description + * Returns the programmed the maximum time allowed by the user to the + * device to run a full ranging sequence for the current mode + * (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + + +/** + * Program continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @param Dev Device Handle + * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms. + * this value should be greater than the duration set in + * @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() to ensure smooth ranging + * operation. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t InterMeasurementPeriodMilliSeconds); + +/** + * Get continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * + * @param Dev Device Handle + * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed + * Inter-Measurement Period in milliseconds. + * @return VL53L1_ERROR_NONE + */ +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t *pInterMeasurementPeriodMilliSeconds); + +/** + * @brief target reflectance for Dmax setting + * @par Function Description + * Allow user to set the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param DmaxReflectance Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS in case input value is not in range + * from 0 to 100. Note that this is a fix point value so the max value is + * 100 * 65536. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance); + +/** + * @brief Get target reflectance for Dmax + * @par Function Description + * Retrieves the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param pDmaxReflectance pointer to Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance); +/** + * @brief Set function for ambient Dmax mode + * + * + * @param Dev Device Handle + * @param DmaxMode DMAX mode to be used in ranging + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode); + +/** + * @brief Get function for ambient Dmax mode + * + * @param Dev Device Handle + * @param pDmaxMode output pointer to DMAX mode currently in use + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode); + +/** @} VL53L1_parameters_group */ + + +/** @defgroup VL53L1_limitcheck_group VL53L1 Limit Check Functions + * @brief Functions used for the Limit checks + * @{ + */ + + + +/** + * @brief Get the number of the check limit managed by a given Device + * + * @par Function Description + * This function give the number of the check limit managed by the Device + * + * @param pNumberOfLimitCheck Pointer to the number of check limit. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfLimitCheck( + uint16_t *pNumberOfLimitCheck); + +/** + * @brief Return a description string for a given limit check number + * + * @par Function Description + * This function returns a description string for a given limit check number. + * The limit check is identified with the LimitCheckId. + * + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckString Pointer to the description string of + * the given check limit. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString); + +/** + * @brief Return a the Status of the specified check limit + * + * @par Function Description + * This function returns the Status of the specified check limit. + * The value indicate if the check is fail or not. + * The limit check is identified with the LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckStatus Pointer to the + Limit Check Status of the given check limit. + * LimitCheckStatus : + * 0 the check is not fail or not enabled + * 1 the check if fail + * + *

    + *
  • VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: the sigma indicate the quality + * of the measure. The more it is little the better it is. + * The status is 1 when current sigma is greater then the limit.
  • + *
  • VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: the signal rate indicate + * the strength of the returned signal. The more it is big the better it is. + * The status is 1 when current signal is lower then the limit.
  • + *

+ * + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus); + +/** + * @brief Enable/Disable a specific limit check + * + * @par Function Description + * This function Enable/Disable a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckEnable + * @li set LimitCheckEnable=1 enables the LimitCheckId limit + * @li set LimitCheckEnable=0 disables the LimitCheckId limit + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable); + +/** + * @brief Get specific limit check enable state + * + * @par Function Description + * This function get the enable state of a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckEnable Pointer to the check limit enable + * value. + * @li if 1 the check limit corresponding to LimitCheckId is Enabled + * @li if 0 the check limit corresponding to LimitCheckId is disabled + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + +/** + * @brief Set a specific limit check value + * + * @par Function Description + * This function set a specific limit check value. + * The limit check is identified with the LimitCheckId. + * + * @note Note that the value written with that function will not be applied if + * the limit is not enabled. In other words this function will not enable the + * limit but change only the value. In case the limit is not enabled the value + * is saved internally and applied with VL53L1_SetLimitCheckEnable. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckValue Limit check Value for a given + * LimitCheckId + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t LimitCheckValue); + +/** + * @brief Get a specific limit check value + * + * @par Function Description + * This function get a specific limit check value from device then it updates + * internal values and check enables. + * The limit check is identified with the LimitCheckId. + * + * @note This function get the current value from device if zero then the value + * returned is the one stored by the user, but in that case the check is store + * as disabled. If the value from device is not zero, this is returned and set + * into the memory at the same way that user call VL53L1_SetLimitCheckValue() + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckValue Pointer to Limit + * check Value for a given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckValue); + +/** + * @brief Get the current value of the signal used for the limit check + * + * @par Function Description + * This function get a the current value of the signal used for the limit check. + * To obtain the latest value you should run a valid ranging before. + * The value reported is linked to the limit check identified with the + * LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckCurrent Pointer to current Value for a + * given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckCurrent); + +/** @} VL53L1_limitcheck_group */ + + + +/** @defgroup VL53L1_ROI_group VL53L1 ROI Functions + * @brief Functions used to select ROIs + * @{ + */ + +/** + * @brief Get the Maximum number of ROI Zones managed by the Device + * + * @par Function Description + * Get Maximum number of ROI Zones managed by the Device. + * + * @note The number of Zone depends on the preset mode used so to have the + * right number this function should be call after @a VL53L1_SetPresetMode() + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pMaxNumberOfROI Pointer to the Maximum Number + * of ROI Zones value. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI); +/** + * @brief Set the ROI to be used for ranging + * + * @par Function Description + * The user defined ROIs are rectangles described as per the following system + * from the Top Left corner to the Bottom Right corner. + *
Minimal ROI size is 4x4 spads + * @image html roi_coord.png + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** + * @brief Get the ROI managed by the Device + * + * @par Function Description + * Get the ROI managed by the Device + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** @} VL53L1_ROI_group */ + +/* \internal */ +/** @defgroup VL53L1_sequencestep_group VL53L1 Sequence Step Functions + * @brief Functions used to select Steps done on each ranging + * @{ + */ + +/** + * @brief Gets number of sequence steps managed by the API. + * + * @par Function Description + * This function retrieves the number of sequence steps currently managed + * by the API + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pNumberOfSequenceSteps Out parameter reporting the number of + * sequence steps. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps); + +/** + * @brief Gets the name of a given sequence step. + * + * @par Function Description + * This function retrieves the name of sequence steps corresponding to + * SequenceStepId. + * + * @note This function doesn't Accesses the device + * + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepsString Pointer to Info string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepsInfo( + VL53L1_SequenceStepId SequenceStepId, char *pSequenceStepsString); + + + +/** + * @brief Sets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function enables/disables a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param SequenceStepEnabled Demanded state {0=Off,1=On} + * is enabled. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function retrieves the state of a requested sequence step, i.e. on/off. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepEnabled Out parameter reporting if the sequence step + * is enabled {0=Off,1=On}. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled); + + +/** @} VL53L1_sequencestep_group */ +/* \endinternal */ + + + +/** @defgroup VL53L1_measurement_group VL53L1 Measurement Functions + * @brief Functions used for the measurements + * @{ + */ + +/** + * @brief Start device measurement + * + * @details Started measurement will depend on preset parameters set through + * @a VL53L1_SetPreseMode() + * This function will change the VL53L1_State from VL53L1_STATE_IDLE to + * VL53L1_STATE_RUNNING. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * PresetMode programmed with @a VL53L1_SetPresetMode + * @return VL53L1_ERROR_TIME_OUT Time out on start measurement + * @return VL53L1_ERROR_INVALID_PARAMS This error might occur in timed mode + * when inter measurement period is smaller or too close to the timing budget. + * In such case measurements are not started and user must correct the timings + * passed to @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() and + * @a VL53L1_SetInterMeasurementPeriodMilliSeconds() functions. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Stop device measurement + * + * @details Will set the device in standby mode at end of current measurement\n + * Not necessary in single mode as device shall return automatically + * in standby mode at end of measurement. + * This function will change the VL53L1_State from VL53L1_STATE_RUNNING + * to VL53L1_STATE_IDLE. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev); + +/** + * @brief Clear the Interrupt flag and start new measurement + * * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Return Measurement Data Ready + * + * @par Function Description + * This function indicate that a measurement data is ready. + * This function is used for non-blocking capture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementDataReady Pointer to Measurement Data Ready. + * 0 = data not ready, 1 = data ready + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady); + +/** + * @brief Wait for measurement data ready. + * Blocking function. + * Note that the timeout is given by: + * VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS defined in def.h + * + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_TIME_OUT In case of timeout + */ +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev); + + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + */ +/** + * @warning this function will return only the first ROI data and only the + * first object. For multi objects or multi ROI use: + * @a Vl53L1_GetMultiRangingData. + * In case of RANGING only one output is given, this can + * be selected with the help of @a VL53L1_SetOutputMode() + * In case of MULTIZONES_SCANNING and error will be raised because not + * supported in that function. + */ +/** + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED in case of MULTIZONES_SCANNING + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Retrieve all ROI's measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + * @warning USER should take care about @a VL53L1_GetNumberOfROI() + * before get data. + * Bare driver will fill a NumberOfROI times the corresponding data + * structure used in the measurement function. + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pMultiRangingData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData); + +/** + * @brief Get Additional Data + * + * @par Function Description + * This function is used to get lld debugging data on the last histogram + * measurement. shall be called when a new measurement is ready (interrupt or + * positive VL53L1_GetMeasurementDataReady() polling) and before a call to + * VL53L1_ClearInterruptAndStartMeasurement(). Depending on the PresetMode + * currently set parts of the returned data structure may be not relevant. + * + * @param Dev Device Handle + * @param pAdditionalData Pointer to Additional data + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData); + + +/** @} VL53L1_measurement_group */ + +/** @defgroup VL53L1_Calibration_group VL53L1 Calibration Functions + * @brief Functions used for Calibration + * @{ + */ + + +/** + * @brief Set Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to improve the performance of the device. It permit to + * change a particular value used for a timeout or a threshold or a constant + * in an algorithm. The function will change the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param TuningParameterValue Tuning Parameter Value + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue); + +/** + * @brief Get Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to get the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param pTuningParameterValue Pointer to Tuning Parameter Value + * for a given TuningParameterId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue); + +/** + * @brief Performs Reference Spad Management + * + * @par Function Description + * The reference SPAD initialization procedure determines the minimum amount + * of reference spads to be enables to achieve a target reference signal rate + * and should be performed once during initialization. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev); + +/** + * @brief Enable/Disable dynamic Xtalk compensation feature + * + * Enable/Disable dynamic Xtalk compensation (aka smudge correction). + * + * @param Dev Device Handle + * @param Mode Set the smudge correction mode + * See ::VL53L1_SmudgeCorrectionModes + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode); + +/** + * @brief Enable/Disable Cross talk compensation feature + * + * Enable/Disable Cross Talk correction. + * + * @param Dev Device Handle + * @param XTalkCompensationEnable Cross talk compensation + * to be set 0 = disabled or 1 = enabled. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, +uint8_t XTalkCompensationEnable); + +/** + * @brief Get Cross talk compensation rate enable + * + * Get if the Cross Talk is Enabled or Disabled. + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pXTalkCompensationEnable Pointer to the Cross talk compensation + * state 0=disabled or 1 = enabled + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable); + + +/** + * @brief Perform XTalk Calibration + * + * @details Perform a XTalk calibration of the Device. + * This function will launch a ranging measurement, if interrupts + * are enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the XTalk compensation + * and it will enable the cross talk before exit. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalibrationOption Select the Calibration to be run : + * @param CalibrationOption + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET the calibration uses current + * preset and distance mode without altering them.
+ * User must call @a VL53L1_SetPresetMode() with VL53L1_PRESETMODE_AUTONOMOUS, + * VL53L1_PRESETMODE_LITE_RANGING or VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * parameter prior to launch calibration + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. during this calibration mode no object must be put below a 80cm + * distance from the target + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. + * The ROI settings must define a single 16x16 ROI before to launch this + * function. + * The calibration uses a target which should be located at least @60cm from the + * device. The actual location of the target shall be passed + * through the bare driver tuning parameters table + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption); + +/** + * @brief Define the mode to be used for the offset calibration + * + * Define the mode to be used for the offset calibration. This function should + * be called before run the @a VL53L1_PerformOffsetCalibration() + * + * @param Dev Device Handle + * @param OffsetCalibrationMode Offset Calibration Mode valid values are: + * @li VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * @li VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + * @li VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode); + +/** + * @brief Define the mode to be used for the offset correction + * + * Define the mode to be used for the offset correction. + * + * @param Dev Device Handle + * @param OffsetCorrectionMode Offset Correction Mode valid values are: + * @li VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li VL53L1_OFFSETCORRECTIONMODE_PERZONE + * @li VL53L1_OFFSETCORRECTIONMODE_PERVCSEL + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode); + + +/** + * @brief Perform Offset Calibration + * + * @details Perform a Offset calibration of the Device. + * This function will launch a ranging measurement, if interrupts are + * enabled interrupts will be done. + * This function will program a new value for the Offset calibration value + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * @param CalReflectancePercent Calibration Target reflectance @ 940nm + * in percentage. + * + * @return VL53L1_ERROR_NONE + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, + FixPoint1616_t CalReflectancePercent); + +/** + * @brief Perform Offset simple Calibration + * + * @details Perform a very simple offset calibration of the Device. + * This function will launch few ranging measurements and computes offset + * calibration. The preset mode and the distance mode MUST be set by the + * application before to call this function. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance combined to the number of loops performed in the calibration lead to + * an internal overflow. Try to reduce the distance of the target (140 mm) + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter); + +/** + * @brief Perform Offset simple Calibration with a "zero distance" target + * + * @details Perform a simple offset calibration of the Device. + * This function will launch few ranging measurements and computes offset + * calibration. The preset mode and the distance mode MUST be set by the + * application before to call this function. + * A target must be place very close to the device. + * Ideally the target shall be touching the coverglass. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance is too large, try to put the target closer to the device + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetZeroDistanceCalibration(VL53L1_DEV Dev); + +/** + * @brief Perform Offset per Vcsel Calibration. i.e. per distance mode + * + * @details Perform offset calibration of the Device depending on the + * three distance mode settings: short, medium and long. + * This function will launch few ranging measurements and computes offset + * calibration in each of the three distance modes. + * The preset mode MUST be set by the application before to call this function. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Distance of the target used for the + * offset compensation calibration. + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance combined to the number of loops performed in the calibration lead to + * an internal overflow. Try to reduce the distance of the target (140 mm) + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetPerVcselCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter); +/** + * @brief Sets the Calibration Data. + * + * @par Function Description + * This function set all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData Pointer to Calibration data to be set. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS pCalibrationData points to an older + * version of the inner structure. Need for support to convert its content. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Gets the Calibration Data. + * + * @par Function Description + * This function get all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData pointer where to store Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Sets the Zone Calibration Data. + * + * @par Function Description + * This function set all the Zone nCalibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() in multi zone + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData Pointer to Zone Calibration data to be + * set. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); + +/** + * @brief Gets the Zone Calibration Data. + * + * @par Function Description + * This function get all the Zone Calibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData pointer where to store Zone Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); +/** + * @brief Gets the optical center. + * + * @par Function Description + * This function get the optical center issued from the nvm set at FTM stage + * expressed in the same coordinate system as the ROI are + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param pOpticalCenterX pointer to the X position of center + * in 16.16 fix point + * @param pOpticalCenterY pointer to the Y position of center + * in 16.16 fix point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY); + +/** @} VL53L1_Calibration_group */ + +/** @defgroup VL53L1_Thresholds_group VL53L1 IRQ Triggered events Functions + * @brief Functions used to configure interrupt to be triggered only when + * a measurement satisfies some thresholds parameters + * @{ + */ + +/** + * @brief Configure the interrupt config, from the given structure + * + * @param[in] Dev : Device Handle + * @param[in] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + +/** + * @brief Retrieves the interrupt config structure currently programmed + * into the API + * + * @param[in] Dev : Device Handle + * @param[out] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + + +/** @} VL53L1_Thresholds_group */ + + +/** @} VL53L1_cut11_group */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_API_H_ */ diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_api_calibration.h b/drivers/input/misc/vl53L1/inc/vl53l1_api_calibration.h new file mode 100644 index 0000000000000000000000000000000000000000..6bce3dd06994ab6ca79511f2ca44d09a6d965c6b --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_api_calibration.h @@ -0,0 +1,137 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_API_CALIBRATION_H_ +#define _VL53L1_API_CALIBRATION_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_run_ref_spad_char(VL53L1_DEV Dev, + VL53L1_Error * pcal_status); + + + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode); + + + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data); + + + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status); + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pxtalk_results, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo); + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase); + + + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_api_core.h b/drivers/input/misc/vl53L1/inc/vl53l1_api_core.h new file mode 100644 index 0000000000000000000000000000000000000000..4a90a269ec404cad12fe34bb012e2ca95880d09d --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_api_core.h @@ -0,0 +1,680 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_API_CORE_H_ +#define _VL53L1_API_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pversion); + + + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version); + + + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data); + + + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data); + + + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms); + + + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms); + + + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us); + + + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period); + + + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period); + + + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value); + + + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue); + + + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity); + + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity); + + + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps); + + + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current); + + + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi); + + + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms); + + + + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset); + + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev); + + + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev); + + + + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable); + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level); + + + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level); + + + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level, + VL53L1_range_results_t *prange_results); + + + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode); + + + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *phist_data); + + + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults); + + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg); + + + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm); + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ); + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf); + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode); + + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode); + + + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal); + + + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode); + + + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode); + + + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cor_mode); + + + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode); + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency); + + + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency); + + + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency); + + + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency); + + + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma); + + + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma); + + + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate); + + + + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate); + + + + + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma); + + + + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma); + + + + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev); + + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm); + + + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm); + + + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order); + + + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order); + + + + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value); + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value); + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound); + + + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound); + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value); + + + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ); + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ); + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + +VL53L1_Error VL53L1_load_patch(VL53L1_DEV Dev); + +VL53L1_Error VL53L1_unload_patch(VL53L1_DEV Dev); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_api_debug.h b/drivers/input/misc/vl53L1/inc/vl53l1_api_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..c3ce689c719f4de8ad13400bbe09ace849656c5a --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_api_debug.h @@ -0,0 +1,341 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_API_DEBUG_H_ +#define _VL53L1_API_DEBUG_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_nvm_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata); + + + + + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata); + + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata); + + + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata); + + + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata); + +#ifdef VL53L1_LOG_ENABLE + + + +void VL53L1_signed_fixed_point_sprintf( + int32_t fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer); + + + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_api_preset_modes.h b/drivers/input/misc/vl53L1/inc/vl53l1_api_preset_modes.h new file mode 100644 index 0000000000000000000000000000000000000000..8efc203ca308c28d6f37f3dde5c1d6368f70ce74 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_api_preset_modes.h @@ -0,0 +1,595 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_API_PRESET_MODES_H_ +#define _VL53L1_API_PRESET_MODES_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata); + + + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata); + + + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata); + + + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata); + + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata); + + + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata); + + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata); + + + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata); + + + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata); + + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata); + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic); + + + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_api_strings.h b/drivers/input/misc/vl53L1/inc/vl53l1_api_strings.h new file mode 100644 index 0000000000000000000000000000000000000000..eb9904cead675227bc0d19116e0f12628a9f8c76 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_api_strings.h @@ -0,0 +1,159 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file vl53l1_api_strings.h + * @brief VL53L1 API function declarations for decoding error codes to a + * text strings + */ + + +#ifndef VL53L1_API_STRINGS_H_ +#define VL53L1_API_STRINGS_H_ + +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * @brief Generates a string for the input device range status code + * + * @param[in] RangeStatus : Device Range AStatus Code + * @param[out] pRangeStatusString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Generates an error string for the input PAL error code + * + * @param[in] PalErrorCode : PAL Error Code + * @param[out] pPalErrorString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Generates a string for the input PAL State code + * + * @param[in] PalStateCode : PAL State Code + * @param[out] pPalStateString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString); + + +/** + * @brief Generates a string for the sequence step Id + * + * @param[in] SequenceStepId : Sequence Step Id + * @param[out] pSequenceStepsString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString); + +/** + * @brief Generates a string for the limit check Id + * + * @param[in] LimitCheckId : Limit check Id + * @param[out] pLimitCheckString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString); + +#ifndef VL53L1_USE_EMPTY_STRING + #define VL53L1_STRING_DEVICE_INFO_NAME0 "VL53L1 cut1.0" + #define VL53L1_STRING_DEVICE_INFO_NAME1 "VL53L1 cut1.1" + #define VL53L1_STRING_DEVICE_INFO_TYPE "VL53L1" + + /* Range Status */ + #define VL53L1_STRING_RANGESTATUS_NONE "No Update" + #define VL53L1_STRING_RANGESTATUS_RANGEVALID "Range Valid" + #define VL53L1_STRING_RANGESTATUS_SIGMA "Sigma Fail" + #define VL53L1_STRING_RANGESTATUS_SIGNAL "Signal Fail" + #define VL53L1_STRING_RANGESTATUS_MINRANGE "Min Range Fail" + #define VL53L1_STRING_RANGESTATUS_PHASE "Phase Fail" + #define VL53L1_STRING_RANGESTATUS_HW "Hardware Fail" + + + /* Range Status */ + #define VL53L1_STRING_STATE_POWERDOWN "POWERDOWN State" + #define VL53L1_STRING_STATE_WAIT_STATICINIT \ + "Wait for staticinit State" + #define VL53L1_STRING_STATE_STANDBY "STANDBY State" + #define VL53L1_STRING_STATE_IDLE "IDLE State" + #define VL53L1_STRING_STATE_RUNNING "RUNNING State" + #define VL53L1_STRING_STATE_RESET "RESET State" + #define VL53L1_STRING_STATE_UNKNOWN "UNKNOWN State" + #define VL53L1_STRING_STATE_ERROR "ERROR State" + + + + /* Check Enable */ + #define VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \ + "SIGMA FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \ + "SIGNAL RATE FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_MIN_CLIP \ + "SIGNAL MIN CLIP" + #define VL53L1_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \ + "RANGE IGNORE THRESHOLD" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_HIGH \ + "RANGE PHASE HIGH" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_LOW \ + "RANGE PHASE LOW" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_CONSISTENCY \ + "RANGE PHASE CONSISTENCY" + + /* Sequence Step */ + #define VL53L1_STRING_SEQUENCESTEP_VHV "VHV" + #define VL53L1_STRING_SEQUENCESTEP_PHASECAL "PHASE CAL" + #define VL53L1_STRING_SEQUENCESTEP_REFPHASE "REF PHASE" + #define VL53L1_STRING_SEQUENCESTEP_DSS1 "DSS1" + #define VL53L1_STRING_SEQUENCESTEP_DSS2 "DSS2" + #define VL53L1_STRING_SEQUENCESTEP_MM1 "MM1" + #define VL53L1_STRING_SEQUENCESTEP_MM2 "MM2" + #define VL53L1_STRING_SEQUENCESTEP_RANGE "RANGE" +#endif /* VL53L1_USE_EMPTY_STRING */ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_core.h b/drivers/input/misc/vl53L1/inc/vl53l1_core.h new file mode 100644 index 0000000000000000000000000000000000000000..dc08caae52776eeacbefea765b4b8745cc65f828 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_core.h @@ -0,0 +1,748 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_CORE_H_ +#define _VL53L1_CORE_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_core_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +void VL53L1_init_version( + VL53L1_DEV Dev); + + + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState ll_state); + + + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev); + + + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer); + + + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata); + + + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata); + + + + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev); + + + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata); + + + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer); + + + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer); + + + + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer); + + + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset); + + + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl); + + + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value); + + + + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value); + + + + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev); + + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev); + + + + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev); + + + + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev); + + + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009); + + + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult); + + + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us); + + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us); + + + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us); + + + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us); + + + + +uint16_t VL53L1_encode_timeout( + uint32_t timeout_mclks); + + + + +uint32_t VL53L1_decode_timeout( + uint16_t encoded_timeout); + + + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming); + + + + +uint8_t VL53L1_encode_vcsel_period( + uint8_t VL53L1_p_031); + + + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes); + + + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata); + + + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr); + + + + + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status); + + + + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status); + + + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr); + + + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm); + + + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm); + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta); + + + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask); + + + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number); + + + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight); + + + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size); + + + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur); + + + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col); + + + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads); + + + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads); + + + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore); + + + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output); + + + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg); + + + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults); + + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val + ); + + + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev); + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist + ); + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf); + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config); + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency); + + + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency); + + + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates); + + + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps); + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ); + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ); + + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ); + + + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ); + + + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev); + + + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev); + + +VL53L1_Error VL53L1_compute_histo_merge_nb( + VL53L1_DEV Dev, uint8_t *histo_merge_nb); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_core_support.h b/drivers/input/misc/vl53L1/inc/vl53l1_core_support.h new file mode 100644 index 0000000000000000000000000000000000000000..644c1ebc6699219d48c8e312b0703fbd404f0787 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_core_support.h @@ -0,0 +1,152 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_CORE_SUPPORT_H_ +#define _VL53L1_CORE_SUPPORT_H_ + +#include "vl53l1_types.h" +#include "vl53l1_hist_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency); + + + + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t periods_elapsed_mclks); + + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration); + + + + +uint32_t VL53L1_isqrt( + uint32_t num); + + + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata); + + + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata); + + + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency); + + + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us); + + + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value); + + + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm); + + + + +uint8_t VL53L1_decode_vcsel_period( + uint8_t vcsel_period_reg); + + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist); + + + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata); + + + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol); + + + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata); + + + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_def.h b/drivers/input/misc/vl53L1/inc/vl53l1_def.h new file mode 100644 index 0000000000000000000000000000000000000000..3431e58009f072e5424fa265afda9730d29fc24e --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_def.h @@ -0,0 +1,804 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file vl53l1_def.h + * + * @brief Type definitions for VL53L1 API. + * + */ + + +#ifndef _VL53L1_DEF_H_ +#define _VL53L1_DEF_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup VL53L1_globaldefine_group VL53L1 Defines + * @brief VL53L1 Defines + * @{ + */ + + +/** VL53L1 IMPLEMENTATION major version */ +#define VL53L1_IMPLEMENTATION_VER_MAJOR 6 +/** VL53L1 IMPLEMENTATION minor version */ +#define VL53L1_IMPLEMENTATION_VER_MINOR 6 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_SUB 4 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_REVISION 2462 + +/**************************************** + * PRIVATE define do not edit + ****************************************/ + +/** @brief Defines the parameters of the Get Version Functions + */ +typedef struct { + uint32_t revision; /*!< revision number */ + uint8_t major; /*!< major number */ + uint8_t minor; /*!< minor number */ + uint8_t build; /*!< build number */ +} VL53L1_Version_t; + + +#define VL53L1_DEVINFO_STRLEN 32 + +/** @brief Defines the parameters of the Get Device Info Functions + */ +typedef struct { + char Name[VL53L1_DEVINFO_STRLEN]; + /*!< Full Name of the Device e.g. VL53L1 cut1.1 */ + char Type[VL53L1_DEVINFO_STRLEN]; + /*!< Type of the Device e.g VL53L1 */ + char ProductId[VL53L1_DEVINFO_STRLEN]; + /*!< Product Identifier String + * @warning Not yet implemented + */ + uint8_t ProductType; + /*!< Product Type, VL53L1 = 0xCC, VL53L3 = 0xAA + * Stands as module_type in the datasheet + */ + uint8_t ProductRevisionMajor; + /*!< Product revision major */ + uint8_t ProductRevisionMinor; + /*!< Product revision minor */ +} VL53L1_DeviceInfo_t; + + + +/** @defgroup VL53L1_define_PresetModes_group Defines Preset modes + * Defines all possible preset modes for the device + * @{ + */ +typedef uint8_t VL53L1_PresetModes; + +#define VL53L1_PRESETMODE_RANGING ((VL53L1_PresetModes) 1) +#define VL53L1_PRESETMODE_MULTIZONES_SCANNING ((VL53L1_PresetModes) 2) +#define VL53L1_PRESETMODE_AUTONOMOUS ((VL53L1_PresetModes) 3) +#define VL53L1_PRESETMODE_LITE_RANGING ((VL53L1_PresetModes) 4) +#define VL53L1_PRESETMODE_OLT ((VL53L1_PresetModes) 7) +#define VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS ((VL53L1_PresetModes) 8) +#define VL53L1_PRESETMODE_PROXY_RANGING_MODE ((VL53L1_PresetModes) 9) + + /* ... Modes to be added depending on device */ +/** @} VL53L1_define_PresetModes_group */ + + +/** @defgroup VL53L1_define_DistanceModes_group Defines Distance modes + * Defines all possible Distance modes for the device + * @{ + */ +typedef uint8_t VL53L1_DistanceModes; + +#define VL53L1_DISTANCEMODE_SHORT ((VL53L1_DistanceModes) 1) +#define VL53L1_DISTANCEMODE_MEDIUM ((VL53L1_DistanceModes) 2) +#define VL53L1_DISTANCEMODE_LONG ((VL53L1_DistanceModes) 3) +/** @} VL53L1_define_DistanceModes_group */ + +/** @defgroup VL53L1_define_OutputModes_group Defines Output modes + * Defines all possible Output modes for the device + * @{ + */ +typedef uint8_t VL53L1_OutputModes; + +#define VL53L1_OUTPUTMODE_NEAREST ((VL53L1_OutputModes) 1) +#define VL53L1_OUTPUTMODE_STRONGEST ((VL53L1_OutputModes) 2) + +/** @} VL53L1_define_OutputModes_group */ + +/** @defgroup VL53L1_define_XtalkCal_group Defines Xtalk Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_XtalkCalibrationModes; + +#define VL53L1_XTALKCALIBRATIONMODE_NO_TARGET \ + ((VL53L1_OffsetCalibrationModes) 0) +/*!< To perform Xtalk calibration with no target below 80 cm */ +#define VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET \ + ((VL53L1_OffsetCalibrationModes) 1) +/*!< To perform Xtalk calibration with one target */ +#define VL53L1_XTALKCALIBRATIONMODE_FULL_ROI \ + ((VL53L1_OffsetCalibrationModes) 2) +/*!< To perform Xtalk calibration based on histogram with full ROI */ + +/** @} VL53L1_define_XtalkCal_group */ + +/** @defgroup VL53L1_define_OffsetCal_group Defines Offset Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCalibrationModes; + +#define VL53L1_OFFSETCALIBRATIONMODE_STANDARD \ + ((VL53L1_OffsetCalibrationModes) 1) +#define VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY \ + ((VL53L1_OffsetCalibrationModes) 2) +#define VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE \ + ((VL53L1_OffsetCalibrationModes) 3) + +/** @} VL53L1_define_OffsetCal_group */ + +/** @defgroup VL53L1_define_DeviceDmaxModes_group Defines Dmax source modes + * Defines all possible sources for Dmax calibration for the device + * @{ + */ +typedef uint8_t VL53L1_DeviceDmaxModes; + +#define VL53L1_DMAXMODE_FMT_CAL_DATA ((VL53L1_DeviceDmaxModes) 1) +#define VL53L1_DMAXMODE_CUSTCAL_DATA ((VL53L1_DeviceDmaxModes) 2) +#define VL53L1_DMAXMODE_PER_ZONE_CAL_DATA ((VL53L1_DeviceDmaxModes) 3) + +/** @} VL53L1_define_DeviceDmaxModes_group */ + +/** @defgroup VL53L1_define_OffsetCorrectionModesBD_group + * Device Offset Correction Mode + * + * @brief Defines all possible offset correction modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCorrectionModes; + +#define VL53L1_OFFSETCORRECTIONMODE_STANDARD ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE_PERZONE ((VL53L1_OffsetCorrectionMode) 2) +#define VL53L1_OFFSETCORRECTIONMODE_PERVCSEL ((VL53L1_OffsetCorrectionMode) 3) + +/** @} VL53L1_define_OffsetCorrectionModesBD_group */ + +/** @defgroup VL53L1_define_RoiStatus_group Defines Roi Status + * Defines the read status mode + * @{ + */ +typedef uint8_t VL53L1_RoiStatus; + +#define VL53L1_ROISTATUS_NOT_VALID ((VL53L1_RoiStatus) 0) +#define VL53L1_ROISTATUS_VALID_NOT_LAST ((VL53L1_RoiStatus) 1) +#define VL53L1_ROISTATUS_VALID_LAST ((VL53L1_RoiStatus) 2) +/** @} VL53L1_define_RoiStatus_group */ + + +/** @defgroup VL53L1_CheckEnable_group Check Enable list + * @brief Check Enable code + * + * Define used to specify the LimitCheckId. + * Use @a VL53L1_GetLimitCheckInfo() to get the string. + * @{ + */ + +#define VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE 0 +#define VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1 + +#define VL53L1_CHECKENABLE_NUMBER_OF_CHECKS 2 + +/** @} end of VL53L1_CheckEnable_group */ + + +/** @defgroup VL53L1_ThresholdMode_gropup Detection Functionality + * @brief Defines the different functionalities for the detection feature + * @{ + */ +typedef uint8_t VL53L1_ThresholdMode; + +#define VL53L1_THRESHOLD_CROSSED_LOW \ + ((VL53L1_ThresholdMode) 0) + /*!< Trigger interrupt if value < thresh_low */ +#define VL53L1_THRESHOLD_CROSSED_HIGH \ + ((VL53L1_ThresholdMode) 1) + /*!< Trigger interrupt if value > thresh_high */ +#define VL53L1_THRESHOLD_OUT_OF_WINDOW \ + ((VL53L1_ThresholdMode) 2) + /*!< Trigger interrupt if value < thresh_low OR value > thresh_high */ +#define VL53L1_THRESHOLD_IN_WINDOW \ + ((VL53L1_ThresholdMode) 3) + /*!< Trigger interrupt if value > thresh_low AND value < thresh_high */ + +/** @} end of VL53L1_ThresholdMode_gropup */ + +/** @brief Defines parameters for Distance detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + uint16_t High; /*!< Distance threshold high limit in mm */ + uint16_t Low; /*!< Distance threshold low limit in mm */ +} VL53L1_DistanceThreshold_t; + +/** @brief Defines parameters for Signal rate detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + FixPoint1616_t High; /*!< Signal rate threshold high limit */ + FixPoint1616_t Low; /*!< Signal rate threshold low limit */ +} VL53L1_RateThreshold_t; + +/** @defgroup VL53L1_DetectionMode_group Gpio Functionality + * @brief Defines conditions leading to device's IT on GPIO + * @{ + */ +typedef uint8_t VL53L1_DetectionMode; + +#define VL53L1_DETECTION_NORMAL_RUN \ + ((VL53L1_DetectionMode) 0) + /*!< Trigger interrupt on new measurement regardless of threshold + * just like after a VL53L1_SetPresetMode() call + */ +#define VL53L1_DETECTION_DISTANCE_ONLY \ + ((VL53L1_DetectionMode) 1) + /*!< Trigger interrupt if "threshold event" occurs on distance */ +#define VL53L1_DETECTION_RATE_ONLY \ + ((VL53L1_DetectionMode) 2) + /*!< Trigger interrupt if "threshold event" occurs on signal rate */ +#define VL53L1_DETECTION_DISTANCE_AND_RATE \ + ((VL53L1_DetectionMode) 3) + /*!< Trigger interrupt if "threshold event" occurs on distance AND rate + */ +#define VL53L1_DETECTION_DISTANCE_OR_RATE \ + ((VL53L1_DetectionMode) 4) + /*!< Trigger interrupt if "threshold event" occurs on distance OR rate + */ + +/** @} end of VL53L1_DetectionMode_group */ + +/** @brief Defines parameters for User/object Detection configuration + */ +typedef struct { + VL53L1_DetectionMode DetectionMode; /*!< See #VL53L1_DetectionMode*/ + uint8_t IntrNoTarget; /*!< 1 to trigger IT in case of no target found */ + VL53L1_DistanceThreshold_t Distance; /*!< limits in mm */ + VL53L1_RateThreshold_t Rate;/*!< limits in FixPoint1616_t */ +} VL53L1_DetectionConfig_t; + + +/** @brief Defines all parameters for the device + */ +typedef struct { + VL53L1_PresetModes PresetMode; + /*!< Defines the operating mode to be used for the next measure */ + VL53L1_OutputModes OutputMode; + /*!< Defines the Output mode to be used for the next measure */ + VL53L1_DistanceModes DistanceMode; + /*!< Defines the operating mode to be used for the next measure */ + uint32_t MeasurementTimingBudgetMicroSeconds; + /*!< Defines the allowed total time for a single measurement */ + uint8_t LimitChecksEnable[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check enable for this device. */ + uint8_t LimitChecksStatus[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Status of the check linked to last + * measurement. + */ + FixPoint1616_t LimitChecksValue[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check value for this device */ + FixPoint1616_t LimitChecksCurrent[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check current value from latest + * ranging + */ +} VL53L1_DeviceParameters_t; + + +/** @defgroup VL53L1_define_State_group Defines the current status of the device + * Defines the current status of the device + * @{ + */ + +typedef uint8_t VL53L1_State; + +#define VL53L1_STATE_POWERDOWN ((VL53L1_State) 0) + /*!< Device is in HW reset */ +#define VL53L1_STATE_WAIT_STATICINIT ((VL53L1_State) 1) + /*!< Device is initialized and wait for static initialization */ +#define VL53L1_STATE_STANDBY ((VL53L1_State) 2) + /*!< Device is in Low power Standby mode */ +#define VL53L1_STATE_IDLE ((VL53L1_State) 3) + /*!< Device has been initialized and ready to do measurements */ +#define VL53L1_STATE_RUNNING ((VL53L1_State) 4) + /*!< Device is performing measurement */ +#define VL53L1_STATE_RESET ((VL53L1_State) 5) + /*!< Soft reset has been run on Device */ +#define VL53L1_STATE_UNKNOWN ((VL53L1_State) 98) + /*!< Device is in unknown state and need to be rebooted */ +#define VL53L1_STATE_ERROR ((VL53L1_State) 99) + /*!< Device is in error state and need to be rebooted */ + +/** @} VL53L1_define_State_group */ + +/** @defgroup VL53L1_define_Smudge_Mode_group Defines smudge correction modes + * Defines the smudge correction modes + * @{ + */ + +typedef uint8_t VL53L1_SmudgeCorrectionModes; + +#define VL53L1_SMUDGE_CORRECTION_NONE ((VL53L1_SmudgeCorrectionModes) 0) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_CONTINUOUS ((VL53L1_SmudgeCorrectionModes) 1) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_SINGLE ((VL53L1_SmudgeCorrectionModes) 2) + /*!< Smudge correction is applied only once accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_DEBUG ((VL53L1_SmudgeCorrectionModes) 3) + /*!< Smudge detection is applied continously but Xtalk values are not + * updated automatically within the driver + */ + +/** @} VL53L1_define_Smudge_Correction_Mode_group */ + + +/** + * @struct VL53L1_RangingMeasurementData_t + * @brief Single Range measurement data. + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ +} VL53L1_RangingMeasurementData_t; + +/** + * @struct VL53L1_TargetRangeData_t + * @brief One Range measurement data for each target. + */ +typedef struct { + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + int16_t RangeMaxMilliMeter; + /*!< Tells what is the maximum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + int16_t RangeMinMilliMeter; + /*!< Tells what is the minimum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ + + uint8_t ExtendedRange; + /*!< Extended range flag for the current measurement. + * Value = 1 means timings A&B are combined to increase the + * maximum distance range. + */ +} VL53L1_TargetRangeData_t; +/** + * @struct VL53L1_MultiRangingData_t + * @brief Structure for storing the set of range results for a single ROI + * + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RoiNumber; + /*!< Denotes on which ROI the range data is related to. */ + uint8_t NumberOfObjectsFound; + /*!< Indicate the number of objects found in the current ROI. + * This is used to know how many ranging data should be get. + * NumberOfObjectsFound is in the range 0 to + * VL53L1_MAX_RANGE_RESULTS. + */ + VL53L1_RoiStatus RoiStatus; + /*!< Indicate if the data read is valid or not or if this is + * the last valid data in the ROI. + */ + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + /*!< Range data each target distance */ + uint8_t HasXtalkValueChanged; + /*!< set to 1 if a new Xtalk value has been computed whilst + * smudge correction mode enable by with + * VL53L1_SmudgeCorrectionEnable() function is either + * VL53L1_SMUDGE_CORRECTION_CONTINUOUS or + * VL53L1_SMUDGE_CORRECTION_SINGLE. + */ + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + int16_t DmaxMilliMeter; + /*!< range Dmax distance in millimeter. + */ + VL53L1_DistanceModes RecommendedDistanceMode; + /*!< suggestion for a better distance mode choice to improve + * range accuracy. + */ +} VL53L1_MultiRangingData_t; + + +/** @brief Defines User Zone(ROI) parameters + * + */ +typedef struct { + + uint8_t TopLeftX; /*!< Top Left x coordinate: 0-15 range */ + uint8_t TopLeftY; /*!< Top Left y coordinate: 0-15 range */ + uint8_t BotRightX; /*!< Bot Right x coordinate: 0-15 range */ + uint8_t BotRightY; /*!< Bot Right y coordinate: 0-15 range */ + +} VL53L1_UserRoi_t; + + +/** @brief Defines ROI configuration parameters + * + * Support up a max of 16 zones, Each Zone has the same size + * + */ +typedef struct { + + uint8_t NumberOfRoi; /*!< Number of Rois defined*/ + + VL53L1_UserRoi_t UserRois[VL53L1_MAX_USER_ZONES]; + /*!< List of Rois */ + +} VL53L1_RoiConfig_t; + +/** + * @struct VL53L1_CustomerNvmManaged_t + * + */ + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + uint8_t global_config__spad_enables_ref_1; + uint8_t global_config__spad_enables_ref_2; + uint8_t global_config__spad_enables_ref_3; + uint8_t global_config__spad_enables_ref_4; + uint8_t global_config__spad_enables_ref_5; + uint8_t global_config__ref_en_start_select; + uint8_t ref_spad_man__num_requested_ref_spads; + uint8_t ref_spad_man__ref_location; + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + uint16_t ref_spad_char__total_rate_target_mcps; + int16_t algo__part_to_part_range_offset_mm; + int16_t mm_config__inner_offset_mm; + int16_t mm_config__outer_offset_mm; +} VL53L1_CustomerNvmManaged_t; + +/** + * @struct VL53L1_CalibrationData_t + * @brief Structure for storing the Calibration Data + * + */ + +typedef struct { + + uint32_t struct_version; + VL53L1_CustomerNvmManaged_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_per_vcsel_period_offset_cal_data_t per_vcsel_cal_data; + uint32_t algo__xtalk_cpo_HistoMerge_kcps[VL53L1_BIN_REC_SIZE]; +} VL53L1_CalibrationData_t; + +#define VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION 0x20 +/** VL53L1 additional Calibration Data struct version final struct version + * is given by adding it to VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + */ + +#define VL53L1_CALIBRATION_DATA_STRUCT_VERSION \ + (VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + \ + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION) +/* VL53L1 Calibration Data struct version */ + +/** + * @struct VL53L1_AdditionalData_t + * @brief Structure for storing the Additional Data + * + */ +typedef VL53L1_additional_data_t VL53L1_AdditionalData_t; + +/** + * @struct VL53L1_ZoneCalibrationData_t + * @brief Structure for storing the Zone Calibration Data + * + */ +typedef VL53L1_zone_calibration_results_t VL53L1_ZoneCalibrationData_t; + +/** @defgroup VL53L1_define_SequenceStepId_group Defines the SequenceStep + * Defines the the sequence steps performed during ranging.. + * @{ + */ +typedef uint8_t VL53L1_SequenceStepId; + +#define VL53L1_SEQUENCESTEP_VHV ((VL53L1_SequenceStepId) 0) +/*!>12)&0xFFFF) +#define VL53L1_FIXPOINT44TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<12) + +#define VL53L1_FIXPOINT1616TOFIXPOINT72(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT72TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT97(Value) \ + (uint16_t)((Value>>9)&0xFFFF) +#define VL53L1_FIXPOINT97TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<9) + +#define VL53L1_FIXPOINT1616TOFIXPOINT88(Value) \ + (uint16_t)((Value>>8)&0xFFFF) +#define VL53L1_FIXPOINT88TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT412(Value) \ + (uint16_t)((Value>>4)&0xFFFF) +#define VL53L1_FIXPOINT412TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<4) + +#define VL53L1_FIXPOINT1616TOFIXPOINT313(Value) \ + (uint16_t)((Value>>3)&0xFFFF) +#define VL53L1_FIXPOINT313TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<3) + +#define VL53L1_FIXPOINT1616TOFIXPOINT08(Value) \ + (uint8_t)((Value>>8)&0x00FF) +#define VL53L1_FIXPOINT08TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT53(Value) \ + (uint8_t)((Value>>13)&0x00FF) +#define VL53L1_FIXPOINT53TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<13) + +#define VL53L1_FIXPOINT1616TOFIXPOINT102(Value) \ + (uint16_t)((Value>>14)&0x0FFF) +#define VL53L1_FIXPOINT102TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT142(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT142TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT160(Value) \ + (uint16_t)((Value>>16)&0xFFFF) +#define VL53L1_FIXPOINT160TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<16) + +#define VL53L1_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \ + (uint16_t)lsb) + +#ifndef SUPPRESS_UNUSED_WARNING +#define SUPPRESS_UNUSED_WARNING(x) ((void) (x)) +#endif + +/** @} VL53L1_define_GeneralMacro_group */ + +/** @} VL53L1_globaldefine_group */ + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_DEF_H_ */ diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_dmax_structs.h b/drivers/input/misc/vl53L1/inc/vl53l1_dmax_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..2e4537b3653ee2ad210c8336dafe5e83a78133bd --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_dmax_structs.h @@ -0,0 +1,92 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + + + +#ifndef _VL53L1_DMAX_STRUCTS_H_ +#define _VL53L1_DMAX_STRUCTS_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define VL53L1_MAX_AMBIENT_DMAX_VALUES 5 + + + + + +typedef struct { + + + + uint16_t ref__actual_effective_spads; + + uint16_t ref__peak_signal_count_rate_mcps; + + uint16_t ref__distance_mm; + + uint16_t ref_reflectance_pc; + + + + + uint16_t coverglass_transmission; + + +} VL53L1_dmax_calibration_data_t; + + + + +typedef struct { + + + + uint8_t signal_thresh_sigma; + + uint8_t ambient_thresh_sigma; + + int32_t min_ambient_thresh_events; + + int32_t signal_total_events_limit; + + + uint16_t target_reflectance_for_dmax_calc[ + VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + uint16_t max_effective_spads; + + + + + uint16_t dss_config__target_total_rate_mcps; + + uint8_t dss_config__aperture_attenuation; + + +} VL53L1_hist_gen3_dmax_config_t; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_error_codes.h b/drivers/input/misc/vl53L1/inc/vl53l1_error_codes.h new file mode 100644 index 0000000000000000000000000000000000000000..cf7cda97dfe7f37d6105d3030d0a8b7079dcc9d9 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_error_codes.h @@ -0,0 +1,223 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file vl53l1_error_codes.h + * + * @brief Error Code definitions for VL53L1 API. + * + */ + +#ifndef _VL53L1_ERROR_CODES_H_ +#define _VL53L1_ERROR_CODES_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + **************************************** + * PRIVATE define do not edit + *************************************** + */ + +/* + * @defgroup VL53L1_define_Error_group Error and Warning code returned by API + * The following DEFINE are used to identify the PAL ERROR + * @{ + */ + +typedef int8_t VL53L1_Error; + +#define VL53L1_ERROR_NONE ((VL53L1_Error) 0) +#define VL53L1_ERROR_CALIBRATION_WARNING ((VL53L1_Error) - 1) + /*!< Warning invalid calibration data may be in used + * \a VL53L1_InitData() + * \a VL53L1_GetOffsetCalibrationData + * \a VL53L1_SetOffsetCalibrationData + */ +#define VL53L1_ERROR_MIN_CLIPPED ((VL53L1_Error) - 2) + /*!< Warning parameter passed was clipped to min before to be applied */ + +#define VL53L1_ERROR_UNDEFINED ((VL53L1_Error) - 3) + /*!< Unqualified error */ +#define VL53L1_ERROR_INVALID_PARAMS ((VL53L1_Error) - 4) + /*!< Parameter passed is invalid or out of range */ +#define VL53L1_ERROR_NOT_SUPPORTED ((VL53L1_Error) - 5) + /*!< Function is not supported in current mode or configuration */ +#define VL53L1_ERROR_RANGE_ERROR ((VL53L1_Error) - 6) + /*!< Device report a ranging error interrupt status */ +#define VL53L1_ERROR_TIME_OUT ((VL53L1_Error) - 7) + /*!< Aborted due to time out */ +#define VL53L1_ERROR_MODE_NOT_SUPPORTED ((VL53L1_Error) - 8) + /*!< Asked mode is not supported by the device */ +#define VL53L1_ERROR_BUFFER_TOO_SMALL ((VL53L1_Error) - 9) + /*!< ... */ +#define VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL ((VL53L1_Error) - 10) + /*!< Supplied buffer is larger than I2C supports */ +#define VL53L1_ERROR_GPIO_NOT_EXISTING ((VL53L1_Error) - 11) + /*!< User tried to setup a non-existing GPIO pin */ +#define VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((VL53L1_Error) - 12) + /*!< unsupported GPIO functionality */ +#define VL53L1_ERROR_CONTROL_INTERFACE ((VL53L1_Error) - 13) + /*!< error reported from IO functions */ +#define VL53L1_ERROR_INVALID_COMMAND ((VL53L1_Error) - 14) + /*!< The command is not allowed in the current device state + * (power down) + */ +#define VL53L1_ERROR_DIVISION_BY_ZERO ((VL53L1_Error) - 15) + /*!< In the function a division by zero occurs */ +#define VL53L1_ERROR_REF_SPAD_INIT ((VL53L1_Error) - 16) + /*!< Error during reference SPAD initialization */ +#define VL53L1_ERROR_GPH_SYNC_CHECK_FAIL ((VL53L1_Error) - 17) + /*!< GPH sync interrupt check fail - API out of sync with device*/ +#define VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 18) + /*!< Stream count check fail - API out of sync with device */ +#define VL53L1_ERROR_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 19) + /*!< GPH ID check fail - API out of sync with device */ +#define VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 20) + /*!< Zone dynamic config stream count check failed - API out of sync */ +#define VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 21) + /*!< Zone dynamic config GPH ID check failed - API out of sync */ + +#define VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL ((VL53L1_Error) - 22) + /*!< Thrown when run_xtalk_extraction fn has 0 succesful samples + * when using the full array to sample the xtalk. In this case there is + * not enough information to generate new Xtalk parm info. The function + * will exit and leave the current xtalk parameters unaltered + */ +#define VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL ((VL53L1_Error) - 23) + /*!< Thrown when run_xtalk_extraction fn has found that the + * avg sigma estimate of the full array xtalk sample is > than the + * maximal limit allowed. In this case the xtalk sample is too noisy for + * measurement. The function will exit and leave the current xtalk + * parameters unaltered. + */ + + +#define VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 24) + /*!< Thrown if there one of stages has no valid offset calibration + * samples. A fatal error calibration not valid + */ +#define VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL ((VL53L1_Error) - 25) + /*!< Thrown if there one of stages has zero effective SPADS + * Traps the case when MM1 SPADs is zero. + * A fatal error calibration not valid + */ +#define VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 26) + /*!< Thrown if then some of the zones have no valid samples + * A fatal error calibration not valid + */ + +#define VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH ((VL53L1_Error) - 27) + /*!< Thrown if the tuning file key table version does not match with + * expected value. The driver expects the key table version to match + * the compiled default version number in the define + * #VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT + */ + +#define VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS ((VL53L1_Error) - 28) + /*!< Thrown if there are less than 5 good SPADs are available. */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH ((VL53L1_Error) - 29) + /*!< Thrown if the final reference rate is greater than + * the upper reference rate limit - default is 40 Mcps. + * Implies a minimum Q3 (x10) SPAD (5) selected + */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW ((VL53L1_Error) - 30) + /*!< Thrown if the final reference rate is less than + * the lower reference rate limit - default is 10 Mcps. + * Implies maximum Q1 (x1) SPADs selected + */ + + +#define VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES ((VL53L1_Error) - 31) + /*!< Thrown if there is less than the requested number of + * valid samples. + */ +#define VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 32) + /*!< Thrown if the offset calibration range sigma estimate is greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 33) + /*!< Thrown when VL53L1_run_offset_calibration() peak rate is greater + * than that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW ((VL53L1_Error) - 34) + /*!< Thrown when VL53L1_run_offset_calibration() when one of stages + * range has less that 5.0 effective SPADS. This is the recommended + * min value to yield a stable offset + */ + + +#define VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES ((VL53L1_Error) - 35) + /*!< Thrown if one of more of the zones have less than + * the requested number of valid samples + */ +#define VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 36) + /*!< Thrown if one or more zones have sigma estimate value greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 37) + /*!< Thrown if one of more zones have peak rate higher than + * that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ + + +#define VL53L1_WARNING_XTALK_MISSING_SAMPLES ((VL53L1_Error) - 38) + /*!< Thrown to notify that some of the xtalk samples did not yield + * valid ranging pulse data while attempting to measure + * the xtalk signal in vl53l1_run_xtalk_extract(). This can signify any + * of the zones are missing samples, for further debug information the + * xtalk_results struct should be referred to. This warning is for + * notification only, xtalk pulse and shape have still been generated + */ +#define VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT ((VL53L1_Error) - 39) + /*!< Thrown to notify that some of teh xtalk samples used for gradient + * generation did not yield valid ranging pulse data while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded no successful samples. + * xtalk_results struct should be referred to for further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ +#define VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT ((VL53L1_Error) - 40) + /*!< Thrown to notify that some of the xtalk samples used for gradient + * generation did not pass the sigma limit check while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded an avg sigma_mm + * value > the limit. The xtalk_results struct should be referred to for + * further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ + +#define VL53L1_ERROR_NOT_IMPLEMENTED ((VL53L1_Error) - 41) + /*!< Tells requested functionality has not been implemented yet or + * not compatible with the device + */ +#define VL53L1_ERROR_PLATFORM_SPECIFIC_START ((VL53L1_Error) - 60) + /*!< Tells the starting code for platform */ +/** @} VL53L1_define_Error_group */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_ERROR_CODES_H_ */ diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_error_exceptions.h b/drivers/input/misc/vl53L1/inc/vl53l1_error_exceptions.h new file mode 100644 index 0000000000000000000000000000000000000000..5508fa31a462b458cc551418e77ce3026d1b74b0 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_error_exceptions.h @@ -0,0 +1,40 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_ERROR_EXCEPTIONS_H_ +#define _VL53L1_ERROR_EXCEPTIONS_H_ + +#define IGNORE_DIVISION_BY_ZERO 0 + +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN 0 + +#define IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW 0 + +#define IGNORE_OFFSET_CAL_MISSING_SAMPLES 0 +#define IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_RATE_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW 0 + +#define IGNORE_ZONE_CAL_MISSING_SAMPLES 0 +#define IGNORE_ZONE_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_ZONE_CAL_RATE_TOO_HIGH 0 + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_error_strings.h b/drivers/input/misc/vl53L1/inc/vl53l1_error_strings.h new file mode 100644 index 0000000000000000000000000000000000000000..3651c429429bda4dbb0eabb86e5c1cd68ae6970c --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_error_strings.h @@ -0,0 +1,148 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#ifndef VL53L1_ERROR_STRINGS_H_ +#define VL53L1_ERROR_STRINGS_H_ + +#include "vl53l1_error_codes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + + +#ifndef VL53L1_USE_EMPTY_STRING + + + #define VL53L1_STRING_ERROR_NONE \ + "No Error" + #define VL53L1_STRING_ERROR_CALIBRATION_WARNING \ + "Calibration Warning Error" + #define VL53L1_STRING_ERROR_MIN_CLIPPED \ + "Min clipped error" + #define VL53L1_STRING_ERROR_UNDEFINED \ + "Undefined error" + #define VL53L1_STRING_ERROR_INVALID_PARAMS \ + "Invalid parameters error" + #define VL53L1_STRING_ERROR_NOT_SUPPORTED \ + "Not supported error" + #define VL53L1_STRING_ERROR_RANGE_ERROR \ + "Range error" + #define VL53L1_STRING_ERROR_TIME_OUT \ + "Time out error" + #define VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED \ + "Mode not supported error" + #define VL53L1_STRING_ERROR_BUFFER_TOO_SMALL \ + "Buffer too small" + #define VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL \ + "Comms Buffer too small" + #define VL53L1_STRING_ERROR_GPIO_NOT_EXISTING \ + "GPIO not existing" + #define VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \ + "GPIO funct not supported" + #define VL53L1_STRING_ERROR_CONTROL_INTERFACE \ + "Control Interface Error" + #define VL53L1_STRING_ERROR_INVALID_COMMAND \ + "Invalid Command Error" + #define VL53L1_STRING_ERROR_DIVISION_BY_ZERO \ + "Division by zero Error" + #define VL53L1_STRING_ERROR_REF_SPAD_INIT \ + "Reference Spad Init Error" + #define VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL \ + "GPH Sync Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL \ + "Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL \ + "GPH ID Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL \ + "Zone Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL \ + "Zone GPH ID Check Fail - API out of sync" + + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL \ + "No Xtalk using full array - Xtalk Extract Fail" + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL \ + "Xtalk does not meet required VL53L1_p_011 limit - Xtalk Extract Fail" + + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL \ + "Offset Cal - one of more stages with no valid samples - fatal" + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL \ + "Offset Cal - one of more stages with no SPADS enables - fatal" + #define VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL \ + "Zone Cal - one of more zones with no valid samples - fatal" + + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS \ + "Ref SPAD Char - Not Enough Good SPADs" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH \ + "Ref SPAD Char - Final Ref Rate too high" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW \ + "Ref SPAD Char - Final Ref Rate too low" + + #define VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES \ + "Offset Cal - Less than the requested number of valid samples" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH \ + "Offset Cal - Sigma estimate value too high - offset not stable" + #define VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH \ + "Offset Cal - Rate too high - in pile up" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW \ + "Offset Cal - Insufficient SPADs - offset may not be stable" + + #define VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES \ + "Zone Cal - One or more zone with less than requested valid samples" + #define VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH \ + "Zone Cal - One of more zones the VL53L1_p_011 estimate too high" + #define VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH \ + "Zone Cal - One of more zones with rate too high - in pile up" + + #define VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT \ + "Xtalk - Gradient sample num = 0" + #define VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT \ + "Xtalk - Gradient Sigma > Limit" + #define VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES \ + "Xtalk - Some missing and invalid samples" + + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD \ + "Device Firmware too old" + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW \ + "Device Firmware too new" + #define VL53L1_STRING_ERROR_UNIT_TEST_FAIL \ + "Unit Test Fail" + #define VL53L1_STRING_ERROR_FILE_READ_FAIL \ + "File Read Fail" + #define VL53L1_STRING_ERROR_FILE_WRITE_FAIL \ + "File Write Fail" + + #define VL53L1_STRING_ERROR_NOT_IMPLEMENTED \ + "Not implemented error" + #define VL53L1_STRING_UNKNOW_ERROR_CODE \ + "Unknown Error Code" + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_hist_char.h b/drivers/input/misc/vl53L1/inc/vl53l1_hist_char.h new file mode 100644 index 0000000000000000000000000000000000000000..04861e7945437ddb02ab48529d0191cae89864ec --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_hist_char.h @@ -0,0 +1,57 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_CHAR_H_ +#define _VL53L1_HIST_CHAR_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout); + + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay); + + + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_hist_map.h b/drivers/input/misc/vl53L1/inc/vl53l1_hist_map.h new file mode 100644 index 0000000000000000000000000000000000000000..19024b5015ce2b554bf889648028ac63bdbc5a49 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_hist_map.h @@ -0,0 +1,68 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_MAP_H_ +#define _VL53L1_HIST_MAP_H_ + +#include "vl53l1_register_map.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_0 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_1 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_2 \ + VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM + +#define VL53L1_HISTOGRAM_CONFIG__AMB_THRESH_HIGH \ + VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS + + + + +#define VL53L1_RESULT__HISTOGRAM_BIN_0_2 0x008E +#define VL53L1_RESULT__HISTOGRAM_BIN_0_1 0x008F +#define VL53L1_RESULT__HISTOGRAM_BIN_0_0 0x0090 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_2 0x00D3 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_1 0x00D4 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0 0x00D5 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB 0x00D9 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB 0x00DA + + + +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES \ + (VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - \ + VL53L1_RESULT__INTERRUPT_STATUS + 1) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_hist_structs.h b/drivers/input/misc/vl53L1/inc/vl53l1_hist_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..3df3e8c7bd129753bc356c1768d754c94e726cd1 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_hist_structs.h @@ -0,0 +1,299 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_STRUCTS_H_ +#define _VL53L1_HIST_STRUCTS_H_ + +#include "vl53l1_ll_device.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_MAX_BIN_SEQUENCE_LENGTH 6 +#define VL53L1_MAX_BIN_SEQUENCE_CODE 15 +#define VL53L1_HISTOGRAM_BUFFER_SIZE 24 +#define VL53L1_XTALK_HISTO_BINS 12 + + + +typedef struct { + + uint8_t histogram_config__spad_array_selection; + + uint8_t histogram_config__low_amb_even_bin_0_1; + uint8_t histogram_config__low_amb_even_bin_2_3; + uint8_t histogram_config__low_amb_even_bin_4_5; + + uint8_t histogram_config__low_amb_odd_bin_0_1; + uint8_t histogram_config__low_amb_odd_bin_2_3; + uint8_t histogram_config__low_amb_odd_bin_4_5; + + uint8_t histogram_config__mid_amb_even_bin_0_1; + uint8_t histogram_config__mid_amb_even_bin_2_3; + uint8_t histogram_config__mid_amb_even_bin_4_5; + + uint8_t histogram_config__mid_amb_odd_bin_0_1; + uint8_t histogram_config__mid_amb_odd_bin_2; + uint8_t histogram_config__mid_amb_odd_bin_3_4; + uint8_t histogram_config__mid_amb_odd_bin_5; + + uint8_t histogram_config__user_bin_offset; + + uint8_t histogram_config__high_amb_even_bin_0_1; + uint8_t histogram_config__high_amb_even_bin_2_3; + uint8_t histogram_config__high_amb_even_bin_4_5; + + uint8_t histogram_config__high_amb_odd_bin_0_1; + uint8_t histogram_config__high_amb_odd_bin_2_3; + uint8_t histogram_config__high_amb_odd_bin_4_5; + + uint16_t histogram_config__amb_thresh_low; + + uint16_t histogram_config__amb_thresh_high; + + +} VL53L1_histogram_config_t; + + + + +typedef struct { + + VL53L1_HistAlgoSelect hist_algo_select; + + + VL53L1_HistTargetOrder hist_target_order; + + + uint8_t filter_woi0; + + uint8_t filter_woi1; + + + VL53L1_HistAmbEstMethod hist_amb_est_method; + + uint8_t ambient_thresh_sigma0; + + uint8_t ambient_thresh_sigma1; + + + + uint16_t ambient_thresh_events_scaler; + + + + int32_t min_ambient_thresh_events; + + uint16_t noise_threshold; + + + int32_t signal_total_events_limit; + + uint8_t sigma_estimator__sigma_ref_mm; + + uint16_t sigma_thresh; + + int16_t range_offset_mm; + + uint16_t gain_factor; + + + uint8_t valid_phase_low; + + uint8_t valid_phase_high; + + uint8_t algo__consistency_check__phase_tolerance; + + uint8_t algo__consistency_check__event_sigma; + + + + uint16_t algo__consistency_check__event_min_spad_count; + + + + uint16_t algo__consistency_check__min_max_tolerance; + + + uint8_t algo__crosstalk_compensation_enable; + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + + uint8_t algo__crosstalk_detect_event_sigma; + + + + uint16_t algo__crosstalk_detect_min_max_tolerance; + + +} VL53L1_hist_post_process_config_t; + + + +typedef struct { + + + VL53L1_DeviceState cfg_device_state; + + VL53L1_DeviceState rd_device_state; + + + uint8_t zone_id; + + uint32_t time_stamp; + + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_023; + + uint8_t VL53L1_p_024; + + uint8_t number_of_ambient_bins; + + uint8_t bin_seq[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + uint8_t bin_rep[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + int32_t bin_data[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + uint8_t result__interrupt_status; + + uint8_t result__range_status; + + uint8_t result__report_status; + + uint8_t result__stream_count; + + uint16_t result__dss_actual_effective_spads; + + + uint16_t phasecal_result__reference_phase; + + uint8_t phasecal_result__vcsel_start; + + uint8_t cal_config__vcsel_start; + + uint16_t vcsel_width; + + uint8_t VL53L1_p_009; + + uint16_t VL53L1_p_019; + + uint32_t total_periods_elapsed; + + + uint32_t peak_duration_us; + + uint32_t woi_duration_us; + + + int32_t min_bin_value; + + int32_t max_bin_value; + + + uint16_t zero_distance_phase; + + uint8_t number_of_ambient_samples; + + int32_t ambient_events_sum; + + int32_t VL53L1_p_004; + + + uint8_t roi_config__user_roi_centre_spad; + + uint8_t roi_config__user_roi_requested_global_xy_size; + + +} VL53L1_histogram_bin_data_t; + + + + +typedef struct { + + + uint8_t zone_id; + + uint32_t time_stamp; + + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_023; + + uint8_t VL53L1_p_024; + + uint32_t bin_data[VL53L1_XTALK_HISTO_BINS]; + + + + uint16_t phasecal_result__reference_phase; + + uint8_t phasecal_result__vcsel_start; + + uint8_t cal_config__vcsel_start; + + uint16_t vcsel_width; + + uint16_t VL53L1_p_019; + + uint16_t zero_distance_phase; + + +} VL53L1_xtalk_histogram_shape_t; + + + + +typedef struct { + + + VL53L1_xtalk_histogram_shape_t xtalk_shape; + + VL53L1_histogram_bin_data_t xtalk_hist_removed; + +} VL53L1_xtalk_histogram_data_t; + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_ll_def.h b/drivers/input/misc/vl53L1/inc/vl53l1_ll_def.h new file mode 100644 index 0000000000000000000000000000000000000000..3ced6c02ec3562bdf7b6759c8e7d957c1bdb0e9d --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_ll_def.h @@ -0,0 +1,1754 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_LL_DEF_H_ +#define _VL53L1_LL_DEF_H_ + +#include "vl53l1_error_codes.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_platform_user_config.h" +#include "vl53l1_platform_user_defines.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_dmax_structs.h" +#include "vl53l1_error_exceptions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR 1 + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MINOR 1 + +#define VL53L1_LL_API_IMPLEMENTATION_VER_SUB 48 + +#define VL53L1_LL_API_IMPLEMENTATION_VER_REVISION 12224 + +#define VL53L1_LL_API_IMPLEMENTATION_VER_STRING "1.1.48.12224" + + +#define VL53L1_FIRMWARE_VER_MINIMUM 398 +#define VL53L1_FIRMWARE_VER_MAXIMUM 400 + + + + +#define VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION 0xECAB0102 + + + + +#define VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION 0xECAE0101 + + + + + +#define VL53L1_BIN_REC_SIZE 6 + +#define VL53L1_TIMING_CONF_A_B_SIZE 2 + +#define VL53L1_FRAME_WAIT_EVENT 6 + + + +#define VL53L1_MAX_XTALK_RANGE_RESULTS 5 + + +#define VL53L1_MAX_OFFSET_RANGE_RESULTS 3 + + +#define VL53L1_NVM_MAX_FMT_RANGE_DATA 4 + + +#define VL53L1_NVM_PEAK_RATE_MAP_SAMPLES 25 + +#define VL53L1_NVM_PEAK_RATE_MAP_WIDTH 5 + +#define VL53L1_NVM_PEAK_RATE_MAP_HEIGHT 5 + + + + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD ((VL53L1_Error) - 80) + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW ((VL53L1_Error) - 85) + +#define VL53L1_ERROR_UNIT_TEST_FAIL ((VL53L1_Error) - 90) + +#define VL53L1_ERROR_FILE_READ_FAIL ((VL53L1_Error) - 95) + +#define VL53L1_ERROR_FILE_WRITE_FAIL ((VL53L1_Error) - 96) + + + + + + +typedef struct { + uint32_t ll_revision; + uint8_t ll_major; + uint8_t ll_minor; + uint8_t ll_build; +} VL53L1_ll_version_t; + + + + +typedef struct { + + uint8_t device_test_mode; + uint8_t VL53L1_p_009; + uint32_t timeout_us; + uint16_t target_count_rate_mcps; + + uint16_t min_count_rate_limit_mcps; + + uint16_t max_count_rate_limit_mcps; + + +} VL53L1_refspadchar_config_t; + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + uint32_t phasecal_config_timeout_us; + + uint32_t mm_config_timeout_us; + + uint32_t range_config_timeout_us; + + uint8_t num_of_samples; + + int16_t algo__crosstalk_extract_min_valid_range_mm; + + int16_t algo__crosstalk_extract_max_valid_range_mm; + + uint16_t algo__crosstalk_extract_max_valid_rate_kcps; + + uint16_t algo__crosstalk_extract_max_sigma_mm; + + +} VL53L1_xtalkextract_config_t; + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + uint32_t phasecal_config_timeout_us; + + uint32_t range_config_timeout_us; + + uint32_t mm_config_timeout_us; + + uint8_t pre_num_of_samples; + + uint8_t mm1_num_of_samples; + + uint8_t mm2_num_of_samples; + + +} VL53L1_offsetcal_config_t; + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + uint32_t phasecal_config_timeout_us; + + uint32_t mm_config_timeout_us; + + uint32_t range_config_timeout_us; + + uint16_t phasecal_num_of_samples; + + uint16_t zone_num_of_samples; + + +} VL53L1_zonecal_config_t; + + + + + +typedef struct { + + VL53L1_DeviceSscArray array_select; + + uint8_t VL53L1_p_009; + + uint8_t vcsel_start; + + uint8_t vcsel_width; + + uint32_t timeout_us; + + uint16_t rate_limit_mcps; + + +} VL53L1_ssc_config_t; + + + + +typedef struct { + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + uint32_t nvm_default__crosstalk_compensation_plane_offset_kcps; + + int16_t nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + int16_t nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + uint8_t global_crosstalk_compensation_enable; + + int16_t histogram_mode_crosstalk_margin_kcps; + + int16_t lite_mode_crosstalk_margin_kcps; + + uint8_t crosstalk_range_ignore_threshold_mult; + + uint16_t crosstalk_range_ignore_threshold_rate_mcps; + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + +} VL53L1_xtalk_config_t; + + + + +typedef struct { + + + uint16_t tp_tuning_parm_version; + + uint16_t tp_tuning_parm_key_table_version; + + uint16_t tp_tuning_parm_lld_version; + + uint8_t tp_init_phase_rtn_lite_long; + + uint8_t tp_init_phase_rtn_lite_med; + + uint8_t tp_init_phase_rtn_lite_short; + + uint8_t tp_init_phase_ref_lite_long; + + uint8_t tp_init_phase_ref_lite_med; + + uint8_t tp_init_phase_ref_lite_short; + + + uint8_t tp_init_phase_rtn_hist_long; + + uint8_t tp_init_phase_rtn_hist_med; + + uint8_t tp_init_phase_rtn_hist_short; + + uint8_t tp_init_phase_ref_hist_long; + + uint8_t tp_init_phase_ref_hist_med; + + uint8_t tp_init_phase_ref_hist_short; + + + uint8_t tp_consistency_lite_phase_tolerance; + + uint8_t tp_phasecal_target; + + uint16_t tp_cal_repeat_rate; + + uint8_t tp_lite_min_clip; + + + uint16_t tp_lite_long_sigma_thresh_mm; + + uint16_t tp_lite_med_sigma_thresh_mm; + + uint16_t tp_lite_short_sigma_thresh_mm; + + + uint16_t tp_lite_long_min_count_rate_rtn_mcps; + + uint16_t tp_lite_med_min_count_rate_rtn_mcps; + + uint16_t tp_lite_short_min_count_rate_rtn_mcps; + + + uint8_t tp_lite_sigma_est_pulse_width_ns; + + uint8_t tp_lite_sigma_est_amb_width_ns; + + uint8_t tp_lite_sigma_ref_mm; + + uint8_t tp_lite_seed_cfg; + + uint8_t tp_timed_seed_cfg; + + + uint8_t tp_lite_quantifier; + + uint8_t tp_lite_first_order_select; + + + uint16_t tp_dss_target_lite_mcps; + + uint16_t tp_dss_target_histo_mcps; + + uint16_t tp_dss_target_histo_mz_mcps; + + uint16_t tp_dss_target_timed_mcps; + + uint16_t tp_dss_target_very_short_mcps; + + + uint32_t tp_phasecal_timeout_lite_us; + + uint32_t tp_phasecal_timeout_hist_long_us; + + uint32_t tp_phasecal_timeout_hist_med_us; + + uint32_t tp_phasecal_timeout_hist_short_us; + + + uint32_t tp_phasecal_timeout_mz_long_us; + + uint32_t tp_phasecal_timeout_mz_med_us; + + uint32_t tp_phasecal_timeout_mz_short_us; + + uint32_t tp_phasecal_timeout_timed_us; + + + uint32_t tp_mm_timeout_lite_us; + + uint32_t tp_mm_timeout_histo_us; + + uint32_t tp_mm_timeout_mz_us; + + uint32_t tp_mm_timeout_timed_us; + + uint32_t tp_mm_timeout_lpa_us; + + + uint32_t tp_range_timeout_lite_us; + + uint32_t tp_range_timeout_histo_us; + + uint32_t tp_range_timeout_mz_us; + + uint32_t tp_range_timeout_timed_us; + + uint32_t tp_range_timeout_lpa_us; + + uint32_t tp_phasecal_patch_power; + + uint8_t tp_hist_merge; + + uint32_t tp_reset_merge_threshold; + + uint8_t tp_hist_merge_max_size; + + uint8_t tp_uwr_enable; + int16_t tp_uwr_med_z_1_min; + int16_t tp_uwr_med_z_1_max; + int16_t tp_uwr_med_z_2_min; + int16_t tp_uwr_med_z_2_max; + int16_t tp_uwr_med_z_3_min; + int16_t tp_uwr_med_z_3_max; + int16_t tp_uwr_med_z_4_min; + int16_t tp_uwr_med_z_4_max; + int16_t tp_uwr_med_z_5_min; + int16_t tp_uwr_med_z_5_max; + int16_t tp_uwr_med_z_6_min; + int16_t tp_uwr_med_z_6_max; + int16_t tp_uwr_med_corr_z_1_rangea; + int16_t tp_uwr_med_corr_z_1_rangeb; + int16_t tp_uwr_med_corr_z_2_rangea; + int16_t tp_uwr_med_corr_z_2_rangeb; + int16_t tp_uwr_med_corr_z_3_rangea; + int16_t tp_uwr_med_corr_z_3_rangeb; + int16_t tp_uwr_med_corr_z_4_rangea; + int16_t tp_uwr_med_corr_z_4_rangeb; + int16_t tp_uwr_med_corr_z_5_rangea; + int16_t tp_uwr_med_corr_z_5_rangeb; + int16_t tp_uwr_med_corr_z_6_rangea; + int16_t tp_uwr_med_corr_z_6_rangeb; + int16_t tp_uwr_lng_z_1_min; + int16_t tp_uwr_lng_z_1_max; + int16_t tp_uwr_lng_z_2_min; + int16_t tp_uwr_lng_z_2_max; + int16_t tp_uwr_lng_z_3_min; + int16_t tp_uwr_lng_z_3_max; + int16_t tp_uwr_lng_z_4_min; + int16_t tp_uwr_lng_z_4_max; + int16_t tp_uwr_lng_z_5_min; + int16_t tp_uwr_lng_z_5_max; + int16_t tp_uwr_lng_corr_z_1_rangea; + int16_t tp_uwr_lng_corr_z_1_rangeb; + int16_t tp_uwr_lng_corr_z_2_rangea; + int16_t tp_uwr_lng_corr_z_2_rangeb; + int16_t tp_uwr_lng_corr_z_3_rangea; + int16_t tp_uwr_lng_corr_z_3_rangeb; + int16_t tp_uwr_lng_corr_z_4_rangea; + int16_t tp_uwr_lng_corr_z_4_rangeb; + int16_t tp_uwr_lng_corr_z_5_rangea; + int16_t tp_uwr_lng_corr_z_5_rangeb; + +} VL53L1_tuning_parm_storage_t; + + + + + +typedef struct { + + uint8_t x_centre; + uint8_t y_centre; + +} VL53L1_optical_centre_t; + + + + +typedef struct { + + uint8_t x_centre; + uint8_t y_centre; + uint8_t width; + uint8_t height; + +} VL53L1_user_zone_t; + + + + +typedef struct { + + uint8_t max_zones; + uint8_t active_zones; + + + +VL53L1_histogram_config_t multizone_hist_cfg; + + VL53L1_user_zone_t user_zones[VL53L1_MAX_USER_ZONES]; + + + uint8_t bin_config[VL53L1_MAX_USER_ZONES]; + + +} VL53L1_zone_config_t; + + + +typedef struct { + + + VL53L1_GPIO_Interrupt_Mode intr_mode_distance; + + + VL53L1_GPIO_Interrupt_Mode intr_mode_rate; + + + uint8_t intr_new_measure_ready; + + + uint8_t intr_no_target; + + + uint8_t intr_combined_mode; + + + + + + uint16_t threshold_distance_high; + + + uint16_t threshold_distance_low; + + + uint16_t threshold_rate_high; + + + uint16_t threshold_rate_low; + +} VL53L1_GPIO_interrupt_config_t; + + + + +typedef struct { + + + uint8_t vhv_loop_bound; + + + uint8_t is_low_power_auto_mode; + + + uint8_t low_power_auto_range_count; + + + uint8_t saved_interrupt_config; + + + uint8_t saved_vhv_init; + + + uint8_t saved_vhv_timeout; + + + uint8_t first_run_phasecal_result; + + + uint32_t dss__total_rate_per_spad_mcps; + + + uint16_t dss__required_spads; + +} VL53L1_low_power_auto_data_t; + + + + + + + +typedef struct { + + + uint8_t smudge_corr_enabled; + + + uint8_t smudge_corr_apply_enabled; + + + uint8_t smudge_corr_single_apply; + + + + + uint16_t smudge_margin; + + + uint32_t noise_margin; + + + uint32_t user_xtalk_offset_limit; + + + uint8_t user_xtalk_offset_limit_hi; + + + uint32_t sample_limit; + + + uint32_t single_xtalk_delta; + + + uint32_t averaged_xtalk_delta; + + + uint32_t smudge_corr_clip_limit; + + + uint32_t smudge_corr_ambient_threshold; + + + uint8_t scaler_calc_method; + + + int16_t x_gradient_scaler; + + + int16_t y_gradient_scaler; + + + uint8_t user_scaler_set; + + + uint32_t nodetect_ambient_threshold; + + + uint32_t nodetect_sample_limit; + + + uint32_t nodetect_xtalk_offset; + + + uint16_t nodetect_min_range_mm; + + + uint32_t max_smudge_factor; + +} VL53L1_smudge_corrector_config_t; + + + +typedef struct { + + + uint32_t current_samples; + + + uint32_t required_samples; + + + uint64_t accumulator; + + + uint32_t nodetect_counter; + +} VL53L1_smudge_corrector_internals_t; + + + +typedef struct { + + + uint8_t smudge_corr_valid; + + + uint8_t smudge_corr_clipped; + + + uint8_t single_xtalk_delta_flag; + + + uint8_t averaged_xtalk_delta_flag; + + + uint8_t sample_limit_exceeded_flag; + + + uint8_t gradient_zero_flag; + + + uint8_t new_xtalk_applied_flag; + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + +} VL53L1_smudge_corrector_data_t; + + + + + +typedef struct { + + + + uint8_t range_id; + + uint32_t time_stamp; + + uint8_t VL53L1_p_015; + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_025; + + uint8_t VL53L1_p_026; + + uint8_t VL53L1_p_016; + + uint8_t VL53L1_p_027; + + + uint16_t width; + + uint8_t VL53L1_p_030; + + + uint16_t fast_osc_frequency; + + uint16_t zero_distance_phase; + + uint16_t VL53L1_p_006; + + + uint32_t total_periods_elapsed; + + + uint32_t peak_duration_us; + + + uint32_t woi_duration_us; + + + + + + uint32_t VL53L1_p_020; + + uint32_t VL53L1_p_021; + + int32_t VL53L1_p_013; + + + + + uint16_t peak_signal_count_rate_mcps; + + uint16_t avg_signal_count_rate_mcps; + + uint16_t ambient_count_rate_mcps; + + uint16_t total_rate_per_spad_mcps; + + uint32_t VL53L1_p_012; + + + + + uint16_t VL53L1_p_005; + + + + + uint16_t VL53L1_p_028; + + uint16_t VL53L1_p_014; + + uint16_t VL53L1_p_029; + + + + + int16_t min_range_mm; + + int16_t median_range_mm; + + int16_t max_range_mm; + + + + + uint8_t range_status; + +} VL53L1_range_data_t; + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + VL53L1_DeviceState rd_device_state; + + uint8_t zone_id; + + uint8_t stream_count; + + + int16_t VL53L1_p_007[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + int16_t wrap_dmax_mm; + + + uint8_t device_status; + + + uint8_t max_results; + + uint8_t active_results; + + VL53L1_range_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + VL53L1_range_data_t xmonitor; + + VL53L1_smudge_corrector_data_t smudge_corrector_data; + + + +} VL53L1_range_results_t; + + + + +typedef struct { + + uint8_t no_of_samples; + + uint32_t rate_per_spad_kcps_sum; + + uint32_t rate_per_spad_kcps_avg; + + int32_t signal_total_events_sum; + + int32_t signal_total_events_avg; + + uint32_t sigma_mm_sum; + + uint32_t sigma_mm_avg; + + uint32_t median_phase_sum; + + uint32_t median_phase_avg; + + +} VL53L1_xtalk_range_data_t; + + + + +typedef struct { + + VL53L1_Error cal_status; + + uint8_t num_of_samples_status; + + uint8_t zero_samples_status; + + uint8_t max_sigma_status; + + uint8_t max_results; + + uint8_t active_results; + + + VL53L1_xtalk_range_data_t + VL53L1_p_002[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + VL53L1_histogram_bin_data_t central_histogram_sum; + + VL53L1_histogram_bin_data_t central_histogram_avg; + + uint8_t central_histogram__window_start; + + uint8_t central_histogram__window_end; + + VL53L1_histogram_bin_data_t + histogram_avg_1[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + VL53L1_histogram_bin_data_t + histogram_avg_2[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + VL53L1_histogram_bin_data_t + xtalk_avg[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + +} VL53L1_xtalk_range_results_t; + + + + +typedef struct { + + uint8_t preset_mode; + + uint8_t dss_config__roi_mode_control; + + uint16_t dss_config__manual_effective_spads_select; + + uint8_t no_of_samples; + + uint32_t effective_spads; + + uint32_t peak_rate_mcps; + + uint32_t VL53L1_p_005; + + int32_t median_range_mm; + + int32_t range_mm_offset; + + +} VL53L1_offset_range_data_t; + + + + +typedef struct { + + int16_t cal_distance_mm; + + uint16_t cal_reflectance_pc; + + VL53L1_Error cal_status; + + uint8_t cal_report; + + uint8_t max_results; + + uint8_t active_results; + + VL53L1_offset_range_data_t + VL53L1_p_002[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + +} VL53L1_offset_range_results_t; + + + + +typedef struct { + + uint16_t result__mm_inner_actual_effective_spads; + + uint16_t result__mm_outer_actual_effective_spads; + + uint16_t result__mm_inner_peak_signal_count_rtn_mcps; + + uint16_t result__mm_outer_peak_signal_count_rtn_mcps; + + +} VL53L1_additional_offset_cal_data_t; + + + +typedef struct { + int16_t short_a_offset_mm; + int16_t short_b_offset_mm; + int16_t medium_a_offset_mm; + int16_t medium_b_offset_mm; + int16_t long_a_offset_mm; + int16_t long_b_offset_mm; +} VL53L1_per_vcsel_period_offset_cal_data_t; + + + + + +typedef struct { + + uint32_t VL53L1_p_020; + + uint32_t VL53L1_p_021; + + uint16_t VL53L1_p_014; + + uint8_t range_status; + + +} VL53L1_object_data_t; + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + VL53L1_DeviceState rd_device_state; + + uint8_t zone_id; + + uint8_t stream_count; + + uint8_t max_objects; + + uint8_t active_objects; + + VL53L1_object_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + + VL53L1_object_data_t xmonitor; + + +} VL53L1_zone_objects_t; + + + + + + +typedef struct { + + uint8_t max_zones; + + uint8_t active_zones; + + VL53L1_zone_objects_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + +} VL53L1_zone_results_t; + + + + +typedef struct { + + VL53L1_DeviceState rd_device_state; + + + uint8_t number_of_ambient_bins; + + + uint16_t result__dss_actual_effective_spads; + + uint8_t VL53L1_p_009; + + uint32_t total_periods_elapsed; + + + int32_t ambient_events_sum; + + +} VL53L1_zone_hist_info_t; + + + + +typedef struct { + + uint8_t max_zones; + + uint8_t active_zones; + + VL53L1_zone_hist_info_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + +} VL53L1_zone_histograms_t; + + + + +typedef struct { + + uint32_t no_of_samples; + + uint32_t effective_spads; + + uint32_t peak_rate_mcps; + + uint32_t VL53L1_p_014; + + uint32_t VL53L1_p_005; + + int32_t median_range_mm; + + int32_t range_mm_offset; + + +} VL53L1_zone_calibration_data_t; + + + + + + +typedef struct { + + uint32_t struct_version; + + VL53L1_DevicePresetModes preset_mode; + + VL53L1_DeviceZonePreset zone_preset; + + int16_t cal_distance_mm; + + uint16_t cal_reflectance_pc; + + uint16_t phasecal_result__reference_phase; + + uint16_t zero_distance_phase; + + VL53L1_Error cal_status; + + uint8_t max_zones; + + uint8_t active_zones; + + VL53L1_zone_calibration_data_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + +} VL53L1_zone_calibration_results_t; + + + + + +typedef struct { + + int16_t cal_distance_mm; + + uint16_t cal_reflectance_pc; + + uint16_t max_samples; + + uint16_t width; + + uint16_t height; + + uint16_t peak_rate_mcps[VL53L1_NVM_PEAK_RATE_MAP_SAMPLES]; + + +} VL53L1_cal_peak_rate_map_t; + + + + +typedef struct { + + uint8_t expected_stream_count; + + uint8_t expected_gph_id; + + uint8_t dss_mode; + + uint16_t dss_requested_effective_spad_count; + + uint8_t seed_cfg; + + uint8_t initial_phase_seed; + + + uint8_t roi_config__user_roi_centre_spad; + + uint8_t roi_config__user_roi_requested_global_xy_size; + + +} VL53L1_zone_private_dyn_cfg_t; + + + + +typedef struct { + + uint8_t max_zones; + + uint8_t active_zones; + + VL53L1_zone_private_dyn_cfg_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + +} VL53L1_zone_private_dyn_cfgs_t; + + + +typedef struct { + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + uint32_t algo__xtalk_cpo_HistoMerge_kcps[VL53L1_BIN_REC_SIZE]; + + +} VL53L1_xtalk_calibration_results_t; + + + + +typedef struct { + + + uint32_t sample_count; + + + uint32_t pll_period_mm; + + + uint32_t peak_duration_us_sum; + + + uint32_t effective_spad_count_sum; + + + uint32_t zero_distance_phase_sum; + + + uint32_t zero_distance_phase_avg; + + + int32_t event_scaler_sum; + + + int32_t event_scaler_avg; + + + int32_t signal_events_sum; + + + uint32_t xtalk_rate_kcps_per_spad; + + + int32_t xtalk_start_phase; + + + int32_t xtalk_end_phase; + + + int32_t xtalk_width_phase; + + + int32_t target_start_phase; + + + int32_t target_end_phase; + + + int32_t target_width_phase; + + + int32_t effective_width; + + + int32_t event_scaler; + + + uint8_t VL53L1_p_015; + + + uint8_t VL53L1_p_016; + + + uint8_t target_start; + + + int32_t max_shape_value; + + + int32_t bin_data_sums[VL53L1_XTALK_HISTO_BINS]; + +} VL53L1_hist_xtalk_extract_data_t; + + + + +typedef struct { + + uint16_t standard_ranging_gain_factor; + + uint16_t histogram_ranging_gain_factor; + + +} VL53L1_gain_calibration_data_t; + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + uint8_t cfg_stream_count; + + uint8_t cfg_internal_stream_count; + + uint8_t cfg_internal_stream_count_val; + + uint8_t cfg_gph_id; + + uint8_t cfg_timing_status; + + uint8_t cfg_zone_id; + + + VL53L1_DeviceState rd_device_state; + + uint8_t rd_stream_count; + + uint8_t rd_internal_stream_count; + + uint8_t rd_internal_stream_count_val; + + uint8_t rd_gph_id; + + uint8_t rd_timing_status; + + uint8_t rd_zone_id; + + +} VL53L1_ll_driver_state_t; + + + + +typedef struct { + + uint8_t wait_method; + + VL53L1_DevicePresetModes preset_mode; + + VL53L1_DeviceZonePreset zone_preset; + + VL53L1_DeviceMeasurementModes measurement_mode; + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + VL53L1_DeviceDmaxMode dmax_mode; + + uint32_t phasecal_config_timeout_us; + + uint32_t mm_config_timeout_us; + + uint32_t range_config_timeout_us; + + uint32_t inter_measurement_period_ms; + + uint16_t dss_config__target_total_rate_mcps; + + uint32_t fw_ready_poll_duration_ms; + + uint8_t fw_ready; + + uint8_t debug_mode; + + + + VL53L1_ll_version_t version; + + + VL53L1_ll_driver_state_t ll_state; + + + VL53L1_GPIO_interrupt_config_t gpio_interrupt_config; + + + VL53L1_customer_nvm_managed_t customer; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_user_zone_t mm_roi; + VL53L1_optical_centre_t optical_centre; + VL53L1_zone_config_t zone_cfg; + + + VL53L1_tuning_parm_storage_t tuning_parms; + + + uint8_t rtn_good_spads[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + VL53L1_refspadchar_config_t refspadchar; + VL53L1_ssc_config_t ssc_cfg; + VL53L1_hist_post_process_config_t histpostprocess; + VL53L1_hist_gen3_dmax_config_t dmax_cfg; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_offsetcal_config_t offsetcal_cfg; + VL53L1_zonecal_config_t zonecal_cfg; + + + VL53L1_static_nvm_managed_t stat_nvm; + VL53L1_histogram_config_t hist_cfg; + VL53L1_static_config_t stat_cfg; + VL53L1_general_config_t gen_cfg; + VL53L1_timing_config_t tim_cfg; + VL53L1_dynamic_config_t dyn_cfg; + VL53L1_system_control_t sys_ctrl; + VL53L1_system_results_t sys_results; + VL53L1_nvm_copy_data_t nvm_copy_data; + + + VL53L1_histogram_bin_data_t hist_data; + VL53L1_histogram_bin_data_t hist_xtalk; + + + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + VL53L1_xtalk_calibration_results_t xtalk_cal; + VL53L1_hist_xtalk_extract_data_t xtalk_extract; + + + VL53L1_offset_range_results_t offset_results; + + + VL53L1_core_results_t core_results; + VL53L1_debug_results_t dbg_results; + + VL53L1_smudge_corrector_config_t smudge_correct_config; + + VL53L1_smudge_corrector_internals_t smudge_corrector_internals; + + + + + VL53L1_low_power_auto_data_t low_power_auto_data; + + +#ifdef PAL_EXTENDED + + VL53L1_patch_results_t patch_results; + VL53L1_shadow_core_results_t shadow_core_results; + VL53L1_shadow_system_results_t shadow_sys_results; + VL53L1_prev_shadow_core_results_t prev_shadow_core_results; + VL53L1_prev_shadow_system_results_t prev_shadow_sys_results; +#endif + uint8_t wArea1[1536]; + uint8_t wArea2[512]; + VL53L1_per_vcsel_period_offset_cal_data_t per_vcsel_cal_data; + + uint8_t bin_rec_pos; + + uint8_t pos_before_next_recom; + + int32_t multi_bins_rec[VL53L1_BIN_REC_SIZE] + [VL53L1_TIMING_CONF_A_B_SIZE][VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int16_t PreviousRangeMilliMeter[VL53L1_MAX_RANGE_RESULTS]; + uint8_t PreviousRangeStatus[VL53L1_MAX_RANGE_RESULTS]; + uint8_t PreviousExtendedRange[VL53L1_MAX_RANGE_RESULTS]; + uint8_t PreviousStreamCount; + +} VL53L1_LLDriverData_t; + + + + +typedef struct { + + + VL53L1_range_results_t range_results; + + + VL53L1_zone_private_dyn_cfgs_t zone_dyn_cfgs; + + + VL53L1_zone_results_t zone_results; + VL53L1_zone_histograms_t zone_hists; + VL53L1_zone_calibration_results_t zone_cal; + +} VL53L1_LLDriverResults_t; + + + + +typedef struct { + + uint32_t struct_version; + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_per_vcsel_period_offset_cal_data_t per_vcsel_cal_data; + +} VL53L1_calibration_data_t; + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_histogram_bin_data_t hist_data; + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + +} VL53L1_xtalk_debug_data_t; + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_offset_range_results_t offset_results; + +} VL53L1_offset_debug_data_t; + + + + +typedef struct { + uint16_t vl53l1_tuningparm_version; + uint16_t vl53l1_tuningparm_key_table_version; + uint16_t vl53l1_tuningparm_lld_version; + uint8_t vl53l1_tuningparm_hist_algo_select; + uint8_t vl53l1_tuningparm_hist_target_order; + uint8_t vl53l1_tuningparm_hist_filter_woi_0; + uint8_t vl53l1_tuningparm_hist_filter_woi_1; + uint8_t vl53l1_tuningparm_hist_amb_est_method; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_0; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_1; + int32_t vl53l1_tuningparm_hist_min_amb_thresh_events; + uint16_t vl53l1_tuningparm_hist_amb_events_scaler; + uint16_t vl53l1_tuningparm_hist_noise_threshold; + int32_t vl53l1_tuningparm_hist_signal_total_events_limit; + uint8_t vl53l1_tuningparm_hist_sigma_est_ref_mm; + uint16_t vl53l1_tuningparm_hist_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_hist_gain_factor; + uint8_t vl53l1_tuningparm_consistency_hist_phase_tolerance; + uint16_t vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm; + uint8_t vl53l1_tuningparm_consistency_hist_event_sigma; + uint16_t vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_short_range; + int16_t vl53l1_tuningparm_xtalk_detect_min_valid_range_mm; + int16_t vl53l1_tuningparm_xtalk_detect_max_valid_range_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_max_sigma_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_min_max_tolerance; + uint16_t vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps; + uint8_t vl53l1_tuningparm_xtalk_detect_event_sigma; + int16_t vl53l1_tuningparm_hist_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_consistency_lite_phase_tolerance; + uint8_t vl53l1_tuningparm_phasecal_target; + uint16_t vl53l1_tuningparm_lite_cal_repeat_rate; + uint16_t vl53l1_tuningparm_lite_ranging_gain_factor; + uint8_t vl53l1_tuningparm_lite_min_clip_mm; + uint16_t vl53l1_tuningparm_lite_long_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_med_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_short_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps; + uint8_t vl53l1_tuningparm_lite_sigma_est_pulse_width; + uint8_t vl53l1_tuningparm_lite_sigma_est_amb_width_ns; + uint8_t vl53l1_tuningparm_lite_sigma_ref_mm; + uint8_t vl53l1_tuningparm_lite_rit_mult; + uint8_t vl53l1_tuningparm_lite_seed_config; + uint8_t vl53l1_tuningparm_lite_quantifier; + uint8_t vl53l1_tuningparm_lite_first_order_select; + int16_t vl53l1_tuningparm_lite_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_short_range; + uint8_t vl53l1_tuningparm_timed_seed_config; + uint8_t vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_0; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_1; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_2; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_3; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_4; + uint8_t vl53l1_tuningparm_vhv_loopbound; + uint8_t vl53l1_tuningparm_refspadchar_device_test_mode; + uint8_t vl53l1_tuningparm_refspadchar_vcsel_period; + uint32_t vl53l1_tuningparm_refspadchar_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_refspadchar_target_count_rate_mcps; + uint16_t vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps; + uint16_t vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps; + uint8_t vl53l1_tuningparm_xtalk_extract_num_of_samples; + int16_t vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm; + int16_t vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm; + uint16_t vl53l1_tuningparm_xtalk_extract_dss_rate_mcps; + uint32_t vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps; + uint16_t vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm; + uint32_t vl53l1_tuningparm_xtalk_extract_dss_timeout_us; + uint32_t vl53l1_tuningparm_xtalk_extract_bin_timeout_us; + uint16_t vl53l1_tuningparm_offset_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_offset_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_mm_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_range_timeout_us; + uint8_t vl53l1_tuningparm_offset_cal_pre_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm1_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm2_samples; + uint16_t vl53l1_tuningparm_zone_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_zone_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_zone_cal_dss_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_phasecal_num_samples; + uint32_t vl53l1_tuningparm_zone_cal_range_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_zone_num_samples; + uint8_t vl53l1_tuningparm_spadmap_vcsel_period; + uint8_t vl53l1_tuningparm_spadmap_vcsel_start; + uint16_t vl53l1_tuningparm_spadmap_rate_limit_mcps; + uint16_t vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps; + uint32_t vl53l1_tuningparm_lite_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_range_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_range_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_range_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_range_config_timeout_us; + uint16_t vl53l1_tuningparm_dynxtalk_smudge_margin; + uint32_t vl53l1_tuningparm_dynxtalk_noise_margin; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit; + uint8_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi; + uint32_t vl53l1_tuningparm_dynxtalk_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_single_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_clip_limit; + uint8_t vl53l1_tuningparm_dynxtalk_scaler_calc_method; + int16_t vl53l1_tuningparm_dynxtalk_xgradient_scaler; + int16_t vl53l1_tuningparm_dynxtalk_ygradient_scaler; + uint8_t vl53l1_tuningparm_dynxtalk_user_scaler_set; + uint8_t vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps; + uint16_t vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm; + uint8_t vl53l1_tuningparm_lowpowerauto_vhv_loop_bound; + uint32_t vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lowpowerauto_range_config_timeout_us; + uint16_t vl53l1_tuningparm_very_short_dss_rate_mcps; + uint32_t vl53l1_tuningparm_phasecal_patch_power; +} VL53L1_tuning_parameters_t; + + + + + +typedef struct { + + uint16_t target_reflectance_for_dmax[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + +} VL53L1_dmax_reflectance_array_t; + + + + +typedef struct { + + uint8_t spad_type; + + uint16_t VL53L1_p_023; + + uint16_t rate_data[VL53L1_NO_OF_SPAD_ENABLES]; + + uint16_t no_of_values; + + uint8_t fractional_bits; + + uint8_t error_status; + + +} VL53L1_spad_rate_data_t; + + + + + + +typedef struct { + + VL53L1_DevicePresetModes preset_mode; + + VL53L1_DeviceZonePreset zone_preset; + + VL53L1_DeviceMeasurementModes measurement_mode; + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + VL53L1_DeviceDmaxMode dmax_mode; + + + uint32_t phasecal_config_timeout_us; + + uint32_t mm_config_timeout_us; + + uint32_t range_config_timeout_us; + + uint32_t inter_measurement_period_ms; + + uint16_t dss_config__target_total_rate_mcps; + + + VL53L1_histogram_bin_data_t VL53L1_p_010; + + +} VL53L1_additional_data_t; + + + + + + + + +#define SUPPRESS_UNUSED_WARNING(x) \ + ((void) (x)) + + +#define IGNORE_STATUS(__FUNCTION_ID__, __ERROR_STATUS_CHECK__, __STATUS__) \ + do { \ + DISABLE_WARNINGS(); \ + if (__FUNCTION_ID__) { \ + if (__STATUS__ == __ERROR_STATUS_CHECK__) { \ + __STATUS__ = VL53L1_ERROR_NONE; \ + WARN_OVERRIDE_STATUS(__FUNCTION_ID__); \ + } \ + } \ + ENABLE_WARNINGS(); \ + } \ + while (0) + +#define VL53L1_COPYSTRING(str, ...) \ + (strncpy(str, ##__VA_ARGS__, VL53L1_MAX_STRING_LENGTH-1)) + +#ifdef __cplusplus +} +#endif + +#endif + + + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_ll_device.h b/drivers/input/misc/vl53L1/inc/vl53l1_ll_device.h new file mode 100644 index 0000000000000000000000000000000000000000..fd57e97fa8619d8c36a02479556753c7d5b98f4f --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_ll_device.h @@ -0,0 +1,1063 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_LL_DEVICE_H_ +#define _VL53L1_LL_DEVICE_H_ + +#include "vl53l1_types.h" +#include "vl53l1_platform_user_config.h" + +#define VL53L1_I2C 0x01 +#define VL53L1_SPI 0x00 + + + + + +typedef uint8_t VL53L1_WaitMethod; + +#define VL53L1_WAIT_METHOD_BLOCKING ((VL53L1_WaitMethod) 0) +#define VL53L1_WAIT_METHOD_NON_BLOCKING ((VL53L1_WaitMethod) 1) + + + + +typedef uint8_t VL53L1_DeviceState; + +#define VL53L1_DEVICESTATE_POWERDOWN ((VL53L1_DeviceState) 0) +#define VL53L1_DEVICESTATE_HW_STANDBY ((VL53L1_DeviceState) 1) +#define VL53L1_DEVICESTATE_FW_COLDBOOT ((VL53L1_DeviceState) 2) +#define VL53L1_DEVICESTATE_SW_STANDBY ((VL53L1_DeviceState) 3) +#define VL53L1_DEVICESTATE_RANGING_DSS_AUTO ((VL53L1_DeviceState) 4) +#define VL53L1_DEVICESTATE_RANGING_DSS_MANUAL ((VL53L1_DeviceState) 5) +#define VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC ((VL53L1_DeviceState) 6) +#define VL53L1_DEVICESTATE_RANGING_GATHER_DATA ((VL53L1_DeviceState) 7) +#define VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA ((VL53L1_DeviceState) 8) + +#define VL53L1_DEVICESTATE_UNKNOWN ((VL53L1_DeviceState) 98) +#define VL53L1_DEVICESTATE_ERROR ((VL53L1_DeviceState) 99) + + + + + +typedef uint8_t VL53L1_DeviceZonePreset; + +#define VL53L1_DEVICEZONEPRESET_NONE \ + ((VL53L1_DeviceZonePreset) 0) + +#define VL53L1_DEVICEZONEPRESET_XTALK_PLANAR \ + ((VL53L1_DeviceZonePreset) 1) +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16 \ + ((VL53L1_DeviceZonePreset) 2) +#define VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8 \ + ((VL53L1_DeviceZonePreset) 3) +#define VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16 \ + ((VL53L1_DeviceZonePreset) 4) +#define VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8 \ + ((VL53L1_DeviceZonePreset) 5) +#define VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 6) +#define VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 7) +#define VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 8) +#define VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 9) +#define VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 10) + +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8 \ + ((VL53L1_DeviceZonePreset) 11) + +#define VL53L1_DEVICEZONEPRESET_CUSTOM \ + ((VL53L1_DeviceZonePreset) 255) + + + + + +typedef uint8_t VL53L1_DevicePresetModes; + +#define VL53L1_DEVICEPRESETMODE_NONE \ + ((VL53L1_DevicePresetModes) 0) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING \ + ((VL53L1_DevicePresetModes) 1) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 2) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 3) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 4) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 5) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING \ + ((VL53L1_DevicePresetModes) 6) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 7) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 8) +#define VL53L1_DEVICEPRESETMODE_NEAR_FARRANGING \ + ((VL53L1_DevicePresetModes) 9) +#define VL53L1_DEVICEPRESETMODE_QUADRANT_RANGING \ + ((VL53L1_DevicePresetModes) 10) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING \ + ((VL53L1_DevicePresetModes) 11) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING \ + ((VL53L1_DevicePresetModes) 12) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION \ + ((VL53L1_DevicePresetModes) 13) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR \ + ((VL53L1_DevicePresetModes) 14) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1 \ + ((VL53L1_DevicePresetModes) 15) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2 \ + ((VL53L1_DevicePresetModes) 16) +#define VL53L1_DEVICEPRESETMODE_OLT \ + ((VL53L1_DevicePresetModes) 17) +#define VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING \ + ((VL53L1_DevicePresetModes) 18) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY \ + ((VL53L1_DevicePresetModes) 19) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1 \ + ((VL53L1_DevicePresetModes) 20) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2 \ + ((VL53L1_DevicePresetModes) 21) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 22) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 23) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE \ + ((VL53L1_DevicePresetModes) 24) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 25) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 26) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 27) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 28) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 29) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 30) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 31) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 32) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 33) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 34) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 35) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 36) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 37) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 38) +#define VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 39) + + + + + +typedef uint8_t VL53L1_DeviceMeasurementModes; + +#define VL53L1_DEVICEMEASUREMENTMODE_STOP \ + ((VL53L1_DeviceMeasurementModes) 0x00) +#define VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT \ + ((VL53L1_DeviceMeasurementModes) 0x10) +#define VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK \ + ((VL53L1_DeviceMeasurementModes) 0x20) +#define VL53L1_DEVICEMEASUREMENTMODE_TIMED \ + ((VL53L1_DeviceMeasurementModes) 0x40) +#define VL53L1_DEVICEMEASUREMENTMODE_ABORT \ + ((VL53L1_DeviceMeasurementModes) 0x80) + + + + + +typedef uint8_t VL53L1_OffsetCalibrationMode; + +#define VL53L1_OFFSETCALIBRATIONMODE__NONE \ + ((VL53L1_OffsetCalibrationMode) 0) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD \ + ((VL53L1_OffsetCalibrationMode) 1) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM \ + ((VL53L1_OffsetCalibrationMode) 2) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 3) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 4) +#define VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE \ + ((VL53L1_OffsetCalibrationMode) 5) + + + + + +typedef uint8_t VL53L1_OffsetCorrectionMode; + +#define VL53L1_OFFSETCORRECTIONMODE__NONE \ + ((VL53L1_OffsetCorrectionMode) 0) +#define VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 2) +#define VL53L1_OFFSETCORRECTIONMODE__PER_VCSEL_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 3) + + + + + +typedef uint8_t VL53L1_DeviceDmaxMode; + +#define VL53L1_DEVICEDMAXMODE__NONE \ + ((VL53L1_DeviceDmaxMode) 0) +#define VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 1) +#define VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 2) +#define VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 3) + + + + + +typedef uint8_t VL53L1_DeviceSequenceConfig; + +#define VL53L1_DEVICESEQUENCECONFIG_VHV \ + ((VL53L1_DeviceSequenceConfig) 0) +#define VL53L1_DEVICESEQUENCECONFIG_PHASECAL \ + ((VL53L1_DeviceSequenceConfig) 1) +#define VL53L1_DEVICESEQUENCECONFIG_REFERENCE_PHASE \ + ((VL53L1_DeviceSequenceConfig) 2) +#define VL53L1_DEVICESEQUENCECONFIG_DSS1 \ + ((VL53L1_DeviceSequenceConfig) 3) +#define VL53L1_DEVICESEQUENCECONFIG_DSS2 \ + ((VL53L1_DeviceSequenceConfig) 4) +#define VL53L1_DEVICESEQUENCECONFIG_MM1 \ + ((VL53L1_DeviceSequenceConfig) 5) +#define VL53L1_DEVICESEQUENCECONFIG_MM2 \ + ((VL53L1_DeviceSequenceConfig) 6) +#define VL53L1_DEVICESEQUENCECONFIG_RANGE \ + ((VL53L1_DeviceSequenceConfig) 7) + + + + + +typedef uint8_t VL53L1_DeviceInterruptPolarity; + +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_HIGH \ + ((VL53L1_DeviceInterruptPolarity) 0x00) +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0xEF) + + + + + +typedef uint8_t VL53L1_DeviceGpioMode; + +#define VL53L1_DEVICEGPIOMODE_OUTPUT_CONSTANT_ZERO \ + ((VL53L1_DeviceGpioMode) 0x00) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x01) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_TIMIER_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x02) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_MODE_INTERRUPT_STATUS \ + ((VL53L1_DeviceGpioMode) 0x03) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_SLOW_OSCILLATOR_CLOCK \ + ((VL53L1_DeviceGpioMode) 0x04) +#define VL53L1_DEVICEGPIOMODE_BIT_MASK \ + ((VL53L1_DeviceGpioMode) 0x0F) +#define VL53L1_DEVICEGPIOMODE_CLEAR_MASK \ + ((VL53L1_DeviceGpioMode) 0xF0) + + + + + +typedef uint8_t VL53L1_DeviceError; + +#define VL53L1_DEVICEERROR_NOUPDATE \ + ((VL53L1_DeviceError) 0) + +#define VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \ + ((VL53L1_DeviceError) 1) +#define VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \ + ((VL53L1_DeviceError) 2) +#define VL53L1_DEVICEERROR_NOVHVVALUEFOUND \ + ((VL53L1_DeviceError) 3) +#define VL53L1_DEVICEERROR_MSRCNOTARGET \ + ((VL53L1_DeviceError) 4) +#define VL53L1_DEVICEERROR_RANGEPHASECHECK \ + ((VL53L1_DeviceError) 5) +#define VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK \ + ((VL53L1_DeviceError) 6) +#define VL53L1_DEVICEERROR_PHASECONSISTENCY \ + ((VL53L1_DeviceError) 7) +#define VL53L1_DEVICEERROR_MINCLIP \ + ((VL53L1_DeviceError) 8) +#define VL53L1_DEVICEERROR_RANGECOMPLETE \ + ((VL53L1_DeviceError) 9) +#define VL53L1_DEVICEERROR_ALGOUNDERFLOW \ + ((VL53L1_DeviceError) 10) +#define VL53L1_DEVICEERROR_ALGOOVERFLOW \ + ((VL53L1_DeviceError) 11) +#define VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD \ + ((VL53L1_DeviceError) 12) +#define VL53L1_DEVICEERROR_USERROICLIP \ + ((VL53L1_DeviceError) 13) +#define VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS \ + ((VL53L1_DeviceError) 14) +#define VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET \ + ((VL53L1_DeviceError) 15) +#define VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET \ + ((VL53L1_DeviceError) 16) +#define VL53L1_DEVICEERROR_MULTCLIPFAIL \ + ((VL53L1_DeviceError) 17) +#define VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY \ + ((VL53L1_DeviceError) 18) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK \ + ((VL53L1_DeviceError) 19) +#define VL53L1_DEVICEERROR_EVENTCONSISTENCY \ + ((VL53L1_DeviceError) 20) +#define VL53L1_DEVICEERROR_MINSIGNALEVENTCHECK \ + ((VL53L1_DeviceError) 21) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE \ + ((VL53L1_DeviceError) 22) + + +#define VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS \ + ((VL53L1_DeviceError) 23) + + + + + +typedef uint8_t VL53L1_DeviceReportStatus; + +#define VL53L1_DEVICEREPORTSTATUS_NOUPDATE \ + ((VL53L1_DeviceReportStatus) 0) + +#define VL53L1_DEVICEREPORTSTATUS_ROI_SETUP \ + ((VL53L1_DeviceReportStatus) 1) +#define VL53L1_DEVICEREPORTSTATUS_VHV \ + ((VL53L1_DeviceReportStatus) 2) +#define VL53L1_DEVICEREPORTSTATUS_PHASECAL \ + ((VL53L1_DeviceReportStatus) 3) +#define VL53L1_DEVICEREPORTSTATUS_REFERENCE_PHASE \ + ((VL53L1_DeviceReportStatus) 4) +#define VL53L1_DEVICEREPORTSTATUS_DSS1 \ + ((VL53L1_DeviceReportStatus) 5) +#define VL53L1_DEVICEREPORTSTATUS_DSS2 \ + ((VL53L1_DeviceReportStatus) 6) +#define VL53L1_DEVICEREPORTSTATUS_MM1 \ + ((VL53L1_DeviceReportStatus) 7) +#define VL53L1_DEVICEREPORTSTATUS_MM2 \ + ((VL53L1_DeviceReportStatus) 8) +#define VL53L1_DEVICEREPORTSTATUS_RANGE \ + ((VL53L1_DeviceReportStatus) 9) +#define VL53L1_DEVICEREPORTSTATUS_HISTOGRAM \ + ((VL53L1_DeviceReportStatus) 10) + + + + + +typedef uint8_t VL53L1_DeviceDssMode; + +#define VL53L1_DEVICEDSSMODE__DISABLED \ + ((VL53L1_DeviceDssMode) 0) +#define VL53L1_DEVICEDSSMODE__TARGET_RATE \ + ((VL53L1_DeviceDssMode) 1) +#define VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS \ + ((VL53L1_DeviceDssMode) 2) +#define VL53L1_DEVICEDSSMODE__BLOCK_SELECT \ + ((VL53L1_DeviceDssMode) 3) + + + + + + +typedef uint8_t VL53L1_HistAlgoSelect; + +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN1 \ + ((VL53L1_HistAlgoSelect) 1) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN2 \ + ((VL53L1_HistAlgoSelect) 2) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN3 \ + ((VL53L1_HistAlgoSelect) 3) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN4 \ + ((VL53L1_HistAlgoSelect) 4) + + + + + + +typedef uint8_t VL53L1_HistTargetOrder; + +#define VL53L1_HIST_TARGET_ORDER__INCREASING_DISTANCE \ + ((VL53L1_HistTargetOrder) 1) +#define VL53L1_HIST_TARGET_ORDER__STRONGEST_FIRST \ + ((VL53L1_HistTargetOrder) 2) + + + + + + +typedef uint8_t VL53L1_HistAmbEstMethod; + +#define VL53L1_HIST_AMB_EST_METHOD__AMBIENT_BINS \ + ((VL53L1_HistAmbEstMethod) 1) +#define VL53L1_HIST_AMB_EST_METHOD__THRESHOLDED_BINS \ + ((VL53L1_HistAmbEstMethod) 2) + + + + + + +typedef uint8_t VL53L1_HistXtalkCompEnable; + +#define VL53L1_HIST_XTALK_COMP__DIS \ + ((VL53L1_HistXtalkCompEnable) 0) +#define VL53L1_HIST_XTALK_COMP__EN \ + ((VL53L1_HistXtalkCompEnable) 1) + + + + +typedef uint8_t VL53L1_DeviceConfigLevel; + +#define VL53L1_DEVICECONFIGLEVEL_SYSTEM_CONTROL \ + ((VL53L1_DeviceConfigLevel) 0) + +#define VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 1) + +#define VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 2) + +#define VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 3) + +#define VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 4) + +#define VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 5) + +#define VL53L1_DEVICECONFIGLEVEL_FULL \ + ((VL53L1_DeviceConfigLevel) 6) + + + + + + +typedef uint8_t VL53L1_DeviceResultsLevel; + +#define VL53L1_DEVICERESULTSLEVEL_SYSTEM_RESULTS \ + ((VL53L1_DeviceResultsLevel) 0) + +#define VL53L1_DEVICERESULTSLEVEL_UPTO_CORE \ + ((VL53L1_DeviceResultsLevel) 1) + +#define VL53L1_DEVICERESULTSLEVEL_FULL \ + ((VL53L1_DeviceResultsLevel) 2) + + + + + + + +typedef uint8_t VL53L1_DeviceTestMode; + +#define VL53L1_DEVICETESTMODE_NONE \ + ((VL53L1_DeviceTestMode) 0x00) + +#define VL53L1_DEVICETESTMODE_NVM_ZERO \ + ((VL53L1_DeviceTestMode) 0x01) + +#define VL53L1_DEVICETESTMODE_NVM_COPY \ + ((VL53L1_DeviceTestMode) 0x02) + +#define VL53L1_DEVICETESTMODE_PATCH \ + ((VL53L1_DeviceTestMode) 0x03) + +#define VL53L1_DEVICETESTMODE_DCR \ + ((VL53L1_DeviceTestMode) 0x04) + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_OFF \ + ((VL53L1_DeviceTestMode) 0x05) + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_ON \ + ((VL53L1_DeviceTestMode) 0x06) + +#define VL53L1_DEVICETESTMODE_SPOT_CENTRE_LOCATE \ + ((VL53L1_DeviceTestMode) 0x07) + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_WITH_PRE_VHV \ + ((VL53L1_DeviceTestMode) 0x08) + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_ONLY \ + ((VL53L1_DeviceTestMode) 0x09) + + + + + + + +typedef uint8_t VL53L1_DeviceSscArray; + +#define VL53L1_DEVICESSCARRAY_RTN ((VL53L1_DeviceSscArray) 0x00) + +#define VL53L1_DEVICETESTMODE_REF ((VL53L1_DeviceSscArray) 0x01) + + + + + + + +#define VL53L1_RETURN_ARRAY_ONLY 0x01 + +#define VL53L1_REFERENCE_ARRAY_ONLY 0x10 + +#define VL53L1_BOTH_RETURN_AND_REFERENCE_ARRAYS 0x11 + +#define VL53L1_NEITHER_RETURN_AND_REFERENCE_ARRAYS 0x00 + + + + + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH 0x00 + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_LOW 0x10 + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK 0x10 + + + + + + +#define VL53L1_POLLING_DELAY_US 1000 + +#define VL53L1_SOFTWARE_RESET_DURATION_US 100 + +#define VL53L1_FIRMWARE_BOOT_TIME_US 1200 + +#define VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US 250 + +#define VL53L1_SPAD_ARRAY_WIDTH 16 + +#define VL53L1_SPAD_ARRAY_HEIGHT 16 + +#define VL53L1_NVM_SIZE_IN_BYTES 512 + +#define VL53L1_NO_OF_SPAD_ENABLES 256 + +#define VL53L1_RTN_SPAD_BUFFER_SIZE 32 + +#define VL53L1_REF_SPAD_BUFFER_SIZE 6 + +#define VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS 256 + +#define VL53L1_RANGING_WINDOW_VCSEL_PERIODS 2048 + +#define VL53L1_MACRO_PERIOD_VCSEL_PERIODS \ + (VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS + \ + VL53L1_RANGING_WINDOW_VCSEL_PERIODS) + +#define VL53L1_MAX_ALLOWED_PHASE 0xFFFF + + +#define VL53L1_RTN_SPAD_UNITY_TRANSMISSION 0x0100 + +#define VL53L1_RTN_SPAD_APERTURE_TRANSMISSION 0x0038 + + +#define VL53L1_SPAD_TOTAL_COUNT_MAX ((0x01 << 29) - 1) + +#define VL53L1_SPAD_TOTAL_COUNT_RES_THRES (0x01 << 24) + +#define VL53L1_COUNT_RATE_INTERNAL_MAX ((0x01 << 24) - 1) + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR 299704 + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 (299704 >> 3) + + + + + + + + +typedef uint8_t VL53L1_ZoneConfig_BinConfig_select; + +#define VL53L1_ZONECONFIG_BINCONFIG__LOWAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 1) +#define VL53L1_ZONECONFIG_BINCONFIG__MIDAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 2) +#define VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 3) + + + + + +typedef uint8_t VL53L1_GPIO_Interrupt_Mode; + +#define VL53L1_GPIOINTMODE_LEVEL_LOW \ + ((VL53L1_GPIO_Interrupt_Mode) 0) + +#define VL53L1_GPIOINTMODE_LEVEL_HIGH \ + ((VL53L1_GPIO_Interrupt_Mode) 1) + +#define VL53L1_GPIOINTMODE_OUT_OF_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 2) + +#define VL53L1_GPIOINTMODE_IN_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 3) + + + + + + +typedef uint16_t VL53L1_TuningParms; + +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEB) + +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS) + +#define VL53L1_TUNINGPARM_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 0)) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 1)) +#define VL53L1_TUNINGPARM_LLD_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 2)) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 3)) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 4)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 5)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 6)) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 7)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 8)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 9)) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 10)) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 11)) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 12)) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 13)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 14)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 15)) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 16)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 17)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 18)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 19)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 20)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 21)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 22)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 23)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 24)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 25)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 26)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 27)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 28)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 29)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 30)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 31)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 32)) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 33)) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 34)) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 35)) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 36)) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 37)) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 38)) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 39)) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 40)) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 41)) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 42)) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 43)) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 44)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 45)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 46)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 47)) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 48)) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 49)) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 50)) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 51)) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 52)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 53)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 54)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 55)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 56)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 57)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 58)) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 59)) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 60)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 61)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 62)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 63)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 64)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 65)) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 66)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 67)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 68)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 69)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 70)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 71)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 72)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 73)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 74)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 75)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 76)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 77)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 78)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 79)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 80)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 81)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 82)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 83)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 84)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 85)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 86)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 87)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 88)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 89)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 90)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 91)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 92)) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 93)) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 94)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 95)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 96)) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 97)) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 98)) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 99)) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 100)) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 101)) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 102)) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 103)) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 104)) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 105)) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 106)) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 107)) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 108)) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 109)) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 110)) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 111)) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 112)) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 113)) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 114)) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 115)) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 116)) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 117)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 118)) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 119)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 120)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 121)) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 122)) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 123)) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 124)) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 125)) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 126)) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 127)) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 128)) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 129)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 130)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 131)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 132)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 133)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 134)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 135)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 136)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 137)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 138)) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 139)) +#define VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 140)) +#define VL53L1_TUNINGPARM_HIST_MERGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 141)) +#define VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 142)) +#define VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 143)) +#define VL53L1_TUNINGPARM_DYNXTALK_MAX_SMUDGE_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 144)) +#define VL53L1_TUNINGPARM_UWR_ENABLE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 145)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 146)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 147)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 148)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 149)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 150)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 151)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 152)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 153)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 154)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 155)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 156)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 157)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 158)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 159)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 160)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 161)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 162)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 163)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 164)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 165)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 166)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 167)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 168)) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 169)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 170)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 171)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 172)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 173)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 174)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 175)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 176)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 177)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 178)) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MAX \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 179)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 180)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 181)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 182)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 183)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 184)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 185)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 186)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 187)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 188)) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEB \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 189)) + + + + + +#endif + + + + + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_nvm.h b/drivers/input/misc/vl53L1/inc/vl53l1_nvm.h new file mode 100644 index 0000000000000000000000000000000000000000..58e136e77c3f57f429c3888eef1e3fc32c219e2d --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_nvm.h @@ -0,0 +1,169 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + + + +#ifndef _VL53L1_NVM_H_ +#define _VL53L1_NVM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_NVM_POWER_UP_DELAY_US 50 +#define VL53L1_NVM_READ_TRIGGER_DELAY_US 5 + + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us); + + + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata); + + + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata); + + + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata); + + + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata); + + + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata); + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata); + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata); + + + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata); + + + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data); + + + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data); + + + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info); + + + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre); + + + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data); + + + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data); + + + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_nvm_debug.h b/drivers/input/misc/vl53L1/inc/vl53l1_nvm_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..34259440eb707e44ab7c9cb54ba3382b67fe4da3 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_nvm_debug.h @@ -0,0 +1,75 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_NVM_DEBUG_H_ +#define _VL53L1_NVM_DEBUG_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_nvm_structs.h" + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef VL53L1_LOG_ENABLE + + + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags); + + + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_nvm_map.h b/drivers/input/misc/vl53L1/inc/vl53l1_nvm_map.h new file mode 100644 index 0000000000000000000000000000000000000000..795bfe007d823b820d2c2846e14c685a8e15bbb8 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_nvm_map.h @@ -0,0 +1,447 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + + + +#ifndef _VL53L1_NVM_MAP_H_ +#define _VL53L1_NVM_MAP_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +#define VL53L1_NVM__IDENTIFICATION__MODEL_ID 0x0008 + +#define VL53L1_NVM__IDENTIFICATION__MODULE_TYPE 0x000C + +#define VL53L1_NVM__IDENTIFICATION__REVISION_ID 0x000D + +#define VL53L1_NVM__IDENTIFICATION__MODULE_ID 0x000E + +#define VL53L1_NVM__I2C_VALID 0x0010 + +#define VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS 0x0011 + +#define VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY 0x0014 + +#define VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX 0x0016 + +#define VL53L1_NVM__EWS__FAST_OSC_FREQ_SET 0x0017 + +#define VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION 0x0018 + +#define VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY 0x001C + +#define VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX 0x001E + +#define VL53L1_NVM__FMT__FAST_OSC_FREQ_SET 0x001F + +#define VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION 0x0020 + +#define VL53L1_NVM__VHV_CONFIG_UNLOCK 0x0028 + +#define VL53L1_NVM__REF_SELVDDPIX 0x0029 + +#define VL53L1_NVM__REF_SELVQUENCH 0x002A + +#define VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL 0x002B + +#define VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x002C + +#define VL53L1_NVM__VHV_CONFIG__COUNT_THRESH 0x002D + +#define VL53L1_NVM__VHV_CONFIG__OFFSET 0x002E + +#define VL53L1_NVM__VHV_CONFIG__INIT 0x002F + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL 0x0030 + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL 0x0031 + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL 0x0032 + +#define VL53L1_NVM__LASER_SAFETY__MULT_LL 0x0034 + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LL 0x0035 + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD 0x0038 + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD 0x0039 + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD 0x003A + +#define VL53L1_NVM__LASER_SAFETY__MULT_LD 0x003C + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LD 0x003D + +#define VL53L1_NVM__LASER_SAFETY_LOCK_BYTE 0x0040 + +#define VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE 0x0044 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_ 0x0048 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_1_ 0x0049 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_2_ 0x004A + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_3_ 0x004B + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_4_ 0x004C + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_5_ 0x004D + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_6_ 0x004E + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_7_ 0x004F + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_8_ 0x0050 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_9_ 0x0051 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_10_ 0x0052 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_11_ 0x0053 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_12_ 0x0054 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_13_ 0x0055 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_14_ 0x0056 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_15_ 0x0057 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_16_ 0x0058 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_17_ 0x0059 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_18_ 0x005A + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_19_ 0x005B + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_20_ 0x005C + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_21_ 0x005D + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_22_ 0x005E + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_23_ 0x005F + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_24_ 0x0060 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_25_ 0x0061 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_26_ 0x0062 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_27_ 0x0063 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_28_ 0x0064 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_29_ 0x0065 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_30_ 0x0066 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_31_ 0x0067 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_ 0x0068 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_1_ 0x0069 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_2_ 0x006A + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_3_ 0x006B + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_4_ 0x006C + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_5_ 0x006D + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_ 0x0070 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_1_ 0x0071 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_2_ 0x0072 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_3_ 0x0073 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_4_ 0x0074 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_5_ 0x0075 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_ 0x0078 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_1_ 0x0079 + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_2_ 0x007A + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_3_ 0x007B + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_4_ 0x007C + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_5_ 0x007D + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_ 0x0080 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_1_ 0x0081 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_2_ 0x0082 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_3_ 0x0083 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_4_ 0x0084 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_5_ 0x0085 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_6_ 0x0086 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_7_ 0x0087 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_8_ 0x0088 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_9_ 0x0089 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_10_ 0x008A + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_11_ 0x008B + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_12_ 0x008C + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_13_ 0x008D + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_14_ 0x008E + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_15_ 0x008F + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_16_ 0x0090 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_17_ 0x0091 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_18_ 0x0092 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_19_ 0x0093 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_20_ 0x0094 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_21_ 0x0095 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_22_ 0x0096 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_23_ 0x0097 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_24_ 0x0098 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_25_ 0x0099 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_26_ 0x009A + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_27_ 0x009B + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_28_ 0x009C + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_29_ 0x009D + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_30_ 0x009E + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_31_ 0x009F + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_ 0x00A0 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_1_ 0x00A1 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_2_ 0x00A2 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_3_ 0x00A3 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_4_ 0x00A4 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_5_ 0x00A5 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_ 0x00A8 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_1_ 0x00A9 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_2_ 0x00AA + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_3_ 0x00AB + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_4_ 0x00AC + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_5_ 0x00AD + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_ 0x00B0 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_1_ 0x00B1 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_2_ 0x00B2 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_3_ 0x00B3 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_4_ 0x00B4 + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_5_ 0x00B5 + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x00B8 + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE 0x00B9 + +#define VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00BC + +#define VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION 0x00BD + +#define VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM 0x00C0 + +#define VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM 0x00C2 + +#define VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00C4 + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00C8 + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00CA + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00CC + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00CE + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00CF + +#define VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED 0x00E0 + +#define VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS 0x00E4 + +#define VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00E8 + +#define VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION 0x00E9 + +#define VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM 0x00EC + +#define VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM 0x00EE + +#define VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00F0 + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00F4 + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00F6 + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00F8 + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00FA + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00FB + +#define VL53L1_NVM__FMT__FGC__BYTE_0 0x01DC + +#define VL53L1_NVM__FMT__FGC__BYTE_1 0x01DD + +#define VL53L1_NVM__FMT__FGC__BYTE_2 0x01DE + +#define VL53L1_NVM__FMT__FGC__BYTE_3 0x01DF + +#define VL53L1_NVM__FMT__FGC__BYTE_4 0x01E0 + +#define VL53L1_NVM__FMT__FGC__BYTE_5 0x01E1 + +#define VL53L1_NVM__FMT__FGC__BYTE_6 0x01E2 + +#define VL53L1_NVM__FMT__FGC__BYTE_7 0x01E3 + +#define VL53L1_NVM__FMT__FGC__BYTE_8 0x01E4 + +#define VL53L1_NVM__FMT__FGC__BYTE_9 0x01E5 + +#define VL53L1_NVM__FMT__FGC__BYTE_10 0x01E6 + +#define VL53L1_NVM__FMT__FGC__BYTE_11 0x01E7 + +#define VL53L1_NVM__FMT__FGC__BYTE_12 0x01E8 + +#define VL53L1_NVM__FMT__FGC__BYTE_13 0x01E9 + +#define VL53L1_NVM__FMT__FGC__BYTE_14 0x01EA + +#define VL53L1_NVM__FMT__FGC__BYTE_15 0x01EB + +#define VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR 0x01EC + +#define VL53L1_NVM__FMT__MAP_MAJOR_MINOR 0x01ED + +#define VL53L1_NVM__FMT__YEAR_MONTH 0x01EE + +#define VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE 0x01EF + +#define VL53L1_NVM__FMT__TIME 0x01F0 + +#define VL53L1_NVM__FMT__TESTER_ID 0x01F2 + +#define VL53L1_NVM__FMT__SITE_ID 0x01F3 + +#define VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR 0x01F4 + +#define VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR 0x01F5 + +#define VL53L1_NVM__EWS__TESTER_ID 0x01F6 + +#define VL53L1_NVM__EWS__LOT__BYTE_0 0x01F8 + +#define VL53L1_NVM__EWS__LOT__BYTE_1 0x01F9 + +#define VL53L1_NVM__EWS__LOT__BYTE_2 0x01FA + +#define VL53L1_NVM__EWS__LOT__BYTE_3 0x01FB + +#define VL53L1_NVM__EWS__LOT__BYTE_4 0x01FC + +#define VL53L1_NVM__EWS__LOT__BYTE_5 0x01FD + +#define VL53L1_NVM__EWS__WAFER 0x01FD + +#define VL53L1_NVM__EWS__XCOORD 0x01FE + +#define VL53L1_NVM__EWS__YCOORD 0x01FF + + +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX 0x00B8 +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE 4 + +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX 0x015C +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE 56 + +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX 0x0194 +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE 8 + +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE 0x019C +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK 0x01AC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK 0x01BC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT 0x01CC +#define VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES 16 + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_nvm_structs.h b/drivers/input/misc/vl53L1/inc/vl53l1_nvm_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..caeac2add3f704e37b25799aa8e14fa385f9fb10 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_nvm_structs.h @@ -0,0 +1,297 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + + + +#ifndef _VL53L1_NVM_STRUCTS_H_ +#define _VL53L1_NVM_STRUCTS_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "vl53l1_platform.h" +#include "vl53l1_ll_def.h" + + + + +typedef struct { + + uint16_t result__actual_effective_rtn_spads; + + uint8_t ref_spad_array__num_requested_ref_spads; + + uint8_t ref_spad_array__ref_location; + + uint16_t result__peak_signal_count_rate_rtn_mcps; + + uint16_t result__ambient_count_rate_rtn_mcps; + + uint16_t result__peak_signal_count_rate_ref_mcps; + + uint16_t result__ambient_count_rate_ref_mcps; + + uint16_t measured_distance_mm; + + uint16_t measured_distance_stdev_mm; + + +} VL53L1_decoded_nvm_fmt_range_data_t; + + + + +typedef struct { + + char nvm__fmt__fgc[19]; + + uint8_t nvm__fmt__test_program_major; + + uint8_t nvm__fmt__test_program_minor; + + uint8_t nvm__fmt__map_major; + + uint8_t nvm__fmt__map_minor; + + uint8_t nvm__fmt__year; + + uint8_t nvm__fmt__month; + + uint8_t nvm__fmt__day; + + uint8_t nvm__fmt__module_date_phase; + + uint16_t nvm__fmt__time; + + uint8_t nvm__fmt__tester_id; + + uint8_t nvm__fmt__site_id; + + uint8_t nvm__ews__test_program_major; + + uint8_t nvm__ews__test_program_minor; + + uint8_t nvm__ews__probe_card_major; + + uint8_t nvm__ews__probe_card_minor; + + uint8_t nvm__ews__tester_id; + + + char nvm__ews__lot[8]; + + uint8_t nvm__ews__wafer; + + uint8_t nvm__ews__xcoord; + + uint8_t nvm__ews__ycoord; + +} VL53L1_decoded_nvm_fmt_info_t; + + + + +typedef struct { + + uint8_t nvm__ews__test_program_major; + + uint8_t nvm__ews__test_program_minor; + + uint8_t nvm__ews__probe_card_major; + + uint8_t nvm__ews__probe_card_minor; + + uint8_t nvm__ews__tester_id; + + + char nvm__ews__lot[8]; + + uint8_t nvm__ews__wafer; + + uint8_t nvm__ews__xcoord; + + uint8_t nvm__ews__ycoord; + + +} VL53L1_decoded_nvm_ews_info_t; + + + + +typedef struct { + uint8_t nvm__identification_model_id; + + uint8_t nvm__identification_module_type; + + uint8_t nvm__identification_revision_id; + + uint16_t nvm__identification_module_id; + + uint8_t nvm__i2c_valid; + + uint8_t nvm__i2c_device_address_ews; + + uint16_t nvm__ews__fast_osc_frequency; + + uint8_t nvm__ews__fast_osc_trim_max; + + uint8_t nvm__ews__fast_osc_freq_set; + + uint16_t nvm__ews__slow_osc_calibration; + + uint16_t nvm__fmt__fast_osc_frequency; + + uint8_t nvm__fmt__fast_osc_trim_max; + + uint8_t nvm__fmt__fast_osc_freq_set; + + uint16_t nvm__fmt__slow_osc_calibration; + + uint8_t nvm__vhv_config_unlock; + + uint8_t nvm__ref_selvddpix; + + uint8_t nvm__ref_selvquench; + + uint8_t nvm__regavdd1v2_sel; + + uint8_t nvm__regdvdd1v2_sel; + + uint8_t nvm__vhv_timeout__macrop; + + uint8_t nvm__vhv_loop_bound; + + uint8_t nvm__vhv_count_threshold; + + uint8_t nvm__vhv_offset; + + uint8_t nvm__vhv_init_enable; + + uint8_t nvm__vhv_init_value; + + uint8_t nvm__laser_safety_vcsel_trim_ll; + + uint8_t nvm__laser_safety_vcsel_selion_ll; + + uint8_t nvm__laser_safety_vcsel_selion_max_ll; + + uint8_t nvm__laser_safety_mult_ll; + + uint8_t nvm__laser_safety_clip_ll; + + uint8_t nvm__laser_safety_vcsel_trim_ld; + + uint8_t nvm__laser_safety_vcsel_selion_ld; + + uint8_t nvm__laser_safety_vcsel_selion_max_ld; + + uint8_t nvm__laser_safety_mult_ld; + + uint8_t nvm__laser_safety_clip_ld; + + uint8_t nvm__laser_safety_lock_byte; + + uint8_t nvm__laser_safety_unlock_byte; + + uint8_t nvm__ews__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + uint8_t nvm__ews__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + uint8_t nvm__ews__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + uint8_t nvm__ews__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + uint8_t nvm__fmt__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + uint8_t nvm__fmt__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + uint8_t nvm__fmt__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + uint8_t nvm__fmt__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + uint8_t nvm__fmt__roi_config__mode_roi_centre_spad; + + uint8_t nvm__fmt__roi_config__mode_roi_x_size; + + uint8_t nvm__fmt__roi_config__mode_roi_y_size; + + uint8_t nvm__fmt__ref_spad_apply__num_requested_ref_spad; + + uint8_t nvm__fmt__ref_spad_man__ref_location; + + uint16_t nvm__fmt__mm_config__inner_offset_mm; + + uint16_t nvm__fmt__mm_config__outer_offset_mm; + + uint16_t nvm__fmt__algo_part_to_part_range_offset_mm; + + uint16_t nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps; + + uint16_t nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps; + + uint16_t nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps; + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_0; + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_1; + + uint8_t nvm__customer_space_programmed; + + uint8_t nvm__cust__i2c_device_address; + + uint8_t nvm__cust__ref_spad_apply__num_requested_ref_spad; + + uint8_t nvm__cust__ref_spad_man__ref_location; + + uint16_t nvm__cust__mm_config__inner_offset_mm; + + uint16_t nvm__cust__mm_config__outer_offset_mm; + + uint16_t nvm__cust__algo_part_to_part_range_offset_mm; + + uint16_t nvm__cust__algo__crosstalk_compensation_plane_offset_kcps; + + uint16_t nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps; + + uint16_t nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps; + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_0; + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_1; + + + VL53L1_optical_centre_t fmt_optical_centre; + VL53L1_cal_peak_rate_map_t fmt_peak_rate_map; + VL53L1_additional_offset_cal_data_t fmt_add_offset_data; + + VL53L1_decoded_nvm_fmt_range_data_t + fmt_range_data[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + VL53L1_decoded_nvm_fmt_info_t fmt_info; + VL53L1_decoded_nvm_ews_info_t ews_info; + +} VL53L1_decoded_nvm_data_t; + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_preset_setup.h b/drivers/input/misc/vl53L1/inc/vl53l1_preset_setup.h new file mode 100644 index 0000000000000000000000000000000000000000..834273efdc6af703cf78a5d0d56be96ffaa78556 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_preset_setup.h @@ -0,0 +1,67 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +#ifndef _VL53L1_PRESET_SETUP_H_ +#define _VL53L1_PRESET_SETUP_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* indexes for the bare driver tuning setting API function */ +enum VL53L1_Tuning_t { + VL53L1_TUNING_VERSION = 0, + VL53L1_TUNING_PROXY_MIN, + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID, + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT, + VL53L1_TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN, + VL53L1_TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET, + VL53L1_TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR, + VL53L1_TUNING_MAX_TUNABLE_KEY +}; + +/* default values for the tuning settings parameters */ +#define TUNING_VERSION 0x0007 + +#define TUNING_PROXY_MIN -30 /* min distance in mm */ +#define TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM 600 +/* Target distance in mm for single target Xtalk */ +#define TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER 50 +/* Number of sample used for single target Xtalk */ +#define TUNING_MIN_AMBIENT_DMAX_VALID 8 +/* Minimum ambient level to state the Dmax returned by the device is valid */ +#define TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER 10 +/* Maximum loops to perform simple offset calibration */ +#define TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM 600 +/* Target distance in mm for target Xtalk from Bins method*/ +#define TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT 3 +/* Number of loops done during the simple offset calibration*/ +#define TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR_DEFAULT 9 +/* zero distance offset calibration non linear compensation default value */ + +/* The following settings are related to the fix for ticket EwokP #558410 */ +#define TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN 24 +/* Acceptance margin for the xtalk_shape bin_data sum computation */ +#define TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET 50 +/* Recovery value for Xtalk compensation plane offset in kcps */ +/* 50 stands for ~0.10 kcps cover glass in 7.9 format */ +/* End of settings related to the fix for ticket EwokP #558410 */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_PRESET_SETUP_H_ */ diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_register_funcs.h b/drivers/input/misc/vl53L1/inc/vl53l1_register_funcs.h new file mode 100644 index 0000000000000000000000000000000000000000..7e1185b4cb47275b341aefadcec28f503f2f41ee --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_register_funcs.h @@ -0,0 +1,662 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_REGISTER_FUNCS_H_ +#define _VL53L1_REGISTER_FUNCS_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata); + + + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata); + + + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata); + + + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata); + + + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata); + + + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata); + + + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata); + + + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata); + + + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata); + + + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata); + + + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata); + + + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata); + + + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata); + + + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_register_map.h b/drivers/input/misc/vl53L1/inc/vl53l1_register_map.h new file mode 100644 index 0000000000000000000000000000000000000000..148a9c15252e11870a6d8a20335614fcf041eb58 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_register_map.h @@ -0,0 +1,2390 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_REGISTER_MAP_H_ +#define _VL53L1_REGISTER_MAP_H_ + + + +#define VL53L1_SOFT_RESET 0x0000 + +#define VL53L1_I2C_SLAVE__DEVICE_ADDRESS 0x0001 + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VDDPIX 0x0002 + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VQUENCH 0x0003 + +#define VL53L1_ANA_CONFIG__REG_AVDD1V2_SEL 0x0004 + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM 0x0005 + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY 0x0006 + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_HI 0x0006 + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_LO 0x0007 + +#define VL53L1_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x0008 + +#define VL53L1_VHV_CONFIG__COUNT_THRESH 0x0009 + +#define VL53L1_VHV_CONFIG__OFFSET 0x000A + +#define VL53L1_VHV_CONFIG__INIT 0x000B + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 0x000D + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_1 0x000E + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_2 0x000F + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_3 0x0010 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_4 0x0011 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_5 0x0012 + +#define VL53L1_GLOBAL_CONFIG__REF_EN_START_SELECT 0x0013 + +#define VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS 0x0014 + +#define VL53L1_REF_SPAD_MAN__REF_LOCATION 0x0015 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x0016 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_HI 0x0016 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_LO 0x0017 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS 0x0018 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_HI 0x0018 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_LO 0x0019 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS 0x001A + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_HI 0x001A + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_LO 0x001B + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS 0x001C + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_HI 0x001C + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_LO 0x001D + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x001E + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_HI 0x001E + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_LO 0x001F + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM 0x0020 + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_HI 0x0020 + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_LO 0x0021 + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM 0x0022 + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_HI 0x0022 + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_LO 0x0023 + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS 0x0024 + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_HI 0x0024 + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_LO 0x0025 + +#define VL53L1_DEBUG__CTRL 0x0026 + +#define VL53L1_TEST_MODE__CTRL 0x0027 + +#define VL53L1_CLK_GATING__CTRL 0x0028 + +#define VL53L1_NVM_BIST__CTRL 0x0029 + +#define VL53L1_NVM_BIST__NUM_NVM_WORDS 0x002A + +#define VL53L1_NVM_BIST__START_ADDRESS 0x002B + +#define VL53L1_HOST_IF__STATUS 0x002C + +#define VL53L1_PAD_I2C_HV__CONFIG 0x002D + +#define VL53L1_PAD_I2C_HV__EXTSUP_CONFIG 0x002E + +#define VL53L1_GPIO_HV_PAD__CTRL 0x002F + +#define VL53L1_GPIO_HV_MUX__CTRL 0x0030 + +#define VL53L1_GPIO__TIO_HV_STATUS 0x0031 + +#define VL53L1_GPIO__FIO_HV_STATUS 0x0032 + +#define VL53L1_ANA_CONFIG__SPAD_SEL_PSWIDTH 0x0033 + +#define VL53L1_ANA_CONFIG__VCSEL_PULSE_WIDTH_OFFSET 0x0034 + +#define VL53L1_ANA_CONFIG__FAST_OSC__CONFIG_CTRL 0x0035 + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS 0x0036 + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS 0x0037 + +#define VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM 0x0038 + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_VALID_HEIGHT_MM 0x0039 + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_0 0x003A + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_1 0x003B + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS 0x003C + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_HI 0x003C + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_LO 0x003D + +#define VL53L1_ALGO__RANGE_IGNORE_VALID_HEIGHT_MM 0x003E + +#define VL53L1_ALGO__RANGE_MIN_CLIP 0x003F + +#define VL53L1_ALGO__CONSISTENCY_CHECK__TOLERANCE 0x0040 + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_2 0x0041 + +#define VL53L1_SD_CONFIG__RESET_STAGES_MSB 0x0042 + +#define VL53L1_SD_CONFIG__RESET_STAGES_LSB 0x0043 + +#define VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE 0x0044 + +#define VL53L1_GLOBAL_CONFIG__STREAM_DIVIDER 0x0045 + +#define VL53L1_SYSTEM__INTERRUPT_CONFIG_GPIO 0x0046 + +#define VL53L1_CAL_CONFIG__VCSEL_START 0x0047 + +#define VL53L1_CAL_CONFIG__REPEAT_RATE 0x0048 + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_HI 0x0048 + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_LO 0x0049 + +#define VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH 0x004A + +#define VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP 0x004B + +#define VL53L1_PHASECAL_CONFIG__TARGET 0x004C + +#define VL53L1_PHASECAL_CONFIG__OVERRIDE 0x004D + +#define VL53L1_DSS_CONFIG__ROI_MODE_CONTROL 0x004F + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH 0x0050 + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_HI 0x0050 + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_LO 0x0051 + +#define VL53L1_SYSTEM__THRESH_RATE_LOW 0x0052 + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_HI 0x0052 + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_LO 0x0053 + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0054 + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0054 + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0055 + +#define VL53L1_DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0056 + +#define VL53L1_DSS_CONFIG__APERTURE_ATTENUATION 0x0057 + +#define VL53L1_DSS_CONFIG__MAX_SPADS_LIMIT 0x0058 + +#define VL53L1_DSS_CONFIG__MIN_SPADS_LIMIT 0x0059 + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI 0x005A + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_LO 0x005B + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_HI 0x005C + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_LO 0x005D + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x005E + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x005F + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A 0x0060 + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0061 + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0062 + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_B 0x0063 + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH 0x0064 + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_HI 0x0064 + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_LO 0x0065 + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0066 + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0066 + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0067 + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_LOW 0x0068 + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_HIGH 0x0069 + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD 0x006C + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_3 0x006C + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_2 0x006D + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_1 0x006E + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_0 0x006F + +#define VL53L1_SYSTEM__FRACTIONAL_ENABLE 0x0070 + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 0x0071 + +#define VL53L1_SYSTEM__THRESH_HIGH 0x0072 + +#define VL53L1_SYSTEM__THRESH_HIGH_HI 0x0072 + +#define VL53L1_SYSTEM__THRESH_HIGH_LO 0x0073 + +#define VL53L1_SYSTEM__THRESH_LOW 0x0074 + +#define VL53L1_SYSTEM__THRESH_LOW_HI 0x0074 + +#define VL53L1_SYSTEM__THRESH_LOW_LO 0x0075 + +#define VL53L1_SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x0076 + +#define VL53L1_SYSTEM__SEED_CONFIG 0x0077 + +#define VL53L1_SD_CONFIG__WOI_SD0 0x0078 + +#define VL53L1_SD_CONFIG__WOI_SD1 0x0079 + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD0 0x007A + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD1 0x007B + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_1 0x007C + +#define VL53L1_SD_CONFIG__FIRST_ORDER_SELECT 0x007D + +#define VL53L1_SD_CONFIG__QUANTIFIER 0x007E + +#define VL53L1_ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x007F + +#define VL53L1_ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x0080 + +#define VL53L1_SYSTEM__SEQUENCE_CONFIG 0x0081 + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD 0x0082 + +#define VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE 0x0083 + +#define VL53L1_SYSTEM__STREAM_COUNT_CTRL 0x0084 + +#define VL53L1_FIRMWARE__ENABLE 0x0085 + +#define VL53L1_SYSTEM__INTERRUPT_CLEAR 0x0086 + +#define VL53L1_SYSTEM__MODE_START 0x0087 + +#define VL53L1_RESULT__INTERRUPT_STATUS 0x0088 + +#define VL53L1_RESULT__RANGE_STATUS 0x0089 + +#define VL53L1_RESULT__REPORT_STATUS 0x008A + +#define VL53L1_RESULT__STREAM_COUNT 0x008B + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x008C + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x008C + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x008D + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x008E + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x008E + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x008F + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0090 + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0090 + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0091 + +#define VL53L1_RESULT__SIGMA_SD0 0x0092 + +#define VL53L1_RESULT__SIGMA_SD0_HI 0x0092 + +#define VL53L1_RESULT__SIGMA_SD0_LO 0x0093 + +#define VL53L1_RESULT__PHASE_SD0 0x0094 + +#define VL53L1_RESULT__PHASE_SD0_HI 0x0094 + +#define VL53L1_RESULT__PHASE_SD0_LO 0x0095 + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0096 + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0096 + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0097 + +#define VL53L1_PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0098 + +#define VL53L1__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0098 + +#define VL53L1___PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0099 + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009A + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009A + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009B + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009C + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009C + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009D + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x009E + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x009E + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x009F + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x00A0 + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x00A0 + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x00A1 + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x00A2 + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x00A2 + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x00A3 + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x00A4 + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x00A4 + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x00A5 + +#define VL53L1_RESULT__SIGMA_SD1 0x00A6 + +#define VL53L1_RESULT__SIGMA_SD1_HI 0x00A6 + +#define VL53L1_RESULT__SIGMA_SD1_LO 0x00A7 + +#define VL53L1_RESULT__PHASE_SD1 0x00A8 + +#define VL53L1_RESULT__PHASE_SD1_HI 0x00A8 + +#define VL53L1_RESULT__PHASE_SD1_LO 0x00A9 + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x00AA + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x00AA + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x00AB + +#define VL53L1_RESULT__SPARE_0_SD1 0x00AC + +#define VL53L1_RESULT__SPARE_0_SD1_HI 0x00AC + +#define VL53L1_RESULT__SPARE_0_SD1_LO 0x00AD + +#define VL53L1_RESULT__SPARE_1_SD1 0x00AE + +#define VL53L1_RESULT__SPARE_1_SD1_HI 0x00AE + +#define VL53L1_RESULT__SPARE_1_SD1_LO 0x00AF + +#define VL53L1_RESULT__SPARE_2_SD1 0x00B0 + +#define VL53L1_RESULT__SPARE_2_SD1_HI 0x00B0 + +#define VL53L1_RESULT__SPARE_2_SD1_LO 0x00B1 + +#define VL53L1_RESULT__SPARE_3_SD1 0x00B2 + +#define VL53L1_RESULT__THRESH_INFO 0x00B3 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x00B4 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x00B4 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x00B5 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x00B6 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x00B7 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x00B8 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x00B8 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x00B9 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x00BA + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x00BB + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x00BC + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x00BC + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x00BD + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x00BE + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x00BF + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x00C0 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x00C0 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x00C1 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x00C2 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x00C3 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x00C4 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x00C4 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x00C5 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x00C6 + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x00C7 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x00C8 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x00C8 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x00C9 + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x00CA + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x00CB + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x00CC + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x00CC + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x00CD + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x00CE + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x00CF + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x00D0 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x00D0 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x00D1 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x00D2 + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x00D3 + +#define VL53L1_RESULT_CORE__SPARE_0 0x00D4 + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE 0x00D6 + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x00D6 + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x00D7 + +#define VL53L1_PHASECAL_RESULT__VCSEL_START 0x00D8 + +#define VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS 0x00D9 + +#define VL53L1_REF_SPAD_CHAR_RESULT__REF_LOCATION 0x00DA + +#define VL53L1_VHV_RESULT__COLDBOOT_STATUS 0x00DB + +#define VL53L1_VHV_RESULT__SEARCH_RESULT 0x00DC + +#define VL53L1_VHV_RESULT__LATEST_SETTING 0x00DD + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL 0x00DE + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_HI 0x00DE + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_LO 0x00DF + +#define VL53L1_ANA_CONFIG__POWERDOWN_GO1 0x00E0 + +#define VL53L1_ANA_CONFIG__REF_BG_CTRL 0x00E1 + +#define VL53L1_ANA_CONFIG__REGDVDD1V2_CTRL 0x00E2 + +#define VL53L1_ANA_CONFIG__OSC_SLOW_CTRL 0x00E3 + +#define VL53L1_TEST_MODE__STATUS 0x00E4 + +#define VL53L1_FIRMWARE__SYSTEM_STATUS 0x00E5 + +#define VL53L1_FIRMWARE__MODE_STATUS 0x00E6 + +#define VL53L1_FIRMWARE__SECONDARY_MODE_STATUS 0x00E7 + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER 0x00E8 + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_HI 0x00E8 + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_LO 0x00E9 + +#define VL53L1_FIRMWARE__HISTOGRAM_BIN 0x00EA + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH 0x00EC + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_HI 0x00EC + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_LO 0x00ED + +#define VL53L1_GPH__SYSTEM__THRESH_LOW 0x00EE + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_HI 0x00EE + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_LO 0x00EF + +#define VL53L1_GPH__SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x00F0 + +#define VL53L1_GPH__SPARE_0 0x00F1 + +#define VL53L1_GPH__SD_CONFIG__WOI_SD0 0x00F2 + +#define VL53L1_GPH__SD_CONFIG__WOI_SD1 0x00F3 + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD0 0x00F4 + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD1 0x00F5 + +#define VL53L1_GPH__SD_CONFIG__FIRST_ORDER_SELECT 0x00F6 + +#define VL53L1_GPH__SD_CONFIG__QUANTIFIER 0x00F7 + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x00F8 + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x00F9 + +#define VL53L1_GPH__SYSTEM__SEQUENCE_CONFIG 0x00FA + +#define VL53L1_GPH__GPH_ID 0x00FB + +#define VL53L1_SYSTEM__INTERRUPT_SET 0x00FC + +#define VL53L1_INTERRUPT_MANAGER__ENABLES 0x00FD + +#define VL53L1_INTERRUPT_MANAGER__CLEAR 0x00FE + +#define VL53L1_INTERRUPT_MANAGER__STATUS 0x00FF + +#define VL53L1_MCU_TO_HOST_BANK__WR_ACCESS_EN 0x0100 + +#define VL53L1_POWER_MANAGEMENT__GO1_RESET_STATUS 0x0101 + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO 0x0102 + +#define VL53L1_PAD_STARTUP_MODE__VALUE_CTRL 0x0103 + +#define VL53L1_PLL_PERIOD_US 0x0104 + +#define VL53L1_PLL_PERIOD_US_3 0x0104 + +#define VL53L1_PLL_PERIOD_US_2 0x0105 + +#define VL53L1_PLL_PERIOD_US_1 0x0106 + +#define VL53L1_PLL_PERIOD_US_0 0x0107 + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT 0x0108 + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_3 0x0108 + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_2 0x0109 + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_1 0x010A + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_0 0x010B + +#define VL53L1_NVM_BIST__COMPLETE 0x010C + +#define VL53L1_NVM_BIST__STATUS 0x010D + +#define VL53L1_IDENTIFICATION__MODEL_ID 0x010F + +#define VL53L1_IDENTIFICATION__MODULE_TYPE 0x0110 + +#define VL53L1_IDENTIFICATION__REVISION_ID 0x0111 + +#define VL53L1_IDENTIFICATION__MODULE_ID 0x0112 + +#define VL53L1_IDENTIFICATION__MODULE_ID_HI 0x0112 + +#define VL53L1_IDENTIFICATION__MODULE_ID_LO 0x0113 + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM_MAX 0x0114 + +#define VL53L1_ANA_CONFIG__FAST_OSC__FREQ_SET 0x0115 + +#define VL53L1_ANA_CONFIG__VCSEL_TRIM 0x0116 + +#define VL53L1_ANA_CONFIG__VCSEL_SELION 0x0117 + +#define VL53L1_ANA_CONFIG__VCSEL_SELION_MAX 0x0118 + +#define VL53L1_PROTECTED_LASER_SAFETY__LOCK_BIT 0x0119 + +#define VL53L1_LASER_SAFETY__KEY 0x011A + +#define VL53L1_LASER_SAFETY__KEY_RO 0x011B + +#define VL53L1_LASER_SAFETY__CLIP 0x011C + +#define VL53L1_LASER_SAFETY__MULT 0x011D + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_0 0x011E + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_1 0x011F + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_2 0x0120 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_3 0x0121 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_4 0x0122 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_5 0x0123 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_6 0x0124 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_7 0x0125 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_8 0x0126 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_9 0x0127 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_10 0x0128 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_11 0x0129 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_12 0x012A + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_13 0x012B + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_14 0x012C + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_15 0x012D + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_16 0x012E + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_17 0x012F + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_18 0x0130 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_19 0x0131 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_20 0x0132 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_21 0x0133 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_22 0x0134 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_23 0x0135 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_24 0x0136 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_25 0x0137 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_26 0x0138 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_27 0x0139 + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_28 0x013A + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_29 0x013B + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_30 0x013C + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_31 0x013D + +#define VL53L1_ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x013E + +#define VL53L1_ROI_CONFIG__MODE_ROI_XY_SIZE 0x013F + +#define VL53L1_GO2_HOST_BANK_ACCESS__OVERRIDE 0x0300 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND 0x0400 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_3 0x0400 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_2 0x0401 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_1 0x0402 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_0 0x0403 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER 0x0404 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_3 0x0404 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_2 0x0405 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_1 0x0406 + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_0 0x0407 + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI 0x0408 + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_3 0x0408 + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_2 0x0409 + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_1 0x040A + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_0 0x040B + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO 0x040C + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_3 0x040C + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_2 0x040D + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_1 0x040E + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_0 0x040F + +#define VL53L1_MCU_UTIL_MULTIPLIER__START 0x0410 + +#define VL53L1_MCU_UTIL_MULTIPLIER__STATUS 0x0411 + +#define VL53L1_MCU_UTIL_DIVIDER__START 0x0412 + +#define VL53L1_MCU_UTIL_DIVIDER__STATUS 0x0413 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND 0x0414 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_3 0x0414 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_2 0x0415 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_1 0x0416 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_0 0x0417 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR 0x0418 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_3 0x0418 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_2 0x0419 + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_1 0x041A + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_0 0x041B + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT 0x041C + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_3 0x041C + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_2 0x041D + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_1 0x041E + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_0 0x041F + +#define VL53L1_TIMER0__VALUE_IN 0x0420 + +#define VL53L1_TIMER0__VALUE_IN_3 0x0420 + +#define VL53L1_TIMER0__VALUE_IN_2 0x0421 + +#define VL53L1_TIMER0__VALUE_IN_1 0x0422 + +#define VL53L1_TIMER0__VALUE_IN_0 0x0423 + +#define VL53L1_TIMER1__VALUE_IN 0x0424 + +#define VL53L1_TIMER1__VALUE_IN_3 0x0424 + +#define VL53L1_TIMER1__VALUE_IN_2 0x0425 + +#define VL53L1_TIMER1__VALUE_IN_1 0x0426 + +#define VL53L1_TIMER1__VALUE_IN_0 0x0427 + +#define VL53L1_TIMER0__CTRL 0x0428 + +#define VL53L1_TIMER1__CTRL 0x0429 + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_0 0x042C + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_1 0x042D + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_2 0x042E + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_3 0x042F + +#define VL53L1_MCU_RANGE_CALC__CONFIG 0x0430 + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE 0x0432 + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_HI 0x0432 + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_LO 0x0433 + +#define VL53L1_MCU_RANGE_CALC__SPARE_4 0x0434 + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_3 0x0434 + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_2 0x0435 + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_1 0x0436 + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_0 0x0437 + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC 0x0438 + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_HI 0x0438 + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_LO 0x0439 + +#define VL53L1_MCU_RANGE_CALC__ALGO_VCSEL_PERIOD 0x043C + +#define VL53L1_MCU_RANGE_CALC__SPARE_5 0x043D + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS 0x043E + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_HI 0x043E + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_LO 0x043F + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE 0x0440 + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_3 0x0440 + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_2 0x0441 + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_1 0x0442 + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_0 0x0443 + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS 0x0444 + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_3 0x0444 + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_2 0x0445 + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_1 0x0446 + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_0 0x0447 + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS 0x0448 + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_3 0x0448 + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_2 0x0449 + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_1 0x044A + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_0 0x044B + +#define VL53L1_MCU_RANGE_CALC__SPARE_6 0x044C + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_HI 0x044C + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_LO 0x044D + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD 0x044E + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_HI 0x044E + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_LO 0x044F + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS 0x0450 + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_HI 0x0450 + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_LO 0x0451 + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT 0x0452 + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_HI 0x0452 + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_LO 0x0453 + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS 0x0454 + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_3 0x0454 + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_2 0x0455 + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_1 0x0456 + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_0 0x0457 + +#define VL53L1_MCU_RANGE_CALC__SPARE_7 0x0458 + +#define VL53L1_MCU_RANGE_CALC__SPARE_8 0x0459 + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS 0x045A + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_HI 0x045A + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_LO 0x045B + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS 0x045C + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_HI 0x045C + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_LO 0x045D + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS 0x045E + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_HI 0x045E + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_LO 0x045F + +#define VL53L1_MCU_RANGE_CALC__XTALK 0x0460 + +#define VL53L1_MCU_RANGE_CALC__XTALK_HI 0x0460 + +#define VL53L1_MCU_RANGE_CALC__XTALK_LO 0x0461 + +#define VL53L1_MCU_RANGE_CALC__CALC_STATUS 0x0462 + +#define VL53L1_MCU_RANGE_CALC__DEBUG 0x0463 + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS 0x0464 + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_HI 0x0464 + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_LO 0x0465 + +#define VL53L1_MCU_RANGE_CALC__SPARE_0 0x0468 + +#define VL53L1_MCU_RANGE_CALC__SPARE_1 0x0469 + +#define VL53L1_MCU_RANGE_CALC__SPARE_2 0x046A + +#define VL53L1_MCU_RANGE_CALC__SPARE_3 0x046B + +#define VL53L1_PATCH__CTRL 0x0470 + +#define VL53L1_PATCH__JMP_ENABLES 0x0472 + +#define VL53L1_PATCH__JMP_ENABLES_HI 0x0472 + +#define VL53L1_PATCH__JMP_ENABLES_LO 0x0473 + +#define VL53L1_PATCH__DATA_ENABLES 0x0474 + +#define VL53L1_PATCH__DATA_ENABLES_HI 0x0474 + +#define VL53L1_PATCH__DATA_ENABLES_LO 0x0475 + +#define VL53L1_PATCH__OFFSET_0 0x0476 + +#define VL53L1_PATCH__OFFSET_0_HI 0x0476 + +#define VL53L1_PATCH__OFFSET_0_LO 0x0477 + +#define VL53L1_PATCH__OFFSET_1 0x0478 + +#define VL53L1_PATCH__OFFSET_1_HI 0x0478 + +#define VL53L1_PATCH__OFFSET_1_LO 0x0479 + +#define VL53L1_PATCH__OFFSET_2 0x047A + +#define VL53L1_PATCH__OFFSET_2_HI 0x047A + +#define VL53L1_PATCH__OFFSET_2_LO 0x047B + +#define VL53L1_PATCH__OFFSET_3 0x047C + +#define VL53L1_PATCH__OFFSET_3_HI 0x047C + +#define VL53L1_PATCH__OFFSET_3_LO 0x047D + +#define VL53L1_PATCH__OFFSET_4 0x047E + +#define VL53L1_PATCH__OFFSET_4_HI 0x047E + +#define VL53L1_PATCH__OFFSET_4_LO 0x047F + +#define VL53L1_PATCH__OFFSET_5 0x0480 + +#define VL53L1_PATCH__OFFSET_5_HI 0x0480 + +#define VL53L1_PATCH__OFFSET_5_LO 0x0481 + +#define VL53L1_PATCH__OFFSET_6 0x0482 + +#define VL53L1_PATCH__OFFSET_6_HI 0x0482 + +#define VL53L1_PATCH__OFFSET_6_LO 0x0483 + +#define VL53L1_PATCH__OFFSET_7 0x0484 + +#define VL53L1_PATCH__OFFSET_7_HI 0x0484 + +#define VL53L1_PATCH__OFFSET_7_LO 0x0485 + +#define VL53L1_PATCH__OFFSET_8 0x0486 + +#define VL53L1_PATCH__OFFSET_8_HI 0x0486 + +#define VL53L1_PATCH__OFFSET_8_LO 0x0487 + +#define VL53L1_PATCH__OFFSET_9 0x0488 + +#define VL53L1_PATCH__OFFSET_9_HI 0x0488 + +#define VL53L1_PATCH__OFFSET_9_LO 0x0489 + +#define VL53L1_PATCH__OFFSET_10 0x048A + +#define VL53L1_PATCH__OFFSET_10_HI 0x048A + +#define VL53L1_PATCH__OFFSET_10_LO 0x048B + +#define VL53L1_PATCH__OFFSET_11 0x048C + +#define VL53L1_PATCH__OFFSET_11_HI 0x048C + +#define VL53L1_PATCH__OFFSET_11_LO 0x048D + +#define VL53L1_PATCH__OFFSET_12 0x048E + +#define VL53L1_PATCH__OFFSET_12_HI 0x048E + +#define VL53L1_PATCH__OFFSET_12_LO 0x048F + +#define VL53L1_PATCH__OFFSET_13 0x0490 + +#define VL53L1_PATCH__OFFSET_13_HI 0x0490 + +#define VL53L1_PATCH__OFFSET_13_LO 0x0491 + +#define VL53L1_PATCH__OFFSET_14 0x0492 + +#define VL53L1_PATCH__OFFSET_14_HI 0x0492 + +#define VL53L1_PATCH__OFFSET_14_LO 0x0493 + +#define VL53L1_PATCH__OFFSET_15 0x0494 + +#define VL53L1_PATCH__OFFSET_15_HI 0x0494 + +#define VL53L1_PATCH__OFFSET_15_LO 0x0495 + +#define VL53L1_PATCH__ADDRESS_0 0x0496 + +#define VL53L1_PATCH__ADDRESS_0_HI 0x0496 + +#define VL53L1_PATCH__ADDRESS_0_LO 0x0497 + +#define VL53L1_PATCH__ADDRESS_1 0x0498 + +#define VL53L1_PATCH__ADDRESS_1_HI 0x0498 + +#define VL53L1_PATCH__ADDRESS_1_LO 0x0499 + +#define VL53L1_PATCH__ADDRESS_2 0x049A + +#define VL53L1_PATCH__ADDRESS_2_HI 0x049A + +#define VL53L1_PATCH__ADDRESS_2_LO 0x049B + +#define VL53L1_PATCH__ADDRESS_3 0x049C + +#define VL53L1_PATCH__ADDRESS_3_HI 0x049C + +#define VL53L1_PATCH__ADDRESS_3_LO 0x049D + +#define VL53L1_PATCH__ADDRESS_4 0x049E + +#define VL53L1_PATCH__ADDRESS_4_HI 0x049E + +#define VL53L1_PATCH__ADDRESS_4_LO 0x049F + +#define VL53L1_PATCH__ADDRESS_5 0x04A0 + +#define VL53L1_PATCH__ADDRESS_5_HI 0x04A0 + +#define VL53L1_PATCH__ADDRESS_5_LO 0x04A1 + +#define VL53L1_PATCH__ADDRESS_6 0x04A2 + +#define VL53L1_PATCH__ADDRESS_6_HI 0x04A2 + +#define VL53L1_PATCH__ADDRESS_6_LO 0x04A3 + +#define VL53L1_PATCH__ADDRESS_7 0x04A4 + +#define VL53L1_PATCH__ADDRESS_7_HI 0x04A4 + +#define VL53L1_PATCH__ADDRESS_7_LO 0x04A5 + +#define VL53L1_PATCH__ADDRESS_8 0x04A6 + +#define VL53L1_PATCH__ADDRESS_8_HI 0x04A6 + +#define VL53L1_PATCH__ADDRESS_8_LO 0x04A7 + +#define VL53L1_PATCH__ADDRESS_9 0x04A8 + +#define VL53L1_PATCH__ADDRESS_9_HI 0x04A8 + +#define VL53L1_PATCH__ADDRESS_9_LO 0x04A9 + +#define VL53L1_PATCH__ADDRESS_10 0x04AA + +#define VL53L1_PATCH__ADDRESS_10_HI 0x04AA + +#define VL53L1_PATCH__ADDRESS_10_LO 0x04AB + +#define VL53L1_PATCH__ADDRESS_11 0x04AC + +#define VL53L1_PATCH__ADDRESS_11_HI 0x04AC + +#define VL53L1_PATCH__ADDRESS_11_LO 0x04AD + +#define VL53L1_PATCH__ADDRESS_12 0x04AE + +#define VL53L1_PATCH__ADDRESS_12_HI 0x04AE + +#define VL53L1_PATCH__ADDRESS_12_LO 0x04AF + +#define VL53L1_PATCH__ADDRESS_13 0x04B0 + +#define VL53L1_PATCH__ADDRESS_13_HI 0x04B0 + +#define VL53L1_PATCH__ADDRESS_13_LO 0x04B1 + +#define VL53L1_PATCH__ADDRESS_14 0x04B2 + +#define VL53L1_PATCH__ADDRESS_14_HI 0x04B2 + +#define VL53L1_PATCH__ADDRESS_14_LO 0x04B3 + +#define VL53L1_PATCH__ADDRESS_15 0x04B4 + +#define VL53L1_PATCH__ADDRESS_15_HI 0x04B4 + +#define VL53L1_PATCH__ADDRESS_15_LO 0x04B5 + +#define VL53L1_SPI_ASYNC_MUX__CTRL 0x04C0 + +#define VL53L1_CLK__CONFIG 0x04C4 + +#define VL53L1_GPIO_LV_MUX__CTRL 0x04CC + +#define VL53L1_GPIO_LV_PAD__CTRL 0x04CD + +#define VL53L1_PAD_I2C_LV__CONFIG 0x04D0 + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO_GO1 0x04D4 + +#define VL53L1_HOST_IF__STATUS_GO1 0x04D5 + +#define VL53L1_MCU_CLK_GATING__CTRL 0x04D8 + +#define VL53L1_TEST__BIST_ROM_CTRL 0x04E0 + +#define VL53L1_TEST__BIST_ROM_RESULT 0x04E1 + +#define VL53L1_TEST__BIST_ROM_MCU_SIG 0x04E2 + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_HI 0x04E2 + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_LO 0x04E3 + +#define VL53L1_TEST__BIST_RAM_CTRL 0x04E4 + +#define VL53L1_TEST__BIST_RAM_RESULT 0x04E5 + +#define VL53L1_TEST__TMC 0x04E8 + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD 0x04F0 + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_HI 0x04F0 + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_LO 0x04F1 + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD 0x04F2 + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_HI 0x04F2 + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_LO 0x04F3 + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT 0x04F4 + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_HI 0x04F4 + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_LO 0x04F5 + +#define VL53L1_TEST__PLL_BIST_GONOGO 0x04F6 + +#define VL53L1_TEST__PLL_BIST_CTRL 0x04F7 + +#define VL53L1_RANGING_CORE__DEVICE_ID 0x0680 + +#define VL53L1_RANGING_CORE__REVISION_ID 0x0681 + +#define VL53L1_RANGING_CORE__CLK_CTRL1 0x0683 + +#define VL53L1_RANGING_CORE__CLK_CTRL2 0x0684 + +#define VL53L1_RANGING_CORE__WOI_1 0x0685 + +#define VL53L1_RANGING_CORE__WOI_REF_1 0x0686 + +#define VL53L1_RANGING_CORE__START_RANGING 0x0687 + +#define VL53L1_RANGING_CORE__LOW_LIMIT_1 0x0690 + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_1 0x0691 + +#define VL53L1_RANGING_CORE__LOW_LIMIT_REF_1 0x0692 + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_REF_1 0x0693 + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_MSB 0x0694 + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_LSB 0x0695 + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_MSB 0x0696 + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_LSB 0x0697 + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_MSB 0x0698 + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_LSB 0x0699 + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_MSB 0x069A + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_LSB 0x069B + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_1 0x069C + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_REF_1 0x069D + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_MSB 0x069E + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_LSB 0x069F + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_MSB 0x06A0 + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_LSB 0x06A1 + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_MSB 0x06A4 + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_LSB 0x06A5 + +#define VL53L1_RANGING_CORE__INVERT_HW 0x06A6 + +#define VL53L1_RANGING_CORE__FORCE_HW 0x06A7 + +#define VL53L1_RANGING_CORE__STATIC_HW_VALUE 0x06A8 + +#define VL53L1_RANGING_CORE__FORCE_CONTINUOUS_AMBIENT 0x06A9 + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_FILTER 0x06AA + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_TIMING_GEN 0x06AB + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_1 0x06AC + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_REF_1 0x06AD + +#define VL53L1_RANGING_CORE__FORCE_UP_IN 0x06AE + +#define VL53L1_RANGING_CORE__FORCE_DN_IN 0x06AF + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_1 0x06B0 + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_REF_1 0x06B1 + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_1 0x06B2 + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_REF_1 0x06B3 + +#define VL53L1_RANGING_CORE__MONITOR_UP_DN 0x06B4 + +#define VL53L1_RANGING_CORE__INVERT_UP_DN 0x06B5 + +#define VL53L1_RANGING_CORE__CPUMP_1 0x06B6 + +#define VL53L1_RANGING_CORE__CPUMP_2 0x06B7 + +#define VL53L1_RANGING_CORE__CPUMP_3 0x06B8 + +#define VL53L1_RANGING_CORE__OSC_1 0x06B9 + +#define VL53L1_RANGING_CORE__PLL_1 0x06BB + +#define VL53L1_RANGING_CORE__PLL_2 0x06BC + +#define VL53L1_RANGING_CORE__REFERENCE_1 0x06BD + +#define VL53L1_RANGING_CORE__REFERENCE_3 0x06BF + +#define VL53L1_RANGING_CORE__REFERENCE_4 0x06C0 + +#define VL53L1_RANGING_CORE__REFERENCE_5 0x06C1 + +#define VL53L1_RANGING_CORE__REGAVDD1V2 0x06C3 + +#define VL53L1_RANGING_CORE__CALIB_1 0x06C4 + +#define VL53L1_RANGING_CORE__CALIB_2 0x06C5 + +#define VL53L1_RANGING_CORE__CALIB_3 0x06C6 + +#define VL53L1_RANGING_CORE__TST_MUX_SEL1 0x06C9 + +#define VL53L1_RANGING_CORE__TST_MUX_SEL2 0x06CA + +#define VL53L1_RANGING_CORE__TST_MUX 0x06CB + +#define VL53L1_RANGING_CORE__GPIO_OUT_TESTMUX 0x06CC + +#define VL53L1_RANGING_CORE__CUSTOM_FE 0x06CD + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2 0x06CE + +#define VL53L1_RANGING_CORE__SPAD_READOUT 0x06CF + +#define VL53L1_RANGING_CORE__SPAD_READOUT_1 0x06D0 + +#define VL53L1_RANGING_CORE__SPAD_READOUT_2 0x06D1 + +#define VL53L1_RANGING_CORE__SPAD_PS 0x06D2 + +#define VL53L1_RANGING_CORE__LASER_SAFETY_2 0x06D4 + +#define VL53L1_RANGING_CORE__NVM_CTRL__MODE 0x0780 + +#define VL53L1_RANGING_CORE__NVM_CTRL__PDN 0x0781 + +#define VL53L1_RANGING_CORE__NVM_CTRL__PROGN 0x0782 + +#define VL53L1_RANGING_CORE__NVM_CTRL__READN 0x0783 + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB 0x0784 + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_LSB 0x0785 + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_MSB 0x0786 + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_LSB 0x0787 + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_MSB 0x0788 + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_LSB 0x0789 + +#define VL53L1_RANGING_CORE__NVM_CTRL__TST 0x078A + +#define VL53L1_RANGING_CORE__NVM_CTRL__TESTREAD 0x078B + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_MMM 0x078C + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LMM 0x078D + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLM 0x078E + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLL 0x078F + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM 0x0790 + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LMM 0x0791 + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLM 0x0792 + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLL 0x0793 + +#define VL53L1_RANGING_CORE__NVM_CTRL__ADDR 0x0794 + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_ECC 0x0795 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_0 0x0796 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_1 0x0797 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_2 0x0798 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_3 0x0799 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_4 0x079A + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_5 0x079B + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_6 0x079C + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_7 0x079D + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_8 0x079E + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_9 0x079F + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_10 0x07A0 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_11 0x07A1 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_12 0x07A2 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_13 0x07A3 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_14 0x07A4 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_15 0x07A5 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_16 0x07A6 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_17 0x07A7 + +#define VL53L1_RANGING_CORE__SPAD_SHIFT_EN 0x07BA + +#define VL53L1_RANGING_CORE__SPAD_DISABLE_CTRL 0x07BB + +#define VL53L1_RANGING_CORE__SPAD_EN_SHIFT_OUT_DEBUG 0x07BC + +#define VL53L1_RANGING_CORE__SPI_MODE 0x07BD + +#define VL53L1_RANGING_CORE__GPIO_DIR 0x07BE + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD 0x0880 + +#define VL53L1_RANGING_CORE__VCSEL_START 0x0881 + +#define VL53L1_RANGING_CORE__VCSEL_STOP 0x0882 + +#define VL53L1_RANGING_CORE__VCSEL_1 0x0885 + +#define VL53L1_RANGING_CORE__VCSEL_STATUS 0x088D + +#define VL53L1_RANGING_CORE__STATUS 0x0980 + +#define VL53L1_RANGING_CORE__LASER_CONTINUITY_STATE 0x0981 + +#define VL53L1_RANGING_CORE__RANGE_1_MMM 0x0982 + +#define VL53L1_RANGING_CORE__RANGE_1_LMM 0x0983 + +#define VL53L1_RANGING_CORE__RANGE_1_LLM 0x0984 + +#define VL53L1_RANGING_CORE__RANGE_1_LLL 0x0985 + +#define VL53L1_RANGING_CORE__RANGE_REF_1_MMM 0x0986 + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LMM 0x0987 + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLM 0x0988 + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLL 0x0989 + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_MMM 0x098A + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LMM 0x098B + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLM 0x098C + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLL 0x098D + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_MMM 0x098E + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LMM 0x098F + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLM 0x0990 + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLL 0x0991 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_MMM 0x0992 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LMM 0x0993 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLM 0x0994 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLL 0x0995 + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_MM 0x0996 + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LM 0x0997 + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LL 0x0998 + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_MM 0x0999 + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LM 0x099A + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LL 0x099B + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_MMM 0x099C + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LMM 0x099D + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLM 0x099E + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLL 0x099F + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_MMM 0x09A0 + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LMM 0x09A1 + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLM 0x09A2 + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLL 0x09A3 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_MMM 0x09A4 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LMM 0x09A5 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLM 0x09A6 + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLL 0x09A7 + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_MM 0x09A8 + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LM 0x09A9 + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LL 0x09AA + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_MM 0x09AB + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LM 0x09AC + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LL 0x09AD + +#define VL53L1_RANGING_CORE__GPIO_CONFIG__A0 0x0A00 + +#define VL53L1_RANGING_CORE__RESET_CONTROL__A0 0x0A01 + +#define VL53L1_RANGING_CORE__INTR_MANAGER__A0 0x0A02 + +#define VL53L1_RANGING_CORE__POWER_FSM_TIME_OSC__A0 0x0A06 + +#define VL53L1_RANGING_CORE__VCSEL_ATEST__A0 0x0A07 + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD_CLIPPED__A0 0x0A08 + +#define VL53L1_RANGING_CORE__VCSEL_STOP_CLIPPED__A0 0x0A09 + +#define VL53L1_RANGING_CORE__CALIB_2__A0 0x0A0A + +#define VL53L1_RANGING_CORE__STOP_CONDITION__A0 0x0A0B + +#define VL53L1_RANGING_CORE__STATUS_RESET__A0 0x0A0C + +#define VL53L1_RANGING_CORE__READOUT_CFG__A0 0x0A0D + +#define VL53L1_RANGING_CORE__WINDOW_SETTING__A0 0x0A0E + +#define VL53L1_RANGING_CORE__VCSEL_DELAY__A0 0x0A1A + +#define VL53L1_RANGING_CORE__REFERENCE_2__A0 0x0A1B + +#define VL53L1_RANGING_CORE__REGAVDD1V2__A0 0x0A1D + +#define VL53L1_RANGING_CORE__TST_MUX__A0 0x0A1F + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2__A0 0x0A20 + +#define VL53L1_RANGING_CORE__SPAD_READOUT__A0 0x0A21 + +#define VL53L1_RANGING_CORE__CPUMP_1__A0 0x0A22 + +#define VL53L1_RANGING_CORE__SPARE_REGISTER__A0 0x0A23 + +#define VL53L1_RANGING_CORE__VCSEL_CONT_STAGE5_BYPASS__A0 0x0A24 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_18 0x0A25 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_19 0x0A26 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_20 0x0A27 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_21 0x0A28 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_22 0x0A29 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_23 0x0A2A + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_24 0x0A2B + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_25 0x0A2C + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_26 0x0A2D + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_27 0x0A2E + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_28 0x0A2F + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_29 0x0A30 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_30 0x0A31 + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_31 0x0A32 + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_0__EWOK 0x0A33 + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_1__EWOK 0x0A34 + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_2__EWOK 0x0A35 + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_3__EWOK 0x0A36 + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_4__EWOK 0x0A37 + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_5__EWOK 0x0A38 + +#define VL53L1_RANGING_CORE__REF_EN_START_SELECT 0x0A39 + +#define VL53L1_RANGING_CORE__REGDVDD1V2_ATEST__EWOK 0x0A41 + +#define VL53L1_SOFT_RESET_GO1 0x0B00 + +#define VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV 0x0E00 + +#define VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS 0x0ED0 + +#define VL53L1_PREV_SHADOW_RESULT__RANGE_STATUS 0x0ED1 + +#define VL53L1_PREV_SHADOW_RESULT__REPORT_STATUS 0x0ED2 + +#define VL53L1_PREV_SHADOW_RESULT__STREAM_COUNT 0x0ED3 + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0ED4 + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0ED4 + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0ED5 + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0ED6 + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0ED6 + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0ED7 + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0ED8 + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0ED8 + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0ED9 + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0 0x0EDA + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_HI 0x0EDA + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_LO 0x0EDB + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0 0x0EDC + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_HI 0x0EDC + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_LO 0x0EDD + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0EDE + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0EDE + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0EDF + +#define VL53L1_PREV__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0EE0 + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0EE0 + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0EE1 + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE2 + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE2 + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE3 + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE4 + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE4 + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE5 + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0EE6 + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0EE6 + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0EE7 + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0EE8 + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0EE8 + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0EE9 + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0EEA + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0EEA + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0EEB + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0EEC + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0EEC + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0EED + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1 0x0EEE + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_HI 0x0EEE + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_LO 0x0EEF + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1 0x0EF0 + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_HI 0x0EF0 + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_LO 0x0EF1 + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0EF2 + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0EF2 + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0EF3 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1 0x0EF4 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_HI 0x0EF4 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_LO 0x0EF5 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1 0x0EF6 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_HI 0x0EF6 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_LO 0x0EF7 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1 0x0EF8 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_HI 0x0EF8 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_LO 0x0EF9 + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1 0x0EFA + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_HI 0x0EFA + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_LO 0x0EFB + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0EFC + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0EFC + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0EFD + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0EFE + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0EFF + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0F00 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0F00 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0F01 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0F02 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0F03 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0F04 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0F04 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0F05 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0F06 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0F07 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0F08 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0F08 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0F09 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0F0A + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0F0B + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0F0C + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0F0C + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0F0D + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0F0E + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0F0F + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0F10 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0F10 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0F11 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0F12 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0F13 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0F14 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0F14 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0F15 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0F16 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0F17 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0F18 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0F18 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0F19 + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0F1A + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0F1B + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SPARE_0 0x0F1C + +#define VL53L1_RESULT__DEBUG_STATUS 0x0F20 + +#define VL53L1_RESULT__DEBUG_STAGE 0x0F21 + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH 0x0F24 + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_HI 0x0F24 + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_LO 0x0F25 + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW 0x0F26 + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_HI 0x0F26 + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_LO 0x0F27 + +#define VL53L1_GPH__SYSTEM__INTERRUPT_CONFIG_GPIO 0x0F28 + +#define VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL 0x0F2F + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0F30 + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0F30 + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0F31 + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0F32 + +#define VL53L1_GPH__DSS_CONFIG__MAX_SPADS_LIMIT 0x0F33 + +#define VL53L1_GPH__DSS_CONFIG__MIN_SPADS_LIMIT 0x0F34 + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI 0x0F36 + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_LO 0x0F37 + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_HI 0x0F38 + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_LO 0x0F39 + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x0F3A + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x0F3B + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_A 0x0F3C + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_B 0x0F3D + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0F3E + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0F3F + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH 0x0F40 + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_HI 0x0F40 + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_LO 0x0F41 + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0F42 + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0F42 + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0F43 + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_LOW 0x0F44 + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_HIGH 0x0F45 + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV 0x0F46 + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNTER_VAL 0x0F47 + +#define VL53L1_DSS_CALC__ROI_CTRL 0x0F54 + +#define VL53L1_DSS_CALC__SPARE_1 0x0F55 + +#define VL53L1_DSS_CALC__SPARE_2 0x0F56 + +#define VL53L1_DSS_CALC__SPARE_3 0x0F57 + +#define VL53L1_DSS_CALC__SPARE_4 0x0F58 + +#define VL53L1_DSS_CALC__SPARE_5 0x0F59 + +#define VL53L1_DSS_CALC__SPARE_6 0x0F5A + +#define VL53L1_DSS_CALC__SPARE_7 0x0F5B + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_0 0x0F5C + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_1 0x0F5D + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_2 0x0F5E + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_3 0x0F5F + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_4 0x0F60 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_5 0x0F61 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_6 0x0F62 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_7 0x0F63 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_8 0x0F64 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_9 0x0F65 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_10 0x0F66 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_11 0x0F67 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_12 0x0F68 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_13 0x0F69 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_14 0x0F6A + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_15 0x0F6B + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_16 0x0F6C + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_17 0x0F6D + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_18 0x0F6E + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_19 0x0F6F + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_20 0x0F70 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_21 0x0F71 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_22 0x0F72 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_23 0x0F73 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_24 0x0F74 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_25 0x0F75 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_26 0x0F76 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_27 0x0F77 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_28 0x0F78 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_29 0x0F79 + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_30 0x0F7A + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_31 0x0F7B + +#define VL53L1_DSS_CALC__USER_ROI_0 0x0F7C + +#define VL53L1_DSS_CALC__USER_ROI_1 0x0F7D + +#define VL53L1_DSS_CALC__MODE_ROI_0 0x0F7E + +#define VL53L1_DSS_CALC__MODE_ROI_1 0x0F7F + +#define VL53L1_SIGMA_ESTIMATOR_CALC__SPARE_0 0x0F80 + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS 0x0F82 + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_HI 0x0F82 + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_LO 0x0F83 + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF 0x0F84 + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_3 0x0F84 + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_2 0x0F85 + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_1 0x0F86 + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_0 0x0F87 + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF 0x0F88 + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_HI 0x0F88 + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_LO 0x0F89 + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD 0x0F8A + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_HI 0x0F8A + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_LO 0x0F8B + +#define VL53L1_DSS_RESULT__ENABLED_BLOCKS 0x0F8C + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS 0x0F8E + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_HI 0x0F8E + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_LO 0x0F8F + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE 0x0F92 + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_HI 0x0F92 + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_LO 0x0F93 + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE 0x0F94 + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_HI 0x0F94 + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_LO 0x0F95 + +#define VL53L1_MM_RESULT__TOTAL_OFFSET 0x0F96 + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_HI 0x0F96 + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_LO 0x0F97 + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS 0x0F98 + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_3 0x0F98 + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_2 0x0F99 + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_1 0x0F9A + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_0 0x0F9B + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS 0x0F9C + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_3 0x0F9C + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_2 0x0F9D + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_1 0x0F9E + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_0 0x0F9F + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS 0x0FA0 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_3 0x0FA0 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_2 0x0FA1 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_1 0x0FA2 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_0 0x0FA3 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS 0x0FA4 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_3 0x0FA4 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_2 0x0FA5 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_1 0x0FA6 + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_0 0x0FA7 + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE 0x0FA8 + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_3 0x0FA8 + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_2 0x0FA9 + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_1 0x0FAA + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_0 0x0FAB + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE 0x0FAC + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_HI 0x0FAC + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_LO 0x0FAD + +#define VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START 0x0FAE + +#define VL53L1_SHADOW_RESULT__INTERRUPT_STATUS 0x0FB0 + +#define VL53L1_SHADOW_RESULT__RANGE_STATUS 0x0FB1 + +#define VL53L1_SHADOW_RESULT__REPORT_STATUS 0x0FB2 + +#define VL53L1_SHADOW_RESULT__STREAM_COUNT 0x0FB3 + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FB4 + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FB4 + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FB5 + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FB6 + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FB6 + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FB7 + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0FB8 + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0FB8 + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0FB9 + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0 0x0FBA + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_HI 0x0FBA + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_LO 0x0FBB + +#define VL53L1_SHADOW_RESULT__PHASE_SD0 0x0FBC + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_HI 0x0FBC + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_LO 0x0FBD + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0FBE + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0FBE + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0FBF + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0FC0 + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0FC0 + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0FC1 + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC2 + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC2 + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC3 + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC4 + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC4 + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC5 + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FC6 + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FC6 + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FC7 + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0FC8 + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0FC8 + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0FC9 + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0FCA + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0FCA + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0FCB + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0FCC + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0FCC + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0FCD + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1 0x0FCE + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_HI 0x0FCE + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_LO 0x0FCF + +#define VL53L1_SHADOW_RESULT__PHASE_SD1 0x0FD0 + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_HI 0x0FD0 + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_LO 0x0FD1 + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0FD2 + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0FD2 + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0FD3 + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1 0x0FD4 + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_HI 0x0FD4 + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_LO 0x0FD5 + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1 0x0FD6 + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_HI 0x0FD6 + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_LO 0x0FD7 + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1 0x0FD8 + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_HI 0x0FD8 + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_LO 0x0FD9 + +#define VL53L1_SHADOW_RESULT__SPARE_3_SD1 0x0FDA + +#define VL53L1_SHADOW_RESULT__THRESH_INFO 0x0FDB + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0FDC + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0FDC + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0FDD + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0FDE + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0FDF + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0FE0 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0FE0 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0FE1 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0FE2 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0FE3 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0FE4 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0FE4 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0FE5 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0FE6 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0FE7 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0FE8 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0FE8 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0FE9 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0FEA + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0FEB + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0FEC + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0FEC + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0FED + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0FEE + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0FEF + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0FF0 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0FF0 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0FF1 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0FF2 + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0FF3 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0FF4 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0FF4 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0FF5 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0FF6 + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0FF7 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0FF8 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0FF8 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0FF9 + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0FFA + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0FFB + +#define VL53L1_SHADOW_RESULT_CORE__SPARE_0 0x0FFC + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x0FFE + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x0FFF + + + + + +#endif + + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_register_settings.h b/drivers/input/misc/vl53L1/inc/vl53l1_register_settings.h new file mode 100644 index 0000000000000000000000000000000000000000..856777bd93e50eebc7896d8e7981382965c42706 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_register_settings.h @@ -0,0 +1,130 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_REGISTER_SETTINGS_H_ +#define _VL53L1_REGISTER_SETTINGS_H_ + + + + + + +#define VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO 0x00 +#define VL53L1_DEVICESCHEDULERMODE_STREAMING 0x01 +#define VL53L1_DEVICESCHEDULERMODE_HISTOGRAM 0x02 + + + + + +#define VL53L1_DEVICEREADOUTMODE_SINGLE_SD (0x00 << 2) +#define VL53L1_DEVICEREADOUTMODE_DUAL_SD (0x01 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_READOUT (0x02 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL (0x03 << 2) + + + + + + +#define VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK 0xF0 +#define VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK 0x0F + +#define VL53L1_GROUPEDPARAMETERHOLD_ID_MASK 0x02 + + + +#define VL53L1_EWOK_I2C_DEV_ADDR_DEFAULT 0x29 + +#define VL53L1_OSC_FREQUENCY 0x00 +#define VL53L1_OSC_TRIM_DEFAULT 0x00 +#define VL53L1_OSC_FREQ_SET_DEFAULT 0x00 + +#define VL53L1_RANGE_HISTOGRAM_REF 0x08 +#define VL53L1_RANGE_HISTOGRAM_RET 0x10 +#define VL53L1_RANGE_HISTOGRAM_BOTH 0x18 +#define VL53L1_RANGE_HISTOGRAM_INIT 0x20 +#define VL53L1_RANGE_VHV_INIT 0x40 + + +#define VL53L1_RESULT_RANGE_STATUS 0x1F + + +#define VL53L1_SYSTEM__SEED_CONFIG__MANUAL 0x00 +#define VL53L1_SYSTEM__SEED_CONFIG__STANDARD 0x01 +#define VL53L1_SYSTEM__SEED_CONFIG__EVEN_UPDATE_ONLY 0x02 + + +#define VL53L1_INTERRUPT_CONFIG_LEVEL_LOW 0x00 +#define VL53L1_INTERRUPT_CONFIG_LEVEL_HIGH 0x01 +#define VL53L1_INTERRUPT_CONFIG_OUT_OF_WINDOW 0x02 +#define VL53L1_INTERRUPT_CONFIG_IN_WINDOW 0x03 +#define VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY 0x20 + + +#define VL53L1_CLEAR_RANGE_INT 0x01 +#define VL53L1_CLEAR_ERROR_INT 0x02 + + +#define VL53L1_SEQUENCE_VHV_EN 0x01 +#define VL53L1_SEQUENCE_PHASECAL_EN 0x02 +#define VL53L1_SEQUENCE_REFERENCE_PHASE_EN 0x04 +#define VL53L1_SEQUENCE_DSS1_EN 0x08 +#define VL53L1_SEQUENCE_DSS2_EN 0x10 +#define VL53L1_SEQUENCE_MM1_EN 0x20 +#define VL53L1_SEQUENCE_MM2_EN 0x40 +#define VL53L1_SEQUENCE_RANGE_EN 0x80 + + +#define VL53L1_DSS_CONTROL__ROI_SUBTRACT 0x20 +#define VL53L1_DSS_CONTROL__ROI_INTERSECT 0x10 + +#define VL53L1_DSS_CONTROL__MODE_DISABLED 0x00 +#define VL53L1_DSS_CONTROL__MODE_TARGET_RATE 0x01 +#define VL53L1_DSS_CONTROL__MODE_EFFSPADS 0x02 +#define VL53L1_DSS_CONTROL__MODE_BLOCKSELECT 0x03 + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD 0x45 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_ARRAY_ONLY 0x05 +#define VL53L1_RANGING_CORE__SPAD_READOUT__REFERENCE_ARRAY_ONLY 0x55 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_SPLIT_ARRAY 0x25 +#define VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES 0xF5 + + +#define VL53L1_LASER_SAFETY__KEY_VALUE 0x6C + + + +#define VL53L1_RANGE_STATUS__RANGE_STATUS_MASK 0x1F +#define VL53L1_RANGE_STATUS__MAX_THRESHOLD_HIT_MASK 0x20 +#define VL53L1_RANGE_STATUS__MIN_THRESHOLD_HIT_MASK 0x40 +#define VL53L1_RANGE_STATUS__GPH_ID_RANGE_STATUS_MASK 0x80 + + + +#define VL53L1_INTERRUPT_STATUS__INT_STATUS_MASK 0x07 +#define VL53L1_INTERRUPT_STATUS__INT_ERROR_STATUS_MASK 0x18 +#define VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK 0x20 + + + + +#endif + + + + + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_register_structs.h b/drivers/input/misc/vl53L1/inc/vl53l1_register_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..1a08dc7f665236177a1eee8f5d05d213f1687517 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_register_structs.h @@ -0,0 +1,999 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_REGISTER_STRUCTS_H_ +#define _VL53L1_REGISTER_STRUCTS_H_ + +#include "vl53l1_types.h" +#include "vl53l1_register_map.h" + +#define VL53L1_STATIC_NVM_MANAGED_I2C_INDEX \ + VL53L1_I2C_SLAVE__DEVICE_ADDRESS +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX \ + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 +#define VL53L1_STATIC_CONFIG_I2C_INDEX \ + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS +#define VL53L1_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE +#define VL53L1_TIMING_CONFIG_I2C_INDEX \ + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_DYNAMIC_CONFIG_I2C_INDEX \ + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 +#define VL53L1_SYSTEM_CONTROL_I2C_INDEX \ + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE +#define VL53L1_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_CORE_RESULTS_I2C_INDEX \ + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_DEBUG_RESULTS_I2C_INDEX \ + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE +#define VL53L1_NVM_COPY_DATA_I2C_INDEX \ + VL53L1_IDENTIFICATION__MODEL_ID +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_PATCH_DEBUG_I2C_INDEX \ + VL53L1_RESULT__DEBUG_STATUS +#define VL53L1_GPH_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH +#define VL53L1_GPH_STATIC_CONFIG_I2C_INDEX \ + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL +#define VL53L1_GPH_TIMING_CONFIG_I2C_INDEX \ + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_FW_INTERNAL_I2C_INDEX \ + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV +#define VL53L1_PATCH_RESULTS_I2C_INDEX \ + VL53L1_DSS_CALC__ROI_CTRL +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START +#define VL53L1_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 + +#define VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES 11 +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES 23 +#define VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES 32 +#define VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES 22 +#define VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES 23 +#define VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES 18 +#define VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES 5 +#define VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES 56 +#define VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES 49 +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES 2 +#define VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES 5 +#define VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES 6 +#define VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES 16 +#define VL53L1_FW_INTERNAL_I2C_SIZE_BYTES 2 +#define VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES 90 +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 82 +#define VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 + + + + +typedef struct { + uint8_t i2c_slave__device_address; + + uint8_t ana_config__vhv_ref_sel_vddpix; + + uint8_t ana_config__vhv_ref_sel_vquench; + + uint8_t ana_config__reg_avdd1v2_sel; + + uint8_t ana_config__fast_osc__trim; + + uint16_t osc_measured__fast_osc__frequency; + + uint8_t vhv_config__timeout_macrop_loop_bound; + + uint8_t vhv_config__count_thresh; + + uint8_t vhv_config__offset; + + uint8_t vhv_config__init; + +} VL53L1_static_nvm_managed_t; + + + + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + + uint8_t global_config__spad_enables_ref_1; + + uint8_t global_config__spad_enables_ref_2; + + uint8_t global_config__spad_enables_ref_3; + + uint8_t global_config__spad_enables_ref_4; + + uint8_t global_config__spad_enables_ref_5; + + uint8_t global_config__ref_en_start_select; + + uint8_t ref_spad_man__num_requested_ref_spads; + + uint8_t ref_spad_man__ref_location; + + uint16_t algo__crosstalk_compensation_plane_offset_kcps; + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + uint16_t ref_spad_char__total_rate_target_mcps; + + int16_t algo__part_to_part_range_offset_mm; + + int16_t mm_config__inner_offset_mm; + + int16_t mm_config__outer_offset_mm; + +} VL53L1_customer_nvm_managed_t; + + + + +typedef struct { + uint16_t dss_config__target_total_rate_mcps; + + uint8_t debug__ctrl; + + uint8_t test_mode__ctrl; + + uint8_t clk_gating__ctrl; + + uint8_t nvm_bist__ctrl; + + uint8_t nvm_bist__num_nvm_words; + + uint8_t nvm_bist__start_address; + + uint8_t host_if__status; + + uint8_t pad_i2c_hv__config; + + uint8_t pad_i2c_hv__extsup_config; + + uint8_t gpio_hv_pad__ctrl; + + uint8_t gpio_hv_mux__ctrl; + + uint8_t gpio__tio_hv_status; + + uint8_t gpio__fio_hv_status; + + uint8_t ana_config__spad_sel_pswidth; + + uint8_t ana_config__vcsel_pulse_width_offset; + + uint8_t ana_config__fast_osc__config_ctrl; + + uint8_t sigma_estimator__effective_pulse_width_ns; + + uint8_t sigma_estimator__effective_ambient_width_ns; + + uint8_t sigma_estimator__sigma_ref_mm; + + uint8_t algo__crosstalk_compensation_valid_height_mm; + + uint8_t spare_host_config__static_config_spare_0; + + uint8_t spare_host_config__static_config_spare_1; + + uint16_t algo__range_ignore_threshold_mcps; + + uint8_t algo__range_ignore_valid_height_mm; + + uint8_t algo__range_min_clip; + + uint8_t algo__consistency_check__tolerance; + + uint8_t spare_host_config__static_config_spare_2; + + uint8_t sd_config__reset_stages_msb; + + uint8_t sd_config__reset_stages_lsb; + +} VL53L1_static_config_t; + + + + +typedef struct { + uint8_t gph_config__stream_count_update_value; + + uint8_t global_config__stream_divider; + + uint8_t system__interrupt_config_gpio; + + uint8_t cal_config__vcsel_start; + + uint16_t cal_config__repeat_rate; + + uint8_t global_config__vcsel_width; + + uint8_t phasecal_config__timeout_macrop; + + uint8_t phasecal_config__target; + + uint8_t phasecal_config__override; + + uint8_t dss_config__roi_mode_control; + + uint16_t system__thresh_rate_high; + + uint16_t system__thresh_rate_low; + + uint16_t dss_config__manual_effective_spads_select; + + uint8_t dss_config__manual_block_select; + + uint8_t dss_config__aperture_attenuation; + + uint8_t dss_config__max_spads_limit; + + uint8_t dss_config__min_spads_limit; + +} VL53L1_general_config_t; + + + + +typedef struct { + uint8_t mm_config__timeout_macrop_a_hi; + + uint8_t mm_config__timeout_macrop_a_lo; + + uint8_t mm_config__timeout_macrop_b_hi; + + uint8_t mm_config__timeout_macrop_b_lo; + + uint8_t range_config__timeout_macrop_a_hi; + + uint8_t range_config__timeout_macrop_a_lo; + + uint8_t range_config__vcsel_period_a; + + uint8_t range_config__timeout_macrop_b_hi; + + uint8_t range_config__timeout_macrop_b_lo; + + uint8_t range_config__vcsel_period_b; + + uint16_t range_config__sigma_thresh; + + uint16_t range_config__min_count_rate_rtn_limit_mcps; + + uint8_t range_config__valid_phase_low; + + uint8_t range_config__valid_phase_high; + + uint32_t system__intermeasurement_period; + + uint8_t system__fractional_enable; + +} VL53L1_timing_config_t; + + + + +typedef struct { + uint8_t system__grouped_parameter_hold_0; + + uint16_t system__thresh_high; + + uint16_t system__thresh_low; + + uint8_t system__enable_xtalk_per_quadrant; + + uint8_t system__seed_config; + + uint8_t sd_config__woi_sd0; + + uint8_t sd_config__woi_sd1; + + uint8_t sd_config__initial_phase_sd0; + + uint8_t sd_config__initial_phase_sd1; + + uint8_t system__grouped_parameter_hold_1; + + uint8_t sd_config__first_order_select; + + uint8_t sd_config__quantifier; + + uint8_t roi_config__user_roi_centre_spad; + + uint8_t roi_config__user_roi_requested_global_xy_size; + + uint8_t system__sequence_config; + + uint8_t system__grouped_parameter_hold; + +} VL53L1_dynamic_config_t; + + + + +typedef struct { + uint8_t power_management__go1_power_force; + + uint8_t system__stream_count_ctrl; + + uint8_t firmware__enable; + + uint8_t system__interrupt_clear; + + uint8_t system__mode_start; + +} VL53L1_system_control_t; + + + + +typedef struct { + uint8_t result__interrupt_status; + + uint8_t result__range_status; + + uint8_t result__report_status; + + uint8_t result__stream_count; + + uint16_t result__dss_actual_effective_spads_sd0; + + uint16_t result__peak_signal_count_rate_mcps_sd0; + + uint16_t result__ambient_count_rate_mcps_sd0; + + uint16_t result__sigma_sd0; + + uint16_t result__phase_sd0; + + uint16_t result__final_crosstalk_corrected_range_mm_sd0; + + uint16_t result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + uint16_t result__mm_inner_actual_effective_spads_sd0; + + uint16_t result__mm_outer_actual_effective_spads_sd0; + + uint16_t result__avg_signal_count_rate_mcps_sd0; + + uint16_t result__dss_actual_effective_spads_sd1; + + uint16_t result__peak_signal_count_rate_mcps_sd1; + + uint16_t result__ambient_count_rate_mcps_sd1; + + uint16_t result__sigma_sd1; + + uint16_t result__phase_sd1; + + uint16_t result__final_crosstalk_corrected_range_mm_sd1; + + uint16_t result__spare_0_sd1; + + uint16_t result__spare_1_sd1; + + uint16_t result__spare_2_sd1; + + uint8_t result__spare_3_sd1; + + uint8_t result__thresh_info; + +} VL53L1_system_results_t; + + + + +typedef struct { + uint32_t result_core__ambient_window_events_sd0; + + uint32_t result_core__ranging_total_events_sd0; + + int32_t result_core__signal_total_events_sd0; + + uint32_t result_core__total_periods_elapsed_sd0; + + uint32_t result_core__ambient_window_events_sd1; + + uint32_t result_core__ranging_total_events_sd1; + + int32_t result_core__signal_total_events_sd1; + + uint32_t result_core__total_periods_elapsed_sd1; + + uint8_t result_core__spare_0; + +} VL53L1_core_results_t; + + + + +typedef struct { + uint16_t phasecal_result__reference_phase; + + uint8_t phasecal_result__vcsel_start; + + uint8_t ref_spad_char_result__num_actual_ref_spads; + + uint8_t ref_spad_char_result__ref_location; + + uint8_t vhv_result__coldboot_status; + + uint8_t vhv_result__search_result; + + uint8_t vhv_result__latest_setting; + + uint16_t result__osc_calibrate_val; + + uint8_t ana_config__powerdown_go1; + + uint8_t ana_config__ref_bg_ctrl; + + uint8_t ana_config__regdvdd1v2_ctrl; + + uint8_t ana_config__osc_slow_ctrl; + + uint8_t test_mode__status; + + uint8_t firmware__system_status; + + uint8_t firmware__mode_status; + + uint8_t firmware__secondary_mode_status; + + uint16_t firmware__cal_repeat_rate_counter; + + uint16_t gph__system__thresh_high; + + uint16_t gph__system__thresh_low; + + uint8_t gph__system__enable_xtalk_per_quadrant; + + uint8_t gph__spare_0; + + uint8_t gph__sd_config__woi_sd0; + + uint8_t gph__sd_config__woi_sd1; + + uint8_t gph__sd_config__initial_phase_sd0; + + uint8_t gph__sd_config__initial_phase_sd1; + + uint8_t gph__sd_config__first_order_select; + + uint8_t gph__sd_config__quantifier; + + uint8_t gph__roi_config__user_roi_centre_spad; + + uint8_t gph__roi_config__user_roi_requested_global_xy_size; + + uint8_t gph__system__sequence_config; + + uint8_t gph__gph_id; + + uint8_t system__interrupt_set; + + uint8_t interrupt_manager__enables; + + uint8_t interrupt_manager__clear; + + uint8_t interrupt_manager__status; + + uint8_t mcu_to_host_bank__wr_access_en; + + uint8_t power_management__go1_reset_status; + + uint8_t pad_startup_mode__value_ro; + + uint8_t pad_startup_mode__value_ctrl; + + uint32_t pll_period_us; + + uint32_t interrupt_scheduler__data_out; + + uint8_t nvm_bist__complete; + + uint8_t nvm_bist__status; + +} VL53L1_debug_results_t; + + + + +typedef struct { + uint8_t identification__model_id; + + uint8_t identification__module_type; + + uint8_t identification__revision_id; + + uint16_t identification__module_id; + + uint8_t ana_config__fast_osc__trim_max; + + uint8_t ana_config__fast_osc__freq_set; + + uint8_t ana_config__vcsel_trim; + + uint8_t ana_config__vcsel_selion; + + uint8_t ana_config__vcsel_selion_max; + + uint8_t protected_laser_safety__lock_bit; + + uint8_t laser_safety__key; + + uint8_t laser_safety__key_ro; + + uint8_t laser_safety__clip; + + uint8_t laser_safety__mult; + + uint8_t global_config__spad_enables_rtn_0; + + uint8_t global_config__spad_enables_rtn_1; + + uint8_t global_config__spad_enables_rtn_2; + + uint8_t global_config__spad_enables_rtn_3; + + uint8_t global_config__spad_enables_rtn_4; + + uint8_t global_config__spad_enables_rtn_5; + + uint8_t global_config__spad_enables_rtn_6; + + uint8_t global_config__spad_enables_rtn_7; + + uint8_t global_config__spad_enables_rtn_8; + + uint8_t global_config__spad_enables_rtn_9; + + uint8_t global_config__spad_enables_rtn_10; + + uint8_t global_config__spad_enables_rtn_11; + + uint8_t global_config__spad_enables_rtn_12; + + uint8_t global_config__spad_enables_rtn_13; + + uint8_t global_config__spad_enables_rtn_14; + + uint8_t global_config__spad_enables_rtn_15; + + uint8_t global_config__spad_enables_rtn_16; + + uint8_t global_config__spad_enables_rtn_17; + + uint8_t global_config__spad_enables_rtn_18; + + uint8_t global_config__spad_enables_rtn_19; + + uint8_t global_config__spad_enables_rtn_20; + + uint8_t global_config__spad_enables_rtn_21; + + uint8_t global_config__spad_enables_rtn_22; + + uint8_t global_config__spad_enables_rtn_23; + + uint8_t global_config__spad_enables_rtn_24; + + uint8_t global_config__spad_enables_rtn_25; + + uint8_t global_config__spad_enables_rtn_26; + + uint8_t global_config__spad_enables_rtn_27; + + uint8_t global_config__spad_enables_rtn_28; + + uint8_t global_config__spad_enables_rtn_29; + + uint8_t global_config__spad_enables_rtn_30; + + uint8_t global_config__spad_enables_rtn_31; + + uint8_t roi_config__mode_roi_centre_spad; + + uint8_t roi_config__mode_roi_xy_size; + +} VL53L1_nvm_copy_data_t; + + + + +typedef struct { + uint8_t prev_shadow_result__interrupt_status; + + uint8_t prev_shadow_result__range_status; + + uint8_t prev_shadow_result__report_status; + + uint8_t prev_shadow_result__stream_count; + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd0; + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd0; + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd0; + + uint16_t prev_shadow_result__sigma_sd0; + + uint16_t prev_shadow_result__phase_sd0; + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd0; + + uint16_t + psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + uint16_t prev_shadow_result__mm_inner_actual_effective_spads_sd0; + + uint16_t prev_shadow_result__mm_outer_actual_effective_spads_sd0; + + uint16_t prev_shadow_result__avg_signal_count_rate_mcps_sd0; + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd1; + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd1; + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd1; + + uint16_t prev_shadow_result__sigma_sd1; + + uint16_t prev_shadow_result__phase_sd1; + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd1; + + uint16_t prev_shadow_result__spare_0_sd1; + + uint16_t prev_shadow_result__spare_1_sd1; + + uint16_t prev_shadow_result__spare_2_sd1; + + uint16_t prev_shadow_result__spare_3_sd1; + +} VL53L1_prev_shadow_system_results_t; + + + + +typedef struct { + uint32_t prev_shadow_result_core__ambient_window_events_sd0; + + uint32_t prev_shadow_result_core__ranging_total_events_sd0; + + int32_t prev_shadow_result_core__signal_total_events_sd0; + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd0; + + uint32_t prev_shadow_result_core__ambient_window_events_sd1; + + uint32_t prev_shadow_result_core__ranging_total_events_sd1; + + int32_t prev_shadow_result_core__signal_total_events_sd1; + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd1; + + uint8_t prev_shadow_result_core__spare_0; + +} VL53L1_prev_shadow_core_results_t; + + + + +typedef struct { + uint8_t result__debug_status; + + uint8_t result__debug_stage; + +} VL53L1_patch_debug_t; + + + + +typedef struct { + uint16_t gph__system__thresh_rate_high; + + uint16_t gph__system__thresh_rate_low; + + uint8_t gph__system__interrupt_config_gpio; + +} VL53L1_gph_general_config_t; + + + + +typedef struct { + uint8_t gph__dss_config__roi_mode_control; + + uint16_t gph__dss_config__manual_effective_spads_select; + + uint8_t gph__dss_config__manual_block_select; + + uint8_t gph__dss_config__max_spads_limit; + + uint8_t gph__dss_config__min_spads_limit; + +} VL53L1_gph_static_config_t; + + + + +typedef struct { + uint8_t gph__mm_config__timeout_macrop_a_hi; + + uint8_t gph__mm_config__timeout_macrop_a_lo; + + uint8_t gph__mm_config__timeout_macrop_b_hi; + + uint8_t gph__mm_config__timeout_macrop_b_lo; + + uint8_t gph__range_config__timeout_macrop_a_hi; + + uint8_t gph__range_config__timeout_macrop_a_lo; + + uint8_t gph__range_config__vcsel_period_a; + + uint8_t gph__range_config__vcsel_period_b; + + uint8_t gph__range_config__timeout_macrop_b_hi; + + uint8_t gph__range_config__timeout_macrop_b_lo; + + uint16_t gph__range_config__sigma_thresh; + + uint16_t gph__range_config__min_count_rate_rtn_limit_mcps; + + uint8_t gph__range_config__valid_phase_low; + + uint8_t gph__range_config__valid_phase_high; + +} VL53L1_gph_timing_config_t; + + + + +typedef struct { + uint8_t firmware__internal_stream_count_div; + + uint8_t firmware__internal_stream_counter_val; + +} VL53L1_fw_internal_t; + + + + +typedef struct { + uint8_t dss_calc__roi_ctrl; + + uint8_t dss_calc__spare_1; + + uint8_t dss_calc__spare_2; + + uint8_t dss_calc__spare_3; + + uint8_t dss_calc__spare_4; + + uint8_t dss_calc__spare_5; + + uint8_t dss_calc__spare_6; + + uint8_t dss_calc__spare_7; + + uint8_t dss_calc__user_roi_spad_en_0; + + uint8_t dss_calc__user_roi_spad_en_1; + + uint8_t dss_calc__user_roi_spad_en_2; + + uint8_t dss_calc__user_roi_spad_en_3; + + uint8_t dss_calc__user_roi_spad_en_4; + + uint8_t dss_calc__user_roi_spad_en_5; + + uint8_t dss_calc__user_roi_spad_en_6; + + uint8_t dss_calc__user_roi_spad_en_7; + + uint8_t dss_calc__user_roi_spad_en_8; + + uint8_t dss_calc__user_roi_spad_en_9; + + uint8_t dss_calc__user_roi_spad_en_10; + + uint8_t dss_calc__user_roi_spad_en_11; + + uint8_t dss_calc__user_roi_spad_en_12; + + uint8_t dss_calc__user_roi_spad_en_13; + + uint8_t dss_calc__user_roi_spad_en_14; + + uint8_t dss_calc__user_roi_spad_en_15; + + uint8_t dss_calc__user_roi_spad_en_16; + + uint8_t dss_calc__user_roi_spad_en_17; + + uint8_t dss_calc__user_roi_spad_en_18; + + uint8_t dss_calc__user_roi_spad_en_19; + + uint8_t dss_calc__user_roi_spad_en_20; + + uint8_t dss_calc__user_roi_spad_en_21; + + uint8_t dss_calc__user_roi_spad_en_22; + + uint8_t dss_calc__user_roi_spad_en_23; + + uint8_t dss_calc__user_roi_spad_en_24; + + uint8_t dss_calc__user_roi_spad_en_25; + + uint8_t dss_calc__user_roi_spad_en_26; + + uint8_t dss_calc__user_roi_spad_en_27; + + uint8_t dss_calc__user_roi_spad_en_28; + + uint8_t dss_calc__user_roi_spad_en_29; + + uint8_t dss_calc__user_roi_spad_en_30; + + uint8_t dss_calc__user_roi_spad_en_31; + + uint8_t dss_calc__user_roi_0; + + uint8_t dss_calc__user_roi_1; + + uint8_t dss_calc__mode_roi_0; + + uint8_t dss_calc__mode_roi_1; + + uint8_t sigma_estimator_calc__spare_0; + + uint16_t vhv_result__peak_signal_rate_mcps; + + uint32_t vhv_result__signal_total_events_ref; + + uint16_t phasecal_result__phase_output_ref; + + uint16_t dss_result__total_rate_per_spad; + + uint8_t dss_result__enabled_blocks; + + uint16_t dss_result__num_requested_spads; + + uint16_t mm_result__inner_intersection_rate; + + uint16_t mm_result__outer_complement_rate; + + uint16_t mm_result__total_offset; + + uint32_t xtalk_calc__xtalk_for_enabled_spads; + + uint32_t xtalk_result__avg_xtalk_user_roi_kcps; + + uint32_t xtalk_result__avg_xtalk_mm_inner_roi_kcps; + + uint32_t xtalk_result__avg_xtalk_mm_outer_roi_kcps; + + uint32_t range_result__accum_phase; + + uint16_t range_result__offset_corrected_range; + +} VL53L1_patch_results_t; + + + + +typedef struct { + uint8_t shadow_phasecal_result__vcsel_start; + + uint8_t shadow_result__interrupt_status; + + uint8_t shadow_result__range_status; + + uint8_t shadow_result__report_status; + + uint8_t shadow_result__stream_count; + + uint16_t shadow_result__dss_actual_effective_spads_sd0; + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd0; + + uint16_t shadow_result__ambient_count_rate_mcps_sd0; + + uint16_t shadow_result__sigma_sd0; + + uint16_t shadow_result__phase_sd0; + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd0; + + uint16_t + shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + uint16_t shadow_result__mm_inner_actual_effective_spads_sd0; + + uint16_t shadow_result__mm_outer_actual_effective_spads_sd0; + + uint16_t shadow_result__avg_signal_count_rate_mcps_sd0; + + uint16_t shadow_result__dss_actual_effective_spads_sd1; + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd1; + + uint16_t shadow_result__ambient_count_rate_mcps_sd1; + + uint16_t shadow_result__sigma_sd1; + + uint16_t shadow_result__phase_sd1; + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd1; + + uint16_t shadow_result__spare_0_sd1; + + uint16_t shadow_result__spare_1_sd1; + + uint16_t shadow_result__spare_2_sd1; + + uint8_t shadow_result__spare_3_sd1; + + uint8_t shadow_result__thresh_info; + + uint8_t shadow_phasecal_result__reference_phase_hi; + + uint8_t shadow_phasecal_result__reference_phase_lo; + +} VL53L1_shadow_system_results_t; + + + + +typedef struct { + uint32_t shadow_result_core__ambient_window_events_sd0; + + uint32_t shadow_result_core__ranging_total_events_sd0; + + int32_t shadow_result_core__signal_total_events_sd0; + + uint32_t shadow_result_core__total_periods_elapsed_sd0; + + uint32_t shadow_result_core__ambient_window_events_sd1; + + uint32_t shadow_result_core__ranging_total_events_sd1; + + int32_t shadow_result_core__signal_total_events_sd1; + + uint32_t shadow_result_core__total_periods_elapsed_sd1; + + uint8_t shadow_result_core__spare_0; + +} VL53L1_shadow_core_results_t; + + +#endif + + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_silicon_core.h b/drivers/input/misc/vl53L1/inc/vl53l1_silicon_core.h new file mode 100644 index 0000000000000000000000000000000000000000..7df54088e77abf5180e82a7d759fabdf6ba5243a --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_silicon_core.h @@ -0,0 +1,37 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_SILICON_CORE_H_ +#define _VL53L1_SILICON_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_tuning_parm_defaults.h b/drivers/input/misc/vl53L1/inc/vl53l1_tuning_parm_defaults.h new file mode 100644 index 0000000000000000000000000000000000000000..d880ea5b72d6805ea183f3555a5c260b16d431e8 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_tuning_parm_defaults.h @@ -0,0 +1,393 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + +#define VL53L1_TUNINGPARM_VERSION_DEFAULT \ +((uint16_t) 31) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT \ +((uint16_t) 14) +#define VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT \ +((uint16_t) 12180) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT \ +((uint8_t) 4) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT \ +((uint8_t) 100) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT \ +((int32_t) 16) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT \ +((uint16_t) 4157) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT \ +((int32_t) 100) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 180) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT \ +((uint16_t) 1987) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT \ +((uint16_t) 2048) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 5) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT \ +((int16_t) -50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT \ +((int16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 400) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT \ +((uint8_t) 33) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT \ +((uint16_t) 2011) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT \ +((uint8_t) 16) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT \ +((uint8_t) 64) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT \ +((uint8_t) 32) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT \ +((uint16_t) 15) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT \ +((uint16_t) 52) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT \ +((uint16_t) 200) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT \ +((uint16_t) 364) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT \ +((uint16_t) 400) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND_DEFAULT \ +((uint8_t) 129) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 11) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 1280) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT \ +((uint8_t) 7) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT \ +((int16_t) -70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT \ +((int16_t) 70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 640) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT \ +((uint32_t) 10000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT \ +((uint8_t) 40) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT \ +((uint16_t) 16) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT \ +((uint16_t) 8) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 18) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT \ +((uint8_t) 15) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 12) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 63000) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT \ +((uint32_t) 100) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT \ +((uint32_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 200) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT \ +((uint32_t) 2048) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT \ +((uint32_t) 308) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT \ +((uint32_t) 10240) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT \ +((uint32_t) 128) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT \ +((uint32_t) 57671680) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 40) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT \ +((uint32_t) 410) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT \ +((uint16_t) 900) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 8000) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 10240) +#define VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER_DEFAULT \ +((uint32_t) 0) +#define VL53L1_TUNINGPARM_HIST_MERGE_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_DYNXTALK_MAX_SMUDGE_FACTOR_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_UWR_ENABLE_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MIN_DEFAULT \ +((int16_t) 2000) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MAX_DEFAULT \ +((int16_t) 2750) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MIN_DEFAULT \ +((int16_t) 250) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MAX_DEFAULT \ +((int16_t) 1000) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MIN_DEFAULT \ +((int16_t) 1250) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MAX_DEFAULT \ +((int16_t) 1750) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MIN_DEFAULT \ +((int16_t) 1250) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MAX_DEFAULT \ +((int16_t) 1750) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MIN_DEFAULT \ +((int16_t) -200) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MAX_DEFAULT \ +((int16_t) 200) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MIN_DEFAULT \ +((int16_t) 250) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MAX_DEFAULT \ +((int16_t) 1250) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEA_DEFAULT \ +((int16_t) 2300) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEB_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEA_DEFAULT \ +((int16_t) 2300) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEB_DEFAULT \ +((int16_t) 3050) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEA_DEFAULT \ +((int16_t) 4600) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEB_DEFAULT \ +((int16_t) 3050) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEA_DEFAULT \ +((int16_t) 4600) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEB_DEFAULT \ +((int16_t) 6200) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEA_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEB_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEA_DEFAULT \ +((int16_t) 6960) +#define VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEB_DEFAULT \ +((int16_t) 6190) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MIN_DEFAULT \ +((int16_t) 250) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MAX_DEFAULT \ +((int16_t) 1250) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MIN_DEFAULT \ +((int16_t) 3250) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MAX_DEFAULT \ +((int16_t) 4500) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MIN_DEFAULT \ +((int16_t) -200) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MAX_DEFAULT \ +((int16_t) 200) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MIN_DEFAULT \ +((int16_t) 2850) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MAX_DEFAULT \ +((int16_t) 3300) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MIN_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MAX_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEA_DEFAULT \ +((int16_t) 3850) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEB_DEFAULT \ +((int16_t) 4600) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEA_DEFAULT \ +((int16_t) 3850) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEB_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEA_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEB_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEA_DEFAULT \ +((int16_t) 7700) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEB_DEFAULT \ +((int16_t) 4640) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEA_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEB_DEFAULT \ +((int16_t) 0) + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_wait.h b/drivers/input/misc/vl53L1/inc/vl53l1_wait.h new file mode 100644 index 0000000000000000000000000000000000000000..9c49305bc5369740e9abd2de1bd67c3364bc2b37 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_wait.h @@ -0,0 +1,100 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_WAIT_H_ +#define _VL53L1_WAIT_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev); + + + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev); + + + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready); + + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/inc/vl53l1_zone_presets.h b/drivers/input/misc/vl53L1/inc/vl53l1_zone_presets.h new file mode 100644 index 0000000000000000000000000000000000000000..4629ea72eed2cf121ea79c66c8809ae2464f2f11 --- /dev/null +++ b/drivers/input/misc/vl53L1/inc/vl53l1_zone_presets.h @@ -0,0 +1,55 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_ZONE_PRESETS_H_ +#define _VL53L1_ZONE_PRESETS_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata); + + + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg); + + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/ipp/ipp_linux.c b/drivers/input/misc/vl53L1/ipp/ipp_linux.c new file mode 100644 index 0000000000000000000000000000000000000000..b3a16791514850e72d94fd836eb5e581a7ba5bbf --- /dev/null +++ b/drivers/input/misc/vl53L1/ipp/ipp_linux.c @@ -0,0 +1,336 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file ipp_linux.c kernel side implementation of vl53l1 protected processing + * + * @date Sep 1, 2016 + * @author : imaging + * + * @ingroup ipp_dev + */ + +#include "stmvl53l1.h" + +#define IPP_ERR_CODE (VL53L1_ERROR_PLATFORM_SPECIFIC_START-1) + +static int stmvl53l1_ipp_do_wrapper(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout, int payload_out) +{ + int rc; + + if (data->ipp.buzy) { + vl53l1_errmsg("try exec new ipp but still buzy on previous"); + /* TODO shall we discard it and push new ? */ + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pin->payload > IPP_WORK_MAX_PAYLOAD); + stmvl531_ipp_tim_start(data); + rc = stmvl53l1_ipp_do(data, pin, pout); + if (rc != 0) { + vl53l1_errmsg("stmvl53l1_ipp_do err %d\n", rc); + rc = IPP_ERR_CODE; + goto done; + } + vl53l1_dbgmsg("ipp ok \n"); + /* check what we got back if valid answer error etc */ + if (pout->status) { + vl53l1_errmsg("ipp error status %d from user", pout->status); + if (pout->status >= stmvl53l1_ipp_status_proc_code) + rc = pout->status & (stmvl53l1_ipp_status_proc_code-1); + else + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pout->payload > IPP_WORK_MAX_PAYLOAD); + if (pout->payload != payload_out) { + /* bad formated answer */ + vl53l1_errmsg("bad payload %d != %d in ipp work back", + pout->payload, payload_out); + rc = IPP_ERR_CODE; + goto done; + } + stmvl531_ipp_tim_stop(data); + stmvl531_ipp_stat(data, "ipp #%5x to=%3d fm=%3d in %5ld us", + pin->xfer_id, pin->payload, + pout->payload, + stmvl531_ipp_time(data)); + + rc = 0; +done: + + return rc; +} + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[in] pArea1 : Extern. allocated to save stack + * @param[in] pArea1 : Extern. allocated to save stack + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + uint8_t *pArea1, + uint8_t *pArea2, + uint8_t *phisto_merge_nb, + VL53L1_range_results_t *presults) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_range_results_t *presults_ipp; + + IPP_SERIALIZE_VAR; + + /* These external workspace input params are useless with IPP managed in + * the daemon because the histogram processing function is actually + * allocating its data in USER stack within the daemon not the kernel one + */ + (void)pArea1; + (void)pArea2; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 6); + IPP_SET_ARG_PTR(pin->data, 0, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 2, ppost_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + IPP_SET_ARG_PTR(pin->data, 4, pxtalk); + IPP_SET_ARG_PTR(pin->data, 5, phisto_merge_nb); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_cal_hist; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, presults_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(presults, presults_ipp, sizeof(*presults)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + int16_t *pambient_dmax_mm_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 4); + IPP_SET_ARG(pin->data, 0, target_reflectance); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 2, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_hist_ambient_dmax; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pambient_dmax_mm_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pambient_dmax_mm, pambient_dmax_mm_ipp, + sizeof(*pambient_dmax_mm)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_xtalk_histogram_data_t *pxtalk_shape_ipp; + VL53L1_xtalk_calibration_results_t *pxtalk_cal_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 1); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_ranges); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_xtalk_calibration; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 2); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_shape_ipp); + IPP_OUT_ARG_PTR(pout->data, 1, pxtalk_cal_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_shape, pxtalk_shape_ipp, sizeof(*pxtalk_shape)); + memcpy(pxtalk_cal, pxtalk_cal_ipp, sizeof(*pxtalk_cal)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_histogram_bin_data_t *pxtalk_avg_samples_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 3); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_results); + IPP_SET_ARG(pin->data, 1, expected_target_distance_mm); + IPP_SET_ARG(pin->data, 2, higher_reflectance); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_avg_samples_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_avg_samples, pxtalk_avg_samples_ipp, + sizeof(*pxtalk_avg_samples)); + + rc = 0; +done: + + return rc; +} diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_dmax.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_dmax.h new file mode 100644 index 0000000000000000000000000000000000000000..1e81a23051114742d96106a6ff17bec2c2ad4620 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_dmax.h @@ -0,0 +1,63 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_DMAX_H_ +#define _VL53L1_DMAX_H_ + +#include "vl53l1_types.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_dmax_private_structs.h" +#include "vl53l1_error_codes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_f_001( + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pcal, + VL53L1_hist_gen3_dmax_config_t *pcfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_dmax_private_data_t *pdata, + int16_t *pambient_dmax_mm); + + + + +uint32_t VL53L1_f_002( + uint32_t events_threshold, + uint32_t ref_signal_events, + uint32_t ref_distance_mm, + uint32_t signal_thresh_sigma); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_dmax_private_structs.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_dmax_private_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..d3395e3d25565f715ec66d64a2c6a649e58afbec --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_dmax_private_structs.h @@ -0,0 +1,89 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + + + +#ifndef _VL53L1_DMAX_PRIVATE_STRUCTS_H_ +#define _VL53L1_DMAX_PRIVATE_STRUCTS_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +typedef struct { + + uint32_t VL53L1_p_036; + + + uint8_t VL53L1_p_064; + + uint8_t VL53L1_p_065; + + + uint16_t VL53L1_p_066; + + uint16_t VL53L1_p_067; + + uint16_t VL53L1_p_068; + + uint16_t VL53L1_p_037; + + + uint32_t VL53L1_p_012; + + uint32_t VL53L1_p_033; + + + uint16_t VL53L1_p_001; + + + uint16_t VL53L1_p_006; + + + uint32_t VL53L1_p_004; + + uint32_t VL53L1_p_034; + + + int16_t VL53L1_p_035; + + int16_t VL53L1_p_007; + + +} VL53L1_hist_gen3_dmax_private_data_t; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_algos_gen3.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_algos_gen3.h new file mode 100644 index 0000000000000000000000000000000000000000..72ca3df9d7731a6991cc7f35ae81c83ace953c10 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_algos_gen3.h @@ -0,0 +1,156 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_ALGOS_GEN3_H_ +#define _VL53L1_HIST_ALGOS_GEN3_H_ + +#include "vl53l1_types.h" +#include "vl53l1_ll_def.h" + +#include "vl53l1_hist_private_structs.h" +#include "vl53l1_dmax_private_structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +void VL53L1_f_016( + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + + + +VL53L1_Error VL53L1_f_018( + uint16_t ambient_threshold_events_scaler, + int32_t ambient_threshold_sigma, + int32_t min_ambient_threshold_events, + uint8_t algo__crosstalk_compensation_enable, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_histogram_bin_data_t *pxtalk, + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + + + +VL53L1_Error VL53L1_f_019( + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + +VL53L1_Error VL53L1_f_020( + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + +VL53L1_Error VL53L1_f_021( + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + +VL53L1_Error VL53L1_f_028( + VL53L1_HistTargetOrder target_order, + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + +VL53L1_Error VL53L1_f_022( + uint8_t pulse_no, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + +VL53L1_Error VL53L1_f_027( + uint8_t pulse_no, + uint8_t clip_events, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + +VL53L1_Error VL53L1_f_030( + int16_t VL53L1_p_022, + int16_t VL53L1_p_026, + uint8_t VL53L1_p_031, + uint8_t clip_events, + VL53L1_histogram_bin_data_t *pbins, + uint32_t *pphase); + + + + +VL53L1_Error VL53L1_f_023( + uint8_t pulse_no, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_algo_private_data_t *palgo, + int32_t pad_value, + VL53L1_histogram_bin_data_t *ppulse); + + + + +VL53L1_Error VL53L1_f_026( + uint8_t bin, + uint8_t sigma_estimator__sigma_ref_mm, + uint8_t VL53L1_p_031, + uint8_t VL53L1_p_055, + uint8_t crosstalk_compensation_enable, + VL53L1_histogram_bin_data_t *phist_data_ap, + VL53L1_histogram_bin_data_t *phist_data_zp, + VL53L1_histogram_bin_data_t *pxtalk_hist, + uint16_t *psigma_est); + + + + +void VL53L1_f_029( + uint8_t range_id, + uint8_t valid_phase_low, + uint8_t valid_phase_high, + uint16_t sigma_thres, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_pulse_data_t *ppulse, + VL53L1_range_data_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_algos_gen4.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_algos_gen4.h new file mode 100644 index 0000000000000000000000000000000000000000..1c4eb162419b5b9062b39d5c1d461ac2157586d0 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_algos_gen4.h @@ -0,0 +1,102 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_ALGOS_GEN4_H_ +#define _VL53L1_HIST_ALGOS_GEN4_H_ + +#include "vl53l1_types.h" +#include "vl53l1_ll_def.h" + +#include "vl53l1_hist_private_structs.h" +#include "vl53l1_dmax_private_structs.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +void VL53L1_f_032( + VL53L1_hist_gen4_algo_filtered_data_t *palgo); + + + + +VL53L1_Error VL53L1_f_033( + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_histogram_bin_data_t *pxtalk, + VL53L1_hist_gen3_algo_private_data_t *palgo, + VL53L1_hist_gen4_algo_filtered_data_t *pfiltered, + VL53L1_hist_gen3_dmax_private_data_t *pdmax_algo, + VL53L1_range_results_t *presults, + uint8_t histo_merge_nb); + + + + + +VL53L1_Error VL53L1_f_034( + uint8_t pulse_no, + VL53L1_histogram_bin_data_t *ppulse, + VL53L1_hist_gen3_algo_private_data_t *palgo, + VL53L1_hist_gen4_algo_filtered_data_t *pfiltered); + + + + +VL53L1_Error VL53L1_f_035( + uint8_t pulse_no, + uint16_t noise_threshold, + VL53L1_hist_gen4_algo_filtered_data_t *pfiltered, + VL53L1_hist_gen3_algo_private_data_t *palgo); + + + + +VL53L1_Error VL53L1_f_036( + uint8_t bin, + int32_t VL53L1_p_003, + int32_t VL53L1_p_018, + int32_t VL53L1_p_001, + int32_t ax, + int32_t bx, + int32_t cx, + int32_t VL53L1_p_004, + uint8_t VL53L1_p_031, + uint32_t *pmedian_phase); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_core.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_core.h new file mode 100644 index 0000000000000000000000000000000000000000..e53c4d92512e86bef22d079f1821fac9e3c6d80b --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_core.h @@ -0,0 +1,100 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_CORE_H_ +#define _VL53L1_HIST_CORE_H_ + +#include "vl53l1_types.h" +#include "vl53l1_ll_def.h" +#include "vl53l1_hist_private_structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +void VL53L1_f_013( + uint8_t VL53L1_p_018, + uint8_t filter_woi, + VL53L1_histogram_bin_data_t *pbins, + int32_t *pa, + int32_t *pb, + int32_t *pc); + + + + +VL53L1_Error VL53L1_f_011( + uint16_t vcsel_width, + uint16_t fast_osc_frequency, + uint32_t total_periods_elapsed, + uint16_t VL53L1_p_006, + VL53L1_range_data_t *pdata, + uint8_t histo_merge_nb); + + + + +void VL53L1_f_012( + uint16_t gain_factor, + int16_t range_offset_mm, + VL53L1_range_data_t *pdata); + + + + +void VL53L1_f_037( + VL53L1_histogram_bin_data_t *pdata, + int32_t ambient_estimate_counts_per_bin); + + + + +void VL53L1_f_004( + VL53L1_histogram_bin_data_t *pxtalk, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_histogram_bin_data_t *pxtalk_realigned); + + + +int8_t VL53L1_f_038( + VL53L1_histogram_bin_data_t *pdata1, + VL53L1_histogram_bin_data_t *pdata2); + + + +VL53L1_Error VL53L1_f_039( + VL53L1_histogram_bin_data_t *pidata, + VL53L1_histogram_bin_data_t *podata); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_funcs.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_funcs.h new file mode 100644 index 0000000000000000000000000000000000000000..070c6880fe924728d6a6c3b3d0974697566093d8 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_funcs.h @@ -0,0 +1,67 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_FUNCS_H_ +#define _VL53L1_HIST_FUNCS_H_ + +#include "vl53l1_types.h" +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +VL53L1_Error VL53L1_hist_process_data( + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + uint8_t *pArea1, + uint8_t *pArea2, + VL53L1_range_results_t *presults, + uint8_t *HistMergeNumber); + + + + +VL53L1_Error VL53L1_hist_ambient_dmax( + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_private_structs.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_private_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..2fd0fde0544f21a7a00a3e824c292c76de409566 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_hist_private_structs.h @@ -0,0 +1,269 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + +#ifndef _VL53L1_HIST_PRIVATE_STRUCTS_H_ +#define _VL53L1_HIST_PRIVATE_STRUCTS_H_ + +#include "vl53l1_types.h" +#include "vl53l1_hist_structs.h" + +#define VL53L1_D_001 8 + +#ifdef __cplusplus +extern "C" { +#endif + + + + +typedef struct { + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_023; + + uint8_t VL53L1_p_024; + + uint8_t VL53L1_p_030; + + int32_t VL53L1_p_020; + + + int32_t VL53L1_p_048[VL53L1_HISTOGRAM_BUFFER_SIZE]; + int32_t VL53L1_p_069[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + uint8_t VL53L1_p_043[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_008[VL53L1_HISTOGRAM_BUFFER_SIZE]; + uint16_t VL53L1_p_017[VL53L1_HISTOGRAM_BUFFER_SIZE]; + uint16_t VL53L1_p_011[VL53L1_HISTOGRAM_BUFFER_SIZE]; + +} VL53L1_hist_gen1_algo_private_data_t; + + + + +typedef struct { + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_023; + + uint8_t VL53L1_p_024; + + uint16_t VL53L1_p_019; + + uint8_t VL53L1_p_009; + + uint8_t VL53L1_p_030; + + int32_t VL53L1_p_004; + + int32_t VL53L1_p_020; + + + int32_t VL53L1_p_003[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_018[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_001[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + int32_t VL53L1_p_008[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_041[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_039[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_040[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + +} VL53L1_hist_gen2_algo_filtered_data_t; + + + + +typedef struct { + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_023; + + uint8_t VL53L1_p_024; + + int32_t VL53L1_p_032; + + + uint8_t VL53L1_p_042[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + uint8_t VL53L1_p_044[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + uint32_t VL53L1_p_017[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + uint16_t VL53L1_p_011[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + uint8_t VL53L1_p_043[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + +} VL53L1_hist_gen2_algo_detection_data_t; + + + + +typedef struct { + + uint8_t VL53L1_p_015; + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_025; + + uint8_t VL53L1_p_026; + + uint8_t VL53L1_p_016; + + + uint8_t VL53L1_p_027; + + uint8_t VL53L1_p_055; + + + int32_t VL53L1_p_020; + + int32_t VL53L1_p_021; + + int32_t VL53L1_p_013; + + + uint32_t VL53L1_p_028; + + uint32_t VL53L1_p_014; + + uint32_t VL53L1_p_029; + + + uint16_t VL53L1_p_005; + + +} VL53L1_hist_pulse_data_t; + + + + +typedef struct { + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_023; + + uint8_t VL53L1_p_024; + + uint8_t VL53L1_p_031; + + uint8_t VL53L1_p_045; + + int32_t VL53L1_p_004; + + int32_t VL53L1_p_032; + + + uint8_t VL53L1_p_043[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + uint8_t VL53L1_p_046[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + uint8_t VL53L1_p_047[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + int32_t VL53L1_p_056[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_048[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_008[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + uint8_t VL53L1_p_049; + + uint8_t VL53L1_p_050; + + uint8_t VL53L1_p_051; + + + VL53L1_hist_pulse_data_t VL53L1_p_002[VL53L1_D_001]; + + + + + VL53L1_histogram_bin_data_t VL53L1_p_010; + + VL53L1_histogram_bin_data_t VL53L1_p_038; + + VL53L1_histogram_bin_data_t VL53L1_p_052; + + VL53L1_histogram_bin_data_t VL53L1_p_053; + + VL53L1_histogram_bin_data_t VL53L1_p_054; + + + + +} VL53L1_hist_gen3_algo_private_data_t; + + + + +typedef struct { + + uint8_t VL53L1_p_022; + + uint8_t VL53L1_p_023; + + uint8_t VL53L1_p_024; + + + int32_t VL53L1_p_003[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_018[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_001[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + int32_t VL53L1_p_039[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + int32_t VL53L1_p_040[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + uint8_t VL53L1_p_043[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + +} VL53L1_hist_gen4_algo_filtered_data_t; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_sigma_estimate.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_sigma_estimate.h new file mode 100644 index 0000000000000000000000000000000000000000..9aa88da09381c58289f4b4a6134c7b1989ef47d5 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_sigma_estimate.h @@ -0,0 +1,126 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#ifndef _VL53L1_SIGMA_ESTIMATE_H_ +#define _VL53L1_SIGMA_ESTIMATE_H_ + +#include "vl53l1_types.h" +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define VL53L1_D_002 0xFFFF + + +#define VL53L1_D_008 0xFFFF +#define VL53L1_D_003 0xFFFFFF +#define VL53L1_D_007 0xFFFFFFFF +#define VL53L1_D_005 0x7FFFFFFFFF +#define VL53L1_D_009 0xFFFFFFFFFF +#define VL53L1_D_010 0xFFFFFFFFFFFF +#define VL53L1_D_004 0xFFFFFFFFFFFFFF +#define VL53L1_D_006 0x7FFFFFFFFFFFFFFF +#define VL53L1_D_011 0xFFFFFFFFFFFFFFFF + + + + +uint16_t VL53L1_f_042( + uint8_t sigma_estimator__effective_pulse_width_ns, + uint8_t sigma_estimator__effective_ambient_width_ns, + uint8_t sigma_estimator__sigma_ref_mm, + VL53L1_range_data_t *pdata); + + + + +uint16_t VL53L1_f_044( + uint8_t sigma_estimator__effective_pulse_width_ns, + uint8_t sigma_estimator__effective_ambient_width_ns, + uint8_t sigma_estimator__sigma_ref_mm, + VL53L1_range_data_t *pdata); + + + + + + +VL53L1_Error VL53L1_f_045( + uint8_t sigma_estimator__sigma_ref_mm, + uint32_t VL53L1_p_003, + uint32_t VL53L1_p_018, + uint32_t VL53L1_p_001, + uint32_t a_zp, + uint32_t c_zp, + uint32_t bx, + uint32_t ax_zp, + uint32_t cx_zp, + uint32_t VL53L1_p_004, + uint16_t fast_osc_frequency, + uint16_t *psigma_est); + + + + + + + +VL53L1_Error VL53L1_f_014( + uint8_t sigma_estimator__sigma_ref_mm, + uint32_t VL53L1_p_003, + uint32_t VL53L1_p_018, + uint32_t VL53L1_p_001, + uint32_t a_zp, + uint32_t c_zp, + uint32_t bx, + uint32_t ax_zp, + uint32_t cx_zp, + uint32_t VL53L1_p_004, + uint16_t fast_osc_frequency, + uint16_t *psigma_est); + + + +uint32_t VL53L1_f_046( + uint64_t VL53L1_p_003, + uint32_t size + ); + + + + + +uint32_t VL53L1_f_043( + uint32_t VL53L1_p_003, + uint32_t VL53L1_p_018); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_xtalk.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_xtalk.h new file mode 100644 index 0000000000000000000000000000000000000000..936f76c82d2a78f07d49f264aa4b68197acff7a4 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_xtalk.h @@ -0,0 +1,168 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + + + +#ifndef _VL53L1_XTALK_H_ +#define _VL53L1_XTALK_H_ + +#include "vl53l1_types.h" +#include "vl53l1_ll_def.h" +#include "vl53l1_xtalk_private_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + +VL53L1_Error VL53L1_xtalk_calibration_process_data( + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal); + + + + +VL53L1_Error VL53L1_f_049( + VL53L1_histogram_bin_data_t *pavg_bins, + VL53L1_xtalk_algo_data_t *pdebug, + VL53L1_xtalk_range_data_t *pxtalk_data, + uint8_t histogram__window_start, + uint8_t histogram__window_end, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + +VL53L1_Error VL53L1_f_047( + VL53L1_xtalk_range_results_t *pxtalk_results, + VL53L1_xtalk_algo_data_t *pdebug, + int16_t *xgradient, + int16_t *ygradient); + + + + +VL53L1_Error VL53L1_f_048( + VL53L1_xtalk_range_data_t *pxtalk_data, + VL53L1_xtalk_algo_data_t *pdebug, + uint32_t *xtalk_mean_offset_kcps); + + + + +VL53L1_Error VL53L1_f_053( + VL53L1_histogram_bin_data_t *phist_data, + VL53L1_xtalk_range_data_t *pxtalk_data, + VL53L1_xtalk_algo_data_t *pdebug, + VL53L1_xtalk_histogram_shape_t *pxtalk_histo); + + + + + +VL53L1_Error VL53L1_f_040( + uint32_t mean_offset, + int16_t xgradient, + int16_t ygradient, + int8_t centre_offset_x, + int8_t centre_offset_y, + uint16_t roi_effective_spads, + uint8_t roi_centre_spad, + uint8_t roi_xy_size, + uint32_t *xtalk_rate_kcps); + + + + +VL53L1_Error VL53L1_f_041( + VL53L1_histogram_bin_data_t *phist_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_data, + uint32_t xtalk_rate_kcps, + VL53L1_histogram_bin_data_t *pxtalkcount_data); + + + + +VL53L1_Error VL53L1_f_055( + VL53L1_histogram_bin_data_t *phist_data, + VL53L1_histogram_bin_data_t *pxtalk_data, + uint8_t xtalk_bin_offset); + + + +VL53L1_Error VL53L1_f_052( + VL53L1_histogram_bin_data_t *pxtalk_data, + uint32_t amb_threshold, + uint8_t VL53L1_p_022, + uint8_t VL53L1_p_026); + + + +VL53L1_Error VL53L1_f_054( + VL53L1_customer_nvm_managed_t *pcustomer, + VL53L1_dynamic_config_t *pdyn_cfg, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_histogram_bin_data_t *pip_hist_data, + VL53L1_histogram_bin_data_t *pop_hist_data, + VL53L1_histogram_bin_data_t *pxtalk_count_data); + + + + +VL53L1_Error VL53L1_f_051( + uint8_t sigma_mult, + int32_t VL53L1_p_004, + uint32_t *ambient_noise); + + + +VL53L1_Error VL53L1_generate_dual_reflectance_xtalk_samples( + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples +); + + + + + +VL53L1_Error VL53L1_f_050( + VL53L1_histogram_bin_data_t *pzone_avg_1, + VL53L1_histogram_bin_data_t *pzone_avg_2, + uint16_t expected_target_distance, + uint8_t subtract_amb, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_output +); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/inc/vl53l1_xtalk_private_structs.h b/drivers/input/misc/vl53L1/protected/inc/vl53l1_xtalk_private_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..788ace14da0d09f5e33a6c64b433ff3dada36a03 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/inc/vl53l1_xtalk_private_structs.h @@ -0,0 +1,75 @@ + +/* SPDX-License-Identifier: BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + + +#ifndef _VL53L1_XTALK_PRIVATE_STRUCTS_H_ +#define _VL53L1_XTALK_PRIVATE_STRUCTS_H_ + +#include "vl53l1_types.h" +#include "vl53l1_hist_structs.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_D_012 4 + + + +typedef struct { + + + + + uint32_t VL53L1_p_062[VL53L1_D_012]; + + + int16_t VL53L1_p_060; + + int16_t VL53L1_p_061; + + + VL53L1_histogram_bin_data_t VL53L1_p_057; + + VL53L1_histogram_bin_data_t VL53L1_p_058; + + + + uint32_t VL53L1_p_059; + + + uint32_t VL53L1_p_063[VL53L1_XTALK_HISTO_BINS]; + + +} VL53L1_xtalk_algo_data_t; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/protected/src/vl53l1_dmax.c b/drivers/input/misc/vl53L1/protected/src/vl53l1_dmax.c new file mode 100644 index 0000000000000000000000000000000000000000..23cda26565f4aa9653bfcb5dd7753d9e63e56081 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/src/vl53l1_dmax.c @@ -0,0 +1,299 @@ + +// SPDX-License-Identifier: BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#include "vl53l1_types.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_platform_user_defines.h" +#include "vl53l1_core_support.h" +#include "vl53l1_error_codes.h" + +#include "vl53l1_dmax.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_PROTECTED, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_PROTECTED, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_PROTECTED, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_PROTECTED, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_f_001( + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pcal, + VL53L1_hist_gen3_dmax_config_t *pcfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_dmax_private_data_t *pdata, + int16_t *pambient_dmax_mm) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t pll_period_us = 0; + uint32_t periods_elapsed = 0; + + uint32_t tmp32 = 0; + uint64_t tmp64 = 0; + + uint32_t amb_thres_delta = 0; + + LOG_FUNCTION_START(""); + + + + pdata->VL53L1_p_006 = 0x0000; + pdata->VL53L1_p_033 = 0x0000; + pdata->VL53L1_p_001 = 0x0000; + pdata->VL53L1_p_012 = 0x0000; + pdata->VL53L1_p_004 = 0x0000; + pdata->VL53L1_p_034 = 0x0000; + pdata->VL53L1_p_035 = 0; + pdata->VL53L1_p_007 = 0; + + *pambient_dmax_mm = 0; + + + if ((pbins->VL53L1_p_019 != 0) && + (pbins->total_periods_elapsed != 0)) { + + + + pll_period_us = + VL53L1_calc_pll_period_us(pbins->VL53L1_p_019); + + + + periods_elapsed = pbins->total_periods_elapsed + 1; + + + + pdata->VL53L1_p_036 = + VL53L1_duration_maths( + pll_period_us, + 1<<4, + VL53L1_RANGING_WINDOW_VCSEL_PERIODS, + periods_elapsed); + + + pdata->VL53L1_p_001 = + VL53L1_rate_maths( + pbins->VL53L1_p_004, + pdata->VL53L1_p_036); + + + + pdata->VL53L1_p_033 = + VL53L1_events_per_spad_maths( + pbins->VL53L1_p_004, + pbins->result__dss_actual_effective_spads, + pdata->VL53L1_p_036); + + + + pdata->VL53L1_p_037 = pcfg->max_effective_spads; + pdata->VL53L1_p_006 = pcfg->max_effective_spads; + + if (pdata->VL53L1_p_033 > 0) { + tmp64 = + (uint64_t)pcfg->dss_config__target_total_rate_mcps; + tmp64 *= 1000; + tmp64 <<= (11+1); + tmp32 = pdata->VL53L1_p_033/2; + tmp64 += (uint64_t)tmp32; + tmp64 = do_division_u(tmp64, + (uint64_t)pdata->VL53L1_p_033); + + if (tmp64 < (uint64_t)pcfg->max_effective_spads) + pdata->VL53L1_p_006 = (uint16_t)tmp64; + } + } + + + + if ((pcal->ref__actual_effective_spads != 0) && + (pbins->VL53L1_p_019 != 0) && + (pcal->ref_reflectance_pc != 0) && + (pbins->total_periods_elapsed != 0)) { + + + + tmp64 = (uint64_t)pcal->ref__peak_signal_count_rate_mcps; + tmp64 *= (1000 * 256); + tmp32 = pcal->ref__actual_effective_spads/2; + tmp64 += (uint64_t)tmp32; + tmp64 = do_division_u(tmp64, + (uint64_t)pcal->ref__actual_effective_spads); + + pdata->VL53L1_p_012 = (uint32_t)tmp64; + pdata->VL53L1_p_012 <<= 4; + + + + tmp64 = (uint64_t)pdata->VL53L1_p_036; + tmp64 *= (uint64_t)pdata->VL53L1_p_033; + tmp64 *= (uint64_t)pdata->VL53L1_p_006; + tmp64 += (1<<(11+7)); + tmp64 >>= (11+8); + tmp64 += 500; + tmp64 = do_division_u(tmp64, 1000); + + + if (tmp64 > 0x00FFFFFF) + tmp64 = 0x00FFFFFF; + + pdata->VL53L1_p_004 = (uint32_t)tmp64; + + + + tmp64 = (uint64_t)pdata->VL53L1_p_036; + tmp64 *= (uint64_t)pdata->VL53L1_p_012; + tmp64 *= (uint64_t)pdata->VL53L1_p_006; + tmp64 += (1<<(11+7)); + tmp64 >>= (11+8); + + + + tmp64 *= ((uint64_t)target_reflectance * + (uint64_t)pcal->coverglass_transmission); + + tmp64 += ((uint64_t)pcal->ref_reflectance_pc * 128); + tmp64 = do_division_u(tmp64, + ((uint64_t)pcal->ref_reflectance_pc * 256)); + + tmp64 += 500; + tmp64 = do_division_u(tmp64, 1000); + + + if (tmp64 > 0x00FFFFFF) + tmp64 = 0x00FFFFFF; + + pdata->VL53L1_p_034 = (uint32_t)tmp64; + + + + tmp32 = VL53L1_isqrt(pdata->VL53L1_p_004 << 8); + tmp32 *= (uint32_t)pcfg->ambient_thresh_sigma; + + + + if (pdata->VL53L1_p_004 < + (uint32_t)pcfg->min_ambient_thresh_events) { + + amb_thres_delta = + pcfg->min_ambient_thresh_events - + (uint32_t)pdata->VL53L1_p_004; + + + amb_thres_delta <<= 8; + + if (tmp32 < amb_thres_delta) + tmp32 = amb_thres_delta; + } + + + + pdata->VL53L1_p_007 = + (int16_t)VL53L1_f_002( + tmp32, + pdata->VL53L1_p_034, + (uint32_t)pcal->ref__distance_mm, + (uint32_t)pcfg->signal_thresh_sigma); + + + + tmp32 = (uint32_t)pdata->VL53L1_p_034; + tmp32 *= (uint32_t)pbins->vcsel_width; + tmp32 += (1 << 3); + tmp32 /= (1 << 4); + + pdata->VL53L1_p_035 = + (int16_t)VL53L1_f_002( + 256 * (uint32_t)pcfg->signal_total_events_limit, + tmp32, + (uint32_t)pcal->ref__distance_mm, + (uint32_t)pcfg->signal_thresh_sigma); + + + + + if (pdata->VL53L1_p_035 < pdata->VL53L1_p_007) + *pambient_dmax_mm = pdata->VL53L1_p_035; + else + *pambient_dmax_mm = pdata->VL53L1_p_007; + + } + + LOG_FUNCTION_END(status); + + return status; + +} + + +uint32_t VL53L1_f_002( + uint32_t events_threshold, + uint32_t ref_signal_events, + uint32_t ref_distance_mm, + uint32_t signal_thresh_sigma) +{ + + + + uint32_t tmp32 = 0; + uint32_t range_mm = 0; + + tmp32 = 4 * events_threshold; + + + + tmp32 += ((uint32_t)signal_thresh_sigma * + (uint32_t)signal_thresh_sigma); + + + + tmp32 = VL53L1_isqrt(tmp32); + tmp32 += (uint32_t)signal_thresh_sigma; + + + + range_mm = + (uint32_t)VL53L1_isqrt(ref_signal_events << 4); + range_mm *= ref_distance_mm; + + if (tmp32 > 0) { + range_mm += (tmp32); + range_mm /= (2*tmp32); + } + + return range_mm; + +} + diff --git a/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_algos_gen3.c b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_algos_gen3.c new file mode 100644 index 0000000000000000000000000000000000000000..8596a55e2b3c2c0c4c61e3ad44b9f41f19473327 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_algos_gen3.c @@ -0,0 +1,857 @@ + +// SPDX-License-Identifier: BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#include "vl53l1_types.h" +#include "vl53l1_platform_log.h" + +#include "vl53l1_core_support.h" +#include "vl53l1_error_codes.h" + +#include "vl53l1_hist_core.h" +#include "vl53l1_hist_algos_gen3.h" +#include "vl53l1_sigma_estimate.h" +#include "vl53l1_dmax.h" + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +void VL53L1_f_016( + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + uint8_t lb = 0; + + palgo->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + palgo->VL53L1_p_022 = 0; + palgo->VL53L1_p_024 = 0; + palgo->VL53L1_p_045 = 0; + palgo->VL53L1_p_004 = 0; + palgo->VL53L1_p_032 = 0; + + for (lb = palgo->VL53L1_p_022; lb < palgo->VL53L1_p_023; lb++) { + palgo->VL53L1_p_043[lb] = 0; + palgo->VL53L1_p_046[lb] = 0; + palgo->VL53L1_p_047[lb] = 0; + palgo->VL53L1_p_048[lb] = 0; + palgo->VL53L1_p_008[lb] = 0; + } + + palgo->VL53L1_p_049 = 0; + palgo->VL53L1_p_050 = VL53L1_D_001; + palgo->VL53L1_p_051 = 0; + + + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(palgo->VL53L1_p_010)); + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(palgo->VL53L1_p_038)); + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(palgo->VL53L1_p_052)); + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(palgo->VL53L1_p_053)); + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(palgo->VL53L1_p_054)); +} + + + +VL53L1_Error VL53L1_f_018( + uint16_t ambient_threshold_events_scaler, + int32_t ambient_threshold_sigma, + int32_t min_ambient_threshold_events, + uint8_t algo__crosstalk_compensation_enable, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_histogram_bin_data_t *pxtalk, + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t lb = 0; + uint8_t VL53L1_p_001 = 0; + int64_t tmp = 0; + int32_t amb_events = 0; + int32_t VL53L1_p_008 = 0; + int32_t samples = 0; + + LOG_FUNCTION_START(""); + + + palgo->VL53L1_p_023 = pbins->VL53L1_p_023; + palgo->VL53L1_p_022 = pbins->VL53L1_p_022; + palgo->VL53L1_p_024 = pbins->VL53L1_p_024; + palgo->VL53L1_p_004 = pbins->VL53L1_p_004; + + + + palgo->VL53L1_p_031 = + VL53L1_decode_vcsel_period(pbins->VL53L1_p_009); + + + + tmp = (int64_t)pbins->VL53L1_p_004; + tmp *= (int64_t)ambient_threshold_events_scaler; + tmp += 2048; + tmp = do_division_s(tmp, 4096); + amb_events = (int32_t)tmp; + + + + for (lb = 0; lb < pbins->VL53L1_p_024; lb++) { + + VL53L1_p_001 = lb >> 2; + samples = (int32_t)pbins->bin_rep[VL53L1_p_001]; + + if (samples > 0) { + + if (lb < pxtalk->VL53L1_p_024 && + algo__crosstalk_compensation_enable > 0) + VL53L1_p_008 = samples * (amb_events + + pxtalk->bin_data[lb]); + else + VL53L1_p_008 = samples * amb_events; + + VL53L1_p_008 = VL53L1_isqrt(VL53L1_p_008); + + VL53L1_p_008 += (samples/2); + VL53L1_p_008 /= samples; + VL53L1_p_008 *= ambient_threshold_sigma; + VL53L1_p_008 += 8; + VL53L1_p_008 /= 16; + VL53L1_p_008 += amb_events; + + if (VL53L1_p_008 < min_ambient_threshold_events) + VL53L1_p_008 = min_ambient_threshold_events; + + palgo->VL53L1_p_056[lb] = VL53L1_p_008; + palgo->VL53L1_p_032 = VL53L1_p_008; + } + + + + } + + + + palgo->VL53L1_p_045 = 0; + + for (lb = pbins->VL53L1_p_022; lb < pbins->VL53L1_p_024; lb++) { + + if (pbins->bin_data[lb] > palgo->VL53L1_p_056[lb]) { + palgo->VL53L1_p_043[lb] = 1; + palgo->VL53L1_p_046[lb] = 1; + palgo->VL53L1_p_045++; + } else { + palgo->VL53L1_p_043[lb] = 0; + palgo->VL53L1_p_046[lb] = 0; + } + } + + LOG_FUNCTION_END(status); + + return status; + +} + + + + +VL53L1_Error VL53L1_f_019( + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t j = 0; + uint8_t found = 0; + + LOG_FUNCTION_START(""); + + palgo->VL53L1_p_049 = 0; + + for (i = 0; i < palgo->VL53L1_p_031; i++) { + + j = (i + 1) % palgo->VL53L1_p_031; + + + + if (i < palgo->VL53L1_p_024 && j < palgo->VL53L1_p_024) { + if (palgo->VL53L1_p_046[i] == 0 && + palgo->VL53L1_p_046[j] == 1 && + found == 0) { + palgo->VL53L1_p_049 = i; + found = 1; + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_020( + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t i = 0; + uint8_t j = 0; + uint8_t lb = 0; + + LOG_FUNCTION_START(""); + + for (lb = palgo->VL53L1_p_049; + lb < (palgo->VL53L1_p_049 + + palgo->VL53L1_p_031); + lb++) { + + + + i = lb % palgo->VL53L1_p_031; + j = (lb + 1) % palgo->VL53L1_p_031; + + + + if (i < palgo->VL53L1_p_024 && j < palgo->VL53L1_p_024) { + + if (palgo->VL53L1_p_046[i] == 0 && + palgo->VL53L1_p_046[j] == 1) + palgo->VL53L1_p_051++; + + if (palgo->VL53L1_p_046[i] > 0) + palgo->VL53L1_p_047[i] = palgo->VL53L1_p_051; + else + palgo->VL53L1_p_047[i] = 0; + } + + } + + + if (palgo->VL53L1_p_051 > palgo->VL53L1_p_050) + palgo->VL53L1_p_051 = palgo->VL53L1_p_050; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_f_021( + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t j = 0; + uint8_t blb = 0; + uint8_t pulse_no = 0; + + uint8_t max_filter_half_width = 0; + + VL53L1_hist_pulse_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + max_filter_half_width = palgo->VL53L1_p_031 - 1; + max_filter_half_width = max_filter_half_width >> 1; + + for (blb = palgo->VL53L1_p_049; + blb < (palgo->VL53L1_p_049 + + palgo->VL53L1_p_031); + blb++) { + + + + i = blb % palgo->VL53L1_p_031; + j = (blb + 1) % palgo->VL53L1_p_031; + + + + if (i < palgo->VL53L1_p_024 && + j < palgo->VL53L1_p_024) { + + + + if (palgo->VL53L1_p_047[i] == 0 && + palgo->VL53L1_p_047[j] > 0) { + + pulse_no = palgo->VL53L1_p_047[j] - 1; + pdata = &(palgo->VL53L1_p_002[pulse_no]); + + if (pulse_no < palgo->VL53L1_p_050) { + pdata->VL53L1_p_015 = blb; + pdata->VL53L1_p_022 = blb + 1; + pdata->VL53L1_p_025 = 0xFF; + pdata->VL53L1_p_026 = 0; + pdata->VL53L1_p_016 = 0; + } + } + + + + if (palgo->VL53L1_p_047[i] > 0 + && palgo->VL53L1_p_047[j] == 0) { + + pulse_no = palgo->VL53L1_p_047[i] - 1; + pdata = &(palgo->VL53L1_p_002[pulse_no]); + + if (pulse_no < palgo->VL53L1_p_050) { + + pdata->VL53L1_p_026 = blb; + pdata->VL53L1_p_016 = blb + 1; + + pdata->VL53L1_p_027 = + (pdata->VL53L1_p_026 + 1) - + pdata->VL53L1_p_022; + pdata->VL53L1_p_055 = + (pdata->VL53L1_p_016 + 1) - + pdata->VL53L1_p_015; + + if (pdata->VL53L1_p_055 > + max_filter_half_width) + pdata->VL53L1_p_055 = + max_filter_half_width; + } + + } + } + } + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_f_028( + VL53L1_HistTargetOrder target_order, + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_hist_pulse_data_t tmp; + VL53L1_hist_pulse_data_t *ptmp = &tmp; + VL53L1_hist_pulse_data_t *p0; + VL53L1_hist_pulse_data_t *p1; + + uint8_t i = 0; + uint8_t swapped = 1; + + LOG_FUNCTION_START(""); + + if (!(palgo->VL53L1_p_051 > 1)) + goto ENDFUNC; + + while (swapped > 0) { + + swapped = 0; + + for (i = 1; i < palgo->VL53L1_p_051; i++) { + + p0 = &(palgo->VL53L1_p_002[i-1]); + p1 = &(palgo->VL53L1_p_002[i]); + + + + if (target_order + == VL53L1_HIST_TARGET_ORDER__STRONGEST_FIRST) { + + if (p0->VL53L1_p_013 < + p1->VL53L1_p_013) { + + + + memcpy(ptmp, + p1, sizeof(VL53L1_hist_pulse_data_t)); + memcpy(p1, + p0, sizeof(VL53L1_hist_pulse_data_t)); + memcpy(p0, + ptmp, sizeof(VL53L1_hist_pulse_data_t)); + + swapped = 1; + } + + } else { + + if (p0->VL53L1_p_014 > p1->VL53L1_p_014) { + + + + memcpy(ptmp, + p1, sizeof(VL53L1_hist_pulse_data_t)); + memcpy(p1, + p0, sizeof(VL53L1_hist_pulse_data_t)); + memcpy(p0, + ptmp, sizeof(VL53L1_hist_pulse_data_t)); + + swapped = 1; + } + + } + } + } + +ENDFUNC: + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_f_022( + uint8_t pulse_no, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t lb = 0; + + VL53L1_hist_pulse_data_t *pdata = &(palgo->VL53L1_p_002[pulse_no]); + + LOG_FUNCTION_START(""); + + + + pdata->VL53L1_p_021 = 0; + pdata->VL53L1_p_020 = 0; + + for (lb = pdata->VL53L1_p_015; lb <= pdata->VL53L1_p_016; lb++) { + i = lb % palgo->VL53L1_p_031; + pdata->VL53L1_p_021 += pbins->bin_data[i]; + pdata->VL53L1_p_020 += palgo->VL53L1_p_004; + } + + + + pdata->VL53L1_p_013 = + pdata->VL53L1_p_021 - pdata->VL53L1_p_020; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_027( + uint8_t pulse_no, + uint8_t clip_events, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_algo_private_data_t *palgo) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + int16_t VL53L1_p_015 = 0; + int16_t VL53L1_p_016 = 0; + int16_t window_width = 0; + uint32_t tmp_phase = 0; + + VL53L1_hist_pulse_data_t *pdata = &(palgo->VL53L1_p_002[pulse_no]); + + LOG_FUNCTION_START(""); + + + + i = pdata->VL53L1_p_025 % palgo->VL53L1_p_031; + + VL53L1_p_015 = (int16_t)i; + VL53L1_p_015 += (int16_t)pdata->VL53L1_p_015; + VL53L1_p_015 -= (int16_t)pdata->VL53L1_p_025; + + VL53L1_p_016 = (int16_t)i; + VL53L1_p_016 += (int16_t)pdata->VL53L1_p_016; + VL53L1_p_016 -= (int16_t)pdata->VL53L1_p_025; + + + window_width = VL53L1_p_016 - VL53L1_p_015; + if (window_width > 3) + window_width = 3; + + status = + VL53L1_f_030( + VL53L1_p_015, + VL53L1_p_015 + window_width, + palgo->VL53L1_p_031, + clip_events, + pbins, + &(pdata->VL53L1_p_028)); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_030( + VL53L1_p_016 - window_width, + VL53L1_p_016, + palgo->VL53L1_p_031, + clip_events, + pbins, + &(pdata->VL53L1_p_029)); + + + if (pdata->VL53L1_p_028 > pdata->VL53L1_p_029) { + tmp_phase = pdata->VL53L1_p_028; + pdata->VL53L1_p_028 = pdata->VL53L1_p_029; + pdata->VL53L1_p_029 = tmp_phase; + } + + + if (pdata->VL53L1_p_014 < pdata->VL53L1_p_028) + pdata->VL53L1_p_028 = pdata->VL53L1_p_014; + + + if (pdata->VL53L1_p_014 > pdata->VL53L1_p_029) + pdata->VL53L1_p_029 = pdata->VL53L1_p_014; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_030( + int16_t VL53L1_p_022, + int16_t VL53L1_p_026, + uint8_t VL53L1_p_031, + uint8_t clip_events, + VL53L1_histogram_bin_data_t *pbins, + uint32_t *pphase) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int16_t i = 0; + int16_t lb = 0; + + int64_t VL53L1_p_008 = 0; + int64_t event_sum = 0; + int64_t weighted_sum = 0; + + LOG_FUNCTION_START(""); + + *pphase = VL53L1_MAX_ALLOWED_PHASE; + + for (lb = VL53L1_p_022; lb <= VL53L1_p_026; lb++) { + + + if (lb < 0) + i = lb + (int16_t)VL53L1_p_031; + else + i = lb % (int16_t)VL53L1_p_031; + + VL53L1_p_008 = + (int64_t)pbins->bin_data[i] - + (int64_t)pbins->VL53L1_p_004; + + + if (clip_events > 0 && VL53L1_p_008 < 0) + VL53L1_p_008 = 0; + + event_sum += VL53L1_p_008; + + weighted_sum += + (VL53L1_p_008 * (1024 + (2048*(int64_t)lb))); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\tb = %5d : i = %5d : VL53L1_p_008 = %8d,", + lb, i, VL53L1_p_008); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + " event_sum = %8d, weighted_sum = %8d\n", + event_sum, weighted_sum); + } + + if (event_sum > 0) { + + weighted_sum += do_division_s(event_sum, 2); + weighted_sum = do_division_s(weighted_sum, event_sum); + + if (weighted_sum < 0) + weighted_sum = 0; + + *pphase = (uint32_t)weighted_sum; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_023( + uint8_t pulse_no, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_gen3_algo_private_data_t *palgo, + int32_t pad_value, + VL53L1_histogram_bin_data_t *ppulse) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t lb = 0; + + VL53L1_hist_pulse_data_t *pdata = &(palgo->VL53L1_p_002[pulse_no]); + + LOG_FUNCTION_START(""); + + + + memcpy(ppulse, pbins, sizeof(VL53L1_histogram_bin_data_t)); + + + + for (lb = palgo->VL53L1_p_049; + lb < (palgo->VL53L1_p_049 + + palgo->VL53L1_p_031); + lb++) { + + if (lb < pdata->VL53L1_p_015 || lb > pdata->VL53L1_p_016) { + i = lb % palgo->VL53L1_p_031; + if (i < ppulse->VL53L1_p_024) + ppulse->bin_data[i] = pad_value; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_026( + uint8_t bin, + uint8_t sigma_estimator__sigma_ref_mm, + uint8_t VL53L1_p_031, + uint8_t VL53L1_p_055, + uint8_t crosstalk_compensation_enable, + VL53L1_histogram_bin_data_t *phist_data_ap, + VL53L1_histogram_bin_data_t *phist_data_zp, + VL53L1_histogram_bin_data_t *pxtalk_hist, + uint16_t *psigma_est) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_Error func_status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + int32_t VL53L1_p_003 = 0; + int32_t VL53L1_p_018 = 0; + int32_t VL53L1_p_001 = 0; + int32_t a_zp = 0; + int32_t c_zp = 0; + int32_t ax = 0; + int32_t bx = 0; + int32_t cx = 0; + + + + i = bin % VL53L1_p_031; + + + + VL53L1_f_013( + i, + VL53L1_p_055, + phist_data_zp, + &a_zp, + &VL53L1_p_018, + &c_zp); + + + + VL53L1_f_013( + i, + VL53L1_p_055, + phist_data_ap, + &VL53L1_p_003, + &VL53L1_p_018, + &VL53L1_p_001); + + if (crosstalk_compensation_enable > 0) + VL53L1_f_013( + i, + VL53L1_p_055, + pxtalk_hist, + &ax, + &bx, + &cx); + + + + + + + + func_status = + VL53L1_f_014( + sigma_estimator__sigma_ref_mm, + (uint32_t)VL53L1_p_003, + (uint32_t)VL53L1_p_018, + (uint32_t)VL53L1_p_001, + (uint32_t)a_zp, + (uint32_t)c_zp, + (uint32_t)bx, + (uint32_t)ax, + (uint32_t)cx, + (uint32_t)phist_data_ap->VL53L1_p_004, + phist_data_ap->VL53L1_p_019, + psigma_est); + + + + + if (func_status == VL53L1_ERROR_DIVISION_BY_ZERO) + *psigma_est = 0xFFFF; + + + return status; +} + + +void VL53L1_f_029( + uint8_t range_id, + uint8_t valid_phase_low, + uint8_t valid_phase_high, + uint16_t sigma_thres, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_hist_pulse_data_t *ppulse, + VL53L1_range_data_t *pdata) +{ + + uint16_t lower_phase_limit = 0; + uint16_t upper_phase_limit = 0; + + + + pdata->range_id = range_id; + pdata->time_stamp = 0; + + pdata->VL53L1_p_015 = ppulse->VL53L1_p_015; + pdata->VL53L1_p_022 = ppulse->VL53L1_p_022; + pdata->VL53L1_p_025 = ppulse->VL53L1_p_025; + pdata->VL53L1_p_026 = ppulse->VL53L1_p_026; + pdata->VL53L1_p_016 = ppulse->VL53L1_p_016; + pdata->VL53L1_p_027 = ppulse->VL53L1_p_027; + + + + pdata->VL53L1_p_030 = + (ppulse->VL53L1_p_016 + 1) - ppulse->VL53L1_p_015; + + + + pdata->zero_distance_phase = pbins->zero_distance_phase; + pdata->VL53L1_p_005 = ppulse->VL53L1_p_005; + pdata->VL53L1_p_028 = (uint16_t)ppulse->VL53L1_p_028; + pdata->VL53L1_p_014 = (uint16_t)ppulse->VL53L1_p_014; + pdata->VL53L1_p_029 = (uint16_t)ppulse->VL53L1_p_029; + pdata->VL53L1_p_021 = (uint32_t)ppulse->VL53L1_p_021; + pdata->VL53L1_p_013 = ppulse->VL53L1_p_013; + pdata->VL53L1_p_020 = (uint32_t)ppulse->VL53L1_p_020; + pdata->total_periods_elapsed = pbins->total_periods_elapsed; + + + + pdata->range_status = VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK; + + + if (sigma_thres > 0 && + (uint32_t)ppulse->VL53L1_p_005 > ((uint32_t)sigma_thres << 5)) + pdata->range_status = VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK; + + + + lower_phase_limit = (uint8_t)valid_phase_low << 8; + if (lower_phase_limit < pdata->zero_distance_phase) + lower_phase_limit = + pdata->zero_distance_phase - + lower_phase_limit; + else + lower_phase_limit = 0; + + upper_phase_limit = (uint8_t)valid_phase_high << 8; + upper_phase_limit += pbins->zero_distance_phase; + + if (pdata->VL53L1_p_014 < lower_phase_limit || + pdata->VL53L1_p_014 > upper_phase_limit) + pdata->range_status = VL53L1_DEVICEERROR_RANGEPHASECHECK; + +} + + diff --git a/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_algos_gen4.c b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_algos_gen4.c new file mode 100644 index 0000000000000000000000000000000000000000..e450804b23e6e417fa48088b1dee7a3366b12746 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_algos_gen4.c @@ -0,0 +1,561 @@ + +// SPDX-License-Identifier: BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#include "vl53l1_types.h" +#include "vl53l1_platform_log.h" + +#include "vl53l1_core_support.h" +#include "vl53l1_error_codes.h" + +#include "vl53l1_hist_core.h" +#include "vl53l1_hist_algos_gen3.h" +#include "vl53l1_hist_algos_gen4.h" +#include "vl53l1_sigma_estimate.h" +#include "vl53l1_dmax.h" +#ifdef __KERNEL__ +#include +#include +#endif + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +void VL53L1_f_032( + VL53L1_hist_gen4_algo_filtered_data_t *palgo) +{ + + + uint8_t lb = 0; + + palgo->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + palgo->VL53L1_p_022 = 0; + palgo->VL53L1_p_024 = 0; + + for (lb = palgo->VL53L1_p_022; lb < palgo->VL53L1_p_023; lb++) { + palgo->VL53L1_p_003[lb] = 0; + palgo->VL53L1_p_018[lb] = 0; + palgo->VL53L1_p_001[lb] = 0; + palgo->VL53L1_p_039[lb] = 0; + palgo->VL53L1_p_040[lb] = 0; + palgo->VL53L1_p_043[lb] = 0; + } +} + + +VL53L1_Error VL53L1_f_033( + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins_input, + VL53L1_histogram_bin_data_t *pxtalk, + VL53L1_hist_gen3_algo_private_data_t *palgo3, + VL53L1_hist_gen4_algo_filtered_data_t *pfiltered, + VL53L1_hist_gen3_dmax_private_data_t *pdmax_algo, + VL53L1_range_results_t *presults, + uint8_t histo_merge_nb) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_hist_pulse_data_t *ppulse_data; + VL53L1_range_data_t *prange_data; + + uint8_t p = 0; + VL53L1_histogram_bin_data_t *pB = &(palgo3->VL53L1_p_010); + + LOG_FUNCTION_START(""); + + + + + + VL53L1_f_016(palgo3); + + + + memcpy( + &(palgo3->VL53L1_p_010), + pbins_input, + sizeof(VL53L1_histogram_bin_data_t)); + + + + presults->cfg_device_state = pbins_input->cfg_device_state; + presults->rd_device_state = pbins_input->rd_device_state; + presults->zone_id = pbins_input->zone_id; + presults->stream_count = pbins_input->result__stream_count; + presults->wrap_dmax_mm = 0; + presults->max_results = VL53L1_MAX_RANGE_RESULTS; + presults->active_results = 0; + + for (p = 0; p < VL53L1_MAX_AMBIENT_DMAX_VALUES; p++) + presults->VL53L1_p_007[p] = 0; + + + + VL53L1_hist_calc_zero_distance_phase(&(palgo3->VL53L1_p_010)); + + + + if (ppost_cfg->hist_amb_est_method == + VL53L1_HIST_AMB_EST_METHOD__THRESHOLDED_BINS) + VL53L1_hist_estimate_ambient_from_thresholded_bins( + (int32_t)ppost_cfg->ambient_thresh_sigma0, + &(palgo3->VL53L1_p_010)); + else + VL53L1_hist_estimate_ambient_from_ambient_bins( + &(palgo3->VL53L1_p_010)); + + + VL53L1_hist_remove_ambient_bins(&(palgo3->VL53L1_p_010)); + + + if (ppost_cfg->algo__crosstalk_compensation_enable > 0) + VL53L1_f_004( + pxtalk, + &(palgo3->VL53L1_p_010), + &(palgo3->VL53L1_p_038)); + + + + pdmax_cfg->ambient_thresh_sigma = + ppost_cfg->ambient_thresh_sigma1; + + for (p = 0; p < VL53L1_MAX_AMBIENT_DMAX_VALUES; p++) { + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_f_001( + pdmax_cfg->target_reflectance_for_dmax_calc[p], + pdmax_cal, + pdmax_cfg, + &(palgo3->VL53L1_p_010), + pdmax_algo, + &(presults->VL53L1_p_007[p])); + } + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_018( + ppost_cfg->ambient_thresh_events_scaler, + (int32_t)ppost_cfg->ambient_thresh_sigma1, + (int32_t)ppost_cfg->min_ambient_thresh_events, + ppost_cfg->algo__crosstalk_compensation_enable, + &(palgo3->VL53L1_p_010), + &(palgo3->VL53L1_p_038), + palgo3); + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_019(palgo3); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_020(palgo3); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_021(palgo3); + + + + for (p = 0; p < palgo3->VL53L1_p_051; p++) { + + ppulse_data = &(palgo3->VL53L1_p_002[p]); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_022( + p, + &(palgo3->VL53L1_p_010), + palgo3); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_023( + p, + &(palgo3->VL53L1_p_010), + palgo3, + pB->VL53L1_p_004, + &(palgo3->VL53L1_p_052)); + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_f_023( + p, + &(palgo3->VL53L1_p_010), + palgo3, + 0, + &(palgo3->VL53L1_p_053)); + } + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_f_023( + p, + &(palgo3->VL53L1_p_038), + palgo3, + 0, + &(palgo3->VL53L1_p_054)); + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_034( + p, + &(palgo3->VL53L1_p_052), + palgo3, + pfiltered); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_035( + p, + ppost_cfg->noise_threshold, + pfiltered, + palgo3); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_026( + ppulse_data->VL53L1_p_025, + ppost_cfg->sigma_estimator__sigma_ref_mm, + palgo3->VL53L1_p_031, + ppulse_data->VL53L1_p_055, + ppost_cfg->algo__crosstalk_compensation_enable, + &(palgo3->VL53L1_p_052), + &(palgo3->VL53L1_p_053), + &(palgo3->VL53L1_p_054), + &(ppulse_data->VL53L1_p_005)); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_027( + p, + 1, + &(palgo3->VL53L1_p_010), + palgo3); + + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_028( + ppost_cfg->hist_target_order, + palgo3); + + + + for (p = 0; p < palgo3->VL53L1_p_051; p++) { + + ppulse_data = &(palgo3->VL53L1_p_002[p]); + + + if (!(presults->active_results < presults->max_results)) + continue; + + + + + if (ppulse_data->VL53L1_p_013 > + ppost_cfg->signal_total_events_limit && + ppulse_data->VL53L1_p_025 < 0xFF) { + + prange_data = + &(presults->VL53L1_p_002[presults->active_results]); + + if (status == VL53L1_ERROR_NONE) + VL53L1_f_029( + presults->active_results, + ppost_cfg->valid_phase_low, + ppost_cfg->valid_phase_high, + ppost_cfg->sigma_thresh, + &(palgo3->VL53L1_p_010), + ppulse_data, + prange_data); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_011( + pB->vcsel_width, + pB->VL53L1_p_019, + pB->total_periods_elapsed, + pB->result__dss_actual_effective_spads, + prange_data, + histo_merge_nb); + + if (status == VL53L1_ERROR_NONE) + VL53L1_f_012( + ppost_cfg->gain_factor, + ppost_cfg->range_offset_mm, + prange_data); + + presults->active_results++; + } + + } + + + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_f_034( + uint8_t pulse_no, + VL53L1_histogram_bin_data_t *ppulse, + VL53L1_hist_gen3_algo_private_data_t *palgo3, + VL53L1_hist_gen4_algo_filtered_data_t *pfiltered) +{ + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_hist_pulse_data_t *pdata = &(palgo3->VL53L1_p_002[pulse_no]); + + uint8_t lb = 0; + uint8_t i = 0; + int32_t suma = 0; + int32_t sumb = 0; + int32_t sumc = 0; + + LOG_FUNCTION_START(""); + + pfiltered->VL53L1_p_023 = palgo3->VL53L1_p_023; + pfiltered->VL53L1_p_022 = palgo3->VL53L1_p_022; + pfiltered->VL53L1_p_024 = palgo3->VL53L1_p_024; + + + + for (lb = pdata->VL53L1_p_015; lb <= pdata->VL53L1_p_016; lb++) { + + i = lb % palgo3->VL53L1_p_031; + + + VL53L1_f_013( + i, + pdata->VL53L1_p_055, + ppulse, + &suma, + &sumb, + &sumc); + + + pfiltered->VL53L1_p_003[i] = suma; + pfiltered->VL53L1_p_018[i] = sumb; + pfiltered->VL53L1_p_001[i] = sumc; + + + + pfiltered->VL53L1_p_039[i] = + (suma + sumb) - + (sumc + palgo3->VL53L1_p_004); + + + + pfiltered->VL53L1_p_040[i] = + (sumb + sumc) - + (suma + palgo3->VL53L1_p_004); + } + + return status; +} + + +VL53L1_Error VL53L1_f_035( + uint8_t pulse_no, + uint16_t noise_threshold, + VL53L1_hist_gen4_algo_filtered_data_t *pfiltered, + VL53L1_hist_gen3_algo_private_data_t *palgo3) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_Error func_status = VL53L1_ERROR_NONE; + + VL53L1_hist_pulse_data_t *pdata = &(palgo3->VL53L1_p_002[pulse_no]); + + uint8_t lb = 0; + uint8_t i = 0; + uint8_t j = 0; + + SUPPRESS_UNUSED_WARNING(noise_threshold); + + for (lb = pdata->VL53L1_p_015; lb < pdata->VL53L1_p_016; lb++) { + + i = lb % palgo3->VL53L1_p_031; + j = (lb+1) % palgo3->VL53L1_p_031; + + if (i < palgo3->VL53L1_p_024 && + j < palgo3->VL53L1_p_024) { + + if (pfiltered->VL53L1_p_039[i] == 0 && + pfiltered->VL53L1_p_040[i] == 0) + + pfiltered->VL53L1_p_043[i] = 0; + + else if (pfiltered->VL53L1_p_039[i] >= 0 && + pfiltered->VL53L1_p_040[i] >= 0) + pfiltered->VL53L1_p_043[i] = 1; + + else if (pfiltered->VL53L1_p_039[i] < 0 && + pfiltered->VL53L1_p_040[i] >= 0 && + pfiltered->VL53L1_p_039[j] >= 0 && + pfiltered->VL53L1_p_040[j] < 0) + pfiltered->VL53L1_p_043[i] = 1; + + else + pfiltered->VL53L1_p_043[i] = 0; + + + if (pfiltered->VL53L1_p_043[i] > 0) { + + pdata->VL53L1_p_025 = lb; + + func_status = + VL53L1_f_036( + lb, + pfiltered->VL53L1_p_003[i], + pfiltered->VL53L1_p_018[i], + pfiltered->VL53L1_p_001[i], + 0, + 0, + 0, + palgo3->VL53L1_p_004, + palgo3->VL53L1_p_031, + &(pdata->VL53L1_p_014)); + + if (func_status == + VL53L1_ERROR_DIVISION_BY_ZERO) + pfiltered->VL53L1_p_043[i] = 0; + + } + } + } + + return status; +} + + +VL53L1_Error VL53L1_f_036( + uint8_t bin, + int32_t VL53L1_p_003, + int32_t VL53L1_p_018, + int32_t VL53L1_p_001, + int32_t ax, + int32_t bx, + int32_t cx, + int32_t VL53L1_p_004, + uint8_t VL53L1_p_031, + uint32_t *pmean_phase) +{ + + + VL53L1_Error status = VL53L1_ERROR_DIVISION_BY_ZERO; + + int64_t mean_phase = VL53L1_MAX_ALLOWED_PHASE; + int32_t mean_phase32; + int64_t VL53L1_p_041 = 0; + int64_t half_b_minus_amb = 0; + + + VL53L1_p_041 = 4096 * ((int64_t)VL53L1_p_001 - + (int64_t)cx - (int64_t)VL53L1_p_003 - (int64_t)ax); + half_b_minus_amb = 4096 * ((int64_t)VL53L1_p_018 - + (int64_t)bx - (int64_t)VL53L1_p_004); + + if (half_b_minus_amb != 0) { + mean_phase = (4096 * VL53L1_p_041) + half_b_minus_amb; + mean_phase = do_division_s(mean_phase, (half_b_minus_amb * 2)); + mean_phase += 2048; + mean_phase += (4096 * (int64_t)bin); + + mean_phase = do_division_s((mean_phase + 1), 2); + + if (mean_phase < 0) + mean_phase = 0; + if (mean_phase > VL53L1_MAX_ALLOWED_PHASE) + mean_phase = VL53L1_MAX_ALLOWED_PHASE; + + mean_phase32 = (int32_t)mean_phase; + mean_phase32 = mean_phase32 % + ((int32_t)VL53L1_p_031 * 2048); + mean_phase = mean_phase32; + + status = VL53L1_ERROR_NONE; + } + + *pmean_phase = (uint32_t)mean_phase; + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_core.c b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_core.c new file mode 100644 index 0000000000000000000000000000000000000000..6aeb97dec15445001ef3169671a93279fdfdd4b9 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_core.c @@ -0,0 +1,520 @@ + +// SPDX-License-Identifier: BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#include "vl53l1_platform_log.h" + +#include "vl53l1_core_support.h" +#include "vl53l1_hist_structs.h" + +#include "vl53l1_xtalk.h" +#include "vl53l1_sigma_estimate.h" + +#include "vl53l1_hist_core.h" + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +void VL53L1_f_013( + uint8_t VL53L1_p_018, + uint8_t filter_woi, + VL53L1_histogram_bin_data_t *pbins, + int32_t *pa, + int32_t *pb, + int32_t *pc) +{ + + + uint8_t w = 0; + uint8_t j = 0; + + *pa = 0; + *pb = pbins->bin_data[VL53L1_p_018]; + *pc = 0; + + for (w = 0 ; w < ((filter_woi << 1)+1) ; w++) { + + + j = ((VL53L1_p_018 + w + pbins->VL53L1_p_024) - + filter_woi) % pbins->VL53L1_p_024; + + + if (w < filter_woi) + *pa += pbins->bin_data[j]; + else if (w > filter_woi) + *pc += pbins->bin_data[j]; + } +} + + +VL53L1_Error VL53L1_f_011( + uint16_t vcsel_width, + uint16_t fast_osc_frequency, + uint32_t total_periods_elapsed, + uint16_t VL53L1_p_006, + VL53L1_range_data_t *pdata, + uint8_t histo_merge_nb) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t pll_period_us = 0; + uint32_t periods_elapsed = 0; + uint32_t count_rate_total = 0; + + LOG_FUNCTION_START(""); + + + + pdata->width = vcsel_width; + pdata->fast_osc_frequency = fast_osc_frequency; + pdata->total_periods_elapsed = total_periods_elapsed; + pdata->VL53L1_p_006 = VL53L1_p_006; + + + + if (pdata->fast_osc_frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (pdata->total_periods_elapsed == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + + + pll_period_us = + VL53L1_calc_pll_period_us(pdata->fast_osc_frequency); + + + + periods_elapsed = pdata->total_periods_elapsed + 1; + + + + pdata->peak_duration_us = VL53L1_duration_maths( + pll_period_us, + (uint32_t)pdata->width, + VL53L1_RANGING_WINDOW_VCSEL_PERIODS, + periods_elapsed); + + pdata->woi_duration_us = VL53L1_duration_maths( + pll_period_us, + ((uint32_t)pdata->VL53L1_p_030) << 4, + VL53L1_RANGING_WINDOW_VCSEL_PERIODS, + periods_elapsed); + + + + pdata->peak_signal_count_rate_mcps = VL53L1_rate_maths( + (int32_t)pdata->VL53L1_p_013, + pdata->peak_duration_us); + + pdata->avg_signal_count_rate_mcps = VL53L1_rate_maths( + (int32_t)pdata->VL53L1_p_013, + pdata->woi_duration_us); + + pdata->ambient_count_rate_mcps = VL53L1_rate_maths( + (int32_t)pdata->VL53L1_p_020, + pdata->woi_duration_us); + + + + count_rate_total = + (uint32_t)pdata->peak_signal_count_rate_mcps + + (uint32_t)pdata->ambient_count_rate_mcps; + + if (histo_merge_nb > 1) + count_rate_total /= histo_merge_nb; + + pdata->total_rate_per_spad_mcps = + VL53L1_rate_per_spad_maths( + 0x06, + count_rate_total, + pdata->VL53L1_p_006, + 0xFFFF); + + + + pdata->VL53L1_p_012 = + VL53L1_events_per_spad_maths( + pdata->VL53L1_p_013, + pdata->VL53L1_p_006, + pdata->peak_duration_us); + + + + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %d:%-46s : %10d\n", + pdata->range_id, "peak_duration_us", + pdata->peak_duration_us); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %d:%-46s : %10d\n", + pdata->range_id, "woi_duration_us", + pdata->woi_duration_us); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %d:%-46s : %10u\n", + pdata->range_id, "peak_signal_count_rate_mcps", + pdata->peak_signal_count_rate_mcps); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %d:%-46s : %10u\n", + pdata->range_id, "ambient_count_rate_mcps", + pdata->ambient_count_rate_mcps); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %d:%-46s : %10u\n", + pdata->range_id, "total_rate_per_spad_mcps", + pdata->total_rate_per_spad_mcps); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %d:%-46s : %10u\n", + pdata->range_id, "VL53L1_p_012", + pdata->VL53L1_p_012); + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_f_012( + uint16_t gain_factor, + int16_t range_offset_mm, + VL53L1_range_data_t *pdata) +{ + + + LOG_FUNCTION_START(""); + + + + pdata->min_range_mm = + (int16_t)VL53L1_range_maths( + pdata->fast_osc_frequency, + pdata->VL53L1_p_028, + pdata->zero_distance_phase, + 0, + (int32_t)gain_factor, + (int32_t)range_offset_mm); + + pdata->median_range_mm = + (int16_t)VL53L1_range_maths( + pdata->fast_osc_frequency, + pdata->VL53L1_p_014, + pdata->zero_distance_phase, + 0, + (int32_t)gain_factor, + (int32_t)range_offset_mm); + + pdata->max_range_mm = + (int16_t)VL53L1_range_maths( + pdata->fast_osc_frequency, + pdata->VL53L1_p_029, + pdata->zero_distance_phase, + 0, + (int32_t)gain_factor, + (int32_t)range_offset_mm); + + + + + + LOG_FUNCTION_END(0); +} + + +void VL53L1_f_037( + VL53L1_histogram_bin_data_t *pdata, + int32_t ambient_estimate_counts_per_bin) +{ + + + uint8_t i = 0; + + for (i = 0 ; i < pdata->VL53L1_p_024 ; i++) + pdata->bin_data[i] = pdata->bin_data[i] - + ambient_estimate_counts_per_bin; +} + + +void VL53L1_f_004( + VL53L1_histogram_bin_data_t *pxtalk, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_histogram_bin_data_t *pxtalk_realigned) +{ + + + uint8_t i = 0; + uint8_t min_bins = 0; + int8_t bin_offset = 0; + int8_t bin_access = 0; + + LOG_FUNCTION_START(""); + + + + + + memcpy( + pxtalk_realigned, + pbins, + sizeof(VL53L1_histogram_bin_data_t)); + + for (i = 0 ; i < pxtalk_realigned->VL53L1_p_023 ; i++) + pxtalk_realigned->bin_data[i] = 0; + + + + bin_offset = VL53L1_f_038( + pbins, + pxtalk); + + + + if (pxtalk->VL53L1_p_024 < pbins->VL53L1_p_024) + min_bins = pxtalk->VL53L1_p_024; + else + min_bins = pbins->VL53L1_p_024; + + + for (i = 0 ; i < min_bins ; i++) { + + + + if (bin_offset >= 0) + bin_access = ((int8_t)i + (int8_t)bin_offset) + % (int8_t)pbins->VL53L1_p_024; + else + bin_access = ((int8_t)pbins->VL53L1_p_024 + + ((int8_t)i + (int8_t)bin_offset)) + % (int8_t)pbins->VL53L1_p_024; + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + "Subtract: %8d : %8d : %8d : %8d : %8d : %8d\n", + i, bin_access, bin_offset, pbins->VL53L1_p_024, + pbins->bin_data[(uint8_t)bin_access], + pxtalk->bin_data[i]); + + + + if (pbins->bin_data[(uint8_t)bin_access] > + pxtalk->bin_data[i]) { + + pbins->bin_data[(uint8_t)bin_access] = + pbins->bin_data[(uint8_t)bin_access] + - pxtalk->bin_data[i]; + + } else { + pbins->bin_data[(uint8_t)bin_access] = 0; + } + + + + + pxtalk_realigned->bin_data[(uint8_t)bin_access] = + pxtalk->bin_data[i]; + + + + } + + + + LOG_FUNCTION_END(0); +} + + +int8_t VL53L1_f_038( + VL53L1_histogram_bin_data_t *pdata1, + VL53L1_histogram_bin_data_t *pdata2) +{ + + + int32_t phase_delta = 0; + int8_t bin_offset = 0; + uint32_t period = 0; + uint32_t remapped_phase = 0; + + LOG_FUNCTION_START(""); + + + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period(pdata1->VL53L1_p_009); + + remapped_phase = (uint32_t)pdata2->zero_distance_phase % period; + + + phase_delta = (int32_t)pdata1->zero_distance_phase + - (int32_t)remapped_phase; + + + + if (phase_delta > 0) + bin_offset = (int8_t)((phase_delta + 1024) / 2048); + else + bin_offset = (int8_t)((phase_delta - 1024) / 2048); + + LOG_FUNCTION_END(0); + + return bin_offset; +} + + +VL53L1_Error VL53L1_f_039( + VL53L1_histogram_bin_data_t *pidata, + VL53L1_histogram_bin_data_t *podata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t bin_initial_index[VL53L1_MAX_BIN_SEQUENCE_CODE+1]; + uint8_t bin_repeat_count[VL53L1_MAX_BIN_SEQUENCE_CODE+1]; + + uint8_t bin_cfg = 0; + uint8_t bin_seq_length = 0; + int32_t repeat_count = 0; + + uint8_t VL53L1_p_018 = 0; + uint8_t lc = 0; + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + memcpy(podata, pidata, sizeof(VL53L1_histogram_bin_data_t)); + + + podata->VL53L1_p_024 = 0; + + for (lc = 0 ; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH ; lc++) + podata->bin_seq[lc] = VL53L1_MAX_BIN_SEQUENCE_CODE+1; + + for (lc = 0 ; lc < podata->VL53L1_p_023 ; lc++) + podata->bin_data[lc] = 0; + + + + for (lc = 0 ; lc <= VL53L1_MAX_BIN_SEQUENCE_CODE ; lc++) { + bin_initial_index[lc] = 0x00; + bin_repeat_count[lc] = 0x00; + } + + + + + bin_seq_length = 0x00; + + for (lc = 0 ; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH ; lc++) { + + bin_cfg = pidata->bin_seq[lc]; + + + + if (bin_repeat_count[bin_cfg] == 0) { + bin_initial_index[bin_cfg] = bin_seq_length * 4; + podata->bin_seq[bin_seq_length] = bin_cfg; + bin_seq_length++; + } + + bin_repeat_count[bin_cfg]++; + + + + VL53L1_p_018 = bin_initial_index[bin_cfg]; + + for (i = 0 ; i < 4 ; i++) + podata->bin_data[VL53L1_p_018+i] += + pidata->bin_data[lc*4+i]; + + } + + + + for (lc = 0 ; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH ; lc++) { + + bin_cfg = podata->bin_seq[lc]; + + if (bin_cfg <= VL53L1_MAX_BIN_SEQUENCE_CODE) + podata->bin_rep[lc] = + bin_repeat_count[bin_cfg]; + else + podata->bin_rep[lc] = 0; + } + + podata->VL53L1_p_024 = bin_seq_length * 4; + + + + + + for (lc = 0 ; lc <= VL53L1_MAX_BIN_SEQUENCE_CODE ; lc++) { + + repeat_count = (int32_t)bin_repeat_count[lc]; + + if (repeat_count > 0) { + + VL53L1_p_018 = bin_initial_index[lc]; + + for (i = 0 ; i < 4 ; i++) { + podata->bin_data[VL53L1_p_018+i] += + (repeat_count/2); + podata->bin_data[VL53L1_p_018+i] /= + repeat_count; + } + } + } + + + + podata->number_of_ambient_bins = 0; + if ((bin_repeat_count[7] > 0) || + (bin_repeat_count[15] > 0)) + podata->number_of_ambient_bins = 4; + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_funcs.c b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_funcs.c new file mode 100644 index 0000000000000000000000000000000000000000..a55d90eac7a26cb14a967d44ed5dc291b009fc54 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/src/vl53l1_hist_funcs.c @@ -0,0 +1,293 @@ + +// SPDX-License-Identifier: BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + + + + +#include "vl53l1_types.h" +#include "vl53l1_platform_log.h" + +#include "vl53l1_core_support.h" +#include "vl53l1_error_codes.h" +#include "vl53l1_ll_def.h" + +#include "vl53l1_hist_funcs.h" +#include "vl53l1_hist_core.h" +#include "vl53l1_hist_private_structs.h" +#include "vl53l1_dmax_private_structs.h" +#include "vl53l1_xtalk.h" +#include "vl53l1_hist_algos_gen3.h" +#include "vl53l1_hist_algos_gen4.h" +#include "vl53l1_dmax.h" + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_hist_process_data( + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins_input, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + uint8_t *pArea1, + uint8_t *pArea2, + VL53L1_range_results_t *presults, + uint8_t *HistMergeNumber) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_hist_gen3_algo_private_data_t *palgo_gen3 = + (VL53L1_hist_gen3_algo_private_data_t *) pArea1; + VL53L1_hist_gen4_algo_filtered_data_t *pfiltered4 = + (VL53L1_hist_gen4_algo_filtered_data_t *) pArea2; + + VL53L1_hist_gen3_dmax_private_data_t dmax_algo_gen3; + VL53L1_hist_gen3_dmax_private_data_t *pdmax_algo_gen3 = + &dmax_algo_gen3; + + VL53L1_histogram_bin_data_t bins_averaged; + VL53L1_histogram_bin_data_t *pbins_averaged = &bins_averaged; + + VL53L1_range_data_t *pdata; + + uint32_t xtalk_rate_kcps = 0; + uint32_t max_xtalk_rate_per_spad_kcps = 0; + uint8_t xtalk_enable = 0; + uint8_t r = 0; + uint8_t t = 0; + uint32_t XtalkDetectMaxSigma = 0; + + + int16_t delta_mm = 0; + + + LOG_FUNCTION_START(""); + + + + VL53L1_f_039( + pbins_input, + pbins_averaged); + + + + VL53L1_init_histogram_bin_data_struct( + 0, + pxtalk_shape->xtalk_shape.VL53L1_p_024, + &(pxtalk_shape->xtalk_hist_removed)); + + + + VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + &(pxtalk_shape->xtalk_shape), + &(pxtalk_shape->xtalk_hist_removed)); + + + + if ((status == VL53L1_ERROR_NONE) && + (ppost_cfg->algo__crosstalk_compensation_enable > 0)) + status = + VL53L1_f_040( + ppost_cfg->algo__crosstalk_compensation_plane_offset_kcps, + ppost_cfg->algo__crosstalk_compensation_x_plane_gradient_kcps, + ppost_cfg->algo__crosstalk_compensation_y_plane_gradient_kcps, + 0, + 0, + pbins_input->result__dss_actual_effective_spads, + pbins_input->roi_config__user_roi_centre_spad, + pbins_input->roi_config__user_roi_requested_global_xy_size, + &(xtalk_rate_kcps)); + + + + if ((status == VL53L1_ERROR_NONE) && + (ppost_cfg->algo__crosstalk_compensation_enable > 0)) + status = + VL53L1_f_041( + pbins_averaged, + &(pxtalk_shape->xtalk_shape), + xtalk_rate_kcps, + &(pxtalk_shape->xtalk_hist_removed)); + + + + + + presults->xmonitor.total_periods_elapsed = + pbins_averaged->total_periods_elapsed; + presults->xmonitor.VL53L1_p_006 = + pbins_averaged->result__dss_actual_effective_spads; + + presults->xmonitor.peak_signal_count_rate_mcps = 0; + presults->xmonitor.VL53L1_p_012 = 0; + + presults->xmonitor.range_id = 0; + presults->xmonitor.range_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + xtalk_enable = 0; + if (ppost_cfg->algo__crosstalk_compensation_enable > 0) + xtalk_enable = 1; + + + + for (r = 0 ; r <= xtalk_enable ; r++) { + + + ppost_cfg->algo__crosstalk_compensation_enable = r; + + + + status = + VL53L1_f_033( + pdmax_cal, + pdmax_cfg, + ppost_cfg, + pbins_averaged, + &(pxtalk_shape->xtalk_hist_removed), + palgo_gen3, + pfiltered4, + pdmax_algo_gen3, + presults, + *HistMergeNumber); + + + if (!(status == VL53L1_ERROR_NONE && r == 0)) + continue; + + + + if (presults->active_results == 0) { + pdata = &(presults->VL53L1_p_002[0]); + pdata->ambient_count_rate_mcps = + pdmax_algo_gen3->VL53L1_p_001; + pdata->VL53L1_p_006 = + pdmax_algo_gen3->VL53L1_p_006; + } + + + + max_xtalk_rate_per_spad_kcps = (uint32_t)( + ppost_cfg->algo__crosstalk_detect_max_valid_rate_kcps); + max_xtalk_rate_per_spad_kcps *= (uint32_t)(*HistMergeNumber); + max_xtalk_rate_per_spad_kcps <<= 4; + + for (t = 0 ; t < presults->active_results ; t++) { + + pdata = &(presults->VL53L1_p_002[t]); + + + + if (pdata->max_range_mm > pdata->min_range_mm) + delta_mm = + pdata->max_range_mm - + pdata->min_range_mm; + else + delta_mm = + pdata->min_range_mm - + pdata->max_range_mm; + + XtalkDetectMaxSigma = + ppost_cfg->algo__crosstalk_detect_max_sigma_mm; + XtalkDetectMaxSigma *= (uint32_t)(*HistMergeNumber); + XtalkDetectMaxSigma <<= 5; + if (pdata->median_range_mm > + ppost_cfg->algo__crosstalk_detect_min_valid_range_mm && + pdata->median_range_mm < + ppost_cfg->algo__crosstalk_detect_max_valid_range_mm && + pdata->VL53L1_p_012 < + max_xtalk_rate_per_spad_kcps && + pdata->VL53L1_p_005 < XtalkDetectMaxSigma && + delta_mm < + ppost_cfg->algo__crosstalk_detect_min_max_tolerance) { + + + + memcpy( + &(presults->xmonitor), + pdata, + sizeof(VL53L1_range_data_t)); + + } + } + + } + + + + ppost_cfg->algo__crosstalk_compensation_enable = xtalk_enable; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_ambient_dmax( + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_hist_gen3_dmax_private_data_t dmax_algo; + VL53L1_hist_gen3_dmax_private_data_t *pdmax_algo = &dmax_algo; + + LOG_FUNCTION_START(""); + + status = + VL53L1_f_001( + target_reflectance, + pdmax_cal, + pdmax_cfg, + pbins, + pdmax_algo, + pambient_dmax_mm); + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/protected/src/vl53l1_sigma_estimate.c b/drivers/input/misc/vl53L1/protected/src/vl53l1_sigma_estimate.c new file mode 100644 index 0000000000000000000000000000000000000000..725436b7cfce34c06f861c1997d53d3bdd87e715 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/src/vl53l1_sigma_estimate.c @@ -0,0 +1,550 @@ + +// SPDX-License-Identifier: BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#include "vl53l1_types.h" +#include "vl53l1_platform_log.h" + +#include "vl53l1_core_support.h" +#include "vl53l1_error_codes.h" + +#include "vl53l1_sigma_estimate.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_PROTECTED, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_PROTECTED, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_PROTECTED, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_PROTECTED, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +uint16_t VL53L1_f_042( + uint8_t sigma_estimator__effective_pulse_width_ns, + uint8_t sigma_estimator__effective_ambient_width_ns, + uint8_t sigma_estimator__sigma_ref_mm, + VL53L1_range_data_t *pdata) +{ + + + + uint16_t sigma_est = VL53L1_D_002; + + uint32_t tmp0 = 0; + uint32_t tmp1 = 0; + uint32_t tmp2 = 0; + + uint32_t sigma_est__rtn_array = 0; + uint32_t sigma_est__ref_array = 0; + + LOG_FUNCTION_START(""); + + if (pdata->peak_signal_count_rate_mcps > 0 && + pdata->VL53L1_p_013 > 0) { + + + + tmp0 = 100 * + (uint32_t)sigma_estimator__effective_pulse_width_ns; + + + + tmp1 = ((uint32_t)sigma_estimator__effective_pulse_width_ns * + 100 * + (uint32_t)sigma_estimator__effective_ambient_width_ns); + + tmp1 = (tmp1 + + (uint32_t)pdata->peak_signal_count_rate_mcps/2) / + (uint32_t)pdata->peak_signal_count_rate_mcps; + + + + sigma_est__rtn_array = + VL53L1_f_043(tmp0, tmp1); + + + + sigma_est__rtn_array = + ((VL53L1_SPEED_OF_LIGHT_IN_AIR + 1000) / 2000) * + sigma_est__rtn_array; + + + + tmp2 = + VL53L1_isqrt(12 * (uint32_t)pdata->VL53L1_p_013); + + if (tmp2 > 0) { + + sigma_est__rtn_array = + (sigma_est__rtn_array + tmp2/2) / tmp2; + + + + sigma_est__ref_array = + 100 * (uint32_t)sigma_estimator__sigma_ref_mm; + + sigma_est = + (uint16_t)VL53L1_f_043( + (uint32_t)sigma_est__ref_array, + sigma_est__rtn_array); + + } else { + sigma_est = VL53L1_D_002; + } + + } + + pdata->VL53L1_p_005 = sigma_est; + + LOG_FUNCTION_END(0); + + return sigma_est; + +} + + +uint16_t VL53L1_f_044( + uint8_t sigma_estimator__effective_pulse_width_ns, + uint8_t sigma_estimator__effective_ambient_width_ns, + uint8_t sigma_estimator__sigma_ref_mm, + VL53L1_range_data_t *pdata) +{ + + + uint16_t sigma_est = VL53L1_D_002; + + uint32_t eqn7 = 0; + uint32_t sigma_est__ref_sq = 0; + uint32_t sigma_est__rtn_sq = 0; + + uint64_t tmp0 = 0; + uint64_t tmp1 = 0; + + LOG_FUNCTION_START(""); + + if (pdata->peak_signal_count_rate_mcps > 0 && + pdata->VL53L1_p_013 > 0) { + + + + eqn7 = 4573 * 4573; + eqn7 = eqn7 / (3 * (uint32_t)pdata->VL53L1_p_013); + + + + tmp0 = ((uint64_t)sigma_estimator__effective_pulse_width_ns) + << 8; + + + + tmp1 = ((uint64_t)pdata->ambient_count_rate_mcps * + (uint64_t)sigma_estimator__effective_ambient_width_ns) + << 8; + + tmp1 = do_division_u(tmp1, + (uint64_t)pdata->peak_signal_count_rate_mcps); + + + + tmp1 = 16 * (uint64_t)eqn7 * (tmp0 * tmp0 + tmp1 * tmp1); + tmp1 = do_division_u(tmp1, (15625 * 15625)); + sigma_est__rtn_sq = (uint32_t)tmp1; + + + + sigma_est__ref_sq = ((uint32_t)sigma_estimator__sigma_ref_mm) + << 2; + + sigma_est__ref_sq = sigma_est__ref_sq * sigma_est__ref_sq; + + + + sigma_est = (uint16_t)VL53L1_isqrt(sigma_est__ref_sq + + sigma_est__rtn_sq); + + } + + pdata->VL53L1_p_005 = sigma_est; + + LOG_FUNCTION_END(0); + + return sigma_est; + +} + + + +VL53L1_Error VL53L1_f_045( + uint8_t sigma_estimator__sigma_ref_mm, + uint32_t VL53L1_p_003, + uint32_t VL53L1_p_018, + uint32_t VL53L1_p_001, + uint32_t a_zp, + uint32_t c_zp, + uint32_t bx, + uint32_t ax_zp, + uint32_t cx_zp, + uint32_t VL53L1_p_004, + uint16_t fast_osc_frequency, + uint16_t *psigma_est) +{ + + + VL53L1_Error status = VL53L1_ERROR_DIVISION_BY_ZERO; + uint32_t sigma_int = VL53L1_D_002; + + uint32_t pll_period_mm = 0; + + uint64_t tmp0 = 0; + uint64_t tmp1 = 0; + uint64_t b_minus_amb = 0; + uint64_t VL53L1_p_041 = 0; + + *psigma_est = VL53L1_D_002; + + + + if (fast_osc_frequency != 0) { + + + + pll_period_mm = VL53L1_calc_pll_period_mm(fast_osc_frequency); + + + pll_period_mm = (pll_period_mm + 0x02) >> 2; + + + + if (VL53L1_p_004 > VL53L1_p_018) + b_minus_amb = (uint64_t)VL53L1_p_004 - + (uint64_t)VL53L1_p_018; + else + b_minus_amb = (uint64_t)VL53L1_p_018 - + (uint64_t)VL53L1_p_004; + + + + if (VL53L1_p_003 > VL53L1_p_001) + VL53L1_p_041 = (uint64_t)VL53L1_p_003 - + (uint64_t)VL53L1_p_001; + else + VL53L1_p_041 = (uint64_t)VL53L1_p_001 - + (uint64_t)VL53L1_p_003; + + + + + + if (b_minus_amb != 0) { + + + + tmp0 = (uint64_t)pll_period_mm * + (uint64_t)pll_period_mm; + tmp0 = tmp0 * ((uint64_t)c_zp + + (uint64_t)cx_zp + (uint64_t)a_zp + + (uint64_t)ax_zp); + tmp0 = do_division_u((tmp0 + (b_minus_amb >> 1)), + b_minus_amb); + + + + tmp1 = (uint64_t)pll_period_mm * + (uint64_t)pll_period_mm * VL53L1_p_041; + tmp1 = do_division_u((tmp1 + (b_minus_amb >> 1)), + b_minus_amb); + + tmp1 = tmp1 * VL53L1_p_041; + tmp1 = do_division_u((tmp1 + (b_minus_amb >> 1)), + b_minus_amb); + + tmp1 = tmp1 * ((uint64_t)VL53L1_p_018 + (uint64_t)bx + + (uint64_t)VL53L1_p_004); + tmp1 = do_division_u((tmp1 + (b_minus_amb >> 1)), + b_minus_amb); + + + + tmp0 = tmp0 + tmp1; + tmp0 = do_division_u((tmp0 + (b_minus_amb >> 1)), + b_minus_amb); + tmp0 = (tmp0 + 0x01) >> 2; + + + + tmp1 = (uint64_t)sigma_estimator__sigma_ref_mm << 2; + tmp1 = tmp1 * tmp1; + tmp0 = tmp0 + tmp1; + + + + if (tmp0 > 0xFFFFFFFF) + tmp0 = 0xFFFFFFFF; + + sigma_int = VL53L1_isqrt((uint32_t)tmp0); + + + + if (sigma_int > VL53L1_D_002) + *psigma_est = + (uint16_t)VL53L1_D_002; + else + *psigma_est = (uint16_t)sigma_int; + + status = VL53L1_ERROR_NONE; + } + + } + + return status; +} + + + +VL53L1_Error VL53L1_f_014( + uint8_t sigma_estimator__sigma_ref_mm, + uint32_t VL53L1_p_003, + uint32_t VL53L1_p_018, + uint32_t VL53L1_p_001, + uint32_t a_zp, + uint32_t c_zp, + uint32_t bx, + uint32_t ax_zp, + uint32_t cx_zp, + uint32_t VL53L1_p_004, + uint16_t fast_osc_frequency, + uint16_t *psigma_est) +{ + + + VL53L1_Error status = VL53L1_ERROR_DIVISION_BY_ZERO; + uint32_t sigma_int = VL53L1_D_002; + + uint32_t pll_period_mm = 0; + + uint64_t tmp0 = 0; + uint64_t tmp1 = 0; + uint64_t b_minus_amb = 0; + uint64_t VL53L1_p_041 = 0; + + *psigma_est = VL53L1_D_002; + + + + if (fast_osc_frequency != 0) { + + + + pll_period_mm = VL53L1_calc_pll_period_mm(fast_osc_frequency); + + + + if (VL53L1_p_004 > VL53L1_p_018) + b_minus_amb = (uint64_t)VL53L1_p_004 - + (uint64_t)VL53L1_p_018; + else + b_minus_amb = (uint64_t)VL53L1_p_018 - + (uint64_t)VL53L1_p_004; + + + + if (VL53L1_p_003 > VL53L1_p_001) + VL53L1_p_041 = (uint64_t)VL53L1_p_003 - + (uint64_t)VL53L1_p_001; + else + VL53L1_p_041 = (uint64_t)VL53L1_p_001 - + (uint64_t)VL53L1_p_003; + + + + if (b_minus_amb != 0) { + + + + + tmp0 = (uint64_t)VL53L1_p_018 + (uint64_t)bx + + (uint64_t)VL53L1_p_004; + if (tmp0 > VL53L1_D_003) + tmp0 = VL53L1_D_003; + + + + tmp1 = (uint64_t)VL53L1_p_041 * (uint64_t)VL53L1_p_041; + tmp1 = tmp1 << 8; + + + if (tmp1 > VL53L1_D_004) + tmp1 = VL53L1_D_004; + + + tmp1 = do_division_u(tmp1, b_minus_amb); + tmp1 = do_division_u(tmp1, b_minus_amb); + + + if (tmp1 > (uint64_t)VL53L1_D_005) + tmp1 = (uint64_t)VL53L1_D_005; + + + tmp0 = tmp1 * tmp0; + + + tmp1 = (uint64_t)c_zp + (uint64_t)cx_zp + + (uint64_t)a_zp + (uint64_t)ax_zp; + + + if (tmp1 > (uint64_t)VL53L1_D_003) + tmp1 = (uint64_t)VL53L1_D_003; + + tmp1 = tmp1 << 8; + + + tmp0 = tmp1 + tmp0; + if (tmp0 > (uint64_t)VL53L1_D_006) + tmp0 = (uint64_t)VL53L1_D_006; + + + + + + + if (tmp0 > (uint64_t)VL53L1_D_007) { + tmp0 = do_division_u(tmp0, b_minus_amb); + tmp0 = tmp0 * pll_period_mm; + } else { + tmp0 = tmp0 * pll_period_mm; + tmp0 = do_division_u(tmp0, b_minus_amb); + } + + + if (tmp0 > (uint64_t)VL53L1_D_006) + tmp0 = (uint64_t)VL53L1_D_006; + + + + if (tmp0 > (uint64_t)VL53L1_D_007) { + tmp0 = do_division_u(tmp0, b_minus_amb); + tmp0 = do_division_u(tmp0, 4); + tmp0 = tmp0 * pll_period_mm; + } else { + tmp0 = tmp0 * pll_period_mm; + tmp0 = do_division_u(tmp0, b_minus_amb); + tmp0 = do_division_u(tmp0, 4); + } + + + if (tmp0 > (uint64_t)VL53L1_D_006) + tmp0 = (uint64_t)VL53L1_D_006; + + + tmp0 = tmp0 >> 2; + + + if (tmp0 > (uint64_t)VL53L1_D_007) + tmp0 = (uint64_t)VL53L1_D_007; + + + tmp1 = (uint64_t)sigma_estimator__sigma_ref_mm << 7; + tmp1 = tmp1 * tmp1; + tmp0 = tmp0 + tmp1; + + + if (tmp0 > (uint64_t)VL53L1_D_007) + tmp0 = (uint64_t)VL53L1_D_007; + + + sigma_int = VL53L1_isqrt((uint32_t)tmp0); + + *psigma_est = (uint16_t)sigma_int; + + status = VL53L1_ERROR_NONE; + } + + } + + return status; +} + +uint32_t VL53L1_f_046( + uint64_t VL53L1_p_003, + uint32_t size + ) +{ + + + uint64_t next; + uint64_t upper; + uint64_t lower; + uint32_t stepsize; + uint32_t count; + + + next = VL53L1_p_003; + upper = 0; + lower = 0; + stepsize = size/2; + count = 0; + + while (1) { + upper = next >> stepsize; + lower = next & ((1 << stepsize) - 1); + + if (upper != 0) { + count += stepsize; + next = upper; + } else { + next = lower; + } + + stepsize = stepsize / 2; + if (stepsize == 0) + break; + } + + return count; +} + + + +uint32_t VL53L1_f_043( + uint32_t VL53L1_p_003, + uint32_t VL53L1_p_018) +{ + + + uint32_t res = 0; + + if (VL53L1_p_003 > 65535 || VL53L1_p_018 > 65535) + res = 65535; + else + res = VL53L1_isqrt(VL53L1_p_003*VL53L1_p_003 + + VL53L1_p_018*VL53L1_p_018); + + return res; +} + + diff --git a/drivers/input/misc/vl53L1/protected/src/vl53l1_xtalk.c b/drivers/input/misc/vl53L1/protected/src/vl53l1_xtalk.c new file mode 100644 index 0000000000000000000000000000000000000000..2ddfcb28bc24ef28a76a89403d9a6c5671c2e3d1 --- /dev/null +++ b/drivers/input/misc/vl53L1/protected/src/vl53l1_xtalk.c @@ -0,0 +1,1195 @@ + +// SPDX-License-Identifier: BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Protected and is dual licensed, + either 'STMicroelectronics Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ****************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + ****************************************************************************** + */ + + + + +#include "vl53l1_types.h" +#include "vl53l1_platform_log.h" + +#include "vl53l1_core_support.h" +#include "vl53l1_error_codes.h" + +#include "vl53l1_xtalk.h" +#include "vl53l1_hist_core.h" + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_HISTOGRAM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_xtalk_calibration_process_data( + VL53L1_xtalk_range_results_t *pxtalk_results, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_xtalk_algo_data_t xtalk_debug; + VL53L1_xtalk_algo_data_t *pdebug = &xtalk_debug; + VL53L1_xtalk_range_data_t *pxtalk_data = NULL; + + VL53L1_histogram_bin_data_t avg_bins; + VL53L1_histogram_bin_data_t *pavg_bins = &avg_bins; + + LOG_FUNCTION_START(""); + + + + memcpy(pavg_bins, &(pxtalk_results->central_histogram_avg), + sizeof(VL53L1_histogram_bin_data_t)); + + + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_histogram_bin_data_struct( + 0, 0, &(pdebug->VL53L1_p_057)); + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_histogram_bin_data_struct( + 0, 0, &(pdebug->VL53L1_p_058)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_f_047( + pxtalk_results, + pdebug, + &(pxtalk_cal->algo__crosstalk_compensation_x_plane_gradient_kcps + ), + &(pxtalk_cal->algo__crosstalk_compensation_y_plane_gradient_kcps + )); + + + + + + if (status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pxtalk_data = &(pxtalk_results->VL53L1_p_002[4]); + + if (pxtalk_data->no_of_samples > 0) { + + + + if (status == VL53L1_ERROR_NONE) { + memcpy(&(pdebug->VL53L1_p_057), + pavg_bins, + sizeof(VL53L1_histogram_bin_data_t)); + } + + + + status = VL53L1_f_048( + pxtalk_data, + pdebug, + &(pxtalk_cal->algo__crosstalk_compensation_plane_offset_kcps)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_f_049( + pavg_bins, + pdebug, + pxtalk_data, + pxtalk_results->central_histogram__window_start, + pxtalk_results->central_histogram__window_end, + &(pxtalk_shape->xtalk_shape)); + + } else { + + + + pxtalk_cal->algo__crosstalk_compensation_plane_offset_kcps = 0; + + + + pdebug->VL53L1_p_059 = 0; + + + } + + +ENDFUNC: + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_generate_dual_reflectance_xtalk_samples( + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples +) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_histogram_bin_data_t *pzone_avg_1 = + &(pxtalk_results->histogram_avg_1[0]); + VL53L1_histogram_bin_data_t *pzone_avg_2 = + &(pxtalk_results->histogram_avg_2[0]); + + VL53L1_histogram_bin_data_t *pxtalk_output = pxtalk_avg_samples; + + + + int i = 0; + + + + for (i = 0 ; i < 5 ; i++) { + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_histogram_bin_data_struct( + 0, 0, pzone_avg_1); + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_histogram_bin_data_struct( + 0, 0, pzone_avg_2); + + pzone_avg_1++; + pzone_avg_2++; + } + + + + + pzone_avg_1 = &(pxtalk_results->histogram_avg_1[0]); + pzone_avg_2 = &(pxtalk_results->histogram_avg_2[0]); + + for (i = 0 ; i < 5 ; i++) { + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_f_050( + pzone_avg_1, + pzone_avg_2, + expected_target_distance_mm, + 0x01, + higher_reflectance, + pxtalk_output + ); + + + + pzone_avg_1++; + pzone_avg_2++; + pxtalk_output++; + + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_050( + VL53L1_histogram_bin_data_t *pzone_avg_1, + VL53L1_histogram_bin_data_t *pzone_avg_2, + uint16_t expected_target_distance, + uint8_t subtract_amb, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_output +) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_histogram_bin_data_t zone_avg_realigned; + + + SUPPRESS_UNUSED_WARNING(pxtalk_output); + SUPPRESS_UNUSED_WARNING(expected_target_distance); + + + + if ((status == VL53L1_ERROR_NONE) && (subtract_amb == 0x01)) { + VL53L1_f_037( + pzone_avg_1, + pzone_avg_1->VL53L1_p_004); + + + pzone_avg_1->VL53L1_p_004 = 0x0; + } + + if ((status == VL53L1_ERROR_NONE) && (subtract_amb == 0x01)) { + VL53L1_f_037( + pzone_avg_2, + pzone_avg_2->VL53L1_p_004); + + + pzone_avg_2->VL53L1_p_004 = 0x0; + } + + + + + + if (status == VL53L1_ERROR_NONE) { + if (higher_reflectance == 0x01) { + VL53L1_f_004( + pzone_avg_2, + pzone_avg_1, + &zone_avg_realigned); + } else { + + + + VL53L1_f_004( + pzone_avg_1, + pzone_avg_2, + &zone_avg_realigned); + + + + } + } + + + + + + + + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_f_049( + VL53L1_histogram_bin_data_t *pavg_bins, + VL53L1_xtalk_algo_data_t *pdebug, + VL53L1_xtalk_range_data_t *pxtalk_data, + uint8_t histogram__window_start, + uint8_t histogram__window_end, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint32_t ambient_thresh = 0; + + + + if (status == VL53L1_ERROR_NONE) + VL53L1_f_037( + pavg_bins, + pavg_bins->VL53L1_p_004); + + + + if (status == VL53L1_ERROR_NONE) + VL53L1_f_051( + 6, + pavg_bins->VL53L1_p_004, + &ambient_thresh); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_f_052( + pavg_bins, + ambient_thresh, + histogram__window_start, + histogram__window_end); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_f_053( + pavg_bins, + pxtalk_data, + pdebug, + pxtalk_shape); + + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_f_047( + VL53L1_xtalk_range_results_t *pxtalk_results, + VL53L1_xtalk_algo_data_t *pdebug, + int16_t *xgradient, + int16_t *ygradient + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_xtalk_range_data_t *presults_int = NULL; + + int i = 0; + + uint32_t xtalk_per_spad[4]; + int32_t VL53L1_p_060 = 0; + int32_t VL53L1_p_061 = 0; + + uint8_t result_invalid = 0; + + + LOG_FUNCTION_START(""); + + + + *xgradient = 0; + *ygradient = 0; + + + + + for (i = 0; i < 4; i++) + xtalk_per_spad[i] = 0; + + + + for (i = 0; i < 4; i++) { + + if (status == VL53L1_ERROR_NONE) { + + presults_int = &(pxtalk_results->VL53L1_p_002[i]); + + + + + if (presults_int->no_of_samples == 0) { + + + result_invalid = 1; + pdebug->VL53L1_p_062[i] = 0; + + + } else { + + xtalk_per_spad[i] = + presults_int->rate_per_spad_kcps_avg; + + + + pdebug->VL53L1_p_062[i] = + (uint32_t)xtalk_per_spad[i]; + + } + } + + } + + + + if ((status == VL53L1_ERROR_NONE) && (result_invalid == 0)) { + + + + if (status == VL53L1_ERROR_NONE) { + VL53L1_p_060 = ((int32_t)xtalk_per_spad[1] + - (int32_t)xtalk_per_spad[0]) / (8); + VL53L1_p_061 = ((int32_t)xtalk_per_spad[3] + - (int32_t)xtalk_per_spad[2]) / (8); + } + + + + + if (status == VL53L1_ERROR_NONE) { + if (VL53L1_p_060 < -32767) { + VL53L1_p_060 = -32767; + } else { + if (VL53L1_p_060 > 32767) + VL53L1_p_060 = 32767; + } + + if (VL53L1_p_061 < -32767) { + VL53L1_p_061 = -32767; + } else { + if (VL53L1_p_061 > 32767) + VL53L1_p_061 = 32767; + } + + + + pdebug->VL53L1_p_060 = (int16_t)VL53L1_p_060; + pdebug->VL53L1_p_061 = (int16_t)VL53L1_p_061; + } + + } else { + + + + VL53L1_p_060 = 0; + VL53L1_p_061 = 0; + + pdebug->VL53L1_p_060 = 0; + pdebug->VL53L1_p_061 = 0; + } + + + + if (status == VL53L1_ERROR_NONE) { + *xgradient = (int16_t)VL53L1_p_060; + *ygradient = (int16_t)VL53L1_p_061; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_048( + VL53L1_xtalk_range_data_t *pxtalk_data, + VL53L1_xtalk_algo_data_t *pdebug, + uint32_t *xtalk_mean_offset_kcps + ) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t xtalk_per_spad = 0; + uint8_t result_invalid = 0; + + LOG_FUNCTION_START(""); + + *xtalk_mean_offset_kcps = 0; + + + if (pxtalk_data->no_of_samples == 0) { + + + + result_invalid = 1; + + + + pdebug->VL53L1_p_059 = 0; + + } + + + + + if ((status == VL53L1_ERROR_NONE) && (result_invalid == 0)) { + + + + xtalk_per_spad = pxtalk_data->rate_per_spad_kcps_avg >> 2; + + + + pdebug->VL53L1_p_059 = xtalk_per_spad; + + + if (xtalk_per_spad < 0x3FFFF) + *xtalk_mean_offset_kcps = (uint32_t)xtalk_per_spad; + else + *xtalk_mean_offset_kcps = 0x3FFFF; + + } else { + + + + *xtalk_mean_offset_kcps = 0; + } + + LOG_FUNCTION_END(status); + + return status; + +} + + + + +VL53L1_Error VL53L1_f_053( + VL53L1_histogram_bin_data_t *phist_data, + VL53L1_xtalk_range_data_t *pxtalk_data, + VL53L1_xtalk_algo_data_t *pdebug, + VL53L1_xtalk_histogram_shape_t *pxtalk_histo + ) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t idx; + int32_t tmpi32; + uint8_t i = 0; + uint64_t bin_data[VL53L1_XTALK_HISTO_BINS]; + + LOG_FUNCTION_START(""); + + + + + + + pxtalk_histo->VL53L1_p_023 = + phist_data->VL53L1_p_023; + pxtalk_histo->cal_config__vcsel_start = + phist_data->cal_config__vcsel_start; + pxtalk_histo->VL53L1_p_019 = + phist_data->VL53L1_p_019; + pxtalk_histo->VL53L1_p_022 = + phist_data->VL53L1_p_022; + pxtalk_histo->time_stamp = + phist_data->time_stamp; + pxtalk_histo->vcsel_width = + phist_data->vcsel_width; + pxtalk_histo->zero_distance_phase = + phist_data->zero_distance_phase; + pxtalk_histo->zone_id = + phist_data->zone_id; + pxtalk_histo->VL53L1_p_024 = + VL53L1_XTALK_HISTO_BINS; + pxtalk_histo->phasecal_result__reference_phase = + phist_data->phasecal_result__reference_phase; + pxtalk_histo->phasecal_result__vcsel_start = + phist_data->phasecal_result__vcsel_start; + + memcpy(&(pdebug->VL53L1_p_058), + phist_data, sizeof(VL53L1_histogram_bin_data_t)); + + + + + + if (pxtalk_data->signal_total_events_avg == 0) { + for (i = 0; i < pxtalk_histo->VL53L1_p_024; i++) + bin_data[i] = 0; + goto FAIL; + } + + for (i = 0; i < pxtalk_histo->VL53L1_p_024; i++) { + idx = i + phist_data->number_of_ambient_bins; + if (phist_data->bin_data[idx] > 0) { + bin_data[i] = + ((uint64_t)phist_data->bin_data[idx] << 10); + tmpi32 = pxtalk_data->signal_total_events_avg / 2; + bin_data[i] = bin_data[i] + (uint64_t)tmpi32; + bin_data[i] = do_division_u(bin_data[i], + (uint64_t)pxtalk_data->signal_total_events_avg); + } else { + bin_data[i] = 0; + } + } + +FAIL: + + + for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) + pxtalk_histo->bin_data[i] = (uint32_t)bin_data[i]; + + + + for (i = 0; i < pxtalk_histo->VL53L1_p_024; i++) + pdebug->VL53L1_p_063[i] = pxtalk_histo->bin_data[i]; + + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_f_054( + VL53L1_customer_nvm_managed_t *pcustomer, + VL53L1_dynamic_config_t *pdyn_cfg, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_histogram_bin_data_t *pip_hist_data, + VL53L1_histogram_bin_data_t *pop_hist_data, + VL53L1_histogram_bin_data_t *pxtalk_count_data) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint32_t xtalk_rate_kcps = 0; + + LOG_FUNCTION_START(""); + + + + memcpy(pop_hist_data, pip_hist_data, + sizeof(VL53L1_histogram_bin_data_t)); + + + + status = + VL53L1_f_040( + pcustomer->algo__crosstalk_compensation_plane_offset_kcps, + pcustomer->algo__crosstalk_compensation_x_plane_gradient_kcps, + pcustomer->algo__crosstalk_compensation_y_plane_gradient_kcps, + 0, + 0, + pip_hist_data->result__dss_actual_effective_spads, + + pdyn_cfg->roi_config__user_roi_centre_spad, + pdyn_cfg->roi_config__user_roi_requested_global_xy_size, + &(xtalk_rate_kcps)); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_041( + pip_hist_data, + &(pxtalk_shape->xtalk_shape), + xtalk_rate_kcps, + pxtalk_count_data); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_f_055( + pop_hist_data, + pxtalk_count_data, + pip_hist_data->number_of_ambient_bins); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_040( + uint32_t mean_offset, + int16_t xgradient, + int16_t ygradient, + int8_t centre_offset_x, + int8_t centre_offset_y, + uint16_t roi_effective_spads, + uint8_t roi_centre_spad, + uint8_t roi_xy_size, + uint32_t *xtalk_rate_kcps + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t row = 0; + uint8_t col = 0; + + + + int16_t bound_l_x = 0; + int16_t bound_r_x = 0; + int16_t bound_u_y = 0; + int16_t bound_d_y = 0; + + int64_t xtalk_rate_ll = 0; + int64_t xtalk_rate_ur = 0; + + int64_t xtalk_avg = 0; + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(roi_effective_spads); + + + + + + + if (status == VL53L1_ERROR_NONE) { + VL53L1_decode_row_col( + roi_centre_spad, + &row, + &col); + } + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Row", row); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Col", col); + + + + if (status == VL53L1_ERROR_NONE) { + if ((((int16_t)roi_xy_size / 16) & 0x01) == 1) + bound_l_x = (int16_t) col - + (((int16_t)roi_xy_size / 32) + 1); + else + bound_l_x = (int16_t) col - + ((int16_t)roi_xy_size / 32); + + bound_r_x = (int16_t) col + ((int16_t)roi_xy_size / 32); + + if ((((int16_t)roi_xy_size) & 0x01) == 1) + bound_d_y = (int16_t) row - + ((((int16_t)roi_xy_size & 0x0f) / 2) + 1); + else + bound_d_y = (int16_t) row - + (((int16_t)roi_xy_size & 0x0f) / 2); + + bound_u_y = (int16_t) row + + (((int16_t)roi_xy_size & 0xf) / 2); + } + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_l_x", bound_l_x); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_r_x", bound_r_x); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_u_y", bound_u_y); + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_d_y", bound_d_y); + + + + + if (status == VL53L1_ERROR_NONE) { + bound_l_x = (2 * bound_l_x) - 15 + + (2 * (int16_t)centre_offset_x); + bound_r_x = (2 * bound_r_x) - 15 + + (2 * (int16_t)centre_offset_x); + bound_u_y = (2 * bound_u_y) - 15 + + (2 * (int16_t)centre_offset_y); + bound_d_y = (2 * bound_d_y) - 15 + + (2 * (int16_t)centre_offset_y); + } + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_l_x", bound_l_x); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_r_x", bound_r_x); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_u_y", bound_u_y); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "Bound_d_y", bound_d_y); + + + + + if (status == VL53L1_ERROR_NONE) { + xtalk_rate_ll = ((int64_t)bound_l_x * + ((int64_t)xgradient)) + ((int64_t)bound_d_y * + ((int64_t)ygradient)); + xtalk_rate_ll = do_division_s((xtalk_rate_ll + 1), 2); + xtalk_rate_ll += ((int64_t)mean_offset * 4); + + xtalk_rate_ur = ((int64_t)bound_r_x * + ((int64_t)xgradient)) + ((int64_t)bound_u_y * + ((int64_t)ygradient)); + xtalk_rate_ur = do_division_s((xtalk_rate_ur + 1), 2); + xtalk_rate_ur += ((int64_t)mean_offset * 4); + } + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "xtalk_rate_ll", xtalk_rate_ll); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "xtalk_rate_ur", xtalk_rate_ur); + + + + if (status == VL53L1_ERROR_NONE) + xtalk_avg = do_division_s( + ((xtalk_rate_ll + xtalk_rate_ur) + 1), 2); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "xtalk_avg", xtalk_avg); + + + + if (status == VL53L1_ERROR_NONE) + if (xtalk_avg < 0) + xtalk_avg = 0; + + + + + + *xtalk_rate_kcps = (uint32_t) xtalk_avg; + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "xtalk_rate_kcps", xtalk_avg); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_f_041( + VL53L1_histogram_bin_data_t *phist_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_data, + uint32_t xtalk_rate_kcps, + VL53L1_histogram_bin_data_t *pxtalkcount_data + ) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint64_t xtalk_events_per_spad = 0; + uint64_t xtalk_total_events = 0; + uint64_t xtalk_temp_bin = 0; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "pk_duration_internal", phist_data->peak_duration_us); + + + + xtalk_events_per_spad = do_division_u((((uint64_t)xtalk_rate_kcps * + (uint64_t)phist_data->peak_duration_us) + 500), 1000); + + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "xtalk_events_per_spad", xtalk_events_per_spad); + + + + + xtalk_total_events = xtalk_events_per_spad * + (uint64_t)phist_data->result__dss_actual_effective_spads; + + xtalk_total_events = do_division_u((xtalk_total_events), 256); + + xtalk_total_events = do_division_u((xtalk_total_events + 1024), 2048); + + if (xtalk_total_events > 0xFFFFFFFF) + xtalk_total_events = 0xFFFFFFFF; + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "xtalk_total_events", xtalk_total_events); + + + + + + + for (i = 0; i < pxtalk_data->VL53L1_p_024; i++) { + xtalk_temp_bin = (uint64_t)pxtalk_data->bin_data[i] * + (uint64_t)xtalk_total_events; + xtalk_temp_bin = do_division_u((xtalk_temp_bin + 512), 1024); + pxtalkcount_data->bin_data[i] = (uint32_t)xtalk_temp_bin; + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "bin_data", pxtalkcount_data->bin_data[i]); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_055( + VL53L1_histogram_bin_data_t *phist_data, + VL53L1_histogram_bin_data_t *pxtalk_data, + uint8_t xtalk_bin_offset) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + int32_t temp_bin; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + for (i = xtalk_bin_offset; + i < pxtalk_data->VL53L1_p_024; i++) { + + temp_bin = (int32_t)phist_data->bin_data[i] - + (int32_t)pxtalk_data->bin_data[i - xtalk_bin_offset]; + + if (temp_bin < 0) + temp_bin = 0; + + phist_data->bin_data[i] = (uint32_t)temp_bin; + } + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_052( + VL53L1_histogram_bin_data_t *pxtalk_data, + uint32_t amb_threshold, + uint8_t VL53L1_p_022, + uint8_t VL53L1_p_026) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t first_bin_int = 0; + uint8_t first_bin_inc = 0; + uint8_t last_bin_int = 0; + uint8_t realign_bin = 0; + uint8_t realign_index = 0; + int32_t realign_bin_data[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + LOG_FUNCTION_START(""); + + + + for (i = 0 ; i < VL53L1_HISTOGRAM_BUFFER_SIZE ; i++) + realign_bin_data[i] = 0; + + first_bin_int = VL53L1_p_022; + last_bin_int = VL53L1_p_026; + + + + + + VL53L1_hist_remove_ambient_bins(pxtalk_data); + + + + first_bin_int = (first_bin_int) % + pxtalk_data->VL53L1_p_024; + + last_bin_int = (last_bin_int) % + pxtalk_data->VL53L1_p_024; + + first_bin_inc = (first_bin_int + 1) % pxtalk_data->VL53L1_p_024; + + + + if (first_bin_inc > last_bin_int) { + + + realign_bin = pxtalk_data->VL53L1_p_024 - first_bin_inc; + + + first_bin_int = (first_bin_int + realign_bin) % + pxtalk_data->VL53L1_p_024; + last_bin_int = (last_bin_int + realign_bin) % + pxtalk_data->VL53L1_p_024; + + + pxtalk_data->zero_distance_phase = + pxtalk_data->zero_distance_phase + + ((uint16_t)realign_bin * 2048); + } + + if (realign_bin > 0) { + + for (i = 0; i < pxtalk_data->VL53L1_p_024; i++) + realign_bin_data[i] = pxtalk_data->bin_data[i]; + + + for (i = 0; i < pxtalk_data->VL53L1_p_024; i++) { + realign_index = (pxtalk_data->VL53L1_p_024 - + realign_bin + i) + % pxtalk_data->VL53L1_p_024; + + pxtalk_data->bin_data[i] = + realign_bin_data[realign_index]; + } + } + + + + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "first bin int", first_bin_int); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "last bin int", last_bin_int); + + trace_print( + VL53L1_TRACE_LEVEL_DEBUG, + " %-48s : %10d\n", + "amb thresh", amb_threshold); + + + + + + for (i = 0; i < pxtalk_data->VL53L1_p_024; i++) { + + if (first_bin_int <= last_bin_int) { + if ((i >= first_bin_int) && (i <= last_bin_int)) { + if (pxtalk_data->bin_data[i] < + (int32_t)amb_threshold) + pxtalk_data->bin_data[i] = 0; + } else { + pxtalk_data->bin_data[i] = 0; + } + } else { + if ((i >= first_bin_int) || (i <= last_bin_int)) { + if (pxtalk_data->bin_data[i] < + (int32_t)amb_threshold) { + pxtalk_data->bin_data[i] = 0; + } + } else { + pxtalk_data->bin_data[i] = 0; + } + } + } + + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_f_051( + uint8_t sigma_mult, + int32_t VL53L1_p_004, + uint32_t *ambient_noise) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t ambient_events_per_bin_int = 0; + + LOG_FUNCTION_START(""); + + if (VL53L1_p_004 <= 0) + ambient_events_per_bin_int = 1; + else + ambient_events_per_bin_int = (uint32_t)VL53L1_p_004; + + *ambient_noise = VL53L1_isqrt(ambient_events_per_bin_int); + + *ambient_noise = *ambient_noise * (uint32_t)sigma_mult; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + + + + + + + + + + + + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_api.c b/drivers/input/misc/vl53L1/src/vl53l1_api.c new file mode 100644 index 0000000000000000000000000000000000000000..0b20343749c4ee67ac259e12cca4d1b96a024c46 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_api.c @@ -0,0 +1,3977 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_api.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_core.h" +#include "vl53l1_api_calibration.h" +#include "vl53l1_wait.h" +#include "vl53l1_preset_setup.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_api_core.h" +#include "vl53l1_nvm.h" + + +#define ZONE_CHECK VL53L1_MAX_USER_ZONES + +#if ZONE_CHECK < 5 +#error Must define at least 5 zones in MAX_USER_ZONES constant +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, \ + fmt, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE +#define trace_print(level, ...) trace_print_module_function(\ + VL53L1_TRACE_MODULE_API, level, VL53L1_TRACE_FUNCTION_NONE, \ + ##__VA_ARGS__) +#endif + +#ifndef MIN +#define MIN(v1, v2) ((v1) < (v2) ? (v1) : (v2)) +#endif +#ifndef MAX +#define MAX(v1, v2) ((v1) < (v2) ? (v2) : (v1)) +#endif + +#define DMAX_REFLECTANCE_IDX 2 + + + +#define LOWPOWER_AUTO_VHV_LOOP_DURATION_US 245 +#define LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING 1448 +#define LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING 2100 + +#define FDA_MAX_TIMING_BUDGET_US 550000 + + + + + + +static int32_t BDTable[VL53L1_TUNING_MAX_TUNABLE_KEY] = { + TUNING_VERSION, + TUNING_PROXY_MIN, + TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + TUNING_MIN_AMBIENT_DMAX_VALID, + TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT, + TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN, + TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET, + TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR_DEFAULT, +}; + + +static VL53L1_Error SingleTargetXTalkCalibration(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint32_t sum_ranging = 0; + uint32_t sum_spads = 0; + FixPoint1616_t sum_signalRate = 0; + FixPoint1616_t total_count = 0; + uint8_t xtalk_meas = 0; + uint8_t xtalk_measmax = + BDTable[VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER]; + VL53L1_RangingMeasurementData_t RMData; + FixPoint1616_t xTalkStoredMeanSignalRate; + FixPoint1616_t xTalkStoredMeanRange; + FixPoint1616_t xTalkStoredMeanRtnSpads; + uint32_t xTalkStoredMeanRtnSpadsAsInt; + uint32_t xTalkCalDistanceAsInt; + FixPoint1616_t XTalkCompensationRateMegaCps; + uint32_t signalXTalkTotalPerSpad; + VL53L1_PresetModes PresetMode; + VL53L1_CalibrationData_t CalibrationData; + VL53L1_CustomerNvmManaged_t *pC; + + + LOG_FUNCTION_START(""); + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode != VL53L1_PRESETMODE_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LITE_RANGING)) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + goto ENDFUNC; + } + + + Status = VL53L1_disable_xtalk_compensation(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_StartMeasurement(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + + sum_ranging = 0; + sum_spads = 0; + sum_signalRate = 0; + total_count = 0; + for (xtalk_meas = 0; xtalk_meas < xtalk_measmax; xtalk_meas++) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + if (RMData.RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + sum_ranging += RMData.RangeMilliMeter; + sum_signalRate += RMData.SignalRateRtnMegaCps; + sum_spads += RMData.EffectiveSpadRtnCount / 256; + total_count++; + } + } + Status = VL53L1_StopMeasurement(Dev); + + if (total_count > 0) { + + xTalkStoredMeanSignalRate = sum_signalRate / total_count; + xTalkStoredMeanRange = (FixPoint1616_t)(sum_ranging << 16); + xTalkStoredMeanRange /= total_count; + xTalkStoredMeanRtnSpads = (FixPoint1616_t)(sum_spads << 16); + xTalkStoredMeanRtnSpads /= total_count; + + + xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads + + 0x8000) >> 16; + + + xTalkCalDistanceAsInt = ((uint32_t)BDTable[ + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM]); + if (xTalkStoredMeanRtnSpadsAsInt == 0 || + xTalkCalDistanceAsInt == 0 || + xTalkStoredMeanRange >= (xTalkCalDistanceAsInt << 16)) { + XTalkCompensationRateMegaCps = 0; + } else { + + signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) / + xTalkStoredMeanRtnSpadsAsInt; + + + signalXTalkTotalPerSpad *= (((uint32_t)1 << 16) - + (xTalkStoredMeanRange / xTalkCalDistanceAsInt)); + + + XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad + + 0x8000) >> 16; + } + + + Status = VL53L1_GetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pC = &CalibrationData.customer; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)(1000 * ((XTalkCompensationRateMegaCps + + ((uint32_t)1<<6)) >> (16-9))); + + Status = VL53L1_SetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_enable_xtalk_compensation(Dev); + + } else + + Status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + + +static VL53L1_Error CheckValidRectRoi(VL53L1_UserRoi_t ROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + if ((ROI.TopLeftX > 15) || (ROI.TopLeftY > 15) || + (ROI.BotRightX > 15) || (ROI.BotRightY > 15)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if ((ROI.TopLeftX > ROI.BotRightX) || (ROI.TopLeftY < ROI.BotRightY)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_GPIO_Interrupt_Mode ConvertModeToLLD(VL53L1_Error *pStatus, + VL53L1_ThresholdMode CrossMode) +{ + VL53L1_GPIO_Interrupt_Mode Mode; + + switch (CrossMode) { + case VL53L1_THRESHOLD_CROSSED_LOW: + Mode = VL53L1_GPIOINTMODE_LEVEL_LOW; + break; + case VL53L1_THRESHOLD_CROSSED_HIGH: + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + break; + case VL53L1_THRESHOLD_OUT_OF_WINDOW: + Mode = VL53L1_GPIOINTMODE_OUT_OF_WINDOW; + break; + case VL53L1_THRESHOLD_IN_WINDOW: + Mode = VL53L1_GPIOINTMODE_IN_WINDOW; + break; + default: + + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + *pStatus = VL53L1_ERROR_INVALID_PARAMS; + } + return Mode; +} + +static VL53L1_ThresholdMode ConvertModeFromLLD(VL53L1_Error *pStatus, + VL53L1_GPIO_Interrupt_Mode CrossMode) +{ + VL53L1_ThresholdMode Mode; + + switch (CrossMode) { + case VL53L1_GPIOINTMODE_LEVEL_LOW: + Mode = VL53L1_THRESHOLD_CROSSED_LOW; + break; + case VL53L1_GPIOINTMODE_LEVEL_HIGH: + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + break; + case VL53L1_GPIOINTMODE_OUT_OF_WINDOW: + Mode = VL53L1_THRESHOLD_OUT_OF_WINDOW; + break; + case VL53L1_GPIOINTMODE_IN_WINDOW: + Mode = VL53L1_THRESHOLD_IN_WINDOW; + break; + default: + + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + *pStatus = VL53L1_ERROR_UNDEFINED; + } + return Mode; +} + + + +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pVersion->major = VL53L1_IMPLEMENTATION_VER_MAJOR; + pVersion->minor = VL53L1_IMPLEMENTATION_VER_MINOR; + pVersion->build = VL53L1_IMPLEMENTATION_VER_SUB; + + pVersion->revision = VL53L1_IMPLEMENTATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + revision_id = pLLData->nvm_copy_data.identification__revision_id; + *pProductRevisionMajor = 1; + *pProductRevisionMinor = (revision_id & 0xF0) >> 4; + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + + strncpy(pVL53L1_DeviceInfo->ProductId, "", + VL53L1_DEVINFO_STRLEN-1); + pVL53L1_DeviceInfo->ProductType = + pLLData->nvm_copy_data.identification__module_type; + + revision_id = pLLData->nvm_copy_data.identification__revision_id; + pVL53L1_DeviceInfo->ProductRevisionMajor = 1; + pVL53L1_DeviceInfo->ProductRevisionMinor = (revision_id & 0xF0) >> 4; + +#ifndef VL53L1_USE_EMPTY_STRING + if (pVL53L1_DeviceInfo->ProductRevisionMinor == 0) + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME0, + VL53L1_DEVINFO_STRLEN-1); + else + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME1, + VL53L1_DEVINFO_STRLEN-1); + strncpy(pVL53L1_DeviceInfo->Type, + VL53L1_STRING_DEVICE_INFO_TYPE, + VL53L1_DEVINFO_STRLEN-1); + + if (pVL53L1_DeviceInfo->ProductType == 0xAA) { + pVL53L1_DeviceInfo->Name[5] = '3'; + pVL53L1_DeviceInfo->Type[5] = '3'; + } +#else + pVL53L1_DeviceInfo->Name[0] = 0; + pVL53L1_DeviceInfo->Type[0] = 0; +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetUID(VL53L1_DEV Dev, uint64_t *pUid) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t fmtdata[8]; + + LOG_FUNCTION_START(""); + + Status = VL53L1_read_nvm_raw_data(Dev, + (uint8_t)(0x1F8 >> 2), + (uint8_t)(8 >> 2), + fmtdata); + memcpy(pUid, fmtdata, sizeof(uint64_t)); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_range_status_string(RangeStatus, + pRangeStatusString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_error_string(PalErrorCode, pPalErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_state_string(PalStateCode, pPalStateString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, VL53L1_State *pPalState) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPalState = VL53L1DevDataGet(Dev, PalState); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, uint8_t DeviceAddress) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_WrByte(Dev, VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + DeviceAddress / 2); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t i; + VL53L1_LLDriverData_t *pdev; + + LOG_FUNCTION_START(""); + + +#ifdef USE_I2C_2V8 + Status = VL53L1_RdByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, &i); + if (Status == VL53L1_ERROR_NONE) { + i = (i & 0xfe) | 0x01; + Status = VL53L1_WrByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, + i); + } +#endif + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_data_init(Dev, 1); + + if (Status == VL53L1_ERROR_NONE) { + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + memset(&pdev->per_vcsel_cal_data, 0, + sizeof(pdev->per_vcsel_cal_data)); + } + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_WAIT_STATICINIT); + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, + VL53L1_PRESETMODE_RANGING); + } + + + for (i = 0; i < VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL53L1_ERROR_NONE) + Status |= VL53L1_SetLimitCheckEnable(Dev, i, 1); + else + break; + + } + + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_set_dmax_mode(Dev, + VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA); + } + + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t measurement_mode; + + LOG_FUNCTION_START(""); + + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + VL53L1DevDataSet(Dev, LLData.measurement_mode, measurement_mode); + + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + VL53L1_DISTANCEMODE_LONG); + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_poll_for_boot_completion(Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + +static VL53L1_Error ComputeDevicePresetMode( + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + VL53L1_DevicePresetModes *pDevicePresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint8_t DistIdx; + VL53L1_DevicePresetModes LightModes[3] = { + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes RangingModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE}; + + VL53L1_DevicePresetModes ScanningModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE}; + + VL53L1_DevicePresetModes TimedModes[3] = { + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes LowPowerTimedModes[3] = { + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE}; + + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + + switch (DistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + DistIdx = 0; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + DistIdx = 1; + break; + default: + DistIdx = 2; + } + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + *pDevicePresetMode = LightModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_RANGING: + *pDevicePresetMode = RangingModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + *pDevicePresetMode = ScanningModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + *pDevicePresetMode = TimedModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + *pDevicePresetMode = LowPowerTimedModes[DistIdx]; + break; + case VL53L1_PRESETMODE_OLT: + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_OLT; + break; + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + *pDevicePresetMode = + VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE; + break; + + default: + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + return Status; +} + +static VL53L1_Error SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + uint32_t inter_measurement_period_ms) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DevicePresetModes device_preset_mode; + uint8_t measurement_mode; + uint16_t dss_config__target_total_rate_mcps; + uint32_t phasecal_config_timeout_us; + uint32_t mm_config_timeout_us; + uint32_t lld_range_config_timeout_us; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_TIMED; + else + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + + Status = ComputeDevicePresetMode(PresetMode, DistanceMode, + &device_preset_mode); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_preset_mode_timing_cfg(Dev, + device_preset_mode, + &dss_config__target_total_rate_mcps, + &phasecal_config_timeout_us, + &mm_config_timeout_us, + &lld_range_config_timeout_us); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_preset_mode( + Dev, + device_preset_mode, + dss_config__target_total_rate_mcps, + phasecal_config_timeout_us, + mm_config_timeout_us, + lld_range_config_timeout_us, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.measurement_mode, + measurement_mode); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, PresetMode); + + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, VL53L1_PresetModes PresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DistanceModes DistanceMode = VL53L1_DISTANCEMODE_LONG; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + + Status = VL53L1_low_power_auto_data_init(Dev); + + if (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + DistanceMode = VL53L1_DISTANCEMODE_SHORT; + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + 1000); + + if (Status == VL53L1_ERROR_NONE) { + if ((PresetMode == VL53L1_PRESETMODE_LITE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 41000); + else + + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 33333); + } + + if (Status == VL53L1_ERROR_NONE) { + + Status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, + 1000); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint32_t inter_measurement_period_ms; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + uint32_t PhaseCalTimeoutUs; + VL53L1_zone_config_t zone_config; + + LOG_FUNCTION_START("%d", (int)DistanceMode); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + if ((PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) && + (DistanceMode != VL53L1_DISTANCEMODE_SHORT)) + return VL53L1_ERROR_INVALID_PARAMS; + if ((DistanceMode != VL53L1_DISTANCEMODE_SHORT) && + (DistanceMode != VL53L1_DISTANCEMODE_MEDIUM) && + (DistanceMode != VL53L1_DISTANCEMODE_LONG)) + return VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_zone_config(Dev, &zone_config); + + inter_measurement_period_ms = VL53L1DevDataGet(Dev, + LLData.inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, &PhaseCalTimeoutUs, + &MmTimeoutUs, &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + DistanceMode); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_set_timeouts_us(Dev, PhaseCalTimeoutUs, + MmTimeoutUs, TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.range_config_timeout_us, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_config); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pDistanceMode = VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if ((OutputMode != VL53L1_OUTPUTMODE_NEAREST) && + (OutputMode != VL53L1_OUTPUTMODE_STRONGEST)) + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + else + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pOutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t MeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled; + uint8_t Mm2Enabled; + uint32_t TimingGuard; + uint32_t divisor; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + VL53L1_PresetModes PresetMode; + uint32_t PhaseCalTimeoutUs; + uint32_t vhv; + int32_t vhv_loops; + uint32_t FDAMaxTimingBudgetUs = FDA_MAX_TIMING_BUDGET_US; + + LOG_FUNCTION_START(""); + + + if (MeasurementTimingBudgetMicroSeconds > 10000000) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + TimingGuard = 0; + divisor = 1; + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 5000; + else + TimingGuard = 1000; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 26600; + else + TimingGuard = 21600; + divisor = 2; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + divisor = 2; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + TimingGuard = 1700; + divisor = 6; + break; + + case VL53L1_PRESETMODE_OLT: + TimingGuard = MmTimeoutUs + 5000; + break; + default: + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + if (MeasurementTimingBudgetMicroSeconds <= TimingGuard) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget = (MeasurementTimingBudgetMicroSeconds + - TimingGuard); + } + + if (Status == VL53L1_ERROR_NONE) { + if (TimingBudget > FDAMaxTimingBudgetUs) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget /= divisor; + Status = VL53L1_set_timeouts_us( + Dev, + PhaseCalTimeoutUs, + MmTimeoutUs, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, + LLData.range_config_timeout_us, + TimingBudget); + } + } + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled = 0; + uint8_t Mm2Enabled = 0; + uint32_t MmTimeoutUs = 0; + uint32_t RangeTimeoutUs = 0; + uint32_t MeasTimingBdg = 0; + uint32_t PhaseCalTimeoutUs = 0; + VL53L1_PresetModes PresetMode; + uint32_t TimingGuard; + uint32_t vhv; + int32_t vhv_loops; + + LOG_FUNCTION_START(""); + + *pMeasurementTimingBudgetMicroSeconds = 0; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &RangeTimeoutUs); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = RangeTimeoutUs + 5000; + else + MeasTimingBdg = RangeTimeoutUs + 1000; + + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = 2 * RangeTimeoutUs + 26600; + else + MeasTimingBdg = 2 * RangeTimeoutUs + 21600; + + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + MeasTimingBdg = 2 * RangeTimeoutUs + TimingGuard; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + MeasTimingBdg = (6 * RangeTimeoutUs) + 1700; + break; + + case VL53L1_PRESETMODE_OLT: + MeasTimingBdg = RangeTimeoutUs + MmTimeoutUs + 5000; + break; + default: + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + } + if (Status == VL53L1_ERROR_NONE) + *pMeasurementTimingBudgetMicroSeconds = MeasTimingBdg; + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t InterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + + adjustedIMP = InterMeasurementPeriodMilliSeconds; + adjustedIMP += (adjustedIMP * 64) / 1000; + + Status = VL53L1_set_inter_measurement_period_ms(Dev, + adjustedIMP); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_inter_measurement_period_ms(Dev, &adjustedIMP); + + adjustedIMP -= (adjustedIMP * 64) / 1000; + *pInterMeasurementPeriodMilliSeconds = adjustedIMP; + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + + LOG_FUNCTION_START(""); + + if (DmaxReflectance > 100*65536) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_dmax_reflectance_values(Dev, + &dmax_reflectances); + + if (Status == VL53L1_ERROR_NONE) { + dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX] = + VL53L1_FIXPOINT1616TOFIXPOINT72(DmaxReflectance); + Status = VL53L1_set_dmax_reflectance_values(Dev, + &dmax_reflectances); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + uint16_t r; + + LOG_FUNCTION_START(""); + Status = VL53L1_get_dmax_reflectance_values(Dev, &dmax_reflectances); + if (Status == VL53L1_ERROR_NONE) { + r = dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX]; + *pDmaxReflectance = VL53L1_FIXPOINT72TOFIXPOINT1616(r); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode) +{ + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + switch (DmaxMode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + break; + case VL53L1_DMAXMODE_CUSTCAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA; + break; + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_dmax_mode(Dev, dmax_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_dmax_mode(Dev, &dmax_mode); + if (Status == VL53L1_ERROR_NONE) { + switch (dmax_mode) { + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_FMT_CAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_CUSTCAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_PER_ZONE_CAL_DATA; + break; + default: + *pDmaxMode = VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA; + Status = VL53L1_ERROR_NOT_IMPLEMENTED; + break; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +VL53L1_Error VL53L1_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfLimitCheck = VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_limit_check_info(LimitCheckId, + pLimitCheckString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckStatus) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + LimitCheckId, Temp8); + *pLimitCheckStatus = Temp8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetLimitValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t value) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t tmpuint16; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT142(value); + VL53L1_set_lite_sigma_threshold(Dev, tmpuint16); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT97(value); + VL53L1_set_lite_min_count_rate(Dev, tmpuint16); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t LimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + if (LimitCheckEnable == 0) + TempFix1616 = 0; + else + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, TempFix1616); + + Status = SetLimitValue(Dev, LimitCheckId, TempFix1616); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, + LimitCheckId, + ((LimitCheckEnable == 0) ? 0 : 1)); + + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + *pLimitCheckEnable = 0; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, Temp8); + *pLimitCheckEnable = Temp8; + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t LimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t LimitChecksEnable; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, + LimitChecksEnable); + + if (LimitChecksEnable == 0) { + + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } else { + + Status = SetLimitValue(Dev, LimitCheckId, + LimitCheckValue); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, + LimitCheckId, LimitCheckValue); + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t MinCountRate; + FixPoint1616_t TempFix1616; + uint16_t SigmaThresh; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + Status = VL53L1_get_lite_sigma_threshold(Dev, &SigmaThresh); + TempFix1616 = VL53L1_FIXPOINT142TOFIXPOINT1616(SigmaThresh); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + Status = VL53L1_get_lite_min_count_rate(Dev, &MinCountRate); + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616(MinCountRate); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) { + + if (TempFix1616 == 0) { + + VL53L1_GETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 0); + } else { + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 1); + } + } + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckCurrent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksCurrent, + LimitCheckId, TempFix1616); + *pLimitCheckCurrent = TempFix1616; + } + + LOG_FUNCTION_END(Status); + return Status; + +} + + + + + + + + +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + *pMaxNumberOfROI = VL53L1_MAX_USER_ZONES; + else + *pMaxNumberOfROI = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint8_t MaxNumberOfROI = 1; + VL53L1_zone_config_t zone_cfg; + VL53L1_UserRoi_t CurrROI; + uint8_t i; + uint8_t x_centre; + uint8_t y_centre; + uint8_t width, height; + + LOG_FUNCTION_START(""); + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + MaxNumberOfROI = VL53L1_MAX_USER_ZONES; + + if ((pRoiConfig->NumberOfRoi > MaxNumberOfROI) || + (pRoiConfig->NumberOfRoi < 1)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + + + zone_cfg.max_zones = MaxNumberOfROI; + zone_cfg.active_zones = pRoiConfig->NumberOfRoi - 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + CurrROI = pRoiConfig->UserRois[i]; + + Status = CheckValidRectRoi(CurrROI); + if (Status != VL53L1_ERROR_NONE) + break; + + x_centre = (CurrROI.BotRightX + CurrROI.TopLeftX + 1) + / 2; + y_centre = (CurrROI.TopLeftY + CurrROI.BotRightY + 1) + / 2; + width = (CurrROI.BotRightX - CurrROI.TopLeftX); + height = (CurrROI.TopLeftY - CurrROI.BotRightY); + if ((width < 3) || (height < 3)) { + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + zone_cfg.user_zones[i].x_centre = x_centre; + zone_cfg.user_zones[i].y_centre = y_centre; + zone_cfg.user_zones[i].width = width; + zone_cfg.user_zones[i].height = height; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_cfg); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_zone_config_t zone_cfg; + uint8_t i; + uint8_t TopLeftX; + uint8_t TopLeftY; + uint8_t BotRightX; + uint8_t BotRightY; + + LOG_FUNCTION_START(""); + + VL53L1_get_zone_config(Dev, &zone_cfg); + + pRoiConfig->NumberOfRoi = zone_cfg.active_zones + 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + TopLeftX = (2 * zone_cfg.user_zones[i].x_centre - + zone_cfg.user_zones[i].width) >> 1; + TopLeftY = (2 * zone_cfg.user_zones[i].y_centre + + zone_cfg.user_zones[i].height) >> 1; + BotRightX = (2 * zone_cfg.user_zones[i].x_centre + + zone_cfg.user_zones[i].width) >> 1; + BotRightY = (2 * zone_cfg.user_zones[i].y_centre - + zone_cfg.user_zones[i].height) >> 1; + pRoiConfig->UserRois[i].TopLeftX = TopLeftX; + pRoiConfig->UserRois[i].TopLeftY = TopLeftY; + pRoiConfig->UserRois[i].BotRightX = BotRightX; + pRoiConfig->UserRois[i].BotRightY = BotRightY; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); + + *pNumberOfSequenceSteps = VL53L1_SEQUENCESTEP_NUMBER_OF_ITEMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetSequenceStepsInfo(VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_steps_info( + SequenceStepId, + pSequenceStepsString); + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t MeasurementTimingBudgetMicroSeconds; + + LOG_FUNCTION_START(""); + + + + Status = VL53L1_set_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + SequenceStepEnabled); + + + if (Status == VL53L1_ERROR_NONE) { + + + MeasurementTimingBudgetMicroSeconds = VL53L1DevDataGet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds); + + VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + + return Status; +} + + +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + pSequenceStepEnabled); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + + + +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev) +{ +#define TIMED_MODE_TIMING_GUARD_MILLISECONDS 4 + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + VL53L1_State CurrPalState; + VL53L1_Error lStatus; + uint32_t MTBus, IMPms; + uint8_t i; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + LOG_FUNCTION_START(""); + VL53L1_load_patch(Dev); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) { + pdev->PreviousRangeMilliMeter[i] = 0; + pdev->PreviousRangeStatus[i] = 255; + pdev->PreviousExtendedRange[i] = 0; + } + pdev->PreviousStreamCount = 0; + CurrPalState = VL53L1DevDataGet(Dev, PalState); + switch (CurrPalState) { + case VL53L1_STATE_IDLE: + Status = VL53L1_ERROR_NONE; + break; + case VL53L1_STATE_POWERDOWN: + case VL53L1_STATE_WAIT_STATICINIT: + case VL53L1_STATE_STANDBY: + case VL53L1_STATE_RUNNING: + case VL53L1_STATE_RESET: + case VL53L1_STATE_UNKNOWN: + case VL53L1_STATE_ERROR: + Status = VL53L1_ERROR_INVALID_COMMAND; + break; + default: + Status = VL53L1_ERROR_UNDEFINED; + } + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + + if ((Status == VL53L1_ERROR_NONE) && + (DeviceMeasurementMode == VL53L1_DEVICEMEASUREMENTMODE_TIMED)) { + lStatus = VL53L1_GetMeasurementTimingBudgetMicroSeconds(Dev, + &MTBus); + + MTBus /= 1000; + lStatus = VL53L1_GetInterMeasurementPeriodMilliSeconds(Dev, + &IMPms); + + SUPPRESS_UNUSED_WARNING(lStatus); + if (IMPms < MTBus + TIMED_MODE_TIMING_GUARD_MILLISECONDS) + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_init_and_start_range( + Dev, + DeviceMeasurementMode, + VL53L1_DEVICECONFIGLEVEL_FULL); + + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_RUNNING); + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_stop_range(Dev); + VL53L1_unload_patch(Dev); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + + LOG_FUNCTION_START(""); + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + Status = VL53L1_clear_interrupt_and_enable_next_range(Dev, + DeviceMeasurementMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_is_new_data_ready(Dev, pMeasurementDataReady); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + Status = VL53L1_poll_for_range_completion(Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + +static void GenNewPresetMode(int16_t RefRange, + VL53L1_DistanceModes InternalDistanceMode, + VL53L1_DistanceModes *pNewDistanceMode) +{ + uint16_t HRLI = 600; + uint16_t HRLH = 700; + uint16_t MRLI = 1400; + uint16_t MRLH = 1500; + + switch (InternalDistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange > HRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + break; + default: + + if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + else if (RefRange < MRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + } +} + +static void CheckAndChangeDistanceMode(VL53L1_DEV Dev, + VL53L1_TargetRangeData_t *pRangeData, + int16_t Ambient100DmaxMm, + VL53L1_DistanceModes *pNewDistanceMode +) +{ + VL53L1_DistanceModes DistanceMode; + uint8_t RangeStatus = pRangeData->RangeStatus; + uint8_t DmaxValid; + int32_t MinAmbient = BDTable[VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID]; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + int32_t tmpint32; + + + switch (RangeStatus) { + case VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL: + case VL53L1_RANGESTATUS_WRAP_TARGET_FAIL: + case VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE: + case VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL: + case VL53L1_RANGESTATUS_SYNCRONISATION_INT: + case VL53L1_RANGESTATUS_NONE: + return; + default: + + break; + } + + DmaxValid = 1; + tmpint32 = pdev->hist_data.VL53L1_p_004; + if ((tmpint32 < MinAmbient) || (Ambient100DmaxMm == 0)) + DmaxValid = 0; + + DistanceMode = VL53L1DevDataGet(Dev, + CurrentParameters.DistanceMode); + + *pNewDistanceMode = DistanceMode; + + if (RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + GenNewPresetMode(pRangeData->RangeMilliMeter, + DistanceMode, pNewDistanceMode); + else { + if (DmaxValid) + GenNewPresetMode(Ambient100DmaxMm, + DistanceMode, pNewDistanceMode); + else + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + } +} + +static uint8_t ComputeRQL(uint8_t active_results, + uint8_t FilteredRangeStatus, + VL53L1_range_data_t *presults_data) +{ + int16_t T_Wide = 150; + int16_t SRL = 300; + uint16_t SRAS = 30; + FixPoint1616_t RAS; + FixPoint1616_t SRQL; + FixPoint1616_t GI = 7713587; + FixPoint1616_t GGm = 3198157; + FixPoint1616_t LRAP = 6554; + FixPoint1616_t partial; + uint8_t finalvalue; + uint8_t returnvalue; + + if (active_results == 0) + returnvalue = 0; + else if (((presults_data->max_range_mm - + presults_data->min_range_mm) >= T_Wide) || + (FilteredRangeStatus == VL53L1_DEVICEERROR_PHASECONSISTENCY)) + returnvalue = 50; + else { + if (presults_data->median_range_mm < SRL) + RAS = SRAS * 65536; + else + RAS = LRAP * presults_data->median_range_mm; + + + if (RAS != 0) { + partial = (GGm * presults_data->VL53L1_p_005); + partial = partial + (RAS >> 1); + partial = partial / RAS; + partial = partial * 65536; + if (partial <= GI) + SRQL = GI - partial; + else + SRQL = 50 * 65536; + } else + SRQL = 100 * 65536; + + finalvalue = (uint8_t)(SRQL >> 16); + returnvalue = MAX(50, MIN(100, finalvalue)); + } + + return returnvalue; +} + + +static uint8_t ConvertStatusLite(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY: + RangeStatus = VL53L1_RANGESTATUS_SYNCRONISATION_INT; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_MSRCNOTARGET: + RangeStatus = VL53L1_RANGESTATUS_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD: + RangeStatus = VL53L1_RANGESTATUS_XTALK_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_MINCLIP: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MIN_RANGE_CLIPPED; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + + +static uint8_t ConvertStatusHisto(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS: + RangeStatus = VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL; + break; + case VL53L1_DEVICEERROR_EVENTCONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + +static VL53L1_Error SetSimpleData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t device_status, + VL53L1_range_data_t *presults_data, + VL53L1_RangingMeasurementData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range; + + pRangeData->TimeStamp = presults_data->time_stamp; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + pRangeData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + return Status; +} + +static VL53L1_Error SetTargetData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t streamcount, uint8_t iteration, + uint8_t device_status, VL53L1_range_data_t *presults_data, + VL53L1_TargetRangeData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_tuning_parm_storage_t *tp = + &(pdev->tuning_parms); + uint8_t sequency; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range, RangeDiff, RangeMillimeterInit; + int32_t ExtendedRangeEnabled = 0; + uint8_t uwr_status; + int16_t AddOffset; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + pRangeData->RangeMaxMilliMeter = presults_data->max_range_mm; + pRangeData->RangeMinMilliMeter = presults_data->min_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (active_results == 0)) { + pRangeData->RangeStatus = VL53L1_RANGESTATUS_NONE; + pRangeData->SignalRateRtnMegaCps = 0; + pRangeData->SigmaMilliMeter = 0; + pRangeData->RangeMilliMeter = 8191; + pRangeData->RangeMaxMilliMeter = 8191; + pRangeData->RangeMinMilliMeter = 8191; + } + + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_UWR_ENABLE, + &ExtendedRangeEnabled); + + sequency = streamcount % 2; + uwr_status = 1; + RangeMillimeterInit = pRangeData->RangeMilliMeter; + AddOffset = 0; + + pRangeData->ExtendedRange = 0; + + if (ExtendedRangeEnabled && + (pRangeData->RangeStatus == + VL53L1_RANGESTATUS_WRAP_TARGET_FAIL || + pRangeData->RangeStatus == + VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL) + && (pdev->PreviousRangeStatus[iteration] == + VL53L1_RANGESTATUS_WRAP_TARGET_FAIL || + pdev->PreviousRangeStatus[iteration] == + VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL || + (pdev->PreviousRangeStatus[iteration] == + VL53L1_RANGESTATUS_RANGE_VALID && + pdev->PreviousExtendedRange[iteration] == 1))) + { + if (((pdev->PreviousStreamCount) == + (pdev->hist_data.result__stream_count - 1 )) + || ((pdev->PreviousStreamCount) == + (pdev->hist_data.result__stream_count + 127))) + { + RangeDiff = pRangeData->RangeMilliMeter - + pdev->PreviousRangeMilliMeter[iteration]; + + switch (pdev->preset_mode) { + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + + uwr_status = 0; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + if (RangeDiff > tp->tp_uwr_med_z_1_min && + RangeDiff < tp->tp_uwr_med_z_1_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_med_corr_z_1_rangeb; + } + else + if (RangeDiff < -tp->tp_uwr_med_z_1_min && + RangeDiff > -tp->tp_uwr_med_z_1_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_med_corr_z_1_rangea; + } + else + if (RangeDiff > tp->tp_uwr_med_z_2_min && + RangeDiff < tp->tp_uwr_med_z_2_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_med_corr_z_2_rangea; + } + else + if (RangeDiff < -tp->tp_uwr_med_z_2_min && + RangeDiff > -tp->tp_uwr_med_z_2_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_med_corr_z_2_rangeb; + } + else + if (RangeDiff > tp->tp_uwr_med_z_3_min && + RangeDiff < tp->tp_uwr_med_z_3_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_med_corr_z_3_rangeb; + } + else + if (RangeDiff < -tp->tp_uwr_med_z_3_min && + RangeDiff > -tp->tp_uwr_med_z_3_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_med_corr_z_3_rangea; + } + else + if (RangeDiff > tp->tp_uwr_med_z_4_min && + RangeDiff < tp->tp_uwr_med_z_4_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_med_corr_z_4_rangea; + } + else + if (RangeDiff < -tp->tp_uwr_med_z_4_min && + RangeDiff > -tp->tp_uwr_med_z_4_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_med_corr_z_4_rangeb; + } + else + if (RangeDiff < tp->tp_uwr_med_z_5_max && + RangeDiff > tp->tp_uwr_med_z_5_min) { + AddOffset = + tp->tp_uwr_med_corr_z_5_rangea; + } + else + if (RangeDiff > tp->tp_uwr_med_z_6_min && + RangeDiff < tp->tp_uwr_med_z_6_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_med_corr_z_6_rangeb; + } + else + if (RangeDiff < -tp->tp_uwr_med_z_6_min && + RangeDiff > -tp->tp_uwr_med_z_6_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_med_corr_z_6_rangea; + } + else + + + + + + + + + + + + uwr_status = 0; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + if (RangeDiff > tp->tp_uwr_lng_z_1_min && + RangeDiff < tp->tp_uwr_lng_z_1_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_lng_corr_z_1_rangea; + } + else + if (RangeDiff < -tp->tp_uwr_lng_z_1_min && + RangeDiff > -tp->tp_uwr_lng_z_1_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_lng_corr_z_1_rangeb; + } + else + if (RangeDiff > tp->tp_uwr_lng_z_2_min && + RangeDiff < tp->tp_uwr_lng_z_2_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_lng_corr_z_2_rangeb; + } + else + if (RangeDiff < -tp->tp_uwr_lng_z_2_min && + RangeDiff > -tp->tp_uwr_lng_z_2_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_lng_corr_z_2_rangea; + } + else + if (RangeDiff < tp->tp_uwr_lng_z_3_max && + RangeDiff > tp->tp_uwr_lng_z_3_min) { + AddOffset = + tp->tp_uwr_lng_corr_z_3_rangea; + } + else + if (RangeDiff > tp->tp_uwr_lng_z_4_min && + RangeDiff < tp->tp_uwr_lng_z_4_max && + sequency == 1) { + AddOffset = + tp->tp_uwr_lng_corr_z_4_rangeb; + } + else + if (RangeDiff < -tp->tp_uwr_lng_z_4_min && + RangeDiff > -tp->tp_uwr_lng_z_4_max && + sequency == 0) { + AddOffset = + tp->tp_uwr_lng_corr_z_4_rangea; + } + else + uwr_status = 0; + break; + + default: + uwr_status = 0; + break; + } + } + + if (uwr_status) { + pRangeData->RangeMilliMeter += AddOffset; + pRangeData->RangeMinMilliMeter += AddOffset; + pRangeData->RangeMaxMilliMeter += AddOffset; + pRangeData->ExtendedRange = 1; + pRangeData->RangeStatus = 0; + } + + } + + pdev->PreviousRangeMilliMeter[iteration] = RangeMillimeterInit; + pdev->PreviousRangeStatus[iteration] = pRangeData->RangeStatus; + pdev->PreviousExtendedRange[iteration] = pRangeData->ExtendedRange; + pdev->PreviousStreamCount = pdev->hist_data.result__stream_count; + + return Status; +} + +static uint8_t GetOutputDataIndex(VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + uint8_t i; + uint8_t index = 0; + VL53L1_OutputModes OutputMode; + + OutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + + if (OutputMode == VL53L1_OUTPUTMODE_NEAREST) + return 0; + + + for (i = 1; i < presults->active_results; i++) { + if (presults->VL53L1_p_002[i].peak_signal_count_rate_mcps > + presults->VL53L1_p_002[index].peak_signal_count_rate_mcps) + index = i; + } + + return index; +} + +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_range_results_t *presults = + (VL53L1_range_results_t *) pdev->wArea1; + VL53L1_range_data_t *presults_data; + VL53L1_PresetModes PresetMode; + uint8_t index = 0; + + LOG_FUNCTION_START(""); + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + LOG_FUNCTION_END(Status); + return Status; + } + + + memset(pRangingMeasurementData, 0xFF, + sizeof(VL53L1_RangingMeasurementData_t)); + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + if (Status == VL53L1_ERROR_NONE) { + pRangingMeasurementData->StreamCount = presults->stream_count; + + + index = GetOutputDataIndex(Dev, presults); + presults_data = &(presults->VL53L1_p_002[index]); + Status = SetSimpleData(Dev, presults->active_results, + presults->device_status, + presults_data, + pRangingMeasurementData); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetMeasurementData(VL53L1_DEV Dev, + VL53L1_range_results_t *presults, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + uint8_t i; + uint8_t iteration; + VL53L1_TargetRangeData_t *pRangeData; + VL53L1_range_data_t *presults_data; + int16_t dmax_min; + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Furthest_idx = 0; + int16_t Furthest_range = 0; + uint8_t ActiveResults, amb_idx; + + pMultiRangingData->NumberOfObjectsFound = presults->active_results; + pMultiRangingData->RoiNumber = presults->zone_id; + pMultiRangingData->HasXtalkValueChanged = + presults->smudge_corrector_data.new_xtalk_applied_flag; + dmax_min = MIN(presults->wrap_dmax_mm, + presults->VL53L1_p_007[DMAX_REFLECTANCE_IDX]); + pMultiRangingData->DmaxMilliMeter = dmax_min; + + + pMultiRangingData->TimeStamp = 0; + + pMultiRangingData->StreamCount = presults->stream_count; + + pMultiRangingData->RecommendedDistanceMode = + VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + ActiveResults = presults->active_results; + if (ActiveResults < 1) + + iteration = 1; + else + iteration = ActiveResults; + for (i = 0; i < iteration; i++) { + pRangeData = &(pMultiRangingData->RangeData[i]); + + presults_data = &(presults->VL53L1_p_002[i]); + if (Status == VL53L1_ERROR_NONE) + Status = SetTargetData(Dev, ActiveResults, + pMultiRangingData->StreamCount, + i, + presults->device_status, + presults_data, + pRangeData); + + pMultiRangingData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + && (pRangeData->RangeMilliMeter > Furthest_range)) { + Furthest_range = pRangeData->RangeMilliMeter; + Furthest_idx = i; + } + } + for (i = iteration; i < VL53L1_MAX_RANGE_RESULTS; i++) { + pdev->PreviousRangeMilliMeter[i] = 0; + pdev->PreviousRangeStatus[i] = 255; + pdev->PreviousExtendedRange[i] = 0; + } + + if ((Status == VL53L1_ERROR_NONE) && (ActiveResults > 0)) { + pRangeData = &(pMultiRangingData->RangeData[Furthest_idx]); + amb_idx = VL53L1_MAX_AMBIENT_DMAX_VALUES-1; + CheckAndChangeDistanceMode(Dev, pRangeData, + presults->VL53L1_p_007[amb_idx], + &pMultiRangingData->RecommendedDistanceMode); + } + + return Status; +} + +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_range_results_t *presults = + (VL53L1_range_results_t *) pdev->wArea1; + + LOG_FUNCTION_START(""); + + + memset(pMultiRangingData, 0xFF, + sizeof(VL53L1_MultiRangingData_t)); + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + + if (Status == VL53L1_ERROR_NONE) { + switch (presults->rd_device_state) { + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_NOT_LAST; + break; + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_LAST; + break; + default: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_NOT_VALID; + } + + Status = SetMeasurementData(Dev, + presults, + pMultiRangingData); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_additional_data(Dev, pAdditionalData); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (TuningParameterId == + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS) + return VL53L1_ERROR_INVALID_PARAMS; + + if (TuningParameterId >= 32768) + Status = VL53L1_set_tuning_parm(Dev, + TuningParameterId, + TuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + BDTable[TuningParameterId] = TuningParameterValue; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (TuningParameterId >= 32768) + Status = VL53L1_get_tuning_parm(Dev, + TuningParameterId, + pTuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + *pTuningParameterValue = BDTable[TuningParameterId]; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev) +{ +#ifdef VL53L1_NOCALIB + VL53L1_Error Status = VL53L1_ERROR_NOT_SUPPORTED; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); +#else + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error RawStatus; + uint8_t dcrbuffer[24]; + uint8_t *commbuf; + uint8_t numloc[2] = {5, 3}; + VL53L1_LLDriverData_t *pdev; + VL53L1_customer_nvm_managed_t *pc; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + pc = &pdev->customer; + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + Status = VL53L1_run_ref_spad_char(Dev, &RawStatus); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_SetPresetMode(Dev, PresetMode); + } + + if (Status == VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH) { + + Status = VL53L1_read_nvm_raw_data(Dev, + (uint8_t)(0xA0 >> 2), + (uint8_t)(24 >> 2), + dcrbuffer); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + numloc, 2); + + if (Status == VL53L1_ERROR_NONE) { + pc->ref_spad_man__num_requested_ref_spads = numloc[0]; + pc->ref_spad_man__ref_location = numloc[1]; + } + + if (Status == VL53L1_ERROR_NONE) + commbuf = &dcrbuffer[16]; + + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + commbuf, 6); + + if (Status == VL53L1_ERROR_NONE) { + pc->global_config__spad_enables_ref_0 = commbuf[0]; + pc->global_config__spad_enables_ref_1 = commbuf[1]; + pc->global_config__spad_enables_ref_2 = commbuf[2]; + pc->global_config__spad_enables_ref_3 = commbuf[3]; + pc->global_config__spad_enables_ref_4 = commbuf[4]; + pc->global_config__spad_enables_ref_5 = commbuf[5]; + } + + } + +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error s1 = VL53L1_ERROR_NONE; + VL53L1_Error s2 = VL53L1_ERROR_NONE; + VL53L1_Error s3 = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (Mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + s1 = VL53L1_dynamic_xtalk_correction_disable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_SINGLE: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_enable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_DEBUG: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + + if (Status == VL53L1_ERROR_NONE) { + Status = s1; + if (Status == VL53L1_ERROR_NONE) + Status = s2; + if (Status == VL53L1_ERROR_NONE) + Status = s3; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t XTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (XTalkCompensationEnable == 0) + Status = VL53L1_disable_xtalk_compensation(Dev); + else + Status = VL53L1_enable_xtalk_compensation(Dev); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + VL53L1_get_xtalk_compensation_enable( + Dev, + pXTalkCompensationEnable); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UStatus; + int16_t CalDistanceMm; + VL53L1_xtalk_calibration_results_t xtalk; + + VL53L1_CalibrationData_t caldata; + VL53L1_LLDriverData_t *pLLData; + int i; + uint32_t *pPlaneOffsetKcps; + uint32_t Margin = + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_BIN_SUM_MARGIN]; + uint32_t DefaultOffset = + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_DEFAULT_OFFSET]; + uint32_t *pLLDataPlaneOffsetKcps; + uint32_t sum = 0; + uint8_t binok = 0; + int32_t merge; + + LOG_FUNCTION_START(""); + + pPlaneOffsetKcps = + &caldata.customer.algo__crosstalk_compensation_plane_offset_kcps; + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + pLLDataPlaneOffsetKcps = + &pLLData->xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps; + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, &merge); + + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, 0); + switch (CalibrationOption) { + case VL53L1_XTALKCALIBRATIONMODE_NO_TARGET: + Status = VL53L1_run_xtalk_extraction(Dev, &UStatus); + + if (Status == VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL) + VL53L1_xtalk_cal_data_init(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET: + Status = SingleTargetXTalkCalibration(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_FULL_ROI: + CalDistanceMm = (int16_t) + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM]; + + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, + merge); + Status = VL53L1_run_hist_xtalk_extraction(Dev, CalDistanceMm, + &UStatus); + + VL53L1_GetCalibrationData(Dev, &caldata); + for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) { + sum += caldata.xtalkhisto.xtalk_shape.bin_data[i]; + if (caldata.xtalkhisto.xtalk_shape.bin_data[i] > 0) + binok++; + } + if ((UStatus == + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL) || + (sum > (1024 + Margin)) || (sum < (1024 - Margin)) || + (binok < 3)) { + *pPlaneOffsetKcps = DefaultOffset; + *pLLDataPlaneOffsetKcps = DefaultOffset; + caldata.xtalkhisto.xtalk_shape.bin_data[0] = 307; + caldata.xtalkhisto.xtalk_shape.bin_data[1] = 410; + caldata.xtalkhisto.xtalk_shape.bin_data[2] = 410; + caldata.xtalkhisto.xtalk_shape.bin_data[3] = 307; + for (i = 4; i < VL53L1_XTALK_HISTO_BINS; i++) + caldata.xtalkhisto.xtalk_shape.bin_data[i] = 0; + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + caldata.algo__xtalk_cpo_HistoMerge_kcps[i] = + DefaultOffset + DefaultOffset * i; + VL53L1_SetCalibrationData(Dev, &caldata); + } + + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, merge); + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + xtalk.algo__crosstalk_compensation_plane_offset_kcps); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCalibrationMode offset_cal_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCalibrationMode == VL53L1_OFFSETCALIBRATIONMODE_STANDARD) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_calibration_mode(Dev, + offset_cal_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCorrectionMode offset_cor_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCorrectionMode == VL53L1_OFFSETCORRECTIONMODE_STANDARD) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + } else if (OffsetCorrectionMode == + VL53L1_OFFSETCORRECTIONMODE_PERZONE) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS; + } else if (OffsetCorrectionMode == + VL53L1_OFFSETCORRECTIONMODE_PERVCSEL) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__PER_VCSEL_OFFSETS; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_correction_mode(Dev, + offset_cor_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, FixPoint1616_t CalReflectancePercent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UnfilteredStatus; + VL53L1_OffsetCalibrationMode offset_cal_mode; + uint16_t CalReflectancePercent_int; + + VL53L1_DevicePresetModes device_preset_mode; + VL53L1_DeviceZonePreset zone_preset; + VL53L1_zone_config_t zone_cfg; + int32_t MergeEnabled; + + LOG_FUNCTION_START(""); + + CalReflectancePercent_int = + VL53L1_FIXPOINT1616TOFIXPOINT72(CalReflectancePercent); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_offset_calibration_mode(Dev, + &offset_cal_mode); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + + if ((offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD) || + (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY + )) { + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_offset_calibration( + Dev, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + + } else if (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE) { + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, + &MergeEnabled); + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, 0); + device_preset_mode = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE; + zone_preset = VL53L1_DEVICEZONEPRESET_CUSTOM; + + Status = VL53L1_get_zone_config(Dev, &zone_cfg); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_zone_calibration( + Dev, + device_preset_mode, + zone_preset, + &zone_cfg, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, + MergeEnabled); + + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging; + uint8_t offset_meas; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t total_count, inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + int16_t offset; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + memset(&pdev->per_vcsel_cal_data, 0, sizeof(pdev->per_vcsel_cal_data)); + Repeat = BDTable[VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT]; + Max = BDTable[ + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + sum_ranging = 0; + total_count = 0; + + while ((Repeat > 0) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_StartMeasurement(Dev); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + + inloopcount = 0; + offset_meas = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (offset_meas < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + inloopcount++; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + offset_meas++; + } + total_count += inloopcount; + + + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + + VL53L1_StopMeasurement(Dev); + + Repeat--; + + } + + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + + if ((sum_ranging < 0) || + (sum_ranging > ((int32_t) total_count * 0xffff))) + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if ((Status == VL53L1_ERROR_NONE) && (total_count > 0)) { + IncRounding = total_count / 2; + meanDistance_mm = (int16_t)((sum_ranging + IncRounding) + / total_count); + offset = (int16_t)CalDistanceMilliMeter - meanDistance_mm; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = offset; + pdev->customer.mm_config__outer_offset_mm = offset; + + Status = VL53L1_set_customer_nvm_managed(Dev, + &(pdev->customer)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetZeroDistanceCalibration(VL53L1_DEV Dev) +{ + #define START_OFFSET 50 + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging; + uint8_t offset_meas; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t total_count, inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + int16_t offset, ZeroDistanceOffset; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = START_OFFSET; + pdev->customer.mm_config__outer_offset_mm = START_OFFSET; + memset(&pdev->per_vcsel_cal_data, 0, sizeof(pdev->per_vcsel_cal_data)); + ZeroDistanceOffset = BDTable[ + VL53L1_TUNING_ZERO_DISTANCE_OFFSET_NON_LINEAR_FACTOR]; + Repeat = BDTable[VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT]; + Max = BDTable[ + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + sum_ranging = 0; + total_count = 0; + + while ((Repeat > 0) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_StartMeasurement(Dev); + if (Status == VL53L1_ERROR_NONE) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + inloopcount = 0; + offset_meas = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (offset_meas < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + inloopcount++; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + offset_meas++; + } + total_count += inloopcount; + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + VL53L1_StopMeasurement(Dev); + Repeat--; + } + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + if ((sum_ranging < 0) || + (sum_ranging > ((int32_t) total_count * 0xffff))) + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if ((Status == VL53L1_ERROR_NONE) && (total_count > 0)) { + IncRounding = total_count / 2; + meanDistance_mm = (int16_t) + ((sum_ranging + IncRounding) / total_count); + offset = START_OFFSET - meanDistance_mm + ZeroDistanceOffset; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = offset; + pdev->customer.mm_config__outer_offset_mm = offset; + Status = VL53L1_set_customer_nvm_managed(Dev, + &(pdev->customer)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_calibration_data_t cal_data; + uint32_t x, IncomeVersion, CurrentVersion; + uint8_t CalStopsOn_cal_peak_rate_map = 0; + VL53L1_xtalk_calibration_results_t xtalk; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + cal_data.struct_version = pCalibrationData->struct_version - + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + IncomeVersion = pCalibrationData->struct_version; + CurrentVersion = VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + if ((IncomeVersion < CurrentVersion) && + ((IncomeVersion & 0xFFFFFF0F) == + (CurrentVersion & 0xFFFFFF0F))) { + cal_data.struct_version = + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION; + CalStopsOn_cal_peak_rate_map = 1; + + pdev->tuning_parms.tp_hist_merge = 0; + } + + + + memcpy( + &(cal_data.fmt_dmax_cal), + &(pCalibrationData->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(cal_data.cust_dmax_cal), + &(pCalibrationData->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(cal_data.add_off_cal_data), + &(pCalibrationData->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + memcpy( + &(cal_data.optical_centre), + &(pCalibrationData->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + memcpy( + &(cal_data.xtalkhisto), + &(pCalibrationData->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + memcpy( + &(cal_data.gain_cal), + &(pCalibrationData->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + memcpy( + &(cal_data.cal_peak_rate_map), + &(pCalibrationData->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + if (!CalStopsOn_cal_peak_rate_map) + memcpy( + &(cal_data.per_vcsel_cal_data), + &(pCalibrationData->per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + else { + cal_data.per_vcsel_cal_data.short_a_offset_mm = + cal_data.per_vcsel_cal_data.short_b_offset_mm = + cal_data.per_vcsel_cal_data.medium_a_offset_mm = + cal_data.per_vcsel_cal_data.medium_b_offset_mm = + cal_data.per_vcsel_cal_data.long_a_offset_mm = + cal_data.per_vcsel_cal_data.long_b_offset_mm = 0; + } + + pC = &pCalibrationData->customer; + x = pC->algo__crosstalk_compensation_plane_offset_kcps; + cal_data.customer.algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)(x&0x0000FFFF); + + cal_data.customer.global_config__spad_enables_ref_0 = + pC->global_config__spad_enables_ref_0; + cal_data.customer.global_config__spad_enables_ref_1 = + pC->global_config__spad_enables_ref_1; + cal_data.customer.global_config__spad_enables_ref_2 = + pC->global_config__spad_enables_ref_2; + cal_data.customer.global_config__spad_enables_ref_3 = + pC->global_config__spad_enables_ref_3; + cal_data.customer.global_config__spad_enables_ref_4 = + pC->global_config__spad_enables_ref_4; + cal_data.customer.global_config__spad_enables_ref_5 = + pC->global_config__spad_enables_ref_5; + cal_data.customer.global_config__ref_en_start_select = + pC->global_config__ref_en_start_select; + cal_data.customer.ref_spad_man__num_requested_ref_spads = + pC->ref_spad_man__num_requested_ref_spads; + cal_data.customer.ref_spad_man__ref_location = + pC->ref_spad_man__ref_location; + cal_data.customer.algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + cal_data.customer.algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + cal_data.customer.ref_spad_char__total_rate_target_mcps = + pC->ref_spad_char__total_rate_target_mcps; + cal_data.customer.algo__part_to_part_range_offset_mm = + pC->algo__part_to_part_range_offset_mm; + cal_data.customer.mm_config__inner_offset_mm = + pC->mm_config__inner_offset_mm; + cal_data.customer.mm_config__outer_offset_mm = + pC->mm_config__outer_offset_mm; + + Status = VL53L1_set_part_to_part_data(Dev, &cal_data); + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + xtalk.algo__crosstalk_compensation_plane_offset_kcps = x; + + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + x); + + + if (!CalStopsOn_cal_peak_rate_map) + memcpy( + &(xtalk.algo__xtalk_cpo_HistoMerge_kcps[0]), + &(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps[0]), + sizeof(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps)); + else + memset( + &(xtalk.algo__xtalk_cpo_HistoMerge_kcps[0]), 0, + sizeof(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps)); + + Status = VL53L1_set_current_xtalk_settings(Dev, &xtalk); + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t cal_data; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_customer_nvm_managed_t *pC2; + VL53L1_xtalk_calibration_results_t xtalk; + uint32_t tmp; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + + Status = VL53L1_get_part_to_part_data(Dev, &cal_data); + + pCalibrationData->struct_version = cal_data.struct_version + + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + + memcpy( + &(pCalibrationData->fmt_dmax_cal), + &(cal_data.fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(pCalibrationData->cust_dmax_cal), + &(cal_data.cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(pCalibrationData->add_off_cal_data), + &(cal_data.add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + memcpy( + &(pCalibrationData->optical_centre), + &(cal_data.optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + memcpy( + &(pCalibrationData->xtalkhisto), + &(cal_data.xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + memcpy( + &(pCalibrationData->gain_cal), + &(cal_data.gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + memcpy( + &(pCalibrationData->cal_peak_rate_map), + &(cal_data.cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + memcpy( + &(pCalibrationData->per_vcsel_cal_data), + &(cal_data.per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + + pC = &pCalibrationData->customer; + pC2 = &cal_data.customer; + pC->global_config__spad_enables_ref_0 = + pC2->global_config__spad_enables_ref_0; + pC->global_config__spad_enables_ref_1 = + pC2->global_config__spad_enables_ref_1; + pC->global_config__spad_enables_ref_2 = + pC2->global_config__spad_enables_ref_2; + pC->global_config__spad_enables_ref_3 = + pC2->global_config__spad_enables_ref_3; + pC->global_config__spad_enables_ref_4 = + pC2->global_config__spad_enables_ref_4; + pC->global_config__spad_enables_ref_5 = + pC2->global_config__spad_enables_ref_5; + pC->global_config__ref_en_start_select = + pC2->global_config__ref_en_start_select; + pC->ref_spad_man__num_requested_ref_spads = + pC2->ref_spad_man__num_requested_ref_spads; + pC->ref_spad_man__ref_location = + pC2->ref_spad_man__ref_location; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->ref_spad_char__total_rate_target_mcps = + pC2->ref_spad_char__total_rate_target_mcps; + pC->algo__part_to_part_range_offset_mm = + pC2->algo__part_to_part_range_offset_mm; + pC->mm_config__inner_offset_mm = + pC2->mm_config__inner_offset_mm; + pC->mm_config__outer_offset_mm = + pC2->mm_config__outer_offset_mm; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)( + pC2->algo__crosstalk_compensation_plane_offset_kcps); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + ) { + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + tmp = xtalk.algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = tmp; + + memcpy(&(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps[0]), + &(xtalk.algo__xtalk_cpo_HistoMerge_kcps[0]), + sizeof(pCalibrationData->algo__xtalk_cpo_HistoMerge_kcps)); + } +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_set_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t CalibrationData; + + LOG_FUNCTION_START(""); + + *pOpticalCenterX = 0; + *pOpticalCenterY = 0; + Status = VL53L1_get_part_to_part_data(Dev, &CalibrationData); + if (Status == VL53L1_ERROR_NONE) { + *pOpticalCenterX = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.x_centre); + *pOpticalCenterY = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.y_centre); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ +#define BADTHRESBOUNDS(T) \ + (((T.CrossMode == VL53L1_THRESHOLD_OUT_OF_WINDOW) || \ + (T.CrossMode == VL53L1_THRESHOLD_IN_WINDOW)) && (T.Low > T.High)) + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + uint16_t g; + FixPoint1616_t gain, high1616, low1616; + VL53L1_LLDriverData_t *pdev; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + if (Status != VL53L1_ERROR_NONE) + return Status; + + if (pConfig->DetectionMode == VL53L1_DETECTION_NORMAL_RUN) { + Cfg.intr_new_measure_ready = 1; + Status = VL53L1_set_GPIO_interrupt_config_struct(Dev, + Cfg); + } else { + if (BADTHRESBOUNDS(pConfig->Distance)) + Status = VL53L1_ERROR_INVALID_PARAMS; + if ((Status == VL53L1_ERROR_NONE) && + (BADTHRESBOUNDS(pConfig->Rate))) + Status = VL53L1_ERROR_INVALID_PARAMS; + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_new_measure_ready = 0; + Cfg.intr_no_target = pConfig->IntrNoTarget; + + g = pdev->gain_cal.standard_ranging_gain_factor; + if (g != 0) { + + gain = (FixPoint1616_t) ((uint32_t)g << 5); + high1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.High << 16); + low1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.Low << 16); + + high1616 = (high1616 + 32768) / gain; + low1616 = (low1616 + 32768) / gain; + Cfg.threshold_distance_high = (uint16_t) + (high1616 & 0xFFFF); + Cfg.threshold_distance_low = (uint16_t) + (low1616 & 0xFFFF); + } + Cfg.threshold_rate_high = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.High); + Cfg.threshold_rate_low = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.Low); + + Cfg.intr_mode_distance = ConvertModeToLLD( + &Status, + pConfig->Distance.CrossMode); + if (Status == VL53L1_ERROR_NONE) + Cfg.intr_mode_rate = ConvertModeToLLD( + &Status, + pConfig->Rate.CrossMode); + } + + + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_combined_mode = 1; + switch (pConfig->DetectionMode) { + case VL53L1_DETECTION_DISTANCE_ONLY: + Cfg.threshold_rate_high = 0; + Cfg.threshold_rate_low = 0; + break; + case VL53L1_DETECTION_RATE_ONLY: + Cfg.threshold_distance_high = 0; + Cfg.threshold_distance_low = 0; + break; + case VL53L1_DETECTION_DISTANCE_OR_RATE: + + break; + case VL53L1_DETECTION_DISTANCE_AND_RATE: + Cfg.intr_combined_mode = 0; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = + VL53L1_set_GPIO_interrupt_config_struct(Dev, Cfg); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + pConfig->IntrNoTarget = Cfg.intr_no_target; + pConfig->Distance.High = Cfg.threshold_distance_high; + pConfig->Distance.Low = Cfg.threshold_distance_low; + pConfig->Rate.High = + VL53L1_FIXPOINT97TOFIXPOINT1616( + Cfg.threshold_rate_high); + pConfig->Rate.Low = + VL53L1_FIXPOINT97TOFIXPOINT1616(Cfg.threshold_rate_low); + pConfig->Distance.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_distance); + if (Status == VL53L1_ERROR_NONE) + pConfig->Rate.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_rate); + + if (Cfg.intr_new_measure_ready == 1) { + pConfig->DetectionMode = VL53L1_DETECTION_NORMAL_RUN; + } else { + + if (Status == VL53L1_ERROR_NONE) { + if (Cfg.intr_combined_mode == 0) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_AND_RATE; + else { + if ((Cfg.threshold_distance_high == 0) && + (Cfg.threshold_distance_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_RATE_ONLY; + else if ((Cfg.threshold_rate_high == 0) && + (Cfg.threshold_rate_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_ONLY; + else + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_OR_RATE; + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + +VL53L1_Error VL53L1_PerformOffsetPerVcselCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging_range_A, sum_ranging_range_B; + uint8_t offset_meas_range_A, offset_meas_range_B; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_PresetModes currentMode; + VL53L1_DistanceModes currentDist; + VL53L1_DistanceModes DistMode[3] = {VL53L1_DISTANCEMODE_SHORT, + VL53L1_DISTANCEMODE_MEDIUM, VL53L1_DISTANCEMODE_LONG}; + int16_t offsetA[3]; + int16_t offsetB[3]; + + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en, isc; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + memset(&pdev->per_vcsel_cal_data, 0, sizeof(pdev->per_vcsel_cal_data)); + + Repeat = 0; + Max = 2 * BDTable[ + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + + Status = VL53L1_GetPresetMode(Dev, ¤tMode); + Status = VL53L1_GetDistanceMode(Dev, ¤tDist); + + while ((Repeat < 3) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_SetDistanceMode(Dev, DistMode[Repeat]); + Status = VL53L1_StartMeasurement(Dev); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + + inloopcount = 0; + offset_meas_range_A = 0; + sum_ranging_range_A = 0; + offset_meas_range_B = 0; + sum_ranging_range_B = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (inloopcount < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + isc = pdev->ll_state.cfg_internal_stream_count; + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + if (isc & 0x01) { + sum_ranging_range_A += + RangingMeasurementData.RangeMilliMeter; + offset_meas_range_A++; + } else { + sum_ranging_range_B += + RangingMeasurementData.RangeMilliMeter; + offset_meas_range_B++; + } + inloopcount = offset_meas_range_A + + offset_meas_range_B; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + } + + + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + + VL53L1_StopMeasurement(Dev); + + + if ((sum_ranging_range_A < 0) || + (sum_ranging_range_B < 0) || + (sum_ranging_range_A > + ((int32_t) offset_meas_range_A * 0xffff)) || + (sum_ranging_range_B > + ((int32_t) offset_meas_range_B * 0xffff))) { + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + } + + if ((Status == VL53L1_ERROR_NONE) && + (offset_meas_range_A > 0)) { + IncRounding = offset_meas_range_A / 2; + meanDistance_mm = (int16_t) + ((sum_ranging_range_A + IncRounding) + / offset_meas_range_A); + offsetA[Repeat] = (int16_t) + CalDistanceMilliMeter - meanDistance_mm; + } + + if ((Status == VL53L1_ERROR_NONE) && + (offset_meas_range_B > 0)) { + IncRounding = offset_meas_range_B / 2; + meanDistance_mm = (int16_t) + ((sum_ranging_range_B + IncRounding) + / offset_meas_range_B); + offsetB[Repeat] = (int16_t) + CalDistanceMilliMeter - meanDistance_mm; + } + Repeat++; + } + + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + + if (Status == VL53L1_ERROR_NONE) { + pdev->per_vcsel_cal_data.short_a_offset_mm = offsetA[0]; + pdev->per_vcsel_cal_data.short_b_offset_mm = offsetB[0]; + pdev->per_vcsel_cal_data.medium_a_offset_mm = offsetA[1]; + pdev->per_vcsel_cal_data.medium_b_offset_mm = offsetB[1]; + pdev->per_vcsel_cal_data.long_a_offset_mm = offsetA[2]; + pdev->per_vcsel_cal_data.long_b_offset_mm = offsetB[2]; + } + + VL53L1_SetPresetMode(Dev, currentMode); + VL53L1_SetDistanceMode(Dev, currentDist); + + LOG_FUNCTION_END(Status); + return Status; +} + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_api_calibration.c b/drivers/input/misc/vl53L1/src/vl53l1_api_calibration.c new file mode 100644 index 0000000000000000000000000000000000000000..8ebb26811e7d513848b07be1450afdc0604e70cf --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_api_calibration.c @@ -0,0 +1,2221 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + +******************************************************************************** + +*/ + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_api_calibration.h" + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_api_debug.h" +#endif + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_run_ref_spad_char( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[6]; + + VL53L1_refspadchar_config_t *prefspadchar = &(pdev->refspadchar); + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_ref_spad_char_config( + Dev, + prefspadchar->VL53L1_p_009, + prefspadchar->timeout_us, + prefspadchar->target_count_rate_mcps, + prefspadchar->max_count_rate_limit_mcps, + prefspadchar->min_count_rate_limit_mcps, + pdev->stat_nvm.osc_measured__fast_osc__frequency); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_run_device_test( + Dev, + prefspadchar->device_test_mode); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->dbg_results.ref_spad_char_result__num_actual_ref_spads = + comms_buffer[0]; + pdev->dbg_results.ref_spad_char_result__ref_location = + comms_buffer[1]; + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.ref_spad_man__num_requested_ref_spads = + comms_buffer[0]; + pdev->customer.ref_spad_man__ref_location = + comms_buffer[1]; + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__SPARE_0_SD1, + comms_buffer, + 6); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + 6); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.global_config__spad_enables_ref_0 = + comms_buffer[0]; + pdev->customer.global_config__spad_enables_ref_1 = + comms_buffer[1]; + pdev->customer.global_config__spad_enables_ref_2 = + comms_buffer[2]; + pdev->customer.global_config__spad_enables_ref_3 = + comms_buffer[3]; + pdev->customer.global_config__spad_enables_ref_4 = + comms_buffer[4]; + pdev->customer.global_config__spad_enables_ref_5 = + comms_buffer[5]; + } + +#ifdef VL53L1_LOG_ENABLE + + if (status == VL53L1_ERROR_NONE) + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_ref_spad_char():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_REF_SPAD_CHAR); +#endif + + if (status == VL53L1_ERROR_NONE) { + + switch (pdev->sys_results.result__range_status) { + + case VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS: + status = VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW; + break; + } + } + + + + *pcal_status = status; + + + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW, + status); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + + + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + + uint8_t results_invalid = 0; + + uint8_t i = 0; + uint16_t tmp16 = 0; + + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_START(""); + + + + + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_avg)); + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_sum)); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR, + + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + + 100); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_xtalk_compensation(Dev); + + + + pdev->xtalk_results.max_results = VL53L1_MAX_XTALK_RANGE_RESULTS; + pdev->xtalk_results.active_results = pdev->zone_cfg.active_zones+1; + + + + pdev->xtalk_results.central_histogram__window_start = 0xFF; + pdev->xtalk_results.central_histogram__window_end = 0x00; + + pdev->xtalk_results.num_of_samples_status = 0x00; + pdev->xtalk_results.zero_samples_status = 0x00; + pdev->xtalk_results.max_sigma_status = 0x00; + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + pdev->xtalk_results.VL53L1_p_002[i].no_of_samples = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg = 0; + + pdev->xtalk_results.VL53L1_p_002[i].median_phase_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].median_phase_avg = 0; + + } + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_get_and_avg_xtalk_samples( + Dev, + + pX->num_of_samples, + + measurement_mode, + + pX->algo__crosstalk_extract_max_valid_range_mm, + pX->algo__crosstalk_extract_min_valid_range_mm, + pX->algo__crosstalk_extract_max_valid_rate_kcps, + + 0x0, + 0x4, + &(pdev->xtalk_results), + &(pdev->xtalk_results.central_histogram_sum), + &(pdev->xtalk_results.central_histogram_avg)); + } + + + + + + + + if (status == VL53L1_ERROR_NONE) + if ((pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) || + (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + ((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm + << 5))) + results_invalid = 0x01; + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "pdev->xtalk_results", + VL53L1_TRACE_MODULE_CORE); +#endif + + if ((status == VL53L1_ERROR_NONE) && (results_invalid == 0)) { + + status = + VL53L1_ipp_xtalk_calibration_process_data( + Dev, + &(pdev->xtalk_results), + &(pdev->xtalk_shapes), + &(pdev->xtalk_cal)); + + } + if ((status == VL53L1_ERROR_NONE) && (results_invalid == 0)) { + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + pXC->algo__xtalk_cpo_HistoMerge_kcps[i] = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + } + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_xtalk_compensation(Dev); + + + + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples != + + pX->num_of_samples) { + + pdev->xtalk_results.num_of_samples_status = + pdev->xtalk_results.num_of_samples_status | + (1 << i); + } + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples == + 0x00) { + pdev->xtalk_results.zero_samples_status = + pdev->xtalk_results.zero_samples_status | + (1 << i); + } + + + + + tmp16 = pX->algo__crosstalk_extract_max_sigma_mm; + if (pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg > + ((uint32_t)tmp16 << 5)) { + pdev->xtalk_results.max_sigma_status = + pdev->xtalk_results.max_sigma_status | + (1 << i); + } + + } + } + + + if (results_invalid > 0) { + + if (pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) { + status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + } else { + + + if (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + (((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm) + << 5)) { + status = + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + } + + } + } else { + + if (pdev->xtalk_results.zero_samples_status != 0x00) { + status = VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.max_sigma_status != 0x00) { + status = + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.num_of_samples_status != + 0x00) + status = + VL53L1_WARNING_XTALK_MISSING_SAMPLES; + } + } + } + + + + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN, + VL53L1_WARNING_XTALK_MISSING_SAMPLES, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_extract_config( + &(pdev->xtalk_extract_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_extract_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "run_xtalk_extraction():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "run_xtalk_extraction():pdev->lldata.xtalk_results.", + VL53L1_TRACE_MODULE_XTALK_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pXR, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + +#ifdef VL53L1_LOG_ENABLE + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); +#endif + + VL53L1_range_results_t *prs = + (VL53L1_range_results_t *) pdev->wArea1; + + VL53L1_range_data_t *prange_data; + VL53L1_xtalk_range_data_t *pxtalk_range_data; + + uint8_t i = 0; + uint8_t j = 0; + uint8_t zone_id = 0; + uint8_t final_zone = pdev->zone_cfg.active_zones+1; + uint8_t valid_result; + + uint8_t smudge_corr_en = 0; + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + VL53L1_load_patch(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + for (i = 0; i <= (final_zone*num_of_samples); i++) { + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prs); + + + + if (status == VL53L1_ERROR_NONE && + pdev->ll_state.rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + zone_id = pdev->ll_state.rd_zone_id + xtalk_result_id; + prange_data = &(prs->VL53L1_p_002[0]); + + + if (prs->active_results > 1) { + for (j = 1; + j < prs->active_results; j++) { + if (prs->VL53L1_p_002[j].median_range_mm + < + prange_data->median_range_mm) + prange_data = + &(prs->VL53L1_p_002[j]); + + } + } + + pxtalk_range_data = &(pXR->VL53L1_p_002[zone_id]); + + + + if ((prs->active_results > 0) && + (prange_data->median_range_mm < + xtalk_filter_thresh_max_mm) && + (prange_data->median_range_mm > + xtalk_filter_thresh_min_mm) && + (prange_data->VL53L1_p_012 < + (uint32_t)(xtalk_max_valid_rate_kcps * 16))) + valid_result = 1; + else + valid_result = 0; + + if (valid_result == 1) { + + pxtalk_range_data->no_of_samples++; + + pxtalk_range_data->rate_per_spad_kcps_sum += + prange_data->VL53L1_p_012; + + pxtalk_range_data->signal_total_events_sum += + prange_data->VL53L1_p_013; + + pxtalk_range_data->sigma_mm_sum += + (uint32_t)prange_data->VL53L1_p_005; + + + + pxtalk_range_data->median_phase_sum += + (uint32_t)prange_data->VL53L1_p_014; + + + + + } + + if ((valid_result == 1) && (zone_id >= 4)) { + status = VL53L1_sum_histogram_data( + &(pdev->hist_data), + psum_histo); + + + + if (prange_data->VL53L1_p_015 < + pXR->central_histogram__window_start) + pXR->central_histogram__window_start = + prange_data->VL53L1_p_015; + + + if (prange_data->VL53L1_p_016 > + pXR->central_histogram__window_end) + pXR->central_histogram__window_end = + prange_data->VL53L1_p_016; + + } + + } + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_range_results( + &(pres->range_results), + "pres->range_results.", + VL53L1_TRACE_MODULE_CORE); + } +#endif + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + + + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + VL53L1_unload_patch(Dev); + + + + for (i = 0; i < (pdev->zone_cfg.active_zones+1); i++) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[i+xtalk_result_id]); + + if (pxtalk_range_data->no_of_samples > 0) { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum / + (int32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + } else { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum; + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum; + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum; + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum; + + + } + } + + + + memcpy(pavg_histo, &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + + + if (status == VL53L1_ERROR_NONE) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[xtalk_histo_id]); + + status = VL53L1_avg_histogram_data( + pxtalk_range_data->no_of_samples, + psum_histo, + pavg_histo); + } + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_DevicePresetModes device_preset_modes[ + VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + VL53L1_range_results_t *prange_results = + (VL53L1_range_results_t *) pdev->wArea1; + + VL53L1_range_data_t *pRData = NULL; + VL53L1_offset_range_data_t *pfs = NULL; + VL53L1_general_config_t *pG = &(pdev->gen_cfg); + VL53L1_additional_offset_cal_data_t *pAO = &(pdev->add_off_cal_data); + + uint8_t i = 0; + uint8_t m = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + uint16_t manual_effective_spads = + pG->dss_config__manual_effective_spads_select; + + uint8_t num_of_samples[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + uint8_t smudge_corr_en = 0; + + LOG_FUNCTION_START(""); + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL; + break; + + default: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL; + break; + } + + + + num_of_samples[0] = pdev->offsetcal_cfg.pre_num_of_samples; + num_of_samples[1] = pdev->offsetcal_cfg.mm1_num_of_samples; + num_of_samples[2] = pdev->offsetcal_cfg.mm2_num_of_samples; + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + pdev->offset_results.active_results = 1; + + break; + + default: + + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + pdev->offset_results.active_results = + VL53L1_MAX_OFFSET_RANGE_RESULTS; + + break; + } + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.cal_distance_mm = cal_distance_mm; + pdev->offset_results.cal_reflectance_pc = cal_reflectance_pc; + + for (m = 0; m < VL53L1_MAX_OFFSET_RANGE_RESULTS; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + pfs->preset_mode = 0; + pfs->no_of_samples = 0; + pfs->effective_spads = 0; + pfs->peak_rate_mcps = 0; + pfs->VL53L1_p_005 = 0; + pfs->median_range_mm = 0; + } + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + pfs->preset_mode = device_preset_modes[m]; + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_modes[m], + + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps, + pdev->offsetcal_cfg.phasecal_config_timeout_us, + pdev->offsetcal_cfg.mm_config_timeout_us, + pdev->offsetcal_cfg.range_config_timeout_us, + + 100); + + pG->dss_config__manual_effective_spads_select = + manual_effective_spads; + + + VL53L1_load_patch(Dev); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= (num_of_samples[m]+2); i++) { + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + pRData = &(prange_results->VL53L1_p_002[0]); + + if ((prange_results->active_results > 0 && + prange_results->stream_count > 1) && + (pRData->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + + pfs->no_of_samples++; + pfs->effective_spads += + (uint32_t)pRData->VL53L1_p_006; + pfs->peak_rate_mcps += + (uint32_t)pRData->peak_signal_count_rate_mcps; + pfs->VL53L1_p_005 += + (uint32_t)pRData->VL53L1_p_005; + pfs->median_range_mm += + (int32_t)pRData->median_range_mm; + + pfs->dss_config__roi_mode_control = + pG->dss_config__roi_mode_control; + pfs->dss_config__manual_effective_spads_select = + pG->dss_config__manual_effective_spads_select; + + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + VL53L1_unload_patch(Dev); + + + if (pfs->no_of_samples > 0) { + + pfs->effective_spads += (pfs->no_of_samples/2); + pfs->effective_spads /= pfs->no_of_samples; + + pfs->peak_rate_mcps += (pfs->no_of_samples/2); + pfs->peak_rate_mcps /= pfs->no_of_samples; + + pfs->VL53L1_p_005 += (pfs->no_of_samples/2); + pfs->VL53L1_p_005 /= pfs->no_of_samples; + + pfs->median_range_mm += (pfs->no_of_samples/2); + pfs->median_range_mm /= pfs->no_of_samples; + + pfs->range_mm_offset = (int32_t)cal_distance_mm; + pfs->range_mm_offset -= pfs->median_range_mm; + + + if (pfs->preset_mode == + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING) + manual_effective_spads = + (uint16_t)pfs->effective_spads; + } + } + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + + pdev->customer.mm_config__inner_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + break; + + default: + + pdev->customer.mm_config__inner_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[1].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[2].range_mm_offset; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + pAO->result__mm_inner_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].effective_spads; + pAO->result__mm_outer_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].effective_spads; + + pAO->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].peak_rate_mcps; + pAO->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].peak_rate_mcps; + + break; + } + + + + pdev->cust_dmax_cal.ref__actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].effective_spads; + pdev->cust_dmax_cal.ref__peak_signal_count_rate_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].peak_rate_mcps; + + + pdev->cust_dmax_cal.ref__distance_mm = cal_distance_mm * 16; + + pdev->cust_dmax_cal.ref_reflectance_pc = cal_reflectance_pc; + pdev->cust_dmax_cal.coverglass_transmission = 0x0100; + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + if (status == VL53L1_ERROR_NONE) { + + pdev->offset_results.cal_report = m; + + if (pfs->no_of_samples < num_of_samples[m]) + status = + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES; + + + if (m == 0 && pfs->VL53L1_p_005 > + ((uint32_t)VL53L1_OFFSET_CAL_MAX_SIGMA_MM << 5)) + status = + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if (pfs->peak_rate_mcps > + VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH; + + if (pfs->dss_config__manual_effective_spads_select < + VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS) + status = + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW; + + if (pfs->dss_config__manual_effective_spads_select == 0) + status = + VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL; + + if (pfs->no_of_samples == 0) + status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + } + } + + + + pdev->offset_results.cal_status = status; + *pcal_status = pdev->offset_results.cal_status; + + + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_MISSING_SAMPLES, + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_offset_calibration():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "run_offset_calibration():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "run_offset_calibration():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "run_offset_calibration():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_offset_range_results( + &(pdev->offset_results), + "run_offset_calibration():pdev->lldata.offset_results.", + VL53L1_TRACE_MODULE_OFFSET_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint16_t i = 0; + uint16_t m = 0; + uint32_t samples = 0; + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + uint32_t phasecal_result__reference_phase = 0; + uint32_t zero_distance_phase = 0; + + + VL53L1_load_patch(Dev); + + for (m = 0; m < phasecal_num_of_samples; m++) { + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= 1; i++) { + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + if (status == VL53L1_ERROR_NONE) { + + samples++; + + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period( + pdev->hist_data.VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + VL53L1_p_017 += + (2048 * + (uint32_t)phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * + (uint32_t)pdev->hist_data.cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + phasecal_result__reference_phase += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + + zero_distance_phase += (uint32_t)VL53L1_p_017; + } + } + VL53L1_unload_patch(Dev); + + + + if (status == VL53L1_ERROR_NONE && samples > 0) { + + phasecal_result__reference_phase += (samples >> 1); + phasecal_result__reference_phase /= samples; + + zero_distance_phase += (samples >> 1); + zero_distance_phase /= samples; + + *pphasecal_result__reference_phase = + (uint16_t)phasecal_result__reference_phase; + *pzero_distance_phase = + (uint16_t)zero_distance_phase; + } + + return status; +} + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t *pRR = + (VL53L1_range_results_t *) pdev->wArea1; + VL53L1_range_data_t *prange_data = NULL; + VL53L1_zone_calibration_data_t *pzone_data = NULL; + + uint16_t i = 0; + uint16_t m = 0; + + uint8_t z = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + VL53L1_OffsetCorrectionMode offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__NONE; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_mode, + + pdev->zonecal_cfg.dss_config__target_total_rate_mcps, + pdev->zonecal_cfg.phasecal_config_timeout_us, + pdev->zonecal_cfg.mm_config_timeout_us, + pdev->zonecal_cfg.range_config_timeout_us, + + 100); + + + + if (zone_preset == VL53L1_DEVICEZONEPRESET_CUSTOM) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_config( + Dev, + pzone_cfg); + + } else if (zone_preset != VL53L1_DEVICEZONEPRESET_NONE) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_preset( + Dev, + zone_preset); + } + + + + pres->zone_cal.preset_mode = device_preset_mode; + pres->zone_cal.zone_preset = zone_preset; + + pres->zone_cal.cal_distance_mm = cal_distance_mm * 16; + pres->zone_cal.cal_reflectance_pc = cal_reflectance_pc; + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = pdev->zone_cfg.active_zones + 1; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_014 = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_005 = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pres->zone_cal.phasecal_result__reference_phase = 0; + pres->zone_cal.zero_distance_phase = 0; + + + + status = + VL53L1_get_offset_correction_mode( + Dev, + &offset_cor_mode); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + VL53L1_OFFSETCORRECTIONMODE__NONE); + + + VL53L1_load_patch(Dev); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + + + m = (pdev->zonecal_cfg.zone_num_of_samples + 2) * + (uint16_t)pres->zone_cal.active_zones; + + + for (i = 0; i <= m; i++) { + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + pRR); + + + + prange_data = &(pRR->VL53L1_p_002[0]); + + if (pRR->active_results > 0 && + i > (uint16_t)pres->zone_cal.active_zones) { + + if (prange_data->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + + pres->zone_cal.phasecal_result__reference_phase + = + pdev->hist_data.phasecal_result__reference_phase + ; + pres->zone_cal.zero_distance_phase = + pdev->hist_data.zero_distance_phase; + + pzone_data = + &(pres->zone_cal.VL53L1_p_002[pRR->zone_id]); + pzone_data->no_of_samples++; + pzone_data->effective_spads += + (uint32_t)prange_data->VL53L1_p_006; + pzone_data->peak_rate_mcps += (uint32_t)( + prange_data->peak_signal_count_rate_mcps); + pzone_data->VL53L1_p_014 += + (uint32_t)prange_data->VL53L1_p_014; + pzone_data->VL53L1_p_005 += + (uint32_t)prange_data->VL53L1_p_005; + pzone_data->median_range_mm += + (int32_t)prange_data->median_range_mm; + + } + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + VL53L1_unload_patch(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_phasecal_average( + Dev, + measurement_mode, + pdev->hist_data.phasecal_result__vcsel_start, + + pdev->zonecal_cfg.phasecal_num_of_samples, + + pRR, + &(pres->zone_cal.phasecal_result__reference_phase), + &(pres->zone_cal.zero_distance_phase)); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + offset_cor_mode); + + + + if (status == VL53L1_ERROR_NONE) { + + for (z = 0; z < pres->zone_cal.active_zones; z++) { + + pzone_data = &(pres->zone_cal.VL53L1_p_002[z]); + + + if (pzone_data->no_of_samples > 0) { + + pzone_data->effective_spads += + (pzone_data->no_of_samples/2); + pzone_data->effective_spads /= + pzone_data->no_of_samples; + + pzone_data->peak_rate_mcps += + (pzone_data->no_of_samples/2); + pzone_data->peak_rate_mcps /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_014 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_014 /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_005 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_005 /= + pzone_data->no_of_samples; + + + + pzone_data->median_range_mm = + VL53L1_range_maths( + pdev->stat_nvm.osc_measured__fast_osc__frequency + , (uint16_t)pzone_data->VL53L1_p_014, + pres->zone_cal.zero_distance_phase, + 2, + 0x0800, + 0); + + pzone_data->range_mm_offset = + ((int32_t)cal_distance_mm) * 4; + pzone_data->range_mm_offset -= + pzone_data->median_range_mm; + + + if (pzone_data->no_of_samples < + pdev->zonecal_cfg.zone_num_of_samples) + status = + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES; + + + if (pzone_data->VL53L1_p_005 > + ((uint32_t)VL53L1_ZONE_CAL_MAX_SIGMA_MM + << 5)) + status = + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH; + + if (pzone_data->peak_rate_mcps > + VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH; + + } else { + status = VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL; + } + } + } + + + + pres->zone_cal.cal_status = status; + *pcal_status = pres->zone_cal.cal_status; + + + + IGNORE_STATUS( + IGNORE_ZONE_CAL_MISSING_SAMPLES, + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + VL53L1_print_zone_calibration_results( + &(pres->zone_cal), + "run_zone_calibration():pdev->llresults.zone_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + if (status == VL53L1_ERROR_NONE) { + pdev->ssc_cfg.array_select = array_select; + pdev->ssc_cfg.timeout_us = ssc_config_timeout_us; + status = + VL53L1_set_ssc_config( + Dev, + &(pdev->ssc_cfg), + pdev->stat_nvm.osc_measured__fast_osc__frequency); + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_device_test( + Dev, + device_test_mode); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_spad_rate_data( + Dev, + pspad_rate_data); + + if (device_test_mode == VL53L1_DEVICETESTMODE_LCR_VCSEL_ON) + pspad_rate_data->fractional_bits = 7; + else + pspad_rate_data->fractional_bits = 15; + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + +#ifdef VL53L1_LOG_ENABLE + + + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_spad_rate_data( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + VL53L1_print_spad_rate_map( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + } +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[2]; + uint8_t gpio_hv_mux__ctrl = 0; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_RdByte( + Dev, + VL53L1_GPIO_HV_MUX__CTRL, + &gpio_hv_mux__ctrl); + + if (status == VL53L1_ERROR_NONE) + pdev->stat_cfg.gpio_hv_mux__ctrl = gpio_hv_mux__ctrl; + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_start_test( + Dev, + device_test_mode); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_test_completion(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__RANGE_STATUS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->sys_results.result__range_status = comms_buffer[0]; + pdev->sys_results.result__report_status = comms_buffer[1]; + } + + + + pdev->sys_results.result__range_status &= + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + if (status == VL53L1_ERROR_NONE) { + trace_print( + VL53L1_TRACE_LEVEL_INFO, + " Device Test Complete:\n\t%-32s = %3u\n\t%-32s = %3u\n", + "result__range_status", + pdev->sys_results.result__range_status, + "result__report_status", + pdev->sys_results.result__report_status); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_clear_interrupt(Dev); + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_start_test( + Dev, + 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + int32_t lb = 0; + + pxtalk_data->sample_count = 0U; + pxtalk_data->pll_period_mm = 0U; + pxtalk_data->peak_duration_us_sum = 0U; + pxtalk_data->effective_spad_count_sum = 0U; + pxtalk_data->zero_distance_phase_sum = 0U; + pxtalk_data->zero_distance_phase_avg = 0U; + pxtalk_data->event_scaler_sum = 0U; + pxtalk_data->event_scaler_avg = 4096U; + pxtalk_data->signal_events_sum = 0; + pxtalk_data->xtalk_rate_kcps_per_spad = 0U; + pxtalk_data->VL53L1_p_015 = 0U; + pxtalk_data->VL53L1_p_016 = 0U; + pxtalk_data->target_start = 0U; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) + pxtalk_data->bin_data_sums[lb] = 0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_hist_xtalk_extract_calc_window( + target_distance_mm, + target_width_oversize, + phist_bins, + pxtalk_data); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_hist_xtalk_extract_calc_event_sums( + phist_bins, + pxtalk_data); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_xtalk_calibration_results_t *pX = pxtalk_cal; + + LOG_FUNCTION_START(""); + + if (pxtalk_data->sample_count > 0) { + + + pxtalk_data->event_scaler_avg = pxtalk_data->event_scaler_sum; + pxtalk_data->event_scaler_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->event_scaler_avg /= pxtalk_data->sample_count; + + + + status = + VL53L1_hist_xtalk_extract_calc_rate_per_spad( + pxtalk_data); + + + + if (status == VL53L1_ERROR_NONE) { + + + pxtalk_data->zero_distance_phase_avg = + pxtalk_data->zero_distance_phase_sum; + pxtalk_data->zero_distance_phase_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->zero_distance_phase_avg /= + pxtalk_data->sample_count; + + + status = + VL53L1_hist_xtalk_extract_calc_shape( + pxtalk_data, + pxtalk_shape); + + + + + pxtalk_shape->phasecal_result__vcsel_start = + phist_bins->phasecal_result__vcsel_start; + pxtalk_shape->cal_config__vcsel_start = + phist_bins->cal_config__vcsel_start; + pxtalk_shape->vcsel_width = + phist_bins->vcsel_width; + pxtalk_shape->VL53L1_p_019 = + phist_bins->VL53L1_p_019; + } + + + if (status == VL53L1_ERROR_NONE) { + + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pxtalk_data->xtalk_rate_kcps_per_spad; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps + = 0U; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps + = 0U; + + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status) +{ + + + #define OVERSIZE 4 + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + + + + uint8_t smudge_corr_en = 0; + uint8_t i = 0; + int8_t k = 0; + uint8_t nbloops; + int32_t initMergeSize = 0; + int32_t MergeEnabled = 0; + uint32_t deltaXtalk; + uint32_t stepXtalk; + uint32_t XtalkMin; + uint32_t XtalkMax; + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + int8_t MaxId; + uint8_t histo_merge_nb; + uint8_t wait_for_accumulation; + VL53L1_range_results_t *prange_results = + (VL53L1_range_results_t *) pdev->wArea1; + uint8_t Very1stRange = 0; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE, + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + 100); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_xtalk_compensation(Dev); + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + VL53L1_load_patch(Dev); + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + &initMergeSize); + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, + &MergeEnabled); + memset(&pdev->xtalk_cal, 0, sizeof(pdev->xtalk_cal)); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_and_start_range( + Dev, measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + MaxId = pdev->tuning_parms.tp_hist_merge_max_size - 1; + nbloops = (MergeEnabled == 0 ? 1 : 2); + for (k = 0; k < nbloops; k++) { + + VL53L1_hist_xtalk_extract_data_init( + &(pdev->xtalk_extract)); + VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + k * MaxId + 1); + + for (i = 0; i <= pX->num_of_samples; i++) { + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_device_results(Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + Very1stRange = + (pdev->ll_state.rd_device_state == + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC); + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + wait_for_accumulation = ((k != 0) && + (MergeEnabled) && + (status == VL53L1_ERROR_NONE) && + (histo_merge_nb < + pdev->tuning_parms.tp_hist_merge_max_size)); + if (wait_for_accumulation) + i = 0; + else { + if ((status == VL53L1_ERROR_NONE) && + (!Very1stRange)) { + status = + VL53L1_hist_xtalk_extract_update( + cal_distance_mm, + OVERSIZE, + &(pdev->hist_data), + &(pdev->xtalk_extract)); + } + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, measurement_mode); + } + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_xtalk_extract_fini( + &(pdev->hist_data), + &(pdev->xtalk_extract), + &(pdev->xtalk_cal), + &(pdev->xtalk_shapes.xtalk_shape)); + if (status == VL53L1_ERROR_NONE) { + pXC->algo__xtalk_cpo_HistoMerge_kcps[k * MaxId] = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + } + } + + + VL53L1_stop_range(Dev); + + VL53L1_set_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + initMergeSize); + VL53L1_unload_patch(Dev); + + if (status != VL53L1_ERROR_NONE) + status = VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + else if ((MergeEnabled == 1) && (MaxId > 0)) { + XtalkMin = pXC->algo__xtalk_cpo_HistoMerge_kcps[0]; + XtalkMax = pXC->algo__xtalk_cpo_HistoMerge_kcps[MaxId]; + pXC->algo__crosstalk_compensation_plane_offset_kcps = + XtalkMin; + if (XtalkMax >= XtalkMin) { + deltaXtalk = XtalkMax - XtalkMin; + stepXtalk = deltaXtalk / MaxId; + for (k = 1; k < MaxId; k++) + pXC->algo__xtalk_cpo_HistoMerge_kcps[k] = + XtalkMin + stepXtalk * k; + } else + status = + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + } + + if (status == VL53L1_ERROR_NONE) { + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + } + + + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + + status = VL53L1_enable_xtalk_compensation(Dev); + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + +#ifdef VL53L1_LOG_ENABLE + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_api_core.c b/drivers/input/misc/vl53L1/src/vl53l1_api_core.c new file mode 100644 index 0000000000000000000000000000000000000000..9444cab99427e1e6ef7b606a039418b2eefde2b6 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_api_core.c @@ -0,0 +1,7294 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_tuning_parm_defaults.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_api_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#define VL53L1_MAX_I2C_XFER_SIZE 256 + +static VL53L1_Error select_offset_per_vcsel(VL53L1_LLDriverData_t *pdev, + int16_t *poffset) { + VL53L1_Error status = VL53L1_ERROR_NONE; + int16_t tA, tB; + uint8_t isc; + + switch (pdev->preset_mode) { + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + tA = pdev->per_vcsel_cal_data.short_a_offset_mm; + tB = pdev->per_vcsel_cal_data.short_b_offset_mm; + break; + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + tA = pdev->per_vcsel_cal_data.medium_a_offset_mm; + tB = pdev->per_vcsel_cal_data.medium_b_offset_mm; + break; + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + tA = pdev->per_vcsel_cal_data.long_a_offset_mm; + tB = pdev->per_vcsel_cal_data.long_b_offset_mm; + break; + default: + status = VL53L1_ERROR_INVALID_PARAMS; + *poffset = 0; + break; + } + + isc = pdev->ll_state.cfg_internal_stream_count; + if (status == VL53L1_ERROR_NONE) + *poffset = (isc & 0x01) ? tA : tB; + + return status; +} + +static void vl53l1_diff_histo_stddev(VL53L1_LLDriverData_t *pdev, + VL53L1_histogram_bin_data_t *pdata, uint8_t timing, uint8_t HighIndex, + uint8_t prev_pos, int32_t *pdiff_histo_stddev) { + uint16_t bin = 0; + int32_t total_rate_pre = 0; + int32_t total_rate_cur = 0; + int32_t PrevBin, CurrBin; + + total_rate_pre = 0; + total_rate_cur = 0; + + + for (bin = timing * 4; bin < HighIndex; bin++) { + total_rate_pre += + pdev->multi_bins_rec[prev_pos][timing][bin]; + total_rate_cur += pdata->bin_data[bin]; + } + + if ((total_rate_pre != 0) && (total_rate_cur != 0)) + for (bin = timing * 4; bin < HighIndex; bin++) { + PrevBin = pdev->multi_bins_rec[prev_pos][timing][bin]; + PrevBin = (PrevBin * 1000) / total_rate_pre; + CurrBin = pdata->bin_data[bin] * 1000 / total_rate_cur; + *pdiff_histo_stddev += (PrevBin - CurrBin) * + (PrevBin - CurrBin); + } +} + +static void vl53l1_histo_merge(VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) { + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + uint16_t bin = 0; + uint8_t i = 0; + int32_t TuningBinRecSize = 0; + uint8_t recom_been_reset = 0; + uint8_t timing = 0; + int32_t rmt = 0; + int32_t diff_histo_stddev = 0; + uint8_t HighIndex, prev_pos; + uint8_t BuffSize = VL53L1_HISTOGRAM_BUFFER_SIZE; + uint8_t pos; + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE, + &TuningBinRecSize); + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD, + &rmt); + + + if (pdev->pos_before_next_recom == 0) { + + timing = 1 - pdata->result__stream_count % 2; + + diff_histo_stddev = 0; + HighIndex = BuffSize - timing * 4; + if (pdev->bin_rec_pos > 0) + prev_pos = pdev->bin_rec_pos - 1; + else + prev_pos = (TuningBinRecSize - 1); + + if (pdev->multi_bins_rec[prev_pos][timing][4] > 0) + vl53l1_diff_histo_stddev(pdev, pdata, + timing, HighIndex, prev_pos, + &diff_histo_stddev); + + if (diff_histo_stddev >= rmt) { + memset(pdev->multi_bins_rec, 0, + sizeof(pdev->multi_bins_rec)); + pdev->bin_rec_pos = 0; + + recom_been_reset = 1; + + if (timing == 0) + pdev->pos_before_next_recom = + VL53L1_FRAME_WAIT_EVENT; + else + pdev->pos_before_next_recom = + VL53L1_FRAME_WAIT_EVENT + 1; + } else { + + pos = pdev->bin_rec_pos; + for (i = 0; i < BuffSize; i++) + pdev->multi_bins_rec[pos][timing][i] = + pdata->bin_data[i]; + } + + if (pdev->bin_rec_pos == (TuningBinRecSize - 1) && timing == 1) + pdev->bin_rec_pos = 0; + else if (timing == 1) + pdev->bin_rec_pos++; + + if (!((recom_been_reset == 1) && (timing == 0)) && + (pdev->pos_before_next_recom == 0)) { + + for (bin = 0; bin < BuffSize; bin++) + pdata->bin_data[bin] = 0; + + for (bin = 0; bin < BuffSize; bin++) + for (i = 0; i < TuningBinRecSize; i++) + pdata->bin_data[bin] += + (pdev->multi_bins_rec[i][timing][bin]); + } + } else { + + pdev->pos_before_next_recom--; + if (pdev->pos_before_next_recom == 255) + pdev->pos_before_next_recom = 0; + } +} + +VL53L1_Error VL53L1_load_patch( + VL53L1_DEV Dev) { + VL53L1_Error status = VL53L1_ERROR_NONE; + int32_t patch_tuning = 0; + uint8_t comms_buffer[256]; + uint32_t patch_power; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x00); + + if (status == VL53L1_ERROR_NONE) + VL53L1_enable_powerforce(Dev); + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER, + &patch_tuning); + + switch (patch_tuning) { + case 0: + patch_power = 0x00; + break; + case 1: + patch_power = 0x10; + break; + case 2: + patch_power = 0x20; + break; + case 3: + patch_power = 0x40; + break; + default: + patch_power = 0x00; + } + + if (status == VL53L1_ERROR_NONE) { + + comms_buffer[0] = 0x29; + comms_buffer[1] = 0xC9; + comms_buffer[2] = 0x0E; + comms_buffer[3] = 0x40; + comms_buffer[4] = 0x28; + comms_buffer[5] = patch_power; + + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__OFFSET_0, comms_buffer, 6); + } + + if (status == VL53L1_ERROR_NONE) { + comms_buffer[0] = 0x03; + comms_buffer[1] = 0x6D; + comms_buffer[2] = 0x03; + comms_buffer[3] = 0x6F; + comms_buffer[4] = 0x07; + comms_buffer[5] = 0x29; + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__ADDRESS_0, comms_buffer, 6); + } + + if (status == VL53L1_ERROR_NONE) { + comms_buffer[0] = 0x00; + comms_buffer[1] = 0x07; + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__JMP_ENABLES, comms_buffer, 2); + } + + if (status == VL53L1_ERROR_NONE) { + comms_buffer[0] = 0x00; + comms_buffer[1] = 0x07; + status = VL53L1_WriteMulti(Dev, + VL53L1_PATCH__DATA_ENABLES, comms_buffer, 2); + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_PATCH__CTRL, 0x01); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_unload_patch( + VL53L1_DEV Dev) { + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x00); + + if (status == VL53L1_ERROR_NONE) + VL53L1_disable_powerforce(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_PATCH__CTRL, 0x00); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte(Dev, + VL53L1_FIRMWARE__ENABLE, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pdata) +{ + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_init_version(Dev); + + memcpy(pdata, &(pdev->version), sizeof(VL53L1_ll_version_t)); + + return VL53L1_ERROR_NONE; +} + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_RdWord( + Dev, + VL53L1_MCU_GENERAL_PURPOSE__GP_0, + pfw_version); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + + + VL53L1_zone_objects_t *pobjects; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_UNKNOWN); + + pres->range_results.max_results = VL53L1_MAX_RANGE_RESULTS; + pres->range_results.active_results = 0; + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = 0; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pobjects = &(pres->zone_results.VL53L1_p_002[i]); + pobjects->xmonitor.VL53L1_p_020 = 0; + pobjects->xmonitor.VL53L1_p_021 = 0; + pobjects->xmonitor.VL53L1_p_014 = 0; + pobjects->xmonitor.range_status = + VL53L1_DEVICEERROR_NOUPDATE; + } + + + + pres->zone_hists.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_hists.active_zones = 0; + + + + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = 0; + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pdev->wait_method = VL53L1_WAIT_METHOD_BLOCKING; + pdev->preset_mode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + pdev->zone_preset = VL53L1_DEVICEZONEPRESET_NONE; + pdev->measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_STOP; + + pdev->offset_calibration_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + pdev->offset_correction_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + pdev->dmax_mode = + VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + + pdev->phasecal_config_timeout_us = 1000; + pdev->mm_config_timeout_us = 2000; + pdev->range_config_timeout_us = 13000; + pdev->inter_measurement_period_ms = 100; + pdev->dss_config__target_total_rate_mcps = 0x0A00; + pdev->debug_mode = 0x00; + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.active_results = 0; + + + + pdev->gain_cal.standard_ranging_gain_factor = + VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT; + pdev->gain_cal.histogram_ranging_gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + VL53L1_init_version(Dev); + + + memset(pdev->multi_bins_rec, 0, sizeof(pdev->multi_bins_rec)); + pdev->bin_rec_pos = 0; + pdev->pos_before_next_recom = 0; + + + + if (read_p2p_data > 0 && status == VL53L1_ERROR_NONE) + status = VL53L1_read_p2p_data(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_refspadchar_config_struct( + &(pdev->refspadchar)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_ssc_config_struct( + &(pdev->ssc_cfg)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_xtalk_config_struct( + &(pdev->customer), + &(pdev->xtalk_cfg)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_xtalk_extract_config_struct( + &(pdev->xtalk_extract_cfg)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_offset_cal_config_struct( + &(pdev->offsetcal_cfg)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_zone_cal_config_struct( + &(pdev->zonecal_cfg)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_hist_post_process_config_struct( + pdev->xtalk_cfg.global_crosstalk_compensation_enable, + &(pdev->histpostprocess)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_hist_gen3_dmax_config_struct( + &(pdev->dmax_cfg)); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_tuning_parm_storage_struct( + &(pdev->tuning_parms)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_set_preset_mode( + Dev, + pdev->preset_mode, + pdev->dss_config__target_total_rate_mcps, + pdev->phasecal_config_timeout_us, + pdev->mm_config_timeout_us, + pdev->range_config_timeout_us, + pdev->inter_measurement_period_ms); + + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_data)); + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_xtalk)); + + + VL53L1_init_xtalk_bin_data_struct( + 0, + VL53L1_XTALK_HISTO_BINS, + &(pdev->xtalk_shapes.xtalk_shape)); + + + + VL53L1_xtalk_cal_data_init( + Dev + ); + + + + VL53L1_dynamic_xtalk_correction_data_init( + Dev + ); + + + + VL53L1_low_power_auto_data_init( + Dev + ); + +#ifdef VL53L1_LOG_ENABLE + + + + VL53L1_print_static_nvm_managed( + &(pdev->stat_nvm), + "data_init():pdev->lldata.stat_nvm.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "data_init():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_nvm_copy_data( + &(pdev->nvm_copy_data), + "data_init():pdev->lldata.nvm_copy_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "data_init():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "data_init():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "data_init():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_user_zone( + &(pdev->mm_roi), + "data_init():pdev->lldata.mm_roi.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_optical_centre( + &(pdev->optical_centre), + "data_init():pdev->lldata.optical_centre.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_cal_peak_rate_map( + &(pdev->cal_peak_rate_map), + "data_init():pdev->lldata.cal_peak_rate_map.", + VL53L1_TRACE_MODULE_DATA_INIT); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_additional_offset_cal_data_t *pCD = &(pdev->add_off_cal_data); + + VL53L1_decoded_nvm_fmt_range_data_t fmt_rrd; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_static_nvm_managed( + Dev, + &(pdev->stat_nvm)); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_customer_nvm_managed( + Dev, + &(pdev->customer)); + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_get_nvm_copy_data( + Dev, + &(pdev->nvm_copy_data)); + + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + } + + + + if (status == VL53L1_ERROR_NONE) { + pHP->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_optical_centre( + Dev, + &(pdev->optical_centre)); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_cal_peak_rate_map( + Dev, + &(pdev->cal_peak_rate_map)); + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_additional_offset_cal_data( + Dev, + &(pdev->add_off_cal_data)); + + + + if (pCD->result__mm_inner_peak_signal_count_rtn_mcps == 0 && + pCD->result__mm_outer_peak_signal_count_rtn_mcps == 0) { + + pCD->result__mm_inner_peak_signal_count_rtn_mcps + = 0x0080; + pCD->result__mm_outer_peak_signal_count_rtn_mcps + = 0x0180; + + + + VL53L1_calc_mm_effective_spads( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + 0xC7, + 0xFF, + &(pdev->rtn_good_spads[0]), + VL53L1_RTN_SPAD_APERTURE_TRANSMISSION, + &(pCD->result__mm_inner_actual_effective_spads), + &(pCD->result__mm_outer_actual_effective_spads)); + } + } + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_fmt_range_results_data( + Dev, + VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK, + &fmt_rrd); + + if (status == VL53L1_ERROR_NONE) { + pdev->fmt_dmax_cal.ref__actual_effective_spads = + fmt_rrd.result__actual_effective_rtn_spads; + pdev->fmt_dmax_cal.ref__peak_signal_count_rate_mcps = + fmt_rrd.result__peak_signal_count_rate_rtn_mcps; + pdev->fmt_dmax_cal.ref__distance_mm = + fmt_rrd.measured_distance_mm; + + + if (pdev->cal_peak_rate_map.cal_reflectance_pc != 0) { + pdev->fmt_dmax_cal.ref_reflectance_pc = + pdev->cal_peak_rate_map.cal_reflectance_pc; + } else { + pdev->fmt_dmax_cal.ref_reflectance_pc = 0x0014; + } + + + pdev->fmt_dmax_cal.coverglass_transmission = 0x0100; + } + } + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_RdWord( + Dev, + VL53L1_RESULT__OSC_CALIBRATE_VAL, + &(pdev->dbg_results.result__osc_calibrate_val)); + + + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency < 0x1000) { + trace_print( + VL53L1_TRACE_LEVEL_WARNING, + "\nInvalid %s value (0x%04X) - forcing to 0x%04X\n\n", + "pdev->stat_nvm.osc_measured__fast_osc__frequency", + pdev->stat_nvm.osc_measured__fast_osc__frequency, + 0xBCCC); + pdev->stat_nvm.osc_measured__fast_osc__frequency = 0xBCCC; + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_mode_mitigation_roi( + Dev, + &(pdev->mm_roi)); + + + + if (pdev->optical_centre.x_centre == 0 && + pdev->optical_centre.y_centre == 0) { + pdev->optical_centre.x_centre = + pdev->mm_roi.x_centre << 4; + pdev->optical_centre.y_centre = + pdev->mm_roi.y_centre << 4; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x00); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitUs( + Dev, + VL53L1_SOFTWARE_RESET_DURATION_US); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x01); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_boot_completion(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint32_t tempu32; + + LOG_FUNCTION_START(""); + + if (pcal_data->struct_version != + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION) { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (status == VL53L1_ERROR_NONE) { + + + memcpy( + &(pdev->customer), + &(pcal_data->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + memcpy( + &(pdev->add_off_cal_data), + &(pcal_data->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + memcpy( + &(pdev->fmt_dmax_cal), + &(pcal_data->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(pdev->cust_dmax_cal), + &(pcal_data->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(pdev->xtalk_shapes), + &(pcal_data->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + memcpy( + &(pdev->gain_cal), + &(pcal_data->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + memcpy( + &(pdev->cal_peak_rate_map), + &(pcal_data->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + memcpy( + &(pdev->per_vcsel_cal_data), + &(pcal_data->per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + + + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + if (pC->global_crosstalk_compensation_enable == 0x00) { + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + } else { + tempu32 = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + + + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_customer_nvm_managed_t *pCN = &(pcal_data->customer); + + LOG_FUNCTION_START(""); + + pcal_data->struct_version = + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION; + + + memcpy( + &(pcal_data->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + + + if (pC->algo__crosstalk_compensation_plane_offset_kcps > 0xFFFF) { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + 0xFFFF; + } else { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)pC->algo__crosstalk_compensation_plane_offset_kcps; + } + pCN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pCN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + memcpy( + &(pcal_data->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(pcal_data->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + memcpy( + &(pcal_data->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + memcpy( + &(pcal_data->optical_centre), + &(pdev->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + memcpy( + &(pcal_data->xtalkhisto), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + memcpy( + &(pcal_data->gain_cal), + &(pdev->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + memcpy( + &(pcal_data->cal_peak_rate_map), + &(pdev->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + memcpy( + &(pcal_data->per_vcsel_cal_data), + &(pdev->per_vcsel_cal_data), + sizeof(VL53L1_per_vcsel_period_offset_cal_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + pdev->tim_cfg.system__intermeasurement_period = + inter_measurement_period_ms * + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) + *pinter_measurement_period_ms = + pdev->tim_cfg.system__intermeasurement_period / + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + pdev->phasecal_config_timeout_us = phasecal_config_timeout_us; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + + status = + VL53L1_calc_timeout_register_values( + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us, + pdev->stat_nvm.osc_measured__fast_osc__frequency, + &(pdev->gen_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + + macro_period_us = + VL53L1_calc_macro_period_us( + pdev->stat_nvm.osc_measured__fast_osc__frequency, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + *pphasecal_config_timeout_us = + VL53L1_calc_timeout_us( + (uint32_t)pdev->gen_cfg.phasecal_config__timeout_macrop, + macro_period_us); + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_lo; + + *pmm_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_lo; + + *prange_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + pdev->phasecal_config_timeout_us = *pphasecal_config_timeout_us; + pdev->mm_config_timeout_us = *pmm_config_timeout_us; + pdev->range_config_timeout_us = *prange_config_timeout_us; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->gen_cfg.cal_config__repeat_rate = cal_config__repeat_period; + + return status; + +} + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pcal_config__repeat_period = pdev->gen_cfg.cal_config__repeat_rate; + + return status; + +} + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + uint8_t clr_mask = 0xFF - bit_mask; + uint8_t bit_value = value & bit_mask; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) { + bit_mask = 0x01 << bit_id; + bit_value = bit_value << bit_id; + clr_mask = 0xFF - bit_mask; + } + + pdev->dyn_cfg.system__sequence_config = + (pdev->dyn_cfg.system__sequence_config & clr_mask) | + bit_value; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; + +} + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) + bit_mask = 0x01 << bit_id; + + *pvalue = + pdev->dyn_cfg.system__sequence_config & bit_mask; + + if (bit_id > 0) + *pvalue = *pvalue >> bit_id; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; +} + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->stat_cfg.gpio_hv_mux__ctrl = + (pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK) | + (interrupt_polarity & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK); + + return status; + +} + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->refspadchar.device_test_mode = pdata->device_test_mode; + pdev->refspadchar.VL53L1_p_009 = pdata->VL53L1_p_009; + pdev->refspadchar.timeout_us = pdata->timeout_us; + pdev->refspadchar.target_count_rate_mcps = + pdata->target_count_rate_mcps; + pdev->refspadchar.min_count_rate_limit_mcps = + pdata->min_count_rate_limit_mcps; + pdev->refspadchar.max_count_rate_limit_mcps = + pdata->max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdata->device_test_mode = pdev->refspadchar.device_test_mode; + pdata->VL53L1_p_009 = pdev->refspadchar.VL53L1_p_009; + pdata->timeout_us = pdev->refspadchar.timeout_us; + pdata->target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + pdata->min_count_rate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + pdata->max_count_rate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + range_ignore_threshold_mcps; + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + range_ignore_thresh_mult; + + return status; + +} + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *prange_ignore_thresh_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + *prange_ignore_threshold_mcps_current = + pdev->stat_cfg.algo__range_ignore_threshold_mcps; + + *prange_ignore_threshold_mcps_internal = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + + return status; + +} + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pinterrupt_polarity = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK; + + return status; + +} + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + VL53L1_encode_row_col( + puser_zone->y_centre, + puser_zone->x_centre, + &(pdev->dyn_cfg.roi_config__user_roi_centre_spad)); + + + VL53L1_encode_zone_size( + puser_zone->width, + puser_zone->height, + &(pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size)); + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + VL53L1_decode_row_col( + pdev->dyn_cfg.roi_config__user_roi_centre_spad, + &(puser_zone->y_centre), + &(puser_zone->x_centre)); + + + VL53L1_decode_zone_size( + pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size, + &(puser_zone->width), + &(puser_zone->height)); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t x = 0; + uint8_t y = 0; + uint8_t xy_size = 0; + + LOG_FUNCTION_START(""); + + + VL53L1_decode_row_col( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + &y, + &x); + + pmm_roi->x_centre = x; + pmm_roi->y_centre = y; + + + xy_size = pdev->nvm_copy_data.roi_config__mode_roi_xy_size; + + pmm_roi->height = xy_size >> 4; + pmm_roi->width = xy_size & 0x0F; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy(&(pdev->zone_cfg.user_zones), &(pzone_cfg->user_zones), + sizeof(pdev->zone_cfg.user_zones)); + + + pdev->zone_cfg.max_zones = pzone_cfg->max_zones; + pdev->zone_cfg.active_zones = pzone_cfg->active_zones; + + status = VL53L1_init_zone_config_histogram_bins(&pdev->zone_cfg); + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy(pzone_cfg, &(pdev->zone_cfg), sizeof(VL53L1_zone_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_OLT: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_hist_post_process_config_t *phistpostprocess = + &(pdev->histpostprocess); + + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_histogram_config_t *phistogram = &(pdev->hist_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_tuning_parm_storage_t *ptuning_parms = &(pdev->tuning_parms); + VL53L1_low_power_auto_data_t *plpadata = + &(pdev->low_power_auto_data); + + LOG_FUNCTION_START(""); + + + pdev->preset_mode = device_preset_mode; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + + + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + status = VL53L1_preset_mode_standard_ranging_mm1_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + status = VL53L1_preset_mode_standard_ranging_mm2_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + status = VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + status = VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + status = VL53L1_preset_mode_histogram_ranging_with_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm2_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + status = VL53L1_preset_mode_histogram_multizone( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_multizone_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + status = VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + status = VL53L1_preset_mode_histogram_ranging_ref( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + status = VL53L1_preset_mode_histogram_ranging_short_timing( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + status = VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + status = VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + status = VL53L1_preset_mode_histogram_long_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + status = VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + status = VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + status = VL53L1_preset_mode_histogram_medium_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + status = VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + status = VL53L1_preset_mode_histogram_short_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + status = VL53L1_preset_mode_histogram_characterisation( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR: + status = VL53L1_preset_mode_histogram_xtalk_planar( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1: + status = VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2: + status = VL53L1_preset_mode_histogram_xtalk_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_OLT: + status = VL53L1_preset_mode_olt( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + status = VL53L1_preset_mode_singleshot_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + status = VL53L1_preset_mode_low_power_auto_short_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + status = VL53L1_preset_mode_low_power_auto_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + status = VL53L1_preset_mode_low_power_auto_long_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_special_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + + + if (status == VL53L1_ERROR_NONE) { + + pstatic->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + pdev->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_timeouts_us( + Dev, + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_inter_measurement_period_ms( + Dev, + inter_measurement_period_ms); + + + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + + LOG_FUNCTION_START(""); + + + pdev->zone_preset = zone_preset; + + + + switch (zone_preset) { + + case VL53L1_DEVICEZONEPRESET_XTALK_PLANAR: + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + 8, 1, 1, + 15, 15, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + 4, 8, 2, + 15, 7, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + 8, 1, 1, + 7, 15, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + 4, 8, 2, + 7, 7, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 2, 5, 3, + 2, 5, 3, + 4, 4, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 4, 4, + 2, 4, 4, + 3, 3, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 3, 5, + 2, 3, 5, + 3, 3, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 3, 1, 11, + 3, 1, 11, + 4, 4, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 1, 13, + 2, 1, 13, + 3, 3, + pzone_cfg); + + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + 8, 1, 1, + 3, 3, + pzone_cfg); + break; + + } + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint32_t tempu32; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + tempu32 = VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps + = pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps + = pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + pC->global_crosstalk_compensation_enable = 0x01; + + pHP->algo__crosstalk_compensation_enable = + pC->global_crosstalk_compensation_enable; + + + + + if (status == VL53L1_ERROR_NONE) { + pC->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->algo__crosstalk_compensation_x_plane_gradient_kcps, + pC->algo__crosstalk_compensation_y_plane_gradient_kcps, + pC->crosstalk_range_ignore_threshold_mult); +} + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + LOG_FUNCTION_END(status); + + return status; + +} + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable) +{ + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + *pcrosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + +} + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + + LOG_FUNCTION_START(""); + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pC->nvm_default__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + + + + pdev->xtalk_cfg.global_crosstalk_compensation_enable = 0x00; + + pHP->algo__crosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + + + + if (status == VL53L1_ERROR_NONE) { + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + 0x0000; + } + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + } + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + + LOG_FUNCTION_START(""); + + *pphase_consistency = + pHP->algo__consistency_check__phase_tolerance; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__phase_tolerance = + phase_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pevent_consistency = + pdev->histpostprocess.algo__consistency_check__event_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__event_sigma = + event_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pamb_thresh_sigma = + pdev->histpostprocess.ambient_thresh_sigma1; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.ambient_thresh_sigma1 = + amb_thresh_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_sigma = + pdev->tim_cfg.range_config__sigma_thresh; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__sigma_thresh = lite_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_mincountrate = + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps = + lite_mincountrate; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pmax_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + *pmin_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + *pmax_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + *pmax_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + max_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + min_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + max_valid_rate_kcps; + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *phist_target_order = + pdev->histpostprocess.hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.hist_target_order = hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdmax_reflectances->target_reflectance_for_dmax[i] = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i] = + pdmax_reflectances->target_reflectance_for_dmax[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound / 4; + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (vhv_loopbound * 4); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_init_en = (pdev->stat_nvm.vhv_config__init & 0x80) >> 7; + *pvhv_init_value = + (pdev->stat_nvm.vhv_config__init & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__init = + ((vhv_init_en & 0x01) << 7) + + (vhv_init_value & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_static_nvm_managed_t *pstatic_nvm = &(pdev->stat_nvm); + VL53L1_customer_nvm_managed_t *pcustomer_nvm = &(pdev->customer); + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint8_t *pbuffer = &buffer[0]; + uint16_t i = 0; + uint16_t i2c_index = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + pdev->measurement_mode = measurement_mode; + + + + psystem->system__mode_start = + (psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + measurement_mode; + + + + status = + VL53L1_set_user_zone( + Dev, + &(pdev->zone_cfg.user_zones[pdev->ll_state.cfg_zone_id])); + + + if (pdev->zone_cfg.active_zones > 0) { + status = + VL53L1_set_zone_dss_config( + Dev, + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]) + ); + } + + + + + if (((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == 0x00) && + (pdev->xtalk_cfg.global_crosstalk_compensation_enable + == 0x01)) { + pdev->stat_cfg.algo__range_ignore_threshold_mcps = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + } + + + + + + if (pdev->low_power_auto_data.low_power_auto_range_count == 0xFF) + pdev->low_power_auto_data.low_power_auto_range_count = 0x0; + + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 0)) { + + pdev->low_power_auto_data.saved_interrupt_config = + pdev->gen_cfg.system__interrupt_config_gpio; + + pdev->gen_cfg.system__interrupt_config_gpio = 1 << 5; + + if ((pdev->dyn_cfg.system__sequence_config & ( + VL53L1_SEQUENCE_MM1_EN | VL53L1_SEQUENCE_MM2_EN)) == + 0x0) { + pN->algo__part_to_part_range_offset_mm = + (pN->mm_config__outer_offset_mm << 2); + } else { + pN->algo__part_to_part_range_offset_mm = 0x0; + } + + + if (device_config_level < + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS) { + device_config_level = + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS; + } + } + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 1)) { + + pdev->gen_cfg.system__interrupt_config_gpio = + pdev->low_power_auto_data.saved_interrupt_config; + + + device_config_level = VL53L1_DEVICECONFIGLEVEL_FULL; + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_save_cfg_data(Dev); + + + + switch (device_config_level) { + case VL53L1_DEVICECONFIGLEVEL_FULL: + i2c_index = VL53L1_STATIC_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS: + i2c_index = VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS: + i2c_index = VL53L1_STATIC_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS: + i2c_index = VL53L1_GENERAL_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS: + i2c_index = VL53L1_TIMING_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS: + i2c_index = VL53L1_DYNAMIC_CONFIG_I2C_INDEX; + break; + default: + i2c_index = VL53L1_SYSTEM_CONTROL_I2C_INDEX; + break; + } + + + + i2c_buffer_size_bytes = + (VL53L1_SYSTEM_CONTROL_I2C_INDEX + + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) - + i2c_index; + + + + pbuffer = &buffer[0]; + for (i = 0; i < i2c_buffer_size_bytes; i++) + *pbuffer++ = 0; + + + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_nvm_managed( + pstatic_nvm, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_customer_nvm_managed( + pcustomer_nvm, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_config( + pstatic, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_GENERAL_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_general_config( + pgeneral, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_TIMING_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_timing_config( + ptiming, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DYNAMIC_CONFIG_I2C_INDEX - i2c_index; + + + if ((psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) { + pdynamic->system__grouped_parameter_hold_0 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold_1 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold = + pstate->cfg_gph_id; + } + status = + VL53L1_i2c_encode_dynamic_config( + pdynamic, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_SYSTEM_CONTROL_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_system_control( + psystem, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_WriteMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + } + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_rd_state(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_cfg_state(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + VL53L1_DEVICEMEASUREMENTMODE_ABORT; + + status = VL53L1_set_system_control( + Dev, + &pdev->sys_ctrl); + + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK); + + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + + V53L1_init_zone_dss_configs(Dev); + + + if (pdev->low_power_auto_data.is_low_power_auto_mode == 1) + VL53L1_low_power_auto_data_stop_range(Dev); + + return status; +} + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_system_results_t *psystem_results = &(pdev->sys_results); + VL53L1_core_results_t *pcore_results = &(pdev->core_results); + VL53L1_debug_results_t *pdebug_results = &(pdev->dbg_results); + + uint16_t i2c_index = VL53L1_SYSTEM_RESULTS_I2C_INDEX; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + + switch (device_results_level) { + case VL53L1_DEVICERESULTSLEVEL_FULL: + i2c_buffer_size_bytes = + (VL53L1_DEBUG_RESULTS_I2C_INDEX + + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + case VL53L1_DEVICERESULTSLEVEL_UPTO_CORE: + i2c_buffer_size_bytes = + (VL53L1_CORE_RESULTS_I2C_INDEX + + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + default: + i2c_buffer_size_bytes = + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES; + break; + } + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + + + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DEBUG_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pdebug_results); + } + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_UPTO_CORE && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CORE_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pcore_results); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = 0; + status = + VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + psystem_results); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level, + VL53L1_range_results_t *prange_results) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t *presults = + &(pres->range_results); + VL53L1_zone_objects_t *pobjects = + &(pres->zone_results.VL53L1_p_002[0]); + VL53L1_ll_driver_state_t *pstate = + &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = + &(pdev->zone_cfg); + VL53L1_zone_hist_info_t *phist_info = + &(pres->zone_hists.VL53L1_p_002[0]); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_low_power_auto_data_t *pL = &(pdev->low_power_auto_data); + VL53L1_histogram_bin_data_t *pHD = &(pdev->hist_data); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_zone_histograms_t *pZH = &(pres->zone_hists); + VL53L1_xtalk_calibration_results_t *pXCR = &(pdev->xtalk_cal); + uint8_t tmp8; + uint8_t zid; + uint8_t i; + uint8_t histo_merge_nb, idx; + uint8_t merge_enabled; + VL53L1_range_data_t *pdata; + + LOG_FUNCTION_START(""); + + merge_enabled = (pdev->tuning_parms.tp_hist_merge == 1) && + (VL53L1DevDataGet(Dev, CurrentParameters.PresetMode) == + VL53L1_PRESETMODE_RANGING); + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) + == VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) { + + + + status = VL53L1_get_histogram_bin_data( + Dev, + &(pdev->hist_data)); + + + + + if (status == VL53L1_ERROR_NONE && + pHD->number_of_ambient_bins == 0) { + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_copy_and_scale_ambient_info( + &(pZH->VL53L1_p_002[zid]), + &(pdev->hist_data)); + } + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + if (histo_merge_nb == 0) + histo_merge_nb = 1; + idx = histo_merge_nb - 1; + if (merge_enabled) + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXCR->algo__xtalk_cpo_HistoMerge_kcps[idx]; + + pHP->gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdev->dmax_cfg.ambient_thresh_sigma = + pHP->ambient_thresh_sigma1; + pdev->dmax_cfg.min_ambient_thresh_events = + pHP->min_ambient_thresh_events; + pdev->dmax_cfg.signal_total_events_limit = + pHP->signal_total_events_limit; + pdev->dmax_cfg.dss_config__target_total_rate_mcps = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + pdev->dmax_cfg.dss_config__aperture_attenuation = + pdev->gen_cfg.dss_config__aperture_attenuation; + + pHP->algo__crosstalk_detect_max_valid_range_mm = + pC->algo__crosstalk_detect_max_valid_range_mm; + pHP->algo__crosstalk_detect_min_valid_range_mm = + pC->algo__crosstalk_detect_min_valid_range_mm; + pHP->algo__crosstalk_detect_max_valid_rate_kcps = + pC->algo__crosstalk_detect_max_valid_rate_kcps; + pHP->algo__crosstalk_detect_max_sigma_mm = + pC->algo__crosstalk_detect_max_sigma_mm; + + + + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + + + + switch (pdev->offset_correction_mode) { + + case VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS: + tmp8 = pdev->gen_cfg.dss_config__aperture_attenuation; + + VL53L1_hist_combine_mm1_mm2_offsets( + pN->mm_config__inner_offset_mm, + pN->mm_config__outer_offset_mm, + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->add_off_cal_data), + &(pdev->rtn_good_spads[0]), + (uint16_t)tmp8, + &(pHP->range_offset_mm)); + break; + case VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS: + zid = pdev->ll_state.rd_zone_id; + pHP->range_offset_mm = (int16_t)( + pres->zone_cal.VL53L1_p_002[zid].range_mm_offset); + break; + case VL53L1_OFFSETCORRECTIONMODE__PER_VCSEL_OFFSETS: + select_offset_per_vcsel( + pdev, + &(pHP->range_offset_mm)); + pHP->range_offset_mm *= 4; + break; + default: + pHP->range_offset_mm = 0; + break; + + } + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + VL53L1_calc_max_effective_spads( + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->rtn_good_spads[0]), + (uint16_t)pdev->gen_cfg.dss_config__aperture_attenuation, + &(pdev->dmax_cfg.max_effective_spads)); + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->dmax_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_ipp_hist_process_data( + Dev, + pdmax_cal, + &(pdev->dmax_cfg), + &(pdev->histpostprocess), + &(pdev->hist_data), + &(pdev->xtalk_shapes), + pdev->wArea1, + pdev->wArea2, + &histo_merge_nb, + presults); + + if ((merge_enabled) && (histo_merge_nb > 1)) + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) { + pdata = &(presults->VL53L1_p_002[i]); + pdata->VL53L1_p_020 /= histo_merge_nb; + pdata->VL53L1_p_021 /= histo_merge_nb; + pdata->VL53L1_p_013 /= histo_merge_nb; + pdata->peak_signal_count_rate_mcps /= histo_merge_nb; + pdata->avg_signal_count_rate_mcps /= histo_merge_nb; + pdata->ambient_count_rate_mcps /= histo_merge_nb; + pdata->VL53L1_p_012 /= histo_merge_nb; + } + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_hist_wrap_dmax( + &(pdev->histpostprocess), + &(pdev->hist_data), + &(presults->wrap_dmax_mm)); + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_phase_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + presults); + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_xmonitor_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + &(presults->xmonitor)); + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + zid = pdev->ll_state.rd_zone_id; + pZH->max_zones = VL53L1_MAX_USER_ZONES; + pZH->active_zones = + pdev->zone_cfg.active_zones+1; + pHD->zone_id = zid; + + if (zid < + pres->zone_results.max_zones) { + + phist_info = + &(pZH->VL53L1_p_002[zid]); + + phist_info->rd_device_state = + pHD->rd_device_state; + + phist_info->number_of_ambient_bins = + pHD->number_of_ambient_bins; + + phist_info->result__dss_actual_effective_spads = + pHD->result__dss_actual_effective_spads; + + phist_info->VL53L1_p_009 = + pHD->VL53L1_p_009; + + phist_info->total_periods_elapsed = + pHD->total_periods_elapsed; + + phist_info->ambient_events_sum = + pHD->ambient_events_sum; + } + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + VL53L1_hist_copy_results_to_sys_and_core( + &(pdev->hist_data), + presults, + &(pdev->sys_results), + &(pdev->core_results)); + + +UPDATE_DYNAMIC_CONFIG: + if (pzone_cfg->active_zones > 0) { + if (pstate->rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_dynamic_zone_update( + Dev, presults); + } + } + + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pzone_cfg->bin_config[i] = + ((pdev->ll_state.cfg_internal_stream_count) + & 0x01) ? + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB : + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_multizone_hist_bins_update(Dev); + + } + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_dynamic_xtalk_correction_corrector(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "get_device_results():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_HISTOGRAM_DATA); +#endif + + if (merge_enabled) + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXCR->algo__xtalk_cpo_HistoMerge_kcps[0]; + } else { + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_measurement_results( + Dev, + device_results_level); + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_sys_and_core_results_to_range_results( + (int32_t)pdev->gain_cal.standard_ranging_gain_factor, + &(pdev->sys_results), + &(pdev->core_results), + presults); + + + + if (pL->is_low_power_auto_mode == 1) { + + if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 0)) { + + status = + VL53L1_low_power_auto_setup_manual_calibration( + Dev); + pL->low_power_auto_range_count = 1; + } else if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 1)) { + pL->low_power_auto_range_count = 2; + } + + + if ((pL->low_power_auto_range_count != 0xFF) && + (status == VL53L1_ERROR_NONE)) { + status = VL53L1_low_power_auto_update_DSS( + Dev); + } + } + + } + + + presults->cfg_device_state = pdev->ll_state.cfg_device_state; + presults->rd_device_state = pdev->ll_state.rd_device_state; + presults->zone_id = pdev->ll_state.rd_zone_id; + + if (status == VL53L1_ERROR_NONE) { + + + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = pdev->zone_cfg.active_zones+1; + zid = pdev->ll_state.rd_zone_id; + + if (zid < pres->zone_results.max_zones) { + + pobjects = + &(pres->zone_results.VL53L1_p_002[zid]); + + pobjects->cfg_device_state = + presults->cfg_device_state; + pobjects->rd_device_state = presults->rd_device_state; + pobjects->zone_id = presults->zone_id; + pobjects->stream_count = presults->stream_count; + + + + pobjects->xmonitor.VL53L1_p_020 = + presults->xmonitor.VL53L1_p_020; + pobjects->xmonitor.VL53L1_p_021 = + presults->xmonitor.VL53L1_p_021; + pobjects->xmonitor.VL53L1_p_014 = + presults->xmonitor.VL53L1_p_014; + pobjects->xmonitor.range_status = + presults->xmonitor.range_status; + + pobjects->max_objects = presults->max_results; + pobjects->active_objects = presults->active_results; + + for (i = 0; i < presults->active_results; i++) { + pobjects->VL53L1_p_002[i].VL53L1_p_020 = + presults->VL53L1_p_002[i].VL53L1_p_020; + pobjects->VL53L1_p_002[i].VL53L1_p_021 = + presults->VL53L1_p_002[i].VL53L1_p_021; + pobjects->VL53L1_p_002[i].VL53L1_p_014 = + presults->VL53L1_p_002[i].VL53L1_p_014; + pobjects->VL53L1_p_002[i].range_status = + presults->VL53L1_p_002[i].range_status; + } + + + } + } + + + + memcpy( + prange_results, + presults, + sizeof(VL53L1_range_results_t)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_check_ll_driver_rd_state(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_range_results( + presults, + "get_device_results():pdev->llresults.range_results.", + VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + + VL53L1_static_nvm_managed_t *pstat_nvm = &(pdev->stat_nvm); + VL53L1_static_config_t *pstat_cfg = &(pdev->stat_cfg); + VL53L1_general_config_t *pgen_cfg = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptim_cfg = &(pdev->tim_cfg); + VL53L1_range_results_t *presults = &(pres->range_results); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + uint8_t *pbuffer = &buffer[0]; + uint8_t bin_23_0 = 0x00; + uint16_t bin = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t encoded_timeout = 0; + uint32_t pll_period_us = 0; + uint32_t periods_elapsed_tmp = 0; + uint8_t i = 0; + int32_t hist_merge = 0; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX, + pbuffer, + VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES); + + + + pdata->result__interrupt_status = *(pbuffer + 0); + pdata->result__range_status = *(pbuffer + 1); + pdata->result__report_status = *(pbuffer + 2); + pdata->result__stream_count = *(pbuffer + 3); + pdata->result__dss_actual_effective_spads = + VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + + pdata->phasecal_result__reference_phase = + VL53L1_i2c_decode_uint16_t(2, pbuffer); + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__VCSEL_START - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pdata->phasecal_result__vcsel_start = buffer[i2c_buffer_offset_bytes]; + + + + pdev->dbg_results.phasecal_result__reference_phase = + pdata->phasecal_result__reference_phase; + pdev->dbg_results.phasecal_result__vcsel_start = + pdata->phasecal_result__vcsel_start; + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 = buffer[i2c_buffer_offset_bytes] << 2; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 += buffer[i2c_buffer_offset_bytes]; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + buffer[i2c_buffer_offset_bytes] = bin_23_0; + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_0_2 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + for (bin = 0; bin < VL53L1_HISTOGRAM_BUFFER_SIZE; bin++) { + pdata->bin_data[bin] = + (int32_t)VL53L1_i2c_decode_uint32_t(3, pbuffer); + pbuffer += 3; + } + + VL53L1_get_tuning_parm(Dev, VL53L1_TUNINGPARM_HIST_MERGE, + &hist_merge); + + if (pdata->result__stream_count == 0) { + + memset(pdev->multi_bins_rec, 0, sizeof(pdev->multi_bins_rec)); + pdev->bin_rec_pos = 0; + pdev->pos_before_next_recom = 0; + } + + if (hist_merge == 1) + vl53l1_histo_merge(Dev, pdata); + + + pdata->zone_id = pdev->ll_state.rd_zone_id; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = VL53L1_HISTOGRAM_BUFFER_SIZE; + + pdata->cal_config__vcsel_start = pgen_cfg->cal_config__vcsel_start; + + + + pdata->vcsel_width = + ((uint16_t)pgen_cfg->global_config__vcsel_width) << 4; + pdata->vcsel_width += + (uint16_t)pstat_cfg->ana_config__vcsel_pulse_width_offset; + + + pdata->VL53L1_p_019 = + pstat_nvm->osc_measured__fast_osc__frequency; + + + + VL53L1_hist_get_bin_sequence_config(Dev, pdata); + + + + if (pdev->ll_state.rd_timing_status == 0) { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_a_hi << 8) + + ptim_cfg->range_config__timeout_macrop_a_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_a; + } else { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_b_hi << 8) + + ptim_cfg->range_config__timeout_macrop_b_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_b; + } + + + + pdata->number_of_ambient_bins = 0; + + for (i = 0; i < 6; i++) { + if ((pdata->bin_seq[i] & 0x07) == 0x07) + pdata->number_of_ambient_bins = + pdata->number_of_ambient_bins + 0x04; + } + + pdata->total_periods_elapsed = + VL53L1_decode_timeout(encoded_timeout); + + + + + pll_period_us = + VL53L1_calc_pll_period_us(pdata->VL53L1_p_019); + + + + periods_elapsed_tmp = pdata->total_periods_elapsed + 1; + + + + pdata->peak_duration_us = + VL53L1_duration_maths( + pll_period_us, + (uint32_t)pdata->vcsel_width, + VL53L1_RANGING_WINDOW_VCSEL_PERIODS, + periods_elapsed_tmp); + + pdata->woi_duration_us = 0; + + + + VL53L1_hist_calc_zero_distance_phase(pdata); + + + + VL53L1_hist_estimate_ambient_from_ambient_bins(pdata); + + + + pdata->cfg_device_state = pdev->ll_state.cfg_device_state; + pdata->rd_device_state = pdev->ll_state.rd_device_state; + + + + pzone_dyn_cfg = &(pres->zone_dyn_cfgs.VL53L1_p_002[pdata->zone_id]); + + pdata->roi_config__user_roi_centre_spad = + pzone_dyn_cfg->roi_config__user_roi_centre_spad; + pdata->roi_config__user_roi_requested_global_xy_size = + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size; + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + switch (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + status = VL53L1_ERROR_RANGE_ERROR; + + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults) +{ + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + int32_t range_mm = 0; + uint32_t tmpu32 = 0; + uint16_t rpscr_crosstalk_corrected_mcps_sd0; + uint16_t rmmo_effective_spads_sd0; + uint16_t rmmi_effective_spads_sd0; + + LOG_FUNCTION_START(""); + + + + presults->zone_id = 0; + presults->stream_count = psys->result__stream_count; + presults->wrap_dmax_mm = 0; + presults->max_results = VL53L1_MAX_RANGE_RESULTS; + presults->active_results = 1; + rpscr_crosstalk_corrected_mcps_sd0 = + psys->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + rmmo_effective_spads_sd0 = + psys->result__mm_outer_actual_effective_spads_sd0; + rmmi_effective_spads_sd0 = + psys->result__mm_inner_actual_effective_spads_sd0; + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) + presults->VL53L1_p_007[i] = 0; + + pdata = &(presults->VL53L1_p_002[0]); + + for (i = 0; i < 2; i++) { + + pdata->range_id = i; + pdata->time_stamp = 0; + + if ((psys->result__stream_count == 0) && + ((psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + pdata->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK; + } else { + pdata->range_status = + psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + } + + pdata->VL53L1_p_015 = 0; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_025 = 0; + pdata->VL53L1_p_026 = 0; + pdata->VL53L1_p_016 = 0; + pdata->VL53L1_p_027 = 0; + + switch (i) { + + case 0: + if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM1) + pdata->VL53L1_p_006 = + rmmi_effective_spads_sd0; + else if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM2) + pdata->VL53L1_p_006 = + rmmo_effective_spads_sd0; + else + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd0; + + pdata->peak_signal_count_rate_mcps = + rpscr_crosstalk_corrected_mcps_sd0; + pdata->avg_signal_count_rate_mcps = + psys->result__avg_signal_count_rate_mcps_sd0; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd0; + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd0 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd0; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd0); + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd0; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd0; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd0; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd0; + + break; + case 1: + + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd1; + pdata->peak_signal_count_rate_mcps = + psys->result__peak_signal_count_rate_mcps_sd1; + pdata->avg_signal_count_rate_mcps = + 0xFFFF; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd1; + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd1 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd1; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd1); + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd1; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd1; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd1; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd1; + + break; + } + + + pdata->VL53L1_p_028 = pdata->VL53L1_p_014; + pdata->VL53L1_p_029 = pdata->VL53L1_p_014; + pdata->min_range_mm = pdata->median_range_mm; + pdata->max_range_mm = pdata->median_range_mm; + + pdata++; + } + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + switch (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + presults->VL53L1_p_002[0].range_status = + VL53L1_DEVICEERROR_NOUPDATE; + break; + + } + + LOG_FUNCTION_END(0); +} + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + LOG_FUNCTION_START(""); + + if (pstate->cfg_device_state == + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL) { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_EFFSPADS; + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pzone_dyn_cfg->dss_requested_effective_spad_count; + } else { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->debug_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ipp_hist_ambient_dmax( + Dev, + target_reflectance, + &(pdev->fmt_dmax_cal), + &(pdev->dmax_cfg), + &(pdev->hist_data), + pambient_dmax_mm); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + pintconf->intr_mode_distance = intr_mode_distance; + pintconf->intr_mode_rate = intr_mode_rate; + pintconf->intr_new_measure_ready = intr_new_measure_ready; + pintconf->intr_no_target = intr_no_target; + pintconf->intr_combined_mode = intr_combined_mode; + pintconf->threshold_distance_high = thresh_distance_high; + pintconf->threshold_distance_low = thresh_distance_low; + pintconf->threshold_rate_high = thresh_rate_high; + pintconf->threshold_rate_low = thresh_rate_low; + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + memcpy(pintconf, &(intconf), sizeof(VL53L1_GPIO_interrupt_config_t)); + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + pdev->gpio_interrupt_config = VL53L1_decode_GPIO_interrupt_config( + pdev->gen_cfg.system__interrupt_config_gpio); + + + pdev->gpio_interrupt_config.threshold_distance_high = + pdev->dyn_cfg.system__thresh_high; + pdev->gpio_interrupt_config.threshold_distance_low = + pdev->dyn_cfg.system__thresh_low; + + pdev->gpio_interrupt_config.threshold_rate_high = + pdev->gen_cfg.system__thresh_rate_high; + pdev->gpio_interrupt_config.threshold_rate_low = + pdev->gen_cfg.system__thresh_rate_low; + + if (pintconf == &(pdev->gpio_interrupt_config)) { + + } else { + + + memcpy(pintconf, &(pdev->gpio_interrupt_config), + sizeof(VL53L1_GPIO_interrupt_config_t)); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dmax_mode = dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pdmax_mode = pdev->dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + switch (dmax_mode) { + + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + pdmax_cal->ref__actual_effective_spads = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].effective_spads; + pdmax_cal->ref__peak_signal_count_rate_mcps = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].peak_rate_mcps; + pdmax_cal->ref__distance_mm = + pres->zone_cal.cal_distance_mm; + pdmax_cal->ref_reflectance_pc = + pres->zone_cal.cal_reflectance_pc; + pdmax_cal->coverglass_transmission = 0x0100; + break; + + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy( + &(pdev->dmax_cfg), + pdmax_cfg, + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy( + pdmax_cfg, + &(pdev->dmax_cfg), + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_calibration_mode = offset_cal_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cal_mode = pdev->offset_calibration_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode offset_cor_mode) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_correction_mode = offset_cor_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cor_mode = pdev->offset_correction_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pzone_cal->struct_version != + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION) + status = VL53L1_ERROR_INVALID_PARAMS; + + + if (status == VL53L1_ERROR_NONE) + + memcpy( + &(pres->zone_cal), + pzone_cal, + sizeof(VL53L1_zone_calibration_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy( + pzone_cal, + &(pres->zone_cal), + sizeof(VL53L1_zone_calibration_results_t)); + + pzone_cal->struct_version = + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + ptun_data->vl53l1_tuningparm_version = + pdev->tuning_parms.tp_tuning_parm_version; + + ptun_data->vl53l1_tuningparm_key_table_version = + pdev->tuning_parms.tp_tuning_parm_key_table_version; + + + ptun_data->vl53l1_tuningparm_lld_version = + pdev->tuning_parms.tp_tuning_parm_lld_version; + + ptun_data->vl53l1_tuningparm_hist_algo_select = + pHP->hist_algo_select; + + ptun_data->vl53l1_tuningparm_hist_target_order = + pHP->hist_target_order; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_0 = + pHP->filter_woi0; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_1 = + pHP->filter_woi1; + + ptun_data->vl53l1_tuningparm_hist_amb_est_method = + pHP->hist_amb_est_method; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_0 = + pHP->ambient_thresh_sigma0; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_1 = + pHP->ambient_thresh_sigma1; + + ptun_data->vl53l1_tuningparm_hist_min_amb_thresh_events = + pHP->min_ambient_thresh_events; + + ptun_data->vl53l1_tuningparm_hist_amb_events_scaler = + pHP->ambient_thresh_events_scaler; + + ptun_data->vl53l1_tuningparm_hist_noise_threshold = + pHP->noise_threshold; + + ptun_data->vl53l1_tuningparm_hist_signal_total_events_limit = + pHP->signal_total_events_limit; + + ptun_data->vl53l1_tuningparm_hist_sigma_est_ref_mm = + pHP->sigma_estimator__sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_hist_sigma_thresh_mm = + pHP->sigma_thresh; + + ptun_data->vl53l1_tuningparm_hist_gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_consistency_hist_phase_tolerance = + pHP->algo__consistency_check__phase_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm = + pHP->algo__consistency_check__min_max_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma = + pHP->algo__consistency_check__event_sigma; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit + = pHP->algo__consistency_check__event_min_spad_count; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_long_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_med_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_short_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_long_range = + pdev->tuning_parms.tp_init_phase_ref_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_med_range = + pdev->tuning_parms.tp_init_phase_ref_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_short_range = + pdev->tuning_parms.tp_init_phase_ref_hist_short; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_max_tolerance = + pHP->algo__crosstalk_detect_min_max_tolerance; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_detect_event_sigma = + pHP->algo__crosstalk_detect_event_sigma; + + ptun_data->vl53l1_tuningparm_hist_xtalk_margin_kcps = + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_consistency_lite_phase_tolerance = + pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + + ptun_data->vl53l1_tuningparm_phasecal_target = + pdev->tuning_parms.tp_phasecal_target; + + ptun_data->vl53l1_tuningparm_lite_cal_repeat_rate = + pdev->tuning_parms.tp_cal_repeat_rate; + + ptun_data->vl53l1_tuningparm_lite_ranging_gain_factor = + pdev->gain_cal.standard_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_lite_min_clip_mm = + pdev->tuning_parms.tp_lite_min_clip; + + ptun_data->vl53l1_tuningparm_lite_long_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_med_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_short_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_pulse_width = + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_amb_width_ns = + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_ref_mm = + pdev->tuning_parms.tp_lite_sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_lite_rit_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + ptun_data->vl53l1_tuningparm_lite_seed_config = + pdev->tuning_parms.tp_lite_seed_cfg; + + ptun_data->vl53l1_tuningparm_lite_quantifier = + pdev->tuning_parms.tp_lite_quantifier; + + ptun_data->vl53l1_tuningparm_lite_first_order_select = + pdev->tuning_parms.tp_lite_first_order_select; + + ptun_data->vl53l1_tuningparm_lite_xtalk_margin_kcps = + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_long_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_med_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_short_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_long_range = + pdev->tuning_parms.tp_init_phase_ref_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_med_range = + pdev->tuning_parms.tp_init_phase_ref_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_short_range = + pdev->tuning_parms.tp_init_phase_ref_lite_short; + + ptun_data->vl53l1_tuningparm_timed_seed_config = + pdev->tuning_parms.tp_timed_seed_cfg; + + ptun_data->vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma = + pdev->dmax_cfg.signal_thresh_sigma; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_0 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_1 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_2 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_3 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_4 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + + ptun_data->vl53l1_tuningparm_vhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + ptun_data->vl53l1_tuningparm_refspadchar_device_test_mode = + pdev->refspadchar.device_test_mode; + + ptun_data->vl53l1_tuningparm_refspadchar_vcsel_period = + pdev->refspadchar.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_refspadchar_phasecal_timeout_us = + pdev->refspadchar.timeout_us; + + ptun_data->vl53l1_tuningparm_refspadchar_target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_num_of_samples = + pXC->num_of_samples; + + ptun_data->vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm = + pXC->algo__crosstalk_extract_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm = + pXC->algo__crosstalk_extract_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_rate_mcps = + pXC->dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us = + pXC->phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps = + pXC->algo__crosstalk_extract_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm = + pXC->algo__crosstalk_extract_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_timeout_us = + pXC->mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_bin_timeout_us = + pXC->range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_dss_rate_mcps = + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_offset_cal_phasecal_timeout_us = + pdev->offsetcal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_mm_timeout_us = + pdev->offsetcal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_range_timeout_us = + pdev->offsetcal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_pre_samples = + pdev->offsetcal_cfg.pre_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm1_samples = + pdev->offsetcal_cfg.mm1_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm2_samples = + pdev->offsetcal_cfg.mm2_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_rate_mcps = + pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_timeout_us = + pdev->zonecal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_timeout_us = + pdev->zonecal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_num_samples = + pdev->zonecal_cfg.phasecal_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_range_timeout_us = + pdev->zonecal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_zone_num_samples = + pdev->zonecal_cfg.zone_num_of_samples; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_period = + pdev->ssc_cfg.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_start = + pdev->ssc_cfg.vcsel_start; + + ptun_data->vl53l1_tuningparm_spadmap_rate_limit_mcps = + pdev->ssc_cfg.rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + + ptun_data->vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + + ptun_data->vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + + ptun_data->vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + + ptun_data->vl53l1_tuningparm_lite_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + + ptun_data->vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + + ptun_data->vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + + ptun_data->vl53l1_tuningparm_mz_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + + ptun_data->vl53l1_tuningparm_mz_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + + ptun_data->vl53l1_tuningparm_mz_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + + ptun_data->vl53l1_tuningparm_timed_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_margin = + pdev->smudge_correct_config.smudge_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_noise_margin = + pdev->smudge_correct_config.noise_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit = + pdev->smudge_correct_config.user_xtalk_offset_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi = + pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + + ptun_data->vl53l1_tuningparm_dynxtalk_sample_limit = + pdev->smudge_correct_config.sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_single_xtalk_delta = + pdev->smudge_correct_config.single_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta = + pdev->smudge_correct_config.averaged_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_clip_limit = + pdev->smudge_correct_config.smudge_corr_clip_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_scaler_calc_method = + pdev->smudge_correct_config.scaler_calc_method; + + ptun_data->vl53l1_tuningparm_dynxtalk_xgradient_scaler = + pdev->smudge_correct_config.x_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_ygradient_scaler = + pdev->smudge_correct_config.y_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_user_scaler_set = + pdev->smudge_correct_config.user_scaler_set; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply = + pdev->smudge_correct_config.smudge_corr_single_apply; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold = + pdev->smudge_correct_config.smudge_corr_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps = + pdev->smudge_correct_config.nodetect_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_sample_limit = + pdev->smudge_correct_config.nodetect_sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps = + pdev->smudge_correct_config.nodetect_xtalk_offset; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm = + pdev->smudge_correct_config.nodetect_min_range_mm; + + ptun_data->vl53l1_tuningparm_lowpowerauto_vhv_loop_bound = + pdev->low_power_auto_data.vhv_loop_bound; + + ptun_data->vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_lowpowerauto_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_very_short_dss_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + + ptun_data->vl53l1_tuningparm_phasecal_patch_power = + pdev->tuning_parms.tp_phasecal_patch_power; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_version; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_key_table_version; + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_lld_version; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + *ptuning_parm_value = + (int32_t)pHP->hist_algo_select; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + *ptuning_parm_value = + (int32_t)pHP->hist_target_order; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + *ptuning_parm_value = + (int32_t)pHP->filter_woi0; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + *ptuning_parm_value = + (int32_t)pHP->filter_woi1; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + *ptuning_parm_value = + (int32_t)pHP->hist_amb_est_method; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma0; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma1; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + *ptuning_parm_value = + (int32_t)pHP->min_ambient_thresh_events; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_events_scaler; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + *ptuning_parm_value = + (int32_t)pHP->noise_threshold; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->signal_total_events_limit; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_estimator__sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_thresh; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.histogram_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__phase_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__min_max_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_sigma; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_min_spad_count; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_short; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_min_max_tolerance; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_event_sigma; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_target; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_cal_repeat_rate; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.standard_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_min_clip; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_seed_cfg; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_quantifier; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_first_order_select; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_short; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_timed_seed_cfg; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.signal_thresh_sigma; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + *ptuning_parm_value = + (int32_t)pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.device_test_mode; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.timeout_us; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.target_count_rate_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.min_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.max_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + *ptuning_parm_value = + (int32_t)pXC->num_of_samples; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_min_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pXC->dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_rate_kcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.pre_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm1_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm2_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.zone_num_of_samples; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.vcsel_start; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_lite_mcps; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mcps; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_timed_mcps; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.noise_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.single_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.averaged_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_clip_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.scaler_calc_method; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.x_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.y_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_scaler_set; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_single_apply; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + *ptuning_parm_value = (int32_t)( + pdev->smudge_correct_config.smudge_corr_ambient_threshold); + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_ambient_threshold; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_xtalk_offset; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_min_range_mm; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + *ptuning_parm_value = + (int32_t)pdev->low_power_auto_data.vhv_loop_bound; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_very_short_mcps; + break; + case VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_phasecal_patch_power; + break; + case VL53L1_TUNINGPARM_HIST_MERGE: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_hist_merge; + break; + case VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_reset_merge_threshold; + break; + case VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE: + *ptuning_parm_value = + (int32_t) pdev->tuning_parms.tp_hist_merge_max_size; + break; + case VL53L1_TUNINGPARM_DYNXTALK_MAX_SMUDGE_FACTOR: + *ptuning_parm_value = + pdev->smudge_correct_config.max_smudge_factor; + break; + + case VL53L1_TUNINGPARM_UWR_ENABLE: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_enable; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_1_min; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_1_max; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_2_min; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_2_max; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_3_min; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_3_max; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_4_min; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_4_max; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_5_min; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_5_max; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_6_min; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_z_6_max; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_1_rangea; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_1_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_2_rangea; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_2_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_3_rangea; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_3_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_4_rangea; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_4_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_5_rangea; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_5_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_6_rangea; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_med_corr_z_6_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_1_min; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_1_max; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_2_min; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_2_max; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_3_min; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_3_max; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_4_min; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_4_max; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MIN: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_5_min; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MAX: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_z_5_max; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_1_rangea; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_1_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_2_rangea; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_2_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_3_rangea; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_3_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_4_rangea; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_4_rangeb; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEA: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_5_rangea; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEB: + *ptuning_parm_value = + pdev->tuning_parms.tp_uwr_lng_corr_z_5_rangeb; + break; + + default: + *ptuning_parm_value = 0x7FFFFFFF; + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + pdev->tuning_parms.tp_tuning_parm_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + pdev->tuning_parms.tp_tuning_parm_key_table_version = + (uint16_t)tuning_parm_value; + + + + if ((uint16_t)tuning_parm_value + != VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT) + status = VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH; + + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + pdev->tuning_parms.tp_tuning_parm_lld_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + pHP->hist_algo_select = + (VL53L1_HistAlgoSelect)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + pHP->hist_target_order = + (VL53L1_HistTargetOrder)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + pHP->filter_woi0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + pHP->filter_woi1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + pHP->hist_amb_est_method = + (VL53L1_HistAmbEstMethod)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + pHP->ambient_thresh_sigma0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + pHP->ambient_thresh_sigma1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + pHP->min_ambient_thresh_events = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + pHP->ambient_thresh_events_scaler = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + pHP->noise_threshold = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + pHP->signal_total_events_limit = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + pHP->sigma_estimator__sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + pHP->sigma_thresh = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + pdev->gain_cal.histogram_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + pHP->algo__consistency_check__phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + pHP->algo__consistency_check__min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + pHP->algo__consistency_check__event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + pHP->algo__consistency_check__event_min_spad_count = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + pHP->algo__crosstalk_detect_min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + pHP->algo__crosstalk_detect_event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + pdev->tuning_parms.tp_consistency_lite_phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + pdev->tuning_parms.tp_phasecal_target = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + pdev->tuning_parms.tp_cal_repeat_rate = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + pdev->gain_cal.standard_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + pdev->tuning_parms.tp_lite_min_clip = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + pdev->tuning_parms.tp_lite_sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + pdev->tuning_parms.tp_lite_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + pdev->tuning_parms.tp_lite_quantifier = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + pdev->tuning_parms.tp_lite_first_order_select = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + pdev->tuning_parms.tp_timed_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + pdev->dmax_cfg.signal_thresh_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + pdev->refspadchar.device_test_mode = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + pdev->refspadchar.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + pdev->refspadchar.timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + pdev->refspadchar.target_count_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.min_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.max_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + pXC->num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + pXC->dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + pXC->phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + pXC->algo__crosstalk_extract_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + pXC->algo__crosstalk_extract_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + pXC->mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + pXC->range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + pdev->offsetcal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + pdev->offsetcal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + pdev->offsetcal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + pdev->offsetcal_cfg.pre_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + pdev->offsetcal_cfg.mm1_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + pdev->offsetcal_cfg.mm2_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + pdev->zonecal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + pdev->zonecal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + pdev->zonecal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + pdev->zonecal_cfg.phasecal_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + pdev->zonecal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + pdev->zonecal_cfg.zone_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + pdev->ssc_cfg.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + pdev->ssc_cfg.vcsel_start = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + pdev->ssc_cfg.rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_lite_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mz_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_timed_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + pdev->smudge_correct_config.smudge_margin = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + pdev->smudge_correct_config.noise_margin = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + pdev->smudge_correct_config.user_xtalk_offset_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + pdev->smudge_correct_config.sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + pdev->smudge_correct_config.single_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + pdev->smudge_correct_config.averaged_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + pdev->smudge_correct_config.smudge_corr_clip_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + pdev->smudge_correct_config.scaler_calc_method = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + pdev->smudge_correct_config.x_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + pdev->smudge_correct_config.y_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + pdev->smudge_correct_config.user_scaler_set = + (uint8_t)tuning_parm_value; + break; + + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + pdev->smudge_correct_config.smudge_corr_single_apply = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + pdev->smudge_correct_config.nodetect_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + pdev->smudge_correct_config.nodetect_sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + pdev->smudge_correct_config.nodetect_xtalk_offset = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + pdev->smudge_correct_config.nodetect_min_range_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + pdev->low_power_auto_data.vhv_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_very_short_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER: + pdev->tuning_parms.tp_phasecal_patch_power = + (uint16_t) tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MERGE: + pdev->tuning_parms.tp_hist_merge = + (uint16_t) tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD: + pdev->tuning_parms.tp_reset_merge_threshold = + (uint16_t) tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE: + pdev->tuning_parms.tp_hist_merge_max_size = + (uint16_t) tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_MAX_SMUDGE_FACTOR: + pdev->smudge_correct_config.max_smudge_factor = + (uint32_t)tuning_parm_value; + break; + + case VL53L1_TUNINGPARM_UWR_ENABLE: + pdev->tuning_parms.tp_uwr_enable = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MIN: + pdev->tuning_parms.tp_uwr_med_z_1_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MAX: + pdev->tuning_parms.tp_uwr_med_z_1_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MIN: + pdev->tuning_parms.tp_uwr_med_z_2_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MAX: + pdev->tuning_parms.tp_uwr_med_z_2_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MIN: + pdev->tuning_parms.tp_uwr_med_z_3_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MAX: + pdev->tuning_parms.tp_uwr_med_z_3_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MIN: + pdev->tuning_parms.tp_uwr_med_z_4_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MAX: + pdev->tuning_parms.tp_uwr_med_z_4_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MIN: + pdev->tuning_parms.tp_uwr_med_z_5_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MAX: + pdev->tuning_parms.tp_uwr_med_z_5_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MIN: + pdev->tuning_parms.tp_uwr_med_z_6_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MAX: + pdev->tuning_parms.tp_uwr_med_z_6_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEA: + pdev->tuning_parms.tp_uwr_med_corr_z_1_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEB: + pdev->tuning_parms.tp_uwr_med_corr_z_1_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEA: + pdev->tuning_parms.tp_uwr_med_corr_z_2_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEB: + pdev->tuning_parms.tp_uwr_med_corr_z_2_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEA: + pdev->tuning_parms.tp_uwr_med_corr_z_3_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEB: + pdev->tuning_parms.tp_uwr_med_corr_z_3_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEA: + pdev->tuning_parms.tp_uwr_med_corr_z_4_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEB: + pdev->tuning_parms.tp_uwr_med_corr_z_4_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEA: + pdev->tuning_parms.tp_uwr_med_corr_z_5_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEB: + pdev->tuning_parms.tp_uwr_med_corr_z_5_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEA: + pdev->tuning_parms.tp_uwr_med_corr_z_6_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEB: + pdev->tuning_parms.tp_uwr_med_corr_z_6_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MIN: + pdev->tuning_parms.tp_uwr_lng_z_1_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MAX: + pdev->tuning_parms.tp_uwr_lng_z_1_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MIN: + pdev->tuning_parms.tp_uwr_lng_z_2_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MAX: + pdev->tuning_parms.tp_uwr_lng_z_2_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MIN: + pdev->tuning_parms.tp_uwr_lng_z_3_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MAX: + pdev->tuning_parms.tp_uwr_lng_z_3_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MIN: + pdev->tuning_parms.tp_uwr_lng_z_4_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MAX: + pdev->tuning_parms.tp_uwr_lng_z_4_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MIN: + pdev->tuning_parms.tp_uwr_lng_z_5_min = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MAX: + pdev->tuning_parms.tp_uwr_lng_z_5_max = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEA: + pdev->tuning_parms.tp_uwr_lng_corr_z_1_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEB: + pdev->tuning_parms.tp_uwr_lng_corr_z_1_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEA: + pdev->tuning_parms.tp_uwr_lng_corr_z_2_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEB: + pdev->tuning_parms.tp_uwr_lng_corr_z_2_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEA: + pdev->tuning_parms.tp_uwr_lng_corr_z_3_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEB: + pdev->tuning_parms.tp_uwr_lng_corr_z_3_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEA: + pdev->tuning_parms.tp_uwr_lng_corr_z_4_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEB: + pdev->tuning_parms.tp_uwr_lng_corr_z_4_rangeb = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEA: + pdev->tuning_parms.tp_uwr_lng_corr_z_5_rangea = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEB: + pdev->tuning_parms.tp_uwr_lng_corr_z_5_rangeb = + (int16_t)tuning_parm_value; + break; + + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.x_gradient_scaler = x_scaler_in; + pdev->smudge_correct_config.y_gradient_scaler = y_scaler_in; + pdev->smudge_correct_config.user_scaler_set = user_scaler_set_in; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t i; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pxtalk->algo__crosstalk_compensation_plane_offset_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps; + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps; + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps; + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + pxtalk->algo__xtalk_cpo_HistoMerge_kcps[i] = + pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps[i]; + + LOG_FUNCTION_END(status); + + return status; + +} + + + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t i; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps = + pxtalk->algo__crosstalk_compensation_plane_offset_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps; + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps[i] = + pxtalk->algo__xtalk_cpo_HistoMerge_kcps[i]; + + LOG_FUNCTION_END(status); + + return status; + +} + + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_api_debug.c b/drivers/input/misc/vl53L1/src/vl53l1_api_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..c84618bb94e5d254fb83c967409000a2a1744ca0 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_api_debug.c @@ -0,0 +1,3399 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_api_debug.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_nvm_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (sizeof(VL53L1_calibration_data_t) > buf_size) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + memcpy(pdata, pbuffer, sizeof(VL53L1_calibration_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_read_nvm(Dev, 0, pdata); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_decoded_nvm_data( + pdata, + "get_nvm_debug_data():pnvm_info.", + VL53L1_TRACE_MODULE_NVM_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy( + pdata, + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + pdata->preset_mode = pdev->preset_mode; + pdata->zone_preset = pdev->zone_preset; + pdata->measurement_mode = pdev->measurement_mode; + pdata->offset_calibration_mode = pdev->offset_calibration_mode; + pdata->offset_correction_mode = pdev->offset_correction_mode; + pdata->dmax_mode = pdev->dmax_mode; + + pdata->phasecal_config_timeout_us = pdev->phasecal_config_timeout_us; + pdata->mm_config_timeout_us = pdev->mm_config_timeout_us; + pdata->range_config_timeout_us = pdev->range_config_timeout_us; + pdata->inter_measurement_period_ms = pdev->inter_measurement_period_ms; + pdata->dss_config__target_total_rate_mcps = + pdev->dss_config__target_total_rate_mcps; + + + + status = + VL53L1_get_histogram_debug_data( + Dev, + &(pdata->VL53L1_p_010)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->xtalk_cfg), + &(pdev->xtalk_cfg), + sizeof(VL53L1_xtalk_config_t)); + + memcpy( + &(pdata->hist_data), + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + memcpy( + &(pdata->xtalk_shapes), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + memcpy( + &(pdata->xtalk_results), + &(pdev->xtalk_results), + sizeof(VL53L1_xtalk_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + memcpy( + &(pdata->offset_results), + &(pdev->offset_results), + sizeof(VL53L1_offset_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_signed_fixed_point_sprintf( + int32_t signed_fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer) +{ + + + uint32_t fp_value = 0; + uint32_t unity_fp_value = 0; + uint32_t sign_bit = 0; + uint32_t int_part = 0; + uint32_t frac_part = 0; + uint32_t dec_points = 0; + uint32_t dec_scaler = 0; + uint32_t dec_part = 0; + + uint64_t tmp_long_int = 0; + + char fmt[VL53L1_MAX_STRING_LENGTH]; + + SUPPRESS_UNUSED_WARNING(buf_size); + + + + sign_bit = signed_fp_value >> 31; + + if (sign_bit > 0) { + fp_value = 0x80000000 - + (0x7FFFFFFF & (uint32_t)signed_fp_value); + } else + fp_value = (uint32_t)signed_fp_value; + + int_part = fp_value >> frac_bits; + unity_fp_value = 0x01 << frac_bits; + frac_part = fp_value & (unity_fp_value-1); + + + dec_points = 2; + dec_scaler = 100; + + while (dec_scaler < unity_fp_value) { + dec_points++; + dec_scaler *= 10; + } + + + if (sign_bit > 0) + sprintf(fmt, "-%%u.%%0%uu", dec_points); + else + sprintf(fmt, "%%u.%%0%uu", dec_points); + + + tmp_long_int = (uint64_t)frac_part * (uint64_t)dec_scaler; + tmp_long_int += (uint64_t)unity_fp_value/2; + + tmp_long_int = do_division_u(tmp_long_int, (uint64_t)unity_fp_value); + + dec_part = (uint32_t)tmp_long_int; + + + sprintf( + pbuffer, + fmt, + int_part, + dec_part); +} + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "i2c_slave__device_address", + pdata->i2c_slave__device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vddpix", + pdata->ana_config__vhv_ref_sel_vddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vquench", + pdata->ana_config__vhv_ref_sel_vquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__reg_avdd1v2_sel", + pdata->ana_config__reg_avdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim", + pdata->ana_config__fast_osc__trim); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->osc_measured__fast_osc__frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "osc_measured__fast_osc__frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__timeout_macrop_loop_bound", + pdata->vhv_config__timeout_macrop_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__count_thresh", + pdata->vhv_config__count_thresh); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__offset", + pdata->vhv_config__offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__init", + pdata->vhv_config__init); +} + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_0", + pdata->global_config__spad_enables_ref_0); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_1", + pdata->global_config__spad_enables_ref_1); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_2", + pdata->global_config__spad_enables_ref_2); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_3", + pdata->global_config__spad_enables_ref_3); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_4", + pdata->global_config__spad_enables_ref_4); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_5", + pdata->global_config__spad_enables_ref_5); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__ref_en_start_select", + pdata->global_config__ref_en_start_select); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__num_requested_ref_spads", + pdata->ref_spad_man__num_requested_ref_spads); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__ref_location", + pdata->ref_spad_man__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_spad_char__total_rate_target_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_spad_char__total_rate_target_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__part_to_part_range_offset_mm", + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__inner_offset_mm", + pdata->mm_config__inner_offset_mm); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__outer_offset_mm", + pdata->mm_config__outer_offset_mm); +} + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__model_id", + pdata->identification__model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_type", + pdata->identification__module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__revision_id", + pdata->identification__revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_id", + pdata->identification__module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim_max", + pdata->ana_config__fast_osc__trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__freq_set", + pdata->ana_config__fast_osc__freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_trim", + pdata->ana_config__vcsel_trim); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion", + pdata->ana_config__vcsel_selion); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion_max", + pdata->ana_config__vcsel_selion_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "protected_laser_safety__lock_bit", + pdata->protected_laser_safety__lock_bit); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key", + pdata->laser_safety__key); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key_ro", + pdata->laser_safety__key_ro); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__clip", + pdata->laser_safety__clip); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__mult", + pdata->laser_safety__mult); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_0", + pdata->global_config__spad_enables_rtn_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_1", + pdata->global_config__spad_enables_rtn_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_2", + pdata->global_config__spad_enables_rtn_2); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_3", + pdata->global_config__spad_enables_rtn_3); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_4", + pdata->global_config__spad_enables_rtn_4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_5", + pdata->global_config__spad_enables_rtn_5); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_6", + pdata->global_config__spad_enables_rtn_6); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_7", + pdata->global_config__spad_enables_rtn_7); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_8", + pdata->global_config__spad_enables_rtn_8); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_9", + pdata->global_config__spad_enables_rtn_9); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_10", + pdata->global_config__spad_enables_rtn_10); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_11", + pdata->global_config__spad_enables_rtn_11); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_12", + pdata->global_config__spad_enables_rtn_12); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_13", + pdata->global_config__spad_enables_rtn_13); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_14", + pdata->global_config__spad_enables_rtn_14); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_15", + pdata->global_config__spad_enables_rtn_15); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_16", + pdata->global_config__spad_enables_rtn_16); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_17", + pdata->global_config__spad_enables_rtn_17); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_18", + pdata->global_config__spad_enables_rtn_18); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_19", + pdata->global_config__spad_enables_rtn_19); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_20", + pdata->global_config__spad_enables_rtn_20); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_21", + pdata->global_config__spad_enables_rtn_21); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_22", + pdata->global_config__spad_enables_rtn_22); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_23", + pdata->global_config__spad_enables_rtn_23); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_24", + pdata->global_config__spad_enables_rtn_24); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_25", + pdata->global_config__spad_enables_rtn_25); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_26", + pdata->global_config__spad_enables_rtn_26); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_27", + pdata->global_config__spad_enables_rtn_27); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_28", + pdata->global_config__spad_enables_rtn_28); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_29", + pdata->global_config__spad_enables_rtn_29); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_30", + pdata->global_config__spad_enables_rtn_30); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_31", + pdata->global_config__spad_enables_rtn_31); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "roi_config__mode_roi_centre_spad", + pdata->roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__mode_roi_xy_size", + pdata->roi_config__mode_roi_xy_size); +} + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_bins", + pdata->number_of_ambient_bins); + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_seq[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_seq[i]); + } + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_rep[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_rep[i]); + } + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %d\n", + ppre_text, + pdata->bin_data[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__interrupt_status", + pdata->result__interrupt_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__range_status", + pdata->result__range_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__report_status", + pdata->result__report_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__stream_count", + pdata->result__stream_count); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__dss_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__dss_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_009", + pdata->VL53L1_p_009); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "min_bin_value", + pdata->min_bin_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_bin_value", + pdata->max_bin_value); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_samples", + pdata->number_of_ambient_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "ambient_events_sum", + pdata->ambient_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_004", + pdata->VL53L1_p_004); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_centre_spad", + pdata->roi_config__user_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_requested_global_xy_size", + pdata->roi_config__user_roi_requested_global_xy_size); +} + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->bin_data[i], + 10, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + } + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); +} + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + + sprintf(ppre_text, "%sxtalk_shape.", pprefix); + VL53L1_print_xtalk_histogram_shape_data( + &(pdata->xtalk_shape), + ppre_text, trace_flags); + + + sprintf(ppre_text, "%sxtalk_hist_removed.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->xtalk_hist_removed), + ppre_text, trace_flags); +} + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_id", + pdata->range_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "time_stamp", + pdata->time_stamp); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->VL53L1_p_015); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_025", + pdata->VL53L1_p_025); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_026", + pdata->VL53L1_p_026); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->VL53L1_p_016); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_027", + pdata->VL53L1_p_027); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->width, + 4, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_030", + pdata->VL53L1_p_030); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->fast_osc_frequency, + 12, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "fast_osc_frequency", + fp_text); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_006, + 8, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "actual_effective_spad", + fp_text); + + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_020", + pdata->VL53L1_p_020); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_021", + pdata->VL53L1_p_021); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_013", + pdata->VL53L1_p_013); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->avg_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "avg_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ambient_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ambient_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->total_rate_per_spad_mcps, + 13, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "total_rate_per_spad_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_012, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_012", + fp_text); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_028, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_028", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_029, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_029", + fp_text); + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "min_range_mm", + pdata->min_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "max_range_mm", + pdata->max_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_status", + pdata->range_status); +} + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_id", + pdata->zone_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "stream_count", + pdata->stream_count); + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + sprintf( + ppre_text, + "%sambient_dmax_mm[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->VL53L1_p_007[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "device_status", + pdata->device_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "wrap_dmax_mm", + pdata->wrap_dmax_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_range_data( + &pdata->VL53L1_p_002[i], + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%sxmonitor.", pprefix); + VL53L1_print_range_data( + &pdata->xmonitor, + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_report", + pdata->cal_report); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_offset_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dss_config__roi_mode_control", + pdata->dss_config__roi_mode_control); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__manual_effective_spads_select, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__manual_effective_spads_select", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "range_mm_offset", + pdata->range_mm_offset); +} + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + uint8_t x = 0; + uint8_t y = 0; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_distance_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_samples", + pdata->max_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); + + i = 0; + for (y = 0; y < pdata->height; y++) { + for (x = 0; x < pdata->width; x++) { + + sprintf(ppre_text, "%speak_rate_mcps[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps[i], + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + + i++; + } + } +} + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "measurement_mode", + pdata->measurement_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_calibration_mode", + pdata->offset_calibration_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_correction_mode", + pdata->offset_correction_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dmax_mode", + pdata->dmax_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "inter_measurement_period_ms", + pdata->inter_measurement_period_ms); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + sprintf(ppre_text, "%s VL53L1_p_010.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->VL53L1_p_010, + ppre_text, trace_flags); + + +} + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_peak_signal_count_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_peak_signal_count_rtn_mcps", + fp_text); +} + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->standard_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "standard_ranging_gain_factor", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_ranging_gain_factor", + fp_text); +} + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->median_range_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "median_range_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->range_mm_offset, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "range_mm_offset", + fp_text); +} + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_zone_calibration_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + uint8_t i = 0; + + VL53L1_histogram_bin_data_t *pbin_data; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples_status", + pdata->num_of_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zero_samples_status", + pdata->zero_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_sigma_status", + pdata->max_sigma_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_xtalk_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%scentral_histogram_sum.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_sum, + ppre_text, trace_flags); + + sprintf(ppre_text, "%scentral_histogram_avg.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_avg, + ppre_text, trace_flags); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->central_histogram__window_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->central_histogram__window_end); + + pbin_data = &(pdata->histogram_avg_1[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_1[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->histogram_avg_2[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_2[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->xtalk_avg[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%sxtalk_avg[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } +} + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_sum", + pdata->signal_total_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_avg", + pdata->signal_total_events_avg); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_sum, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_sum", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_avg, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_avg", + fp_text); +} + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); +} + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_crosstalk_compensation_enable", + pdata->global_crosstalk_compensation_enable); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->lite_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "lite_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_mult, + 5, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_mult", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_rate_mcps, + 13, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_max_valid_range_mm", + pdata->algo__crosstalk_detect_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_min_valid_range_mm", + pdata->algo__crosstalk_detect_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_valid_rate_kcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples", + pdata->num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_max_valid_range_mm", + pdata->algo__crosstalk_extract_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_min_valid_range_mm", + pdata->algo__crosstalk_extract_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_valid_rate_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_num_of_samples", + pdata->phasecal_num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_num_of_samples", + pdata->zone_num_of_samples); + +} + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "pre_num_of_samples", + pdata->pre_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm1_num_of_samples", + pdata->mm1_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm2_num_of_samples", + pdata->mm2_num_of_samples); + + +} + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__peak_signal_count_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->coverglass_transmission, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "coverglass_transmission", + fp_text); +} + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%08X\n", + pprefix, + "struct_version", + pdata->struct_version); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soptical_centre.", pprefix); + VL53L1_print_optical_centre( + &(pdata->optical_centre), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalkhisto.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalkhisto), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_gain_calibration_data( + &(pdata->gain_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scal_peak_rate_map.", pprefix); + VL53L1_print_cal_peak_rate_map( + &(pdata->cal_peak_rate_map), + ppre_text, trace_flags); +} + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_cfg.", pprefix); + VL53L1_print_xtalk_config( + &(pdata->xtalk_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_extract_cfg.", pprefix); + VL53L1_print_xtalk_extract_config( + &(pdata->xtalk_extract_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%shist_data.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->hist_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_shapes.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalk_shapes), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_xtalk_range_results( + &(pdata->xtalk_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soffset_results.", pprefix); + VL53L1_print_offset_range_results( + &(pdata->offset_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%suser_zones[%u].", pprefix, i); + VL53L1_print_user_zone( + &pdata->user_zones[i], + ppre_text, + trace_flags); + } +} + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->x_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "x_centre", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->y_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "y_centre", + fp_text); +} + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "x_centre", + pdata->x_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "y_centre", + pdata->y_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); +} + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + uint16_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8s,%4s,%4s, %s\n", + pprefix, + "spad_no", + "row", + "col", + "peak_rate_mcps"); + + for (spad_no = 0; spad_no < pspad_rates->no_of_values; spad_no++) { + + + VL53L1_decode_row_col( + (uint8_t)spad_no, + &row, + &col); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8u,%4u,%4u, %s\n", + pprefix, + spad_no, + row, + col, + fp_text); + } +} + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + uint8_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4s", + pprefix, + " "); + + for (col = 0; col < VL53L1_SPAD_ARRAY_WIDTH; col++) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8u", + col); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + + + for (row = 0; row < VL53L1_SPAD_ARRAY_HEIGHT; row++) { + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4u", + pprefix, + row); + + for (col = 0; col < VL53L1_SPAD_ARRAY_HEIGHT; col++) { + + + + VL53L1_encode_row_col( + row, + col, + &spad_no); + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8s", + fp_text); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + } +} + + +#endif + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_api_preset_modes.c b/drivers/input/misc/vl53L1/src/vl53l1_api_preset_modes.c new file mode 100644 index 0000000000000000000000000000000000000000..d31efb4123b508ca9fb9b9ca4b19e3845daba157 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_api_preset_modes.c @@ -0,0 +1,3680 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_core.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_tuning_parm_defaults.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->device_test_mode = + VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT; + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT; + pdata->timeout_us = + VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT; + pdata->target_count_rate_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT; + pdata->min_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT; + pdata->max_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->array_select = VL53L1_DEVICESSCARRAY_RTN; + + + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT; + + + pdata->vcsel_start = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT; + + + pdata->vcsel_width = 0x02; + + + pdata->timeout_us = 36000; + + + pdata->rate_limit_mcps = + VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + pdata->algo__crosstalk_compensation_plane_offset_kcps = + pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + pdata->nvm_default__crosstalk_compensation_plane_offset_kcps = + (uint32_t)pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->nvm_default__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->nvm_default__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdata->histogram_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT; + pdata->lite_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT; + + + + pdata->crosstalk_range_ignore_threshold_mult = + VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT; + + if ((pdata->algo__crosstalk_compensation_plane_offset_kcps == 0x00) + && (pdata->algo__crosstalk_compensation_x_plane_gradient_kcps + == 0x00) + && (pdata->algo__crosstalk_compensation_y_plane_gradient_kcps + == 0x00)) + pdata->global_crosstalk_compensation_enable = 0x00; + else + pdata->global_crosstalk_compensation_enable = 0x01; + + + if ((status == VL53L1_ERROR_NONE) && + (pdata->global_crosstalk_compensation_enable == 0x01)) { + pdata->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + pdata->crosstalk_range_ignore_threshold_mult); + } else { + pdata->crosstalk_range_ignore_threshold_rate_mcps = 0; + } + + + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT; + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT; + + pdata->num_of_samples = + VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT; + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT; + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT; + + + + + pdata->algo__crosstalk_extract_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_extract_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT; + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT; + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT; + + + + + pdata->pre_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT; + pdata->mm1_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT; + pdata->mm2_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT; + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT; + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT; + + + + + pdata->phasecal_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT; + pdata->zone_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->hist_algo_select = + VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT; + + + + pdata->hist_target_order = + VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT; + + + + pdata->filter_woi0 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT; + pdata->filter_woi1 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT; + + + pdata->hist_amb_est_method = + VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT; + + pdata->ambient_thresh_sigma0 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT; + pdata->ambient_thresh_sigma1 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT; + + + pdata->ambient_thresh_events_scaler = + VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT; + + + pdata->min_ambient_thresh_events = + VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT; + + pdata->noise_threshold = + VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT; + + pdata->signal_total_events_limit = + VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT; + pdata->sigma_estimator__sigma_ref_mm = + VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT; + + + pdata->sigma_thresh = + VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT; + + pdata->range_offset_mm = 0; + + pdata->gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + + pdata->valid_phase_low = 0x08; + pdata->valid_phase_high = 0x88; + + + + pdata->algo__consistency_check__phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT; + + + + pdata->algo__consistency_check__event_sigma = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT; + + + pdata->algo__consistency_check__event_min_spad_count = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT; + + + + pdata->algo__consistency_check__min_max_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT; + + + pdata->algo__crosstalk_compensation_enable = xtalk_compensation_enable; + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + + + + + pdata->algo__crosstalk_detect_event_sigma = + VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT; + + + + pdata->algo__crosstalk_detect_min_max_tolerance = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT; + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->ref__actual_effective_spads = 0x5F2D; + + pdata->ref__peak_signal_count_rate_mcps = 0x0844; + + pdata->ref__distance_mm = 0x08A5; + + + pdata->ref_reflectance_pc = 0x0014; + + + pdata->coverglass_transmission = 0x0100; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->tp_tuning_parm_version = + VL53L1_TUNINGPARM_VERSION_DEFAULT; + pdata->tp_tuning_parm_key_table_version = + VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT; + pdata->tp_tuning_parm_lld_version = + VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT; + pdata->tp_init_phase_rtn_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_consistency_lite_phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT; + pdata->tp_phasecal_target = + VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT; + pdata->tp_cal_repeat_rate = + VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT; + pdata->tp_lite_min_clip = + VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT; + pdata->tp_lite_long_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_med_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_short_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_long_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_med_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_short_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_sigma_est_pulse_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT; + pdata->tp_lite_sigma_est_amb_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT; + pdata->tp_lite_sigma_ref_mm = + VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT; + pdata->tp_lite_seed_cfg = + VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT; + pdata->tp_timed_seed_cfg = + VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT; + pdata->tp_lite_quantifier = + VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT; + pdata->tp_lite_first_order_select = + VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT; + + + + + pdata->tp_dss_target_lite_mcps = + VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mcps = + VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mz_mcps = + VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_timed_mcps = + VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_phasecal_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_long_us = + VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_med_us = + VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_short_us = + VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_long_us = + VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_med_us = + VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_short_us = + VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + + + pdata->tp_mm_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + pdata->tp_dss_target_very_short_mcps = + VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT; + + pdata->tp_phasecal_patch_power = + VL53L1_TUNINGPARM_PHASECAL_PATCH_POWER_DEFAULT; + + pdata->tp_hist_merge = + VL53L1_TUNINGPARM_HIST_MERGE_DEFAULT; + + pdata->tp_reset_merge_threshold = + VL53L1_TUNINGPARM_RESET_MERGE_THRESHOLD_DEFAULT; + + pdata->tp_hist_merge_max_size = + VL53L1_TUNINGPARM_HIST_MERGE_MAX_SIZE_DEFAULT; + + pdata->tp_uwr_enable = + VL53L1_TUNINGPARM_UWR_ENABLE_DEFAULT; + pdata->tp_uwr_med_z_1_min = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MIN_DEFAULT; + pdata->tp_uwr_med_z_1_max = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_1_MAX_DEFAULT; + pdata->tp_uwr_med_z_2_min = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MIN_DEFAULT; + pdata->tp_uwr_med_z_2_max = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_2_MAX_DEFAULT; + pdata->tp_uwr_med_z_3_min = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MIN_DEFAULT; + pdata->tp_uwr_med_z_3_max = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_3_MAX_DEFAULT; + pdata->tp_uwr_med_z_4_min = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MIN_DEFAULT; + pdata->tp_uwr_med_z_4_max = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_4_MAX_DEFAULT; + pdata->tp_uwr_med_z_5_min = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MIN_DEFAULT; + pdata->tp_uwr_med_z_5_max = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_5_MAX_DEFAULT; + pdata->tp_uwr_med_z_6_min = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MIN_DEFAULT; + pdata->tp_uwr_med_z_6_max = + VL53L1_TUNINGPARM_UWR_MEDIUM_ZONE_6_MAX_DEFAULT; + pdata->tp_uwr_med_corr_z_1_rangea = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEA_DEFAULT; + pdata->tp_uwr_med_corr_z_1_rangeb = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_1_RANGEB_DEFAULT; + pdata->tp_uwr_med_corr_z_2_rangea = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEA_DEFAULT; + pdata->tp_uwr_med_corr_z_2_rangeb = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_2_RANGEB_DEFAULT; + pdata->tp_uwr_med_corr_z_3_rangea = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEA_DEFAULT; + pdata->tp_uwr_med_corr_z_3_rangeb = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_3_RANGEB_DEFAULT; + pdata->tp_uwr_med_corr_z_4_rangea = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEA_DEFAULT; + pdata->tp_uwr_med_corr_z_4_rangeb = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_4_RANGEB_DEFAULT; + pdata->tp_uwr_med_corr_z_5_rangea = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEA_DEFAULT; + pdata->tp_uwr_med_corr_z_5_rangeb = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_5_RANGEB_DEFAULT; + pdata->tp_uwr_med_corr_z_6_rangea = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEA_DEFAULT; + pdata->tp_uwr_med_corr_z_6_rangeb = + VL53L1_TUNINGPARM_UWR_MEDIUM_CORRECTION_ZONE_6_RANGEB_DEFAULT; + pdata->tp_uwr_lng_z_1_min = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MIN_DEFAULT; + pdata->tp_uwr_lng_z_1_max = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_1_MAX_DEFAULT; + pdata->tp_uwr_lng_z_2_min = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MIN_DEFAULT; + pdata->tp_uwr_lng_z_2_max = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_2_MAX_DEFAULT; + pdata->tp_uwr_lng_z_3_min = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MIN_DEFAULT; + pdata->tp_uwr_lng_z_3_max = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_3_MAX_DEFAULT; + pdata->tp_uwr_lng_z_4_min = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MIN_DEFAULT; + pdata->tp_uwr_lng_z_4_max = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_4_MAX_DEFAULT; + pdata->tp_uwr_lng_z_5_min = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MIN_DEFAULT; + pdata->tp_uwr_lng_z_5_max = + VL53L1_TUNINGPARM_UWR_LONG_ZONE_5_MAX_DEFAULT; + pdata->tp_uwr_lng_corr_z_1_rangea = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEA_DEFAULT; + pdata->tp_uwr_lng_corr_z_1_rangeb = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_1_RANGEB_DEFAULT; + pdata->tp_uwr_lng_corr_z_2_rangea = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEA_DEFAULT; + pdata->tp_uwr_lng_corr_z_2_rangeb = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_2_RANGEB_DEFAULT; + pdata->tp_uwr_lng_corr_z_3_rangea = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEA_DEFAULT; + pdata->tp_uwr_lng_corr_z_3_rangeb = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_3_RANGEB_DEFAULT; + pdata->tp_uwr_lng_corr_z_4_rangea = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEA_DEFAULT; + pdata->tp_uwr_lng_corr_z_4_rangeb = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_4_RANGEB_DEFAULT; + pdata->tp_uwr_lng_corr_z_5_rangea = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEA_DEFAULT; + pdata->tp_uwr_lng_corr_z_5_rangeb = + VL53L1_TUNINGPARM_UWR_LONG_CORRECTION_ZONE_5_RANGEB_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + pdata->dss_config__target_total_rate_mcps = 0x1400; + pdata->dss_config__aperture_attenuation = 0x38; + + pdata->signal_thresh_sigma = + VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT; + pdata->ambient_thresh_sigma = 0x70; + pdata->min_ambient_thresh_events = 16; + pdata->signal_total_events_limit = 100; + pdata->max_effective_spads = 0xFFFF; + + + + pdata->target_reflectance_for_dmax_calc[0] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT; + pdata->target_reflectance_for_dmax_calc[1] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT; + pdata->target_reflectance_for_dmax_calc[2] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT; + pdata->target_reflectance_for_dmax_calc[3] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT; + pdata->target_reflectance_for_dmax_calc[4] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pstatic->dss_config__target_total_rate_mcps = 0x0A00; + pstatic->debug__ctrl = 0x00; + pstatic->test_mode__ctrl = 0x00; + pstatic->clk_gating__ctrl = 0x00; + pstatic->nvm_bist__ctrl = 0x00; + pstatic->nvm_bist__num_nvm_words = 0x00; + pstatic->nvm_bist__start_address = 0x00; + pstatic->host_if__status = 0x00; + pstatic->pad_i2c_hv__config = 0x00; + pstatic->pad_i2c_hv__extsup_config = 0x00; + + + pstatic->gpio_hv_pad__ctrl = 0x00; + + + pstatic->gpio_hv_mux__ctrl = + VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW | + VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS; + + pstatic->gpio__tio_hv_status = 0x02; + pstatic->gpio__fio_hv_status = 0x00; + pstatic->ana_config__spad_sel_pswidth = 0x02; + pstatic->ana_config__vcsel_pulse_width_offset = 0x08; + pstatic->ana_config__fast_osc__config_ctrl = 0x00; + + pstatic->sigma_estimator__effective_pulse_width_ns = + ptuning_parms->tp_lite_sigma_est_pulse_width_ns; + pstatic->sigma_estimator__effective_ambient_width_ns = + ptuning_parms->tp_lite_sigma_est_amb_width_ns; + pstatic->sigma_estimator__sigma_ref_mm = + ptuning_parms->tp_lite_sigma_ref_mm; + + pstatic->algo__crosstalk_compensation_valid_height_mm = 0x01; + pstatic->spare_host_config__static_config_spare_0 = 0x00; + pstatic->spare_host_config__static_config_spare_1 = 0x00; + + pstatic->algo__range_ignore_threshold_mcps = 0x0000; + + + pstatic->algo__range_ignore_valid_height_mm = 0xff; + pstatic->algo__range_min_clip = + ptuning_parms->tp_lite_min_clip; + + pstatic->algo__consistency_check__tolerance = + ptuning_parms->tp_consistency_lite_phase_tolerance; + pstatic->spare_host_config__static_config_spare_2 = 0x00; + pstatic->sd_config__reset_stages_msb = 0x00; + pstatic->sd_config__reset_stages_lsb = 0x00; + + pgeneral->gph_config__stream_count_update_value = 0x00; + pgeneral->global_config__stream_divider = 0x00; + pgeneral->system__interrupt_config_gpio = + VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY; + pgeneral->cal_config__vcsel_start = 0x0B; + + + pgeneral->cal_config__repeat_rate = + ptuning_parms->tp_cal_repeat_rate; + pgeneral->global_config__vcsel_width = 0x02; + + pgeneral->phasecal_config__timeout_macrop = 0x0D; + + pgeneral->phasecal_config__target = + ptuning_parms->tp_phasecal_target; + pgeneral->phasecal_config__override = 0x00; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__TARGET_RATE; + + pgeneral->system__thresh_rate_high = 0x0000; + pgeneral->system__thresh_rate_low = 0x0000; + + pgeneral->dss_config__manual_effective_spads_select = 0x8C00; + pgeneral->dss_config__manual_block_select = 0x00; + + + pgeneral->dss_config__aperture_attenuation = 0x38; + pgeneral->dss_config__max_spads_limit = 0xFF; + pgeneral->dss_config__min_spads_limit = 0x01; + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x1a; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x20; + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0xCC; + + ptiming->range_config__vcsel_period_a = 0x0B; + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xF5; + + ptiming->range_config__vcsel_period_b = 0x09; + + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_med_sigma_thresh_mm; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_med_min_count_rate_rtn_mcps; + + + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x78; + ptiming->system__intermeasurement_period = 0x00000000; + ptiming->system__fractional_enable = 0x00; + + + + phistogram->histogram_config__low_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__low_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__low_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__low_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__low_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__low_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__mid_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__mid_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__mid_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__mid_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__mid_amb_odd_bin_2 = 0x02; + phistogram->histogram_config__mid_amb_odd_bin_3_4 = 0x43; + phistogram->histogram_config__mid_amb_odd_bin_5 = 0x05; + + phistogram->histogram_config__user_bin_offset = 0x00; + + phistogram->histogram_config__high_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__high_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__high_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__high_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__high_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__high_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__amb_thresh_low = 0xFFFF; + phistogram->histogram_config__amb_thresh_high = 0xFFFF; + + phistogram->histogram_config__spad_array_selection = 0x00; + + + pzone_cfg->max_zones = VL53L1_MAX_USER_ZONES; + pzone_cfg->active_zones = 0x00; + pzone_cfg->user_zones[0].height = 0x0f; + pzone_cfg->user_zones[0].width = 0x0f; + pzone_cfg->user_zones[0].x_centre = 0x08; + pzone_cfg->user_zones[0].y_centre = 0x08; + + + + pdynamic->system__grouped_parameter_hold_0 = 0x01; + + pdynamic->system__thresh_high = 0x0000; + pdynamic->system__thresh_low = 0x0000; + pdynamic->system__enable_xtalk_per_quadrant = 0x00; + pdynamic->system__seed_config = + ptuning_parms->tp_lite_seed_cfg; + + + pdynamic->sd_config__woi_sd0 = 0x0B; + + pdynamic->sd_config__woi_sd1 = 0x09; + + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_med; + + pdynamic->system__grouped_parameter_hold_1 = 0x01; + + + + pdynamic->sd_config__first_order_select = + ptuning_parms->tp_lite_first_order_select; + pdynamic->sd_config__quantifier = + ptuning_parms->tp_lite_quantifier; + + + pdynamic->roi_config__user_roi_centre_spad = 0xC7; + + pdynamic->roi_config__user_roi_requested_global_xy_size = 0xFF; + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + pdynamic->system__grouped_parameter_hold = 0x02; + + + + + psystem->system__stream_count_ctrl = 0x00; + psystem->firmware__enable = 0x01; + psystem->system__interrupt_clear = + VL53L1_CLEAR_RANGE_INT; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_STREAMING | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + ptiming->range_config__vcsel_period_a = 0x07; + ptiming->range_config__vcsel_period_b = 0x05; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_short_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_short_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x38; + + + + pdynamic->sd_config__woi_sd0 = 0x07; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_short; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + ptiming->range_config__vcsel_period_a = 0x0F; + ptiming->range_config__vcsel_period_b = 0x0D; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_long_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_long_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0xB8; + + + + pdynamic->sd_config__woi_sd0 = 0x0F; + pdynamic->sd_config__woi_sd1 = 0x0D; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_long; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0x84; + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x97; + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0B; + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x20; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1A; + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x28; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x21; + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + VL53L1_init_histogram_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + if (status == VL53L1_ERROR_NONE) { + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + ptiming->range_config__vcsel_period_a = 0x04; + ptiming->range_config__vcsel_period_b = 0x03; + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x42; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x42; + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x52; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x66; + + pgeneral->cal_config__vcsel_start = 0x04; + + + + pgeneral->phasecal_config__timeout_macrop = 0xa4; + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0b; + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1b; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x22; + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_long; + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + ptiming->range_config__vcsel_period_a = 0x05; + ptiming->range_config__vcsel_period_b = 0x07; + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x36; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x28; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x44; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x33; + + + + pgeneral->cal_config__vcsel_start = 0x05; + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + pdynamic->sd_config__woi_sd0 = 0x05; + pdynamic->sd_config__woi_sd1 = 0x07; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_med; + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x48; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + ptiming->range_config__vcsel_period_a = 0x03; + ptiming->range_config__vcsel_period_b = 0x05; + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x52; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x37; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x66; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x44; + + + + pgeneral->cal_config__vcsel_start = 0x03; + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + pdynamic->sd_config__woi_sd0 = 0x03; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x28; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + ptiming->range_config__vcsel_period_a = 0x02; + ptiming->range_config__vcsel_period_b = 0x03; + + + + pgeneral->cal_config__vcsel_start = 0x00; + + + + pgeneral->phasecal_config__target = 0x31; + + + + pdynamic->sd_config__woi_sd0 = 0x02; + pdynamic->sd_config__woi_sd1 = 0x03; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + + phistpostprocess->valid_phase_low = 0x10; + phistpostprocess->valid_phase_high = 0x18; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + pstatic->debug__ctrl = 0x01; + psystem->power_management__go1_power_force = 0x01; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_RANGE_EN; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + &(pzone_cfg->multizone_hist_cfg)); + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + VL53L1_init_histogram_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + phistogram); + + + VL53L1_init_histogram_multizone_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + &(pzone_cfg->multizone_hist_cfg)); + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x21; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x29; + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x09; + pdynamic->sd_config__initial_phase_sd0 = 0x09; + pdynamic->sd_config__initial_phase_sd1 = 0x06; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + 4, 8, 2, + 7, 7, + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + 4, 8, 2, + 7, 7, + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg) + ); + } + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + 4, 8, 2, + 7, 7, + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) + + psystem->system__stream_count_ctrl = 0x01; + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic) +{ + + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(pgeneral); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + pstatic->sd_config__reset_stages_lsb = + phistogram->histogram_config__user_bin_offset; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + pdynamic->system__thresh_high = + phistogram->histogram_config__amb_thresh_low; + + pdynamic->system__thresh_low = + phistogram->histogram_config__amb_thresh_high; + + pdynamic->system__enable_xtalk_per_quadrant = + phistogram->histogram_config__spad_array_selection; + + LOG_FUNCTION_END(0); + +} + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming) +{ + + + LOG_FUNCTION_START(""); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + if (status == VL53L1_ERROR_NONE) { + + + + phistogram->histogram_config__spad_array_selection = 0x01; + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_api_strings.c b/drivers/input/misc/vl53L1/src/vl53l1_api_strings.c new file mode 100644 index 0000000000000000000000000000000000000000..1e3b3be1236891a677aa8e0cbad164ad8e11758e --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_api_strings.c @@ -0,0 +1,221 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + + +#include "vl53l1_api_core.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, fmt, \ + ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(RangeStatus); + VL53L1_COPYSTRING(pRangeStatusString, ""); +#else + switch (RangeStatus) { + case 0: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_RANGEVALID); + break; + case 1: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGMA); + break; + case 2: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGNAL); + break; + case 3: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_MINRANGE); + break; + case 4: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_PHASE); + break; + case 5: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_HW); + break; + + default: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_NONE); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(PalStateCode); + VL53L1_COPYSTRING(pPalStateString, ""); +#else + switch (PalStateCode) { + case VL53L1_STATE_POWERDOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_POWERDOWN); + break; + case VL53L1_STATE_WAIT_STATICINIT: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_WAIT_STATICINIT); + break; + case VL53L1_STATE_STANDBY: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_STANDBY); + break; + case VL53L1_STATE_IDLE: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_IDLE); + break; + case VL53L1_STATE_RUNNING: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RUNNING); + break; + case VL53L1_STATE_RESET: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RESET); + break; + case VL53L1_STATE_UNKNOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + break; + case VL53L1_STATE_ERROR: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_ERROR); + break; + + default: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(SequenceStepId); + VL53L1_COPYSTRING(pSequenceStepsString, ""); +#else + switch (SequenceStepId) { + case VL53L1_SEQUENCESTEP_VHV: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_VHV); + break; + case VL53L1_SEQUENCESTEP_PHASECAL: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_PHASECAL); + break; + case VL53L1_SEQUENCESTEP_REFPHASE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS2); + break; + case VL53L1_SEQUENCESTEP_MM1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM1); + break; + case VL53L1_SEQUENCESTEP_MM2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM2); + break; + case VL53L1_SEQUENCESTEP_RANGE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_RANGE); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(LimitCheckId); + VL53L1_COPYSTRING(pLimitCheckString, ""); +#else + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE); + break; + default: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_core.c b/drivers/input/misc/vl53L1/src/vl53l1_core.c new file mode 100644 index 0000000000000000000000000000000000000000..73146ba5d5f20428b48f93e7c0b0e0748a133848 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_core.c @@ -0,0 +1,4883 @@ + +/******************************************************************************* + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + +******************************************************************************** + +*/ + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_core.h" +#include "vl53l1_tuning_parm_defaults.h" + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +void VL53L1_init_version( + VL53L1_DEV Dev) +{ + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->version.ll_major = VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR; + pdev->version.ll_minor = VL53L1_LL_API_IMPLEMENTATION_VER_MINOR; + pdev->version.ll_build = VL53L1_LL_API_IMPLEMENTATION_VER_SUB; + pdev->version.ll_revision = VL53L1_LL_API_IMPLEMENTATION_VER_REVISION; +} + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState device_state) +{ + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + pstate->cfg_device_state = device_state; + pstate->cfg_stream_count = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + + pstate->rd_device_state = device_state; + pstate->rd_stream_count = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + +} + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + + + LOG_FUNCTION_START(""); + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + } else { + + + + if (pstate->rd_stream_count == 0xFF) + pstate->rd_stream_count = 0x80; + else + pstate->rd_stream_count++; + + + status = VL53L1_update_internal_stream_counters(Dev, + pstate->rd_stream_count, + &(pstate->rd_internal_stream_count), + &(pstate->rd_internal_stream_count_val)); + + + + pstate->rd_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + switch (pstate->rd_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + + if ((pdev->dyn_cfg.system__grouped_parameter_hold & + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK) > 0) { + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC; + } else { + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + } + + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + break; + + case VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC: + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_zone_id = 0; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pstate->rd_zone_id++; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pstate->rd_zone_id = 0; + pstate->rd_timing_status ^= 0x01; + + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + break; + + default: + pstate->rd_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + break; + } + } + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_system_results_t *psys_results = &(pdev->sys_results); + VL53L1_histogram_bin_data_t *phist_data = &(pdev->hist_data); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t device_range_status = 0; + uint8_t device_stream_count = 0; + uint8_t device_gph_id = 0; + uint8_t histogram_mode = 0; + uint8_t expected_stream_count = 0; + uint8_t expected_gph_id = 0; + + LOG_FUNCTION_START(""); + + + + device_range_status = + psys_results->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + device_stream_count = psys_results->result__stream_count; + + + + histogram_mode = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM; + + + device_gph_id = (psys_results->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + if (histogram_mode) + device_gph_id = (phist_data->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + + + if (!((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK)) + goto ENDFUNC; + + + + if (pstate->rd_device_state == + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + if (histogram_mode == 0) { + if (device_range_status != + VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY) + status = + VL53L1_ERROR_GPH_SYNC_CHECK_FAIL; + + } + } else { + if (pstate->rd_stream_count != device_stream_count) + status = VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL; + + + if (pstate->rd_gph_id != device_gph_id) + status = VL53L1_ERROR_GPH_ID_CHECK_FAIL; + + + + + expected_stream_count = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_stream_count; + expected_gph_id = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id; + + + + if (expected_stream_count != device_stream_count) { + + + if (!((pdev->zone_cfg.active_zones == 0) && + (device_stream_count == 255))) + status = + VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL; + + + } + + + + if (expected_gph_id != device_gph_id) + status = VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL; + + } + + + +ENDFUNC: + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t prev_cfg_zone_id; + uint8_t prev_cfg_gph_id; + uint8_t prev_cfg_stream_count; + + LOG_FUNCTION_START(""); + + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + prev_cfg_zone_id = 0; + prev_cfg_gph_id = 0; + prev_cfg_stream_count = 0; + + } else { + + prev_cfg_gph_id = pstate->cfg_gph_id; + prev_cfg_zone_id = pstate->cfg_zone_id; + prev_cfg_stream_count = pstate->cfg_stream_count; + + + + if (pstate->cfg_stream_count == 0xFF) + pstate->cfg_stream_count = 0x80; + else + pstate->cfg_stream_count++; + + + status = VL53L1_update_internal_stream_counters( + Dev, + pstate->cfg_stream_count, + &(pstate->cfg_internal_stream_count), + &(pstate->cfg_internal_stream_count_val)); + + + + pstate->cfg_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + switch (pstate->cfg_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + pstate->cfg_zone_id = 1; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + pstate->cfg_stream_count = 1; + + if (pdev->gen_cfg.global_config__stream_divider == 0) { + pstate->cfg_internal_stream_count = 1; + pstate->cfg_internal_stream_count_val = 0; + } else { + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 1; + } + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_AUTO; + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_AUTO: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + + + + + if (pdev->zone_cfg.active_zones > 0) { + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL; + } + } + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_MANUAL: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + break; + + default: + pstate->cfg_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + break; + } + } + + + if (pdev->zone_cfg.active_zones == 0) { + + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count - 1; + + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id = + prev_cfg_gph_id ^ VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + } else { + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count; + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_gph_id = + prev_cfg_gph_id; + } + + + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer) +{ + + + *(pbuffer + 0) = pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 1) = pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 2) = pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 3) = pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 4) = pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 5) = pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 6) = pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 7) = pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 8) = pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 9) = pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 10) = pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 11) = pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 12) = pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 13) = pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 14) = pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 15) = pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 16) = pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 17) = pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 18) = pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 19) = pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 20) = pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 21) = pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 22) = pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 23) = pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 24) = pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 25) = pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 26) = pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 27) = pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 28) = pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 29) = pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 30) = pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 31) = pdata->global_config__spad_enables_rtn_31; +} + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata) +{ + + + pdata->result__interrupt_status = 0xFF; + pdata->result__range_status = 0xFF; + pdata->result__report_status = 0xFF; + pdata->result__stream_count = 0xFF; + + pdata->result__dss_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__sigma_sd0 = 0xFFFF; + pdata->result__phase_sd0 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + 0xFFFF; + pdata->result__mm_inner_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__mm_outer_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__avg_signal_count_rate_mcps_sd0 = 0xFFFF; + + pdata->result__dss_actual_effective_spads_sd1 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__sigma_sd1 = 0xFFFF; + pdata->result__phase_sd1 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd1 = 0xFFFF; + pdata->result__spare_0_sd1 = 0xFFFF; + pdata->result__spare_1_sd1 = 0xFFFF; + pdata->result__spare_2_sd1 = 0xFFFF; + pdata->result__spare_3_sd1 = 0xFF; + +} + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata) +{ + + + + uint8_t z = 0; + VL53L1_zone_objects_t *pobjects; + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + pdata->active_zones = active_zones; + + for (z = 0; z < pdata->max_zones; z++) { + pobjects = &(pdata->VL53L1_p_002[z]); + pobjects->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->max_objects = VL53L1_MAX_RANGE_RESULTS; + pobjects->active_objects = 0; + } +} + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev) +{ + + + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + uint8_t z = 0; + uint8_t max_zones = VL53L1_MAX_USER_ZONES; + VL53L1_zone_private_dyn_cfgs_t *pdata = &(pres->zone_dyn_cfgs); + + for (z = 0; z < max_zones; z++) { + pdata->VL53L1_p_002[z].dss_mode = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + pdata->VL53L1_p_002[z].dss_requested_effective_spad_count = 0; + } +} + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__low_amb_odd_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__low_amb_odd_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__high_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__high_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__high_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 = + pdata->histogram_config__low_amb_odd_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 = + pdata->histogram_config__low_amb_odd_bin_4_5; + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + pdata->histogram_config__spad_array_selection = 0x00; + +} + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__low_amb_odd_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__low_amb_odd_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 + = pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__high_amb_even_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__high_amb_even_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__high_amb_odd_bin_0_1 + = pdata->histogram_config__high_amb_even_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 + = pdata->histogram_config__high_amb_even_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 + = pdata->histogram_config__high_amb_even_bin_4_5; + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + pdata->histogram_config__spad_array_selection = 0x00; +} + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata) +{ + + + + uint16_t i = 0; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_019 = 0; + + pdata->zero_distance_phase = 0; + + for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) { + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + } +} + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + uint16_t i = 0; + uint16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + uint16_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint16_t)*pbuffer++; + + return value; +} + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + uint16_t i = 0; + int16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + int16_t value = 0x00; + + + if (*pbuffer >= 0x80) + value = 0xFFFF; + + while (count-- > 0) + value = (value << 8) | (int16_t)*pbuffer++; + + return value; +} + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + uint16_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + uint32_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + return value; +} + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset) +{ + + + uint32_t value = 0x00; + + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + + value = value & bit_mask; + if (down_shift > 0) + value = value >> down_shift; + + + value = value + offset; + + return value; +} + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + uint16_t i = 0; + int32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + int32_t value = 0x00; + + + if (*pbuffer >= 0x80) + value = 0xFFFFFFFF; + + while (count-- > 0) + value = (value << 8) | (int32_t)*pbuffer++; + + return value; +} + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_TEST_MODE__CTRL, + test_mode__ctrl); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.firmware__enable = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_FIRMWARE__ENABLE, + pdev->sys_ctrl.firmware__enable); + + return status; +} + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.power_management__go1_power_force = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + pdev->sys_ctrl.power_management__go1_power_force); + + return status; +} + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->sys_ctrl.system__interrupt_clear = VL53L1_CLEAR_RANGE_INT; + + status = VL53L1_WrByte( + Dev, + VL53L1_SYSTEM__INTERRUPT_CLEAR, + pdev->sys_ctrl.system__interrupt_clear); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_SHADOW_RESULT__STREAM_COUNT, + 0x00); + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + return status; +} + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009) +{ + + + uint32_t pll_period_us = 0; + uint8_t VL53L1_p_031 = 0; + uint32_t macro_period_us = 0; + + LOG_FUNCTION_START(""); + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + VL53L1_p_031 = VL53L1_decode_vcsel_period(VL53L1_p_009); + + + + macro_period_us = + (uint32_t)VL53L1_MACRO_PERIOD_VCSEL_PERIODS * + pll_period_us; + macro_period_us = macro_period_us >> 6; + + macro_period_us = macro_period_us * (uint32_t)VL53L1_p_031; + macro_period_us = macro_period_us >> 6; + + + + LOG_FUNCTION_END(0); + + return macro_period_us; +} + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult) +{ + + + int32_t range_ignore_thresh_int = 0; + uint16_t range_ignore_thresh_kcps = 0; + int32_t central_rate_int = 0; + int16_t x_gradient_int = 0; + int16_t y_gradient_int = 0; + + LOG_FUNCTION_START(""); + + + + central_rate_int = ((int32_t)central_rate * (1 << 4)) / (1000); + + if (x_gradient < 0) + x_gradient_int = x_gradient * -1; + + if (y_gradient < 0) + y_gradient_int = y_gradient * -1; + + + + + + range_ignore_thresh_int = (8 * x_gradient_int * 4) + + (8 * y_gradient_int * 4); + + + + range_ignore_thresh_int = range_ignore_thresh_int / 1000; + + + + range_ignore_thresh_int = range_ignore_thresh_int + central_rate_int; + + + + range_ignore_thresh_int = (int32_t)rate_mult * range_ignore_thresh_int; + + range_ignore_thresh_int = (range_ignore_thresh_int + (1<<4)) / (1<<5); + + + + if (range_ignore_thresh_int > 0xFFFF) + range_ignore_thresh_kcps = 0xFFFF; + else + range_ignore_thresh_kcps = (uint16_t)range_ignore_thresh_int; + + + + LOG_FUNCTION_END(0); + + return range_ignore_thresh_kcps; +} + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + ((timeout_us << 12) + (macro_period_us>>1)) / + macro_period_us; + + LOG_FUNCTION_END(0); + + return timeout_mclks; +} + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_calc_timeout_mclks(timeout_us, macro_period_us); + + timeout_encoded = + VL53L1_encode_timeout(timeout_mclks); + + + + LOG_FUNCTION_END(0); + + return timeout_encoded; +} + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us) +{ + + + uint32_t timeout_us = 0; + uint64_t tmp = 0; + + LOG_FUNCTION_START(""); + + tmp = (uint64_t)timeout_mclks * (uint64_t)macro_period_us; + tmp += 0x00800; + tmp = tmp >> 12; + + timeout_us = (uint32_t)tmp; + + + + LOG_FUNCTION_END(0); + + return timeout_us; +} + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps) +{ + uint32_t plane_offset_with_margin = 0; + int32_t plane_offset_kcps_temp = 0; + + LOG_FUNCTION_START(""); + + plane_offset_kcps_temp = + (int32_t)plane_offset_kcps + + (int32_t)margin_offset_kcps; + + if (plane_offset_kcps_temp < 0) + plane_offset_kcps_temp = 0; + else + if (plane_offset_kcps_temp > 0x3FFFF) + plane_offset_kcps_temp = 0x3FFFF; + + plane_offset_with_margin = (uint32_t) plane_offset_kcps_temp; + + LOG_FUNCTION_END(0); + + return plane_offset_with_margin; + +} + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us) +{ + + + uint32_t timeout_mclks = 0; + uint32_t timeout_us = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_decode_timeout(timeout_encoded); + + timeout_us = + VL53L1_calc_timeout_us(timeout_mclks, macro_period_us); + + LOG_FUNCTION_END(0); + + return timeout_us; +} + + +uint16_t VL53L1_encode_timeout(uint32_t timeout_mclks) +{ + + + uint16_t encoded_timeout = 0; + uint32_t ls_byte = 0; + uint16_t ms_byte = 0; + + if (timeout_mclks > 0) { + ls_byte = timeout_mclks - 1; + + while ((ls_byte & 0xFFFFFF00) > 0) { + ls_byte = ls_byte >> 1; + ms_byte++; + } + + encoded_timeout = (ms_byte << 8) + + (uint16_t) (ls_byte & 0x000000FF); + } + + return encoded_timeout; +} + + +uint32_t VL53L1_decode_timeout(uint16_t encoded_timeout) +{ + + + uint32_t timeout_macro_clks = 0; + + timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF) + << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1; + + return timeout_macro_clks; +} + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (fast_osc_frequency == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_a); + + + timeout_mclks = + VL53L1_calc_timeout_mclks( + phasecal_config_timeout_us, + macro_period_us); + + + if (timeout_mclks > 0xFF) + timeout_mclks = 0xFF; + + pgeneral->phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_b); + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + timeout_encoded = VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + } + + LOG_FUNCTION_END(0); + + return status; + +} + + +uint8_t VL53L1_encode_vcsel_period(uint8_t VL53L1_p_031) +{ + + + uint8_t vcsel_period_reg = 0; + + vcsel_period_reg = (VL53L1_p_031 >> 1) - 1; + + return vcsel_period_reg; +} + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes) +{ + + + uint8_t i = 0; + uint32_t decoded_value = 0; + + for (i = 0; i < no_of_bytes; i++) + decoded_value = (decoded_value << 8) + (uint32_t)pbuffer[i]; + + return decoded_value; +} + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer) +{ + + + uint8_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + for (i = 0; i < no_of_bytes; i++) { + pbuffer[no_of_bytes-i-1] = VL53L1_p_002 & 0x00FF; + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t evts = 0; + int64_t tmpi = 0; + int64_t tmpo = 0; + + LOG_FUNCTION_START(""); + + + if (pidata->result__dss_actual_effective_spads == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + if (pidata->number_of_ambient_bins > 0 && + podata->number_of_ambient_bins == 0) { + + + + tmpo = 1 + (int64_t)podata->total_periods_elapsed; + tmpo *= + (int64_t)podata->result__dss_actual_effective_spads; + + tmpi = 1 + (int64_t)pidata->total_periods_elapsed; + tmpi *= + (int64_t)pidata->result__dss_actual_effective_spads; + + evts = tmpo * + (int64_t)pidata->ambient_events_sum; + evts += (tmpi/2); + + + if (tmpi != 0) + evts = do_division_s(evts, tmpi); + + podata->ambient_events_sum = (int32_t)evts; + + + + podata->VL53L1_p_004 = + podata->ambient_events_sum; + podata->VL53L1_p_004 += + ((int32_t)pidata->number_of_ambient_bins / 2); + podata->VL53L1_p_004 /= + (int32_t)pidata->number_of_ambient_bins; + } + } + + LOG_FUNCTION_END(0); + + return status; +} + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t amb_thresh_low = 0; + int32_t amb_thresh_high = 0; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + amb_thresh_low = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_low; + amb_thresh_high = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_high; + + + + if ((pdev->ll_state.rd_stream_count & 0x01) == 0) { + + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + & 0x0F; + } + + } else { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_5 + & 0x0F; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_2 & + 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + & 0x0F; + } + } + + + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t lc = 0; + uint8_t p = 0; + + uint16_t phase_delta = 0; + uint16_t phase_tolerance = 0; + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + + + uint8_t event_sigma; + uint16_t event_min_spad_count; + uint16_t min_max_tolerance; + uint8_t pht; + + VL53L1_DeviceError range_status = 0; + + LOG_FUNCTION_START(""); + + event_sigma = + pdev->histpostprocess.algo__consistency_check__event_sigma; + event_min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + min_max_tolerance = + pdev->histpostprocess.algo__consistency_check__min_max_tolerance; + + + pht = pdev->histpostprocess.algo__consistency_check__phase_tolerance; + phase_tolerance = (uint16_t)pht; + phase_tolerance = phase_tolerance << 8; + + + + if (prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_GATHER_DATA && + prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA) + return status; + + + + if (phase_tolerance == 0) + return status; + + for (lc = 0; lc < prange_curr->active_results; lc++) { + + if (!((prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) || + (prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK))) + continue; + + + + + + + if (prange_prev->active_objects == 0) + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS; + else + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PHASECONSISTENCY; + + + + + + for (p = 0; p < prange_prev->active_objects; p++) { + + if (prange_curr->VL53L1_p_002[lc].VL53L1_p_014 > + prange_prev->VL53L1_p_002[p].VL53L1_p_014) { + phase_delta = + prange_curr->VL53L1_p_002[lc].VL53L1_p_014 - + prange_prev->VL53L1_p_002[p].VL53L1_p_014; + } else { + phase_delta = + prange_prev->VL53L1_p_002[p].VL53L1_p_014 - + prange_curr->VL53L1_p_002[lc].VL53L1_p_014; + } + + if (phase_delta < phase_tolerance) { + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_events_consistency_check( + event_sigma, + event_min_spad_count, + phist_prev, + &(prange_prev->VL53L1_p_002[p]), + &(prange_curr->VL53L1_p_002[lc]), + &events_tolerance, + &events_delta, + &range_status); + + + + + if (status == VL53L1_ERROR_NONE && + range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) + status = + VL53L1_hist_merged_pulse_check( + min_max_tolerance, + &(prange_curr->VL53L1_p_002[lc]), + &range_status); + + prange_curr->VL53L1_p_002[lc].range_status = + range_status; + } + } + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t tmpp = 0; + int64_t tmpc = 0; + int64_t events_scaler = 0; + int64_t events_scaler_sq = 0; + int64_t c_signal_events = 0; + int64_t c_sig_noise_sq = 0; + int64_t c_amb_noise_sq = 0; + int64_t p_amb_noise_sq = 0; + + int32_t p_signal_events = 0; + uint32_t noise_sq_sum = 0; + + + + if (event_sigma == 0) { + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + return status; + } + + + + tmpp = 1 + (int64_t)phist_prev->total_periods_elapsed; + tmpp *= (int64_t)phist_prev->result__dss_actual_effective_spads; + + + + tmpc = 1 + (int64_t)prange_curr->total_periods_elapsed; + tmpc *= (int64_t)prange_curr->VL53L1_p_006; + + + + events_scaler = tmpp * 4096; + events_scaler += (tmpc/2); + if (tmpc != 0) + events_scaler = do_division_s(events_scaler, tmpc); + + events_scaler_sq = events_scaler * events_scaler; + events_scaler_sq += 2048; + events_scaler_sq /= 4096; + + + + c_signal_events = (int64_t)prange_curr->VL53L1_p_021; + c_signal_events -= (int64_t)prange_curr->VL53L1_p_020; + c_signal_events *= (int64_t)events_scaler; + c_signal_events += 2048; + c_signal_events /= 4096; + + c_sig_noise_sq = (int64_t)events_scaler_sq; + c_sig_noise_sq *= (int64_t)prange_curr->VL53L1_p_021; + c_sig_noise_sq += 2048; + c_sig_noise_sq /= 4096; + + c_amb_noise_sq = (int64_t)events_scaler_sq; + c_amb_noise_sq *= (int64_t)prange_curr->VL53L1_p_020; + c_amb_noise_sq += 2048; + c_amb_noise_sq /= 4096; + + + c_amb_noise_sq += 2; + c_amb_noise_sq /= 4; + + + + p_amb_noise_sq = + (int64_t)prange_prev->VL53L1_p_020; + + + p_amb_noise_sq += 2; + p_amb_noise_sq /= 4; + + noise_sq_sum = + (uint32_t)prange_prev->VL53L1_p_021 + + (uint32_t)c_sig_noise_sq + + (uint32_t)p_amb_noise_sq + + (uint32_t)c_amb_noise_sq; + + *pevents_tolerance = + (int32_t)VL53L1_isqrt(noise_sq_sum * 16); + + *pevents_tolerance *= (int32_t)event_sigma; + *pevents_tolerance += 32; + *pevents_tolerance /= 64; + + p_signal_events = (int32_t)prange_prev->VL53L1_p_021; + p_signal_events -= (int32_t)prange_prev->VL53L1_p_020; + + if ((int32_t)c_signal_events > p_signal_events) + *pevents_delta = + (int32_t)c_signal_events - p_signal_events; + else + *pevents_delta = + p_signal_events - (int32_t)c_signal_events; + + if (*pevents_delta > *pevents_tolerance && + prange_curr->VL53L1_p_006 > min_effective_spad_count) + *prange_status = VL53L1_DEVICEERROR_EVENTCONSISTENCY; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + + + + + return status; +} + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int16_t delta_mm = 0; + + if (pdata->max_range_mm > pdata->min_range_mm) + delta_mm = + pdata->max_range_mm - pdata->min_range_mm; + else + delta_mm = + pdata->min_range_mm - pdata->max_range_mm; + + if (min_max_tolerance_mm > 0 && + delta_mm > min_max_tolerance_mm) + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + return status; +} + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + uint8_t event_sigma; + uint16_t min_spad_count; + + event_sigma = pdev->histpostprocess.algo__crosstalk_detect_event_sigma; + min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + + if (prange_curr->range_status == VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_curr->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_curr->range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + if (prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + prange_curr->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE; + + status = + VL53L1_hist_events_consistency_check( + event_sigma, + min_spad_count, + phist_prev, + &(prange_prev->xmonitor), + prange_curr, + &events_tolerance, + &events_delta, + &(prange_curr->range_status)); + + } + } + + return status; +} + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t pll_period_mm = 0; + uint32_t wrap_dmax_phase = 0; + uint32_t range_mm = 0; + + LOG_FUNCTION_START(""); + + *pwrap_dmax_mm = 0; + + + if (pcurrent->VL53L1_p_019 != 0) { + + + + pll_period_mm = + VL53L1_calc_pll_period_mm( + pcurrent->VL53L1_p_019); + + + + wrap_dmax_phase = + (uint32_t)phistpostprocess->valid_phase_high << 8; + + + + range_mm = wrap_dmax_phase * pll_period_mm; + range_mm = (range_mm + (1<<14)) >> 15; + + *pwrap_dmax_mm = (int16_t)range_mm; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm) +{ + + + + uint16_t max_mm_inner_effective_spads = 0; + uint16_t max_mm_outer_effective_spads = 0; + uint16_t mm_inner_effective_spads = 0; + uint16_t mm_outer_effective_spads = 0; + + uint32_t scaled_mm1_peak_rate_mcps = 0; + uint32_t scaled_mm2_peak_rate_mcps = 0; + + int32_t tmp0 = 0; + int32_t tmp1 = 0; + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + 0xC7, + 0xFF, + pgood_spads, + aperture_attenuation, + &max_mm_inner_effective_spads, + &max_mm_outer_effective_spads); + + if ((max_mm_inner_effective_spads == 0) || + (max_mm_outer_effective_spads == 0)) + goto FAIL; + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + encoded_zone_centre, + encoded_zone_size, + pgood_spads, + aperture_attenuation, + &mm_inner_effective_spads, + &mm_outer_effective_spads); + + + + scaled_mm1_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_inner_peak_signal_count_rtn_mcps; + scaled_mm1_peak_rate_mcps *= (uint32_t)mm_inner_effective_spads; + scaled_mm1_peak_rate_mcps /= (uint32_t)max_mm_inner_effective_spads; + + scaled_mm2_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_outer_peak_signal_count_rtn_mcps; + scaled_mm2_peak_rate_mcps *= (uint32_t)mm_outer_effective_spads; + scaled_mm2_peak_rate_mcps /= (uint32_t)max_mm_outer_effective_spads; + + + + tmp0 = ((int32_t)mm1_offset_mm * (int32_t)scaled_mm1_peak_rate_mcps); + tmp0 += ((int32_t)mm2_offset_mm * (int32_t)scaled_mm2_peak_rate_mcps); + + tmp1 = (int32_t)scaled_mm1_peak_rate_mcps + + (int32_t)scaled_mm2_peak_rate_mcps; + + + + if (tmp1 != 0) + tmp0 = (tmp0 * 4) / tmp1; +FAIL: + *prange_offset_mm = (int16_t)tmp0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + pxtalk_data->pll_period_mm = + VL53L1_calc_pll_period_mm(phist_bins->VL53L1_p_019); + + + pxtalk_data->xtalk_width_phase = + (int32_t)phist_bins->vcsel_width * 128; + pxtalk_data->target_width_phase = + pxtalk_data->xtalk_width_phase + + (int32_t)target_width_oversize * 128; + + + + pxtalk_data->xtalk_start_phase = + (int32_t)phist_bins->zero_distance_phase - + (pxtalk_data->xtalk_width_phase / 2); + pxtalk_data->xtalk_end_phase = + (int32_t)pxtalk_data->xtalk_start_phase + + pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->xtalk_start_phase < 0) + pxtalk_data->xtalk_start_phase = 0; + + + + + pxtalk_data->VL53L1_p_015 = + (uint8_t)(pxtalk_data->xtalk_start_phase / 2048); + + + pxtalk_data->VL53L1_p_016 = + (uint8_t)((pxtalk_data->xtalk_end_phase + 2047) / 2048); + + + + pxtalk_data->target_start_phase = + (int32_t)target_distance_mm * 2048 * 16; + pxtalk_data->target_start_phase += + ((int32_t)pxtalk_data->pll_period_mm / 2); + pxtalk_data->target_start_phase /= (int32_t)pxtalk_data->pll_period_mm; + pxtalk_data->target_start_phase += + (int32_t)phist_bins->zero_distance_phase; + + + + pxtalk_data->target_start_phase -= + (pxtalk_data->target_width_phase / 2); + pxtalk_data->target_end_phase = + (int32_t)pxtalk_data->target_start_phase + + pxtalk_data->target_width_phase; + + if (pxtalk_data->target_start_phase < 0) + pxtalk_data->target_start_phase = 0; + + + pxtalk_data->target_start = + (uint8_t)(pxtalk_data->target_start_phase / 2048); + + + if (pxtalk_data->VL53L1_p_016 > (pxtalk_data->target_start-1)) + pxtalk_data->VL53L1_p_016 = pxtalk_data->target_start-1; + + + pxtalk_data->effective_width = + (2048 * ((int32_t)pxtalk_data->VL53L1_p_016+1)); + pxtalk_data->effective_width -= pxtalk_data->xtalk_start_phase; + + + if (pxtalk_data->effective_width > pxtalk_data->xtalk_width_phase) + pxtalk_data->effective_width = pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->effective_width < 1) + pxtalk_data->effective_width = 1; + + + pxtalk_data->event_scaler = pxtalk_data->xtalk_width_phase * 1000; + pxtalk_data->event_scaler += (pxtalk_data->effective_width / 2); + pxtalk_data->event_scaler /= pxtalk_data->effective_width; + + + if (pxtalk_data->event_scaler < 1000) + pxtalk_data->event_scaler = 1000; + + if (pxtalk_data->event_scaler > 4000) + pxtalk_data->event_scaler = 4000; + + + pxtalk_data->event_scaler_sum += pxtalk_data->event_scaler; + + + pxtalk_data->peak_duration_us_sum += + (uint32_t)phist_bins->peak_duration_us; + + + pxtalk_data->effective_spad_count_sum += + (uint32_t)phist_bins->result__dss_actual_effective_spads; + + + pxtalk_data->zero_distance_phase_sum += + (uint32_t)phist_bins->zero_distance_phase; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t lb = 0; + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + for (lb = pxtalk_data->VL53L1_p_015; + lb <= pxtalk_data->VL53L1_p_016; + lb++) { + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + pxtalk_data->signal_events_sum += phist_bins->bin_data[i]; + pxtalk_data->signal_events_sum -= + phist_bins->VL53L1_p_004; + } + + + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS && + lb < phist_bins->VL53L1_p_024; lb++) { + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + pxtalk_data->bin_data_sums[lb] += phist_bins->bin_data[i]; + pxtalk_data->bin_data_sums[lb] -= + phist_bins->VL53L1_p_004; + } + + pxtalk_data->sample_count += 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint64_t tmp64_0 = 0; + uint64_t tmp64_1 = 0; + uint64_t xtalk_per_spad = 0; + + LOG_FUNCTION_START(""); + + + + + + + + tmp64_1 = + (uint64_t)pxtalk_data->effective_spad_count_sum * + (uint64_t)pxtalk_data->peak_duration_us_sum; + + if (pxtalk_data->signal_events_sum < 0) { + pxtalk_data->signal_events_sum = 0; + + tmp64_0 = + ((uint64_t)pxtalk_data->sample_count * + (uint64_t)pxtalk_data->event_scaler_avg * 256U) << 9U; + if (tmp64_0 > 0) { + pxtalk_data->signal_events_sum = (int32_t) + do_division_u((50U * tmp64_1), tmp64_0); + } + } + tmp64_0 = + ((uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->sample_count * + (uint64_t)pxtalk_data->event_scaler_avg * 256U) << 9U; + + + + if (tmp64_1 > 0U) { + + tmp64_0 = tmp64_0 + (tmp64_1 >> 1U); + xtalk_per_spad = do_division_u(tmp64_0, tmp64_1); + } else { + xtalk_per_spad = (uint64_t)tmp64_0; + } + + pxtalk_data->xtalk_rate_kcps_per_spad = (uint32_t)xtalk_per_spad; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int32_t lb = 0; + uint64_t total_events = 0U; + uint64_t tmp64_0 = 0U; + int32_t remaining_area = 1024; + + LOG_FUNCTION_START(""); + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg; + pxtalk_shape->phasecal_result__reference_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg + (3*2048); + + + + if (pxtalk_data->signal_events_sum > 0) + total_events = + (uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->event_scaler_avg; + else + total_events = 1; + if (total_events == 0) + total_events = 1; + + + remaining_area = 1024; + pxtalk_data->max_shape_value = 0; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + + if ((lb < (int32_t)pxtalk_data->VL53L1_p_015 || + lb > (int32_t)pxtalk_data->VL53L1_p_016) || + pxtalk_data->bin_data_sums[lb] < 0) { + + + if (remaining_area > 0 && remaining_area < 1024) { + if (remaining_area > + pxtalk_data->max_shape_value) { + pxtalk_shape->bin_data[lb] = + (uint32_t)pxtalk_data->max_shape_value; + remaining_area -= + pxtalk_data->max_shape_value; + } else { + pxtalk_shape->bin_data[lb] = + (uint32_t)remaining_area; + remaining_area = 0; + } + } else { + pxtalk_shape->bin_data[lb] = 0; + } + + } else { + + tmp64_0 = + (uint64_t)pxtalk_data->bin_data_sums[lb] + * 1024U * 1000U; + tmp64_0 += (total_events >> 1); + tmp64_0 = do_division_u(tmp64_0, total_events); + if (tmp64_0 > 0xFFFFU) + tmp64_0 = 0xFFFFU; + + pxtalk_shape->bin_data[lb] = (uint32_t)tmp64_0; + + + if ((int32_t)pxtalk_shape->bin_data[lb] > + pxtalk_data->max_shape_value) + pxtalk_data->max_shape_value = + (int32_t)pxtalk_shape->bin_data[lb]; + + remaining_area -= (int32_t)pxtalk_shape->bin_data[lb]; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t phase_start = 0; + uint32_t phase_stop = 0; + uint32_t phase_bin = 0; + + uint32_t bin_start = 0; + uint32_t bin_stop = 0; + + uint32_t lb = 0; + uint16_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = pulse_centre; + pxtalk_shape->phasecal_result__reference_phase = + pulse_centre + (3*2048); + + + if (pulse_centre > (pulse_width >> 1)) + phase_start = (uint32_t)pulse_centre - + ((uint32_t)pulse_width >> 1); + else + phase_start = 0; + + phase_stop = (uint32_t)pulse_centre + + ((uint32_t)pulse_width >> 1); + + + bin_start = (phase_start / 2048); + bin_stop = (phase_stop / 2048); + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + VL53L1_p_008 = 0; + + + if (lb == bin_start && lb == bin_stop) { + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + phase_stop - phase_start); + + } else if (lb > bin_start && lb < bin_stop) { + + + VL53L1_p_008 = events_per_bin; + + } else if (lb == bin_start) { + + + phase_bin = (lb + 1) * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_bin - phase_start)); + + } else if (lb == bin_stop) { + + + phase_bin = lb * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_stop - phase_bin)); + } + + pxtalk_shape->bin_data[lb] = VL53L1_p_008; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta) +{ + + + uint32_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + VL53L1_p_008 = (uint32_t)events_per_bin * phase_delta; + VL53L1_p_008 += 1024; + VL53L1_p_008 /= 2048; + + + if (VL53L1_p_008 > 0xFFFFU) + VL53L1_p_008 = 0xFFFFU; + + LOG_FUNCTION_END(0); + + return (uint16_t)VL53L1_p_008; +} + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask) +{ + + + + *pbyte_index = spad_number >> 3; + *pbit_index = spad_number & 0x07; + *pbit_mask = 0x01 << *pbit_index; + +} + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number) +{ + + + if (row > 7) + *pspad_number = 128 + (col << 3) + (15-row); + else + *pspad_number = ((15-col) << 3) + row; + +} + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight) +{ + + + + *pheight = encoded_xy_size >> 4; + *pwidth = encoded_xy_size & 0x0F; + +} + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size) +{ + + + *pencoded_xy_size = (height << 4) + width; + +} + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur) +{ + + + + uint8_t x_centre = 0; + uint8_t y_centre = 0; + uint8_t width = 0; + uint8_t height = 0; + + + + VL53L1_decode_row_col( + encoded_xy_centre, + &y_centre, + &x_centre); + + VL53L1_decode_zone_size( + encoded_xy_size, + &width, + &height); + + + + *px_ll = (int16_t)x_centre - ((int16_t)width + 1) / 2; + if (*px_ll < 0) + *px_ll = 0; + + *px_ur = *px_ll + (int16_t)width; + if (*px_ur > (VL53L1_SPAD_ARRAY_WIDTH-1)) + *px_ur = VL53L1_SPAD_ARRAY_WIDTH-1; + + *py_ll = (int16_t)y_centre - ((int16_t)height + 1) / 2; + if (*py_ll < 0) + *py_ll = 0; + + *py_ur = *py_ll + (int16_t)height; + if (*py_ur > (VL53L1_SPAD_ARRAY_HEIGHT-1)) + *py_ur = VL53L1_SPAD_ARRAY_HEIGHT-1; +} + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col) +{ + + + uint8_t is_aperture = 0; + uint8_t mod_row = row % 4; + uint8_t mod_col = col % 4; + + if (mod_row == 0 && mod_col == 2) + is_aperture = 1; + + if (mod_row == 2 && mod_col == 0) + is_aperture = 1; + + return is_aperture; +} + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads) +{ + + + + int16_t x = 0; + int16_t y = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + + + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + *pmax_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + *pmax_effective_spads += + aperture_attenuation; + else + *pmax_effective_spads += 0x0100; + + } + } + } +} + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads) +{ + + + + int16_t x = 0; + int16_t y = 0; + + int16_t mm_x_ll = 0; + int16_t mm_y_ll = 0; + int16_t mm_x_ur = 0; + int16_t mm_y_ur = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + uint16_t spad_attenuation = 0; + + + + VL53L1_decode_zone_limits( + encoded_mm_roi_centre, + encoded_mm_roi_size, + &mm_x_ll, + &mm_y_ll, + &mm_x_ur, + &mm_y_ur); + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + *pmm_inner_effective_spads = 0; + *pmm_outer_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + spad_attenuation = aperture_attenuation; + else + spad_attenuation = 0x0100; + + + + if (x >= mm_x_ll && x <= mm_x_ur && + y >= mm_y_ll && y <= mm_y_ur) + *pmm_inner_effective_spads += + spad_attenuation; + else + *pmm_outer_effective_spads += + spad_attenuation; + } + } + } +} + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore) +{ + + + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + VL53L1_init_system_results(psys); + + + + psys->result__interrupt_status = pbins->result__interrupt_status; + psys->result__range_status = phist->active_results; + psys->result__report_status = pbins->result__report_status; + psys->result__stream_count = pbins->result__stream_count; + + pdata = &(phist->VL53L1_p_002[0]); + + for (i = 0; i < phist->active_results; i++) { + + switch (i) { + case 0: + psys->result__dss_actual_effective_spads_sd0 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd0 = + pdata->peak_signal_count_rate_mcps; + psys->result__avg_signal_count_rate_mcps_sd0 = + pdata->avg_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd0 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd0 = pdata->VL53L1_p_005; + psys->result__phase_sd0 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd0 = + (uint16_t)pdata->median_range_mm; + + psys->result__phase_sd1 = pdata->zero_distance_phase; + + pcore->result_core__ranging_total_events_sd0 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd0 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd0 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd0 = + pdata->VL53L1_p_020; + + break; + case 1: + psys->result__dss_actual_effective_spads_sd1 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd1 = + pdata->peak_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd1 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd1 = pdata->VL53L1_p_005; + psys->result__phase_sd1 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd1 = + (uint16_t)pdata->median_range_mm; + + pcore->result_core__ranging_total_events_sd1 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd1 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd1 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd1 = + pdata->VL53L1_p_020; + break; + } + + pdata++; + } + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t smallest_bin_num = 0; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) { + if (phist_output->VL53L1_p_024 >= + phist_input->VL53L1_p_024) + smallest_bin_num = phist_input->VL53L1_p_024; + else + smallest_bin_num = phist_output->VL53L1_p_024; + } + + + + + + if (status == VL53L1_ERROR_NONE) + for (i = 0; i < smallest_bin_num; i++) + + phist_output->bin_data[i] += phist_input->bin_data[i]; + + if (status == VL53L1_ERROR_NONE) + phist_output->VL53L1_p_004 += + phist_input->VL53L1_p_004; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + + if (status == VL53L1_ERROR_NONE) { + for (i = 0; i < phist_sum->VL53L1_p_024; i++) { + + + + if (no_of_samples > 0) + phist_avg->bin_data[i] = + phist_sum->bin_data[i] / + (int32_t)no_of_samples; + else + phist_avg->bin_data[i] = phist_sum->bin_data[i]; + } + } + + if (status == VL53L1_ERROR_NONE) { + if (no_of_samples > 0) + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004 / + (int32_t)no_of_samples; + else + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + + LOG_FUNCTION_START(""); + + pzone_dyn_cfg = + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]); + + pzone_dyn_cfg->expected_stream_count = + pdev->ll_state.cfg_stream_count; + + pzone_dyn_cfg->expected_gph_id = + pdev->ll_state.cfg_gph_id; + + pzone_dyn_cfg->roi_config__user_roi_centre_spad = + pdynamic->roi_config__user_roi_centre_spad; + + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size = + pdynamic->roi_config__user_roi_requested_global_xy_size; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t zone_id = pdev->ll_state.rd_zone_id; + uint8_t i; + uint16_t max_total_rate_per_spads; + uint16_t target_rate = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + uint32_t temp = 0xFFFF; +#ifdef VL53L1_LOG_ENABLE + uint16_t eff_spad_cnt = + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count; +#endif + + LOG_FUNCTION_START(""); + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = 0; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: peak signal count rate mcps:"); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "%u actual effective spads: %u\n", + presults->VL53L1_p_002[0].peak_signal_count_rate_mcps, + presults->VL53L1_p_002[0].VL53L1_p_006); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: active results: %u\n", + presults->active_results); + + max_total_rate_per_spads = + presults->VL53L1_p_002[0].total_rate_per_spad_mcps; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: max total rate per spad at start: %u\n", + max_total_rate_per_spads); + + for (i = 1; i < presults->active_results; i++) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone total rate per spad: zone_id: %u,", + i); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "total rate per spad: %u\n", + presults->VL53L1_p_002[i].total_rate_per_spad_mcps); + + if (presults->VL53L1_p_002[i].total_rate_per_spad_mcps > + max_total_rate_per_spads) + max_total_rate_per_spads = + presults->VL53L1_p_002[i].total_rate_per_spad_mcps; + + } + + if (max_total_rate_per_spads == 0) { + + temp = 0xFFFF; + } else { + + temp = target_rate << 14; + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 1: temp: %u\n", + temp); + + + temp = temp / max_total_rate_per_spads; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 2: temp: %u\n", + temp); + + + if (temp > 0xFFFF) + temp = 0xFFFF; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 3: temp: %u\n", + temp); + } + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = + (uint16_t)temp; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone_id: %u, target_rate: %u,", + zone_id, + target_rate); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "max_total_rate_per_spads: %u, requested_spads: %u\n", + max_total_rate_per_spads, + eff_spad_cnt); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_histogram_config_t *phist_cfg = &(pdev->hist_cfg); + VL53L1_histogram_config_t *pmulti_hist = + &(pzone_cfg->multizone_hist_cfg); + + uint8_t next_range_is_odd_timing = (pstate->cfg_stream_count) % 2; + + LOG_FUNCTION_START(""); + + + if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB timing\n"); + if (!next_range_is_odd_timing) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB EVEN timing\n" + ); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + } + + + + if (status == VL53L1_ERROR_NONE) { + VL53L1_copy_hist_bins_to_static_cfg( + phist_cfg, + &(pdev->stat_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t stream_divider; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + stream_divider = pdev->gen_cfg.global_config__stream_divider; + + if (stream_divider == 0) { + + + *pinternal_stream_count = external_stream_count; + + } else if (*pinternal_stream_count_val == (stream_divider-1)) { + + + if (*pinternal_stream_count == 0xFF) + *pinternal_stream_count = 0x80; + else + *pinternal_stream_count = *pinternal_stream_count + 1; + + + *pinternal_stream_count_val = 0; + + } else { + + + *pinternal_stream_count_val = *pinternal_stream_count_val + 1; + } + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "UPDINTSTREAMCOUNT internal_steam_count: %d,", + *pinternal_stream_count); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "internal_stream_count_val: %d, divider: %d\n", + *pinternal_stream_count_val, + stream_divider); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + LOG_FUNCTION_END(status); + return status; +} + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + uint8_t system__interrupt_config; + + system__interrupt_config = pintconf->intr_mode_distance; + system__interrupt_config |= ((pintconf->intr_mode_rate) << 2); + system__interrupt_config |= ((pintconf->intr_new_measure_ready) << 5); + system__interrupt_config |= ((pintconf->intr_no_target) << 6); + system__interrupt_config |= ((pintconf->intr_combined_mode) << 7); + + return system__interrupt_config; +} + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config) +{ + VL53L1_GPIO_interrupt_config_t intconf; + + intconf.intr_mode_distance = system__interrupt_config & 0x03; + intconf.intr_mode_rate = (system__interrupt_config >> 2) & 0x03; + intconf.intr_new_measure_ready = (system__interrupt_config >> 5) & 0x01; + intconf.intr_no_target = (system__interrupt_config >> 6) & 0x01; + intconf.intr_combined_mode = (system__interrupt_config >> 7) & 0x01; + + + intconf.threshold_rate_low = 0; + intconf.threshold_rate_high = 0; + intconf.threshold_distance_low = 0; + intconf.threshold_distance_high = 0; + + return intconf; +} + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dyn_cfg.system__thresh_high = threshold_high; + pdev->dyn_cfg.system__thresh_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->gen_cfg.system__thresh_rate_high = threshold_high; + pdev->gen_cfg.system__thresh_rate_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_GPIO_distance_threshold( + Dev, + pintconf->threshold_distance_high, + pintconf->threshold_distance_low); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_GPIO_rate_threshold( + Dev, + pintconf->threshold_rate_high, + pintconf->threshold_rate_low); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[2]; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + vcsel_period_a); + + + + timeout_mclks = phasecal_timeout_us << 12; + timeout_mclks = timeout_mclks + (macro_period_us>>1); + timeout_mclks = timeout_mclks / macro_period_us; + + if (timeout_mclks > 0xFF) + pdev->gen_cfg.phasecal_config__timeout_macrop = 0xFF; + else + pdev->gen_cfg.phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + pdev->tim_cfg.range_config__vcsel_period_a = vcsel_period_a; + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP, + pdev->gen_cfg.phasecal_config__timeout_macrop); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + buffer[0] = pdev->tim_cfg.range_config__vcsel_period_a; + buffer[1] = pdev->tim_cfg.range_config__vcsel_period_a; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + + pdev->customer.ref_spad_char__total_rate_target_mcps = + total_rate_target_mcps; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS, + total_rate_target_mcps); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__SIGMA_THRESH, + max_count_rate_rtn_limit_mcps); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS, + min_count_rate_rtn_limit_mcps); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[5]; + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + pssc_cfg->VL53L1_p_009); + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + pssc_cfg->timeout_us, + macro_period_us); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_CAL_CONFIG__VCSEL_START, + pssc_cfg->vcsel_start); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH, + pssc_cfg->vcsel_width); + + + + buffer[0] = (uint8_t)((timeout_encoded & 0x0000FF00) >> 8); + buffer[1] = (uint8_t) (timeout_encoded & 0x000000FF); + buffer[2] = pssc_cfg->VL53L1_p_009; + buffer[3] = (uint8_t)((pssc_cfg->rate_limit_mcps & 0x0000FF00) >> 8); + buffer[4] = (uint8_t) (pssc_cfg->rate_limit_mcps & 0x000000FF); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI, + buffer, + 5); + + + + buffer[0] = pssc_cfg->VL53L1_p_009; + buffer[1] = pssc_cfg->VL53L1_p_009; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_NVM_BIST__CTRL, + pssc_cfg->array_select); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int i = 0; + + uint8_t VL53L1_p_002[512]; + uint8_t *pdata = &VL53L1_p_002[0]; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV, + pdata, + 512); + + + pdata = &VL53L1_p_002[0]; + for (i = 0; i < VL53L1_NO_OF_SPAD_ENABLES; i++) { + pspad_rates->rate_data[i] = + (uint16_t)VL53L1_decode_unsigned_integer(pdata, 2); + pdata += 2; + } + + + + pspad_rates->VL53L1_p_023 = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->no_of_values = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->fractional_bits = 15; + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + + VL53L1_range_results_t *presults = &(pres->range_results); + VL53L1_range_data_t *pxmonitor = &(presults->xmonitor); + + uint32_t peak_duration_us = pxmonitor->peak_duration_us; + + uint64_t temp64a; + uint64_t temp64z; + + LOG_FUNCTION_START(""); + + if (peak_duration_us == 0) + peak_duration_us = 1000; + + temp64a = pxmonitor->VL53L1_p_021 + + pxmonitor->VL53L1_p_020; + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + + temp64z = pconfig->noise_margin * pxmonitor->VL53L1_p_006; + if (temp64z == 0) + temp64z = 1; + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + + pint->required_samples = (uint32_t)temp64a; + + + if (pint->required_samples < 2) + pint->required_samples = 2; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int16_t x_gradient_scaler; + int16_t y_gradient_scaler; + uint32_t orig_xtalk_offset; + int16_t orig_x_gradient; + int16_t orig_y_gradient; + uint8_t histo_merge_nb; + uint8_t i; + int32_t itemp32; + uint32_t SmudgeFactor; + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pC = &(pdev->xtalk_cal); + uint32_t *pcpo; + uint32_t max, nXtalk, cXtalk; + uint8_t merge_enabled; + + + LOG_FUNCTION_START(""); + + merge_enabled = (pdev->tuning_parms.tp_hist_merge == 1) && + (VL53L1DevDataGet(Dev, CurrentParameters.PresetMode) == + VL53L1_PRESETMODE_RANGING); + + + if (add_smudge == 1) { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out + + (uint32_t)pconfig->smudge_margin; + } else { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out; + } + + + orig_xtalk_offset = + pX->nvm_default__crosstalk_compensation_plane_offset_kcps; + + orig_x_gradient = + pX->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pX->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + if (((pconfig->user_scaler_set == 0) || + (pconfig->scaler_calc_method == 1)) && + (pC->algo__crosstalk_compensation_plane_offset_kcps != 0)) { + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + if (histo_merge_nb == 0) + histo_merge_nb = 1; + if (!merge_enabled) + orig_xtalk_offset = + pC->algo__crosstalk_compensation_plane_offset_kcps; + else + orig_xtalk_offset = + pC->algo__xtalk_cpo_HistoMerge_kcps[histo_merge_nb-1]; + + orig_x_gradient = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + if ((pconfig->user_scaler_set == 0) && (orig_x_gradient == 0)) + pout->gradient_zero_flag |= 0x01; + + if ((pconfig->user_scaler_set == 0) && (orig_y_gradient == 0)) + pout->gradient_zero_flag |= 0x02; + + + + if (orig_xtalk_offset == 0) + orig_xtalk_offset = 1; + + + + if (pconfig->user_scaler_set == 1) { + x_gradient_scaler = pconfig->x_gradient_scaler; + y_gradient_scaler = pconfig->y_gradient_scaler; + } else { + + x_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_x_gradient) << 6), + orig_xtalk_offset); + pconfig->x_gradient_scaler = x_gradient_scaler; + y_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_y_gradient) << 6), + orig_xtalk_offset); + pconfig->y_gradient_scaler = y_gradient_scaler; + } + + + + if (pconfig->scaler_calc_method == 0) { + + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + x_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + y_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } else if (pconfig->scaler_calc_method == 1) { + + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 16)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_x_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 80)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_y_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } + + + if (pconfig->smudge_corr_apply_enabled == 1 && + (soft_update != 1)) { + pout->new_xtalk_applied_flag = 1; + nXtalk = pout->algo__crosstalk_compensation_plane_offset_kcps; + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + max = pdev->tuning_parms.tp_hist_merge_max_size; + pcpo = &(pC->algo__xtalk_cpo_HistoMerge_kcps[0]); + if ((histo_merge_nb > 0) && merge_enabled && (nXtalk != 0)) { + cXtalk = + pC->algo__xtalk_cpo_HistoMerge_kcps[histo_merge_nb-1]; + SmudgeFactor = cXtalk * 1000 / nXtalk; + if (SmudgeFactor >= pconfig->max_smudge_factor) + pout->new_xtalk_applied_flag = 0; + else if (SmudgeFactor > 0) + for (i = 0; i < max; i++) { + *pcpo *= 1000; + *pcpo /= SmudgeFactor; + pcpo++; + } + } + if (pout->new_xtalk_applied_flag) { + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pout->algo__crosstalk_compensation_plane_offset_kcps; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps = + pout->algo__crosstalk_compensation_x_plane_gradient_kcps; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps = + pout->algo__crosstalk_compensation_y_plane_gradient_kcps; + + if (pconfig->smudge_corr_single_apply == 1) { + + pconfig->smudge_corr_apply_enabled = 0; + pconfig->smudge_corr_single_apply = 0; + } + } + } + + + if (soft_update != 1) + pout->smudge_corr_valid = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +#define CONT_CONTINUE 0 +#define CONT_NEXT_LOOP 1 +#define CONT_RESET 2 +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + VL53L1_smudge_corrector_data_t *pout = + &(pres->range_results.smudge_corrector_data); + VL53L1_range_results_t *pR = &(pres->range_results); + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + + uint8_t run_smudge_detection = 0; + uint8_t merging_complete = 0; + uint8_t run_nodetect = 0; + uint8_t ambient_check = 0; + int32_t itemp32 = 0; + uint64_t utemp64 = 0; + uint8_t continue_processing = CONT_CONTINUE; + uint32_t xtalk_offset_out = 0; + uint32_t xtalk_offset_in = 0; + uint32_t current_xtalk = 0; + uint32_t smudge_margin_adjusted = 0; + uint8_t i = 0; + uint8_t nodetect_index = 0; + uint16_t amr; + uint32_t cco; + uint8_t histo_merge_nb; + uint8_t merge_enabled; + + + LOG_FUNCTION_START(""); + + merge_enabled = (pdev->tuning_parms.tp_hist_merge == 1) && + (VL53L1DevDataGet(Dev, CurrentParameters.PresetMode) == + VL53L1_PRESETMODE_RANGING); + + VL53L1_compute_histo_merge_nb(Dev, &histo_merge_nb); + if ((histo_merge_nb == 0) || (!merge_enabled)) + histo_merge_nb = 1; + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + + ambient_check = (pconfig->smudge_corr_ambient_threshold == 0) || + ((pconfig->smudge_corr_ambient_threshold * histo_merge_nb) > + ((uint32_t)pR->xmonitor.ambient_count_rate_mcps)); + + + merging_complete = ((!merge_enabled) || + (histo_merge_nb == pdev->tuning_parms.tp_hist_merge_max_size)); + + run_smudge_detection = + (pconfig->smudge_corr_enabled == 1) && + ambient_check && + (pR->xmonitor.range_status + == VL53L1_DEVICEERROR_RANGECOMPLETE) && + merging_complete; + + + if ((pR->xmonitor.range_status + != VL53L1_DEVICEERROR_RANGECOMPLETE) && + (pconfig->smudge_corr_enabled == 1)) { + + run_nodetect = 2; + for (i = 0; i < pR->active_results; i++) { + if (pR->VL53L1_p_002[i].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + if (pR->VL53L1_p_002[i].median_range_mm + <= + pconfig->nodetect_min_range_mm) { + run_nodetect = 0; + } else { + if (run_nodetect == 2) { + run_nodetect = 1; + nodetect_index = i; + } + } + } + } + + if (run_nodetect == 2) + + run_nodetect = 0; + + amr = + pR->VL53L1_p_002[nodetect_index].ambient_count_rate_mcps; + + if (run_nodetect == 1) { + + + + + utemp64 = 1000 * ((uint64_t)amr); + + + utemp64 = utemp64 << 9; + + + if (utemp64 < pconfig->nodetect_ambient_threshold) + run_nodetect = 1; + else + run_nodetect = 0; + + } + } + + + if (run_smudge_detection) { + + pint->nodetect_counter = 0; + + + VL53L1_dynamic_xtalk_correction_calc_required_samples(Dev); + + + xtalk_offset_in = + pR->xmonitor.VL53L1_p_012; + + + cco = pX->algo__crosstalk_compensation_plane_offset_kcps; + current_xtalk = ((uint32_t)cco) << 2; + + + smudge_margin_adjusted = + ((uint32_t)(pconfig->smudge_margin)) << 2; + + + itemp32 = xtalk_offset_in - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + + if (itemp32 > ((int32_t)pconfig->single_xtalk_delta)) { + if ((int32_t)xtalk_offset_in > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) { + pout->single_xtalk_delta_flag = 1; + } else { + pout->single_xtalk_delta_flag = 2; + } + } + + + pint->current_samples = pint->current_samples + 1; + + + if (pint->current_samples > pconfig->sample_limit) { + pout->sample_limit_exceeded_flag = 1; + continue_processing = CONT_RESET; + } else { + pint->accumulator = pint->accumulator + + xtalk_offset_in; + } + + if (pint->current_samples < pint->required_samples) + continue_processing = CONT_NEXT_LOOP; + + + xtalk_offset_out = + (uint32_t)(do_division_u(pint->accumulator, + pint->current_samples)); + + + itemp32 = xtalk_offset_out - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + if (continue_processing == CONT_CONTINUE && + (itemp32 >= ((int32_t)(pconfig->averaged_xtalk_delta))) + ) { + if ((int32_t)xtalk_offset_out > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) + pout->averaged_xtalk_delta_flag = 1; + else + pout->averaged_xtalk_delta_flag = 2; + } + + if (continue_processing == CONT_CONTINUE && + (itemp32 < ((int32_t)(pconfig->averaged_xtalk_delta))) + ) + + continue_processing = CONT_RESET; + + + + pout->smudge_corr_clipped = 0; + if ((continue_processing == CONT_CONTINUE) && + (pconfig->smudge_corr_clip_limit != 0)) { + if (xtalk_offset_out > + (pconfig->smudge_corr_clip_limit * histo_merge_nb)) { + pout->smudge_corr_clipped = 1; + continue_processing = CONT_RESET; + } + } + + + + if (pconfig->user_xtalk_offset_limit_hi && + (xtalk_offset_out > + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + if ((pconfig->user_xtalk_offset_limit_hi == 0) && + (xtalk_offset_out < + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + xtalk_offset_out = xtalk_offset_out >> 2; + if (xtalk_offset_out > 0x3FFFF) + xtalk_offset_out = 0x3FFFF; + + + if (continue_processing == CONT_CONTINUE) { + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + 0 + ); + + + continue_processing = CONT_RESET; + } else { + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + 1 + ); + } + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + + } + + continue_processing = CONT_CONTINUE; + if (run_nodetect == 1) { + + pint->nodetect_counter += 1; + + + if (pint->nodetect_counter < pconfig->nodetect_sample_limit) + continue_processing = CONT_NEXT_LOOP; + + + xtalk_offset_out = (uint32_t)(pconfig->nodetect_xtalk_offset); + + if (continue_processing == CONT_CONTINUE) { + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + 0 + ); + + + pout->smudge_corr_valid = 2; + + + continue_processing = CONT_RESET; + } else { + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + 1 + ); + } + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ) +{ + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + pdev->smudge_correct_config.smudge_corr_single_apply = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT; + + pdev->smudge_correct_config.smudge_margin = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT; + pdev->smudge_correct_config.noise_margin = + VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT; + pdev->smudge_correct_config.sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.single_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.averaged_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.smudge_corr_clip_limit = + VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT; + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT; + pdev->smudge_correct_config.scaler_calc_method = + 0; + pdev->smudge_correct_config.x_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.y_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.user_scaler_set = + VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT; + pdev->smudge_correct_config.nodetect_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.nodetect_xtalk_offset = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_min_range_mm = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT; + pdev->smudge_correct_config.max_smudge_factor = + VL53L1_TUNINGPARM_DYNXTALK_MAX_SMUDGE_FACTOR_DEFAULT; + + + pdev->smudge_corrector_internals.current_samples = 0; + pdev->smudge_corrector_internals.required_samples = 0; + pdev->smudge_corrector_internals.accumulator = 0; + pdev->smudge_corrector_internals.nodetect_counter = 0; + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ) +{ + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_smudge_corrector_data_t *pdata; + + LOG_FUNCTION_START(""); + + + pdata = &(pres->range_results.smudge_corrector_data); + + pdata->smudge_corr_valid = 0; + pdata->smudge_corr_clipped = 0; + pdata->single_xtalk_delta_flag = 0; + pdata->averaged_xtalk_delta_flag = 0; + pdata->sample_limit_exceeded_flag = 0; + pdata->gradient_zero_flag = 0; + pdata->new_xtalk_applied_flag = 0; + + pdata->algo__crosstalk_compensation_plane_offset_kcps = 0; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ) +{ + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + pdev->xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + memset(&pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps[0], 0, + sizeof(pdev->xtalk_cal.algo__xtalk_cpo_HistoMerge_kcps)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ) +{ + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->low_power_auto_data.vhv_loop_bound = + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT; + pdev->low_power_auto_data.is_low_power_auto_mode = 0; + pdev->low_power_auto_data.low_power_auto_range_count = 0; + pdev->low_power_auto_data.saved_interrupt_config = 0; + pdev->low_power_auto_data.saved_vhv_init = 0; + pdev->low_power_auto_data.saved_vhv_timeout = 0; + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ) +{ + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + pdev->low_power_auto_data.low_power_auto_range_count = 0xFF; + + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + + if (pdev->low_power_auto_data.saved_vhv_init != 0) + pdev->stat_nvm.vhv_config__init = + pdev->low_power_auto_data.saved_vhv_init; + if (pdev->low_power_auto_data.saved_vhv_timeout != 0) + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + pdev->low_power_auto_data.saved_vhv_timeout; + + + pdev->gen_cfg.phasecal_config__override = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ) +{ + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + plpadata->is_low_power_auto_mode = 1; + + + plpadata->low_power_auto_range_count = 0; + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + + + + VL53L1_SEQUENCE_RANGE_EN; + + + pgeneral->dss_config__manual_effective_spads_select = 200 << 8; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev) +{ + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + pdev->low_power_auto_data.saved_vhv_init = + pdev->stat_nvm.vhv_config__init; + pdev->low_power_auto_data.saved_vhv_timeout = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + + pdev->stat_nvm.vhv_config__init &= 0x7F; + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (pdev->low_power_auto_data.vhv_loop_bound << 2); + + pdev->gen_cfg.phasecal_config__override = 0x01; + pdev->low_power_auto_data.first_run_phasecal_result = + pdev->dbg_results.phasecal_result__vcsel_start; + pdev->gen_cfg.cal_config__vcsel_start = + pdev->low_power_auto_data.first_run_phasecal_result; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev) +{ + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_system_results_t *pS = &(pdev->sys_results); + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t utemp32a; + + LOG_FUNCTION_START(""); + + + + + utemp32a = + pS->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 + + pS->result__ambient_count_rate_mcps_sd0; + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + + utemp32a = utemp32a << 16; + + + if (pdev->sys_results.result__dss_actual_effective_spads_sd0 == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + utemp32a = utemp32a / + pdev->sys_results.result__dss_actual_effective_spads_sd0; + + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = + utemp32a; + + + utemp32a = pdev->stat_cfg.dss_config__target_total_rate_mcps << + 16; + + + if (pdev->low_power_auto_data.dss__total_rate_per_spad_mcps + == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + utemp32a = utemp32a / + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps; + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + pdev->low_power_auto_data.dss__required_spads = + (uint16_t)utemp32a; + + + pdev->gen_cfg.dss_config__manual_effective_spads_select + = pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + } + + } + + if (status == VL53L1_ERROR_DIVISION_BY_ZERO) { + + + + pdev->low_power_auto_data.dss__required_spads = 0x8000; + + + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + status = VL53L1_ERROR_NONE; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_compute_histo_merge_nb( + VL53L1_DEV Dev, uint8_t *histo_merge_nb) +{ + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t i, timing; + uint8_t sum = 0; + + timing = (pdev->hist_data.bin_seq[0] == 7 ? 1 : 0); + for (i = 0; i < VL53L1_BIN_REC_SIZE; i++) + if (pdev->multi_bins_rec[i][timing][7] > 0) + sum++; + *histo_merge_nb = sum; + + return status; +} + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_core_support.c b/drivers/input/misc/vl53L1/src/vl53l1_core_support.c new file mode 100644 index 0000000000000000000000000000000000000000..d5f59212f2ea97abf99a06fd04328a19055c5f99 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_core_support.c @@ -0,0 +1,637 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core_support.h" +#include "vl53l1_platform_user_data.h" +#include "vl53l1_platform_user_defines.h" + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency) +{ + + + uint32_t pll_period_us = 0; + + LOG_FUNCTION_START(""); + + if (fast_osc_frequency > 0) + pll_period_us = (0x01 << 30) / fast_osc_frequency; + + + + LOG_FUNCTION_END(0); + + return pll_period_us; +} + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t elapsed_mclks) +{ + + + uint64_t tmp_long_int = 0; + uint32_t duration_us = 0; + + + duration_us = window_vclks * pll_period_us; + + + duration_us = duration_us >> 12; + + + tmp_long_int = (uint64_t)duration_us; + + + duration_us = elapsed_mclks * vcsel_parm_pclks; + + + duration_us = duration_us >> 4; + + + tmp_long_int = tmp_long_int * (uint64_t)duration_us; + + + tmp_long_int = tmp_long_int >> 12; + + + if (tmp_long_int > 0xFFFFFFFF) + tmp_long_int = 0xFFFFFFFF; + + duration_us = (uint32_t)tmp_long_int; + + return duration_us; +} + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration) +{ + uint64_t total_hist_counts = 0; + uint64_t xtalk_per_spad = 0; + uint32_t rate_per_spad_kcps = 0; + + + + + + + uint64_t dividend = ((uint64_t)VL53L1_p_013 + * 1000 * 256); + + if (num_spads != 0) + total_hist_counts = do_division_u( + dividend, (uint64_t)num_spads); + + + + if (duration > 0) { + + + uint64_t dividend = (((uint64_t)(total_hist_counts << 11)) + + ((uint64_t)duration / 2)); + + xtalk_per_spad = do_division_u(dividend, (uint64_t)duration); + } else { + xtalk_per_spad = (uint64_t)(total_hist_counts << 11); + } + + rate_per_spad_kcps = (uint32_t)xtalk_per_spad; + + return rate_per_spad_kcps; +} + + +uint32_t VL53L1_isqrt(uint32_t num) +{ + + + + uint32_t res = 0; + uint32_t bit = 1 << 30; + + + while (bit > num) + bit >>= 2; + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else { + res >>= 1; + } + bit >>= 2; + } + + return res; +} + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata) +{ + + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + + LOG_FUNCTION_START(""); + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period(pdata->VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)pdata->phasecal_result__reference_phase; + VL53L1_p_017 += (2048 * (uint32_t)pdata->phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * (uint32_t)pdata->cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + pdata->zero_distance_phase = (uint16_t)VL53L1_p_017; + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata) +{ + + + uint8_t bin = 0; + int32_t VL53L1_p_032 = 0; + + LOG_FUNCTION_START(""); + + + + VL53L1_hist_find_min_max_bin_values(pdata); + + + + VL53L1_p_032 = + (int32_t)VL53L1_isqrt((uint32_t)pdata->min_bin_value); + VL53L1_p_032 *= ambient_threshold_sigma; + VL53L1_p_032 += 0x07; + VL53L1_p_032 = VL53L1_p_032 >> 4; + VL53L1_p_032 += pdata->min_bin_value; + + + + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) + if (pdata->bin_data[bin] < VL53L1_p_032) { + pdata->ambient_events_sum += pdata->bin_data[bin]; + pdata->number_of_ambient_samples++; + } + + + + if (pdata->number_of_ambient_samples > 0) { + pdata->VL53L1_p_004 = + pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_samples/2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_samples; + } + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + uint8_t bin = 0; + uint8_t lc = 0; + uint8_t i = 0; + + + + if ((pdata->bin_seq[0] & 0x07) == 0x07) { + + i = 0; + for (lc = 0; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + if ((pdata->bin_seq[lc] & 0x07) != 0x07) { + pdata->bin_seq[i] = pdata->bin_seq[lc]; + pdata->bin_rep[i] = pdata->bin_rep[lc]; + i++; + } + } + + + + for (lc = i; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + pdata->bin_seq[lc] = VL53L1_MAX_BIN_SEQUENCE_CODE + 1; + pdata->bin_rep[lc] = 0; + } + } + + if (pdata->number_of_ambient_bins > 0) { + + + for (bin = pdata->number_of_ambient_bins; + bin < pdata->VL53L1_p_023; bin++) { + pdata->bin_data[bin-pdata->number_of_ambient_bins] = + pdata->bin_data[bin]; + } + + + pdata->VL53L1_p_024 = + pdata->VL53L1_p_024 - + pdata->number_of_ambient_bins; + pdata->number_of_ambient_bins = 0; + } +} + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency) +{ + + + uint32_t pll_period_us = 0; + uint32_t pll_period_mm = 0; + + LOG_FUNCTION_START(""); + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + pll_period_mm = + VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 * + (pll_period_us >> 2); + + + pll_period_mm = (pll_period_mm + (0x01<<15)) >> 16; + + LOG_FUNCTION_END(0); + + return pll_period_mm; +} + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us) +{ + + + uint32_t tmp_int = 0; + uint32_t frac_bits = 7; + uint16_t rate_mcps = 0; + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_MAX) + tmp_int = VL53L1_SPAD_TOTAL_COUNT_MAX; + else if (VL53L1_p_008 > 0) + tmp_int = (uint32_t)VL53L1_p_008; + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + frac_bits = 3; + else + frac_bits = 7; + + + if (time_us > 0) + tmp_int = ((tmp_int << frac_bits) + (time_us / 2)) / time_us; + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + tmp_int = tmp_int << 4; + + + + if (tmp_int > 0xFFFF) + tmp_int = 0xFFFF; + + rate_mcps = (uint16_t)tmp_int; + + return rate_mcps; +} + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value) +{ + + uint32_t tmp_int = 0; + + + uint16_t rate_per_spad = 0; + + + + + + if (num_spads > 0) { + tmp_int = (peak_count_rate << 8) << frac_bits; + tmp_int = (tmp_int + + ((uint32_t)num_spads / 2)) / + (uint32_t)num_spads; + } else { + tmp_int = ((peak_count_rate) << frac_bits); + } + + + + if (tmp_int > max_output_value) + tmp_int = max_output_value; + + rate_per_spad = (uint16_t)tmp_int; + + return rate_per_spad; +} + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm) +{ + + + uint32_t pll_period_us = 0; + int64_t tmp_long_int = 0; + int32_t range_mm = 0; + int32_t range_mm_10 = 0; + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + tmp_long_int = (int64_t)VL53L1_p_017 - (int64_t)zero_distance_phase; + + + + tmp_long_int = tmp_long_int * (int64_t)pll_period_us; + + + + tmp_long_int = tmp_long_int / (0x01 << 9); + + + + tmp_long_int = tmp_long_int * VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8; + + + + tmp_long_int = tmp_long_int / (0x01 << 22); + + + range_mm = (int32_t)tmp_long_int + range_offset_mm; + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + + if (fractional_bits == 0) { + range_mm_10 = range_mm * 10; + range_mm_10 = range_mm_10 / (0x01 << 2); + if ((range_mm_10 % 10) < 5) + range_mm = (int16_t)(range_mm_10 / 10); + else + range_mm = (int16_t)(range_mm_10 / 10 + 1); + } else if (fractional_bits == 1) + range_mm = range_mm / (0x01 << 1); + + return range_mm; +} + + +uint8_t VL53L1_decode_vcsel_period(uint8_t vcsel_period_reg) +{ + + + uint8_t VL53L1_p_031 = 0; + + VL53L1_p_031 = (vcsel_period_reg + 1) << 1; + + return VL53L1_p_031; +} + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist) +{ + + + phist->cal_config__vcsel_start = + pxtalk->cal_config__vcsel_start; + phist->VL53L1_p_019 = + pxtalk->VL53L1_p_019; + phist->VL53L1_p_022 = + pxtalk->VL53L1_p_022; + + phist->phasecal_result__reference_phase = + pxtalk->phasecal_result__reference_phase; + phist->phasecal_result__vcsel_start = + pxtalk->phasecal_result__vcsel_start; + + phist->vcsel_width = + pxtalk->vcsel_width; + phist->zero_distance_phase = + pxtalk->zero_distance_phase; + + phist->zone_id = pxtalk->zone_id; + phist->VL53L1_p_023 = pxtalk->VL53L1_p_023; + phist->time_stamp = pxtalk->time_stamp; +} + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + uint16_t i = 0; + + pdata->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pdata->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + pdata->number_of_ambient_bins = 0; + + pdata->result__interrupt_status = 0; + pdata->result__range_status = 0; + pdata->result__report_status = 0; + pdata->result__stream_count = 0; + + pdata->result__dss_actual_effective_spads = 0; + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_009 = 0; + pdata->VL53L1_p_019 = 0; + pdata->total_periods_elapsed = 0; + + pdata->min_bin_value = 0; + pdata->max_bin_value = 0; + + pdata->zero_distance_phase = 0; + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + pdata->VL53L1_p_004 = 0; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_seq[i] = (uint8_t)i; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + + for (i = 0; i < VL53L1_HISTOGRAM_BUFFER_SIZE; i++) + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + + +} + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol) +{ + + + + if (spad_number > 127) { + *prow = 8 + ((255-spad_number) & 0x07); + *pcol = (spad_number-128) >> 3; + } else { + *prow = spad_number & 0x07; + *pcol = (127-spad_number) >> 3; + } +} + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata) +{ + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) { + + if (bin == 0 || pdata->min_bin_value >= pdata->bin_data[bin]) + pdata->min_bin_value = pdata->bin_data[bin]; + + if (bin == 0 || pdata->max_bin_value <= pdata->bin_data[bin]) + pdata->max_bin_value = pdata->bin_data[bin]; + + } + + LOG_FUNCTION_END(0); + +} + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + if (pdata->number_of_ambient_bins > 0) { + + pdata->number_of_ambient_samples = + pdata->number_of_ambient_bins; + + + + pdata->ambient_events_sum = 0; + for (bin = 0; bin < pdata->number_of_ambient_bins; bin++) + pdata->ambient_events_sum += pdata->bin_data[bin]; + + pdata->VL53L1_p_004 = pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_bins / 2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_bins; + + } + + LOG_FUNCTION_END(0); +} + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_error_strings.c b/drivers/input/misc/vl53L1/src/vl53l1_error_strings.c new file mode 100644 index 0000000000000000000000000000000000000000..723e549266d609b8df92cb977f0ed21aac3b043f --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_error_strings.c @@ -0,0 +1,248 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_ll_def.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, \ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(PalErrorCode); +#endif + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pPalErrorString, ""); +#else + + switch (PalErrorCode) { + case VL53L1_ERROR_NONE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NONE); + break; + case VL53L1_ERROR_CALIBRATION_WARNING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CALIBRATION_WARNING); + break; + case VL53L1_ERROR_MIN_CLIPPED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MIN_CLIPPED); + break; + case VL53L1_ERROR_UNDEFINED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNDEFINED); + break; + case VL53L1_ERROR_INVALID_PARAMS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_PARAMS); + break; + case VL53L1_ERROR_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_SUPPORTED); + break; + case VL53L1_ERROR_RANGE_ERROR: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_RANGE_ERROR); + break; + case VL53L1_ERROR_TIME_OUT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_TIME_OUT); + break; + case VL53L1_ERROR_MODE_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED); + break; + case VL53L1_ERROR_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_GPIO_NOT_EXISTING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_NOT_EXISTING); + break; + case VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED); + break; + case VL53L1_ERROR_CONTROL_INTERFACE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CONTROL_INTERFACE); + break; + case VL53L1_ERROR_INVALID_COMMAND: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_COMMAND); + break; + case VL53L1_ERROR_DIVISION_BY_ZERO: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DIVISION_BY_ZERO); + break; + case VL53L1_ERROR_REF_SPAD_INIT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_REF_SPAD_INIT); + break; + case VL53L1_ERROR_GPH_SYNC_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL); + break; + case VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL); + break; + + case VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL); + break; + case VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL); + break; + + case VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL); + break; + case VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL); + break; + case VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL); + break; + + case VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW); + break; + + case VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH); + break; + + case VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW); + break; + + case VL53L1_WARNING_XTALK_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES); + break; + case VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT); + break; + case VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT); + break; + + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD); + break; + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW); + break; + case VL53L1_ERROR_UNIT_TEST_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNIT_TEST_FAIL); + break; + case VL53L1_ERROR_FILE_READ_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_READ_FAIL); + break; + case VL53L1_ERROR_FILE_WRITE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_WRITE_FAIL); + break; + case VL53L1_ERROR_NOT_IMPLEMENTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_IMPLEMENTED); + break; + default: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } + +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_hist_char.c b/drivers/input/misc/vl53L1/src/vl53l1_hist_char.c new file mode 100644 index 0000000000000000000000000000000000000000..208868bbf9baa9bde751db021bd50d0861a0b66d --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_hist_char.c @@ -0,0 +1,162 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#include +#include + + + +#include "vl53l1_core.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_char.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[3]; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_enable_powerforce(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__VCSEL_DELAY__A0, + vcsel_delay__a0); + } + + + + if (status == VL53L1_ERROR_NONE) { + + + comms_buffer[0] = calib_1; + comms_buffer[1] = calib_2; + comms_buffer[2] = calib_3; + + status = VL53L1_WriteMulti( + Dev, + VL53L1_RANGING_CORE__CALIB_1, + comms_buffer, + 3); + } + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CALIB_2__A0, + calib_2__a0); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__SPAD_READOUT, + spad_readout); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x01, + calib_delay, + 0x04, + 0x08, + 0x14, + VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_nvm.c b/drivers/input/misc/vl53L1/src/vl53l1_nvm.c new file mode 100644 index 0000000000000000000000000000000000000000..c3c8f6e2830aebfb8d5e5e4666f203c75ff3e58f --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_nvm.c @@ -0,0 +1,1540 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm.h" + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_NVM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CLK_CTRL1, + 0x05); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + nvm_power_up_delay_us); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__MODE, + 0x01); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrWord( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB, + nvm_ctrl_pulse_width); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t nvm_addr = 0; + + LOG_FUNCTION_START(""); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "nvm_addr", nvm_addr, nvm_addr); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "count", count, count); + + for (nvm_addr = start_address; + nvm_addr < (start_address+count) ; nvm_addr++) { + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__ADDR, + nvm_addr); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x00); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_NVM_READ_TRIGGER_DELAY_US); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM, + pdata, + 4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "NVM address : 0x%02X = 0x%02X%02X%02X%02X\n", + nvm_addr, *pdata, *(pdata+1), *(pdata+2), *(pdata+3)); + + + + pdata = pdata + 4; + + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x00); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t *ptmp = NULL; + int pptmp[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__identification_model_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODEL_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_module_type = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_TYPE, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_revision_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__REVISION_ID, + 0x0000000F, + 0, + 0); + pdata->nvm__identification_module_id = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_ID, + 0x0000FFFF, + 0, + 0); + pdata->nvm__i2c_valid = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_VALID, + 0x000000FF, + 0, + 0); + pdata->nvm__i2c_device_address_ews = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__ews__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__ews__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__ews__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__fmt__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__vhv_config_unlock = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG_UNLOCK, + 0x000000FF, + 0, + 0); + pdata->nvm__ref_selvddpix = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVDDPIX, + 0x0000000F, + 0, + 0); + pdata->nvm__ref_selvquench = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVQUENCH, + 0x00000078, + 3, + 0); + pdata->nvm__regavdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x0000000C, + 2, + 0); + pdata->nvm__regdvdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_timeout__macrop = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_loop_bound = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x000000FC, + 2, + 0); + pdata->nvm__vhv_count_threshold = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__COUNT_THRESH, + 0x000000FF, + 0, + 0); + pdata->nvm__vhv_offset = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__OFFSET, + 0x0000003F, + 0, + 0); + pdata->nvm__vhv_init_enable = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x00000080, + 7, + 0); + pdata->nvm__vhv_init_value = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_lock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_LOCK_BYTE, + 0x000000FF, + 0, + 0); + pdata->nvm__laser_safety_unlock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE, + 0x000000FF, + 0, + 0); + + + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc3[i] = *ptmp++; + + + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc3[i] = *ptmp++; + + + pdata->nvm__fmt__roi_config__mode_roi_centre_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__roi_config__mode_roi_x_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__roi_config__mode_roi_y_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__fmt__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + pdata->nvm__customer_space_programmed = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__i2c_device_address = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__cust__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + buf_size, + pbuffer + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX, + &(pdata->fmt_optical_centre)); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + buf_size, + pbuffer + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX, + &(pdata->fmt_peak_rate_map)); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_additional_offset_cal_data( + buf_size, + pbuffer + + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX, + &(pdata->fmt_add_offset_data)); + + + + pptmp[0] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE; + pptmp[1] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK; + pptmp[2] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK; + pptmp[3] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT; + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + buf_size, + pbuffer + pptmp[i], + &(pdata->fmt_range_data[i])); + } + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_info( + buf_size, + pbuffer, + &(pdata->fmt_info)); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_ews_info( + buf_size, + pbuffer, + &(pdata->ews_info)); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint16_t tmp = 0; + + if (buf_size < VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + + tmp = 0x0100; + tmp -= (uint16_t)*(pbuffer + 2); + if (tmp > 0x0FF) + tmp = 0; + + pdata->x_centre = (uint8_t)tmp; + pdata->y_centre = *(pbuffer + 3); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t *ptmp = NULL; + uint8_t i = 0; + + if (buf_size < VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->cal_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->cal_reflectance_pc = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + pdata->cal_reflectance_pc = + pdata->cal_reflectance_pc >> 6; + + pdata->max_samples = VL53L1_NVM_PEAK_RATE_MAP_SAMPLES; + pdata->width = VL53L1_NVM_PEAK_RATE_MAP_WIDTH; + pdata->height = VL53L1_NVM_PEAK_RATE_MAP_HEIGHT; + + ptmp = pbuffer + 4; + for (i = 0 ; i < VL53L1_NVM_PEAK_RATE_MAP_SAMPLES ; i++) { + pdata->peak_rate_mcps[i] = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, ptmp); + ptmp += 2; + } + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__mm_inner_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->result__mm_outer_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + + pdata->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__actual_effective_rtn_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->ref_spad_array__num_requested_ref_spads = + *(pbuffer+2); + + pdata->ref_spad_array__ref_location = + *(pbuffer+3); + + pdata->result__peak_signal_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__ambient_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + pdata->result__peak_signal_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 8); + + pdata->result__ambient_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 10); + + pdata->measured_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 12); + + pdata->measured_distance_stdev_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 14); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__fmt__fgc[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_0, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[1] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_1, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[2] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_2 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_3 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_4 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[5] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_5 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[6] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[7] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[8] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_7, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[9] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_8, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[10] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_9 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[11] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_10 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[12] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_11 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[13] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_12 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[14] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[15] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[16] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_14, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[17] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_15, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[18] = 0x00; + + pdata->nvm__fmt__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__map_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__map_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__year = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__month = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__day = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x000000F8, + 3, + 0); + pdata->nvm__fmt__module_date_phase = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__time = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__TIME, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__site_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__SITE_ID, + 0x000000FF, + 0, + 0); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__ews__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__ews__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__probe_card_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x000000F0, + 4, + 0); + pdata->nvm__ews__probe_card_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x0000000F, + 0, + 0); + pdata->nvm__ews__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__lot[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_0, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[1] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_1 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[2] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2 - 1, + 0x00000FC0, + 6, + 32); + pdata->nvm__ews__lot[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2, + 0x0000003F, + 0, + 32); + pdata->nvm__ews__lot[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_3, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[5] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_4 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[6] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_5 - 1, + 0x00000FC0, + 6, + 32); + + pdata->nvm__ews__lot[7] = 0x00; + + pdata->nvm__ews__wafer = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__WAFER, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__xcoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__XCOORD, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__ycoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__YCOORD, + 0x000000FF, + 0, + 0); + + return status; + +} + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data) +{ + SUPPRESS_UNUSED_WARNING(pnvm_info); + SUPPRESS_UNUSED_WARNING(pnvm_data); +} + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_enable( + Dev, + 0x0004, + VL53L1_NVM_POWER_UP_DELAY_US); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_read( + Dev, + start_address, + count, + pnvm_raw_data); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_disable(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t nvm_data[VL53L1_NVM_SIZE_IN_BYTES]; + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(nvm_format); + + + + status = VL53L1_read_nvm_raw_data( + Dev, + 0, + VL53L1_NVM_SIZE_IN_BYTES >> 2, + nvm_data); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_format_decode( + VL53L1_NVM_SIZE_IN_BYTES, + nvm_data, + pnvm_info); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t nvm_data[VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE + >> 2), + nvm_data); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE, + nvm_data, + pcentre); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t nvm_data[VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE + >> 2), + nvm_data); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t nvm_data[VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX >> 2), + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE >> 2), + nvm_data); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_decode_additional_offset_cal_data( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t nvm_data[VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(range_results_select >> 2), + (uint8_t)(VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES >> 2), + nvm_data); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES, + nvm_data, + prange_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_nvm_debug.c b/drivers/input/misc/vl53L1/src/vl53l1_nvm_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..0c2e01fd8fed95fb8cfdcfd88305e6f9a747d4c9 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_nvm_debug.c @@ -0,0 +1,1032 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_debug.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags) +{ + + + int i = 0; + + LOG_FUNCTION_START(""); + + for (i = 0 ; i < VL53L1_NVM_SIZE_IN_BYTES ; i++) { + if (i % 4 == 0) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n NVM Addr 0x%02X : 0x", + i/4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%02X", + *pnvm_raw_data++); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + LOG_FUNCTION_END(0); +} + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_model_id", + pdata->nvm__identification_model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_type", + pdata->nvm__identification_module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_revision_id", + pdata->nvm__identification_revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_id", + pdata->nvm__identification_module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_valid", + pdata->nvm__i2c_valid); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_device_address_ews", + pdata->nvm__i2c_device_address_ews); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__ews__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__ews__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_trim_max", + pdata->nvm__ews__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_freq_set", + pdata->nvm__ews__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__slow_osc_calibration", + pdata->nvm__ews__slow_osc_calibration); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_trim_max", + pdata->nvm__fmt__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_freq_set", + pdata->nvm__fmt__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__slow_osc_calibration", + pdata->nvm__fmt__slow_osc_calibration); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_config_unlock", + pdata->nvm__vhv_config_unlock); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvddpix", + pdata->nvm__ref_selvddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvquench", + pdata->nvm__ref_selvquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regavdd1v2_sel", + pdata->nvm__regavdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regdvdd1v2_sel", + pdata->nvm__regdvdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_timeout__macrop", + pdata->nvm__vhv_timeout__macrop); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_loop_bound", + pdata->nvm__vhv_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_count_threshold", + pdata->nvm__vhv_count_threshold); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_offset", + pdata->nvm__vhv_offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_enable", + pdata->nvm__vhv_init_enable); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_value", + pdata->nvm__vhv_init_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ll", + pdata->nvm__laser_safety_vcsel_trim_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ll", + pdata->nvm__laser_safety_vcsel_selion_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ll", + pdata->nvm__laser_safety_vcsel_selion_max_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ll", + pdata->nvm__laser_safety_mult_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ll", + pdata->nvm__laser_safety_clip_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ld", + pdata->nvm__laser_safety_vcsel_trim_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ld", + pdata->nvm__laser_safety_vcsel_selion_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ld", + pdata->nvm__laser_safety_vcsel_selion_max_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ld", + pdata->nvm__laser_safety_mult_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ld", + pdata->nvm__laser_safety_clip_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_lock_byte", + pdata->nvm__laser_safety_lock_byte); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_unlock_byte", + pdata->nvm__laser_safety_unlock_byte); + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc3[i]); + } + + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc3[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_centre_spad", + pdata->nvm__fmt__roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_x_size", + pdata->nvm__fmt__roi_config__mode_roi_x_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_y_size", + pdata->nvm__fmt__roi_config__mode_roi_y_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_man__ref_location", + pdata->nvm__fmt__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__inner_offset_mm", + pdata->nvm__fmt__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__outer_offset_mm", + pdata->nvm__fmt__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_0", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_1", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__customer_space_programmed", + pdata->nvm__customer_space_programmed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__i2c_device_address", + pdata->nvm__cust__i2c_device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_man__ref_location", + pdata->nvm__cust__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__inner_offset_mm", + pdata->nvm__cust__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__outer_offset_mm", + pdata->nvm__cust__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__cust__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_0", + pdata->nvm__cust__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_1", + pdata->nvm__cust__spare__host_config__nvm_config_spare_1); + + + + sprintf( + ppre_text, + "%sfmt_optical_centre.", pprefix); + + VL53L1_print_optical_centre( + &(pdata->fmt_optical_centre), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + sprintf( + ppre_text, + "%sfmt_peak_rate_map.", pprefix); + + VL53L1_print_cal_peak_rate_map( + &(pdata->fmt_peak_rate_map), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + sprintf( + ppre_text, + "%sfmt_add_offset_data.", + pprefix); + + VL53L1_print_additional_offset_cal_data( + &(pdata->fmt_add_offset_data), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + sprintf( + ppre_text, + "%sfmt_range_data[%u].", + pprefix, i); + + VL53L1_print_decoded_nvm_fmt_range_data( + &(pdata->fmt_range_data[i]), + ppre_text, + trace_flags); + } + + sprintf( + ppre_text, + "%sfmt_info.", + pprefix); + + VL53L1_print_decoded_nvm_fmt_info( + &(pdata->fmt_info), + ppre_text, + trace_flags); + + sprintf( + ppre_text, + "%sews_info.", + pprefix); + + VL53L1_print_decoded_nvm_ews_info( + &(pdata->ews_info), + ppre_text, + trace_flags); +} + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__actual_effective_rtn_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__actual_effective_rtn_spads", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__num_requested_ref_spads", + pdata->ref_spad_array__num_requested_ref_spads); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__ref_location", + pdata->ref_spad_array__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__peak_signal_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__peak_signal_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->measured_distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->measured_distance_stdev_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_stdev_mm", + fp_text); +} + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__fmt__fgc", + pdata->nvm__fmt__fgc); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_major", + pdata->nvm__fmt__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_minor", + pdata->nvm__fmt__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_major", + pdata->nvm__fmt__map_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_minor", + pdata->nvm__fmt__map_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__year", + pdata->nvm__fmt__year); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__month", + pdata->nvm__fmt__month); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__day", + pdata->nvm__fmt__day); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__module_date_phase", + pdata->nvm__fmt__module_date_phase); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__time", + pdata->nvm__fmt__time); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__tester_id", + pdata->nvm__fmt__tester_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__site_id", + pdata->nvm__fmt__site_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_major", + pdata->nvm__ews__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_minor", + pdata->nvm__ews__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_major", + pdata->nvm__ews__probe_card_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_minor", + pdata->nvm__ews__probe_card_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__tester_id", + pdata->nvm__ews__tester_id); +} + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__ews__lot", + pdata->nvm__ews__lot); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__wafer", + pdata->nvm__ews__wafer); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__xcoord", + pdata->nvm__ews__xcoord); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__ycoord", + pdata->nvm__ews__ycoord); +} + +#endif + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_register_funcs.c b/drivers/input/misc/vl53L1/src/vl53l1_register_funcs.c new file mode 100644 index 0000000000000000000000000000000000000000..0e3ae3b7de2617aeed0daad2ab0b3f3f2437300b --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_register_funcs.c @@ -0,0 +1,4131 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_funcs.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_REGISTERS, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_REGISTERS, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_REGISTERS,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->i2c_slave__device_address & 0x7F; + *(pbuffer + 1) = + pdata->ana_config__vhv_ref_sel_vddpix & 0xF; + *(pbuffer + 2) = + pdata->ana_config__vhv_ref_sel_vquench & 0x7F; + *(pbuffer + 3) = + pdata->ana_config__reg_avdd1v2_sel & 0x3; + *(pbuffer + 4) = + pdata->ana_config__fast_osc__trim & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->osc_measured__fast_osc__frequency, + 2, + pbuffer + 5); + *(pbuffer + 7) = + pdata->vhv_config__timeout_macrop_loop_bound; + *(pbuffer + 8) = + pdata->vhv_config__count_thresh; + *(pbuffer + 9) = + pdata->vhv_config__offset & 0x3F; + *(pbuffer + 10) = + pdata->vhv_config__init; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->i2c_slave__device_address = + (*(pbuffer + 0)) & 0x7F; + pdata->ana_config__vhv_ref_sel_vddpix = + (*(pbuffer + 1)) & 0xF; + pdata->ana_config__vhv_ref_sel_vquench = + (*(pbuffer + 2)) & 0x7F; + pdata->ana_config__reg_avdd1v2_sel = + (*(pbuffer + 3)) & 0x3; + pdata->ana_config__fast_osc__trim = + (*(pbuffer + 4)) & 0x7F; + pdata->osc_measured__fast_osc__frequency = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 5)); + pdata->vhv_config__timeout_macrop_loop_bound = + (*(pbuffer + 7)); + pdata->vhv_config__count_thresh = + (*(pbuffer + 8)); + pdata->vhv_config__offset = + (*(pbuffer + 9)) & 0x3F; + pdata->vhv_config__init = + (*(pbuffer + 10)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_static_nvm_managed( + pdata, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_nvm_managed( + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->global_config__spad_enables_ref_0; + *(pbuffer + 1) = + pdata->global_config__spad_enables_ref_1; + *(pbuffer + 2) = + pdata->global_config__spad_enables_ref_2; + *(pbuffer + 3) = + pdata->global_config__spad_enables_ref_3; + *(pbuffer + 4) = + pdata->global_config__spad_enables_ref_4; + *(pbuffer + 5) = + pdata->global_config__spad_enables_ref_5 & 0xF; + *(pbuffer + 6) = + pdata->global_config__ref_en_start_select; + *(pbuffer + 7) = + pdata->ref_spad_man__num_requested_ref_spads & 0x3F; + *(pbuffer + 8) = + pdata->ref_spad_man__ref_location & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + 2, + pbuffer + 9); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + 2, + pbuffer + 11); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + 2, + pbuffer + 13); + VL53L1_i2c_encode_uint16_t( + pdata->ref_spad_char__total_rate_target_mcps, + 2, + pbuffer + 15); + VL53L1_i2c_encode_int16_t( + pdata->algo__part_to_part_range_offset_mm & 0x1FFF, + 2, + pbuffer + 17); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__inner_offset_mm, + 2, + pbuffer + 19); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__outer_offset_mm, + 2, + pbuffer + 21); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->global_config__spad_enables_ref_0 = + (*(pbuffer + 0)); + pdata->global_config__spad_enables_ref_1 = + (*(pbuffer + 1)); + pdata->global_config__spad_enables_ref_2 = + (*(pbuffer + 2)); + pdata->global_config__spad_enables_ref_3 = + (*(pbuffer + 3)); + pdata->global_config__spad_enables_ref_4 = + (*(pbuffer + 4)); + pdata->global_config__spad_enables_ref_5 = + (*(pbuffer + 5)) & 0xF; + pdata->global_config__ref_en_start_select = + (*(pbuffer + 6)); + pdata->ref_spad_man__num_requested_ref_spads = + (*(pbuffer + 7)) & 0x3F; + pdata->ref_spad_man__ref_location = + (*(pbuffer + 8)) & 0x3; + pdata->algo__crosstalk_compensation_plane_offset_kcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 9)); + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 11)); + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 13)); + pdata->ref_spad_char__total_rate_target_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 15)); + pdata->algo__part_to_part_range_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 17)) & 0x1FFF; + pdata->mm_config__inner_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 19)); + pdata->mm_config__outer_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_customer_nvm_managed( + pdata, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_customer_nvm_managed( + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__target_total_rate_mcps, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->debug__ctrl & 0x1; + *(pbuffer + 3) = + pdata->test_mode__ctrl & 0xF; + *(pbuffer + 4) = + pdata->clk_gating__ctrl & 0xF; + *(pbuffer + 5) = + pdata->nvm_bist__ctrl & 0x1F; + *(pbuffer + 6) = + pdata->nvm_bist__num_nvm_words & 0x7F; + *(pbuffer + 7) = + pdata->nvm_bist__start_address & 0x7F; + *(pbuffer + 8) = + pdata->host_if__status & 0x1; + *(pbuffer + 9) = + pdata->pad_i2c_hv__config; + *(pbuffer + 10) = + pdata->pad_i2c_hv__extsup_config & 0x1; + *(pbuffer + 11) = + pdata->gpio_hv_pad__ctrl & 0x3; + *(pbuffer + 12) = + pdata->gpio_hv_mux__ctrl & 0x1F; + *(pbuffer + 13) = + pdata->gpio__tio_hv_status & 0x3; + *(pbuffer + 14) = + pdata->gpio__fio_hv_status & 0x3; + *(pbuffer + 15) = + pdata->ana_config__spad_sel_pswidth & 0x7; + *(pbuffer + 16) = + pdata->ana_config__vcsel_pulse_width_offset & 0x1F; + *(pbuffer + 17) = + pdata->ana_config__fast_osc__config_ctrl & 0x1; + *(pbuffer + 18) = + pdata->sigma_estimator__effective_pulse_width_ns; + *(pbuffer + 19) = + pdata->sigma_estimator__effective_ambient_width_ns; + *(pbuffer + 20) = + pdata->sigma_estimator__sigma_ref_mm; + *(pbuffer + 21) = + pdata->algo__crosstalk_compensation_valid_height_mm; + *(pbuffer + 22) = + pdata->spare_host_config__static_config_spare_0; + *(pbuffer + 23) = + pdata->spare_host_config__static_config_spare_1; + VL53L1_i2c_encode_uint16_t( + pdata->algo__range_ignore_threshold_mcps, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->algo__range_ignore_valid_height_mm; + *(pbuffer + 27) = + pdata->algo__range_min_clip; + *(pbuffer + 28) = + pdata->algo__consistency_check__tolerance & 0xF; + *(pbuffer + 29) = + pdata->spare_host_config__static_config_spare_2; + *(pbuffer + 30) = + pdata->sd_config__reset_stages_msb & 0xF; + *(pbuffer + 31) = + pdata->sd_config__reset_stages_lsb; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_config__target_total_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->debug__ctrl = + (*(pbuffer + 2)) & 0x1; + pdata->test_mode__ctrl = + (*(pbuffer + 3)) & 0xF; + pdata->clk_gating__ctrl = + (*(pbuffer + 4)) & 0xF; + pdata->nvm_bist__ctrl = + (*(pbuffer + 5)) & 0x1F; + pdata->nvm_bist__num_nvm_words = + (*(pbuffer + 6)) & 0x7F; + pdata->nvm_bist__start_address = + (*(pbuffer + 7)) & 0x7F; + pdata->host_if__status = + (*(pbuffer + 8)) & 0x1; + pdata->pad_i2c_hv__config = + (*(pbuffer + 9)); + pdata->pad_i2c_hv__extsup_config = + (*(pbuffer + 10)) & 0x1; + pdata->gpio_hv_pad__ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->gpio_hv_mux__ctrl = + (*(pbuffer + 12)) & 0x1F; + pdata->gpio__tio_hv_status = + (*(pbuffer + 13)) & 0x3; + pdata->gpio__fio_hv_status = + (*(pbuffer + 14)) & 0x3; + pdata->ana_config__spad_sel_pswidth = + (*(pbuffer + 15)) & 0x7; + pdata->ana_config__vcsel_pulse_width_offset = + (*(pbuffer + 16)) & 0x1F; + pdata->ana_config__fast_osc__config_ctrl = + (*(pbuffer + 17)) & 0x1; + pdata->sigma_estimator__effective_pulse_width_ns = + (*(pbuffer + 18)); + pdata->sigma_estimator__effective_ambient_width_ns = + (*(pbuffer + 19)); + pdata->sigma_estimator__sigma_ref_mm = + (*(pbuffer + 20)); + pdata->algo__crosstalk_compensation_valid_height_mm = + (*(pbuffer + 21)); + pdata->spare_host_config__static_config_spare_0 = + (*(pbuffer + 22)); + pdata->spare_host_config__static_config_spare_1 = + (*(pbuffer + 23)); + pdata->algo__range_ignore_threshold_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->algo__range_ignore_valid_height_mm = + (*(pbuffer + 26)); + pdata->algo__range_min_clip = + (*(pbuffer + 27)); + pdata->algo__consistency_check__tolerance = + (*(pbuffer + 28)) & 0xF; + pdata->spare_host_config__static_config_spare_2 = + (*(pbuffer + 29)); + pdata->sd_config__reset_stages_msb = + (*(pbuffer + 30)) & 0xF; + pdata->sd_config__reset_stages_lsb = + (*(pbuffer + 31)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_static_config( + pdata, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_config( + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph_config__stream_count_update_value; + *(pbuffer + 1) = + pdata->global_config__stream_divider; + *(pbuffer + 2) = + pdata->system__interrupt_config_gpio; + *(pbuffer + 3) = + pdata->cal_config__vcsel_start & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->cal_config__repeat_rate & 0xFFF, + 2, + pbuffer + 4); + *(pbuffer + 6) = + pdata->global_config__vcsel_width & 0x7F; + *(pbuffer + 7) = + pdata->phasecal_config__timeout_macrop; + *(pbuffer + 8) = + pdata->phasecal_config__target; + *(pbuffer + 9) = + pdata->phasecal_config__override & 0x1; + *(pbuffer + 11) = + pdata->dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_high, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_low, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__manual_effective_spads_select, + 2, + pbuffer + 16); + *(pbuffer + 18) = + pdata->dss_config__manual_block_select; + *(pbuffer + 19) = + pdata->dss_config__aperture_attenuation; + *(pbuffer + 20) = + pdata->dss_config__max_spads_limit; + *(pbuffer + 21) = + pdata->dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph_config__stream_count_update_value = + (*(pbuffer + 0)); + pdata->global_config__stream_divider = + (*(pbuffer + 1)); + pdata->system__interrupt_config_gpio = + (*(pbuffer + 2)); + pdata->cal_config__vcsel_start = + (*(pbuffer + 3)) & 0x7F; + pdata->cal_config__repeat_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)) & 0xFFF; + pdata->global_config__vcsel_width = + (*(pbuffer + 6)) & 0x7F; + pdata->phasecal_config__timeout_macrop = + (*(pbuffer + 7)); + pdata->phasecal_config__target = + (*(pbuffer + 8)); + pdata->phasecal_config__override = + (*(pbuffer + 9)) & 0x1; + pdata->dss_config__roi_mode_control = + (*(pbuffer + 11)) & 0x7; + pdata->system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->dss_config__manual_block_select = + (*(pbuffer + 18)); + pdata->dss_config__aperture_attenuation = + (*(pbuffer + 19)); + pdata->dss_config__max_spads_limit = + (*(pbuffer + 20)); + pdata->dss_config__min_spads_limit = + (*(pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_general_config( + pdata, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_general_config( + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 8) = + pdata->range_config__timeout_macrop_b_lo; + *(pbuffer + 9) = + pdata->range_config__vcsel_period_b & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->range_config__valid_phase_high; + VL53L1_i2c_encode_uint32_t( + pdata->system__intermeasurement_period, + 4, + pbuffer + 18); + *(pbuffer + 22) = + pdata->system__fractional_enable & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->range_config__timeout_macrop_b_hi = + (*(pbuffer + 7)) & 0xF; + pdata->range_config__timeout_macrop_b_lo = + (*(pbuffer + 8)); + pdata->range_config__vcsel_period_b = + (*(pbuffer + 9)) & 0x3F; + pdata->range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->range_config__valid_phase_high = + (*(pbuffer + 15)); + pdata->system__intermeasurement_period = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 18)); + pdata->system__fractional_enable = + (*(pbuffer + 22)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_timing_config( + pdata, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_timing_config( + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->system__grouped_parameter_hold_0 & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_high, + 2, + pbuffer + 1); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_low, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 6) = + pdata->system__seed_config & 0x7; + *(pbuffer + 7) = + pdata->sd_config__woi_sd0; + *(pbuffer + 8) = + pdata->sd_config__woi_sd1; + *(pbuffer + 9) = + pdata->sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 10) = + pdata->sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 11) = + pdata->system__grouped_parameter_hold_1 & 0x3; + *(pbuffer + 12) = + pdata->sd_config__first_order_select & 0x3; + *(pbuffer + 13) = + pdata->sd_config__quantifier & 0xF; + *(pbuffer + 14) = + pdata->roi_config__user_roi_centre_spad; + *(pbuffer + 15) = + pdata->roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 16) = + pdata->system__sequence_config; + *(pbuffer + 17) = + pdata->system__grouped_parameter_hold & 0x3; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->system__grouped_parameter_hold_0 = + (*(pbuffer + 0)) & 0x3; + pdata->system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->system__enable_xtalk_per_quadrant = + (*(pbuffer + 5)) & 0x1; + pdata->system__seed_config = + (*(pbuffer + 6)) & 0x7; + pdata->sd_config__woi_sd0 = + (*(pbuffer + 7)); + pdata->sd_config__woi_sd1 = + (*(pbuffer + 8)); + pdata->sd_config__initial_phase_sd0 = + (*(pbuffer + 9)) & 0x7F; + pdata->sd_config__initial_phase_sd1 = + (*(pbuffer + 10)) & 0x7F; + pdata->system__grouped_parameter_hold_1 = + (*(pbuffer + 11)) & 0x3; + pdata->sd_config__first_order_select = + (*(pbuffer + 12)) & 0x3; + pdata->sd_config__quantifier = + (*(pbuffer + 13)) & 0xF; + pdata->roi_config__user_roi_centre_spad = + (*(pbuffer + 14)); + pdata->roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 15)); + pdata->system__sequence_config = + (*(pbuffer + 16)); + pdata->system__grouped_parameter_hold = + (*(pbuffer + 17)) & 0x3; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_dynamic_config( + pdata, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_dynamic_config( + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->power_management__go1_power_force & 0x1; + *(pbuffer + 1) = + pdata->system__stream_count_ctrl & 0x1; + *(pbuffer + 2) = + pdata->firmware__enable & 0x1; + *(pbuffer + 3) = + pdata->system__interrupt_clear & 0x3; + *(pbuffer + 4) = + pdata->system__mode_start; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->power_management__go1_power_force = + (*(pbuffer + 0)) & 0x1; + pdata->system__stream_count_ctrl = + (*(pbuffer + 1)) & 0x1; + pdata->firmware__enable = + (*(pbuffer + 2)) & 0x1; + pdata->system__interrupt_clear = + (*(pbuffer + 3)) & 0x3; + pdata->system__mode_start = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_system_control( + pdata, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_control( + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->result__range_status; + *(pbuffer + 2) = + pdata->result__report_status & 0xF; + *(pbuffer + 3) = + pdata->result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_2_sd1, + 2, + pbuffer + 40); + *(pbuffer + 42) = + pdata->result__spare_3_sd1; + *(pbuffer + 43) = + pdata->result__thresh_info; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->result__range_status = + (*(pbuffer + 1)); + pdata->result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->result__stream_count = + (*(pbuffer + 3)); + pdata->result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->result__spare_3_sd1 = + (*(pbuffer + 42)); + pdata->result__thresh_info = + (*(pbuffer + 43)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_system_results( + pdata, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_core_results( + pdata, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__reference_phase, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->phasecal_result__vcsel_start & 0x7F; + *(pbuffer + 3) = + pdata->ref_spad_char_result__num_actual_ref_spads & 0x3F; + *(pbuffer + 4) = + pdata->ref_spad_char_result__ref_location & 0x3; + *(pbuffer + 5) = + pdata->vhv_result__coldboot_status & 0x1; + *(pbuffer + 6) = + pdata->vhv_result__search_result & 0x3F; + *(pbuffer + 7) = + pdata->vhv_result__latest_setting & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->result__osc_calibrate_val & 0x3FF, + 2, + pbuffer + 8); + *(pbuffer + 10) = + pdata->ana_config__powerdown_go1 & 0x3; + *(pbuffer + 11) = + pdata->ana_config__ref_bg_ctrl & 0x3; + *(pbuffer + 12) = + pdata->ana_config__regdvdd1v2_ctrl & 0xF; + *(pbuffer + 13) = + pdata->ana_config__osc_slow_ctrl & 0x7; + *(pbuffer + 14) = + pdata->test_mode__status & 0x1; + *(pbuffer + 15) = + pdata->firmware__system_status & 0x3; + *(pbuffer + 16) = + pdata->firmware__mode_status; + *(pbuffer + 17) = + pdata->firmware__secondary_mode_status; + VL53L1_i2c_encode_uint16_t( + pdata->firmware__cal_repeat_rate_counter & 0xFFF, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_high, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_low, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->gph__system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 27) = + pdata->gph__spare_0 & 0x7; + *(pbuffer + 28) = + pdata->gph__sd_config__woi_sd0; + *(pbuffer + 29) = + pdata->gph__sd_config__woi_sd1; + *(pbuffer + 30) = + pdata->gph__sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 31) = + pdata->gph__sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 32) = + pdata->gph__sd_config__first_order_select & 0x3; + *(pbuffer + 33) = + pdata->gph__sd_config__quantifier & 0xF; + *(pbuffer + 34) = + pdata->gph__roi_config__user_roi_centre_spad; + *(pbuffer + 35) = + pdata->gph__roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 36) = + pdata->gph__system__sequence_config; + *(pbuffer + 37) = + pdata->gph__gph_id & 0x1; + *(pbuffer + 38) = + pdata->system__interrupt_set & 0x3; + *(pbuffer + 39) = + pdata->interrupt_manager__enables & 0x1F; + *(pbuffer + 40) = + pdata->interrupt_manager__clear & 0x1F; + *(pbuffer + 41) = + pdata->interrupt_manager__status & 0x1F; + *(pbuffer + 42) = + pdata->mcu_to_host_bank__wr_access_en & 0x1; + *(pbuffer + 43) = + pdata->power_management__go1_reset_status & 0x1; + *(pbuffer + 44) = + pdata->pad_startup_mode__value_ro & 0x3; + *(pbuffer + 45) = + pdata->pad_startup_mode__value_ctrl & 0x3F; + VL53L1_i2c_encode_uint32_t( + pdata->pll_period_us & 0x3FFFF, + 4, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->interrupt_scheduler__data_out, + 4, + pbuffer + 50); + *(pbuffer + 54) = + pdata->nvm_bist__complete & 0x1; + *(pbuffer + 55) = + pdata->nvm_bist__status & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->phasecal_result__reference_phase = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->phasecal_result__vcsel_start = + (*(pbuffer + 2)) & 0x7F; + pdata->ref_spad_char_result__num_actual_ref_spads = + (*(pbuffer + 3)) & 0x3F; + pdata->ref_spad_char_result__ref_location = + (*(pbuffer + 4)) & 0x3; + pdata->vhv_result__coldboot_status = + (*(pbuffer + 5)) & 0x1; + pdata->vhv_result__search_result = + (*(pbuffer + 6)) & 0x3F; + pdata->vhv_result__latest_setting = + (*(pbuffer + 7)) & 0x3F; + pdata->result__osc_calibrate_val = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)) & 0x3FF; + pdata->ana_config__powerdown_go1 = + (*(pbuffer + 10)) & 0x3; + pdata->ana_config__ref_bg_ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->ana_config__regdvdd1v2_ctrl = + (*(pbuffer + 12)) & 0xF; + pdata->ana_config__osc_slow_ctrl = + (*(pbuffer + 13)) & 0x7; + pdata->test_mode__status = + (*(pbuffer + 14)) & 0x1; + pdata->firmware__system_status = + (*(pbuffer + 15)) & 0x3; + pdata->firmware__mode_status = + (*(pbuffer + 16)); + pdata->firmware__secondary_mode_status = + (*(pbuffer + 17)); + pdata->firmware__cal_repeat_rate_counter = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)) & 0xFFF; + pdata->gph__system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->gph__system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->gph__system__enable_xtalk_per_quadrant = + (*(pbuffer + 26)) & 0x1; + pdata->gph__spare_0 = + (*(pbuffer + 27)) & 0x7; + pdata->gph__sd_config__woi_sd0 = + (*(pbuffer + 28)); + pdata->gph__sd_config__woi_sd1 = + (*(pbuffer + 29)); + pdata->gph__sd_config__initial_phase_sd0 = + (*(pbuffer + 30)) & 0x7F; + pdata->gph__sd_config__initial_phase_sd1 = + (*(pbuffer + 31)) & 0x7F; + pdata->gph__sd_config__first_order_select = + (*(pbuffer + 32)) & 0x3; + pdata->gph__sd_config__quantifier = + (*(pbuffer + 33)) & 0xF; + pdata->gph__roi_config__user_roi_centre_spad = + (*(pbuffer + 34)); + pdata->gph__roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 35)); + pdata->gph__system__sequence_config = + (*(pbuffer + 36)); + pdata->gph__gph_id = + (*(pbuffer + 37)) & 0x1; + pdata->system__interrupt_set = + (*(pbuffer + 38)) & 0x3; + pdata->interrupt_manager__enables = + (*(pbuffer + 39)) & 0x1F; + pdata->interrupt_manager__clear = + (*(pbuffer + 40)) & 0x1F; + pdata->interrupt_manager__status = + (*(pbuffer + 41)) & 0x1F; + pdata->mcu_to_host_bank__wr_access_en = + (*(pbuffer + 42)) & 0x1; + pdata->power_management__go1_reset_status = + (*(pbuffer + 43)) & 0x1; + pdata->pad_startup_mode__value_ro = + (*(pbuffer + 44)) & 0x3; + pdata->pad_startup_mode__value_ctrl = + (*(pbuffer + 45)) & 0x3F; + pdata->pll_period_us = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 46)) & 0x3FFFF; + pdata->interrupt_scheduler__data_out = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 50)); + pdata->nvm_bist__complete = + (*(pbuffer + 54)) & 0x1; + pdata->nvm_bist__status = + (*(pbuffer + 55)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_debug_results( + pdata, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->identification__model_id; + *(pbuffer + 1) = + pdata->identification__module_type; + *(pbuffer + 2) = + pdata->identification__revision_id; + VL53L1_i2c_encode_uint16_t( + pdata->identification__module_id, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->ana_config__fast_osc__trim_max & 0x7F; + *(pbuffer + 6) = + pdata->ana_config__fast_osc__freq_set & 0x7; + *(pbuffer + 7) = + pdata->ana_config__vcsel_trim & 0x7; + *(pbuffer + 8) = + pdata->ana_config__vcsel_selion & 0x3F; + *(pbuffer + 9) = + pdata->ana_config__vcsel_selion_max & 0x3F; + *(pbuffer + 10) = + pdata->protected_laser_safety__lock_bit & 0x1; + *(pbuffer + 11) = + pdata->laser_safety__key & 0x7F; + *(pbuffer + 12) = + pdata->laser_safety__key_ro & 0x1; + *(pbuffer + 13) = + pdata->laser_safety__clip & 0x3F; + *(pbuffer + 14) = + pdata->laser_safety__mult & 0x3F; + *(pbuffer + 15) = + pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 16) = + pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 17) = + pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 18) = + pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 19) = + pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 20) = + pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 21) = + pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 22) = + pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 23) = + pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 24) = + pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 25) = + pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 26) = + pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 27) = + pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 28) = + pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 29) = + pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 30) = + pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 31) = + pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 32) = + pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 33) = + pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 34) = + pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 35) = + pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 36) = + pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 37) = + pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 38) = + pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 39) = + pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 40) = + pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 41) = + pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 42) = + pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 43) = + pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 44) = + pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 45) = + pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 46) = + pdata->global_config__spad_enables_rtn_31; + *(pbuffer + 47) = + pdata->roi_config__mode_roi_centre_spad; + *(pbuffer + 48) = + pdata->roi_config__mode_roi_xy_size; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->identification__model_id = + (*(pbuffer + 0)); + pdata->identification__module_type = + (*(pbuffer + 1)); + pdata->identification__revision_id = + (*(pbuffer + 2)); + pdata->identification__module_id = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->ana_config__fast_osc__trim_max = + (*(pbuffer + 5)) & 0x7F; + pdata->ana_config__fast_osc__freq_set = + (*(pbuffer + 6)) & 0x7; + pdata->ana_config__vcsel_trim = + (*(pbuffer + 7)) & 0x7; + pdata->ana_config__vcsel_selion = + (*(pbuffer + 8)) & 0x3F; + pdata->ana_config__vcsel_selion_max = + (*(pbuffer + 9)) & 0x3F; + pdata->protected_laser_safety__lock_bit = + (*(pbuffer + 10)) & 0x1; + pdata->laser_safety__key = + (*(pbuffer + 11)) & 0x7F; + pdata->laser_safety__key_ro = + (*(pbuffer + 12)) & 0x1; + pdata->laser_safety__clip = + (*(pbuffer + 13)) & 0x3F; + pdata->laser_safety__mult = + (*(pbuffer + 14)) & 0x3F; + pdata->global_config__spad_enables_rtn_0 = + (*(pbuffer + 15)); + pdata->global_config__spad_enables_rtn_1 = + (*(pbuffer + 16)); + pdata->global_config__spad_enables_rtn_2 = + (*(pbuffer + 17)); + pdata->global_config__spad_enables_rtn_3 = + (*(pbuffer + 18)); + pdata->global_config__spad_enables_rtn_4 = + (*(pbuffer + 19)); + pdata->global_config__spad_enables_rtn_5 = + (*(pbuffer + 20)); + pdata->global_config__spad_enables_rtn_6 = + (*(pbuffer + 21)); + pdata->global_config__spad_enables_rtn_7 = + (*(pbuffer + 22)); + pdata->global_config__spad_enables_rtn_8 = + (*(pbuffer + 23)); + pdata->global_config__spad_enables_rtn_9 = + (*(pbuffer + 24)); + pdata->global_config__spad_enables_rtn_10 = + (*(pbuffer + 25)); + pdata->global_config__spad_enables_rtn_11 = + (*(pbuffer + 26)); + pdata->global_config__spad_enables_rtn_12 = + (*(pbuffer + 27)); + pdata->global_config__spad_enables_rtn_13 = + (*(pbuffer + 28)); + pdata->global_config__spad_enables_rtn_14 = + (*(pbuffer + 29)); + pdata->global_config__spad_enables_rtn_15 = + (*(pbuffer + 30)); + pdata->global_config__spad_enables_rtn_16 = + (*(pbuffer + 31)); + pdata->global_config__spad_enables_rtn_17 = + (*(pbuffer + 32)); + pdata->global_config__spad_enables_rtn_18 = + (*(pbuffer + 33)); + pdata->global_config__spad_enables_rtn_19 = + (*(pbuffer + 34)); + pdata->global_config__spad_enables_rtn_20 = + (*(pbuffer + 35)); + pdata->global_config__spad_enables_rtn_21 = + (*(pbuffer + 36)); + pdata->global_config__spad_enables_rtn_22 = + (*(pbuffer + 37)); + pdata->global_config__spad_enables_rtn_23 = + (*(pbuffer + 38)); + pdata->global_config__spad_enables_rtn_24 = + (*(pbuffer + 39)); + pdata->global_config__spad_enables_rtn_25 = + (*(pbuffer + 40)); + pdata->global_config__spad_enables_rtn_26 = + (*(pbuffer + 41)); + pdata->global_config__spad_enables_rtn_27 = + (*(pbuffer + 42)); + pdata->global_config__spad_enables_rtn_28 = + (*(pbuffer + 43)); + pdata->global_config__spad_enables_rtn_29 = + (*(pbuffer + 44)); + pdata->global_config__spad_enables_rtn_30 = + (*(pbuffer + 45)); + pdata->global_config__spad_enables_rtn_31 = + (*(pbuffer + 46)); + pdata->roi_config__mode_roi_centre_spad = + (*(pbuffer + 47)); + pdata->roi_config__mode_roi_xy_size = + (*(pbuffer + 48)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_nvm_copy_data( + pdata, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_nvm_copy_data( + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->prev_shadow_result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->prev_shadow_result__range_status; + *(pbuffer + 2) = + pdata->prev_shadow_result__report_status & 0xF; + *(pbuffer + 3) = + pdata->prev_shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_2_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_3_sd1, + 2, + pbuffer + 42); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->prev_shadow_result__range_status = + (*(pbuffer + 1)); + pdata->prev_shadow_result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->prev_shadow_result__stream_count = + (*(pbuffer + 3)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->prev_shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->prev_shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->prev_shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->prev_shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->prev_shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->prev_shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->prev_shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->prev_shadow_result__spare_3_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_prev_shadow_system_results( + pdata, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_system_results( + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->prev_shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->prev_shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->prev_shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->prev_shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->prev_shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->prev_shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->prev_shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_prev_shadow_core_results( + pdata, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_core_results( + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__debug_status; + *(pbuffer + 1) = + pdata->result__debug_stage; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__debug_status = + (*(pbuffer + 0)); + pdata->result__debug_stage = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_patch_debug( + pdata, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_debug( + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_high, + 2, + pbuffer + 0); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_low, + 2, + pbuffer + 2); + *(pbuffer + 4) = + pdata->gph__system__interrupt_config_gpio; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->gph__system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 2)); + pdata->gph__system__interrupt_config_gpio = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_gph_general_config( + pdata, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_general_config( + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->gph__dss_config__manual_effective_spads_select, + 2, + pbuffer + 1); + *(pbuffer + 3) = + pdata->gph__dss_config__manual_block_select; + *(pbuffer + 4) = + pdata->gph__dss_config__max_spads_limit; + *(pbuffer + 5) = + pdata->gph__dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__dss_config__roi_mode_control = + (*(pbuffer + 0)) & 0x7; + pdata->gph__dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->gph__dss_config__manual_block_select = + (*(pbuffer + 3)); + pdata->gph__dss_config__max_spads_limit = + (*(pbuffer + 4)); + pdata->gph__dss_config__min_spads_limit = + (*(pbuffer + 5)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_gph_static_config( + pdata, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_static_config( + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->gph__mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->gph__mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->gph__mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->gph__range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->gph__range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->gph__range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->gph__range_config__vcsel_period_b & 0x3F; + *(pbuffer + 8) = + pdata->gph__range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 9) = + pdata->gph__range_config__timeout_macrop_b_lo; + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->gph__range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->gph__range_config__valid_phase_high; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->gph__mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->gph__mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->gph__mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->gph__range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->gph__range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->gph__range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->gph__range_config__vcsel_period_b = + (*(pbuffer + 7)) & 0x3F; + pdata->gph__range_config__timeout_macrop_b_hi = + (*(pbuffer + 8)) & 0xF; + pdata->gph__range_config__timeout_macrop_b_lo = + (*(pbuffer + 9)); + pdata->gph__range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->gph__range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->gph__range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->gph__range_config__valid_phase_high = + (*(pbuffer + 15)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_gph_timing_config( + pdata, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_timing_config( + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->firmware__internal_stream_count_div; + *(pbuffer + 1) = + pdata->firmware__internal_stream_counter_val; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->firmware__internal_stream_count_div = + (*(pbuffer + 0)); + pdata->firmware__internal_stream_counter_val = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_fw_internal( + pdata, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_fw_internal( + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->dss_calc__roi_ctrl & 0x3; + *(pbuffer + 1) = + pdata->dss_calc__spare_1; + *(pbuffer + 2) = + pdata->dss_calc__spare_2; + *(pbuffer + 3) = + pdata->dss_calc__spare_3; + *(pbuffer + 4) = + pdata->dss_calc__spare_4; + *(pbuffer + 5) = + pdata->dss_calc__spare_5; + *(pbuffer + 6) = + pdata->dss_calc__spare_6; + *(pbuffer + 7) = + pdata->dss_calc__spare_7; + *(pbuffer + 8) = + pdata->dss_calc__user_roi_spad_en_0; + *(pbuffer + 9) = + pdata->dss_calc__user_roi_spad_en_1; + *(pbuffer + 10) = + pdata->dss_calc__user_roi_spad_en_2; + *(pbuffer + 11) = + pdata->dss_calc__user_roi_spad_en_3; + *(pbuffer + 12) = + pdata->dss_calc__user_roi_spad_en_4; + *(pbuffer + 13) = + pdata->dss_calc__user_roi_spad_en_5; + *(pbuffer + 14) = + pdata->dss_calc__user_roi_spad_en_6; + *(pbuffer + 15) = + pdata->dss_calc__user_roi_spad_en_7; + *(pbuffer + 16) = + pdata->dss_calc__user_roi_spad_en_8; + *(pbuffer + 17) = + pdata->dss_calc__user_roi_spad_en_9; + *(pbuffer + 18) = + pdata->dss_calc__user_roi_spad_en_10; + *(pbuffer + 19) = + pdata->dss_calc__user_roi_spad_en_11; + *(pbuffer + 20) = + pdata->dss_calc__user_roi_spad_en_12; + *(pbuffer + 21) = + pdata->dss_calc__user_roi_spad_en_13; + *(pbuffer + 22) = + pdata->dss_calc__user_roi_spad_en_14; + *(pbuffer + 23) = + pdata->dss_calc__user_roi_spad_en_15; + *(pbuffer + 24) = + pdata->dss_calc__user_roi_spad_en_16; + *(pbuffer + 25) = + pdata->dss_calc__user_roi_spad_en_17; + *(pbuffer + 26) = + pdata->dss_calc__user_roi_spad_en_18; + *(pbuffer + 27) = + pdata->dss_calc__user_roi_spad_en_19; + *(pbuffer + 28) = + pdata->dss_calc__user_roi_spad_en_20; + *(pbuffer + 29) = + pdata->dss_calc__user_roi_spad_en_21; + *(pbuffer + 30) = + pdata->dss_calc__user_roi_spad_en_22; + *(pbuffer + 31) = + pdata->dss_calc__user_roi_spad_en_23; + *(pbuffer + 32) = + pdata->dss_calc__user_roi_spad_en_24; + *(pbuffer + 33) = + pdata->dss_calc__user_roi_spad_en_25; + *(pbuffer + 34) = + pdata->dss_calc__user_roi_spad_en_26; + *(pbuffer + 35) = + pdata->dss_calc__user_roi_spad_en_27; + *(pbuffer + 36) = + pdata->dss_calc__user_roi_spad_en_28; + *(pbuffer + 37) = + pdata->dss_calc__user_roi_spad_en_29; + *(pbuffer + 38) = + pdata->dss_calc__user_roi_spad_en_30; + *(pbuffer + 39) = + pdata->dss_calc__user_roi_spad_en_31; + *(pbuffer + 40) = + pdata->dss_calc__user_roi_0; + *(pbuffer + 41) = + pdata->dss_calc__user_roi_1; + *(pbuffer + 42) = + pdata->dss_calc__mode_roi_0; + *(pbuffer + 43) = + pdata->dss_calc__mode_roi_1; + *(pbuffer + 44) = + pdata->sigma_estimator_calc__spare_0; + VL53L1_i2c_encode_uint16_t( + pdata->vhv_result__peak_signal_rate_mcps, + 2, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->vhv_result__signal_total_events_ref, + 4, + pbuffer + 48); + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__phase_output_ref, + 2, + pbuffer + 52); + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__total_rate_per_spad, + 2, + pbuffer + 54); + *(pbuffer + 56) = + pdata->dss_result__enabled_blocks; + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__num_requested_spads, + 2, + pbuffer + 58); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__inner_intersection_rate, + 2, + pbuffer + 62); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__outer_complement_rate, + 2, + pbuffer + 64); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__total_offset, + 2, + pbuffer + 66); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_calc__xtalk_for_enabled_spads & 0xFFFFFF, + 4, + pbuffer + 68); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_user_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 72); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 76); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 80); + VL53L1_i2c_encode_uint32_t( + pdata->range_result__accum_phase, + 4, + pbuffer + 84); + VL53L1_i2c_encode_uint16_t( + pdata->range_result__offset_corrected_range, + 2, + pbuffer + 88); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_calc__roi_ctrl = + (*(pbuffer + 0)) & 0x3; + pdata->dss_calc__spare_1 = + (*(pbuffer + 1)); + pdata->dss_calc__spare_2 = + (*(pbuffer + 2)); + pdata->dss_calc__spare_3 = + (*(pbuffer + 3)); + pdata->dss_calc__spare_4 = + (*(pbuffer + 4)); + pdata->dss_calc__spare_5 = + (*(pbuffer + 5)); + pdata->dss_calc__spare_6 = + (*(pbuffer + 6)); + pdata->dss_calc__spare_7 = + (*(pbuffer + 7)); + pdata->dss_calc__user_roi_spad_en_0 = + (*(pbuffer + 8)); + pdata->dss_calc__user_roi_spad_en_1 = + (*(pbuffer + 9)); + pdata->dss_calc__user_roi_spad_en_2 = + (*(pbuffer + 10)); + pdata->dss_calc__user_roi_spad_en_3 = + (*(pbuffer + 11)); + pdata->dss_calc__user_roi_spad_en_4 = + (*(pbuffer + 12)); + pdata->dss_calc__user_roi_spad_en_5 = + (*(pbuffer + 13)); + pdata->dss_calc__user_roi_spad_en_6 = + (*(pbuffer + 14)); + pdata->dss_calc__user_roi_spad_en_7 = + (*(pbuffer + 15)); + pdata->dss_calc__user_roi_spad_en_8 = + (*(pbuffer + 16)); + pdata->dss_calc__user_roi_spad_en_9 = + (*(pbuffer + 17)); + pdata->dss_calc__user_roi_spad_en_10 = + (*(pbuffer + 18)); + pdata->dss_calc__user_roi_spad_en_11 = + (*(pbuffer + 19)); + pdata->dss_calc__user_roi_spad_en_12 = + (*(pbuffer + 20)); + pdata->dss_calc__user_roi_spad_en_13 = + (*(pbuffer + 21)); + pdata->dss_calc__user_roi_spad_en_14 = + (*(pbuffer + 22)); + pdata->dss_calc__user_roi_spad_en_15 = + (*(pbuffer + 23)); + pdata->dss_calc__user_roi_spad_en_16 = + (*(pbuffer + 24)); + pdata->dss_calc__user_roi_spad_en_17 = + (*(pbuffer + 25)); + pdata->dss_calc__user_roi_spad_en_18 = + (*(pbuffer + 26)); + pdata->dss_calc__user_roi_spad_en_19 = + (*(pbuffer + 27)); + pdata->dss_calc__user_roi_spad_en_20 = + (*(pbuffer + 28)); + pdata->dss_calc__user_roi_spad_en_21 = + (*(pbuffer + 29)); + pdata->dss_calc__user_roi_spad_en_22 = + (*(pbuffer + 30)); + pdata->dss_calc__user_roi_spad_en_23 = + (*(pbuffer + 31)); + pdata->dss_calc__user_roi_spad_en_24 = + (*(pbuffer + 32)); + pdata->dss_calc__user_roi_spad_en_25 = + (*(pbuffer + 33)); + pdata->dss_calc__user_roi_spad_en_26 = + (*(pbuffer + 34)); + pdata->dss_calc__user_roi_spad_en_27 = + (*(pbuffer + 35)); + pdata->dss_calc__user_roi_spad_en_28 = + (*(pbuffer + 36)); + pdata->dss_calc__user_roi_spad_en_29 = + (*(pbuffer + 37)); + pdata->dss_calc__user_roi_spad_en_30 = + (*(pbuffer + 38)); + pdata->dss_calc__user_roi_spad_en_31 = + (*(pbuffer + 39)); + pdata->dss_calc__user_roi_0 = + (*(pbuffer + 40)); + pdata->dss_calc__user_roi_1 = + (*(pbuffer + 41)); + pdata->dss_calc__mode_roi_0 = + (*(pbuffer + 42)); + pdata->dss_calc__mode_roi_1 = + (*(pbuffer + 43)); + pdata->sigma_estimator_calc__spare_0 = + (*(pbuffer + 44)); + pdata->vhv_result__peak_signal_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 46)); + pdata->vhv_result__signal_total_events_ref = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 48)); + pdata->phasecal_result__phase_output_ref = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 52)); + pdata->dss_result__total_rate_per_spad = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 54)); + pdata->dss_result__enabled_blocks = + (*(pbuffer + 56)); + pdata->dss_result__num_requested_spads = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 58)); + pdata->mm_result__inner_intersection_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 62)); + pdata->mm_result__outer_complement_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 64)); + pdata->mm_result__total_offset = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 66)); + pdata->xtalk_calc__xtalk_for_enabled_spads = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 68)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_user_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 72)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 76)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 80)) & 0xFFFFFF; + pdata->range_result__accum_phase = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 84)); + pdata->range_result__offset_corrected_range = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 88)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_patch_results( + pdata, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_results( + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->shadow_phasecal_result__vcsel_start; + *(pbuffer + 2) = + pdata->shadow_result__interrupt_status & 0x3F; + *(pbuffer + 3) = + pdata->shadow_result__range_status; + *(pbuffer + 4) = + pdata->shadow_result__report_status & 0xF; + *(pbuffer + 5) = + pdata->shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_0_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_1_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_2_sd1, + 2, + pbuffer + 42); + *(pbuffer + 44) = + pdata->shadow_result__spare_3_sd1; + *(pbuffer + 45) = + pdata->shadow_result__thresh_info; + *(pbuffer + 80) = + pdata->shadow_phasecal_result__reference_phase_hi; + *(pbuffer + 81) = + pdata->shadow_phasecal_result__reference_phase_lo; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_phasecal_result__vcsel_start = + (*(pbuffer + 0)); + pdata->shadow_result__interrupt_status = + (*(pbuffer + 2)) & 0x3F; + pdata->shadow_result__range_status = + (*(pbuffer + 3)); + pdata->shadow_result__report_status = + (*(pbuffer + 4)) & 0xF; + pdata->shadow_result__stream_count = + (*(pbuffer + 5)); + pdata->shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + pdata->shadow_result__spare_3_sd1 = + (*(pbuffer + 44)); + pdata->shadow_result__thresh_info = + (*(pbuffer + 45)); + pdata->shadow_phasecal_result__reference_phase_hi = + (*(pbuffer + 80)); + pdata->shadow_phasecal_result__reference_phase_lo = + (*(pbuffer + 81)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_shadow_system_results( + pdata, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_system_results( + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_encode_shadow_core_results( + pdata, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_core_results( + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_silicon_core.c b/drivers/input/misc/vl53L1/src/vl53l1_silicon_core.c new file mode 100644 index 0000000000000000000000000000000000000000..de0ca1999f1ea90ab4dffa1038b7619beca1b11b --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_silicon_core.c @@ -0,0 +1,94 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[5]; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_ReadMulti( + Dev, + VL53L1_INTERRUPT_MANAGER__ENABLES, + comms_buffer, + 5); + + if (status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pdev->dbg_results.interrupt_manager__enables = + comms_buffer[0]; + pdev->dbg_results.interrupt_manager__clear = + comms_buffer[1]; + pdev->dbg_results.interrupt_manager__status = + comms_buffer[2]; + pdev->dbg_results.mcu_to_host_bank__wr_access_en = + comms_buffer[3]; + pdev->dbg_results.power_management__go1_reset_status = + comms_buffer[4]; + + if ((pdev->sys_ctrl.power_management__go1_power_force & 0x01) + == 0x01) { + + if (((pdev->dbg_results.interrupt_manager__enables & + 0x1F) == 0x1F) && + ((pdev->dbg_results.interrupt_manager__clear + & 0x1F) == 0x1F)) + *pready = 0x01; + else + *pready = 0x00; + + } else { + + + if ((pdev->dbg_results.power_management__go1_reset_status + & 0x01) == 0x00) + *pready = 0x01; + else + *pready = 0x00; + } + + +ENDFUNC: + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_wait.c b/drivers/input/misc/vl53L1/src/vl53l1_wait.c new file mode 100644 index 0000000000000000000000000000000000000000..08659fe92a55afd8a27d3fc0fd3d03e8916a780c --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_wait.c @@ -0,0 +1,466 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_register_settings.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + status = + VL53L1_poll_for_boot_completion( + Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_boot_complete( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + uint8_t mode_start = 0; + + LOG_FUNCTION_START(""); + + + mode_start = + pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK; + + + + if ((mode_start == VL53L1_DEVICEMEASUREMENTMODE_TIMED) || + (mode_start == VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT)) { + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + status = + VL53L1_poll_for_firmware_ready( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == + VL53L1_ERROR_NONE) { + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev) +{ + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t firmware__system_status = 0; + + LOG_FUNCTION_START(""); + + + + status = + VL53L1_RdByte( + Dev, + VL53L1_FIRMWARE__SYSTEM_STATUS, + &firmware__system_status); + + + + if ((firmware__system_status & 0x01) == 0x01) { + *pready = 0x01; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + } else { + *pready = 0x00; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_FW_COLDBOOT); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + status = VL53L1_is_firmware_ready_silicon( + Dev, + pready); + + pdev->fw_ready = *pready; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t gpio__tio_hv_status = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + + + status = VL53L1_RdByte( + Dev, + VL53L1_GPIO__TIO_HV_STATUS, + &gpio__tio_hv_status); + + + + if ((gpio__tio_hv_status & 0x01) == interrupt_ready) + *pready = 0x01; + else + *pready = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + status = VL53L1_WaitUs( + Dev, + VL53L1_FIRMWARE_BOOT_TIME_US); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_FIRMWARE__SYSTEM_STATUS, + 0x01, + 0x01, + VL53L1_POLLING_DELAY_MS); + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_ll_driver_state(Dev, VL53L1_DEVICESTATE_SW_STANDBY); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t start_time_ms = 0; + uint32_t current_time_ms = 0; + int32_t poll_delay_ms = VL53L1_POLLING_DELAY_MS; + uint8_t fw_ready = 0; + + + + VL53L1_GetTickCount(&start_time_ms); + pdev->fw_ready_poll_duration_ms = 0; + + + + while ((status == VL53L1_ERROR_NONE) && + (pdev->fw_ready_poll_duration_ms < timeout_ms) && + (fw_ready == 0)) { + + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE && + fw_ready == 0 && + poll_delay_ms > 0) { + status = VL53L1_WaitMs( + Dev, + poll_delay_ms); + } + + + VL53L1_GetTickCount(¤t_time_ms); + pdev->fw_ready_poll_duration_ms = + current_time_ms - start_time_ms; + } + + if (fw_ready == 0 && status == VL53L1_ERROR_NONE) + status = VL53L1_ERROR_TIME_OUT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_GPIO__TIO_HV_STATUS, + interrupt_ready, + 0x01, + VL53L1_POLLING_DELAY_MS); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/src/vl53l1_zone_presets.c b/drivers/input/misc/vl53L1/src/vl53l1_zone_presets.c new file mode 100644 index 0000000000000000000000000000000000000000..a3e5b74b1eaa83a914aba121477fc47b76805192 --- /dev/null +++ b/drivers/input/misc/vl53L1/src/vl53l1_zone_presets.c @@ -0,0 +1,152 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_zone_presets.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t x = 0; + uint8_t y = 0; + uint16_t i = 0; + + LOG_FUNCTION_START(""); + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + + i = 0; + + for (x = 0 ; x < x_zones ; x++) { + for (y = 0 ; y < y_zones ; y++) { + + if (i < VL53L1_MAX_USER_ZONES) { + + pdata->active_zones = (uint8_t)i; + pdata->user_zones[i].height = height; + pdata->user_zones[i].width = width; + pdata->user_zones[i].x_centre = + x_off + (x * x_inc); + pdata->user_zones[i].y_centre = + y_off + (y * y_inc); + } + + i++; + } + } + + status = VL53L1_init_zone_config_histogram_bins(pdata); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + pgeneral->global_config__stream_divider = 0x05; + + + pzone_cfg->active_zones = 0x04; + + pzone_cfg->user_zones[0].height = 15; + pzone_cfg->user_zones[0].width = 7; + pzone_cfg->user_zones[0].x_centre = 4; + pzone_cfg->user_zones[0].y_centre = 8; + + pzone_cfg->user_zones[1].height = 15; + pzone_cfg->user_zones[1].width = 7; + pzone_cfg->user_zones[1].x_centre = 12; + pzone_cfg->user_zones[1].y_centre = 8; + + pzone_cfg->user_zones[2].height = 7; + pzone_cfg->user_zones[2].width = 15; + pzone_cfg->user_zones[2].x_centre = 8; + pzone_cfg->user_zones[2].y_centre = 4; + + pzone_cfg->user_zones[3].height = 7; + pzone_cfg->user_zones[3].width = 15; + pzone_cfg->user_zones[3].x_centre = 8; + pzone_cfg->user_zones[3].y_centre = 12; + + + + pzone_cfg->user_zones[4].height = 15; + pzone_cfg->user_zones[4].width = 15; + pzone_cfg->user_zones[4].x_centre = 8; + pzone_cfg->user_zones[4].y_centre = 8; + + status = VL53L1_init_zone_config_histogram_bins(pzone_cfg); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata) +{ + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i; + + LOG_FUNCTION_START(""); + + for (i = 0; i < pdata->max_zones; i++) + pdata->bin_config[i] = VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/input/misc/vl53L1/st,stmvl53l1.txt b/drivers/input/misc/vl53L1/st,stmvl53l1.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f81932590c235b37623945be36530e66db84c45 --- /dev/null +++ b/drivers/input/misc/vl53L1/st,stmvl53l1.txt @@ -0,0 +1,26 @@ +StMicroelectronis vl53l1 + +Requires properties: +- compatible: must be "st,stmvl53l1". +- reg: I2C address of the chip. +- xsdn-gpio: gpio number connected to vl53l1 reset pin. + +Optional properties: +- intr-gpio: gpio number connected to vl53l1 irq pin. +- vdd: a phandle for the regulator supplying power for vl53l1. +- pwren-gpio: gpio number use to control vl53l1 power. + +Example: + &i2c1 { + /* ... */ + + stmvl53l1: stmvl53l1@29 { + compatible = "st,stmvl53l1"; + reg = <0x29>; + xsdn-gpio = <19>; + pwren-gpio = <12>; + intr-gpio = <16>; + }; + + /* ... */ + }; diff --git a/drivers/input/misc/vl53L1/stmvl53l1-i2c.h b/drivers/input/misc/vl53L1/stmvl53l1-i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..323cd577d936f1e5c54e8840aaf0adaea62c185d --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1-i2c.h @@ -0,0 +1,115 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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 stmvl53l1-i2c.h + * Linux kernel i2c/cci wrapper for ST VL53L1 sensor i2c interface + **/ + +#ifndef STMVL53L1_I2C_H +#define STMVL53L1_I2C_H +#include +#include "stmvl53l1.h" + +struct i2c_data { + struct i2c_client *client; + /** back link to driver for interrupt and clean-up */ + struct stmvl53l1_data *vl53l1_data; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_active; + struct pinctrl_state *pins_suspend; + struct pinctrl_state *pins_release; + + + + /* reference counter */ + struct kref ref; + + /*!< if null no regulator use for power ctrl */ + struct regulator *vdd; + + /*!< power enable gpio number + * + * if -1 no gpio if vdd not avl pwr is not controllable + */ + int pwren_gpio; + + /*!< xsdn reset (low active) gpio number to device + * + * -1 mean none assume no "resetable" + */ + int xsdn_gpio; + + /*!< intr gpio number to device + * + * intr is active/low negative edge by default + * + * -1 mean none assume use polling + * @warning if the dev tree and intr gpio is require please adapt code + */ + int intr_gpio; + + /*!< device boot i2c register address + * + * boot_reg is the value of device i2c address after it is bring out + * of reset. + */ + int boot_reg; + + /*!< is set if above irq gpio got acquired */ + struct i2d_data_flags_t { + unsigned pwr_owned:1; /*!< set if pwren gpio is owned*/ + unsigned xsdn_owned:1; /*!< set if sxdn gpio is owned*/ + unsigned intr_owned:1; /*!< set if intr gpio is owned*/ + unsigned intr_started:1; /*!< set if irq is hanlde */ + } io_flag; + + /** the irq vectore assigned to gpio + * -1 if no irq hanled + */ + int irq; + + struct msgtctrl_t { + unsigned unhandled_irq_vec:1; + } msg_flag; +}; + +int stmvl53l1_init_i2c(void); +void __exit stmvl53l1_exit_i2c(void *arg); +int stmvl53l1_power_up_i2c(void *arg); +int stmvl53l1_power_down_i2c(void *arg); +int stmvl53l1_reset_release_i2c(void *arg); +int stmvl53l1_reset_hold_i2c(void *arg); +void stmvl53l1_clean_up_i2c(void); +int stmvl53l1_start_intr(void *object, int *poll_mode); +void *stmvl53l1_get(void *arg); +void stmvl53l1_put(void *arg); + +#endif /* STMVL53L1_I2C_H */ diff --git a/drivers/input/misc/vl53L1/stmvl53l1.dtbo b/drivers/input/misc/vl53L1/stmvl53l1.dtbo new file mode 100644 index 0000000000000000000000000000000000000000..94df07293396d944d3f935fb4469a3e4cdbc5720 Binary files /dev/null and b/drivers/input/misc/vl53L1/stmvl53l1.dtbo differ diff --git a/drivers/input/misc/vl53L1/stmvl53l1.h b/drivers/input/misc/vl53L1/stmvl53l1.h new file mode 100644 index 0000000000000000000000000000000000000000..0c1c9d0dda3127e9f221e6991da8964b34f7d0ac --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1.h @@ -0,0 +1,399 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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 stmvl53l1.h header for vl53l1 sensor driver + */ +#ifndef STMVL53L1_H +#define STMVL53L1_H + +#include +#include +#include +#include +#include + +#include "vl53l1_api.h" + +/** + * IPP adapt + */ +#ifdef DEBUG +# define IPP_PRINT(...) printk(__VA_ARGS__) +#else +# define IPP_PRINT(...) (void)0 +#endif + +#include "stmvl53l1_ipp.h" +#include "stmvl53l1_if.h" + +/** + * Configure the Netlink-id use + */ +#ifndef STMVL531_CFG_NETLINK_USER +#define STMVL531_CFG_NETLINK_USER 29 +#endif + +#define STMVL53L1_MAX_CCI_XFER_SZ 256 +#define STMVL53L1_DRV_NAME "stmvl53l1" + +/** + * configure usage of regulator device from device tree info + * to enable/disable sensor power + * see module-i2c or module-cci file + */ +/* define CFG_STMVL53L1_HAVE_REGULATOR */ + +#define DRIVER_VERSION "14.0.6" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * Configure max number of device the driver can support + */ +#define STMVL53L1_CFG_MAX_DEV 2 +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ +#if 0 +#define DEBUG 1 +#endif +#if 0 +#define FORCE_CONSOLE_DEBUG +#endif + +extern int stmvl53l1_enable_debug; + +#ifdef DEBUG +# ifdef FORCE_CONSOLE_DEBUG +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_info("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +# else +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_debug("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +# endif +#else +# define vl53l1_dbgmsg(...) (void)0 +#endif + +/** + * set to 0 1 activate or not debug from work (data interrupt/polling) + */ +#define WORK_DEBUG 0 +#if WORK_DEBUG +# define work_dbg(msg, ...)\ + printk("[D WK53L1] :" msg "\n", ##__VA_ARGS__) +#else +# define work_dbg(...) (void)0 +#endif + +#define vl53l1_info(str, args...) \ + pr_info("%s: " str "\n", __func__, ##args) + +#define vl53l1_errmsg(str, args...) \ + pr_err("%s: " str, __func__, ##args) + +#define vl53l1_wanrmsg(str, args...) \ + pr_warn("%s: " str, __func__, ##args) + +/* turn off poll log if not defined */ +#ifndef STMVL53L1_LOG_POLL_TIMING +# define STMVL53L1_LOG_POLL_TIMING 0 +#endif +/* turn off cci log timing if not defined */ +#ifndef STMVL53L1_LOG_CCI_TIMING +# define STMVL53L1_LOG_CCI_TIMING 0 +#endif + +/**@} */ /* ingroup mod_dbg*/ + +#include +#include +#include + +#ifndef VL53L1_FULL_KERNEL +/** if set to 1 enable ipp execution timing (if debug enabled) + * @ingroup vl53l1_mod_dbg + */ +#define IPP_LOG_TIMING 1 + +struct ipp_data_t { + struct ipp_work_t work; + struct ipp_work_t work_out; + int test_n; + /*!< buzy state 0 is idle + *any other value do not try to use (state value defined in source) + */ + int buzy; + int waited_xfer_id; + /*!< when buzy is set that is the id we are expecting + * note that value 0 is reserved and stand for "not waiting" + * as such never id 0 will be in any round trip exchange + * it's ok for daemon to use 0 in "ping" when it identify himself + */ + int status; /** if that is not 0 do not look at out work data */ + wait_queue_head_t waitq; + /*!< ipp caller are put in that queue wait while job is posted to user + * @warning ipp and dev mutex will be released before waiting + * see @ref ipp_abort + */ +#if IPP_LOG_TIMING + struct timeval start_tv, stop_tv; +#endif +}; +#endif + +struct stmvl53l1_waiters { + struct list_head list; + pid_t pid; +}; + +/* + * driver data structs + */ +struct stmvl53l1_data { + int id; /*!< multiple device id 0 based*/ + char name[64]; /*!< misc device name */ + uint8_t product_type; /*!< L1:0xCC L3:0xAA i.e. module_type in datasheet */ + + VL53L1_DevData_t stdev; /*!ipp.stop_tv) +# define stmvl531_ipp_tim_start(data)\ + do_gettimeofday(&data->ipp.start_tv) +# define stmvl531_ipp_time(data)\ + stmvl53l1_tv_dif(&data->ipp.start_tv, &data->ipp.stop_tv) +# define stmvl531_ipp_stat(data, fmt, ...)\ + vl53l1_dbgmsg("IPPSTAT " fmt "\n", ##__VA_ARGS__) +#else +# define stmvl531_ipp_tim_stop(data) (void)0 +# define stmvl531_ipp_tim_start(data) (void)0 +# define stmvl531_ipp_stat(...) (void)0 +#endif +#endif +}; + + +/** + * timeval diff in us + * + * @param pstart_tv + * @param pstop_tv + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv); + + +/** + * The device table list table is update as device get added + * we do not support adding removing device mutiple time ! + * use for clean "unload" purpose + */ +extern struct stmvl53l1_data *stmvl53l1_dev_table[]; + +int stmvl53l1_setup(struct stmvl53l1_data *data); +void stmvl53l1_cleanup(struct stmvl53l1_data *data); +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data); +#endif +int stmvl53l1_intr_handler(struct stmvl53l1_data *data); + +#ifndef VL53L1_FULL_KERNEL +/** + * request ipp to abort or stop + * + * require dev work_mutex held + * + * @warning because the "waiting" work can't be aborted we must wake it up + * it will happen and at some later time not earlier than release of lock + * if after lock release we have a new request to start the race may not be + * handled correctly + * + * @param data the device + * @return 0 if no ipp got canceled, @warning this is maybe not grant we + * can't re-sched "dev work" and re-run the worker back + */ +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data); + +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, struct ipp_work_t *work_in, + struct ipp_work_t *work_out); + +/** + * per device netlink init + * @param data + * @return + */ +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data); +/** + * per device ipp netlink cleaning + * @param data + * @return + */ +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data); + +/** + * Module init for netlink + * @return 0 on success + */ +int stmvl53l1_ipp_init(void); + +/** + * Module exit for netlink + * @return 0 on success + */ +void stmvl53l1_ipp_exit(void); + +/** + * enable and start ipp exhange + * @param n_dev number of device to run on + * @param data dev struct + * @return 0 on success + */ +int stmvl53l1_ipp_enable(int n_dev, struct stmvl53l1_data *data); +#endif + + +/* + * function pointer structs + */ + + + +#endif /* STMVL53L1_H */ diff --git a/drivers/input/misc/vl53L1/stmvl53l1_i2c.c b/drivers/input/misc/vl53L1/stmvl53l1_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..7e1715a9d6f66b14bd65d079fc28f58d9b0fde3a --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_i2c.c @@ -0,0 +1,346 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file stmvl53l1_i2c.c vl53l1 linux native i2c interface + * + */ +#include "stmvl53l1.h" +#include "stmvl53l1-i2c.h" +#include + +static inline void st_gettimeofday(struct timeval *tv) +{ + struct timespec64 now; + + ktime_get_real_ts64(&now); + tv->tv_sec = now.tv_sec; + tv->tv_usec = now.tv_nsec/1000; +} + +#if STMVL53L1_LOG_POLL_TIMING +/** + * helper to elapse time in polling + * @param ptv pointer to start time_val + + */ +# define poll_timing_log(ptv) \ + vl53l1_dbgmsg("poll in %d us\n", tv_elapsed_us(ptv)) +#else +# define poll_timing_log(...) (void)0 +#endif + +#if STMVL53L1_LOG_CCI_TIMING +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ + +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ +static uint32_t tv_elapsed_us(struct timeval *tv) +{ + struct timeval now; + + st_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - + tv->tv_usec); +} + +# define cci_access_var struct timeval cci_log_start_tv +# define cci_access_start()\ + st_gettimeofday(&cci_log_start_tv) +# define cci_access_over(fmt, ...) \ + vl53l1_dbgmsg("cci_timing %d us" fmt "\n", \ + tv_elapsed_us(&cci_log_start_tv), ##__VA_ARGS__) +#else +# define cci_access_var +# define cci_access_start(...) (void)0 +# define cci_access_over(...) (void)0 +#endif + +#ifdef STMVL53L1_DEBUG_I2C +# define i2c_debug(fmt, ...) vl53l1_dbgmsg(fmt, ##__VA_ARGS__) +#else +# define i2c_debug(fmt, ...) (void)0 +#endif + +VL53L1_Error VL53L1_GetTickCount(uint32_t *ptime_ms) +{ + (void)ptime_ms; + BUG_ON(1); +} + +/** + * compute elapsed time in in milli sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in milli seconde + */ +static uint32_t tv_elapsed_ms(struct timeval *tv) +{ + struct timeval now; + + st_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000 + + (now.tv_usec - tv->tv_usec) / 1000; +} + +static int cci_write(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[STMVL53L1_MAX_CCI_XFER_SZ + 2]; + struct i2c_msg msg; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + /* copy write data to buffer after index */ + memcpy(buffer + 2, data, len); + /* set i2c msg */ + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buffer; + msg.len = len + 2; + + rc = i2c_transfer(client->adapter, &msg, 1); + if (rc != 1) { + vl53l1_errmsg("wr i2c_transfer err:%d, index 0x%x len %d\n", + rc, index, len); + } + cci_access_over("rd status %d long %d ", rc != 1, len); + return rc != 1; +} + +static int cci_read(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[2]; + struct i2c_msg msg[2]; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; /* Write */ + msg[0].buf = buffer; + msg[0].len = 2; + /* read part of the i2c transaction */ + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD | client->flags; + msg[1].buf = data; + msg[1].len = len; + + rc = i2c_transfer(client->adapter, msg, 2); + if (rc != 2) { + pr_err("%s: i2c_transfer :%d, @%x index 0x%x len %d\n", + __func__, rc, client->addr, index, len); + + } + cci_access_over(" wr len %d status %d", rc != 2, len); + return rc != 2; +} + +VL53L1_Error VL53L1_WrByte(VL53L1_DEV pdev, uint16_t index, uint8_t data) +{ + struct stmvl53l1_data *dev; + + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + return cci_write(dev, index, &data, 1); + +} + +VL53L1_Error VL53L1_RdByte(VL53L1_DEV pdev, uint16_t index, uint8_t *pdata) +{ + struct stmvl53l1_data *dev; + + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + return cci_read(dev, index, pdata, 1) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +} + +VL53L1_Error VL53L1_WrWord(VL53L1_DEV pdev, uint16_t index, uint16_t data) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + /* Split 16-bit word into MS and L* stmvl53l1 FlightSense sensor */ + + buffer[0] = (uint8_t) (data >> 8); + buffer[1] = (uint8_t) (data & 0x00FF); + i2c_debug(" @%x d= %x => [ %x , %x ] ", index, data, buffer[0], + buffer[1]); + status = VL53L1_WriteMulti(pdev, index, buffer, 2); + + return status; +} + +VL53L1_Error VL53L1_RdWord(VL53L1_DEV pdev, uint16_t index, uint16_t *pdata) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 2); + + *pdata = ((uint16_t) buffer[0] << 8) + (uint16_t) buffer[1]; + + return status; +} + +VL53L1_Error VL53L1_WrDWord(VL53L1_DEV pdev, uint16_t index, uint32_t data) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + /* Split 32-bit word into MS ... LS bytes */ + buffer[0] = (uint8_t) (data >> 24); + buffer[1] = (uint8_t) ((data & 0x00FF0000) >> 16); + buffer[2] = (uint8_t) ((data & 0x0000FF00) >> 8); + buffer[3] = (uint8_t) (data & 0x000000FF); + + status = VL53L1_WriteMulti(pdev, index, buffer, 4); + + return status; +} + +VL53L1_Error VL53L1_RdDWord(VL53L1_DEV pdev, uint16_t index, uint32_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 4); + + *pdata = ((uint32_t) buffer[0] << 24) + ((uint32_t) buffer[1] << 16) + + ((uint32_t) buffer[2] << 8) + (uint32_t) buffer[3]; + + return status; +} + +VL53L1_Error VL53L1_WriteMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; + + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + return cci_write(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +} + +VL53L1_Error VL53L1_ReadMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; + + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + return cci_read(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +} + +static int is_time_over(struct timeval *tv, uint32_t msec) +{ + return tv_elapsed_ms(tv) >= msec; +} + +VL53L1_Error VL53L1_WaitValueMaskEx(VL53L1_DEV pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, uint32_t poll_delay_ms) +{ + struct timeval start_tv; + struct stmvl53l1_data *dev; + int rc, time_over; + uint8_t rd_val; + + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + st_gettimeofday(&start_tv); + do { + rc = cci_read(dev, index, &rd_val, 1); + if (rc) + return VL53L1_ERROR_CONTROL_INTERFACE; + if ((rd_val & mask) == value) { + poll_timing_log(&start_tv); + return VL53L1_ERROR_NONE; + } + vl53l1_dbgmsg("poll @%x %x & %d != %x", index, + rd_val, mask, value); + time_over = is_time_over(&start_tv, timeout_ms); + if (!time_over) + msleep(poll_delay_ms); + } while (!time_over); + vl53l1_errmsg("time over %d ms", timeout_ms); + return VL53L1_ERROR_TIME_OUT; +} + +VL53L1_Error VL53L1_WaitUs(VL53L1_DEV pdev, int32_t wait_us) +{ + struct stmvl53l1_data *data; + + data = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + if (!data->is_delay_allowed) + return VL53L1_ERROR_PLATFORM_SPECIFIC_START; + + /* follow Documentation/timers/timers-howto.txt recommendations */ + if (wait_us < 10) + udelay(wait_us); + else if (wait_us < 20000) + usleep_range(wait_us, wait_us + 1); + else + msleep(wait_us / 1000); + + return VL53L1_ERROR_NONE; +} + +VL53L1_Error VL53L1_WaitMs(VL53L1_DEV pdev, int32_t wait_ms) +{ + return VL53L1_WaitUs(pdev, wait_ms * 1000); +} diff --git a/drivers/input/misc/vl53L1/stmvl53l1_if.h b/drivers/input/misc/vl53L1/stmvl53l1_if.h new file mode 100644 index 0000000000000000000000000000000000000000..ac9a31dc6bfe16d564d189c005119a3fd00be4b6 --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_if.h @@ -0,0 +1,677 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file stmvl53l1_if.h vl53l1 kernel driver user interface + * + * @note to use this header in a user space application it requires + * all st bare/ll driver platform wrapper files (for data struct def) + * this files (types etc ..) shall be same or compliant with bar driver version + * used in the kernel module + */ + +#ifndef STMVL53L1_IF_H +#define STMVL53L1_IF_H + + +#include "vl53l1_def.h" +/** + * @addtogroup vl53l1_ioctl + * @{ + */ + +/** + * misc device name for ioctl device + * + * for mutli instance all device 2nd and next instance are basic name +"1"+"2" + * @li stmvl53l1_ranging + * @li stmvl53l1_ranging1 + * @li stmvl53l1_ranging2 + */ +#define VL53L1_MISC_DEV_NAME "stmvl53l1_ranging" +/** + * register data use for simple/single ranging data @ref VL53L1_IOCTL_GETDATAS + * + * @warning this definition is subject to change ! + */ +#define stmvl531_range_data_t VL53L1_RangingMeasurementData_t + +/** + * parameter name in @ref stmvl53l1_parameter when using + * @ref VL53L1_IOCTL_PARAMETER + */ +enum __stmv53l1_parameter_name_e { + VL53L1_XTALKENABLE_PAR = 2, + /*!< VL53L1_XTALKENABLE_PAR enable/disable crosstalk compensation\n + * valid value : + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @warning mode can only be set while not ranging + */ + + VL53L1_DEVICEMODE_PAR = 6, + /*!< DEVICEMODE_PAR set ranging mode  \n + * valid mode value : + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * @li 8 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low power autonomous + * mode + * + * @warning mode can only be set while not ranging + */ + + VL53L1_POLLDELAY_PAR = 10, + /*!< set the polling delay (msec)\n + * + * @note apply only when operates in polling mode as no effect + * otherwise + */ + VL53L1_TIMINGBUDGET_PAR = 11, + /*!< VL53L1_TIMINGBUDGET_PAR + * @ref stmvl53l1_parameter.value field is timing budget + * in micro second + * + * @note Please refer to VL53L1 user manual for minimum timing budget + * according to the selected mode + * + * Mode / timing budget | Min | Typical + * ------------------------------------- | ----- | ------- + * VL53L1_PRESETMODE_RANGING | 8 ms | 16 ms + * VL53L1_PRESETMODE_MULTIZONES_SCANNING | 8 ms | 16 ms + * VL53L1_PRESETMODE_AUTONOMOUS | 41 ms | 76 ms + * VL53L1_PRESETMODE_LITE_RANGING | 17 ms | 66 ms + * VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS | 20 ms | 20 ms + * + */ + + VL53L1_DISTANCEMODE_PAR = 12, + /*!< VL53L1_DISTANCEMODE_PAR + * valid distance mode value : + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_OUTPUTMODE_PAR = 13, + /*!< VL53L1_OUTPUTMODE_PAR + * valid output mode value : + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_FORCEDEVICEONEN_PAR = 14, + /*!< VL53L1_FORCEDEVICEONEN_PAR + * This parameter will control if device is put under reset when + * stopped. + * valid force device on value : + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + */ + + VL53L1_LASTERROR_PAR = 15, + /*!< VL53L1_LASTERROR_PAR + * This is a read only parameter. It will return last device internal + * error. It's valid only after an ioctl/sysfs return an -EIO error. + */ + + VL53L1_OFFSETCORRECTIONMODE_PAR = 16, + /*!< VL53L1_OFFSETCORRECTIONMODE_PAR + * This parameter will define which mode to use for the offset + * correction. + * valid force device on value : + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @warning offset correction mode can only be set while not ranging + */ + + VL53L1_OPTICALCENTER_PAR = 17, + /*!< VL53L1_OPTICALCENTER_PAR + * This is a read only parameter. It will return optical center issued + * from the nvm set at FTM stage. value will contain X position of + * center. value2 will contain Y position of center. + * Return values have FixPoint1616_t type. + */ + + VL53L1_DMAXREFLECTANCE_PAR = 18, + /*!< VL53L1_DMAXREFLECTANCE_PAR + * This parameter will define target reflectance @ 940nm used to + * calculate the ambient DMAX. Parameter is of type FixPoint1616_t. + * + * @warning dmax reflectance can only be be set while not ranging + */ + + VL53L1_DMAXMODE_PAR = 19, + /*!< VL53L1_DMAXMODE_PAR + * This parameter will select Dmax mode. + * valid Dmax mode value : + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @warning Dmax mode can only be set while not ranging + */ + + VL53L1_TUNING_PAR = 20, + /*!< VL53L1_DMAXMODE_PAR + * This parameter is a write only parameter. It will allow to provide + * low level layer with a configuration parameter. + * value will be use as a key parameter. + * value2 will be use as value parameter. + * + * @warning those configuration parameter settings are only allowed + * before device is start once. + */ + + VL53L1_SMUDGECORRECTIONMODE_PAR = 21, + /*!< VL53L1_SMUDGECORRECTIONMODE_PAR + * This parameter will control if smudge correction is enable and how + * crosstalk values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + */ + + VL53L1_ISXTALKVALUECHANGED_PAR = 22, + /*!< VL53L1_ISXTALKCHANGED_PAR + * This is a read only parameter. It will return if Xtalk value has + * been updated while ranging. This parameter is reset each time device + * start to range. + * @li 0 Xtalk values has not been changed. + * @li 1 Xtalk values has been changed. + */ +}; +#define stmv53l1_parameter_name_e enum __stmv53l1_parameter_name_e + +/** + * parameter structure use in @ref VL53L1_IOCTL_PARAMETER + */ +struct stmvl53l1_parameter { + uint32_t is_read; /*!< [in] 1: Get 0: Set*/ + /*!< [in] parameter to set/get + * see @ref stmv53l1_parameter_name_e + */ + stmv53l1_parameter_name_e name; + int32_t value; /*!< [in/out] value to set /get */ + int32_t value2; /*!< [in/out] optional 2nd value */ + int32_t status; /*!< [out] status of the operation */ +}; + + +/** + * roi structure use as @ref VL53L1_IOCTL_ROI arg + * + * see @ref stmvl53l1_roi_full_t for easy to use type variable declaration + * required + */ +struct stmvl53l1_roi_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + /*! roi data and count type use in @ VL53L1_IOCTL_ROI */ + struct roi_cfg_t { + uint8_t NumberOfRoi; + /*!< [in/out] Number of Rois to set/get + * + * on set :\n + * [in] number of roi to set + * @note 0 set can be used to return to device default roi usage + * + * on get :\n + * [in] max number provided\n + * [out] number of ROI copied back to user\n + * @warning 0 will not return any roi datas! + */ + VL53L1_UserRoi_t UserRois[1]; + /*!< roi data array length definition is 1 but + * NumberOfRoi+ FirstRoiToScan in array are required + * and will be effectively copy to/from user space + * + * @sa stmvl53l1_roi_full_t + */ + } roi_cfg /*! [in/out] roi data and count */; +}; + +/** + * full roi struct use in @ref VL53L1_IOCTL_ROI arg + * + * this definition make easier variable declaration with the max roi storage + * capabilities. + * + * @sa stmvl53l1_roi_t for field details + */ +struct stmvl53l1_roi_full_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + VL53L1_RoiConfig_t roi_cfg; + /*!< roi data array of max length but only requested copy to/from user + * space effectively used + * see @a stmvl53l1_roi_t::roi_cfg for details + */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + VL53L1_CalibrationData_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** + * Opaque structure use to hold content of zone offset calibration result. + */ +#define stmvl531_zone_calibration_data_t \ + struct _stmvl531_zone_calibration_data_t + +struct _stmvl531_zone_calibration_data_t { + uint32_t id; + VL53L1_ZoneCalibrationData_t data; +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_ZONE_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_zone_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + stmvl531_zone_calibration_data_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** Select reference spad calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1, param2 and param3 not use + */ +#define VL53L1_CALIBRATION_REF_SPAD 0 + +/** Select crosstalk calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1 is calibration method. param2 and param3 not use. + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI + */ +#define VL53L1_CALIBRATION_CROSSTALK 1 + +/** Select offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is either: + * - VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * - VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE (deprecated) + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE usage is deprecated. Per + * zone offset calibration should use VL53L1_CALIBRATION_OFFSET_PER_ZONE + * instead. + */ +#define VL53L1_CALIBRATION_OFFSET 2 + +/** Select offset calibration per zone @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is: + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that region of interest should be defined by a prior call to + * VL53L1_IOCTL_ROI before calling VL53L1_IOCTL_PERFORM_CALIBRATION / + * VL53L1_CALIBRATION_OFFSET combinaison. + */ +#define VL53L1_CALIBRATION_OFFSET_PER_ZONE 3 + +/** Select simple offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is target distance in mm. + * param2 and param3 are not used + */ +#define VL53L1_CALIBRATION_OFFSET_SIMPLE 4 + +/** Select per Vcsel offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is target distance in mm. + * param2 and param3 are not used + * this calibration is used by the VL53L1_OFFSETCORRECTIONMODE_PERVCSEL mode + */ +#define VL53L1_CALIBRATION_OFFSET_PER_VCSEL 5 + +/** Select no Distance offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1, param2 and param3 are not used + */ +#define VL53L1_CALIBRATION_OFFSET_ZERO_DISTANCE 6 + +/** + * parameter structure use in @ref VL53L1_IOCTL_PERFORM_CALIBRATION + */ +struct stmvl53l1_ioctl_perform_calibration_t { + uint32_t calibration_type; + /*!< [in] select which calibration to do : + * @li @ref VL53L1_CALIBRATION_REF_SPAD + * @li @ref VL53L1_CALIBRATION_CROSSTALK + * @li @ref VL53L1_CALIBRATION_OFFSET + * @li @ref VL53L1_CALIBRATION_OFFSET_PER_ZONE + * @li @ref VL53L1_CALIBRATION_OFFSET_SIMPLE + * @li @ref VL53L1_CALIBRATION_OFFSET_PER_VCSEL + * @li @ref VL53L1_CALIBRATION_OFFSET_ZERO_DISTANCE + */ + uint32_t param1; + /*!< [in] first param. Usage depends on calibration_type */ + uint32_t param2; + /*!< [in] second param. Usage depends on calibration_type */ + uint32_t param3; + /*!< [in] third param. Usage depends on calibration_type */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_AUTONOMOUS_CONFIG + */ +struct stmvl53l1_autonomous_config_t { + int32_t is_read; + /*!< [in] 1: Get 0: Set*/ + uint32_t pollingTimeInMs; + /*!< [in/out] interval between two measure in ms */ + VL53L1_DetectionConfig_t config; + /*!< [int/out] autonomous mode configuration structure */ +}; + +/* + * IOCTL definitions + */ + + +/** + * Start ranging (no argument) + * + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute with no consideration of sysfs path. + * + * @return : + * @li 0 on success + * @li -EBUSY if already started + * @li -ENXIO failed to change i2c address change after reset release + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * example user land : + @code + int smtvl53l1_start(int fd){error + int rc; + rc= ioctl(fd, VL53L1_IOCTL_START,NULL); + if( rc ){ + if( errno == EBUSY){ + //the device is already started + ioctl_warn("already started"); + return EBUSY; + } + } + if( rc ){ + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} + @endcode +*/ + +#define VL53L1_IOCTL_START _IO('p', 0x01) + +/** + * stop ranging (no argument) + + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute action with no consideration of sysfs path. + * + * @return + * @li 0 on success + * @li -EBUSY if it was already + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * c example userland : + @code +int smtvl53l1_stop(int fd){ + int rc; + rc= ioctl(fd, VL53L1_IOCTL_STOP,NULL); + if( rc ){ + if( errno == EBUSY ){ + ioctl_warn("already stopped"); + return errno; + } + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} +@endcode + */ +#define VL53L1_IOCTL_STOP _IO('p', 0x05) + +/** + * get single ranging data @sa for multi zone/objet + * + * retrieve the last range data available form the device + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV. Device has been removed. + * + * @warning this ioctl will not wait for a new range sample acquisition + * it will return what available at time it get called . Hence same data maybe + * returned many time when doing fast polling.\n + * End user must inspect the data structure (time stamp etc )to find about it\n + * Despite it's non "waiting" nature this ioctl may still block/sleep shortly + * to ensure race free usage acquiring mutex and/or locks. + */ +#define VL53L1_IOCTL_GETDATAS \ + _IOWR('p', 0x0b, stmvl531_range_data_t) + +/** + * set or get parameter + * + * @param parameter in/out @ref stmvl53l1_parameter + * @sa stmv53l1_parameter_name_e + * + * for get if ioctl fail do not check for out params it is not valid + * for set theirs not copy back only see ioctl status, errno to get error case + * + * @return 0 on success else o, error check errno + * @li -ENODEV. Device has been removed. + * + * @note a set parameter may not be absorbed straight aways ! + */ +#define VL53L1_IOCTL_PARAMETER \ + _IOWR('p', 0x0d, struct stmvl53l1_parameter) + + +/** + * set/get roi + * + * shall only be use while device is stopped (EBUSY error otherwise) + * setting 0 rois stand for "disable user define roi usage, use device default" + * + * @param roi_cfg [in/out] type @ref stmvl53l1_roi_t and + * @ref stmvl53l1_roi_full_t + * @note when getting roi the returned roi cnt is set to available number + * of roi in driver but at most requested number or available one + * will be set in returned structure + * @warning the coordinate system is not usual image x,y (y down)but traditional + * ecludian x,y (y up) + * + * @warning once defined the user roi is kept alive until unset by user . + * User shall update roi when required (mode change etc ..)\n + * To return to default unset roi by setting none, device will return to default + * at next start + * + * @note roi validity is only checked at start ranging , as such invalid roi set + * can make start to fail + * + * @return 0 on success , see errno for error detail + * @li EBUSY when trying to set roi while ranging + * @li ENODEV never device get started and trying to get more rois than set + * @li other errno code could be ll driver specific + */ +#define VL53L1_IOCTL_ROI\ + _IOWR('p', 0x0e, struct stmvl53l1_roi_t) + +/** + * Get multi object/zone ranging data + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA\ + _IOR('p', 0x0f, VL53L1_MultiRangingData_t) + +/** + * get single ranging data @sa for multi zone/objet + * + * this call is equivalent to VL53L1_IOCTL_GETDATAS but will block until + * new data are available since previous call. + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + */ +#define VL53L1_IOCTL_GETDATAS_BLOCKING\ + _IOWR('p', 0x10, stmvl531_range_data_t) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA but will block until + * new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_BLOCKING\ + _IOR('p', 0x11, VL53L1_MultiRangingData_t) + +/** + * Get / set calibration data + * + * this call allow client to either read calibration data after calibration + * has been performed to store them in the host filesystem or push calibration + * data before ranging at each start-up. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * use this after either VL53L1_CALIBRATION_REF_SPAD, + * VL53L1_CALIBRATION_CROSSTALK or VL53L1_CALIBRATION_OFFSET. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_calibration_data_t) + +/** + * Get / set zone calibration data + * + * this call allow client to either read zone calibration data after calibration + * has been performed to store them in the host filesystem or push zone + * calibration data before ranging at each start-up. + * + * use this after VL53L1_CALIBRATION_OFFSET_PER_ZONE calibration. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_zone_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_ZONE_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_zone_calibration_data_t) + +/** + * perform calibration squence according to calibration_type + * + * this call is attended to be used during factory calibration. You select + * calibration to issue using calibration_type. + * + * @param [in] data struct ptr of type + * @ref stmvl53l1_ioctl_perform_calibration_t. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to perform calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_PERFORM_CALIBRATION\ + _IOW('p', 0x13, struct stmvl53l1_ioctl_perform_calibration_t) + +/** + * set/get configure autonomous mode parameters + * + * Allow to get or set autonomous configuration. Change it only when device + * is stopped otherwise you will receive an EBUSY error. + * + * @param stmvl53l1_autonomous_config_t [in/out] + * + * @note autonomous config validity is only checked at start ranging , as such + * invalid autonomous config set can make start to fail. + * + * @return 0 on success , see errno for error detail + * @li -EFAULT failed to copy from/to configuration. + * @li -EBUSY when trying to change configuration while ranging. + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_AUTONOMOUS_CONFIG\ + _IOWR('p', 0x14, struct stmvl53l1_autonomous_config_t) + +/** @} */ /* ioctl group */ +#endif /* STMVL53L1_IF_H */ diff --git a/drivers/input/misc/vl53L1/stmvl53l1_internal_if.h b/drivers/input/misc/vl53L1/stmvl53l1_internal_if.h new file mode 100644 index 0000000000000000000000000000000000000000..17900318e9c7b62f95666508d7200527ca19d76d --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_internal_if.h @@ -0,0 +1,100 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +#ifndef STMVL53L1_INTERNAL_IF_H +#define STMVL53L1_INTERNAL_IF_H + +#include "vl53l1_def.h" + +/* interface definition move in this file is not supposed to be use by a normal + * client. It's only here for internal testing purpose. + */ + +/* structure and ioctl that allow raw access to vl53l1 register */ +struct stmvl53l1_register { + uint32_t is_read; /*!< type of the access 1: read 0: write*/ + uint32_t index; /*!< register index */ + uint32_t cnt; /*!< register size shall be 1 to n */ + int32_t status; /*!< operation status 0 ok else error */ + + union reg_data_t { + uint8_t b; /*!< single data byte*/ + uint16_t w; /*!< single data word (16 bits)*/ + uint32_t dw; /*!< single data dword (32 bits)*/ + /*!< any size byte array + * @note only effectively used array size is needed and will be + * set/used another possible register definition is + * @ref stmvl53l1_register_flexi + */ + uint8_t bytes[256]; + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by + * @ref VL53L1_IOCTL_REGISTER + */ + } data; +}; + +struct stmvl53l1_register_flexi { + uint32_t is_read; /*!< [in] type of the access 1: read 0: write*/ + uint32_t index; /*!< [in] register index */ + uint32_t cnt; /*!< [in] register size shall be 1 to n */ + int32_t status; /*!< [out] operation status 0 ok else error */ + uint8_t data[]; /*!< [in/out] flexible array size data */ + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by @ref VL53L1_IOCTL_REGISTER + */ +}; + +#define VL53L1_IOCTL_REGISTER _IOWR('p', 0x0c, struct stmvl53l1_register) + +struct stmvl53l1_data_with_additional { + VL53L1_MultiRangingData_t data; + VL53L1_AdditionalData_t additional_data; +}; + +/** + * Get multi object/zone ranging data with additional data for debug + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL\ + _IOR('p', 0x15, struct stmvl53l1_data_with_additional) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA_ADDITIONAL but will block + * until new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\ + _IOR('p', 0x16, struct stmvl53l1_data_with_additional) + +#endif diff --git a/drivers/input/misc/vl53L1/stmvl53l1_ipp.h b/drivers/input/misc/vl53L1/stmvl53l1_ipp.h new file mode 100644 index 0000000000000000000000000000000000000000..d6f21eadca7dac8f43905855cb269eadd5d981dc --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_ipp.h @@ -0,0 +1,366 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file stmvl53l1_ipp.h + * + * helper to serialize de-serialize data in ipp exchange between user/kernel + * + * @date Sep 2, 2016 + * @author imaging + */ + +#ifndef _STMVL53L1_IPP_H_ +#define _STMVL53L1_IPP_H_ + +#include "vl53l1_types.h" + + +/** @ingroup ipp_dev + * @{ + */ + +/** + * @defgroup ipp_serialize ST IPP serialization helper + * + * to use the dump help you lust define first a few extra "specific" + * + * @li IPP_PRINT(fmt,..) with typical printf/printk interface + */ + /** @{ */ +/** + * generic data type to serialized scalar and offset for pointer + * + * serialized data can be seen as a first array of n ipp_art_t + * where each input are arg value for scaler type + * and an offset with respect to the ipp_arg base array where the data + * + * @note if all ipp argument can fit on 32 bit then ipp_arg_t is best set as + * a 32 bit base type '(i e uint32_t) to save space + * on 64 bit cpu it can remain 64 bit type to get better alignment + */ +typedef uint64_t ipp_arg_t; + +/** + * set to the cpu structure alignment and packing constrain + * + * all serialized argument passed by pointer will be stored with + * this memory align constrain + * + * + * @note if target cpu is ok to access unaligned data or less constrain ie 64 + * bit data align 32 are ok then it can be set to 4 to save space in data + * packing and copy\n + * We may be over constraining in many cases as a struct is only required to + * be aligned on i'st biggest item size + * + * @warning it must be a 2 power of 2 (& operation instead of mudulo used in + * align calculation) + * @warning using 8 byte constrain require that the @a ipp_arg_t is already + * aligned on that constrain + */ +#define IPP_ALIGN_REQ 8 + +/** + * set x to it's nearest aligned offset (not that 0 is fine as a valid offset + * than will not be up aligned to next align chunk ) + */ +#define IPP_ALIGN_OFFSET(x) (((x)+(IPP_ALIGN_REQ-1)) & (~(IPP_ALIGN_REQ-1))) + +/** + * declare variable needed for ipp serialization + */ +#define IPP_SERIALIZE_VAR int ipp_offset +/** + * Put in function start to init the serialization coding + * + * @param ipp_args buffer for data serialization + * @param n_args is the total number of argument scalar and ptr to serialized + * dot not count out only arg that will be returned + * + * it define local var "ipp_offset" used to accumulate all input args that must + * be serialize. It reserve header room in the buffer to place for scalar args + * and offset for args ptr copy + * + * args pass by pointer must be serialized by @ref IPP_SET_ARG_PTR in order they + * are declare\n + * scalar args can be serialized in any order with @ref IPP_SET_ARG + * + * scalar args that can't be cast to basic @ref ipp_arg_t shall be serialized + * Manually or using a macro similar to ptr that can be pass by copy + * + *@note @ref IPP_SERIALIZE_VAR must be use first + * @code + * int ipp_to _ser(int arg0, struct st_t *pdata1){ + * char *local var; + * ipp_arg_t args[256]; + * IPP_SERIALIZE_START(2); + * IPP_SET_ARG(args, 0, arg0); + * IPP_SET_ARG_PTR(args, 1, pdata); + * do_one_ipp(args); + * } + * @endcode + * + */ +#define IPP_SERIALIZE_START(ipp_args, n_args)\ + (ipp_offset = IPP_ALIGN_OFFSET((char *)(&ipp_args[n_args]) - \ + (char *)ipp_args)) + +/** + * @brief Serialize scalar argument + * + * serialized arg number n into ipp_args\n + * can be used in any order + * + * @param ipp_args the args buffer + * @param n 0 base arg number + * @param v the scalar argument variable + * @warning usable only for scalar type that can be copy on a ipp_arg_t + */ +#define IPP_SET_ARG(ipp_args, n, v) memcpy(&ipp_args[n], &v, sizeof(v)) + +/** + * @brief Serialize an arg passed by pointer + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize + * @param pdata argument it must be a type like struct x_t * int [n] etc ... + * that size is given by size of and and be copied by a single memcpy + */ +#define IPP_SET_ARG_PTR(ipp_args, n, pdata)\ + do {\ + ipp_args[n] = ipp_offset;\ + memcpy(((char *)ipp_args) + ipp_offset, pdata, sizeof(*pdata));\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + sizeof(*pdata));\ + } while (0) + +/** + * serialize out get ptr for pdata + * + * @note it does not cpy data just set ptr and update the offset + * @warning to be use in order + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize (unused) + * @param pdata init to ptr in ipp_args type is used for offset computation + * @warning to use sequential in order agr are serialized + */ +#define IPP_OUT_ARG_PTR(ipp_args, n, pdata)\ + do {\ + pdata = (void *)(((char *)ipp_args) + ipp_offset);\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + \ + (int)sizeof(*pdata));\ + } while (0) + + +/** + * @brief ipp get payload + * + * @return paylaod at time used \n + * when all done it's overall out payload + * + * require @ref IPP_SERIALIZE_VAR and @ref IPP_SERIALIZE_START used first\n + * best use after all @ref IPP_OUT_ARG_PTR or @ref IPP_SET_ARG_PTR done to get + * full payload + **/ +#define IPP_SERIALIZE_PAYLAOD() (ipp_offset + IPP_WORK_HDR_SIZE) + +/** + * de-serialize and argument that was passed by value + * @param ipp_args the args array + * @param n the 0 base argument number + * @param v argument it must be exact type + * + * + * @code + * f_deserialize(ipp_arg_t args[]) + * { + * // f_ser is like (uint16_t arg0, struct s_arg_t * arg1, int arg2) + * uint16_t arg0; + * void * parg1; + * int arg2; + * + * IPP_GET_ARG( args, 0, arg0) + * IPP_GET_ARG( args, 2, arg2) + * } + * @endcode + */ +#define IPP_GET_ARG(ipp_args, n, v) memcpy(&v, &ipp_args[n], sizeof(v)) + + +/** + * de-serialize an argument passed by pointer + * + * @param ipp_args the serialized argument array + * @param n 0 base argument number + * @param p ptr to arg to be set + * + * @note unlike serializing de-serializing pointer args data can be done in any + * order + * + * @code + * struct some_struct_t *parg2; + * IPP_GET_ARG_PTR(args,2,parg2); + * @endcode + */ +#define IPP_GET_ARG_PTR(ipp_args, n, p) (p = (void *)((char *)ipp_args + \ + ipp_args[n])) + + + + +/** + * debug macro to pint out all serialized args + * + * Implementation shall define IPP_PRINT_FUNC function to use + */ +#define IPP_PRINT_ARGS(ipp_args, n) \ + do {\ + int i;\ + for (i = 0; i < n; i++)\ + IPP_PRINT("arg#%d/%d is %8d 0x%08x\n", i, n,\ + ipp_args[i], ipp_args[i]);\ + IPP_PRINT("used data size %d\n", ipp_offset);\ + } while (0) + + +/** + * processing code type of proccesing + * + * used in @a ipp_work_t::process_no + */ +enum stmvl53l1_ipp_proccesing_e { + stmvl53l1_ipp_ping = 0, + /*!< stmvl53l1_ipp_ping + * @li can be sent by driver to check client is alive + * @li daemon sent it to identify and register himself to the driver + */ + stmvl53l1_ipp_cal_hist = 1, + /*!< stmvl53l1_ipp_cal_hist process cal hist*/ + + stmvl53l1_ipp_xtalk_calibration = 2, + /*!< stmvl53l1_ipp_xtalk_calibration process crosstalk calibration data + */ + + stmvl53l1_ipp_hist_ambient_dmax = 3, + /*!< stmvl53l1_ipp_hist_ambient_dmax process ambient dmac calculation + * from histogram + */ + + stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples = 4, + /*!< stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples process + * Xtalk data from dual reflectance histogram data + */ + + /** keep last*/ + stmvl53l1_ipp_max /*!< stmvl53l1_ipp_max */ +}; + +/** + * status use on @a ipp_work_t::status + */ +enum stmvl53l1_ipp_status_e { + stmvl53l1_ipp_status_ok = 0, /*!< ok work done */ + stmvl53l1_ipp_status_inv_id, /*!< dev id not supported or invalid */ + stmvl53l1_ipp_status_inv_proc, + /*!< process_no asked not supported or not implemented */ + stmvl53l1_ipp_status_inv_payload, + /*!< data payload for asked processing incorrect*/ + + stmvl53l1_ipp_status_proc_code = 0x100, + /*!< the lowest 8 bit is the error code form the processing */ +}; + +/** + * Ipp work (job) struct + * + * containing header with sequenc control information plus serialized data + */ +struct ipp_work_t { + int8_t dev_id; /*!< [in]/[out] device id */ + /*!< Identify the work do be run see @a stmvl53l1_ipp_proccesing_e */ + uint8_t process_no; + /*!< [out] status from daemon */ + int16_t status; + /*!< [in/out] unique xfer id */ + uint32_t xfer_id; + /*!< [in/out] effective data length including header*/ + uint32_t payload; + +/** max IPP data payload (not including header) + * + * we substract size of of item above + * must be lesss than one netlink packet + */ +#define MAX_IPP_DATA ((4096-4*3)/8) + ipp_arg_t data[MAX_IPP_DATA]; /*!< [in][out] */ +}; + +/** + * size of header only message ( no payload) + * require \#include in user land + */ +#define IPP_WORK_HDR_SIZE (offsetof(struct ipp_work_t, data[0])) +/** + * max payload per ipp transfer + */ +#define IPP_WORK_MAX_PAYLOAD sizeof(struct ipp_work_t) + +/** copy ipp header from src to dest + * + * used to prepare return work using incoming work header + * @param dest dest work ptr + * @param src src work ptr + */ +#define IPP_CPY_HEADER(dest, src) memcpy(dest, src, IPP_WORK_HDR_SIZE) + +/** + * dump in human readble way ipp struct + * + * @note require IPP_PRINT macro + * + * @param pw ipp_work struct to dump + * @param max_data max amount of data to be dump + * @param max_dev max number of dev (for check) + */ +static inline void ipp_dump_work(struct ipp_work_t *pw, uint32_t max_data, + int max_dev) +{ + uint32_t data_cnt; + uint32_t i; + uint8_t *pbdata; + + (void)max_dev; /* avoid warning when not used */ + (void)pbdata; /*avoid warning in case no print no use*/ + + IPP_PRINT("dev #%d (%s)\n", pw->dev_id, pw->dev_id < max_dev ? + "ok" : "bad"); + IPP_PRINT("process #%d (%s)\n", pw->process_no, + pw->process_no < stmvl53l1_ipp_max ? "ok" : "bad"); + IPP_PRINT("status %d\n", pw->status); + IPP_PRINT("Xfer id 0x%08X payload %d bytes (%s)\n", pw->xfer_id, + pw->payload, + pw->payload > IPP_WORK_MAX_PAYLOAD ? "invalid" : "ok"); + data_cnt = pw->payload > IPP_WORK_MAX_PAYLOAD ? + IPP_WORK_MAX_PAYLOAD : pw->payload; + data_cnt = data_cnt > max_data ? max_data : data_cnt; + for (i = 0, pbdata = (uint8_t *)pw->data; i < data_cnt; i++) { + if (i%16 == 0) + IPP_PRINT("\n%4X\t", i); + IPP_PRINT("%02X ", pbdata[i]); + } + IPP_PRINT("\n"); +} + +/** @} */ /* ingroup helper */ + +/** @} */ /* ingroup ipp_dev */ +#endif /* _STMVL53L1_IPP_H_ */ diff --git a/drivers/input/misc/vl53L1/stmvl53l1_ipp_nl.c b/drivers/input/misc/vl53L1/stmvl53l1_ipp_nl.c new file mode 100644 index 0000000000000000000000000000000000000000..e545d341a0771dd76f48bf2aa80410634716e1a7 --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_ipp_nl.c @@ -0,0 +1,363 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file stmvl53l1_ipp_nl.c vl53l1 ipp proxy over netlink kernel side + */ +#include +#include +#include +#include +#include + +#include "stmvl53l1.h" + +#include "vl53l1_platform_ipp.h" +#include "stmvl53l1_ipp.h" + +#define IPP_DEBUG 1 +#ifndef IPP_DEBUG +# define _ipp_dump_work(...) (void)0 +#else +# define _ipp_dump_work(...) ipp_dump_work(__VA_ARGS__) +#endif + +#define IPP_STATE_PENDING 1 +#define IPP_STATE_COMPLETED 2 +#define IPP_STATE_CANCELED 4 + +#define IPP_TIMEOUT_MS 100 + +/** the single netlink strut use by all instance + * @note is NULL until set + */ +static struct sock *nl_sk; + +static DEFINE_MUTEX(ipp_mutex); + +/** + * current registered daemon pid + * @note default value 0 or later 1 is kind of invalid and will require + * user space to connect before we can send any packet + */ +static int daemon_pid; + +/** + * next xfer_id (shared other all dev) + * no direct us used @@ref get_next_xfer_id (will get lock) + * @note default to 0 what is "reserved" + */ +static int next_xfer_id; + + +#define ipp_err(fmt, ...) pr_err("STMVL53L1 IPP Err in %s %d :" fmt "\n", \ + __func__, __LINE__, ##__VA_ARGS__) + +#define ipp_warn(fmt, ...) pr_warn("STMVL53L1 IPP wng in %s %d : "fmt"\n",\ + __func__, __LINE__, ##__VA_ARGS__) + +#if 0 +# define ipp_dbg(fmt, ...) pr_info("IPP %s %d " fmt "\n",\ + __func__, __LINE__, ##__VA_ARGS__) +#else +# define ipp_dbg(...) (void)0 +#endif + +/** + * get and managed increment of next xfer_id + * @note will get ipp_mutex + * @return the xfer_id to be used + */ +static int get_next_xfer_id(void) +{ + mutex_lock(&ipp_mutex); + next_xfer_id++; + /*0 is reserved skip it*/ + if (next_xfer_id == 0) + next_xfer_id = 1; + mutex_unlock(&ipp_mutex); + + return next_xfer_id; +} + +static int send_client_msg(void *msg_data, int msg_size) +{ + int rc; + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + void *nl_data; + + ipp_dbg("to send %d byte", msg_size); + skb_out = nlmsg_new(msg_size, 0); + if (!skb_out) { + ipp_err("nlmsg_new fail\n"); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); + NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */ + + nl_data = nlmsg_data(nlh); /*get data ptr from header*/ + memcpy(nl_data, msg_data, msg_size); + + /* FIXME do we real need to lock to send a data other nl_sk ? */ + mutex_lock(&ipp_mutex); + rc = nlmsg_unicast(nl_sk, skb_out, daemon_pid); + if (rc < 0) + ipp_err("fail to send data size %d to pid %d\n", + msg_size, daemon_pid); + /* stat can be done here in else case */ + mutex_unlock(&ipp_mutex); + + return rc; +} + +/* + * ipp lock is held ping already handled + */ +int ipp_in_process(struct ipp_work_t *pwork) +{ + struct stmvl53l1_data *data; + + ipp_dbg("enter"); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, STMVL53L1_CFG_MAX_DEV); + + /* work id check already done */ + data = stmvl53l1_dev_table[pwork->dev_id]; + ipp_dbg("to lock "); + /* Release now useless ipp_mutex for below work since we may deadlock + * with irq path. + */ + mutex_unlock(&ipp_mutex); + mutex_lock(&data->work_mutex); + if (data->ipp.buzy == IPP_STATE_PENDING) { + /* if it was already handled ignore it */ + if (data->ipp.waited_xfer_id == pwork->xfer_id) { + /* ok that is what we are expecting back */ + memcpy(&data->ipp.work_out, pwork, pwork->payload); + data->ipp.buzy |= IPP_STATE_COMPLETED; + ipp_dbg("to wake ipp waiter as buzy state %d", + data->ipp.buzy); + wake_up(&data->ipp.waitq); + goto done_lock; + } + } + /* either not waiting any more or not the expected id drop it */ + ipp_err("dev #%d ippp buzy %d xfer id %d rcv id %d droping it", + data->id, data->ipp.buzy, data->ipp.waited_xfer_id, + pwork->xfer_id); +done_lock: + mutex_unlock(&data->work_mutex); + mutex_lock(&ipp_mutex); + + return 0; +} + +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = data->ipp.buzy; + ipp_dbg("#%d to stop buzy %d", data->id, data->ipp.buzy); + if (data->ipp.buzy) { + /* set invalid wait id to discard canceled job when back */ + data->ipp.waited_xfer_id = 0; + data->ipp.buzy |= IPP_STATE_CANCELED|IPP_STATE_COMPLETED; + ipp_dbg("#%dto wake up worker", data->id); + /* wake up worker or abort the thread */ + wake_up(&data->ipp.waitq); + } + + return rc; +} + +/* + * ipp and dev lock are held + * release and re-grabbed here + */ +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout) +{ + int xfer_id; + int rc; + bool has_timeout; + + ipp_dbg("enter"); + + xfer_id = get_next_xfer_id(); + /* set xfer and device dependent part of the work */ + pin->dev_id = data->id; + pin->xfer_id = xfer_id; + data->ipp.waited_xfer_id = xfer_id; + /* try to do it */ + rc = send_client_msg(pin, pin->payload); + /* shall we retry if fail to send for some time or number of try ? */ + if (rc < 0) { + rc = -1; + ipp_err("fail to send msg %d", rc); + } else if (data->ipp.buzy == 0) { + /* send ok put the ipp on buzy state while locked */ + data->ipp.buzy = IPP_STATE_PENDING; + /* unlock now that state is marked buzy */ + mutex_unlock(&data->work_mutex); + + /* put task to wait for completion */ + ipp_dbg("to wait"); + has_timeout = !wait_event_timeout(data->ipp.waitq, + (data->ipp.buzy != IPP_STATE_PENDING), + msecs_to_jiffies(IPP_TIMEOUT_MS)); + + /* relock the main lock */ + mutex_lock(&data->work_mutex); + + rc = (data->ipp.buzy & IPP_STATE_CANCELED) || has_timeout ? + -1 : 0; + if (rc) { + ipp_dbg("waking up with from canceled/timeout ipp"); + } else { + /* return status from the ipp itself */ + ipp_dbg("ip back with status %d", data->ipp.status); + rc = data->ipp.status; + } + data->ipp.buzy = 0;/* buzy clear but locked so safe */ + } else { + ipp_dbg("buzy still not zero %d", data->ipp.buzy); + rc = -1; + } + + +/* done_lock: */ + return rc; +} + + +static void stmvl53l1_nl_recv_msg(struct sk_buff *skb_in) +{ + int pid_chg = 0; + int pid; + struct nlmsghdr *nlh; + struct ipp_work_t *pwork; + + ipp_dbg("Entering"); + + nlh = (struct nlmsghdr *)skb_in->data; + pid = nlh->nlmsg_pid; /*pid of sending process */ + + pwork = nlmsg_data(nlh); + if (pwork->payload < IPP_WORK_HDR_SIZE || + pwork->payload > IPP_WORK_MAX_PAYLOAD){ + /* invalid header size */ + ipp_err("invalid msg header size %d", pwork->payload); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + return; + } + + mutex_lock(&ipp_mutex); + + if ((pwork->dev_id >= STMVL53L1_CFG_MAX_DEV) || (pwork->dev_id < 0)) { + ipp_err("invalid dev id on msg %d", pwork->dev_id); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + + if (pwork->process_no == stmvl53l1_ipp_ping) { + /* in that case the payload must be exact status size only + * if not it is a badly format message or bad message + */ + if (pwork->payload != IPP_WORK_HDR_SIZE) { + ipp_err("invalid ping msg size %d!=%zu ", + pwork->payload, IPP_WORK_HDR_SIZE); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + /* if pid was not set or change resent all ongoing ipp */ + if (pid != daemon_pid) + ipp_warn("pid chg %d => %d\n", daemon_pid, pid); + else + ipp_dbg("got ping fm pid %d\n", daemon_pid); + daemon_pid = pid; + pid_chg = 1; + } else { + ipp_in_process(pwork); + } + done_locked: + mutex_unlock(&ipp_mutex); +} + +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&ipp_mutex); + + data->ipp.buzy = 0; + init_waitqueue_head(&data->ipp.waitq); + ipp_dbg("now %d dev daemon pid is %d", STMVL53L1_CFG_MAX_DEV, + daemon_pid); + rc = 0; + + mutex_unlock(&ipp_mutex); + + return rc; +} + +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data) +{ + /* nothink to do */ +} + +#if !defined(OLD_NETLINK_API) +struct netlink_kernel_cfg cfg = { + .input = stmvl53l1_nl_recv_msg +}; +#endif + +static int netlink_protocol_type = STMVL531_CFG_NETLINK_USER; + +module_param(netlink_protocol_type, int, 0444); +MODULE_PARM_DESC(netlink_protocol_type, + "select netlink protocol type for ipp communications"); + +int stmvl53l1_ipp_init(void) +{ + mutex_init(&ipp_mutex); + daemon_pid = 1; /* pid 1 is safe should not be use for user space */ + +#if defined(OLD_NETLINK_API) + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + 0, + stmvl53l1_nl_recv_msg, + NULL, + THIS_MODULE); +#else + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + &cfg); +#endif + + return nl_sk ? 0 : -1; +} + + +void stmvl53l1_ipp_exit(void) +{ + if (nl_sk != NULL) { + vl53l1_dbgmsg("releasing netlink socket"); + netlink_kernel_release(nl_sk); + nl_sk = NULL; + } +} + + diff --git a/drivers/input/misc/vl53L1/stmvl53l1_log.c b/drivers/input/misc/vl53L1/stmvl53l1_log.c new file mode 100644 index 0000000000000000000000000000000000000000..bfe5419a673492622e0d14b4b6bd725c6d258f17 --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_log.c @@ -0,0 +1,59 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * This is implementation of low level driver trace support + */ +#include +#include + +#include "stmvl53l1.h" + +#ifdef VL53L1_LOG_ENABLE + +static bool trace_function; +static int trace_module; +static int trace_level; + +module_param(trace_function, bool, 0644); +MODULE_PARM_DESC(trace_function, + "allow tracing of low level function entry and exit"); + +module_param(trace_module, int, 0644); +MODULE_PARM_DESC(trace_module, + "control tracing of low level per module"); + +module_param(trace_level, int, 0644); +MODULE_PARM_DESC(trace_level, + "control tracing of low level per level"); + +void log_trace_print(uint32_t module, uint32_t level, uint32_t function, + const char *format, ...) +{ + va_list args; + + if (function && !trace_function) + return; + + if (!(module & trace_module)) + return; + + if (level > trace_level) + return; + + va_start(args, format); + vprintk(format, args); + va_end(args); +} + +#endif diff --git a/drivers/input/misc/vl53L1/stmvl53l1_module-i2c.c b/drivers/input/misc/vl53L1/stmvl53l1_module-i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..7b501eed90686941bc1bf78fb47085f5a0581d75 --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_module-i2c.c @@ -0,0 +1,944 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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 stmvl53l1_module-i2c.c + * + * implement STM VL53L1 module interface i2c wrapper + control + * using linux native i2c + gpio + reg api + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * power specific includes + */ +#include +#include +#include +#include +#include +#include + +#include "stmvl53l1-i2c.h" +#include "stmvl53l1.h" + +#define STMVL53L1_SLAVE_ADDR (0x52>>1) + +/** @ingroup drv_port + * @{ + */ + +/** + * control specific debug message echo + * + * Set to 0/1 do not remove + * + * most dbg warn err messages goes true main driver macro + * this one permit some specific debug without activating all main dbg + */ +#define MODI2C_DEBUG 0 + +/* + * mutex to handle device i2c address changes. It allow to avoid multiple + * device active with same i2c addresses at the same time. Note that we don't + * support case where boot_reg has the same value as a final i2c address of + * another device. + */ +static DEFINE_MUTEX(dev_addr_change_mutex); + +/** + * i2c client assigned to our driver + * + * this is use for stm test purpose as we fake client create and regstration + * we stores the i2c client for release in clean-up overwise we wan't reload + * the module multiple time + * + * in a normal dev tree prod system this is not required + */ +static struct i2c_client *stm_test_i2c_client; + +/* + * pi3: + * insmod stmvl53l1.ko force_device=1 adapter_nb=1 xsdn_gpio_nb=19 + * intr_gpio_nb=16 pwren_gpio_nb=12 + * + * panda + * insmod stmvl53l1.ko force_device=1 adapter_nb=4 xsdn_gpio_nb=56 + * intr_gpio_nb=59 pwren_gpio_nb=55 + */ + +static int force_device; +static int adapter_nb = -1; +static int xsdn_gpio_nb = -1; +static int pwren_gpio_nb = -1; +static int intr_gpio_nb = -1; + +module_param(force_device, int, 0000); +MODULE_PARM_DESC(force_device, "force device insertion at module init"); + +module_param(adapter_nb, int, 0000); +MODULE_PARM_DESC(adapter_nb, "i2c adapter to use"); + +module_param(xsdn_gpio_nb, int, 0000); +MODULE_PARM_DESC(xsdn_gpio_nb, "select gpio numer to use for vl53l1 reset"); + +module_param(pwren_gpio_nb, int, 0000); +MODULE_PARM_DESC(pwren_gpio_nb, "select gpio numer to use for vl53l1 power"); + +module_param(intr_gpio_nb, int, 0000); +MODULE_PARM_DESC(intr_gpio_nb, "select gpio numer to use for vl53l1 interrupt"); + +/** + * warn message + * + * @warning use only in scope where i2c_data ptr is present + **/ +#define modi2c_warn(fmt, ...)\ + dev_WARN(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + +/** + * err message + * + * @warning use only in scope where i2c_data ptr is present + */ +#define modi2c_err(fmt, ...)\ + dev_err(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + + + +#if MODI2C_DEBUG +# define modi2c_dbg(fmt, ...)\ + pr_devel("%s "fmt"\n", __func__, ##__VA_ARGS__) +#else +# define modi2c_dbg(...) (void)0 +#endif + +static int insert_device(void) +{ + int ret = 0; + struct i2c_adapter *adapter; + struct i2c_board_info info = { + .type = "stmvl53l1", + .addr = STMVL53L1_SLAVE_ADDR, + }; + + memset(&info, 0, sizeof(info)); + strcpy(info.type, "stmvl53l1"); + info.addr = STMVL53L1_SLAVE_ADDR; + adapter = i2c_get_adapter(adapter_nb); + if (!adapter) { + ret = -EINVAL; + goto done; + } + stm_test_i2c_client = i2c_new_device(adapter, &info); + if (!stm_test_i2c_client) + ret = -EINVAL; + +done: + return ret; +} + +static int get_xsdn(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.xsdn_owned = 0; + if (i2c_data->xsdn_gpio == -1) { + vl53l1_errmsg("reset gpio is required"); + rc = -ENODEV; + goto no_gpio; + } + + vl53l1_dbgmsg("request xsdn_gpio %d", i2c_data->xsdn_gpio); + rc = gpio_request(i2c_data->xsdn_gpio, "vl53l1_xsdn"); + if (rc) { + vl53l1_errmsg("fail to acquire xsdn %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->xsdn_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure xsdn as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.xsdn_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_xsdn(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.xsdn_owned) { + vl53l1_dbgmsg("release xsdn_gpio %d", i2c_data->xsdn_gpio); + gpio_free(i2c_data->xsdn_gpio); + i2c_data->io_flag.xsdn_owned = 0; + i2c_data->xsdn_gpio = -1; + } + i2c_data->xsdn_gpio = -1; +} + +static int get_pwren(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.pwr_owned = 0; + if (i2c_data->pwren_gpio == -1) { + vl53l1_wanrmsg("pwren gpio disable"); + goto no_gpio; + } + + vl53l1_dbgmsg("request pwren_gpio %d", i2c_data->pwren_gpio); + rc = gpio_request(i2c_data->pwren_gpio, "vl53l1_pwren"); + if (rc) { + vl53l1_errmsg("fail to acquire pwren %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->pwren_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure pwren as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.pwr_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_pwren(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.pwr_owned) { + vl53l1_dbgmsg("release pwren_gpio %d", i2c_data->pwren_gpio); + gpio_free(i2c_data->pwren_gpio); + i2c_data->io_flag.pwr_owned = 0; + i2c_data->pwren_gpio = -1; + } + i2c_data->pwren_gpio = -1; +} + +static int get_intr(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.intr_owned = 0; + if (i2c_data->intr_gpio == -1) { + vl53l1_wanrmsg("no interrupt gpio"); + goto no_gpio; + } + + vl53l1_dbgmsg("request intr_gpio %d", i2c_data->intr_gpio); + rc = gpio_request(i2c_data->intr_gpio, "vl53l1_intr"); + if (rc) { + vl53l1_errmsg("fail to acquire intr %d", rc); + goto request_failed; + } + + rc = gpio_direction_input(i2c_data->intr_gpio); + if (rc) { + vl53l1_errmsg("fail to configure intr as input %d", rc); + goto direction_failed; + } + + i2c_data->irq = gpio_to_irq(i2c_data->intr_gpio); + if (i2c_data->irq < 0) { + vl53l1_errmsg("fail to map GPIO: %d to interrupt:%d\n", + i2c_data->intr_gpio, i2c_data->irq); + goto irq_failed; + } + i2c_data->io_flag.intr_owned = 1; + + return rc; + +irq_failed: +direction_failed: + gpio_free(i2c_data->intr_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_intr(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.intr_owned) { + if (i2c_data->io_flag.intr_started) { + free_irq(i2c_data->irq, i2c_data); + i2c_data->io_flag.intr_started = 0; + } + vl53l1_dbgmsg("release intr_gpio %d", i2c_data->intr_gpio); + gpio_free(i2c_data->intr_gpio); + i2c_data->io_flag.intr_owned = 0; + } + i2c_data->intr_gpio = -1; +} + +/** + * parse dev tree for all platform specific input + */ +static int stmvl53l1_parse_tree(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(i2c_data->pinctrl)) { + vl53l1_wanrmsg("Failed to get pinctrl, please check dts"); + rc = PTR_ERR(i2c_data->pinctrl); + goto err_pinctrl_get; + } + + i2c_data->pins_active = pinctrl_lookup_state(i2c_data->pinctrl, "stmvl53l1_active"); + if (IS_ERR_OR_NULL(i2c_data->pins_active)) { + vl53l1_wanrmsg("Pin state[active] not found"); + rc = PTR_ERR(i2c_data->pins_active); + goto err_pinctrl_lookup; + } + + i2c_data->pins_suspend = pinctrl_lookup_state(i2c_data->pinctrl, "stmvl53l1_suspend"); + if (IS_ERR_OR_NULL(i2c_data->pins_suspend)) { + vl53l1_wanrmsg("Pin state[suspend] not found"); + rc = PTR_ERR(i2c_data->pins_suspend); + goto err_pinctrl_lookup; + } + + i2c_data->pins_release = pinctrl_lookup_state(i2c_data->pinctrl, "stmvl53l1_release"); + if (IS_ERR_OR_NULL(i2c_data->pins_release)) { + vl53l1_wanrmsg("Pin state[release] not found"); + rc = PTR_ERR(i2c_data->pins_release); + } + + /* if force device is in use then gpio nb comes from module param else + * we use devicetree. + */ + i2c_data->vdd = NULL; + i2c_data->pwren_gpio = -1; + i2c_data->xsdn_gpio = -1; + i2c_data->intr_gpio = -1; + i2c_data->boot_reg = STMVL53L1_SLAVE_ADDR; + if (force_device) { + i2c_data->xsdn_gpio = xsdn_gpio_nb; + i2c_data->pwren_gpio = pwren_gpio_nb; + i2c_data->intr_gpio = intr_gpio_nb; + } else if (dev->of_node) { + /* power : either vdd or pwren_gpio. try reulator first */ + i2c_data->vdd = regulator_get_optional(dev, "vdd"); + if (IS_ERR(i2c_data->vdd) || i2c_data->vdd == NULL) { + i2c_data->vdd = NULL; + /* try gpio */ + rc = of_property_read_u32_array(dev->of_node, + "pwren-gpio", &i2c_data->pwren_gpio, 1); + if (rc) { + i2c_data->pwren_gpio = -1; + vl53l1_wanrmsg( + "no regulator, nor power gpio => power ctrl disabled"); + } + } + //rc = regulator_enable(i2c_data->vdd); + //if (rc) + // pr_err("i2c_data->vdd failed to enable\n"); + + i2c_data->xsdn_gpio = of_get_named_gpio(dev->of_node, "xsdn-gpio",0); + if (i2c_data->xsdn_gpio < 0) + vl53l1_wanrmsg("Unable to get reset_gpio"); + + i2c_data->intr_gpio = of_get_named_gpio(dev->of_node, "intr-gpio",0); + if (i2c_data->intr_gpio < 0) { + vl53l1_wanrmsg("Unable to get intr_gpio"); + } + + rc = of_property_read_u32_array(dev->of_node, "boot-reg", + &i2c_data->boot_reg, 1); + if (rc) { + vl53l1_wanrmsg("Unable to find boot-reg %d %d", + rc, i2c_data->boot_reg); + i2c_data->boot_reg = STMVL53L1_SLAVE_ADDR; + } + } + + /* configure gpios */ + rc = get_xsdn(dev, i2c_data); + if (rc) + goto no_xsdn; + rc = get_pwren(dev, i2c_data); + if (rc) + goto no_pwren; + rc = get_intr(dev, i2c_data); + if (rc) + goto no_intr; + + return rc; + +err_pinctrl_lookup: + if (i2c_data->pinctrl) { + devm_pinctrl_put(i2c_data->pinctrl); + } +err_pinctrl_get: + i2c_data->pinctrl = NULL; + i2c_data->pins_release = NULL; + i2c_data->pins_suspend = NULL; + i2c_data->pins_active = NULL; + return rc; + +no_intr: + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); +no_pwren: + put_xsdn(i2c_data); +no_xsdn: + return rc; +} + +static void stmvl53l1_release_gpios(struct i2c_data *i2c_data) +{ + put_xsdn(i2c_data); + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); + put_intr(i2c_data); +} +struct i2c_data *stmvl53l1_i2c_data = NULL; + +static int stmvl53l1_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct stmvl53l1_data *vl53l1_data = NULL; + struct i2c_data *i2c_data = NULL; + + vl53l1_dbgmsg("Enter %s : 0x%02x\n", client->name, client->addr); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + rc = -EIO; + return rc; + } + + vl53l1_data = kzalloc(sizeof(struct stmvl53l1_data), GFP_KERNEL); + if (!vl53l1_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l1_data) { + vl53l1_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + if (!vl53l1_data) + goto done_freemem; + i2c_data = (struct i2c_data *)vl53l1_data->client_object; + } + i2c_data->client = client; + i2c_data->vl53l1_data = vl53l1_data; + i2c_data->irq = -1 ; /* init to no irq */ + + /* parse and configure hardware */ + rc = stmvl53l1_parse_tree(&i2c_data->client->dev, i2c_data); + if (rc) + goto done_freemem; + + if (i2c_data->pinctrl && i2c_data->pins_active) { + rc = pinctrl_select_state(i2c_data->pinctrl, i2c_data->pins_active); + if (rc < 0) { + vl53l1_dbgmsg("Set suspend pin state error:%d", rc); + } + } + + /* setup device name */ + /* vl53l1_data->dev_name = dev_name(&client->dev); */ + + /* setup client data */ + i2c_set_clientdata(client, vl53l1_data); + + /* end up by core driver setup */ + rc = stmvl53l1_setup(vl53l1_data); + if (rc) + goto release_gpios; + vl53l1_dbgmsg("End\n"); + + kref_init(&i2c_data->ref); + stmvl53l1_i2c_data = i2c_data; + + return rc; + +release_gpios: + stmvl53l1_release_gpios(i2c_data); + +done_freemem: + /* kfree safe against NULL */ + kfree(vl53l1_data); + kfree(i2c_data); + + return -1; +} + +static int stmvl53l1_remove(struct i2c_client *client) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(client); + struct i2c_data *i2c_data = (struct i2c_data *)data->client_object; + int ret = 0; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* main driver cleanup */ + stmvl53l1_cleanup(data); + + /* release gpios */ + stmvl53l1_release_gpios(i2c_data); + + if (i2c_data->pinctrl && i2c_data->pins_active) { + ret = pinctrl_select_state(i2c_data->pinctrl, i2c_data->pins_release); + if (ret < 0) { + vl53l1_dbgmsg("Set suspend pin state error:%d", ret); + } + } + + mutex_unlock(&data->work_mutex); + + stmvl53l1_put(data->client_object); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int stmvl53l1_suspend(struct device *dev) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + int ret = 0; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* Stop ranging */ + stmvl53l1_pm_suspend_stop(data); + + mutex_unlock(&data->work_mutex); + + if (stmvl53l1_i2c_data->pinctrl && stmvl53l1_i2c_data->pins_suspend) { + ret = pinctrl_select_state(stmvl53l1_i2c_data->pinctrl, stmvl53l1_i2c_data->pins_suspend); + if (ret < 0) { + vl53l1_dbgmsg("Set suspend pin state error:%d", ret); + } + } + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_resume(struct device *dev) +{ + int ret = 0; +#if 0 + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + vl53l1_dbgmsg("Enter\n"); + + mutex_lock(&data->work_mutex); + + /* do nothing user will restart measurements */ + + mutex_unlock(&data->work_mutex); + + vl53l1_dbgmsg("End\n"); +#else + vl53l1_dbgmsg("Enter\n"); + if (stmvl53l1_i2c_data->pinctrl && stmvl53l1_i2c_data->pins_active) { + ret = pinctrl_select_state(stmvl53l1_i2c_data->pinctrl, stmvl53l1_i2c_data->pins_active); + if (ret < 0) { + vl53l1_dbgmsg("Set suspend pin state error:%d", ret); + } + } + + vl53l1_dbgmsg("End\n"); +#endif + return 0; +} +#endif + + +static SIMPLE_DEV_PM_OPS(stmvl53l1_pm_ops, stmvl53l1_suspend, stmvl53l1_resume); + +static const struct i2c_device_id stmvl53l1_id[] = { + { STMVL53L1_DRV_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); + +static const struct of_device_id st_stmvl53l1_dt_match[] = { + { .compatible = "st,"STMVL53L1_DRV_NAME, }, + { }, +}; + +static struct i2c_driver stmvl53l1_driver = { + .driver = { + .name = STMVL53L1_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l1_dt_match, + .pm = &stmvl53l1_pm_ops, + }, + .probe = stmvl53l1_probe, + .remove = stmvl53l1_remove, + .id_table = stmvl53l1_id, + +}; + +/** + * give power to device + * + * @param object the i2c layer object + * @return + */ +int stmvl53l1_power_up_i2c(void *object) +{ + int rc = 0; + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + + /* turn on power */ + if (data->vdd) { + rc = regulator_enable(data->vdd); + if (rc) { + vl53l1_errmsg("fail to turn on regulator"); + return rc; + } + } else if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 1); + vl53l1_info("slow power on"); + } else + vl53l1_wanrmsg("no power control"); + + return rc; +} + +/** + * remove power to device (reset it) + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_power_down_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + int rc = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* turn off power */ + if (data->vdd) { + rc = regulator_disable(data->vdd); + if (rc) + vl53l1_errmsg("reg disable failed. rc=%d\n", + rc); + } else if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 0); + } + vl53l1_dbgmsg("power off"); + + vl53l1_dbgmsg("End\n"); + + return rc; +} + +static int handle_i2c_address_device_change_lock(struct i2c_data *data) +{ + struct i2c_client *client = (struct i2c_client *) data->client; + uint8_t buffer[3]; + struct i2c_msg msg; + int rc = 0; + + vl53l1_dbgmsg("change device i2c address from 0x%02x to 0x%02x", + data->boot_reg, client->addr); + /* no i2c-access must occur before fw boot time */ + usleep_range(VL53L1_FIRMWARE_BOOT_TIME_US, + VL53L1_FIRMWARE_BOOT_TIME_US + 1); + + /* manually send message to update i2c address */ + buffer[0] = (VL53L1_I2C_SLAVE__DEVICE_ADDRESS >> 8) & 0xFF; + buffer[1] = (VL53L1_I2C_SLAVE__DEVICE_ADDRESS >> 0) & 0xFF; + buffer[2] = client->addr; + msg.addr = data->boot_reg; + msg.flags = client->flags; + msg.buf = buffer; + msg.len = 3; + if (i2c_transfer(client->adapter, &msg, 1) != 1) { + rc = -ENXIO; + vl53l1_errmsg("Fail to change i2c address to 0x%02x", + client->addr); + } + + return rc; +} + +/* reset release will also handle device address change. It will avoid state + * where multiple stm53l1 are bring out of reset at the same time with the + * same boot address. + * Note that we don't manage case where boot_reg has the same value as a final + * i2c address of another device. This case is not supported and will lead + * to unpredictable behavior. + */ +static int release_reset(struct i2c_data *data) +{ + struct i2c_client *client = (struct i2c_client *) data->client; + int rc = 0; + bool is_address_change = client->addr != data->boot_reg; + + if (is_address_change) + mutex_lock(&dev_addr_change_mutex); + + gpio_set_value(data->xsdn_gpio, 1); + if (is_address_change) { + rc = handle_i2c_address_device_change_lock(data); + if (rc) + gpio_set_value(data->xsdn_gpio, 0); + } + + if (is_address_change) + mutex_unlock(&dev_addr_change_mutex); + + return rc; +} + +/** + * release device reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_release_i2c(void *i2c_object) +{ + int rc; + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + rc = release_reset(data); + if (rc) + goto error; + + /* and now wait for device end of boot */ + data->vl53l1_data->is_delay_allowed = true; + rc = VL53L1_WaitDeviceBooted(&data->vl53l1_data->stdev); + data->vl53l1_data->is_delay_allowed = false; + if (rc) { + gpio_set_value(data->xsdn_gpio, 0); + vl53l1_errmsg("boot fail with error %d", rc); + data->vl53l1_data->last_error = rc; + rc = -EIO; + } + +error: + vl53l1_dbgmsg("End\n"); + + return rc; +} + +/** + * put device under reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_hold_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + gpio_set_value(data->xsdn_gpio, 0); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +int stmvl53l1_init_i2c(void) +{ + int ret = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* register as a i2c client device */ + ret = i2c_add_driver(&stmvl53l1_driver); + if (ret) + vl53l1_errmsg("%d erro ret:%d\n", __LINE__, ret); + + if (!ret && force_device) + ret = insert_device(); + + if (ret) + i2c_del_driver(&stmvl53l1_driver); + + vl53l1_dbgmsg("End with rc:%d\n", ret); + + return ret; +} + + +void stmvl53l1_clean_up_i2c(void) +{ + if (stm_test_i2c_client) { + vl53l1_dbgmsg("to unregister i2c client\n"); + i2c_unregister_device(stm_test_i2c_client); + } +} + +static irqreturn_t stmvl53l1_irq_handler_i2c(int vec, void *info) +{ + struct i2c_data *i2c_data = (struct i2c_data *)info; + + if (i2c_data->irq == vec) { + modi2c_dbg("irq"); + stmvl53l1_intr_handler(i2c_data->vl53l1_data); + modi2c_dbg("over"); + } else { + if (!i2c_data->msg_flag.unhandled_irq_vec) { + modi2c_warn("unmatching vec %d != %d\n", + vec, i2c_data->irq); + i2c_data->msg_flag.unhandled_irq_vec = 1; + } + } + + return IRQ_HANDLED; +} + +/** + * enable and start intr handling + * + * @param object our i2c_data specific object + * @param poll_mode [in/out] set to force mode clear to use irq + * @return 0 on success and set ->poll_mode if it faill ranging wan't start + */ +int stmvl53l1_start_intr(void *object, int *poll_mode) +{ + struct i2c_data *i2c_data; + int rc; + + i2c_data = (struct i2c_data *)object; + /* irq and gpio acquire config done in parse_tree */ + if (i2c_data->irq < 0) { + /* the i2c tree as no intr force polling mode */ + *poll_mode = -1; + return 0; + } + /* clear irq warning report enabe it again for this session */ + i2c_data->msg_flag.unhandled_irq_vec = 0; + /* if started do no nothing */ + if (i2c_data->io_flag.intr_started) { + /* nothing to do */ + *poll_mode = 0; + return 0; + } + + vl53l1_dbgmsg("to register_irq:%d\n", i2c_data->irq); + rc = request_threaded_irq(i2c_data->irq, NULL, + stmvl53l1_irq_handler_i2c, + IRQF_TRIGGER_FALLING|IRQF_ONESHOT, + "vl53l1_interrupt", + (void *)i2c_data); + if (rc) { + vl53l1_errmsg("fail to req threaded irq rc=%d\n", rc); + *poll_mode = 0; + } else { + vl53l1_dbgmsg("irq %d now handled\n", i2c_data->irq); + i2c_data->io_flag.intr_started = 1; + *poll_mode = 0; + } + return rc; +} + +void *stmvl53l1_get(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_get(&data->ref); + vl53l1_dbgmsg("End\n"); + + return object; +} + +static void memory_release(struct kref *kref) +{ + struct i2c_data *data = container_of(kref, struct i2c_data, ref); + + vl53l1_dbgmsg("Enter\n"); + kfree(data->vl53l1_data); + kfree(data); + vl53l1_dbgmsg("End\n"); +} + +void stmvl53l1_put(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_put(&data->ref, memory_release); + vl53l1_dbgmsg("End\n"); +} + +void __exit stmvl53l1_exit_i2c(void *i2c_object) +{ + vl53l1_dbgmsg("Enter\n"); + i2c_del_driver(&stmvl53l1_driver); + vl53l1_dbgmsg("End\n"); +} diff --git a/drivers/input/misc/vl53L1/stmvl53l1_module.c b/drivers/input/misc/vl53L1/stmvl53l1_module.c new file mode 100644 index 0000000000000000000000000000000000000000..2c89dd80f67eba4099fc4c7810f18825be6b56f3 --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_module.c @@ -0,0 +1,4392 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * main file + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * API includes + */ + +#include "stmvl53l1.h" +#include "stmvl53l1-i2c.h" +#include "stmvl53l1_ipp.h" + +#include "stmvl53l1_if.h" /* our device interface to user space */ +#include "stmvl53l1_internal_if.h" + +/* + * include default tuning file + */ +#include "stmvl53l1_tunings.h" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * default polling period delay in millisecond + * + * It can be set at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + * + * @note apply only for device operating in polling mode only + */ +#define STMVL53L1_CFG_POLL_DELAY_MS 5 + +/** + * default timing budget in microsecond + * + * Can be change at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + */ + +#define STMVL53L1_CFG_TIMING_BUDGET_US 30000//16000 + +/** default preset ranging mode */ +#define STMVL53L1_CFG_DEFAULT_MODE VL53L1_PRESETMODE_RANGING + +/** default distance mode */ +#define STMVL53L1_CFG_DEFAULT_DISTANCE_MODE VL53L1_DISTANCEMODE_LONG + +/** default crosstalk enable */ + +#define STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE 1//0 + +/** default output mode */ +#define STMVL53L1_CFG_DEFAULT_OUTPUT_MODE VL53L1_OUTPUTMODE_NEAREST + +#define STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE \ + VL53L1_OFFSETCORRECTIONMODE_STANDARD + +/** default Dmax mode */ +#define STMVL53L1_CFG_DEFAULT_DMAX_MODE VL53L1_DMAXMODE_FMT_CAL_DATA + +/** default smudge correction enable value */ +#define STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE \ + VL53L1_SMUDGE_CORRECTION_CONTINUOUS + +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ + +/** + * activate dump of roi in roi ctrl operation + * + * @note uses @a vl53l1_dbgmsg for output so make sure to enable debug + * to get roi dump + */ + +#define STMVL53L1_CFG_ROI_DEBUG 1 + +/** @} */ /* ingroup vl53l1_mod_dbg*/ + +static inline void st_gettimeofday(struct timeval *tv) +{ + struct timespec64 now; + + ktime_get_real_ts64(&now); + tv->tv_sec = now.tv_sec; + tv->tv_usec = now.tv_nsec/1000; +} + +/* #define DEBUG_TIME_LOG */ + + +#ifdef DEBUG_TIME_LOG +struct timeval start_tv, stop_tv; +#endif + +/* Set default value to 1 to allow to see module insertion debug messages */ +int stmvl53l1_enable_debug = 1; + +#define VL53L1_INPUT_DEVICE_NAME "STM VL53L1 proximity sensor" + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +static int stmvl53l1_open(struct inode *inode, struct file *file); +static int stmvl53l1_release(struct inode *inode, struct file *file); +static int ctrl_start(struct stmvl53l1_data *data); +static int ctrl_stop(struct stmvl53l1_data *data); + +static bool force_device_on_en_default = false; + +module_param(force_device_on_en_default, bool, 0444); +MODULE_PARM_DESC(force_device_on_en_default, + "select whether force_device_on_en is true or false by default"); + +/* boilerplate for integer parameter */ +#define IMPLEMENT_PARAMETER_INTEGER(sysfs_name, info_name)\ +static ssize_t stmvl53l1_show_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ + param = data->sysfs_name; \ + mutex_unlock(&data->work_mutex);; \ +\ + return scnprintf(buf, PAGE_SIZE, "%d\n", param); \ +} \ +\ +static ssize_t stmvl53l1_store_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int rc; \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ +\ + if (kstrtoint(buf, 0, ¶m)) { \ + vl53l1_errmsg("invalid syntax in %s", buf); \ + rc = -EINVAL; \ + } else \ + rc = stmvl53l1_set_##sysfs_name(data, param); \ +\ + mutex_unlock(&data->work_mutex); \ +\ + return rc ? rc : count; \ +} \ +\ +static int ctrl_param_##sysfs_name(struct stmvl53l1_data *data, \ + struct stmvl53l1_parameter *param) \ +{ \ + int rc; \ +\ + if (param->is_read) { \ + param->value = data->sysfs_name; \ + param->status = 0; \ + vl53l1_dbgmsg("get " info_name " %d", param->value); \ + rc = 0; \ + } else { \ + rc = stmvl53l1_set_##sysfs_name(data, param->value); \ + vl53l1_dbgmsg("rc %d req %d now %d", rc, \ + param->value, data->sysfs_name); \ + } \ +\ + return rc; \ +} + +/** + * module interface struct + * interface to platform speficic device handling , concern power/reset ... + */ +struct stmvl53l1_module_fn_t { + int (*init)(void); /*!< init */ + /** + * clean up job + * @param data module specific data ptr + */ + void (*deinit)(void *data); + /** + * give device power + * @param data specific module storage ptr + * @return 0 on sucess + */ + int (*power_up)(void *data); + /** + * power down TOFO also stop intr + */ + int (*power_down)(void *data); + /* + * release reset so device start. + */ + int (*reset_release)(void *data); + /* + * put device under reset. + */ + int (*reset_hold)(void *data); + + /** + * enable interrupt + * + * @param object : interface speficic ptr + * @note "module specfic ptr is data->client_object + * @return 0 on success else error then drievr wan't start ranging! + * if no interrupt or it can't be hooked but still to operated in poll + * mode then return 0 and force data->poll_mode + * might have to clear poll_mode exlplcilty if to operate in real intr + * mode as pool mode + * is the default + */ + int (*start_intr)(void *object, int *poll_mode); + + void (*clean_up)(void); /*!< optional can be void */ + + /* increment reference counter */ + void *(*get)(void *object); + + /* decrement reference counter and deallocate memory when zero */ + void (*put)(void *object); +}; + +/** i2c module interface*/ +static struct stmvl53l1_module_fn_t stmvl53l1_module_func_tbl = { + .init = stmvl53l1_init_i2c, + .deinit = stmvl53l1_exit_i2c, + .power_up = stmvl53l1_power_up_i2c, + .power_down = stmvl53l1_power_down_i2c, + .reset_release = stmvl53l1_reset_release_i2c, + .reset_hold = stmvl53l1_reset_hold_i2c, + .clean_up = stmvl53l1_clean_up_i2c, + .start_intr = stmvl53l1_start_intr, + .get = stmvl53l1_get, + .put = stmvl53l1_put, +}; + + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * INPUT Subsys interface + */ + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data); + +static int FP4SetCalibrationData(struct stmvl53l1_data *pData); + +/* + * Mutex to handle device id add/removal + */ +static DEFINE_MUTEX(dev_table_mutex); + +/** + * in-used device LUT + * we need this as the message reception from netlink message can't + * associate directly to a device instance that is as we look up id + * to device data structure + */ +struct stmvl53l1_data *stmvl53l1_dev_table[STMVL53L1_CFG_MAX_DEV]; + +/** + * Misc device device operations + */ +static const struct file_operations stmvl53l1_ranging_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = stmvl53l1_ioctl, + .open = stmvl53l1_open, + .release = stmvl53l1_release, + /* .flush = stmvl53l0_flush, */ +}; + +static int store_last_error(struct stmvl53l1_data *data, int rc) +{ + data->last_error = rc; + + return -EIO; +} + +static int allocate_dev_id(void) +{ + int i; + + mutex_lock(&dev_table_mutex); + + for (i = 0; i < STMVL53L1_CFG_MAX_DEV; i++) + if (!stmvl53l1_dev_table[i]) + break; + i = i < STMVL53L1_CFG_MAX_DEV ? i : -1; + + mutex_unlock(&dev_table_mutex); + + return i; +} + +static void deallocate_dev_id(int id) +{ + mutex_lock(&dev_table_mutex); + + stmvl53l1_dev_table[id] = NULL; + + mutex_unlock(&dev_table_mutex); +} + +/* helpers to manage reader list for blockint ioctl */ +/* call them with lock */ +static void empty_and_free_list(struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + struct stmvl53l1_waiters *tmp; + + list_for_each_entry_safe(waiter, tmp, head, list) { + list_del(&waiter->list); + kfree(waiter); + } +} + +static int add_reader(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *new_waiter; + + new_waiter = kmalloc(sizeof(struct stmvl53l1_waiters), GFP_KERNEL); + if (!new_waiter) + return -ENOMEM; + new_waiter->pid = pid; + list_add(&new_waiter->list, head); + + return 0; +} + +static bool is_pid_in_list(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + + list_for_each_entry(waiter, head, list) + if (waiter->pid == pid) + return true; + + return false; +} + +static void wake_up_data_waiters(struct stmvl53l1_data *data) +{ + empty_and_free_list(&data->simple_data_reader_list); + empty_and_free_list(&data->mz_data_reader_list); + wake_up(&data->waiter_for_data); +} + +static void stmvl53l1_insert_flush_events_lock(struct stmvl53l1_data *data) +{ + while (data->flush_todo_counter) { + data->flushCount++; + input_report_abs(data->input_dev_ps, ABS_GAS, data->flushCount); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Sensor HAL Flush Count = %u\n", + data->flushCount); + data->flush_todo_counter--; + } +} + +static int reset_release(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("turn on vdd\n"); + rc = stmvl53l1_module_func_tbl.power_up(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error rc %d\n", __LINE__, rc); + return rc; + } + + if (!data->reset_state) + return 0; + + rc = stmvl53l1_module_func_tbl.reset_release(data->client_object); + if (rc) { + vl53l1_errmsg("reset release fail rc=%d\n", rc); + stmvl53l1_module_func_tbl.power_down(data->client_object); + } + else + data->reset_state = 0; + + return rc; +} + +static int reset_hold(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("turn off vdd data reset_state=%d\n", data->reset_state); + rc = stmvl53l1_module_func_tbl.power_down(data->client_object); + + if (data->reset_state) + return 0; + + if (data->force_device_on_en) + return 0; + + rc = stmvl53l1_module_func_tbl.reset_hold(data->client_object); + if (!rc) + data->reset_state = 1; + + return rc; +} + +#ifdef DEBUG_TIME_LOG +static void stmvl53l0_DebugTimeGet(struct timeval *ptv) +{ + st_gettimeofday(ptv); +} + +#endif + +/** + * + * @param pstart_tv time val starting point + * @param pstop_tv time val end point + * @return time dif in usec + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv) +{ + long total_sec, total_usec; + + total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec; + total_usec = (pstop_tv->tv_usec - pstart_tv->tv_usec); + + return total_sec*1000000+total_usec; +} + +#if STMVL53L1_CFG_ROI_DEBUG +static void dump_roi(VL53L1_UserRoi_t *rois, uint32_t n) +{ + uint32_t i; + + vl53l1_dbgmsg("roi dump %d roi:\n", n); + for (i = 0; i < n ; i++) { + vl53l1_dbgmsg("ROI#%02d %2d %2d %2d %2d\n", (int)i, + (int)rois[i].TopLeftX, (int)rois[i].TopLeftY, + (int)rois[i].BotRightX, (int)rois[i].BotRightY); + } +} +#else +# define dump_roi(...) (void)0 +#endif + +static int setup_tunings(struct stmvl53l1_data *data) +{ + int rc = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tunings); i++) { + rc = VL53L1_SetTuningParameter(&data->stdev, tunings[i][0], + tunings[i][1]); + if (rc) { + rc = store_last_error(data, rc); + break; + } + } + + return rc; +} + +/** + * + * @param data device data + * @return non 0 if current "preset mode" is a multi zone one + */ +static int is_mz_mode(struct stmvl53l1_data *data) +{ + return data->preset_mode == VL53L1_PRESETMODE_RANGING || + data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING; +} + +static void kill_mz_data(VL53L1_MultiRangingData_t *pdata) +{ + int i; + + memset(pdata, 0, sizeof(*pdata)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + pdata->RangeData[i].RangeStatus = VL53L1_RANGESTATUS_NONE; + pdata->RoiStatus = VL53L1_ROISTATUS_NOT_VALID; +} + + +static VL53L1_CalibrationData_t laser_cali_data; //Add for save calibration data + +#define ALL_CALIBRATION_FILE "/mnt/vendor/persist/camera/vl53l1_cali.bin" +static int readCalibrationDataDone = 0; //for csc reload calibration data use +static int cali_size = 372; +static uint8_t golden_cali_data[] = {18,1,171,236,255,255,255,250,255,11,0,6,1,134,243,118,156,1,0,0,0,0,0,0,0,10,0,0,7,0,8,0,0,0,0,0,0,0,20,0,0,1,230,59,225,9,64,6,96,1,0,1,112,9,80,49,215,2,20,7,149,115,0,0,0,0,0,0,0,0,0,0,0,12,12,0,47,0,0,0,141,1,0,0,207,1,0,0,117,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,0,0,0,0,0,0,0,0,0,73,40,6,9,40,0,81,188,73,16,243,118,0,0,0,126,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,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,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,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,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,23,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,0,0,0,0,0,0,0,0,0,0,136,126,219,7,195,7,0,0,0,0,25,0,5,0,5,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,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}; +static int32_t get_size_from_file(const char *filename, uint64_t* size) +{ + struct kstat stat; + mm_segment_t fs; + int rc = 0; + + stat.size = 0; + + fs = get_fs(); + set_fs(KERNEL_DS); + + rc = vfs_stat(filename,&stat); + if(rc < 0) + { + pr_err("vfs_stat(%s) failed, rc = %d\n",filename,rc); + rc = -1; + goto END; + } + + *size = stat.size; + END: + set_fs(fs); + return rc; +} +static int read_file_into_buffer(const char *filename, uint8_t* data, uint32_t size) +{ + struct file *fp; + mm_segment_t fs; + loff_t pos; + int rc; + + fp = filp_open(filename,O_RDONLY,S_IRWXU | S_IRWXG | S_IRWXO); + if (IS_ERR(fp)) { + pr_err("open(%s) failed\n", filename); + return -1; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + + pos = 0; + rc = vfs_read(fp, data, size, &pos); + + set_fs(fs); + filp_close(fp, NULL); + + return rc; +} +static int FP4SetCalibrationData(struct stmvl53l1_data *data) { + int rc = 0; + int get_size = 0; + uint64_t size; + uint8_t* pBuffer; + + vl53l1_info("read calibraiont data done (%d),",readCalibrationDataDone); + if (readCalibrationDataDone == 0) { + if(get_size_from_file(ALL_CALIBRATION_FILE, &size) != 0) { + //read golden calibration data if read file failed + if (cali_size > sizeof(uint8_t) *sizeof(VL53L1_CalibrationData_t)) { + memcpy(&laser_cali_data,golden_cali_data,sizeof(uint8_t) *sizeof(VL53L1_CalibrationData_t)); + } else { + memcpy(&laser_cali_data,golden_cali_data,cali_size); + } + readCalibrationDataDone = 1; + vl53l1_info("read golden calibration data"); + } else { + if(!(size == sizeof(VL53L1_CalibrationData_t))){ + vl53l1_errmsg("get size(%d) struct size(%d)\n",size,sizeof(VL53L1_CalibrationData_t)); + /*rc = -1; + goto END;*/ + } + pBuffer = kzalloc(sizeof(uint8_t) *sizeof(VL53L1_CalibrationData_t), GFP_KERNEL); + if (pBuffer) { + get_size = read_file_into_buffer(ALL_CALIBRATION_FILE, pBuffer, size); + if (get_size > sizeof(uint8_t) *sizeof(VL53L1_CalibrationData_t)) { + memcpy(&laser_cali_data,pBuffer,sizeof(uint8_t) *sizeof(VL53L1_CalibrationData_t)); + readCalibrationDataDone = 1; + } else if (get_size > 0) { + memcpy(&laser_cali_data,pBuffer,get_size); + readCalibrationDataDone = 1; + } else{ + rc = -1; + kfree(pBuffer); + goto END; + vl53l1_errmsg("calibration data size(%d) is abnormal, normal(%d)\n",get_size,sizeof(uint8_t) *sizeof(VL53L1_CalibrationData_t)); + } + kfree(pBuffer); + }else{ + rc = -1; + vl53l1_errmsg("alloc buffer fail\n"); + goto END; + } + } + + rc = VL53L1_SetCalibrationData(&data->stdev, &laser_cali_data); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d\n", rc); + rc = store_last_error(data, rc); + }else{ + vl53l1_info("set calibration data done"); + } + }else if(readCalibrationDataDone == 1){ + rc = VL53L1_SetCalibrationData(&data->stdev, &laser_cali_data); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d\n", rc); + rc = store_last_error(data, rc); + }else{ + vl53l1_info("set calibration data done"); + } + }else{ + rc = -1; + vl53l1_errmsg("get_size_from_file fail\n"); + } + + END: + return rc; +} +static void stmvl53l1_setup_auto_config(struct stmvl53l1_data *data) +{ + /* default config is detect object below 300mm with 1s period */ + data->auto_pollingTimeInMs = 1000; + data->auto_config.DetectionMode = VL53L1_DETECTION_DISTANCE_ONLY; + data->auto_config.IntrNoTarget = 0; + data->auto_config.Distance.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Distance.High = 1000; + data->auto_config.Distance.Low = 300; + data->auto_config.Rate.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Rate.High = 0; + data->auto_config.Rate.Low = 0; +} + +static uint32_t stmvl53l1_compute_hash(VL53L1_RoiConfig_t *roi_cfg) +{ + return jhash(roi_cfg->UserRois, + roi_cfg->NumberOfRoi * sizeof(VL53L1_UserRoi_t), + roi_cfg->NumberOfRoi); +} + +static int stmvl53l1_check_calibration_id(struct stmvl53l1_data *data) +{ + uint32_t roi_id; + int rc; + + if (data->offset_correction_mode != VL53L1_OFFSETCORRECTIONMODE_PERZONE) + return 0; + if (data->current_roi_id == 0) + return 0; + + roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + rc = roi_id == data->current_roi_id ? 0 : -EINVAL; + + if (rc) + vl53l1_errmsg( + "Mismatch in zone calibration data 0x%08x != 0x%08x", + roi_id, data->current_roi_id); + + return rc; +} + +/** + * send params to sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_sendparams(struct stmvl53l1_data *data) +{ + int rc; + + /* activated stored or last request defined mode */ + rc = VL53L1_SetPresetMode(&data->stdev, data->preset_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode %d fail %d", + data->preset_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = VL53L1_SetXTalkCompensationEnable(&data->stdev, + data->crosstalk_enable); + if (rc) { + vl53l1_errmsg("VL53L1_SetXTalkCompensationEnable %d fail %d", + data->crosstalk_enable, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply distance mode only in lite and standard ranging */ + rc = VL53L1_SetDistanceMode(&data->stdev, data->distance_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetDistanceMode %d fail %d", + data->distance_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply timing budget */ + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + data->timing_budget); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", + data->timing_budget, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("timing budget @%d\n", data->timing_budget); + + /* apply offset correction mode */ + rc = VL53L1_SetOffsetCorrectionMode(&data->stdev, + data->offset_correction_mode); + if (rc) { + vl53l1_errmsg("offset correction mode %d fail %d", + data->offset_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("offset correction mode @%d\n", + data->offset_correction_mode); + + /* check zone calibration vs roi */ + rc = stmvl53l1_check_calibration_id(data); + if (rc) + goto done; + + /* apply Dmax reflectance */ + rc = VL53L1_SetDmaxReflectance(&data->stdev, data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("dmax relectance %d fail %d", + data->dmax_reflectance, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax reflectance @%d\n", data->dmax_reflectance); + + /* apply Dmax mode */ + rc = VL53L1_SetDmaxMode(&data->stdev, data->dmax_mode); + if (rc) { + vl53l1_errmsg("dmax mode %d fail %d", data->dmax_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax mode @%d\n", data->dmax_mode); + + /* apply smudge correction enable */ + rc = VL53L1_SmudgeCorrectionEnable(&data->stdev, + data->smudge_correction_mode); + if (rc) { + vl53l1_errmsg("smudge correction mode %d fail %d", + data->smudge_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("smudge correction mode @%d\n", + data->smudge_correction_mode); + + /* apply roi if any set */ + if (data->roi_cfg.NumberOfRoi) { + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("#%d custom ROI set status\n", + data->roi_cfg.NumberOfRoi); + } else { + vl53l1_dbgmsg("using default ROI\n"); + } + + /* set autonomous mode configuration */ + if ((data->preset_mode == VL53L1_PRESETMODE_AUTONOMOUS) || + (data->preset_mode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) { + rc = VL53L1_SetInterMeasurementPeriodMilliSeconds(&data->stdev, + data->auto_pollingTimeInMs); + if (rc) { + vl53l1_errmsg("Fail to set auto period %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = VL53L1_SetThresholdConfig(&data->stdev, + &data->auto_config); + if (rc) { + vl53l1_errmsg("Fail to set auto config %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + } + +done: + + return rc; +} + +/** + * start sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_start(struct stmvl53l1_data *data) +{ + int rc; + + data->is_first_irq = true; + data->is_data_valid = false; + data->is_xtalk_value_changed = false; + vl53l1_info("ST_Laser start E"); + rc = reset_release(data); + if (rc) + goto done; + + /* full setup when out of reset or power up */ + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit @%d fail %d\n", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = FP4SetCalibrationData(data); + if (rc) { + vl53l1_errmsg("VL53L1 Set calibration data fail rc(%d)\n",rc); + } + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + /* init the timing */ + st_gettimeofday(&data->start_tv); + data->meas.start_tv = data->start_tv; + /* init the ranging data => kill the previous ranging mz data */ + kill_mz_data(&data->meas.multi_range_data); + /* kill the single ranging data */ + memset(&data->meas.single_range_data, 0, + sizeof(VL53L1_RangingMeasurementData_t)); + + data->allow_hidden_start_stop = false; + /* kick off ranging */ + rc = VL53L1_StartMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StartMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + data->meas.cnt = 0; + data->meas.err_cnt = 0; + data->meas.err_tot = 0; + data->meas.poll_cnt = 0; + data->meas.intr = 0; + data->enable_sensor = 1; + if (data->poll_mode) { + /* kick off the periodical polling work */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } +done: + data->is_first_start_done = true; + + return rc; +} + +/** + * stop sensor + * + * work lock must be held + * @warning to be used if only started! + */ +static int stmvl53l1_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = VL53L1_StopMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StopMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + } + /* put device under reset */ + /* do we ask explicit intr stop or just use stop */ + reset_hold(data); + + data->enable_sensor = 0; + if (data->poll_mode) { + /* cancel periodical polling work */ + cancel_delayed_work(&data->dwork); + } + +#ifndef VL53L1_FULL_KERNEL + /* if we are in ipp waiting mode then abort it */ + stmvl53l1_ipp_stop(data); +#endif + /* wake up all waiters */ + /* they will receive -ENODEV error */ + wake_up_data_waiters(data); + + return rc; +} + +/* + * SysFS support + */ +static ssize_t stmvl53l1_show_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enable_sensor); +} + +static ssize_t stmvl53l1_store_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc = 0; + unsigned long val; + + rc = kstrtoul(buf, 10, &val); + if (rc) { + vl53l1_errmsg("enable sensor syntax in %s\n", buf); + return -EINVAL; + } + if (val == 1) { + rc = ctrl_start(data); + } else if (val == 0) { + rc = ctrl_stop(data); + } else { + /* TODO: Remove this workaround after investigation + * see Codex - 479397 for details + */ + vl53l1_dbgmsg("Unclog Input sub-system\n"); + /* Unclog the input device sub-system */ + input_report_abs(data->input_dev_ps, ABS_HAT0X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT0Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3Y, -1); + input_report_abs(data->input_dev_ps, ABS_WHEEL, -1); + input_report_abs(data->input_dev_ps, ABS_BRAKE, -1); + input_report_abs(data->input_dev_ps, ABS_GAS, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_X, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_Y, -1); + input_report_abs(data->input_dev_ps, ABS_TOOL_WIDTH, -1); + input_report_abs(data->input_dev_ps, ABS_DISTANCE, -1); + input_report_abs(data->input_dev_ps, ABS_THROTTLE, -1); + input_report_abs(data->input_dev_ps, ABS_RUDDER, -1); + input_report_abs(data->input_dev_ps, ABS_MISC, -1); + input_report_abs(data->input_dev_ps, ABS_VOLUME, + -1); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Unclog the input sub-system\n"); + rc = 0; + } + + vl53l1_dbgmsg("End\n"); + + return rc ? rc : count; +} + + +static ssize_t stmvl53l1_show_product_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int param; + + mutex_lock(&data->work_mutex); + param = data->product_type; + mutex_unlock(&data->work_mutex); + + return scnprintf(buf, PAGE_SIZE, "%d\n", param); +} + +/** + * sysfs attribute "product_type" [rd] + * + * @li read show the device product type + * + * @return 0 on success , EINVAL if fail to start + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(product_type, 0440/*S_IRUGO*/, + stmvl53l1_show_product_type, + NULL); + +/** + * sysfs attribute "enable_ps_sensor" [rd/wr] + * + * @li read show the current enable state + * @li write set the new state value "0" put sensor off "1" put it on + * + * @return 0 on success , EINVAL if fail to start + * + * @warning their's no check and assume exclusive usage of sysfs and ioctl\n + * Sensor will be put on/off disregard of any setup done by the ioctl channel. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_ps_sensor, + stmvl53l1_store_enable_ps_sensor); + +static int stmvl53l1_set_poll_delay_ms(struct stmvl53l1_data *data, int delay) +{ + int rc = 0; + + if (delay <= 0) + rc = -EINVAL; + else + data->poll_delay_ms = delay; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(poll_delay_ms, "poll delay ms") + +/** + * sysfs attribute "poll_delay_ms" [rd/wr] + * + * @li read show the current polling delay in millisecond + * @li write set the new polling delay in millisecond + * + * @note apply only if device is in polling mode\n + * for best performances (minimal delay and cpu load ) set it to the device + * period operating period +1 millis + + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_poll_delay_ms, + stmvl53l1_store_poll_delay_ms); + +/* Timing Budget */ +static int stmvl53l1_set_timing_budget(struct stmvl53l1_data *data, int timing) +{ + int rc = 0; + + if (timing <= 0) { + vl53l1_errmsg("invalid timing valid %d\n", timing); + rc = -EINVAL; + } else if (data->enable_sensor) { + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + timing); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", timing, rc); + rc = store_last_error(data, rc); + } else + data->timing_budget = timing; + } else + data->timing_budget = timing; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(timing_budget, "timing budget") + +/** + * sysfs "timing_budget" [rd/wr] + * + * set or get the ranging timing budget in microsecond + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(timing_budget, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_timing_budget, + stmvl53l1_store_timing_budget); + + +static ssize_t stmvl53l1_show_roi(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int i; + int n; + + + mutex_lock(&data->work_mutex); + if (data->roi_cfg.NumberOfRoi == 0) { + /* none define by user */ + /* we could get what stored but may not even be default */ + n = scnprintf(buf, PAGE_SIZE, "device default\n"); + } else { + for (i = 0, n = 0; i < data->roi_cfg.NumberOfRoi; i++) { + n += scnprintf(buf+n, PAGE_SIZE-n, "%d %d %d %d%c", + data->roi_cfg.UserRois[i].TopLeftX, + data->roi_cfg.UserRois[i].TopLeftY, + data->roi_cfg.UserRois[i].BotRightX, + data->roi_cfg.UserRois[i].BotRightY, + i == data->roi_cfg.NumberOfRoi-1 ? + '\n' : ','); + } + } + mutex_unlock(&data->work_mutex); + return n; +} + + +static const char str_roi_ranging[] = "ERROR can't set roi while ranging\n"; + +static ssize_t stmvl53l1_store_roi(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_UserRoi_t rois[VL53L1_MAX_USER_ZONES]; + int rc; + + mutex_lock(&data->work_mutex); + if (data->enable_sensor) { + vl53l1_errmsg(" cant set roi now\n"); + rc = -EBUSY; + } else { + int n, n_roi = 0; + const char *pc = buf; + int tlx, tly, brx, bry; + + while (n_roi < VL53L1_MAX_USER_ZONES && pc != NULL + && *pc != 0 && *pc != '\n') { + n = sscanf(pc, "%d %d %d %d", &tlx, &tly, &brx, &bry); + if (n == 4) { + rois[n_roi].TopLeftX = tlx; + rois[n_roi].TopLeftY = tly; + rois[n_roi].BotRightX = brx; + rois[n_roi].BotRightY = bry; + n_roi++; + } else { + vl53l1_errmsg( +"wrong roi #%d syntax around %s of %s", n_roi, pc, buf); + n_roi = -1; + break; + } + /* find next roi separator */ + pc = strchr(pc, ','); + if (pc) + pc++; + } + /*if any set them */ + if (n_roi >= 0) { + if (n_roi) + memcpy(data->roi_cfg.UserRois, rois, + n_roi*sizeof(rois[0])); + data->roi_cfg.NumberOfRoi = n_roi; + dump_roi(data->roi_cfg.UserRois, + data->roi_cfg.NumberOfRoi); + rc = count; + } else { + rc = -EINVAL; + } + } + mutex_unlock(&data->work_mutex); + vl53l1_dbgmsg("ret %d count %d\n", rc, (int)count); + + return rc; +} + +/** + * sysfs attribute "roi" [rd/wr] + * + * @li read show the current user customized roi setting + * @li write set user custom roi, it can only be done while not ranging. + * + * syntax for set input roi + * @li "[tlx tly brx bry,]\n" repeat n time require will set the n roi + * @li "\n" will reset + * + * @warning roi coordinate is not image x,y(down) but euclidian x,y(up) + * + * @warning roi validity is only check at next range start + * @warning user is responsible to set appropriate number an roi before each + * mode change + * @note roi can be return to default by setting none "" + * + *@code + * >#to set 2x roi + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * >echo $? + * 0 + * >cat /sys/class/input6/roi + * "0 15 15 0,0 8 8 0" + * #to cancel user define roi" + * >echo "" > /sys/class/input1/roi + * >echo $? + * 0 + * >echo "1" > /sys/class/input6/enable_ps_senspor + * #try to set roi while ranging + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * [58451.912109] stmvl53l1_store_roi: cant set roi now + * >echo $? + * 1 + *@endcode + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(roi, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_roi, + stmvl53l1_store_roi); + + +static int stmvl53l1_set_preset_mode(struct stmvl53l1_data *data, int mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change mode while ranging\n"); + rc = -EBUSY; + } else { + switch (mode) { + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + data->preset_mode = mode; + break; + default: + vl53l1_errmsg("invalid mode %d\n", mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(preset_mode, "preset mode") + +/** + * sysfs attribute "mode " [rd/wr] + * + * set the mode value can only be used while: not ranging + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low Power autonomous mode + * @li 5 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_preset_mode, + stmvl53l1_store_preset_mode); + +static int stmvl53l1_set_distance_mode(struct stmvl53l1_data *data, + int distance_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change distance mode while ranging\n"); + rc = -EBUSY; + } else { + switch (distance_mode) { + case VL53L1_DISTANCEMODE_SHORT: + case VL53L1_DISTANCEMODE_MEDIUM: + case VL53L1_DISTANCEMODE_LONG: + data->distance_mode = distance_mode; + break; + default: + vl53l1_errmsg("invalid distance mode %d\n", + distance_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(distance_mode, "distance mode") + +/** + * sysfs attribute " distance mode" [rd/wr] + * + * set the distance mode value can only be used while: not ranging + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(distance_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_distance_mode, + stmvl53l1_store_distance_mode); + +static int stmvl53l1_set_crosstalk_enable(struct stmvl53l1_data *data, + int crosstalk_enable) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change crosstalk enable while ranging\n"); + rc = -EBUSY; + } else if (crosstalk_enable == 0 || crosstalk_enable == 1) { + data->crosstalk_enable = crosstalk_enable; + } else { + vl53l1_errmsg("invalid crosstalk enable %d\n", + crosstalk_enable); + rc = -EINVAL; + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(crosstalk_enable, "crosstalk enable") + +/** + * sysfs attribute " crosstalk enable" [rd/wr] + * + * control if crosstalk compensation is eanble or not + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(crosstalk_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_crosstalk_enable, + stmvl53l1_store_crosstalk_enable); + +static int stmvl53l1_set_output_mode(struct stmvl53l1_data *data, + int output_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change output mode while ranging\n"); + rc = -EBUSY; + } else { + switch (output_mode) { + case VL53L1_OUTPUTMODE_NEAREST: + case VL53L1_OUTPUTMODE_STRONGEST: + data->output_mode = output_mode; + break; + default: + vl53l1_errmsg("invalid output mode %d\n", output_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(output_mode, "output mode") + +/** + * sysfs attribute " output mode" [rd/wr] + * + * set the output mode value can only be used while: not ranging + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(output_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_output_mode, + stmvl53l1_store_output_mode); + + +static int stmvl53l1_set_force_device_on_en(struct stmvl53l1_data *data, + int force_device_on_en) +{ + int rc; + + if (force_device_on_en != 0 && force_device_on_en != 1) { + vl53l1_errmsg("invalid force_device_on_en mode %d\n", + force_device_on_en); + return -EINVAL; + } + + data->force_device_on_en = force_device_on_en; + + /* don't update reset if sensor is enable */ + if (data->enable_sensor) + return 0; + + /* ok update reset according force_device_on_en value */ + if (force_device_on_en) + rc = reset_release(data); + else + rc = reset_hold(data); + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(force_device_on_en, "force device on enable") + +/** + * sysfs attribute " force_device_on_enable" [rd/wr] + * + * Control if device is put under reset when stopped. + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(force_device_on_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_force_device_on_en, + stmvl53l1_store_force_device_on_en); + +static int stmvl53l1_set_offset_correction_mode(struct stmvl53l1_data *data, + int offset_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change offset correction mode while ranging\n"); + rc = -EBUSY; + } else { + switch (offset_correction_mode) { + case VL53L1_OFFSETCORRECTIONMODE_STANDARD: + case VL53L1_OFFSETCORRECTIONMODE_PERZONE: + case VL53L1_OFFSETCORRECTIONMODE_PERVCSEL: + data->offset_correction_mode = offset_correction_mode; + break; + default: + vl53l1_errmsg("invalid offset correction mode %d\n", + offset_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(offset_correction_mode, "offset correction mode") + +/** + * sysfs attribute " offset_correction_mode" [rd/wr] + * + * Control which offset correction is apply on result. can only be used + * while: not ranging + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * @li 3 @a VL53L1_OFFSETCORRECTIONMODE_PERVCSEL + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(offset_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_offset_correction_mode, + stmvl53l1_store_offset_correction_mode); + +static ssize_t stmvl53l1_do_flush(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->work_mutex); + + data->flush_todo_counter++; + if (data->enable_sensor == 0) + stmvl53l1_insert_flush_events_lock(data); + + mutex_unlock(&data->work_mutex); + + return count; +} + +static DEVICE_ATTR(do_flush, 0660/*S_IWUGO | S_IRUGO*/, + NULL, + stmvl53l1_do_flush); + +static ssize_t stmvl53l1_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", stmvl53l1_enable_debug); +} + +static ssize_t stmvl53l1_store_enable_debug(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int enable_debug; + int rc = 0; + + if (kstrtoint(buf, 0, &enable_debug)) { + vl53l1_errmsg("invalid syntax in %s", buf); + rc = -EINVAL; + } else + stmvl53l1_enable_debug = enable_debug; + + return rc ? rc : count; +} + +/** + * sysfs attribute " debug enable" [rd/wr] + * + * dynamic control of vl53l1_dbgmsg messages. Note that in any case your code + * must be enable with DEBUG in stmvl53l1.h at compile time. + * @li 0 disable vl53l1_dbgmsg messages + * @li 1 enable vl53l1_dbgmsg messages + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_debug, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_debug, + stmvl53l1_store_enable_debug); + +static ssize_t display_FixPoint1616(char *buf, size_t size, FixPoint1616_t fix) +{ + uint32_t msb = fix >> 16; + uint32_t lsb = fix & 0xffff; + + lsb = (lsb * 1000000ULL + 32768) / 65536; + + return scnprintf(buf, size, "%d.%06d", msb, (uint32_t) lsb); +} + +static ssize_t stmvl53l1_show_autonomous_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += scnprintf(&buf[res], PAGE_SIZE, "%d %d %d %d %d %d %d ", + data->auto_pollingTimeInMs, + data->auto_config.DetectionMode, + data->auto_config.IntrNoTarget, + data->auto_config.Distance.CrossMode, + data->auto_config.Distance.High, + data->auto_config.Distance.Low, + data->auto_config.Rate.CrossMode); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.High); + + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.Low); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static const char *parse_integer(const char *buf, int *res) +{ + int rc; + + while (*buf == ' ') + buf++; + rc = sscanf(buf, "%d ", res); + if (!rc) + return NULL; + + return strchr(buf, ' '); +} + +static bool is_float_format(const char *buf, bool is_last) +{ + char *dot = strchr(buf, '.'); + char *space_or_eos = strchr(buf, is_last ? '\0' : ' '); + + if (!space_or_eos) + return !!dot; + if (!dot) + return false; + + return dot < space_or_eos ? true : false; +} + +static int parse_FixPoint16x16_lsb(const char *lsb_char) +{ + int lsb = 0; + int digit_nb = 0; + + /* parse at most 6 digits */ + lsb_char++; + while (isdigit(*lsb_char) && digit_nb < 6) { + lsb = lsb * 10 + (*lsb_char - '0'); + lsb_char++; + digit_nb++; + } + while (digit_nb++ < 6) + lsb = lsb * 10; + + return div64_s64(lsb * 65536ULL + 500000, 1000000); +} + +/* parse next fix point value and return a pointer to next blank or newline + * character according to is_last parameter. + * parse string must have digit for integer part (something like '.125' will + * return an error) or an error will be return. Only the first 6 digit of the + * decimal part will be parsed. + */ +static const char *parse_FixPoint16x16(const char *buf, FixPoint1616_t *res, + bool is_last) +{ + bool is_float; + int msb; + int lsb = 0; + int rc; + + while (*buf == ' ') + buf++; + is_float = is_float_format(buf, is_last); + + /* scan msb */ + rc = sscanf(buf, "%d ", &msb); + if (!rc) + return NULL; + /* then lsb if present */ + if (is_float) + lsb = parse_FixPoint16x16_lsb(strchr(buf, '.')); + *res = (msb << 16) + lsb; + + return strchr(buf, is_last ? '\0' : ' '); +} + +static ssize_t stmvl53l1_store_autonomous_config(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int pollingTimeInMs, DetectionMode, IntrNoTarget; + int d_CrossMode, d_High, d_Low; + int r_CrossMode; + FixPoint1616_t r_High, r_Low; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + if (data->enable_sensor) + goto busy; + + buf = parse_integer(buf, &pollingTimeInMs); + if (!buf) + goto invalid; + buf = parse_integer(buf, &DetectionMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &IntrNoTarget); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_CrossMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_High); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_Low); + if (!buf) + goto invalid; + buf = parse_integer(buf, &r_CrossMode); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_High, false); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_Low, true); + if (!buf) + goto invalid; + + data->auto_pollingTimeInMs = pollingTimeInMs; + data->auto_config.DetectionMode = DetectionMode; + data->auto_config.IntrNoTarget = IntrNoTarget; + data->auto_config.Distance.CrossMode = d_CrossMode; + data->auto_config.Distance.High = d_High; + data->auto_config.Distance.Low = d_Low; + data->auto_config.Rate.CrossMode = r_CrossMode; + data->auto_config.Rate.High = r_High; + data->auto_config.Rate.Low = r_Low; + + mutex_unlock(&data->work_mutex); + + return count; + +busy: + vl53l1_errmsg("can't change config while ranging"); + rc = -EBUSY; + goto error; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute " autonomous_config" [rd/wr] + * + * Will set/get autonomous configuration using sysfs. + * + * format is the following : + * + * + * + *@code + * > echo "1000 1 0 0 1000 300 0 2.2 1.001" > autonomous_config + *@endcode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(autonomous_config, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_autonomous_config, + stmvl53l1_store_autonomous_config); + +static ssize_t stmvl53l1_show_last_error_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", data->last_error); +} + +/** + * sysfs attribute " last_error" [rd] + * + * Will get last internal error using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(last_error, 0440/*S_IRUGO*/, + stmvl53l1_show_last_error_config, + NULL); + +static ssize_t stmvl53l1_show_optical_center_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_x); + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_y); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(optical_center, 0440/*S_IRUGO*/, + stmvl53l1_show_optical_center_config, + NULL); + +static int stmvl53l1_set_dmax_reflectance(struct stmvl53l1_data *data, + int dmax_reflectance) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change dmax reflectance while ranging\n"); + rc = -EBUSY; + } else + data->dmax_reflectance = dmax_reflectance; + + return rc; +} + +static ssize_t stmvl53l1_show_dmax_reflectance(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->dmax_reflectance); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static ssize_t stmvl53l1_store_dmax_reflectance(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + FixPoint1616_t dmax_reflectance; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + buf = parse_FixPoint16x16(buf, &dmax_reflectance, true); + if (!buf) + goto invalid; + rc = stmvl53l1_set_dmax_reflectance(data, dmax_reflectance); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "dmax_reflectance" [rd/wr] + * + * target reflectance use for calculate the ambient DMAX. can only be used + * while: not ranging + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_reflectance, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_reflectance, + stmvl53l1_store_dmax_reflectance); + +static int stmvl53l1_set_dmax_mode(struct stmvl53l1_data *data, + int dmax_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change dmax mode while ranging\n"); + rc = -EBUSY; + } else { + switch (dmax_mode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + case VL53L1_DMAXMODE_CUSTCAL_DATA: + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + data->dmax_mode = dmax_mode; + break; + default: + vl53l1_errmsg("invalid dmax mode %d\n", dmax_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(dmax_mode, "dmax mode") + +/** + * sysfs attribute " dmax mode" [rd/wr] + * + * set the dmax mode value can only be used while: not ranging + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_mode, + stmvl53l1_store_dmax_mode); + +static int stmvl53l1_set_tuning(struct stmvl53l1_data *data, int key, + int value) +{ + int rc; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change tuning params while ranging\n"); + return -EBUSY; + } + + if (data->is_calibrating) { + vl53l1_errmsg("can't change tuning params while calibrating\n"); + return -EBUSY; + } + + if (key & ~0xffff) + return -EINVAL; + + vl53l1_dbgmsg("trying to set %d with key %d", value, key); + + rc = VL53L1_SetTuningParameter(&data->stdev, key, value); + if (rc) + rc = store_last_error(data, rc); + + return rc; +} + +static ssize_t stmvl53l1_store_tuning(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int key; + int value; + int n; + int rc; + + mutex_lock(&data->work_mutex); + + n = sscanf(buf, "%d %d", &key, &value); + if (n != 2) { + rc = -EINVAL; + goto error; + } + rc = stmvl53l1_set_tuning(data, key, value); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "tuning" [wr] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning, 0220/*S_IWUGO */, + NULL, + stmvl53l1_store_tuning); + +static int stmvl53l1_display_tuning_key(struct stmvl53l1_data *data, char *buf, + int *pos, int key) +{ + int rc = 0; + int value = 0; + int sz; + + rc = VL53L1_GetTuningParameter(&data->stdev, key, &value); + if (rc) + return 0; + + sz = snprintf(&buf[*pos], PAGE_SIZE - *pos, "%d %d\n", key, value); + if (sz >= PAGE_SIZE - *pos) + return -ENOSPC; /* FIXME : another better error ? */ + + *pos += sz; + + return 0; +} + +static ssize_t stmvl53l1_show_tuning_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const int max_tuning_key = 65535; + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + int i; + int pos = 0; + + mutex_lock(&data->work_mutex); + + for (i = 0; i < max_tuning_key; ++i) { + rc = stmvl53l1_display_tuning_key(data, buf, &pos, i); + if (rc) + break; + } + + mutex_unlock(&data->work_mutex); + + return rc ? rc : pos; +} + +/** + * sysfs attribute "tuning_status" [rd] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning_status, 0440/*S_IRUGO */, + stmvl53l1_show_tuning_status, + NULL); + +static int stmvl53l1_set_smudge_correction_mode(struct stmvl53l1_data *data, + int smudge_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change smudge corr mode while ranging\n"); + rc = -EBUSY; + } else { + switch (smudge_correction_mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + case VL53L1_SMUDGE_CORRECTION_SINGLE: + case VL53L1_SMUDGE_CORRECTION_DEBUG: + data->smudge_correction_mode = smudge_correction_mode; + break; + default: + vl53l1_errmsg("invalid smudge correction mode %d\n", + smudge_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(smudge_correction_mode, "smudge correction mode") + +/** + * sysfs attribute " smudge_correction_mode" [rd/wr] + * + * This parameter will control if smudge correction is enable and how crosstalk + * values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(smudge_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_smudge_correction_mode, + stmvl53l1_store_smudge_correction_mode); + +static ssize_t stmvl53l1_show_is_xtalk_value_changed_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int param; + + mutex_lock(&data->work_mutex); + param = data->is_xtalk_value_changed; + mutex_unlock(&data->work_mutex); + + return scnprintf(buf, PAGE_SIZE, "%d\n", param); +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(is_xtalk_value_changed, 0440/*S_IRUGO*/, + stmvl53l1_show_is_xtalk_value_changed_config, + NULL); + +static struct attribute *stmvl53l1_attributes[] = { + &dev_attr_enable_ps_sensor.attr, + &dev_attr_set_delay_ms.attr, + &dev_attr_timing_budget.attr, + &dev_attr_roi.attr, + &dev_attr_mode.attr, + &dev_attr_do_flush.attr, + &dev_attr_distance_mode.attr, + &dev_attr_crosstalk_enable.attr, + &dev_attr_enable_debug.attr, + &dev_attr_output_mode.attr, + &dev_attr_force_device_on_enable.attr, + &dev_attr_autonomous_config.attr, + &dev_attr_last_error.attr, + &dev_attr_offset_correction_mode.attr, + &dev_attr_optical_center.attr, + &dev_attr_dmax_reflectance.attr, + &dev_attr_dmax_mode.attr, + &dev_attr_tuning.attr, + &dev_attr_tuning_status.attr, + &dev_attr_smudge_correction_mode.attr, + &dev_attr_is_xtalk_value_changed.attr, + &dev_attr_product_type.attr, + NULL +}; + +static const struct attribute_group stmvl53l1_attr_group = { + .attrs = stmvl53l1_attributes, +}; + +static ssize_t stmvl53l1_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_CalibrationData_t calib; + int rc; + void *src = (void *) &calib; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* sanity check */ + if (off < 0 || off > sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + /* got current calibration data */ + memset(&calib, 0, sizeof(calib)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + /* copy to buffer */ + if (off + count > sizeof(VL53L1_CalibrationData_t)) + count = sizeof(VL53L1_CalibrationData_t) - off; + memcpy(buf, src + off, count); + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto error; + } + + /* we only support one time write */ + if (off != 0 || count != sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + rc = VL53L1_SetCalibrationData(&data->stdev, + (VL53L1_CalibrationData_t *) buf); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_calib_data_attr = { + .attr = { + .name = "calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(VL53L1_CalibrationData_t), + .read = stmvl53l1_calib_data_read, + .write = stmvl53l1_calib_data_write, +}; + +static ssize_t stmvl53l1_zone_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *src = (void *) &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* sanity check */ + if (off < 0 || off > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + + /* got current zone calibration data */ + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + data->calib.data.id = data->current_roi_id; + + /* copy to buffer */ + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + count = sizeof(stmvl531_zone_calibration_data_t) - off; + memcpy(buf, src + off, count); + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_zone_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *dst = &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* implementation if quite fragile. We suppose successive access. We + * trigger set on last byte write if amount is exact. + */ + if (off < 0 || off > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + + memcpy(dst + off, buf, count); + if (off + count == sizeof(stmvl531_zone_calibration_data_t)) { + vl53l1_dbgmsg("trigger zone calib setting"); + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto error; + } + data->current_roi_id = data->calib.data.id; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_zone_calib_data_attr = { + .attr = { + .name = "zone_calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(stmvl531_zone_calibration_data_t), + .read = stmvl53l1_zone_calib_data_read, + .write = stmvl53l1_zone_calib_data_write, +}; + +static int ctrl_reg_access(struct stmvl53l1_data *data, void *p) +{ + struct stmvl53l1_register reg; + size_t total_byte; + int rc; + + if (data->is_device_remove) + return -ENODEV; + + total_byte = offsetof(struct stmvl53l1_register, data.b); + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + + if (reg.cnt > STMVL53L1_MAX_CCI_XFER_SZ) { + vl53l1_errmsg("reg len %d > size limit\n", reg.cnt); + return -EINVAL; + } + + total_byte = offsetof(struct stmvl53l1_register, data.bytes[reg.cnt]); + /* for write get the effective data part of the structure */ + if (!reg.is_read) { + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg(" data cpy fail\n"); + return -EFAULT; + } + } + + /* put back to user only needed amount of data */ + if (!reg.is_read) { + rc = VL53L1_WriteMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + /* for write only write back status no data */ + total_byte = offsetof(struct stmvl53l1_register, data.b); + vl53l1_dbgmsg("wr %x %d bytes statu %d\n", + reg.index, reg.cnt, rc); + if (rc) + rc = store_last_error(data, rc); + } else { + rc = VL53L1_ReadMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + vl53l1_dbgmsg("rd %x %d bytes status %d\n", + reg.index, reg.cnt, rc); + /* if fail do not copy back data only status */ + if (rc) { + total_byte = offsetof(struct stmvl53l1_register, + data.b); + rc = store_last_error(data, rc); + } + /* else the total byte is already the full pay-load with data */ + } + + if (copy_to_user(p, ®, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + return rc; +} + + +/* + * + */ +static int ctrl_start(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + + vl53l1_dbgmsg(" state = %d\n", data->enable_sensor); + + /* turn on tof sensor only if it's not already started */ + if (data->enable_sensor == 0 && !data->is_calibrating) { + /* to start */ + rc = stmvl53l1_start(data); + } else{ + rc = -EBUSY; + } + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * no lock version of ctrl_stop (mutex shall be held) + * + * @warning exist only for use in device exit to ensure "locked and started" + * may also beuse in soem erro handling when mutex is already locked + * @return 0 on success and was running >0 if already off <0 on error + */ +static int _ctrl_stop(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("enter state = %d\n", data->enable_sensor); + /* be sure waiters are woken */ + data->is_data_valid = true; + /* turn on tof sensor only if it's not enabled by other client */ + if (data->enable_sensor == 1) { + /* to stop */ + rc = stmvl53l1_stop(data); + } else { + vl53l1_dbgmsg("already off did nothing\n"); + rc = 0; + } + stmvl53l1_insert_flush_events_lock(data); + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + + return rc; +} + +/** + * get work lock and stop sensor + * + * see @ref _ctrl_stop + * + * @param data device + * @return 0 on success EBUSY if arleady off + */ +static int ctrl_stop(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + if (data->enable_sensor) + rc = _ctrl_stop(data); + else + rc = -EBUSY; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_getdata(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(p, + &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static bool is_new_data_for_me(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + return data->is_data_valid && !is_pid_in_list(pid, head); +} + +static bool sleep_for_data_condition(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + bool res; + + mutex_lock(&data->work_mutex); + res = is_new_data_for_me(data, pid, head); + mutex_unlock(&data->work_mutex); + + return res; +} + +static int sleep_for_data(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + int rc; + + mutex_unlock(&data->work_mutex); + rc = wait_event_killable(data->waiter_for_data, + sleep_for_data_condition(data, pid, head)); + mutex_lock(&data->work_mutex); + + return data->enable_sensor ? rc : -ENODEV; +} + +static int ctrl_getdata_blocking(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + /* If device not ranging then exit on error */ + if (data->is_device_remove || !data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->simple_data_reader_list)) + rc = sleep_for_data(data, pid, &data->simple_data_reader_list); + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(p, &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) + goto done; + rc = add_reader(pid, &data->simple_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_common(struct stmvl53l1_data *data, void __user *p, + bool is_additional) +{ + struct stmvl53l1_data_with_additional __user *d = p; + int rc; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + } + if (!data->enable_sensor) + rc = -ENODEV; + else if (!is_mz_mode(data)) + rc = -ENOEXEC; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_blocking_common(struct stmvl53l1_data *data, + void __user *p, bool is_additional) +{ + int rc = 0; + struct stmvl53l1_data_with_additional __user *d = p; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* mode 2 or 3 */ + if (!is_mz_mode(data)) { + rc = -ENOEXEC; + goto done; + } + /* If device not ranging then exit on error */ + if (!data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->mz_data_reader_list)) + rc = sleep_for_data(data, pid, &data->mz_data_reader_list); + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) + goto done; + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) + goto done; + } + rc = add_reader(pid, &data->mz_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * Get multi zone data + * @param data + * @param p [out] user ptr to @ref VL53L1_MultiRangingData_t structure\n + * is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, false); +} + +static int ctrl_mz_data_blocking(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, false); +} + +/** + * Get multi zone data with histogram debug data + * @param data + * @param p [out] user ptr to @ref struct stmvl53l1_data_with_additional + * structure is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data_additional(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, true); +} + +static int ctrl_mz_data_blocking_additional(struct stmvl53l1_data *data, + void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, true); +} + +static int ctrl_param_last_error(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->last_error; + param->status = 0; + vl53l1_dbgmsg("get last error %d", param->value); + rc = 0; + } else { + rc = -EINVAL; + } + + return rc; +} + +static int ctrl_param_optical_center(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->optical_offset_x; + param->value2 = data->optical_offset_y; + + return 0; +} + +static int ctrl_param_dmax_reflectance(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->dmax_reflectance; + param->status = 0; + vl53l1_dbgmsg("get dmax reflectance %d", param->value); + rc = 0; + } else { + rc = stmvl53l1_set_dmax_reflectance(data, param->value); + vl53l1_dbgmsg("rc %d req %d now %d", rc, + param->value, data->dmax_reflectance); + } + + return rc; +} + +static int ctrl_param_tuning(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (param->is_read) + return -EINVAL; + + return stmvl53l1_set_tuning(data, param->value, param->value2); +} + +static int ctrl_param_is_xtalk_value_changed(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->is_xtalk_value_changed; + + return 0; +} + +/** + * handle ioctl set param mode + * + * @param data + * @param p + * @return 0 on success + */ +static int ctrl_params(struct stmvl53l1_data *data, void __user *p) +{ + int rc, rc2; + struct stmvl53l1_parameter param; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(¶m, p, sizeof(param)); + param.status = 0; + if (rc) { + rc = -EFAULT; + goto done; /* no need for status in user struct */ + } + switch (param.name) { + case VL53L1_POLLDELAY_PAR: + rc = ctrl_param_poll_delay_ms(data, ¶m); + break; + case VL53L1_TIMINGBUDGET_PAR: + rc = ctrl_param_timing_budget(data, ¶m); + break; + case VL53L1_DEVICEMODE_PAR: + rc = ctrl_param_preset_mode(data, ¶m); + break; + case VL53L1_DISTANCEMODE_PAR: + rc = ctrl_param_distance_mode(data, ¶m); + break; + case VL53L1_XTALKENABLE_PAR: + rc = ctrl_param_crosstalk_enable(data, ¶m); + break; + case VL53L1_OUTPUTMODE_PAR: + rc = ctrl_param_output_mode(data, ¶m); + break; + case VL53L1_FORCEDEVICEONEN_PAR: + rc = ctrl_param_force_device_on_en(data, ¶m); + break; + case VL53L1_LASTERROR_PAR: + rc = ctrl_param_last_error(data, ¶m); + break; + case VL53L1_OFFSETCORRECTIONMODE_PAR: + rc = ctrl_param_offset_correction_mode(data, ¶m); + break; + case VL53L1_OPTICALCENTER_PAR: + rc = ctrl_param_optical_center(data, ¶m); + break; + case VL53L1_DMAXREFLECTANCE_PAR: + rc = ctrl_param_dmax_reflectance(data, ¶m); + break; + case VL53L1_DMAXMODE_PAR: + rc = ctrl_param_dmax_mode(data, ¶m); + break; + case VL53L1_TUNING_PAR: + rc = ctrl_param_tuning(data, ¶m); + break; + case VL53L1_SMUDGECORRECTIONMODE_PAR: + rc = ctrl_param_smudge_correction_mode(data, ¶m); + break; + case VL53L1_ISXTALKVALUECHANGED_PAR: + rc = ctrl_param_is_xtalk_value_changed(data, ¶m); + break; + default: + vl53l1_errmsg("unknown or unsupported %d\n", param.name); + rc = -EINVAL; + } + /* copy back (status at least ) to user */ + if (param.is_read && rc == 0) { + rc2 = copy_to_user(p, ¶m, sizeof(param)); + if (rc2) { + rc = -EFAULT; /* kill prev status if that fail */ + vl53l1_errmsg("copy to user fail %d\n", rc); + } + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +/** + * implement set/get roi ioctl + * @param data device + * @param p user space ioctl arg ptr + * @return 0 on success <0 errno code + * @li -EINVAL invalid number of roi + * @li -EBUSY when trying to set roi while ranging + * @li -EFAULT if cpy to/fm user fail for requested number of roi + */ +static int ctrl_roi(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + int roi_cnt; + struct stmvl53l1_roi_full_t rois; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* copy fixed part of args at first */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[0])); + if (rc) { + rc = -EFAULT; + goto done; + } + /* check no of roi limit is ok */ + roi_cnt = rois.roi_cfg.NumberOfRoi; + if (roi_cnt > VL53L1_MAX_USER_ZONES) { + vl53l1_errmsg("invalid roi spec cnt=%d > %d", + rois.roi_cfg.NumberOfRoi, + VL53L1_MAX_USER_ZONES); + rc = -EINVAL; + goto done; + } + + if (rois.is_read) { + int cpy_size; + + roi_cnt = MIN(rois.roi_cfg.NumberOfRoi, + data->roi_cfg.NumberOfRoi); + cpy_size = offsetof(VL53L1_RoiConfig_t, UserRois[roi_cnt]); + /* copy from local to user only effective part requested */ + rc = copy_to_user(&((struct stmvl53l1_roi_full_t *)p)->roi_cfg, + &data->roi_cfg, cpy_size); + vl53l1_dbgmsg("return %d of %d\n", roi_cnt, + data->roi_cfg.NumberOfRoi); + } else { + /* SET check cnt roi is ok */ + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set roi while ranging\n"); + goto done; + } + /* get full data that required from user */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[roi_cnt])); + if (rc) { + vl53l1_errmsg("get %d roi fm user fail", roi_cnt); + rc = -EFAULT; + goto done; + } + dump_roi(data->roi_cfg.UserRois, data->roi_cfg.NumberOfRoi); + /* we may ask ll driver to check but check is mode dependent + * and so we could get erroneous error back + */ + memcpy(&data->roi_cfg, &rois.roi_cfg, sizeof(data->roi_cfg)); + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +static int ctrl_autonomous_config(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + struct stmvl53l1_autonomous_config_t full; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* first copy all data */ + rc = copy_from_user(&full, p, sizeof(full)); + if (rc) { + rc = -EFAULT; + goto done; + } + + if (full.is_read) { + full.pollingTimeInMs = data->auto_pollingTimeInMs; + full.config = data->auto_config; + rc = copy_to_user(p, &full, sizeof(full)); + if (rc) + rc = -EFAULT; + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't change config while ranging\n"); + goto done; + } + data->auto_pollingTimeInMs = full.pollingTimeInMs; + data->auto_config = full.config; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_calibration_data(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_calibration_data_t calib; + int data_offset = offsetof(struct stmvl53l1_ioctl_calibration_data_t, + data); + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(&calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib.is_read) { + memset(&calib.data, 0, sizeof(calib.data)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = copy_to_user(p + data_offset, &calib.data, + sizeof(calib.data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib.data, p + data_offset, + sizeof(calib.data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + } + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_zone_calibration_data(struct stmvl53l1_data *data, + void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_zone_calibration_data_t *calib; + int data_offset = + offsetof(struct stmvl53l1_ioctl_zone_calibration_data_t, data); + + mutex_lock(&data->work_mutex); + + calib = &data->calib; + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib->is_read) { + memset(&calib->data, 0, sizeof(calib->data)); + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + calib->data.id = data->current_roi_id; + rc = copy_to_user(p + data_offset, &calib->data, + sizeof(calib->data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib->data, p + data_offset, + sizeof(calib->data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + data->current_roi_id = calib->data.id; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_perform_calibration_ref_spad_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = VL53L1_PerformRefSpadManagement(&data->stdev); + + if (rc) { + vl53l1_errmsg("VL53L1_PerformRefSpadManagement fail => %d", rc); + rc = store_last_error(data, rc); + } + + return rc; +} + +static int ctrl_perform_calibration_crosstalk_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = 0; + + /* Set the preset mode passed on param2 */ + data->preset_mode = (VL53L1_PresetModes)(calib->param2); + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformXTalkCalibration(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_PerformXTalkCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_zone_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* first sanity check */ + if (calib->param1 != VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + vl53l1_errmsg("invalid param1"); + rc = -EINVAL; + goto done; + } + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* set mode to multi zone to allow roi settings */ + rc = VL53L1_SetPresetMode(&data->stdev, + VL53L1_PRESETMODE_MULTIZONES_SCANNING); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* setup roi */ + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + + /* save roi hash for later use */ + data->current_roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + +done: + return rc; +} + +static int ctrl_perform_calibration_offset_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* for legacy purpose we still support mz */ + if (calib->param1 == VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) + return ctrl_perform_zone_calibration_offset_lock(data, calib); + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_simple_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetSimpleCalibration(&data->stdev, calib->param1); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetSimpleCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_per_vcsel_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetPerVcselCalibration(&data->stdev, + calib->param1); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetPerVcselCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_zero_distance_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetZeroDistanceCalibration(&data->stdev); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetZeroDistanceCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_calibration(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_perform_calibration_t calib; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + data->is_calibrating = true; + rc = copy_from_user(&calib, p, sizeof(calib)); + if (rc) { + rc = -EFAULT; + goto done; + } + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't perform calibration while ranging\n"); + goto done; + } + + rc = reset_release(data); + if (rc) + goto done; + + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + switch (calib.calibration_type) { + case VL53L1_CALIBRATION_REF_SPAD: + rc = ctrl_perform_calibration_ref_spad_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_CROSSTALK: + rc = ctrl_perform_calibration_crosstalk_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET: + rc = ctrl_perform_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_SIMPLE: + rc = ctrl_perform_simple_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_PER_ZONE: + rc = ctrl_perform_zone_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_PER_VCSEL: + rc = ctrl_perform_per_vcsel_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_ZERO_DISTANCE: + rc = ctrl_perform_zero_distance_calibration_offset_lock(data, + &calib); + break; + default: + rc = -EINVAL; + break; + } + + reset_hold(data); + +done: + data->is_calibrating = false; + data->is_first_start_done = true; + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int stmvl53l1_ioctl_handler( + struct stmvl53l1_data *data, + unsigned int cmd, unsigned long arg, + void __user *p) +{ + int rc = 0; + + if (!data) + return -EINVAL; + + switch (cmd) { + + case VL53L1_IOCTL_START: + vl53l1_dbgmsg("VL53L1_IOCTL_START\n"); + rc = ctrl_start(data); + break; + + case VL53L1_IOCTL_STOP: + vl53l1_dbgmsg("VL53L1_IOCTL_STOP\n"); + rc = ctrl_stop(data); + break; + + case VL53L1_IOCTL_GETDATAS: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS\n"); */ + rc = ctrl_getdata(data, p); + break; + + case VL53L1_IOCTL_GETDATAS_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS_BLOCKING\n"); */ + rc = ctrl_getdata_blocking(data, p); + break; + + /* Register tool */ + case VL53L1_IOCTL_REGISTER: + vl53l1_dbgmsg("VL53L1_IOCTL_REGISTER\n"); + rc = ctrl_reg_access(data, p); + break; + + case VL53L1_IOCTL_PARAMETER: + vl53l1_dbgmsg("VL53L1_IOCTL_PARAMETER\n"); + rc = ctrl_params(data, p); + break; + + case VL53L1_IOCTL_ROI: + vl53l1_dbgmsg("VL53L1_IOCTL_ROI\n"); + rc = ctrl_roi(data, p); + break; + case VL53L1_IOCTL_MZ_DATA: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA\n"); */ + rc = ctrl_mz_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_BLOCKING\n"); */ + rc = ctrl_mz_data_blocking(data, p); + break; + case VL53L1_IOCTL_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_CALIBRATION_DATA\n"); + rc = ctrl_calibration_data(data, p); + break; + case VL53L1_IOCTL_PERFORM_CALIBRATION: + vl53l1_dbgmsg("VL53L1_IOCTL_PERFORM_CALIBRATION\n"); + rc = ctrl_perform_calibration(data, p); + break; + case VL53L1_IOCTL_AUTONOMOUS_CONFIG: + vl53l1_dbgmsg("VL53L1_IOCTL_AUTONOMOUS_CONFIG\n"); + rc = ctrl_autonomous_config(data, p); + break; + case VL53L1_IOCTL_ZONE_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_ZONE_CALIBRATION_DATA\n"); + rc = ctrl_zone_calibration_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL\n"); */ + rc = ctrl_mz_data_additional(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\n"); + */ + rc = ctrl_mz_data_blocking_additional(data, p); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + + + +static int stmvl53l1_open(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.get(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_release(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.put(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + + +/** max number or error per measure too abort */ +#define stvm531_get_max_meas_err(...) 3 +/** max number or error per stream too abort */ +#define stvm531_get_max_stream_err(...) 6 + +static void detect_xtalk_value_change(struct stmvl53l1_data *data, + VL53L1_MultiRangingData_t *meas) +{ + data->is_xtalk_value_changed = meas->HasXtalkValueChanged ? true : + data->is_xtalk_value_changed; +} + +/** + * handle data retrieval and dispatch + * + * work lock must be held + * + * called form work or interrupt thread it must be a blocable context ! + * @param data the device + */ +static void stmvl53l1_on_newdata_event(struct stmvl53l1_data *data) +{ + int rc; + VL53L1_RangingMeasurementData_t *pmsinglerange; + VL53L1_MultiRangingData_t *pmrange; + VL53L1_MultiRangingData_t *tmprange; + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + VL53L1_RangingMeasurementData_t singledata; + long ts_msec; + int i; + + st_gettimeofday(&data->meas.comp_tv); + ts_msec = stmvl53l1_tv_dif(&data->start_tv, &data->meas.comp_tv)/1000; + + pmrange = &data->meas.multi_range_data; + tmprange = &data->meas.tmp_range_data; + pmsinglerange = &data->meas.single_range_data; + + memcpy(&singledata, pmsinglerange, + sizeof(VL53L1_RangingMeasurementData_t)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + memcpy(&RangeData[i], &pmrange->RangeData[i], + sizeof(VL53L1_TargetRangeData_t)); + + data->meas.intr++; + + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + rc = VL53L1_GetRangingMeasurementData(&data->stdev, + pmsinglerange); + break; + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + /* IMPORTANT : during VL53L1_GetMultiRangingData() call + * work_mutex is release during ipp. This is why we use + * tmp_range_data which is not access somewhere else. When we are + * back we then copy tmp_range_data in multi_range_data. + */ + + rc = VL53L1_GetMultiRangingData(&data->stdev, + &data->meas.tmp_range_data); + if (rc) + vl53l1_errmsg("VL53L1_GetRangingMeasurementData @%d %d", + __LINE__, rc); + + /* be sure we got VL53L1_RANGESTATUS_NONE for object 0 if we got + * invalid roi or no object. So if client read data using + * VL53L1_IOCTL_GETDATAS we got correct status. + */ + if (tmprange->RoiStatus == VL53L1_ROISTATUS_NOT_VALID || + tmprange->NumberOfObjectsFound == 0) + tmprange->RangeData[0].RangeStatus = + VL53L1_RANGESTATUS_NONE; + + memcpy(pmrange, tmprange, sizeof(VL53L1_MultiRangingData_t)); + + /* got histogram debug data in case user want it later on */ + if (!rc) + rc = VL53L1_GetAdditionalData(&data->stdev, + &data->meas.additional_data); + detect_xtalk_value_change(data, pmrange); + break; + default: + /* that must be some bug or data corruption stop now */ + rc = -1; + vl53l1_errmsg("unsorted mode %d=>stop\n", data->preset_mode); + _ctrl_stop(data); + } + /* check if not stopped yet + * as we may have been unlocked we must re-check + */ + if (data->enable_sensor == 0) { + vl53l1_dbgmsg("at meas #%d we got stopped\n", data->meas.cnt); + return; + } + if (rc) { + vl53l1_errmsg("VL53L1_GetRangingMeasurementData @%d %d", + __LINE__, rc); + data->meas.err_cnt++; + data->meas.err_tot++; + if (data->meas.err_cnt > stvm531_get_max_meas_err(data) || + data->meas.err_tot > stvm531_get_max_stream_err(data)) { + vl53l1_errmsg("on #%d %d err %d tot stop", + data->meas.cnt, data->meas.err_cnt, + data->meas.err_tot); + _ctrl_stop(data); + } + return; + } + + /* FIXME: remove when implemented by ll or bare driver */ + pmrange->TimeStamp = ts_msec; + pmsinglerange->TimeStamp = ts_msec; + for (i = 1; i < pmrange->NumberOfObjectsFound; i++) + pmrange->TimeStamp = ts_msec; + + data->meas.cnt++; + vl53l1_dbgmsg("#%3d %2d poll ts %5d status=%d obj cnt=%d\n", + data->meas.cnt, + data->meas.poll_cnt, + pmrange->TimeStamp, + pmrange->RangeData[0].RangeStatus, + pmrange->NumberOfObjectsFound); +#if 1 + vl53l1_dbgmsg( + "meas m#%04d i#%04d p#%04d in %d ms data status_range single[%d %d],multi[%d %d],tmp[%d %d]\n", + + (int)data->meas.cnt, + (int)data->meas.intr, + (int)data->meas.poll_cnt, + (int)stmvl53l1_tv_dif(&data->meas.start_tv, + &data->meas.comp_tv)/1000, + (int)pmsinglerange->RangeStatus, + (int)pmsinglerange->RangeMilliMeter, + (int)pmrange->RangeData[0].RangeStatus, + (int)pmrange->RangeData[0].RangeMilliMeter, + (int)tmprange->RangeData[0].RangeStatus, + (int)tmprange->RangeData[0].RangeMilliMeter); +#endif + /* ready that is not always on each new data event */ + + /* mark data as valid from now */ + data->is_data_valid = true; + + /* wake up sleeping client */ + wake_up_data_waiters(data); + + /* push data to input subsys and only and make val for ioctl*/ + stmvl53l1_input_push_data(data); + stmvl53l1_insert_flush_events_lock(data); + + /* roll time now data got used */ + data->meas.start_tv = data->meas.comp_tv; + data->meas.poll_cnt = 0; + data->meas.err_cnt = 0; +} + + +/** + * * handle interrupt/pusdo irq by polling handling + * + * work lock must be held + * + * @param data driver + * @return 0 on success + */ +static int stmvl53l1_intr_process(struct stmvl53l1_data *data) +{ + uint8_t data_rdy; + int rc = 0; + struct timeval tv_now; + + if (!data->enable_sensor) + goto done; + + data->meas.poll_cnt++; + rc = VL53L1_GetMeasurementDataReady(&data->stdev, &data_rdy); + if (rc) { + vl53l1_errmsg("GetMeasurementDataReady @%d %d, fail\n", + __LINE__, rc); + /* too many successive fail => stop but do not try to do any new + * i/o + */ + goto stop_io; + } + + if (!data_rdy) { + /* FIXME this part to completely skip + * if using interrupt and sure we have + * no false interrupt to handle or no to do any timing check + */ + long poll_us; + + st_gettimeofday(&tv_now); + poll_us = stmvl53l1_tv_dif(&data->meas.start_tv, &tv_now); + if (poll_us > data->timing_budget*4) { + vl53l1_errmsg("we're polling %ld ms too long\n", + poll_us/1000); + /* fixme stop or just warn ? */ + goto stop_io; + } + /* keep trying it could be intr with no processing */ + work_dbg("intr with no data rdy"); + goto done; + } + /* we have data to handle */ + /* first irq after reset has no data so we skip it */ + if (data->is_first_irq) { + data->is_first_irq = false; + + if (data->preset_mode == + VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) { + /* + * If VL53L1_GetRangingMeasurementData() + * is not called after + * for the first ranging measurement, + * the thresholds do not seem + * to work for ALP mode + */ + VL53L1_RangingMeasurementData_t RangingMeasurementData; + + /* printk("Test Workaround for ALP mode\n"); */ + VL53L1_GetRangingMeasurementData(&data->stdev, + &RangingMeasurementData); + } + + } else + stmvl53l1_on_newdata_event(data); + /* enable_sensor could change on event handling check again */ + if (data->enable_sensor) { + /* clear interrupt and continue ranging */ + work_dbg("intr clr"); + /* In autonomous mode, bare driver will trigger stop/start + * sequence. In that case it wall call platform delay functions. + * So allow delay in VL53L1_ClearInterruptAndStartMeasurement() + * call. + */ + data->is_delay_allowed = data->allow_hidden_start_stop; + rc = VL53L1_ClearInterruptAndStartMeasurement(&data->stdev); + data->is_delay_allowed = 0; + if (rc) { + /* go to stop but stop any new i/o for dbg */ + vl53l1_errmsg("Cltr intr restart fail %d\n", rc); + goto stop_io; + } + } +done: + return rc; +stop_io: + /* too many successive fail take action => stop but do not try to do + * any new i/o + */ + vl53l1_errmsg("GetDatardy fail stop\n"); + _ctrl_stop(data); + return rc; + +} + +static void stmvl53l1_work_handler(struct work_struct *work) +{ + struct stmvl53l1_data *data; + + data = container_of(work, struct stmvl53l1_data, dwork.work); + work_dbg("enter"); + mutex_lock(&data->work_mutex); + stmvl53l1_intr_process(data); + if (data->poll_mode && data->enable_sensor) { + /* re-sched ourself */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } + mutex_unlock(&data->work_mutex); +} + +static void stmvl53l1_input_push_data_singleobject(struct stmvl53l1_data *data) +{ + struct input_dev *input = data->input_dev_ps; + VL53L1_RangingMeasurementData_t *meas = &data->meas.single_range_data; + FixPoint1616_t LimitCheckCurrent; + VL53L1_Error st = VL53L1_ERROR_NONE; + + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + vl53l1_dbgmsg("Sensor HAL in Lite ranging mode not yet updated\n"); + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + + /* Do not send the events till this if fixed properly */ + return; + + input_report_abs(input, ABS_DISTANCE, (meas->RangeMilliMeter + 5) / 10); + input_report_abs(input, ABS_HAT0X, meas->TimeStamp / 1000); + input_report_abs(input, ABS_HAT0Y, (meas->TimeStamp % 1000) * 1000); + input_report_abs(input, ABS_HAT1X, meas->RangeMilliMeter); + input_report_abs(input, ABS_HAT1Y, meas->RangeStatus); + input_report_abs(input, ABS_HAT2X, meas->SignalRateRtnMegaCps); + input_report_abs(input, ABS_HAT2Y, meas->AmbientRateRtnMegaCps); + input_report_abs(input, ABS_HAT3X, meas->SigmaMilliMeter); + st = VL53L1_GetLimitCheckCurrent(&data->stdev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, &LimitCheckCurrent); + if (st == VL53L1_ERROR_NONE) + input_report_abs(input, ABS_WHEEL, LimitCheckCurrent); + input_report_abs(input, ABS_TILT_Y, meas->EffectiveSpadRtnCount); + input_report_abs(input, ABS_TOOL_WIDTH, meas->RangeQualityLevel); + + input_sync(input); +} + +static void stmvl53l1_input_push_data_multiobject(struct stmvl53l1_data *data) +{ + VL53L1_MultiRangingData_t *mmeas = &data->meas.multi_range_data; + int i; + int rc; + VL53L1_TargetRangeData_t *meas_array[4]; + VL53L1_CalibrationData_t calibration_data; + struct timeval tv; + struct input_dev *input = data->input_dev_ps; + + st_gettimeofday(&tv); + + for (i = 0; i < 4; i++) + meas_array[i] = &mmeas->RangeData[i]; + + /************************************************************* + * INPUT EVENT CODE L1/L3 Data + ABS_HAT0X Time in Sec(32) + ABS_HAT0Y Time in uSec(32) + ABS_HAT1X Obj0_Distance(16) : Obj0_Sigma(16) + ABS_HAT1Y Obj0_MinRange(16) : Obj0_MaxRange(16) + ABS_HAT2X Obj1_Distance(16) : Obj1_Sigma(16) + ABS_HAT2Y Obj1_ MinRange (16) : Obj1_ MaxRange (16) + ABS_HAT3X Obj0_SignalRate_Spad(32) + ABS_HAT3Y Obj1_SignalRate_Spad(32) + ABS_WHEEL AmbientRate(32) + ABS_BRAKE EffectiveSpadRtnCount(16):RangeStatus_1(8): + Range_status_0(8) + ABS_TILT_X XtalkChange(8) :StreamCount(8) : + NumberofObjects(2) : RoiNumber(4) : + RoiStatus(2) + ABS_TILT_Y DMAX + ABS_TOOL_WIDTH XtalkValue + ABS_DISTANCE + ABS_THROTTLE + ABS_RUDDER + ABS_MISC + ABS_VOLUME + ************************************************************/ + + rc = VL53L1_GetCalibrationData(&data->stdev, &calibration_data); + if (rc) { + /* This should not happen */ + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + return; + } + + /* ABS_HAT0X - Time in Sec(32) */ + + input_report_abs(input, ABS_HAT0X, tv.tv_sec); + vl53l1_dbgmsg("ABS_HAT0X : %ld, %zu\n", tv.tv_sec, sizeof(tv.tv_sec)); + /* ABS_HAT0Y - Time in uSec(32) */ + /* REVISIT : The following code may cause loss of data due to */ + /* 8 bytes to 32 bits conversion */ + input_report_abs(input, ABS_HAT0Y, tv.tv_usec); + vl53l1_dbgmsg("ABS_HAT0Y : %ld\n", tv.tv_usec); + + /* ABS_WHEEL - AmbientRate(32) */ + input_report_abs(input, ABS_WHEEL, + meas_array[0]->AmbientRateRtnMegaCps); + vl53l1_dbgmsg("ABS_WHEEL : AmbRate = %d\n", + meas_array[0]->AmbientRateRtnMegaCps); + + /* ABS_TILT_X XtalkChange(8) :StreamCount(8) : */ + /* Number of Objects(2) : RoiNumber(4) : RoiStatus(2) */ + input_report_abs(input, ABS_TILT_X, + (mmeas->HasXtalkValueChanged << 16) + | (mmeas->StreamCount << 8) + | ((mmeas->NumberOfObjectsFound & 0x3) << 6) + | ((mmeas->RoiNumber & 0xF) << 2) + | (mmeas->RoiStatus & 0x3)); + vl53l1_dbgmsg("ABS_TILT_X :(%d):(%d):(%d):(%d):(%d)\n\n", + mmeas->HasXtalkValueChanged, + mmeas->StreamCount, + mmeas->NumberOfObjectsFound, + mmeas->RoiNumber, + mmeas->RoiStatus + ); + + + /* ABS_TILT_Y DMAX */ + input_report_abs(input, ABS_TILT_Y, mmeas->DmaxMilliMeter); + vl53l1_dbgmsg("ABS_TILT_Y DMAX = %d\n", mmeas->DmaxMilliMeter); + + /* ABS_TOOL_WIDTH */ + input_report_abs(input, ABS_TOOL_WIDTH, +calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + vl53l1_dbgmsg("ABS_TOOL_WIDTH Xtalk = %d\n", +calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + + /* ABS_BRAKE - EffectiveSpadRtnCount(16):RangeStatus_3(1): */ + /* Range_status_2(0) */ + input_report_abs(input, ABS_BRAKE, + mmeas->EffectiveSpadRtnCount << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus); + + vl53l1_dbgmsg("ABS_BRAKE : (%d):(%d):(%d)\n", + mmeas->EffectiveSpadRtnCount, + meas_array[1]->RangeStatus, + meas_array[0]->RangeStatus); + + vl53l1_dbgmsg("ABS_BRAKE : 0x%X\n", + (mmeas->EffectiveSpadRtnCount & 0xFFFF) << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus); + + /* Remaining of data are meaningless in case of no target */ + if (mmeas->NumberOfObjectsFound == 0) { + input_sync(input); + return; + } + + /* ABS_HAT1X - Obj0_Distance(16) : Obj0_Sigma(16) */ + input_report_abs(input, ABS_HAT1X, meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536)); + vl53l1_dbgmsg("ABS_HAT1X : 0x%X(%d:%d)\n", + meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536), + meas_array[0]->RangeMilliMeter, + (meas_array[0]->SigmaMilliMeter/65536)); + + /* ABS_HAT1Y - Obj0_MinRange(16) : Obj0_MaxRange(16) */ + input_report_abs(input, ABS_HAT1Y, + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter); + + vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter, + meas_array[0]->RangeMinMilliMeter, + meas_array[0]->RangeMaxMilliMeter); + + if (mmeas->NumberOfObjectsFound > 1) { + /* ABS_HAT2X - Obj1_Distance(16) : Obj1_Sigma(16) */ + input_report_abs(input, ABS_HAT2X, + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536)); + vl53l1_dbgmsg("ABS_HAT2X : 0x%x(%d:%d)\n", + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536), + meas_array[1]->RangeMilliMeter, + (meas_array[1]->SigmaMilliMeter/65536)); + + /* ABS_HAT2Y - Obj1_ MinRange (16) : Obj1_ MaxRange (16) */ + input_report_abs(input, ABS_HAT2Y, + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter); + + vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter, + meas_array[1]->RangeMinMilliMeter, + meas_array[1]->RangeMaxMilliMeter); + + } + + /* ABS_HAT3X - Obj0_SignalRate_Spad(32) */ + input_report_abs(input, ABS_HAT3X, + meas_array[0]->SignalRateRtnMegaCps); + vl53l1_dbgmsg("ABS_HAT3X : SignalRateRtnMegaCps_0(%d)\n", + meas_array[0]->SignalRateRtnMegaCps); + if (mmeas->NumberOfObjectsFound > 1) { + /* ABS_HAT3Y - Obj1_SignalRate_Spad(32) */ + input_report_abs(input, ABS_HAT3Y, + meas_array[1]->SignalRateRtnMegaCps); + vl53l1_dbgmsg("ABS_HAT3Y : SignalRateRtnMegaCps_1(%d)\n", + meas_array[1]->SignalRateRtnMegaCps); + } + + input_sync(input); + + +} + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data) +{ + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + stmvl53l1_input_push_data_singleobject(data); + break; + default: + /* VL53L1_PRESETMODE_RANGING: + * VL53L1_PRESETMODE_MULTIZONES_SCANNING: + */ + stmvl53l1_input_push_data_multiobject(data); + } +} + +static int stmvl53l1_input_setup(struct stmvl53l1_data *data) +{ + int rc; + struct input_dev *idev; + /* Register to Input Device */ + idev = input_allocate_device(); + if (idev == NULL) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_err; + } + /* setup all event */ + set_bit(EV_ABS, idev->evbit); + + input_set_abs_params(idev, ABS_DISTANCE, 0, 0xff, 0, 0); + + input_set_abs_params(idev, ABS_HAT0X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT0Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_WHEEL, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_TILT_Y, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_BRAKE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TILT_X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TOOL_WIDTH, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_THROTTLE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_RUDDER, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_MISC, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_VOLUME, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_GAS, 0, 0xffffffff, 0, 0); + + idev->name = "STM VL53L1 proximity sensor"; + rc = input_register_device(idev); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_free_dev_ps; + } + /* setup drv data */ + input_set_drvdata(idev, data); + data->input_dev_ps = idev; + return 0; + + +exit_free_dev_ps: + input_free_device(data->input_dev_ps); +exit_err: + return rc; +} + +/** + * handler to be called by interface module on interrupt + * + * managed poll/irq filtering in case poll/irq can be soft forced + * and the module side still fire interrupt + * + * @param data + * @return 0 if all ok else for error + */ +int stmvl53l1_intr_handler(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + /* handle it only if if we are not stopped */ + if (data->enable_sensor) { + rc = stmvl53l1_intr_process(data); + } else { + /* it's likely race/last unhandled interrupt after + * stop. + * Such dummy irq also occured during offset and crosstalk + * calibration procedures. + */ + vl53l1_dbgmsg("got intr but not on (dummy or calibration)\n"); + rc = 0; + } + + mutex_unlock(&data->work_mutex); + return rc; +} + + +/** + * One time device setup + * + * call by bus (i2c/cci) level probe to finalize non bus related device setup + * + * @param data The device data + * @return 0 on success + */ +int stmvl53l1_setup(struct stmvl53l1_data *data) +{ + int rc = 0; + VL53L1_DeviceInfo_t dev_info; + + vl53l1_dbgmsg("Enter\n"); + + /* acquire an id */ + data->id = allocate_dev_id(); + if (data->id < 0) { + vl53l1_errmsg("too many device already created"); + return -1; + } + vl53l1_dbgmsg("Dev id %d is @%p\n", data->id, data); + stmvl53l1_dev_table[data->id] = data; + + /* init mutex */ + /* mutex_init(&data->update_lock); */ + mutex_init(&data->work_mutex); + + /* init work handler */ + INIT_DELAYED_WORK(&data->dwork, stmvl53l1_work_handler); +#ifndef VL53L1_FULL_KERNEL + /* init ipp side */ + stmvl53l1_ipp_setup(data); +#endif + data->force_device_on_en = force_device_on_en_default; + data->reset_state = 1; + data->is_calibrating = false; + data->last_error = VL53L1_ERROR_NONE; + data->is_device_remove = false; + + /* vdd will be controlled in reset_release() */ + //rc = stmvl53l1_module_func_tbl.power_up(data->client_object); + //if (rc) { + // vl53l1_errmsg("%d,error rc %d\n", __LINE__, rc); + // goto exit_ipp_cleanup; + //} + rc = reset_release(data); + if (rc) + goto exit_ipp_cleanup; + + rc = stmvl53l1_input_setup(data); + if (rc) + goto exit_ipp_cleanup; + + /* init blocking ioctl stuff */ + INIT_LIST_HEAD(&data->simple_data_reader_list); + INIT_LIST_HEAD(&data->mz_data_reader_list); + init_waitqueue_head(&data->waiter_for_data); + data->is_data_valid = false; + + /* Register sysfs hooks under input dev */ + rc = sysfs_create_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + + data->enable_sensor = 0; + + data->poll_delay_ms = STMVL53L1_CFG_POLL_DELAY_MS; + data->timing_budget = STMVL53L1_CFG_TIMING_BUDGET_US; + data->preset_mode = STMVL53L1_CFG_DEFAULT_MODE; + data->distance_mode = STMVL53L1_CFG_DEFAULT_DISTANCE_MODE; + data->crosstalk_enable = STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE; + data->output_mode = STMVL53L1_CFG_DEFAULT_OUTPUT_MODE; + data->offset_correction_mode = + STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE; + stmvl53l1_setup_auto_config(data); + data->dmax_mode = STMVL53L1_CFG_DEFAULT_DMAX_MODE; + data->smudge_correction_mode = + STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE; + data->current_roi_id = 0; + data->is_xtalk_value_changed = false; + + data->is_delay_allowed = true; + /* need to be done once */ + rc = VL53L1_DataInit(&data->stdev); + data->is_delay_allowed = false; + if (rc) { + vl53l1_errmsg("VL53L1_DataInit %d\n", rc); + goto exit_unregister_dev_ps; + } + + rc = VL53L1_GetDeviceInfo(&data->stdev, &dev_info); + if (rc) { + vl53l1_errmsg("VL53L1_GetDeviceInfo %d\n", rc); + goto exit_unregister_dev_ps; + } + vl53l1_errmsg("device name %s\ntype %s\n", + dev_info.Name, dev_info.Type); + + data->product_type = dev_info.ProductType; + + /* get managed data here */ + rc = VL53L1_GetDmaxReflectance(&data->stdev, &data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("VL53L1_GetDmaxReflectance %d\n", rc); + goto exit_unregister_dev_ps; + } + rc = VL53L1_GetOpticalCenter(&data->stdev, &data->optical_offset_x, + &data->optical_offset_y); + if (rc) { + vl53l1_errmsg("VL53L1_GetOpticalCenter %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* set tuning from stmvl53l1_tunings.h */ + rc = setup_tunings(data); + if (rc) { + vl53l1_errmsg("setup_tunings %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* Set special parameters for VL53L3 (ticket 513812) */ + if (dev_info.ProductType == 0xAA) { + data->timing_budget = 30000; + data->crosstalk_enable = 1; + data->dmax_mode = VL53L1_DMAXMODE_CUSTCAL_DATA; + data->smudge_correction_mode = + VL53L1_SMUDGE_CORRECTION_CONTINUOUS; + data->dmax_reflectance = (5 << 16); + } + /* End of Set special parameters for VL53L3 (ticket 513812) */ + + /* if working in interrupt ask intr to enable and hook the handler */ + data->poll_mode = 0; + rc = stmvl53l1_module_func_tbl.start_intr(data->client_object, + &data->poll_mode); + if (rc < 0) { + vl53l1_errmsg("can't start no intr\n"); + goto exit_unregister_dev_ps; + } + + data->is_first_irq = true; + data->is_first_start_done = false; + data->is_delay_allowed = false; + + /* to register as a misc device */ + data->miscdev.minor = MISC_DYNAMIC_MINOR; + /* multiple dev name use id in name but 1st */ + if (data->id == 0) + strcpy(data->name, VL53L1_MISC_DEV_NAME); + else + sprintf(data->name, "%s%d", VL53L1_MISC_DEV_NAME, data->id); + + data->miscdev.name = data->name; + data->miscdev.fops = &stmvl53l1_ranging_fops; + vl53l1_errmsg("Misc device registration name:%s\n", data->miscdev.name); + rc = misc_register(&data->miscdev); + if (rc != 0) { + vl53l1_errmsg("misc dev reg fail\n"); + goto exit_unregister_dev_ps; + } + /* bring back device under reset */ + reset_hold(data); + + return 0; + +exit_unregister_dev_ps: + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + input_unregister_device(data->input_dev_ps); +exit_ipp_cleanup: +#ifndef VL53L1_FULL_KERNEL + stmvl53l1_ipp_cleanup(data); +#endif + return rc; +} + + +void stmvl53l1_cleanup(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("enter\n"); + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + if (data->input_dev_ps) { + vl53l1_dbgmsg("to remove sysfs group\n"); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + + vl53l1_dbgmsg("to unregister input dev\n"); + input_unregister_device(data->input_dev_ps); + } + + if (!IS_ERR(data->miscdev.this_device) && + data->miscdev.this_device != NULL) { + vl53l1_dbgmsg("to unregister misc dev\n"); + misc_deregister(&data->miscdev); + } +#ifndef VL53L1_FULL_KERNEL + stmvl53l1_ipp_cleanup(data); +#endif + /* be sure device is put under reset */ + data->force_device_on_en = false; + reset_hold(data); + stmvl53l1_module_func_tbl.power_down(data->client_object); + vl53l1_dbgmsg("done\n"); + deallocate_dev_id(data->id); + data->is_device_remove = true; +} + +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("Enter\n"); + + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + vl53l1_dbgmsg("done\n"); +} +#endif + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + struct stmvl53l1_data *data = + container_of(file->private_data, + struct stmvl53l1_data, miscdev); + ret = stmvl53l1_ioctl_handler(data, cmd, arg, (void __user *)arg); + return ret; +} + +static int __init stmvl53l1_init(void) +{ + int rc = -1; + + vl53l1_dbgmsg("Enter\n"); +#ifndef VL53L1_FULL_KERNEL + rc = stmvl53l1_ipp_init(); + if (rc) + goto done; + /* i2c/cci client specific init function */ + rc = stmvl53l1_module_func_tbl.init(); + if (rc) + stmvl53l1_ipp_exit(); +done: +#else + /* i2c/cci client specific init function */ + rc = stmvl53l1_module_func_tbl.init(); +#endif + vl53l1_dbgmsg("End %d\n", rc); + return rc; +} + +static void __exit stmvl53l1_exit(void) +{ + vl53l1_dbgmsg("Enter\n"); + stmvl53l1_module_func_tbl.deinit(NULL); + if (stmvl53l1_module_func_tbl.clean_up != NULL) + stmvl53l1_module_func_tbl.clean_up(); +#ifndef VL53L1_FULL_KERNEL + stmvl53l1_ipp_exit(); +#endif + vl53l1_dbgmsg("End\n"); +} + + +/* MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); */ +MODULE_AUTHOR("STMicroelectronics Imaging Division"); +MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRIVER_VERSION); + +module_init(stmvl53l1_init); +module_exit(stmvl53l1_exit); diff --git a/drivers/input/misc/vl53L1/stmvl53l1_tunings.h b/drivers/input/misc/vl53L1/stmvl53l1_tunings.h new file mode 100644 index 0000000000000000000000000000000000000000..e74662460d463f6b41f9407f2ac28a2f06076d57 --- /dev/null +++ b/drivers/input/misc/vl53L1/stmvl53l1_tunings.h @@ -0,0 +1,22 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/* + * THIS IS A GENERATED FILE + */ + +#ifndef STMVL53L1_TUNINGS_H +#define STMVL53L1_TUNINGS_H + +static const int tunings[][2] = { +}; + +#endif /* STMVL53L1_TUNINGS_H */ diff --git a/drivers/input/misc/vl53L1/vl53l1_platform.h b/drivers/input/misc/vl53L1/vl53l1_platform.h new file mode 100644 index 0000000000000000000000000000000000000000..588dfbe03c2137a4892c0a4da3920bd572c4bcba --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform.h @@ -0,0 +1,423 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +#ifndef _VL53L1_PLATFORM_H_ +#define _VL53L1_PLATFORM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" + +#define VL53L1_IPP_API +#include "vl53l1_platform_ipp_imports.h" +#include "vl53l1_platform_user_data.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform.h + * + * @brief All end user OS/platform/application porting + */ + + + +/** + * @brief Initialise platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] comms_type : selects between I2C and SPI + * @param[in] comms_speed_khz : unsigned short containing the I2C speed in kHz + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsInitialise( + VL53L1_Dev_t *pdev, + uint8_t comms_type, + uint16_t comms_speed_khz); + + +/** + * @brief Close platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsClose( + VL53L1_Dev_t *pdev); + + +/** + * @brief Writes the supplied byte buffer to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] pdata : pointer to uint8_t (byte) buffer containing the data + * to be written + * @param[in] count : number of bytes in the supplied byte buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WriteMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Reads the requested number of bytes from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to the uint8_t (byte) buffer to store read + * data + * @param[in] count : number of bytes to read + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ReadMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Writes a single byte to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint8_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t data); + + +/** + * @brief Writes a single word (16-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uin16_t data value write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t data); + + +/** + * @brief Writes a single dword (32-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint32_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t data); + + + +/** + * @brief Reads a single byte from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index + * @param[out] pdata : pointer to uint8_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ + +VL53L1_Error VL53L1_RdByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata); + + +/** + * @brief Reads a single word (16-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint16_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t *pdata); + + +/** + * @brief Reads a single dword (32-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint32_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t *pdata); + + + +/** + * @brief Implements a programmable wait in us + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_us : integer wait in micro seconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitUs( + VL53L1_Dev_t *pdev, + int32_t wait_us); + + +/** + * @brief Implements a programmable wait in ms + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_ms : integer wait in milliseconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitMs( + VL53L1_Dev_t *pdev, + int32_t wait_ms); + + +/** + * @brief Get the frequency of the timer used for ranging results time stamps + * + * @param[out] ptimer_freq_hz : pointer for timer frequency + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerFrequency(int32_t *ptimer_freq_hz); + +/** + * @brief Get the timer value in units of timer_freq_hz (see + * VL53L1_get_timestamp_frequency()) + * + * @param[out] ptimer_count : pointer for timer count value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerValue(int32_t *ptimer_count); + + +/** + * @brief Set the mode of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param mode - an identifier specifying the requested mode - defined per + * platform + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetMode(uint8_t pin, uint8_t mode); + + +/** + * @brief Set the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param value - a value to set on the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetValue(uint8_t pin, uint8_t value); + + +/** + * @brief Get the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param pvalue - a value retrieved from the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioGetValue(uint8_t pin, uint8_t *pvalue); + + +/** + * @brief Sets and clears the XShutdown pin on the Ewok + * + * @param value - the value for xshutdown - 0 = in reset, 1 = operational + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioXshutdown(uint8_t value); + + +/** + * @brief Sets and clears the Comms Mode pin (NCS) on the Ewok + * + * @param value - the value for comms select - 0 = I2C, 1 = SPI + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioCommsSelect(uint8_t value); + + +/** + * @brief Enables and disables the power to the Ewok module + * + * @param value - the state of the power supply - 0 = power off, 1 = power on + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioPowerEnable(uint8_t value); + +/** + * @brief Enables callbacks to the supplied funtion pointer when Ewok interrupts + * ocurr + * + * @param function - a function callback supplies by the caller, for interrupt + * notification + * @param edge_type - falling edge or rising edge interrupt detection + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptEnable(void (*function)(void), + uint8_t edge_type); + + +/** + * @brief Disables the callback on Ewok interrupts + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptDisable(void); + + +/* + * @brief Gets current system tick count in [ms] + * + * @return time_ms : current time in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTickCount( + uint32_t *ptime_ms); + + +/** + * @brief Register "wait for value" polling routine + * + * Port of the V2WReg Script function WaitValueMaskEx() + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] timeout_ms : timeout in [ms] + * @param[in] index : uint16_t register index value + * @param[in] value : value to wait for + * @param[in] mask : mask to be applied before comparison with value + * @param[in] poll_delay_ms : polling delay been each read transaction in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitValueMaskEx( + VL53L1_Dev_t *pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, + uint32_t poll_delay_ms); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/vl53l1_platform_ipp.c b/drivers/input/misc/vl53L1/vl53l1_platform_ipp.c new file mode 100644 index 0000000000000000000000000000000000000000..29ebf873c4ace560672d272585447e5ca418dd10 --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform_ipp.c @@ -0,0 +1,127 @@ + +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file vl53l1_platform_ipp.c + * + * @brief EwokPlus25 IPP Wrapper Layer + */ + +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_ll_def.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_hist_funcs.h" +#include "vl53l1_xtalk.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV Dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + uint8_t *pArea1, + uint8_t *pArea2, + uint8_t *phisto_merge_nb, + VL53L1_range_results_t *presults) +{ + + /* + * IPP wrapper for histogram post processing function + */ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + SUPPRESS_UNUSED_WARNING(Dev); + + status = + VL53L1_hist_process_data( + pdmax_cal, + pdmax_cfg, + ppost_cfg, + pbins, + pxtalk, + pArea1, + pArea2, + presults, + phisto_merge_nb); + + return status; +} + + +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm) +{ + + /* + * IPP wrapper for histogram ambient DMAX function + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + */ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + SUPPRESS_UNUSED_WARNING(Dev); + + status = + VL53L1_hist_ambient_dmax( + target_reflectance, + pdmax_cal, + pdmax_cfg, + pbins, + pambient_dmax_mm); + + return status; +} + + +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal) +{ + + /* + * IPP wrapper for histogram post processing function + */ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + SUPPRESS_UNUSED_WARNING(Dev); + + status = + VL53L1_xtalk_calibration_process_data( + pxtalk_ranges, + pxtalk_shape, + pxtalk_cal); + + return status; +} + + diff --git a/drivers/input/misc/vl53L1/vl53l1_platform_ipp.h b/drivers/input/misc/vl53L1/vl53l1_platform_ipp.h new file mode 100644 index 0000000000000000000000000000000000000000..7888bd68ae939e4924d60a1740cf9da9b92ac101 --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform_ipp.h @@ -0,0 +1,170 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +#ifndef _VL53L1_PLATFORM_IPP_H_ +#define _VL53L1_PLATFORM_IPP_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV Dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + uint8_t *pArea1, + uint8_t *pArea2, + uint8_t *phisto_merge_nb, + VL53L1_range_results_t *presults); + + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm); + + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal); + + +/** + * @brief IPP Wrapper call for applying histogram xtalk correction + * + * @param[in] Dev : Device handle + * @param[in] pcustomer : Pointer to input customer data structure + * @param[in] pdyn_cfg : Pointer to input dynamic parameters + * structure + * @param[in] pxtalk_shape : Pointer to input normalised xtalk + * histogram shape + * @param[in] pip_hist_data : Pointer to input histogram data struct + * @param[out] pop_hist_data : Pointer to output xtalk corrected + * histogram data struct + * @param[out] pxtalk_count_data : Pointer to output xtalk histogram + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_xtalk_correction( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pcustomer, + VL53L1_dynamic_config_t *pdyn_cfg, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_histogram_bin_data_t *pip_hist_data, + VL53L1_histogram_bin_data_t *pop_hist_data, + VL53L1_histogram_bin_data_t *pxtalk_count_data); + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples); + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/vl53l1_platform_ipp_imports.h b/drivers/input/misc/vl53L1/vl53l1_platform_ipp_imports.h new file mode 100644 index 0000000000000000000000000000000000000000..c2192510cd74db2119f282e1f739439b3e4274c0 --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform_ipp_imports.h @@ -0,0 +1,17 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + + +#ifndef _VL53L1_PLATFORM_IPP_IMPORTS_H_ +#define _VL53L1_PLATFORM_IPP_IMPORTS_H_ + +#endif diff --git a/drivers/input/misc/vl53L1/vl53l1_platform_log.h b/drivers/input/misc/vl53L1/vl53l1_platform_log.h new file mode 100644 index 0000000000000000000000000000000000000000..743aa5655017499d3d398cd23768d36632916704 --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform_log.h @@ -0,0 +1,157 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file vl53l1_platform_log.h + * + * @brief EwokPlus25 platform logging function definition + */ + + +#ifndef _VL53L1_PLATFORM_LOG_H_ +#define _VL53L1_PLATFORM_LOG_H_ + +#include + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_platform_user_config.h" + + #ifdef _MSC_VER + # define EWOKPLUS_EXPORTS __declspec(dllexport) + #else + # define EWOKPLUS_EXPORTS + #endif + + #include "vl53l1_types.h" + + #ifdef __cplusplus + extern "C" { + #endif + + #include + + /** + * @brief Set the level, output and specific functions for module + * logging. + * + * + * @param filename - full path of output log file, NULL for print to + * stdout + * + * @param modules - Module or None or All to trace + * VL53L1_TRACE_MODULE_NONE + * VL53L1_TRACE_MODULE_API + * VL53L1_TRACE_MODULE_CORE + * VL53L1_TRACE_MODULE_TUNING + * VL53L1_TRACE_MODULE_CHARACTERISATION + * VL53L1_TRACE_MODULE_PLATFORM + * VL53L1_TRACE_MODULE_ALL + * + * @param level - trace level + * VL53L1_TRACE_LEVEL_NONE + * VL53L1_TRACE_LEVEL_ERRORS + * VL53L1_TRACE_LEVEL_WARNING + * VL53L1_TRACE_LEVEL_INFO + * VL53L1_TRACE_LEVEL_DEBUG + * VL53L1_TRACE_LEVEL_ALL + * VL53L1_TRACE_LEVEL_IGNORE + * + * @param functions - function level to trace; + * VL53L1_TRACE_FUNCTION_NONE + * VL53L1_TRACE_FUNCTION_I2C + * VL53L1_TRACE_FUNCTION_ALL + * + * @return status - always VL53L1_ERROR_NONE + * + */ + + #define VL53L1_TRACE_LEVEL_NONE 0x00000000 + #define VL53L1_TRACE_LEVEL_ERRORS 0x00000001 + #define VL53L1_TRACE_LEVEL_WARNING 0x00000002 + #define VL53L1_TRACE_LEVEL_INFO 0x00000004 + #define VL53L1_TRACE_LEVEL_DEBUG 0x00000008 + #define VL53L1_TRACE_LEVEL_ALL 0x00000010 + #define VL53L1_TRACE_LEVEL_IGNORE 0x00000020 + + #define VL53L1_TRACE_FUNCTION_NONE 0x00000000 + #define VL53L1_TRACE_FUNCTION_I2C 0x00000001 + #define VL53L1_TRACE_FUNCTION_ALL 0x7fffffff + + #define VL53L1_TRACE_MODULE_NONE 0x00000000 + #define VL53L1_TRACE_MODULE_API 0x00000001 + #define VL53L1_TRACE_MODULE_CORE 0x00000002 + #define VL53L1_TRACE_MODULE_PROTECTED 0x00000004 + #define VL53L1_TRACE_MODULE_HISTOGRAM 0x00000008 + #define VL53L1_TRACE_MODULE_REGISTERS 0x00000010 + #define VL53L1_TRACE_MODULE_PLATFORM 0x00000020 + #define VL53L1_TRACE_MODULE_NVM 0x00000040 + #define VL53L1_TRACE_MODULE_CALIBRATION_DATA 0x00000080 + #define VL53L1_TRACE_MODULE_NVM_DATA 0x00000100 + #define VL53L1_TRACE_MODULE_HISTOGRAM_DATA 0x00000200 + #define VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA 0x00000400 + #define VL53L1_TRACE_MODULE_XTALK_DATA 0x00000800 + #define VL53L1_TRACE_MODULE_OFFSET_DATA 0x00001000 + #define VL53L1_TRACE_MODULE_DATA_INIT 0x00002000 + #define VL53L1_TRACE_MODULE_REF_SPAD_CHAR 0x00004000 + #define VL53L1_TRACE_MODULE_SPAD_RATE_MAP 0x00008000 + #ifdef PAL_EXTENDED + #define VL53L1_TRACE_MODULE_SPAD 0x01000000 + #define VL53L1_TRACE_MODULE_FMT 0x02000000 + #define VL53L1_TRACE_MODULE_UTILS 0x04000000 + #define VL53L1_TRACE_MODULE_BENCH_FUNCS 0x08000000 + #endif + #define VL53L1_TRACE_MODULE_CUSTOMER_API 0x40000000 + #define VL53L1_TRACE_MODULE_ALL 0x7fffffff + + extern void log_trace_print(uint32_t module, uint32_t level, + uint32_t function, const char *format, ...); + + #define _LOG_TRACE_PRINT_FMT(module, level, function, format, ...) \ + log_trace_print(module, level, function, \ + KERN_INFO " " format, ##__VA_ARGS__) + #define _LOG_TRACE_PRINT(module, level, function, ...) \ + _LOG_TRACE_PRINT_FMT(module, level, function, ##__VA_ARGS__) + #define _LOG_FUNCTION_START(module, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s "fmt"\n", __func__, ##__VA_ARGS__) + #define _LOG_FUNCTION_END(module, status, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d\n", __func__, status) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d"fmt"\n", __func__, status, \ + ##__VA_ARGS__) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + + #define _LOG_STRING_BUFFER(x) char x[VL53L1_MAX_STRING_LENGTH] + + #ifdef __cplusplus + } + #endif + +#else /* VL53L1_LOG_ENABLE - no logging */ + #include "vl53l1_platform_user_config.h" + + #define _LOG_TRACE_PRINT(module, level, function, ...) + #define _LOG_FUNCTION_START(module, fmt, ...) + #define _LOG_FUNCTION_END(module, status, ...) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + #define _LOG_STRING_BUFFER(x) + +#endif /* VL53L1_LOG_ENABLE */ + +#endif /* _VL53L1_PLATFORM_LOG_H_ */ diff --git a/drivers/input/misc/vl53L1/vl53l1_platform_user_config.h b/drivers/input/misc/vl53L1/vl53l1_platform_user_config.h new file mode 100644 index 0000000000000000000000000000000000000000..d21a76549ad07d09805d218e66a2278639193a1a --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform_user_config.h @@ -0,0 +1,97 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file vl53l1_platform_user_config.h + * + * @brief EwokPlus compile time user modifiable configuration + */ + + +#ifndef _VL53L1_PLATFORM_USER_CONFIG_H_ +#define _VL53L1_PLATFORM_USER_CONFIG_H_ + +#define VL53L1_BYTES_PER_WORD 2 +#define VL53L1_BYTES_PER_DWORD 4 + +/* Define polling delays */ +#define VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS 500 +#define VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS 2000 +#define VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS 60000 + +#define VL53L1_POLLING_DELAY_MS 1 + +/* Define LLD TuningParms Page Base Address + * - Part of Patch_AddedTuningParms_11761 + */ +#define VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS 0x8000 +#define VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS 0xC000 + +#define VL53L1_GAIN_FACTOR__STANDARD_DEFAULT 0x0800 + /*!< Default standard ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.980 = 0x07D7 + */ +#define VL53L1_GAIN_FACTOR__HISTOGRAM_DEFAULT 0x0800 + /*!< Default histogram ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.975 = 0x07CC + */ + + +#define VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS 0x0500 + /*!< Lower Limit for the MM1 effective SPAD count during offset + * calibration Format 8.8 0x0500 -> 5.0 effective SPADs + */ + +#define VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Limit for the pre range preak rate during offset + * calibration Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_OFFSET_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during offset calibration + * Check applies to pre-range, mm1 and mm2 ranges + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Peak Rate Limit for the during zone calibration + * Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_ZONE_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during zone calibration + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_XTALK_EXTRACT_MAX_SIGMA_MM 0x008C + /*!< Max Sigma value allowed for a successful xtalk extraction + * Format 14.2 0x008C -> 35.0 mm. + */ + + +#define VL53L1_MAX_USER_ZONES 169 + /*!< Max number of user Zones - maximal limitation from + * FW stream divide - value of 254 + */ + +#define VL53L1_MAX_RANGE_RESULTS 4 + /*!< Sets the maximum number of targets distances the histogram + * post processing can generate + */ + +#define VL53L1_MAX_STRING_LENGTH 512 + +#endif /* _VL53L1_PLATFORM_USER_CONFIG_H_ */ + diff --git a/drivers/input/misc/vl53L1/vl53l1_platform_user_data.h b/drivers/input/misc/vl53L1/vl53l1_platform_user_data.h new file mode 100644 index 0000000000000000000000000000000000000000..a3529a504d38b677974c5c51a7098b299de095f8 --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform_user_data.h @@ -0,0 +1,43 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + +#ifndef _VL53L1_PLATFORM_USER_DATA_H_ +#define _VL53L1_PLATFORM_USER_DATA_H_ + +#include "vl53l1_ll_def.h" + +#include +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define VL53L1_Dev_t VL53L1_DevData_t +#define VL53L1_DEV VL53L1_DevData_t * + +#define VL53L1DevDataGet(Dev, field) (Dev->field) +#define VL53L1DevDataSet(Dev, field, data) ((Dev->field) = (data)) + +#define VL53L1DevStructGetLLDriverHandle(Dev) (&VL53L1DevDataGet(Dev, LLData)) +#define VL53L1DevStructGetLLResultsHandle(Dev) (&VL53L1DevDataGet(Dev,\ + llresults)) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/vl53l1_platform_user_defines.h b/drivers/input/misc/vl53L1/vl53l1_platform_user_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..f9e98beb43d4976cb8c9778c2128be205a92a6d9 --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_platform_user_defines.h @@ -0,0 +1,72 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + + +#ifndef _VL53L1_PLATFORM_USER_DEFINES_H_ +#define _VL53L1_PLATFORM_USER_DEFINES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __KERNEL__ +#include +#endif + +/** + * @file vl53l1_platform_user_defines.h + * + * @brief All end user OS/platform/application definitions + */ + + +/** + * @def do_division_u + * @brief customer supplied division operation - 64-bit unsigned + * + * @param dividend unsigned 64-bit numerator + * @param divisor unsigned 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_u(dividend, divisor) div64_u64(dividend, divisor) +#else +#define do_division_u(dividend, divisor) (dividend / divisor) +#endif + +/** + * @def do_division_s + * @brief customer supplied division operation - 64-bit signed + * + * @param dividend signed 64-bit numerator + * @param divisor signed 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_s(dividend, divisor) div64_s64(dividend, divisor) +#else +#define do_division_s(dividend, divisor) (dividend / divisor) +#endif + +#define WARN_OVERRIDE_STATUS(__X__)\ + trace_print(VL53L1_TRACE_LEVEL_WARNING, #__X__) + + +#define DISABLE_WARNINGS() +#define ENABLE_WARNINGS() + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53L1/vl53l1_types.h b/drivers/input/misc/vl53L1/vl53l1_types.h new file mode 100644 index 0000000000000000000000000000000000000000..3b1c331039eb2819204280f5f4d995aace00565a --- /dev/null +++ b/drivers/input/misc/vl53L1/vl53l1_types.h @@ -0,0 +1,27 @@ + +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/****************************************************************************** + * Copyright (c) 2020, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 and is dual licensed, + either GPL-2.0+ + or 'BSD 3-clause "New" or "Revised" License' , at your option. + ****************************************************************************** + */ + +/** + * @file vl53l1_types.h + * @brief VL53L1 types definition + */ + +#ifndef _VL53L1_TYPES_H_ +#define _VL53L1_TYPES_H_ + +#include +/** use where fractional values are expected + * + * Given a floating point value f it's .16 bit point is (int)(f*(1<<16)) + */ +typedef uint32_t FixPoint1616_t; + +#endif /* VL53L1_TYPES_H_ */ diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index d3c215d7b4eb569785e568fef72cf7fae1132f05..e7a37d89e14b2d9b47441ab341b23ef11fe3e117 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1313,7 +1313,7 @@ config TOUCHSCREEN_ROHM_BU21023 config TOUCHSCREEN_ST tristate "STMicroelectronics Touchscreen Driver" depends on I2C - default y + default n help Say Y here if you have a STMicroelectronics Touchscreen. @@ -1326,7 +1326,7 @@ source "drivers/input/touchscreen/st/Kconfig" config TOUCHSCREEN_SYNAPTICS_DSX bool "Synaptics DSX Touchscreen Driver" depends on I2C - default y + default n help Say Y here if you have a Synaptics Touchscreen. @@ -1340,7 +1340,7 @@ source "drivers/input/touchscreen/synaptics_dsx/Kconfig" config TOUCHSCREEN_SYNAPTICS_TCM bool "Synaptics TCM Touchscreen Driver" depends on I2C - default y + default n help Say Y here if you have a Synaptics Touchscreen. @@ -1351,7 +1351,19 @@ config TOUCHSCREEN_SYNAPTICS_TCM source "drivers/input/touchscreen/synaptics_tcm/Kconfig" -source "drivers/input/touchscreen/focaltech_touch/Kconfig" +source "drivers/input/touchscreen/focaltech_touch_n10/Kconfig" + +config TOUCHSCREEN_HIMAX_CHIPSET + bool "Himax touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Himax CHIPSET touchscreen. + HIMAX controllers are multi touch controllers which can + report 10 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/hxchipset/Kconfig" source "drivers/input/touchscreen/nt36xxx/Kconfig" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 8b766e754948f167844937510da8093f9b885437..f57abf7ea4543730126393de1df1090887bdf1c5 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -112,5 +112,6 @@ obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_ST) += st/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX) += synaptics_dsx/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM) += synaptics_tcm/ -obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch_n10/ +obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ obj-$(CONFIG_TOUCHSCREEN_NT36XXX) += nt36xxx/ diff --git a/drivers/input/touchscreen/focaltech_touch_n10/Kconfig b/drivers/input/touchscreen/focaltech_touch_n10/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..d51dd0051161841bb3b952b9a3c81bcdf734042f --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/Kconfig @@ -0,0 +1,17 @@ +# +# Focaltech Touchscreen driver configuration +# + +config TOUCHSCREEN_FTS + bool "Focaltech Touchscreen" + depends on I2C + default n + help + Say Y here if you have Focaltech touch panel. + If unsure, say N. + +config TOUCHSCREEN_FTS_DIRECTORY + string "Focaltech ts directory name" + default "focaltech_touch" + depends on TOUCHSCREEN_FTS + \ No newline at end of file diff --git a/drivers/input/touchscreen/focaltech_touch_n10/Makefile b/drivers/input/touchscreen/focaltech_touch_n10/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..7dd3fcd6ad65fc2ef9d5feec5481e44f2f39b686 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/Makefile @@ -0,0 +1,14 @@ +# Makefile for the focaltech touchscreen drivers. + + +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_core.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_ex_fun.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_ex_mode.o +#obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_gesture.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_esdcheck.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_point_report_check.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_test/ + +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_i2c.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_flash.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_flash/ diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_common.h b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_common.h new file mode 100755 index 0000000000000000000000000000000000000000..b3144fa2c2f4bc739412f5e15f0f10d74be74312 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_common.h @@ -0,0 +1,167 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2012-2019, Focaltech Ltd. 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. + * + */ +/***************************************************************************** +* +* File Name: focaltech_common.h +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-16 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +#ifndef __LINUX_FOCALTECH_COMMON_H__ +#define __LINUX_FOCALTECH_COMMON_H__ + +#include "focaltech_config.h" + +/***************************************************************************** +* Macro definitions using #define +*****************************************************************************/ +#define FTS_DRIVER_VERSION "Focaltech V3.0 20190102" + +#define BYTE_OFF_0(x) (u8)((x) & 0xFF) +#define BYTE_OFF_8(x) (u8)((x >> 8) & 0xFF) +#define BYTE_OFF_16(x) (u8)((x >> 16) & 0xFF) +#define BYTE_OFF_24(x) (u8)((x >> 24) & 0xFF) +#define FLAGBIT(x) (0x00000001 << (x)) +#define FLAGBITS(x, y) ((0xFFFFFFFF >> (32 - (y) - 1)) & (0xFFFFFFFF << (x))) + +#define FLAG_ICSERIALS_LEN 8 +#define FLAG_HID_BIT 10 +#define FLAG_IDC_BIT 11 + +#define IC_SERIALS (FTS_CHIP_TYPE & FLAGBITS(0, FLAG_ICSERIALS_LEN-1)) +#define IC_TO_SERIALS(x) ((x) & FLAGBITS(0, FLAG_ICSERIALS_LEN-1)) +#define FTS_CHIP_IDC ((FTS_CHIP_TYPE & FLAGBIT(FLAG_IDC_BIT)) == FLAGBIT(FLAG_IDC_BIT)) +#define FTS_HID_SUPPORTTED ((FTS_CHIP_TYPE & FLAGBIT(FLAG_HID_BIT)) == FLAGBIT(FLAG_HID_BIT)) + +#define FTS_CHIP_TYPE_MAPPING {{0x05,0x87, 0x16, 0x87, 0x16, 0x87, 0xA6, 0x00, 0x00}} + +#define FILE_NAME_LENGTH 128 +#define ENABLE 1 +#define DISABLE 0 +#define VALID 1 +#define INVALID 0 +#define FTS_CMD_START1 0x55 +#define FTS_CMD_START2 0xAA +#define FTS_CMD_START_DELAY 10 +#define FTS_CMD_READ_ID 0x90 +#define FTS_CMD_READ_ID_LEN 4 +#define FTS_CMD_READ_ID_LEN_INCELL 1 +/*register address*/ +#define FTS_REG_INT_CNT 0x8F +#define FTS_REG_FLOW_WORK_CNT 0x91 +#define FTS_REG_WORKMODE 0x00 +#define FTS_REG_WORKMODE_FACTORY_VALUE 0x40 +#define FTS_REG_WORKMODE_WORK_VALUE 0x00 +#define FTS_REG_ESDCHECK_DISABLE 0x8D +#define FTS_REG_CHIP_ID 0xA3 +#define FTS_REG_CHIP_ID2 0x9F +#define FTS_REG_POWER_MODE 0xA5 +#define FTS_REG_POWER_MODE_SLEEP_VALUE 0x03 +#define FTS_REG_FW_VER 0xA6 +#define FTS_REG_VENDOR_ID 0xA8 +#define FTS_REG_LCD_BUSY_NUM 0xAB +#define FTS_REG_FACE_DEC_MODE_EN 0xB0 +#define FTS_REG_FACTORY_MODE_DETACH_FLAG 0xB4 +#define FTS_REG_FACE_DEC_MODE_STATUS 0x01 +#define FTS_REG_IDE_PARA_VER_ID 0xB5 +#define FTS_REG_IDE_PARA_STATUS 0xB6 +#define FTS_REG_GLOVE_MODE_EN 0xC0 +#define FTS_REG_COVER_MODE_EN 0xC1 +#define FTS_REG_CHARGER_MODE_EN 0x8B +#define FTS_REG_GESTURE_EN 0xD0 +#define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3 +#define FTS_REG_MODULE_ID 0xE3 +#define FTS_REG_LIC_VER 0xE4 +#define FTS_REG_ESD_SATURATE 0xED + +#define FTS_SYSFS_ECHO_ON(buf) (buf[0] == '1') +#define FTS_SYSFS_ECHO_OFF(buf) (buf[0] == '0') + +#define kfree_safe(pbuf) do {\ + if (pbuf) {\ + kfree(pbuf);\ + pbuf = NULL;\ + }\ +} while(0) + +/***************************************************************************** +* Alternative mode (When something goes wrong, the modules may be able to solve the problem.) +*****************************************************************************/ +/* + * point report check + * default: disable + */ +#define FTS_POINT_REPORT_CHECK_EN 0 + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +struct ft_chip_t { + u64 type; + u8 chip_idh; + u8 chip_idl; + u8 rom_idh; + u8 rom_idl; + u8 pb_idh; + u8 pb_idl; + u8 bl_idh; + u8 bl_idl; +}; + +struct ts_ic_info { + bool is_incell; + bool hid_supported; + struct ft_chip_t ids; +}; + +/***************************************************************************** +* DEBUG function define here +*****************************************************************************/ +#if FTS_DEBUG_EN +#define FTS_DEBUG(fmt, args...) do { \ + printk("[FTS_TS]%s:"fmt"\n", __func__, ##args); \ +} while (0) + +#define FTS_FUNC_ENTER() do { \ + printk("[FTS_TS]%s: Enter\n", __func__); \ +} while (0) + +#define FTS_FUNC_EXIT() do { \ + printk("[FTS_TS]%s: Exit(%d)\n", __func__, __LINE__); \ +} while (0) +#else /* #if FTS_DEBUG_EN*/ +#define FTS_DEBUG(fmt, args...) +#define FTS_FUNC_ENTER() +#define FTS_FUNC_EXIT() +#endif + +#define FTS_INFO(fmt, args...) do { \ + printk(KERN_INFO "[FTS_TS/I]%s:"fmt"\n", __func__, ##args); \ +} while (0) + +#define FTS_ERROR(fmt, args...) do { \ + printk(KERN_ERR "[FTS_TS/E]%s:"fmt"\n", __func__, ##args); \ +} while (0) +#endif /* __LINUX_FOCALTECH_COMMON_H__ */ diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_config.h b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_config.h new file mode 100755 index 0000000000000000000000000000000000000000..a2dfc3d97f7e306fd50102c37df40ae87c851c7d --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_config.h @@ -0,0 +1,240 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. + * + */ +/************************************************************************ +* +* File Name: focaltech_config.h +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: global configurations +* +* Version: v1.0 +* +************************************************************************/ +#ifndef _LINUX_FOCLATECH_CONFIG_H_ +#define _LINUX_FOCLATECH_CONFIG_H_ + +/**************************************************/ +/****** G: A, I: B, S: C, U: D ******************/ +/****** chip type defines, do not modify *********/ +#define _FT8716 0x87160805 +#define _FT8736 0x87360806 +#define _FT8006M 0x80060807 +#define _FT7250 0x72500807 +#define _FT8607 0x86070809 +#define _FT8006U 0x8006D80B +#define _FT8006S 0x8006A80B +#define _FT8613 0x8613080C +#define _FT8719 0x8719080D +#define _FT8739 0x8739080E +#define _FT8615 0x8615080F +#define _FT8201 0x82010810 +#define _FT8006P 0x86220811 +#define _FT7251 0x72510812 +#define _FT7252 0x72520813 +#define _FT8613S 0x8613C814 + +#define _FT5416 0x54160402 +#define _FT5426 0x54260402 +#define _FT5435 0x54350402 +#define _FT5436 0x54360402 +#define _FT5526 0x55260402 +#define _FT5526I 0x5526B402 +#define _FT5446 0x54460402 +#define _FT5346 0x53460402 +#define _FT5446I 0x5446B402 +#define _FT5346I 0x5346B402 +#define _FT7661 0x76610402 +#define _FT7511 0x75110402 +#define _FT7421 0x74210402 +#define _FT7681 0x76810402 +#define _FT3C47U 0x3C47D402 +#define _FT3417 0x34170402 +#define _FT3517 0x35170402 +#define _FT3327 0x33270402 +#define _FT3427 0x34270402 +#define _FT7311 0x73110402 + +#define _FT5626 0x56260401 +#define _FT5726 0x57260401 +#define _FT5826B 0x5826B401 +#define _FT5826S 0x5826C401 +#define _FT7811 0x78110401 +#define _FT3D47 0x3D470401 +#define _FT3617 0x36170401 +#define _FT3717 0x37170401 +#define _FT3817B 0x3817B401 +#define _FT3517U 0x3517D401 + +#define _FT6236U 0x6236D003 +#define _FT6336G 0x6336A003 +#define _FT6336U 0x6336D003 +#define _FT6436U 0x6436D003 + +#define _FT3267 0x32670004 +#define _FT3367 0x33670004 + +#define _FT3327DQQ_XXX 0x3327D482 +#define _FT5446DQS_XXX 0x5446D482 + +#define _FT3518 0x35180481 +#define _FT3558 0x35580481 +#define _FT3528 0x35280481 +#define _FT5536 0x55360481 + +#define _FT5446U 0x5446D083 +#define _FT5456U 0x5456D083 +#define _FT3417U 0x3417D083 +#define _FT5426U 0x5426D083 +#define _FT3428 0x34280083 +#define _FT3437U 0x3437D083 + +#define _FT7302 0x73020084 +#define _FT7202 0x72020084 +#define _FT3308 0x33080084 + +/*************************************************/ + +/* + * choose your ic chip type of focaltech + */ +#define FTS_CHIP_TYPE _FT8716 + +/******************* Enables *********************/ +/*********** 1 to enable, 0 to disable ***********/ + +/* + * show debug log info + * enable it for debug, disable it for release + */ +#define FTS_DEBUG_EN 1 + +/* + * Linux MultiTouch Protocol + * 1: Protocol B(default), 0: Protocol A + */ +#define FTS_MT_PROTOCOL_B_EN 1 + +/* + * Report Pressure in multitouch + * 1:enable(default),0:disable +*/ +#define FTS_REPORT_PRESSURE_EN 1 + +/* + * Gesture function enable + * default: disable + */ +#define FTS_GESTURE_EN 0 + +/* + * ESD check & protection + * default: disable + */ +#define FTS_ESDCHECK_EN 0 + +/* + * Production test enable + * 1: enable, 0:disable(default) + */ +#define FTS_TEST_EN 0 + +/* + * Nodes for tools, please keep enable + */ +#define FTS_SYSFS_NODE_EN 0 +#define FTS_APK_NODE_EN 0 + +/* + * Pinctrl enable + * default: disable + */ +#define FTS_PINCTRL_EN 0 + +/* + * Customer power enable + * enable it when customer need control TP power + * default: disable + */ +#define FTS_POWER_SOURCE_CUST_EN 0 + +/****************************************************/ + +/********************** Upgrade ****************************/ +/* + * auto upgrade + */ +#define FTS_AUTO_UPGRADE_EN 0 + +/* + * auto upgrade for lcd cfg + */ +#define FTS_AUTO_LIC_UPGRADE_EN 0 + +/* + * Numbers of modules support + */ +#define FTS_GET_MODULE_NUM 0 + +/* + * module_id: mean vendor_id generally, also maybe gpio or lcm_id... + * If means vendor_id, the FTS_MODULE_ID = PANEL_ID << 8 + VENDOR_ID + * FTS_GET_MODULE_NUM == 0/1, no check module id, you may ignore them + * FTS_GET_MODULE_NUM >= 2, compatible with FTS_MODULE2_ID + * FTS_GET_MODULE_NUM >= 3, compatible with FTS_MODULE3_ID + */ +#define FTS_MODULE_ID 0x0000 +#define FTS_MODULE2_ID 0x0000 +#define FTS_MODULE3_ID 0x0000 + +/* + * Need set the following when get firmware via firmware_request() + * For example: if module'vendor is tianma, + * #define FTS_MODULE_NAME "tianma" + * then file_name will be "focaltech_ts_fw_tianma" + * You should rename fw to "focaltech_ts_fw_tianma", and push it into + * etc/firmware or by customers + */ +#define FTS_MODULE_NAME "" +#define FTS_MODULE2_NAME "" +#define FTS_MODULE3_NAME "" + +/* + * FW.i file for auto upgrade, you must replace it with your own + * define your own fw_file, the sample one to be replaced is invalid + * NOTE: if FTS_GET_MODULE_NUM > 1, it's the fw corresponding with FTS_VENDOR_ID + */ +#define FTS_UPGRADE_FW_FILE "include/firmware/FT8716_FW_CSOT_NMOS_FHD_5inch_PM85_T_V5D_D02_20180718_app.i" + +/* + * if FTS_GET_MODULE_NUM >= 2, fw corrsponding with FTS_VENDOR_ID2 + * define your own fw_file, the sample one is invalid + */ +#define FTS_UPGRADE_FW2_FILE "include/firmware/FT8716_FW_CSOT_NMOS_FHD_5inch_PM85_T_V5D_D02_20180718_app.i" // MODIFIED by hongwei.tian, 2020-02-26,BUG-8956218 + +/* + * if FTS_GET_MODULE_NUM >= 3, fw corrsponding with FTS_VENDOR_ID3 + * define your own fw_file, the sample one is invalid + */ +#define FTS_UPGRADE_FW3_FILE "include/firmware/FT8716_FW_CSOT_NMOS_FHD_5inch_PM85_T_V5D_D02_20180718_app.i" + +/*********************************************************/ + +#endif /* _LINUX_FOCLATECH_CONFIG_H_ */ diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_core.c new file mode 100755 index 0000000000000000000000000000000000000000..e07aae0c490d59129d7823cbb964288e09a9e2fd --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_core.c @@ -0,0 +1,2004 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. + * + */ +/***************************************************************************** +* +* File Name: focaltech_core.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: entrance for focaltech ts driver +* +* Version: V1.0 +* +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_DRM +#include +#elif defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#define FTS_SUSPEND_LEVEL 1 /* Early-suspend level */ +#endif +#include +#include "focaltech_core.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define FTS_DRIVER_NAME "fts_ts" +#define INTERVAL_READ_REG 200 /* unit:ms */ +#define TIMEOUT_READ_REG 1000 /* unit:ms */ +#if FTS_POWER_SOURCE_CUST_EN +#define FTS_VTG_MIN_UV 2600000 +#define FTS_VTG_MAX_UV 3300000 +#define FTS_I2C_VTG_MIN_UV 1800000 +#define FTS_I2C_VTG_MAX_UV 1800000 +#endif + +static struct drm_panel *active_panel; + +static int check_dt(struct device_node *np) +{ + int i; + int count; + struct device_node *node; + struct drm_panel *panel; + + count = of_count_phandle_with_args(np, "panel", NULL); + if (count <= 0) + return 0; + + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "panel", i); + panel = of_drm_find_panel(node); + of_node_put(node); + if (!IS_ERR(panel)) { + active_panel = panel; + return 0; + } + } + + return -ENODEV; +} + +static int check_default_tp(struct device_node *dt, const char *prop) +{ + const char *active_tp; + const char *compatible; + char *start; + int ret; + + ret = of_property_read_string(dt->parent, prop, &active_tp); + if (ret) { + pr_err(" %s:fail to read %s %d\n", __func__, prop, ret); + return -ENODEV; + } + + ret = of_property_read_string(dt, "compatible", &compatible); + if (ret < 0) { + pr_err(" %s:fail to read %s %d\n", __func__, "compatible", ret); + return -ENODEV; + } + + start = strnstr(active_tp, compatible, strlen(active_tp)); + if (start == NULL) { + pr_err(" %s:no match compatible, %s, %s\n", + __func__, compatible, active_tp); + ret = -ENODEV; + } + + return ret; +} + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +struct fts_ts_data *fts_data; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +static int fts_ts_suspend(struct device *dev); +static int fts_ts_resume(struct device *dev); + +/***************************************************************************** +* Name: fts_wait_tp_to_valid +* Brief: Read chip id until TP FW become valid(Timeout: TIMEOUT_READ_REG), +* need call when reset/power on/resume... +* Input: +* Output: +* Return: return 0 if tp valid, otherwise return error code +*****************************************************************************/ +int fts_wait_tp_to_valid(void) +{ + int ret = 0; + int cnt = 0; + u8 reg_value = 0; + u8 chip_id = fts_data->ic_info.ids.chip_idh; + + do { + ret = fts_read_reg(FTS_REG_CHIP_ID, ®_value); + if ((ret < 0) || (reg_value != chip_id)) { + FTS_DEBUG("TP Not Ready, ReadData = 0x%x", reg_value); + } else if (reg_value == chip_id) { + FTS_INFO("TP Ready, Device ID = 0x%x", reg_value); + return 0; + } + cnt++; + msleep(INTERVAL_READ_REG); + } while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG); + + return -EIO; +} + +/***************************************************************************** +* Name: fts_tp_state_recovery +* Brief: Need execute this function when reset +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_tp_state_recovery(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + /* wait tp stable */ + fts_wait_tp_to_valid(); + /* recover TP charger state 0x8B */ + /* recover TP glove state 0xC0 */ + /* recover TP cover state 0xC1 */ + fts_ex_mode_recovery(ts_data); + /* recover TP gesture state 0xD0 */ +#if FTS_GESTURE_EN + fts_gesture_recovery(ts_data); +#endif + FTS_FUNC_EXIT(); +} + +int fts_reset_proc(int hdelayms) +{ + FTS_DEBUG("tp reset"); + gpio_direction_output(fts_data->pdata->reset_gpio, 0); + msleep(5); + gpio_direction_output(fts_data->pdata->reset_gpio, 1); + if (hdelayms) { + msleep(hdelayms); + } + + return 0; +} + +void fts_irq_disable(void) +{ + unsigned long irqflags; + + FTS_FUNC_ENTER(); + spin_lock_irqsave(&fts_data->irq_lock, irqflags); + + if (!fts_data->irq_disabled) { + disable_irq_nosync(fts_data->irq); + fts_data->irq_disabled = true; + } + + spin_unlock_irqrestore(&fts_data->irq_lock, irqflags); + FTS_FUNC_EXIT(); +} + +void fts_irq_enable(void) +{ + unsigned long irqflags = 0; + + FTS_FUNC_ENTER(); + spin_lock_irqsave(&fts_data->irq_lock, irqflags); + + if (fts_data->irq_disabled) { + enable_irq(fts_data->irq); + fts_data->irq_disabled = false; + } + + spin_unlock_irqrestore(&fts_data->irq_lock, irqflags); + FTS_FUNC_EXIT(); +} + +void fts_hid2std(void) +{ + int ret = 0; + u8 buf[3] = {0xEB, 0xAA, 0x09}; + + ret = fts_write(buf, 3); + if (ret < 0) { + FTS_ERROR("hid2std cmd write fail"); + } else { + msleep(10); + buf[0] = buf[1] = buf[2] = 0; + ret = fts_read(NULL, 0, buf, 3); + if (ret < 0) { + FTS_ERROR("hid2std cmd read fail"); + } else if ((0xEB == buf[0]) && (0xAA == buf[1]) && (0x08 == buf[2])) { + FTS_DEBUG("hidi2c change to stdi2c successful"); + } else { + FTS_DEBUG("hidi2c change to stdi2c not support or fail"); + } + } +} + +static int fts_get_chip_types( + struct fts_ts_data *ts_data, + u8 id_h, u8 id_l, bool fw_valid) +{ + int i = 0; + struct ft_chip_t ctype[] = FTS_CHIP_TYPE_MAPPING; + u32 ctype_entries = sizeof(ctype) / sizeof(struct ft_chip_t); + + if ((0x0 == id_h) || (0x0 == id_l)) { + FTS_ERROR("id_h/id_l is 0"); + return -EINVAL; + } + + FTS_DEBUG("verify id:0x%02x%02x", id_h, id_l); + for (i = 0; i < ctype_entries; i++) { + if (VALID == fw_valid) { + if ((id_h == ctype[i].chip_idh) && (id_l == ctype[i].chip_idl)) + break; + } else { + if (((id_h == ctype[i].rom_idh) && (id_l == ctype[i].rom_idl)) + || ((id_h == ctype[i].pb_idh) && (id_l == ctype[i].pb_idl)) + || ((id_h == ctype[i].bl_idh) && (id_l == ctype[i].bl_idl))) + break; + } + } + + if (i >= ctype_entries) { + return -ENODATA; + } + + ts_data->ic_info.ids = ctype[i]; + return 0; +} + +static int fts_read_bootid(struct fts_ts_data *ts_data, u8 *id) +{ + int ret = 0; + u8 chip_id[2] = { 0 }; + u8 id_cmd[4] = { 0 }; + u32 id_cmd_len = 0; + + id_cmd[0] = FTS_CMD_START1; + id_cmd[1] = FTS_CMD_START2; + ret = fts_write(id_cmd, 2); + if (ret < 0) { + FTS_ERROR("start cmd write fail"); + return ret; + } + + msleep(FTS_CMD_START_DELAY); + id_cmd[0] = FTS_CMD_READ_ID; + id_cmd[1] = id_cmd[2] = id_cmd[3] = 0x00; + if (ts_data->ic_info.is_incell) + id_cmd_len = FTS_CMD_READ_ID_LEN_INCELL; + else + id_cmd_len = FTS_CMD_READ_ID_LEN; + ret = fts_read(id_cmd, id_cmd_len, chip_id, 2); + if ((ret < 0) || (0x0 == chip_id[0]) || (0x0 == chip_id[1])) { + FTS_ERROR("read boot id fail,read:0x%02x%02x", chip_id[0], chip_id[1]); + return -EIO; + } + + id[0] = chip_id[0]; + id[1] = chip_id[1]; + return 0; +} + +/***************************************************************************** +* Name: fts_get_ic_information +* Brief: read chip id to get ic information, after run the function, driver w- +* ill know which IC is it. +* If cant get the ic information, maybe not focaltech's touch IC, need +* unregister the driver +* Input: +* Output: +* Return: return 0 if get correct ic information, otherwise return error code +*****************************************************************************/ +static int fts_get_ic_information(struct fts_ts_data *ts_data) +{ + int ret = 0; + int cnt = 0; + u8 chip_id[2] = { 0 }; + + ts_data->ic_info.is_incell = FTS_CHIP_IDC; + ts_data->ic_info.hid_supported = FTS_HID_SUPPORTTED; + + + do { + ret = fts_read_reg(FTS_REG_CHIP_ID, &chip_id[0]); + ret = fts_read_reg(FTS_REG_CHIP_ID2, &chip_id[1]); + if ((ret < 0) || (0x0 == chip_id[0]) || (0x0 == chip_id[1])) { + FTS_DEBUG("i2c read invalid, read:0x%02x%02x", + chip_id[0], chip_id[1]); + } else { + ret = fts_get_chip_types(ts_data, chip_id[0], chip_id[1], VALID); + if (!ret) + break; + else + FTS_DEBUG("TP not ready, read:0x%02x%02x", + chip_id[0], chip_id[1]); + } + + cnt++; + msleep(INTERVAL_READ_REG); + } while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG); + + if ((cnt * INTERVAL_READ_REG) >= TIMEOUT_READ_REG) { + FTS_INFO("fw is invalid, need read boot id"); + if (ts_data->ic_info.hid_supported) { + fts_hid2std(); + } + + ret = fts_read_bootid(ts_data, &chip_id[0]); + if (ret < 0) { + FTS_ERROR("read boot id fail"); + return ret; + } + + ret = fts_get_chip_types(ts_data, chip_id[0], chip_id[1], INVALID); + if (ret < 0) { + FTS_ERROR("can't get ic informaton"); + return ret; + } + } + + FTS_INFO("get ic information, chip id = 0x%02x%02x", + ts_data->ic_info.ids.chip_idh, ts_data->ic_info.ids.chip_idl); + + return 0; +} + +/***************************************************************************** +* Reprot related +*****************************************************************************/ +static void fts_show_touch_buffer(u8 *data, int datalen) +{ + int i = 0; + int count = 0; + char *tmpbuf = NULL; + + tmpbuf = kzalloc(1024, GFP_KERNEL); + if (!tmpbuf) { + FTS_ERROR("tmpbuf zalloc fail"); + return; + } + + for (i = 0; i < datalen; i++) { + count += snprintf(tmpbuf + count, 1024 - count, "%02X,", data[i]); + if (count >= 1024) + break; + } + FTS_DEBUG("point buffer:%s", tmpbuf); + + if (tmpbuf) { + kfree(tmpbuf); + tmpbuf = NULL; + } +} + +void fts_release_all_finger(void) +{ + struct input_dev *input_dev = fts_data->input_dev; +#if FTS_MT_PROTOCOL_B_EN + u32 finger_count = 0; + u32 max_touches = fts_data->pdata->max_touch_number; +#endif + + FTS_FUNC_ENTER(); + mutex_lock(&fts_data->report_mutex); +#if FTS_MT_PROTOCOL_B_EN + for (finger_count = 0; finger_count < max_touches; finger_count++) { + input_mt_slot(input_dev, finger_count); + input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false); + } +#else + input_mt_sync(input_dev); +#endif + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); + + fts_data->touchs = 0; + fts_data->key_state = 0; + mutex_unlock(&fts_data->report_mutex); + FTS_FUNC_EXIT(); +} + +/***************************************************************************** +* Name: fts_input_report_key +* Brief: process key events,need report key-event if key enable. +* if point's coordinate is in (x_dim-50,y_dim-50) ~ (x_dim+50,y_dim+50), +* need report it to key event. +* x_dim: parse from dts, means key x_coordinate, dimension:+-50 +* y_dim: parse from dts, means key y_coordinate, dimension:+-50 +* Input: +* Output: +* Return: return 0 if it's key event, otherwise return error code +*****************************************************************************/ +static int fts_input_report_key(struct fts_ts_data *data, int index) +{ + int i = 0; + int x = data->events[index].x; + int y = data->events[index].y; + int *x_dim = &data->pdata->key_x_coords[0]; + int *y_dim = &data->pdata->key_y_coords[0]; + + if (!data->pdata->have_key) { + return -EINVAL; + } + for (i = 0; i < data->pdata->key_number; i++) { + if ((x >= x_dim[i] - FTS_KEY_DIM) && (x <= x_dim[i] + FTS_KEY_DIM) && + (y >= y_dim[i] - FTS_KEY_DIM) && (y <= y_dim[i] + FTS_KEY_DIM)) { + if (EVENT_DOWN(data->events[index].flag) + && !(data->key_state & (1 << i))) { + input_report_key(data->input_dev, data->pdata->keys[i], 1); + data->key_state |= (1 << i); + FTS_DEBUG("Key%d(%d,%d) DOWN!", i, x, y); + } else if (EVENT_UP(data->events[index].flag) + && (data->key_state & (1 << i))) { + input_report_key(data->input_dev, data->pdata->keys[i], 0); + data->key_state &= ~(1 << i); + FTS_DEBUG("Key%d(%d,%d) Up!", i, x, y); + } + return 0; + } + } + return -EINVAL; +} + +#if FTS_MT_PROTOCOL_B_EN +static int fts_input_report_b(struct fts_ts_data *data) +{ + int i = 0; + int uppoint = 0; + int touchs = 0; + bool va_reported = false; + u32 max_touch_num = data->pdata->max_touch_number; + struct ts_event *events = data->events; + + for (i = 0; i < data->touch_point; i++) { + if (fts_input_report_key(data, i) == 0) { + continue; + } + + va_reported = true; + input_mt_slot(data->input_dev, events[i].id); + + if (EVENT_DOWN(events[i].flag)) { + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true); + +#if FTS_REPORT_PRESSURE_EN + if (events[i].p <= 0) { + events[i].p = 0x3f; + } + input_report_abs(data->input_dev, ABS_MT_PRESSURE, events[i].p); +#endif + if (events[i].area <= 0) { + events[i].area = 0x09; + } + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, events[i].area); + input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].x); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].y); + + touchs |= BIT(events[i].id); + data->touchs |= BIT(events[i].id); + + if ((data->log_level >= 2) || + ((1 == data->log_level) && (FTS_TOUCH_DOWN == events[i].flag))) { + /*FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!", + events[i].id, + events[i].x, events[i].y, + events[i].p, events[i].area); + */ + } + } else { + uppoint++; + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false); + data->touchs &= ~BIT(events[i].id); + if (data->log_level >= 1) { + //FTS_DEBUG("[B]P%d UP!", events[i].id); + } + } + } + + if (unlikely(data->touchs ^ touchs)) { + for (i = 0; i < max_touch_num; i++) { + if (BIT(i) & (data->touchs ^ touchs)) { + if (data->log_level >= 1) { + // FTS_DEBUG("[B]P%d UP!", i); + } + va_reported = true; + input_mt_slot(data->input_dev, i); + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false); + } + } + } + data->touchs = touchs; + + if (va_reported) { + /* touchs==0, there's no point but key */ + if (EVENT_NO_DOWN(data) || (!touchs)) { + if (data->log_level >= 1) { + //FTS_DEBUG("[B]Points All Up!"); + } + input_report_key(data->input_dev, BTN_TOUCH, 0); + } else { + input_report_key(data->input_dev, BTN_TOUCH, 1); + } + } + + input_sync(data->input_dev); + return 0; +} + +#else +static int fts_input_report_a(struct fts_ts_data *data) +{ + int i = 0; + int touchs = 0; + bool va_reported = false; + struct ts_event *events = data->events; + + for (i = 0; i < data->touch_point; i++) { + if (fts_input_report_key(data, i) == 0) { + continue; + } + + va_reported = true; + if (EVENT_DOWN(events[i].flag)) { + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, events[i].id); +#if FTS_REPORT_PRESSURE_EN + if (events[i].p <= 0) { + events[i].p = 0x3f; + } + input_report_abs(data->input_dev, ABS_MT_PRESSURE, events[i].p); +#endif + if (events[i].area <= 0) { + events[i].area = 0x09; + } + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, events[i].area); + + input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].x); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].y); + + input_mt_sync(data->input_dev); + + if ((data->log_level >= 2) || + ((1 == data->log_level) && (FTS_TOUCH_DOWN == events[i].flag))) { + FTS_DEBUG("[A]P%d(%d, %d)[p:%d,tm:%d] DOWN!", + events[i].id, + events[i].x, events[i].y, + events[i].p, events[i].area); + } + touchs++; + } + } + + /* last point down, current no point but key */ + if (data->touchs && !touchs) { + va_reported = true; + } + data->touchs = touchs; + + if (va_reported) { + if (EVENT_NO_DOWN(data)) { + if (data->log_level >= 1) { + FTS_DEBUG("[A]Points All Up!"); + } + input_report_key(data->input_dev, BTN_TOUCH, 0); + input_mt_sync(data->input_dev); + } else { + input_report_key(data->input_dev, BTN_TOUCH, 1); + } + } + + input_sync(data->input_dev); + return 0; +} +#endif + +static int fts_read_touchdata(struct fts_ts_data *data) +{ + int ret = 0; + u8 *buf = data->point_buf; + + memset(buf, 0xFF, data->pnt_buf_size); + + +#if FTS_GESTURE_EN + if (0 == fts_gesture_readdata(data, NULL)) { + FTS_INFO("succuss to get gesture data in irq handler"); + return 1; + } +#endif + + buf[0] = 0x00; + ret = fts_read(buf, 1, buf, data->pnt_buf_size); + if (ret < 0) { + FTS_ERROR("read touchdata failed, ret:%d", ret); + return ret; + } + + if (data->log_level >= 3) { + fts_show_touch_buffer(buf, data->pnt_buf_size); + } + + return 0; +} + +static int fts_read_parse_touchdata(struct fts_ts_data *data) +{ + int ret = 0; + int i = 0; + u8 pointid = 0; + int base = 0; + struct ts_event *events = data->events; + int max_touch_num = data->pdata->max_touch_number; + u8 *buf = data->point_buf; + + ret = fts_read_touchdata(data); + if (ret) { + return ret; + } + + data->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F; + data->touch_point = 0; + + if (data->ic_info.is_incell) { + if ((data->point_num == 0x0F) && (buf[2] == 0xFF) && (buf[3] == 0xFF) + && (buf[4] == 0xFF) && (buf[5] == 0xFF) && (buf[6] == 0xFF)) { + FTS_DEBUG("touch buff is 0xff, need recovery state"); + fts_release_all_finger(); + fts_tp_state_recovery(data); + return -EIO; + } + } + + if (data->point_num > max_touch_num) { + FTS_INFO("invalid point_num(%d)", data->point_num); + return -EIO; + } + + for (i = 0; i < max_touch_num; i++) { + base = FTS_ONE_TCH_LEN * i; + pointid = (buf[FTS_TOUCH_ID_POS + base]) >> 4; + if (pointid >= FTS_MAX_ID) + break; + else if (pointid >= max_touch_num) { + FTS_ERROR("ID(%d) beyond max_touch_number", pointid); + return -EINVAL; + } + + data->touch_point++; + events[i].x = ((buf[FTS_TOUCH_X_H_POS + base] & 0x0F) << 8) + + (buf[FTS_TOUCH_X_L_POS + base] & 0xFF); + events[i].y = ((buf[FTS_TOUCH_Y_H_POS + base] & 0x0F) << 8) + + (buf[FTS_TOUCH_Y_L_POS + base] & 0xFF); + events[i].flag = buf[FTS_TOUCH_EVENT_POS + base] >> 6; + events[i].id = buf[FTS_TOUCH_ID_POS + base] >> 4; + events[i].area = buf[FTS_TOUCH_AREA_POS + base] >> 4; + events[i].p = buf[FTS_TOUCH_PRE_POS + base]; + + if (EVENT_DOWN(events[i].flag) && (data->point_num == 0)) { + FTS_INFO("abnormal touch data from fw"); + return -EIO; + } + } + + if (data->touch_point == 0) { + FTS_INFO("no touch point information"); + return -EIO; + } + + return 0; +} + +static void fts_irq_read_report(void) +{ + int ret = 0; + struct fts_ts_data *ts_data = fts_data; + +#if FTS_ESDCHECK_EN + fts_esdcheck_set_intr(1); +#endif + +#if FTS_POINT_REPORT_CHECK_EN + fts_prc_queue_work(ts_data); +#endif + + ret = fts_read_parse_touchdata(ts_data); + if (ret == 0) { + mutex_lock(&ts_data->report_mutex); +#if FTS_MT_PROTOCOL_B_EN + fts_input_report_b(ts_data); +#else + fts_input_report_a(ts_data); +#endif + mutex_unlock(&ts_data->report_mutex); + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_set_intr(0); +#endif +} + +static irqreturn_t fts_irq_handler(int irq, void *data) +{ + fts_irq_read_report(); + return IRQ_HANDLED; +} + +static int fts_irq_registration(struct fts_ts_data *ts_data) +{ + int ret = 0; + struct fts_ts_platform_data *pdata = ts_data->pdata; + + ts_data->irq = gpio_to_irq(pdata->irq_gpio); + pdata->irq_gpio_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + FTS_INFO("irq:%d, flag:%x", ts_data->irq, pdata->irq_gpio_flags); + ret = request_threaded_irq(ts_data->irq, NULL, fts_irq_handler, + pdata->irq_gpio_flags, + FTS_DRIVER_NAME, ts_data); + + return ret; +} + +static int fts_input_init(struct fts_ts_data *ts_data) +{ + int ret = 0; + int key_num = 0; + struct fts_ts_platform_data *pdata = ts_data->pdata; + struct input_dev *input_dev; + + FTS_FUNC_ENTER(); + input_dev = input_allocate_device(); + if (!input_dev) { + FTS_ERROR("Failed to allocate memory for input device"); + return -ENOMEM; + } + + /* Init and register Input device */ + input_dev->name = FTS_DRIVER_NAME; + + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = ts_data->dev; + + input_set_drvdata(input_dev, ts_data); + + __set_bit(EV_SYN, input_dev->evbit); + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + + if (pdata->have_key) { + FTS_INFO("set key capabilities"); + for (key_num = 0; key_num < pdata->key_number; key_num++) + input_set_capability(input_dev, EV_KEY, pdata->keys[key_num]); + } + +#if FTS_MT_PROTOCOL_B_EN + input_mt_init_slots(input_dev, pdata->max_touch_number, INPUT_MT_DIRECT); +#else + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0F, 0, 0); +#endif + input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0); +#if FTS_REPORT_PRESSURE_EN + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0); +#endif + + ret = input_register_device(input_dev); + if (ret) { + FTS_ERROR("Input device registration failed"); + input_set_drvdata(input_dev, NULL); + input_free_device(input_dev); + input_dev = NULL; + return ret; + } + + ts_data->input_dev = input_dev; + + FTS_FUNC_EXIT(); + return 0; +} + +static int fts_report_buffer_init(struct fts_ts_data *ts_data) +{ + int point_num = 0; + int events_num = 0; + + + point_num = ts_data->pdata->max_touch_number; + ts_data->pnt_buf_size = point_num * FTS_ONE_TCH_LEN + 3; + ts_data->point_buf = (u8 *)kzalloc(ts_data->pnt_buf_size + 1, GFP_KERNEL); + if (!ts_data->point_buf) { + FTS_ERROR("failed to alloc memory for point buf"); + return -ENOMEM; + } + + events_num = point_num * sizeof(struct ts_event); + ts_data->events = (struct ts_event *)kzalloc(events_num, GFP_KERNEL); + if (!ts_data->events) { + FTS_ERROR("failed to alloc memory for point events"); + kfree_safe(ts_data->point_buf); + return -ENOMEM; + } + + return 0; +} + + + +#if FTS_POWER_SOURCE_CUST_EN +/***************************************************************************** +* Power Control +*****************************************************************************/ +#if FTS_PINCTRL_EN +static int fts_pinctrl_init(struct fts_ts_data *ts) +{ + int ret = 0; + + ts->pinctrl = devm_pinctrl_get(ts->dev); + if (IS_ERR_OR_NULL(ts->pinctrl)) { + FTS_ERROR("Failed to get pinctrl, please check dts"); + ret = PTR_ERR(ts->pinctrl); + goto err_pinctrl_get; + } + + ts->pins_active = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_active"); + if (IS_ERR_OR_NULL(ts->pins_active)) { + FTS_ERROR("Pin state[active] not found"); + ret = PTR_ERR(ts->pins_active); + goto err_pinctrl_lookup; + } + + ts->pins_suspend = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_suspend"); + if (IS_ERR_OR_NULL(ts->pins_suspend)) { + FTS_ERROR("Pin state[suspend] not found"); + ret = PTR_ERR(ts->pins_suspend); + goto err_pinctrl_lookup; + } + + ts->pins_release = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_release"); + if (IS_ERR_OR_NULL(ts->pins_release)) { + FTS_ERROR("Pin state[release] not found"); + ret = PTR_ERR(ts->pins_release); + } + + return 0; +err_pinctrl_lookup: + if (ts->pinctrl) { + devm_pinctrl_put(ts->pinctrl); + } +err_pinctrl_get: + ts->pinctrl = NULL; + ts->pins_release = NULL; + ts->pins_suspend = NULL; + ts->pins_active = NULL; + return ret; +} + +static int fts_pinctrl_select_normal(struct fts_ts_data *ts) +{ + int ret = 0; + + if (ts->pinctrl && ts->pins_active) { + ret = pinctrl_select_state(ts->pinctrl, ts->pins_active); + if (ret < 0) { + FTS_ERROR("Set normal pin state error:%d", ret); + } + } + + return ret; +} + +static int fts_pinctrl_select_suspend(struct fts_ts_data *ts) +{ + int ret = 0; + + if (ts->pinctrl && ts->pins_suspend) { + ret = pinctrl_select_state(ts->pinctrl, ts->pins_suspend); + if (ret < 0) { + FTS_ERROR("Set suspend pin state error:%d", ret); + } + } + + return ret; +} + +static int fts_pinctrl_select_release(struct fts_ts_data *ts) +{ + int ret = 0; + + if (ts->pinctrl) { + if (IS_ERR_OR_NULL(ts->pins_release)) { + devm_pinctrl_put(ts->pinctrl); + ts->pinctrl = NULL; + } else { + ret = pinctrl_select_state(ts->pinctrl, ts->pins_release); + if (ret < 0) + FTS_ERROR("Set gesture pin state error:%d", ret); + } + } + + return ret; +} +#endif /* FTS_PINCTRL_EN */ + +static int fts_power_source_ctrl(struct fts_ts_data *ts_data, int enable) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ts_data->vdd)) { + FTS_ERROR("vdd is invalid"); + return -EINVAL; + } + + FTS_FUNC_ENTER(); + if (enable) { + if (ts_data->power_disabled) { + FTS_DEBUG("regulator enable !"); + gpio_direction_output(ts_data->pdata->reset_gpio, 0); + msleep(1); + ret = regulator_enable(ts_data->vdd); + if (ret) { + FTS_ERROR("enable vdd regulator failed,ret=%d", ret); + } + + if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { + ret = regulator_enable(ts_data->vcc_i2c); + if (ret) { + FTS_ERROR("enable vcc_i2c regulator failed,ret=%d", ret); + } + } + ts_data->power_disabled = false; + } + } else { + if (!ts_data->power_disabled) { + FTS_DEBUG("regulator disable !"); + gpio_direction_output(ts_data->pdata->reset_gpio, 0); + msleep(1); + ret = regulator_disable(ts_data->vdd); + if (ret) { + FTS_ERROR("disable vdd regulator failed,ret=%d", ret); + } + if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { + ret = regulator_disable(ts_data->vcc_i2c); + if (ret) { + FTS_ERROR("disable vcc_i2c regulator failed,ret=%d", ret); + } + } + ts_data->power_disabled = true; + } + } + + FTS_FUNC_EXIT(); + return ret; +} + +/***************************************************************************** +* Name: fts_power_source_init +* Brief: Init regulator power:vdd/vcc_io(if have), generally, no vcc_io +* vdd---->vdd-supply in dts, kernel will auto add "-supply" to parse +* Must be call after fts_gpio_configure() execute,because this function +* will operate reset-gpio which request gpio in fts_gpio_configure() +* Input: +* Output: +* Return: return 0 if init power successfully, otherwise return error code +*****************************************************************************/ +static int fts_power_source_init(struct fts_ts_data *ts_data) +{ + int ret = 0; + + FTS_FUNC_ENTER(); + ts_data->vdd = regulator_get(ts_data->dev, "vdd"); + if (IS_ERR_OR_NULL(ts_data->vdd)) { + ret = PTR_ERR(ts_data->vdd); + FTS_ERROR("get vdd regulator failed,ret=%d", ret); + return ret; + } + + if (regulator_count_voltages(ts_data->vdd) > 0) { + ret = regulator_set_voltage(ts_data->vdd, FTS_VTG_MIN_UV, + FTS_VTG_MAX_UV); + if (ret) { + FTS_ERROR("vdd regulator set_vtg failed ret=%d", ret); + regulator_put(ts_data->vdd); + return ret; + } + } + + ts_data->vcc_i2c = regulator_get(ts_data->dev, "vcc_i2c"); + if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { + if (regulator_count_voltages(ts_data->vcc_i2c) > 0) { + ret = regulator_set_voltage(ts_data->vcc_i2c, + FTS_I2C_VTG_MIN_UV, + FTS_I2C_VTG_MAX_UV); + if (ret) { + FTS_ERROR("vcc_i2c regulator set_vtg failed,ret=%d", ret); + regulator_put(ts_data->vcc_i2c); + } + } + } + +#if FTS_PINCTRL_EN + fts_pinctrl_init(ts_data); + fts_pinctrl_select_normal(ts_data); +#endif + + ts_data->power_disabled = true; + ret = fts_power_source_ctrl(ts_data, ENABLE); + if (ret) { + FTS_ERROR("fail to enable power(regulator)"); + } + + FTS_FUNC_EXIT(); + return ret; +} + +static int fts_power_source_exit(struct fts_ts_data *ts_data) +{ +#if FTS_PINCTRL_EN + fts_pinctrl_select_release(ts_data); +#endif + + fts_power_source_ctrl(ts_data, DISABLE); + + if (!IS_ERR_OR_NULL(ts_data->vdd)) { + if (regulator_count_voltages(ts_data->vdd) > 0) + regulator_set_voltage(ts_data->vdd, 0, FTS_VTG_MAX_UV); + regulator_put(ts_data->vdd); + } + + if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) { + if (regulator_count_voltages(ts_data->vcc_i2c) > 0) + regulator_set_voltage(ts_data->vcc_i2c, 0, FTS_I2C_VTG_MAX_UV); + regulator_put(ts_data->vcc_i2c); + } + + return 0; +} + +static int fts_power_source_suspend(struct fts_ts_data *ts_data) +{ + int ret = 0; + +#if FTS_PINCTRL_EN + fts_pinctrl_select_suspend(ts_data); +#endif + + ret = fts_power_source_ctrl(ts_data, DISABLE); + if (ret < 0) { + FTS_ERROR("power off fail, ret=%d", ret); + } + + return ret; +} + +static int fts_power_source_resume(struct fts_ts_data *ts_data) +{ + int ret = 0; + +#if FTS_PINCTRL_EN + fts_pinctrl_select_normal(ts_data); +#endif + + ret = fts_power_source_ctrl(ts_data, ENABLE); + if (ret < 0) { + FTS_ERROR("power on fail, ret=%d", ret); + } + + return ret; +} +#endif /* FTS_POWER_SOURCE_CUST_EN */ + +static int fts_gpio_configure(struct fts_ts_data *data) +{ + int ret = 0; + + FTS_FUNC_ENTER(); + /* request irq gpio */ + if (gpio_is_valid(data->pdata->irq_gpio)) { + ret = gpio_request(data->pdata->irq_gpio, "fts_irq_gpio"); + if (ret) { + FTS_ERROR("[GPIO]irq gpio request failed"); + goto err_irq_gpio_req; + } + + ret = gpio_direction_input(data->pdata->irq_gpio); + if (ret) { + FTS_ERROR("[GPIO]set_direction for irq gpio failed"); + goto err_irq_gpio_dir; + } + } + + /* request reset gpio */ + if (gpio_is_valid(data->pdata->reset_gpio)) { + ret = gpio_request(data->pdata->reset_gpio, "fts_reset_gpio"); + if (ret) { + FTS_ERROR("[GPIO]reset gpio request failed"); + goto err_irq_gpio_dir; + } + + ret = gpio_direction_output(data->pdata->reset_gpio, 1); + if (ret) { + FTS_ERROR("[GPIO]set_direction for reset gpio failed"); + goto err_reset_gpio_dir; + } + } + + FTS_FUNC_EXIT(); + return 0; + +err_reset_gpio_dir: + if (gpio_is_valid(data->pdata->reset_gpio)) + gpio_free(data->pdata->reset_gpio); +err_irq_gpio_dir: + if (gpio_is_valid(data->pdata->irq_gpio)) + gpio_free(data->pdata->irq_gpio); +err_irq_gpio_req: + FTS_FUNC_EXIT(); + return ret; +} + +/* MODIFIED-BEGIN by hongwei.tian, 2020-02-26,BUG-8956218*/ +static int fts_get_module_id(struct fts_ts_data *data) +{ + int ret = 0; + + FTS_FUNC_ENTER(); + /* request id0 gpio */ + if (gpio_is_valid(data->pdata->id0_gpio)) { + ret = gpio_request(data->pdata->id0_gpio, "fts_id0_gpio"); + if (ret) { + FTS_ERROR("[GPIO]id0 gpio request failed"); + goto err_id0_gpio_req; + } + ret = gpio_direction_input(data->pdata->id0_gpio); + if (ret) { + FTS_ERROR("[GPIO]set_direction for id0 gpio failed"); + goto err_id0_gpio_dir; + } + msleep(1); + data->pdata->id0 = gpio_get_value(data->pdata->id0_gpio); + } + + /* request id1 gpio */ + if (gpio_is_valid(data->pdata->id1_gpio)) { + ret = gpio_request(data->pdata->id1_gpio, "fts_id1_gpio"); + if (ret) { + FTS_ERROR("[GPIO]id1 gpio request failed"); + goto err_id0_gpio_dir; + } + ret = gpio_direction_input(data->pdata->id1_gpio); + if (ret) { + FTS_ERROR("[GPIO]set_direction for id1 gpio failed"); + goto err_id1_gpio_dir; + } + msleep(1); + data->pdata->id1 = gpio_get_value(data->pdata->id1_gpio); + } + if (data->pdata->id0 == 0 && data->pdata->id1 == 0) + data->pdata->panel_vendor = 0x00; /*tdt2nd*/ + else if (data->pdata->id0 == 1 && data->pdata->id1 == 0) + data->pdata->panel_vendor = 0x10; /*csot1st*/ + else + data->pdata->panel_vendor = 0x10; + + if (gpio_is_valid(data->pdata->id0_gpio)) + gpio_free(data->pdata->id0_gpio); + if (gpio_is_valid(data->pdata->id1_gpio)) + gpio_free(data->pdata->id1_gpio); + + FTS_INFO("id0_gpio=%d, id1_gpio=%d, id0=%d, id1=%d", + data->pdata->id0_gpio, data->pdata->id1_gpio, data->pdata->id0, data->pdata->id1); + FTS_FUNC_EXIT(); + return 0; + +err_id1_gpio_dir: + if (gpio_is_valid(data->pdata->id1_gpio)) + gpio_free(data->pdata->id1_gpio); +err_id0_gpio_dir: + if (gpio_is_valid(data->pdata->id0_gpio)) + gpio_free(data->pdata->id0_gpio); +err_id0_gpio_req: + FTS_FUNC_EXIT(); + return ret; +} +/* MODIFIED-END by hongwei.tian,BUG-8956218*/ + +static int fts_get_dt_coords(struct device *dev, char *name, + struct fts_ts_platform_data *pdata) +{ + int ret = 0; + u32 coords[FTS_COORDS_ARR_SIZE] = { 0 }; + struct property *prop; + struct device_node *np = dev->of_node; + int coords_size; + + prop = of_find_property(np, name, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + coords_size = prop->length / sizeof(u32); + if (coords_size != FTS_COORDS_ARR_SIZE) { + FTS_ERROR("invalid:%s, size:%d", name, coords_size); + return -EINVAL; + } + + ret = of_property_read_u32_array(np, name, coords, coords_size); + if (ret < 0) { + FTS_ERROR("Unable to read %s, please check dts", name); + pdata->x_min = FTS_X_MIN_DISPLAY_DEFAULT; + pdata->y_min = FTS_Y_MIN_DISPLAY_DEFAULT; + pdata->x_max = FTS_X_MAX_DISPLAY_DEFAULT; + pdata->y_max = FTS_Y_MAX_DISPLAY_DEFAULT; + return -ENODATA; + } else { + pdata->x_min = coords[0]; + pdata->y_min = coords[1]; + pdata->x_max = coords[2]; + pdata->y_max = coords[3]; + } + + FTS_INFO("display x(%d %d) y(%d %d)", pdata->x_min, pdata->x_max, + pdata->y_min, pdata->y_max); + return 0; +} + +static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata) +{ + int ret = 0; + struct device_node *np = dev->of_node; + u32 temp_val = 0; + + FTS_FUNC_ENTER(); + + ret = fts_get_dt_coords(dev, "focaltech,display-coords", pdata); + if (ret < 0) + FTS_ERROR("Unable to get display-coords"); + + /* key */ + pdata->have_key = of_property_read_bool(np, "focaltech,have-key"); + if (pdata->have_key) { + ret = of_property_read_u32(np, "focaltech,key-number", &pdata->key_number); + if (ret < 0) + FTS_ERROR("Key number undefined!"); + + ret = of_property_read_u32_array(np, "focaltech,keys", + pdata->keys, pdata->key_number); + if (ret < 0) + FTS_ERROR("Keys undefined!"); + else if (pdata->key_number > FTS_MAX_KEYS) + pdata->key_number = FTS_MAX_KEYS; + + ret = of_property_read_u32_array(np, "focaltech,key-x-coords", + pdata->key_x_coords, + pdata->key_number); + if (ret < 0) + FTS_ERROR("Key Y Coords undefined!"); + + ret = of_property_read_u32_array(np, "focaltech,key-y-coords", + pdata->key_y_coords, + pdata->key_number); + if (ret < 0) + FTS_ERROR("Key X Coords undefined!"); + + FTS_INFO("VK Number:%d, key:(%d,%d,%d), " + "coords:(%d,%d),(%d,%d),(%d,%d)", + pdata->key_number, + pdata->keys[0], pdata->keys[1], pdata->keys[2], + pdata->key_x_coords[0], pdata->key_y_coords[0], + pdata->key_x_coords[1], pdata->key_y_coords[1], + pdata->key_x_coords[2], pdata->key_y_coords[2]); + } + + /* reset, irq gpio info */ + pdata->reset_gpio = of_get_named_gpio_flags(np, "focaltech,reset-gpio", + 0, &pdata->reset_gpio_flags); + if (pdata->reset_gpio < 0) + FTS_ERROR("Unable to get reset_gpio"); + + pdata->irq_gpio = of_get_named_gpio_flags(np, "focaltech,irq-gpio", + 0, &pdata->irq_gpio_flags); + if (pdata->irq_gpio < 0) + FTS_ERROR("Unable to get irq_gpio"); + + /* MODIFIED-BEGIN by hongwei.tian, 2020-02-26,BUG-8956218*/ + pdata->id0_gpio = of_get_named_gpio_flags(np, "focaltech,id0-gpio", + 0, &pdata->id0_gpio_flags); + if (pdata->id0_gpio < 0) + FTS_ERROR("Unable to get id0_gpio"); + + pdata->id1_gpio = of_get_named_gpio_flags(np, "focaltech,id1-gpio", + 0, &pdata->id1_gpio_flags); + if (pdata->id1_gpio < 0) + FTS_ERROR("Unable to get id1_gpio"); + /* MODIFIED-END by hongwei.tian,BUG-8956218*/ + + ret = of_property_read_u32(np, "focaltech,max-touch-number", &temp_val); + if (ret < 0) { + FTS_ERROR("Unable to get max-touch-number, please check dts"); + pdata->max_touch_number = FTS_MAX_POINTS_SUPPORT; + } else { + if (temp_val < 2) + pdata->max_touch_number = 2; /* max_touch_number must >= 2 */ + else if (temp_val > FTS_MAX_POINTS_SUPPORT) + pdata->max_touch_number = FTS_MAX_POINTS_SUPPORT; + else + pdata->max_touch_number = temp_val; + } + + FTS_INFO("max touch number:%d, irq gpio:%d, reset gpio:%d", + pdata->max_touch_number, pdata->irq_gpio, pdata->reset_gpio); + + FTS_FUNC_EXIT(); + return 0; +} + +#if defined(CONFIG_DRM) || defined(CONFIG_FB) + +static void fts_resume_work(struct work_struct *work) +{ + struct fts_ts_data *ts_data = container_of(work, struct fts_ts_data, + resume_work); + + fts_ts_resume(ts_data->dev); +} +#endif + +#if defined(CONFIG_DRM) + +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + //struct msm_drm_notifier *evdata = data; + struct drm_panel_notifier *evdata = data; + int *blank = NULL; + struct fts_ts_data *ts_data = container_of(self, struct fts_ts_data, + fb_notif); + + if (!(event == DRM_PANEL_EARLY_EVENT_BLANK || event == DRM_PANEL_EVENT_BLANK)) { + FTS_INFO("event(%lu) do not need process\n", event); + return 0; + } + + blank = evdata->data; + FTS_INFO("FB event:%lu,blank:%d", event, *blank); + + switch (*blank) { + case DRM_PANEL_BLANK_UNBLANK: + if (DRM_PANEL_EARLY_EVENT_BLANK == event) { + FTS_INFO("resume: event = %lu, not care\n", event); + } else if (DRM_PANEL_EVENT_BLANK == event) { + queue_work(fts_data->ts_workqueue, &fts_data->resume_work); + } + break; + case DRM_PANEL_BLANK_POWERDOWN: + if (DRM_PANEL_EARLY_EVENT_BLANK == event) { + cancel_work_sync(&fts_data->resume_work); + fts_ts_suspend(ts_data->dev); + } else if (DRM_PANEL_EVENT_BLANK == event) { + FTS_INFO("suspend: event = %lu, not care\n", event); + } + break; + default: + FTS_INFO("FB BLANK(%d) do not need process\n", *blank); + break; + } + + return 0; +} + +#elif defined(CONFIG_FB) + +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank = NULL; + struct fts_ts_data *ts_data = container_of(self, struct fts_ts_data, + fb_notif); + + if (!(event == FB_EARLY_EVENT_BLANK || event == FB_EVENT_BLANK)) { + FTS_INFO("event(%lu) do not need process\n", event); + return 0; + } + + blank = evdata->data; + FTS_INFO("FB event:%lu,blank:%d", event, *blank); + switch (*blank) { + case FB_BLANK_UNBLANK: + if (FB_EARLY_EVENT_BLANK == event) { + FTS_INFO("resume: event = %lu, not care\n", event); + } else if (FB_EVENT_BLANK == event) { + queue_work(fts_data->ts_workqueue, &fts_data->resume_work); + } + break; + case FB_BLANK_POWERDOWN: + if (FB_EARLY_EVENT_BLANK == event) { + cancel_work_sync(&fts_data->resume_work); + fts_ts_suspend(ts_data->dev); + } else if (FB_EVENT_BLANK == event) { + FTS_INFO("suspend: event = %lu, not care\n", event); + } + break; + default: + FTS_INFO("FB BLANK(%d) do not need process\n", *blank); + break; + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void fts_ts_early_suspend(struct early_suspend *handler) +{ + struct fts_ts_data *ts_data = container_of(handler, struct fts_ts_data, + early_suspend); + + fts_ts_suspend(ts_data->dev); +} + +static void fts_ts_late_resume(struct early_suspend *handler) +{ + struct fts_ts_data *ts_data = container_of(handler, struct fts_ts_data, + early_suspend); + + fts_ts_resume(ts_data->dev); +} +#endif + +static void tct_touch_class_create(struct fts_ts_data *data) +{ + if (data->tct_touch_class == NULL) + data->tct_touch_class = class_create(THIS_MODULE, "tct_touch"); + + if (!data->tct_touch_class) + FTS_ERROR("failed to create tct_touch_class!"); + + if (data->tct_touch_class) { + data->tct_touch_dev = + device_create(data->tct_touch_class, NULL, 0, NULL, "tct_touch_dev"); + if (!data->tct_touch_dev) + FTS_DEBUG("Failed to create tct_touch_dev!"); + } +} + +static int fts_ts_probe_entry(struct fts_ts_data *ts_data) +{ + int ret = 0; + int pdata_size = sizeof(struct fts_ts_platform_data); + + FTS_FUNC_ENTER(); + ts_data->pdata = kzalloc(pdata_size, GFP_KERNEL); + if (!ts_data->pdata) { + FTS_ERROR("allocate memory for platform_data fail"); + return -ENOMEM; + } + + if (ts_data->dev->of_node) { + ret = fts_parse_dt(ts_data->dev, ts_data->pdata); + if (ret) + FTS_ERROR("device-tree parse fail"); + } else { + if (ts_data->dev->platform_data) { + memcpy(ts_data->pdata, ts_data->dev->platform_data, pdata_size); + } else { + FTS_ERROR("platform_data is null"); + return -ENODEV; + } + } + + ts_data->ts_workqueue = create_singlethread_workqueue("fts_wq"); + if (!ts_data->ts_workqueue) { + FTS_ERROR("create fts workqueue fail"); + } + + spin_lock_init(&ts_data->irq_lock); + mutex_init(&ts_data->report_mutex); + mutex_init(&ts_data->bus_lock); + + /* Init communication interface */ + ret = fts_bus_init(ts_data); + if (ret) { + FTS_ERROR("bus initialize fail"); + goto err_bus_init; + } + + ret = fts_input_init(ts_data); + if (ret) { + FTS_ERROR("input initialize fail"); + goto err_input_init; + } + + ret = fts_report_buffer_init(ts_data); + if (ret) { + FTS_ERROR("report buffer init fail"); + goto err_report_buffer; + } + + ret = fts_gpio_configure(ts_data); + if (ret) { + FTS_ERROR("configure the gpios fail"); + goto err_gpio_config; + } + + /* MODIFIED-BEGIN by hongwei.tian, 2020-02-26,BUG-8956218*/ + ret = fts_get_module_id(ts_data); + if (ret) + FTS_ERROR("get modle id"); + /* MODIFIED-END by hongwei.tian,BUG-8956218*/ + +#if FTS_POWER_SOURCE_CUST_EN + ret = fts_power_source_init(ts_data); + if (ret) { + FTS_ERROR("fail to get power(regulator)"); + goto err_power_init; + } +#endif + + + + ts_data->vdd_io = regulator_get(ts_data->dev, "vdd_io"); + if (IS_ERR_OR_NULL(ts_data->vdd_io)) { + ret = PTR_ERR(ts_data->vdd_io); + FTS_ERROR("get vdd_io regulator failed,ret=%d", ret); + } else { + if (regulator_count_voltages(ts_data->vdd_io) > 0) { + ret = regulator_set_voltage(ts_data->vdd_io, 1800000, 1800000); + if (ret) { + FTS_ERROR("vdd_io regulator set_vtg failed ret=%d", ret); + regulator_put(ts_data->vdd_io); + } + } + ret = regulator_enable(ts_data->vdd_io); + if (ret) { + FTS_ERROR("enable vdd_io regulator failed,ret=%d", ret); + } + } + +#if (!FTS_CHIP_IDC) + fts_reset_proc(200); +#endif + + ret = fts_get_ic_information(ts_data); + if (ret) { + FTS_ERROR("not focal IC, unregister driver"); + goto err_irq_req; + } + +#if FTS_APK_NODE_EN + ret = fts_create_apk_debug_channel(ts_data); + if (ret) { + FTS_ERROR("create apk debug node fail"); + } +#endif + + tct_touch_class_create(ts_data); + +#if FTS_SYSFS_NODE_EN + ret = fts_create_sysfs(ts_data); + if (ret) { + FTS_ERROR("create sysfs node fail"); + } +#endif + +#if FTS_POINT_REPORT_CHECK_EN + ret = fts_point_report_check_init(ts_data); + if (ret) { + FTS_ERROR("init point report check fail"); + } +#endif + + ret = fts_ex_mode_init(ts_data); + if (ret) { + FTS_ERROR("init glove/cover/charger fail"); + } + +#if FTS_GESTURE_EN + ret = fts_gesture_init(ts_data); + if (ret) { + FTS_ERROR("init gesture fail"); + } +#endif + +#if FTS_TEST_EN + ret = fts_test_init(ts_data); + if (ret) { + FTS_ERROR("init production test fail"); + } +#endif + +#if FTS_ESDCHECK_EN + ret = fts_esdcheck_init(ts_data); + if (ret) { + FTS_ERROR("init esd check fail"); + } +#endif + + ret = fts_irq_registration(ts_data); + if (ret) { + FTS_ERROR("request irq failed"); + goto err_irq_req; + } + + ret = fts_fwupg_init(ts_data); + if (ret) { + FTS_ERROR("init fw upgrade fail"); + } + +#if defined(CONFIG_FB) || defined(CONFIG_DRM) + if (ts_data->ts_workqueue) { + INIT_WORK(&ts_data->resume_work, fts_resume_work); + } +#endif + +#if defined(CONFIG_DRM) + ts_data->fb_notif.notifier_call = drm_notifier_callback; + if (active_panel) { + ret = drm_panel_notifier_register(active_panel, + &ts_data->fb_notif); + if (ret < 0) + FTS_ERROR("Failed to register fb notifier client"); + } +#elif defined(CONFIG_FB) + ts_data->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts_data->fb_notif); + if (ret) { + FTS_ERROR("[FB]Unable to register fb_notifier: %d", ret); + } +#elif defined(CONFIG_HAS_EARLYSUSPEND) + ts_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + FTS_SUSPEND_LEVEL; + ts_data->early_suspend.suspend = fts_ts_early_suspend; + ts_data->early_suspend.resume = fts_ts_late_resume; + register_early_suspend(&ts_data->early_suspend); +#endif + + FTS_FUNC_EXIT(); + return 0; + +err_irq_req: +#if FTS_POWER_SOURCE_CUST_EN +err_power_init: + fts_power_source_exit(ts_data); +#endif + if (gpio_is_valid(ts_data->pdata->reset_gpio)) + gpio_free(ts_data->pdata->reset_gpio); + if (gpio_is_valid(ts_data->pdata->irq_gpio)) + gpio_free(ts_data->pdata->irq_gpio); +err_gpio_config: + kfree_safe(ts_data->point_buf); + kfree_safe(ts_data->events); +err_report_buffer: + input_unregister_device(ts_data->input_dev); +err_input_init: + if (ts_data->ts_workqueue) + destroy_workqueue(ts_data->ts_workqueue); +err_bus_init: + kfree_safe(ts_data->bus_tx_buf); + kfree_safe(ts_data->bus_rx_buf); + kfree_safe(ts_data->pdata); + + FTS_FUNC_EXIT(); + return ret; +} + +static int fts_ts_remove_entry(struct fts_ts_data *ts_data) +{ + int ret; + FTS_FUNC_ENTER(); + +#if FTS_POINT_REPORT_CHECK_EN + fts_point_report_check_exit(ts_data); +#endif + +#if FTS_APK_NODE_EN + fts_release_apk_debug_channel(ts_data); +#endif + +#if FTS_SYSFS_NODE_EN + fts_remove_sysfs(ts_data); +#endif + + fts_ex_mode_exit(ts_data); + + fts_fwupg_exit(ts_data); + +#if FTS_TEST_EN + fts_test_exit(ts_data); +#endif + +#if FTS_ESDCHECK_EN + fts_esdcheck_exit(ts_data); +#endif + +#if FTS_GESTURE_EN + fts_gesture_exit(ts_data); +#endif + + fts_bus_exit(ts_data); + + free_irq(ts_data->irq, ts_data); + input_unregister_device(ts_data->input_dev); + + if (ts_data->ts_workqueue) + destroy_workqueue(ts_data->ts_workqueue); + +#ifdef CONFIG_DRM + if (active_panel) { + ret = drm_panel_notifier_unregister(active_panel, + &ts_data->fb_notif); + if (ret < 0) + FTS_ERROR("Failed to unregister fb notifier client"); + } +#elif defined(CONFIG_FB) + if (fb_unregister_client(&ts_data->fb_notif)) + FTS_ERROR("Error occurred while unregistering fb_notifier."); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts_data->early_suspend); +#endif + + if (gpio_is_valid(ts_data->pdata->reset_gpio)) + gpio_free(ts_data->pdata->reset_gpio); + + if (gpio_is_valid(ts_data->pdata->irq_gpio)) + gpio_free(ts_data->pdata->irq_gpio); + +#if FTS_POWER_SOURCE_CUST_EN + fts_power_source_exit(ts_data); +#endif + + kfree_safe(ts_data->point_buf); + kfree_safe(ts_data->events); + + kfree_safe(ts_data->pdata); + kfree_safe(ts_data); + + FTS_FUNC_EXIT(); + + return 0; +} + +static int fts_ts_suspend(struct device *dev) +{ + int ret = 0; + struct fts_ts_data *ts_data = fts_data; + + FTS_FUNC_ENTER(); + FTS_ERROR("power suspend enter!"); // MODIFIED by hongwei.tian, 2020-04-10,BUG-8979194 + if (ts_data->suspended) { + FTS_INFO("Already in suspend state"); + return 0; + } + + if (ts_data->fw_loading) { + FTS_INFO("fw upgrade in process, can't suspend"); + return 0; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_suspend(); +#endif + +#if FTS_GESTURE_EN + if (fts_gesture_suspend(ts_data) == 0) { + /* Enter into gesture mode(suspend) */ + ts_data->suspended = true; + return 0; + } +#endif + + fts_irq_disable(); + + /* TP enter sleep mode */ + ret = fts_write_reg(FTS_REG_POWER_MODE, FTS_REG_POWER_MODE_SLEEP_VALUE); + if (ret < 0) + FTS_ERROR("set TP to sleep mode fail, ret=%d", ret); + usleep_range(10000, 10000); + if (!ts_data->ic_info.is_incell) { +#if FTS_POWER_SOURCE_CUST_EN + ret = fts_power_source_suspend(ts_data); + if (ret < 0) { + FTS_ERROR("power enter suspend fail"); + } +#endif + } + + ts_data->suspended = true; + FTS_ERROR("power suspend !"); // MODIFIED by hongwei.tian, 2020-04-10,BUG-8979194 + FTS_FUNC_EXIT(); + return 0; +} + +static int fts_ts_resume(struct device *dev) +{ + struct fts_ts_data *ts_data = fts_data; + + FTS_FUNC_ENTER(); + FTS_ERROR("power resumed enter !"); // MODIFIED by hongwei.tian, 2020-04-10,BUG-8979194 + if (!ts_data->suspended) { + FTS_DEBUG("Already in awake state"); + return 0; + } + + fts_release_all_finger(); + +#if FTS_POWER_SOURCE_CUST_EN + fts_power_source_resume(ts_data); +#endif + fts_reset_proc(200); + + fts_tp_state_recovery(ts_data); + +#if FTS_ESDCHECK_EN + fts_esdcheck_resume(); +#endif + +#if FTS_GESTURE_EN + if (fts_gesture_resume(ts_data) == 0) { + ts_data->suspended = false; + return 0; + } +#endif + + fts_irq_enable(); + + ts_data->suspended = false; + FTS_ERROR("power resumed !"); // MODIFIED by hongwei.tian, 2020-04-10,BUG-8979194 + FTS_FUNC_EXIT(); + return 0; +} + +int fts_esd_check(void) +{ + int ret = 0; + u8 reg_value = 0; + + ret = fts_read_reg(FTS_CMD_READ_ID, ®_value); + if (ret < 0) + pr_info("%s i2c read failed, ret:%d", __func__, ret); + else + pr_info("%s i2c read sucess, reg_value:%d", __func__, reg_value); + + if (reg_value == 0x55) + return false; + else + return true; +} + +/***************************************************************************** +* TP Driver +*****************************************************************************/ + +static int fts_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + int error = 0; + struct fts_ts_data *ts_data = NULL; + struct device_node *dp = client->dev.of_node; + + FTS_INFO("Touch Screen(I2C BUS) driver prboe..."); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + FTS_ERROR("I2C not supported"); + return -ENODEV; + } + + if (check_dt(dp)) { + if (!check_default_tp(dp, "qcom,i2c-touch-active")) + error = -EPROBE_DEFER; + else + error = -ENODEV; + FTS_ERROR("check_dt failed, error=%d", error); + return error; + } + + /* malloc memory for global struct variable */ + ts_data = (struct fts_ts_data *)kzalloc(sizeof(*ts_data), GFP_KERNEL); + if (!ts_data) { + FTS_ERROR("allocate memory for fts_data fail"); + return -ENOMEM; + } + + fts_data = ts_data; + ts_data->client = client; + ts_data->dev = &client->dev; + ts_data->log_level = 1; + ts_data->fw_is_running = 0; + i2c_set_clientdata(client, ts_data); + + ret = fts_ts_probe_entry(ts_data); + if (ret) { + FTS_ERROR("Touch Screen(I2C BUS) driver probe fail"); + kfree_safe(ts_data); + fts_data = NULL; + return ret; + } + + FTS_INFO("Touch Screen(I2C BUS) driver prboe successfully"); + return 0; +} + +static int fts_ts_remove(struct i2c_client *client) +{ + return fts_ts_remove_entry(i2c_get_clientdata(client)); +} + +static const struct i2c_device_id fts_ts_id[] = { + {FTS_DRIVER_NAME, 0}, + {}, +}; +static const struct of_device_id fts_dt_match[] = { + {.compatible = "focaltech,fts", }, + {}, +}; +MODULE_DEVICE_TABLE(of, fts_dt_match); + +static struct i2c_driver fts_ts_driver = { + .probe = fts_ts_probe, + .remove = fts_ts_remove, + .driver = { + .name = FTS_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(fts_dt_match), + }, + .id_table = fts_ts_id, +}; + +static int __init fts_ts_init(void) +{ + int ret = 0; + + FTS_FUNC_ENTER(); + ret = i2c_add_driver(&fts_ts_driver); + if ( ret != 0 ) { + FTS_ERROR("Focaltech touch screen driver init failed!"); + } + FTS_FUNC_EXIT(); + return ret; +} + +static void __exit fts_ts_exit(void) +{ + i2c_del_driver(&fts_ts_driver); +} +module_init(fts_ts_init); +module_exit(fts_ts_exit); + +MODULE_AUTHOR("FocalTech Driver Team"); +MODULE_DESCRIPTION("FocalTech Touchscreen Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_core.h b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_core.h new file mode 100755 index 0000000000000000000000000000000000000000..a2e9d8b08dc7330aed5776833fc88a69e13f4687 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_core.h @@ -0,0 +1,284 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, Focaltech Ltd. 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. + * + */ +/***************************************************************************** +* +* File Name: focaltech_core.h + +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +#ifndef __LINUX_FOCALTECH_CORE_H__ +#define __LINUX_FOCALTECH_CORE_H__ +/***************************************************************************** +* Included header files +*****************************************************************************/ +#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 +#include +#include "focaltech_common.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define FTS_MAX_POINTS_SUPPORT 10 /* constant value, can't be changed */ +#define FTS_MAX_KEYS 4 +#define FTS_KEY_DIM 10 +#define FTS_ONE_TCH_LEN 6 +#define FTS_TOUCH_DATA_LEN (FTS_MAX_POINTS_SUPPORT * FTS_ONE_TCH_LEN + 3) + +#define FTS_SPI_CLK_MAX 10000000 + +#define FTS_GESTURE_POINTS_MAX 6 +#define FTS_GESTURE_DATA_LEN (FTS_GESTURE_POINTS_MAX * 4 + 4) + +#define FTS_MAX_ID 0x0A +#define FTS_TOUCH_X_H_POS 3 +#define FTS_TOUCH_X_L_POS 4 +#define FTS_TOUCH_Y_H_POS 5 +#define FTS_TOUCH_Y_L_POS 6 +#define FTS_TOUCH_PRE_POS 7 +#define FTS_TOUCH_AREA_POS 8 +#define FTS_TOUCH_POINT_NUM 2 +#define FTS_TOUCH_EVENT_POS 3 +#define FTS_TOUCH_ID_POS 5 +#define FTS_COORDS_ARR_SIZE 4 +#define FTS_X_MIN_DISPLAY_DEFAULT 0 +#define FTS_Y_MIN_DISPLAY_DEFAULT 0 +#define FTS_X_MAX_DISPLAY_DEFAULT 720 +#define FTS_Y_MAX_DISPLAY_DEFAULT 1280 + +#define FTS_TOUCH_DOWN 0 +#define FTS_TOUCH_UP 1 +#define FTS_TOUCH_CONTACT 2 +#define EVENT_DOWN(flag) ((FTS_TOUCH_DOWN == flag) || (FTS_TOUCH_CONTACT == flag)) +#define EVENT_UP(flag) (FTS_TOUCH_UP == flag) +#define EVENT_NO_DOWN(data) (!data->point_num) + +#define FTX_MAX_COMPATIBLE_TYPE 4 +#define FTX_MAX_COMMMAND_LENGTH 16 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +struct ftxxxx_proc { + struct proc_dir_entry *proc_entry; + u8 opmode; + u8 cmd_len; + u8 cmd[FTX_MAX_COMMMAND_LENGTH]; +}; + +struct fts_ts_platform_data { + u32 irq_gpio; + u32 irq_gpio_flags; + u32 reset_gpio; + u32 reset_gpio_flags; + bool have_key; + u32 key_number; + u32 keys[FTS_MAX_KEYS]; + u32 key_y_coords[FTS_MAX_KEYS]; + u32 key_x_coords[FTS_MAX_KEYS]; + u32 x_max; + u32 y_max; + u32 x_min; + u32 y_min; + u32 max_touch_number; + /* MODIFIED-BEGIN by hongwei.tian, 2020-02-26,BUG-8956218*/ + u32 id0_gpio; + u32 id0_gpio_flags; + u32 id0; + u32 id1_gpio; + u32 id1_gpio_flags; + u32 id1; + /* MODIFIED-END by hongwei.tian,BUG-8956218*/ + u8 panel_vendor; +}; + +struct ts_event { + int x; /*x coordinate */ + int y; /*y coordinate */ + int p; /* pressure */ + int flag; /* touch event flag: 0 -- down; 1-- up; 2 -- contact */ + int id; /*touch ID */ + int area; +}; + +struct fts_ts_data { + struct i2c_client *client; + struct spi_device *spi; + struct device *dev; + struct input_dev *input_dev; + struct fts_ts_platform_data *pdata; + struct ts_ic_info ic_info; + struct workqueue_struct *ts_workqueue; + struct work_struct fwupg_work; + struct delayed_work esdcheck_work; + struct delayed_work prc_work; + struct work_struct resume_work; + struct ftxxxx_proc proc; + spinlock_t irq_lock; + struct mutex report_mutex; + struct mutex bus_lock; + int irq; + int log_level; + int fw_is_running; /* confirm fw is running when using spi:default 0 */ + bool suspended; + bool fw_loading; + bool irq_disabled; + bool power_disabled; + bool glove_mode; + bool cover_mode; + bool charger_mode; + /* multi-touch */ + struct ts_event *events; + u8 *bus_tx_buf; + u8 *bus_rx_buf; + u8 *point_buf; + int pnt_buf_size; + int touchs; + int key_state; + int touch_point; + int point_num; + struct regulator *vdd; + struct regulator *vcc_i2c; + struct regulator *vdd_io; +#if FTS_PINCTRL_EN + struct pinctrl *pinctrl; + struct pinctrl_state *pins_active; + struct pinctrl_state *pins_suspend; + struct pinctrl_state *pins_release; +#endif +#if defined(CONFIG_FB) || defined(CONFIG_DRM) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + struct class *tct_touch_class; + struct device *tct_touch_gesture; + struct device *tct_touch_dev; +}; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +extern struct fts_ts_data *fts_data; + +/* communication interface */ +int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen); +int fts_read_reg(u8 addr, u8 *value); +int fts_write(u8 *writebuf, u32 writelen); +int fts_write_reg(u8 addr, u8 value); +void fts_hid2std(void); +int fts_bus_init(struct fts_ts_data *ts_data); +int fts_bus_exit(struct fts_ts_data *ts_data); + +/* Gesture functions */ +#if FTS_GESTURE_EN +int fts_gesture_init(struct fts_ts_data *ts_data); +int fts_gesture_exit(struct fts_ts_data *ts_data); +void fts_gesture_recovery(struct fts_ts_data *ts_data); +int fts_gesture_readdata(struct fts_ts_data *ts_data, u8 *data); +int fts_gesture_suspend(struct fts_ts_data *ts_data); +int fts_gesture_resume(struct fts_ts_data *ts_data); +#endif + +/* Apk and functions */ +#if FTS_APK_NODE_EN +int fts_create_apk_debug_channel(struct fts_ts_data *); +void fts_release_apk_debug_channel(struct fts_ts_data *); +#endif + +/* ADB functions */ +#if FTS_SYSFS_NODE_EN +int fts_create_sysfs(struct fts_ts_data *ts_data); +int fts_remove_sysfs(struct fts_ts_data *ts_data); +#endif + +/* ESD */ +#if FTS_ESDCHECK_EN +int fts_esdcheck_init(struct fts_ts_data *ts_data); +int fts_esdcheck_exit(struct fts_ts_data *ts_data); +int fts_esdcheck_switch(bool enable); +int fts_esdcheck_proc_busy(bool proc_debug); +int fts_esdcheck_set_intr(bool intr); +int fts_esdcheck_suspend(void); +int fts_esdcheck_resume(void); +#endif + +/* Production test */ +#if FTS_TEST_EN +int fts_test_init(struct fts_ts_data *ts_data); +int fts_test_exit(struct fts_ts_data *ts_data); +#endif + +/* Point Report Check*/ +#if FTS_POINT_REPORT_CHECK_EN +int fts_point_report_check_init(struct fts_ts_data *ts_data); +int fts_point_report_check_exit(struct fts_ts_data *ts_data); +void fts_prc_queue_work(struct fts_ts_data *ts_data); +#endif + +/* FW upgrade */ +int fts_fwupg_init(struct fts_ts_data *ts_data); +int fts_fwupg_exit(struct fts_ts_data *ts_data); +int fts_upgrade_bin(char *fw_name, bool force); +int fts_enter_test_environment(bool test_state); + +/* Other */ +int fts_reset_proc(int hdelayms); +int fts_wait_tp_to_valid(void); +void fts_release_all_finger(void); +void fts_tp_state_recovery(struct fts_ts_data *ts_data); +int fts_ex_mode_init(struct fts_ts_data *ts_data); +int fts_ex_mode_exit(struct fts_ts_data *ts_data); +int fts_ex_mode_recovery(struct fts_ts_data *ts_data); + +void fts_irq_disable(void); +void fts_irq_enable(void); +#endif /* __LINUX_FOCALTECH_CORE_H__ */ diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_esdcheck.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_esdcheck.c new file mode 100755 index 0000000000000000000000000000000000000000..01c8e2b6e1b94296ffd3955585258d542fe5fb11 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_esdcheck.c @@ -0,0 +1,465 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_esdcheck.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-03 +* +* Abstract: ESD check function +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By luougojin 2016-08-03 +* v1.1: By luougojin 2017-02-15 +* 1. Add LCD_ESD_PATCH to control idc_esdcheck_lcderror +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +#if FTS_ESDCHECK_EN +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define ESDCHECK_WAIT_TIME 1000 /* ms */ +#define LCD_ESD_PATCH 0 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +struct fts_esdcheck_st { + u8 mode : 1; /* 1- need check esd 0- no esd check */ + u8 suspend : 1; + u8 proc_debug : 1; /* apk or adb use */ + u8 intr : 1; /* 1- Interrupt trigger */ + u8 unused : 4; + u8 flow_work_hold_cnt; /* Flow Work Cnt(reg0x91) keep a same value for x times. >=5 times is ESD, need reset */ + u8 flow_work_cnt_last; /* Save Flow Work Cnt(reg0x91) value */ + u32 hardware_reset_cnt; + u32 nack_cnt; + u32 dataerror_cnt; +}; + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct fts_esdcheck_st fts_esdcheck_data; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ +#if LCD_ESD_PATCH +int lcd_need_reset; +static int tp_need_recovery; /* LCD reset cause Tp reset */ +int idc_esdcheck_lcderror(struct fts_ts_data *ts_data) +{ + int ret = 0; + u8 val = 0; + + FTS_DEBUG("[ESD]Check LCD ESD"); + if ( (tp_need_recovery == 1) && (lcd_need_reset == 0) ) { + tp_need_recovery = 0; + /* LCD reset, need recover TP state */ + fts_release_all_finger(); + fts_tp_state_recovery(ts_data); + } + + ret = fts_read_reg(FTS_REG_ESD_SATURATE, &val); + if ( ret < 0) { + FTS_ERROR("[ESD]: Read ESD_SATURATE(0xED) failed ret=%d!", ret); + return -EIO; + } + + if (val == 0xAA) { + /* + * 1. Set flag lcd_need_reset = 1; + * 2. LCD driver need reset(recovery) LCD and set lcd_need_reset to 0 + * 3. recover TP state + */ + FTS_INFO("LCD ESD, Execute LCD reset!"); + lcd_need_reset = 1; + tp_need_recovery = 1; + } + + return 0; +} +#endif + +static int fts_esdcheck_tp_reset(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + + fts_esdcheck_data.flow_work_hold_cnt = 0; + fts_esdcheck_data.hardware_reset_cnt++; + + fts_reset_proc(200); + fts_release_all_finger(); + fts_tp_state_recovery(ts_data); + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: get_chip_id +* Brief: Read Chip Id 3 times +* Input: +* Output: +* Return: 1(ture) - Read Chip Id 3 times failed +* 0(false) - Read Chip Id pass +*****************************************************************************/ +static bool get_chip_id(struct fts_ts_data *ts_data) +{ + int ret = 0; + int i = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + u8 chip_id = ts_data->ic_info.ids.chip_idh; + + for (i = 0; i < 3; i++) { + reg_addr = FTS_REG_CHIP_ID; + ret = fts_read(®_addr, 1, ®_value, 1); + if (ret < 0) { + FTS_ERROR("[ESD]: Read Reg 0xA3 failed ret = %d!!", ret); + fts_esdcheck_data.nack_cnt++; + } else { + if (reg_value == chip_id) { + break; + } else { + FTS_DEBUG("read chip_id:%x,retry:%d", reg_value, i); + fts_esdcheck_data.dataerror_cnt++; + } + } + msleep(10); + } + + /* if can't get correct data in 3 times, then need hardware reset */ + if (i >= 3) { + FTS_ERROR("[ESD]: Read Chip id 3 times failed, need execute TP reset!!"); + return true; + } + + return false; +} + +/***************************************************************************** +* Name: get_flow_cnt +* Brief: Read flow cnt(0x91) +* Input: +* Output: +* Return: 1(true) - Reg 0x91(flow cnt) abnormal: hold a value for 5 times +* 0(false) - Reg 0x91(flow cnt) normal +*****************************************************************************/ +static bool get_flow_cnt(struct fts_ts_data *ts_data) +{ + int ret = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + + reg_addr = FTS_REG_FLOW_WORK_CNT; + ret = fts_read(®_addr, 1, ®_value, 1); + if (ret < 0) { + FTS_ERROR("[ESD]: Read Reg 0x91 failed ret = %d!!", ret); + fts_esdcheck_data.nack_cnt++; + } else { + if ( reg_value == fts_esdcheck_data.flow_work_cnt_last ) { + fts_esdcheck_data.flow_work_hold_cnt++; + } else { + fts_esdcheck_data.flow_work_hold_cnt = 0; + } + + fts_esdcheck_data.flow_work_cnt_last = reg_value; + } + + /* if read flow work cnt 5 times and the value are all the same, then need hardware_reset */ + if (fts_esdcheck_data.flow_work_hold_cnt >= 5) { + FTS_DEBUG("[ESD]: Flow Work Cnt(reg0x91) keep a value for 5 times, need execute TP reset!!"); + return true; + } + + return false; +} + +static int esdcheck_algorithm(struct fts_ts_data *ts_data) +{ + int ret = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + bool hardware_reset = 0; + + /* 1. esdcheck is interrupt, then return */ + if (fts_esdcheck_data.intr == 1) { + FTS_DEBUG("[ESD]: In interrupt state, not check esd, return immediately!!"); + return 0; + } + + /* 2. check power state, if suspend, no need check esd */ + if (fts_esdcheck_data.suspend == 1) { + FTS_DEBUG("[ESD]: In suspend, not check esd, return immediately!!"); + /* because in suspend state, adb can be used, when upgrade FW, will active ESD check(active = 1) + * But in suspend, then will don't queue_delayed_work, when resume, don't check ESD again + */ + return 0; + } + + /* 3. check fts_esdcheck_data.proc_debug state, if 1-proc busy, no need check esd*/ + if (fts_esdcheck_data.proc_debug == 1) { + FTS_INFO("[ESD]: In apk or adb command mode, not check esd, return immediately!!"); + return 0; + } + + /* 4. In factory mode, can't check esd */ + reg_addr = FTS_REG_WORKMODE; + ret = fts_read_reg(reg_addr, ®_value); + if ( ret < 0 ) { + fts_esdcheck_data.nack_cnt++; + } else if ( (reg_value & 0x70) != FTS_REG_WORKMODE_WORK_VALUE) { + FTS_DEBUG("[ESD]: not in work mode, no check esd, return immediately!!"); + return 0; + } + + /* 5. IDC esd check lcd default:close */ +#if LCD_ESD_PATCH + idc_esdcheck_lcderror(ts_data); +#endif + + /* 6. Get Chip ID */ + hardware_reset = get_chip_id(ts_data); + + /* 7. get Flow work cnt: 0x91 If no change for 5 times, then ESD and reset */ + if (!hardware_reset) { + hardware_reset = get_flow_cnt(ts_data); + } + + /* 8. If need hardware reset, then handle it here */ + if ( hardware_reset == 1) { + FTS_DEBUG("[ESD]: NoACK=%d, Error Data=%d, Hardware Reset=%d", \ + fts_esdcheck_data.nack_cnt, fts_esdcheck_data.dataerror_cnt, \ + fts_esdcheck_data.hardware_reset_cnt); + fts_esdcheck_tp_reset(ts_data); + } + + return 0; +} + +static void esdcheck_func(struct work_struct *work) +{ + u8 val = 0; + struct fts_ts_data *ts_data = container_of(work, + struct fts_ts_data, esdcheck_work.work); + + if (ENABLE == fts_esdcheck_data.mode) { + if (ts_data->ic_info.is_incell) { + fts_read_reg(FTS_REG_ESDCHECK_DISABLE, &val); + if (0xA5 == val) { + fts_esdcheck_data.mode = DISABLE; + return; + } + } + esdcheck_algorithm(ts_data); + queue_delayed_work(ts_data->ts_workqueue, &ts_data->esdcheck_work, + msecs_to_jiffies(ESDCHECK_WAIT_TIME)); + } + +} + +int fts_esdcheck_set_intr(bool intr) +{ + /* interrupt don't add debug message */ + fts_esdcheck_data.intr = intr; + return 0; +} + +int fts_esdcheck_get_status(void) +{ + /* interrupt don't add debug message */ + return fts_esdcheck_data.mode; +} + +/***************************************************************************** +* Name: fts_esdcheck_proc_busy +* Brief: When APK or ADB command access TP via driver, then need set proc_debug, +* then will not check ESD. +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_proc_busy(bool proc_debug) +{ + fts_esdcheck_data.proc_debug = proc_debug; + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_switch +* Brief: FTS esd check function switch. +* Input: enable: 1 - Enable esd check +* 0 - Disable esd check +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_switch(bool enable) +{ + struct fts_ts_data *ts_data = fts_data; + FTS_FUNC_ENTER(); + if (fts_esdcheck_data.mode == ENABLE) { + if (enable) { + FTS_DEBUG("[ESD]: ESD check start!!"); + fts_esdcheck_data.flow_work_hold_cnt = 0; + fts_esdcheck_data.flow_work_cnt_last = 0; + queue_delayed_work(ts_data->ts_workqueue, &ts_data->esdcheck_work, + msecs_to_jiffies(ESDCHECK_WAIT_TIME)); + } else { + FTS_DEBUG("[ESD]: ESD check stop!!"); + cancel_delayed_work_sync(&ts_data->esdcheck_work); + } + } else { + FTS_DEBUG("[ESD]: ESD should disable!!"); + cancel_delayed_work_sync(&ts_data->esdcheck_work); + } + + FTS_FUNC_EXIT(); + return 0; +} + +int fts_esdcheck_suspend(void) +{ + FTS_FUNC_ENTER(); + fts_esdcheck_switch(DISABLE); + fts_esdcheck_data.suspend = 1; + FTS_FUNC_EXIT(); + return 0; +} + +int fts_esdcheck_resume( void ) +{ + FTS_FUNC_ENTER(); + fts_esdcheck_switch(ENABLE); + fts_esdcheck_data.suspend = 0; + FTS_FUNC_EXIT(); + return 0; +} + +static ssize_t fts_esdcheck_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_DEBUG("enable esdcheck"); + fts_esdcheck_data.mode = ENABLE; + fts_esdcheck_switch(ENABLE); + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_DEBUG("disable esdcheck"); + fts_esdcheck_data.mode = DISABLE; + fts_esdcheck_switch(DISABLE); + } + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_esdcheck_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count; + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + count = snprintf(buf, PAGE_SIZE, "Esd check: %s\n", \ + fts_esdcheck_get_status() ? "On" : "Off"); + mutex_unlock(&input_dev->mutex); + + return count; +} + +/* sysfs esd node + * read example: cat fts_esd_mode ---read esd mode + * write example:echo 01 > fts_esd_mode ---make esdcheck enable + * + */ +static DEVICE_ATTR (fts_esd_mode, S_IRUGO | S_IWUSR, fts_esdcheck_show, fts_esdcheck_store); + +static struct attribute *fts_esd_mode_attrs[] = { + + &dev_attr_fts_esd_mode.attr, + NULL, +}; + +static struct attribute_group fts_esd_group = { + .attrs = fts_esd_mode_attrs, +}; + +int fts_create_esd_sysfs(struct device *dev) +{ + int ret = 0; + + ret = sysfs_create_group(&dev->kobj, &fts_esd_group); + if ( ret != 0) { + FTS_ERROR("fts_create_esd_sysfs(sysfs) create failed!"); + sysfs_remove_group(&dev->kobj, &fts_esd_group); + return ret; + } + return 0; +} + +int fts_esdcheck_init(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + + if (ts_data->ts_workqueue) { + INIT_DELAYED_WORK(&ts_data->esdcheck_work, esdcheck_func); + } else { + FTS_ERROR("fts workqueue is NULL, can't run esd check function"); + return -EINVAL; + } + + memset((u8 *)&fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st)); + + fts_esdcheck_data.mode = ENABLE; + fts_esdcheck_switch(ENABLE); + fts_create_esd_sysfs(ts_data->dev); + FTS_FUNC_EXIT(); + return 0; +} + +int fts_esdcheck_exit(struct fts_ts_data *ts_data) +{ + sysfs_remove_group(&ts_data->dev->kobj, &fts_esd_group); + return 0; +} +#endif /* FTS_ESDCHECK_EN */ + diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_ex_fun.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_ex_fun.c new file mode 100755 index 0000000000000000000000000000000000000000..02e1543eb3572e9860aee1df772d1eb003189945 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_ex_fun.c @@ -0,0 +1,1173 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, Focaltech Ltd. 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. + * + */ + +/***************************************************************************** +* +* File Name: Focaltech_ex_fun.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define PROC_UPGRADE 0 +#define PROC_READ_REGISTER 1 +#define PROC_WRITE_REGISTER 2 +#define PROC_AUTOCLB 4 +#define PROC_UPGRADE_INFO 5 +#define PROC_WRITE_DATA 6 +#define PROC_READ_DATA 7 +#define PROC_SET_TEST_FLAG 8 +#define PROC_SET_SLAVE_ADDR 10 +#define PROC_HW_RESET 11 +#define PROC_READ_STATUS 12 +#define PROC_SET_BOOT_MODE 13 +#define PROC_ENTER_TEST_ENVIRONMENT 14 +#define PROC_NAME "ftxxxx-debug" +#define PROC_BUF_SIZE 256 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +enum { + RWREG_OP_READ = 0, + RWREG_OP_WRITE = 1, +}; + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct rwreg_operation_t { + int type; /* 0: read, 1: write */ + int reg; /* register */ + int len; /* read/write length */ + int val; /* length = 1; read: return value, write: op return */ + int res; /* 0: success, otherwise: fail */ + char *opbuf; /* length >= 1, read return value, write: op return */ +} rw_op; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +static ssize_t fts_debug_write( + struct file *filp, const char __user *buff, size_t count, loff_t *ppos) +{ + u8 *writebuf = NULL; + u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; + int buflen = count; + int writelen = 0; + int ret = 0; + char tmp[25]; + struct fts_ts_data *ts_data = fts_data; + struct ftxxxx_proc *proc = &ts_data->proc; + + if ((buflen <= 1) || (buflen > PAGE_SIZE)) { + FTS_ERROR("apk proc wirte count(%d>%d) fail", buflen, (int)PAGE_SIZE); + return -EINVAL; + } + + if (buflen > PROC_BUF_SIZE) { + writebuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); + if (NULL == writebuf) { + FTS_ERROR("apk proc wirte buf zalloc fail"); + return -ENOMEM; + } + } else { + writebuf = tmpbuf; + } + + if (copy_from_user(writebuf, buff, buflen)) { + FTS_ERROR("[APK]: copy from user error!!"); + ret = -EFAULT; + goto proc_write_err; + } + + proc->opmode = writebuf[0]; + switch (proc->opmode) { + case PROC_SET_TEST_FLAG: + FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x", writebuf[1]); + if (writebuf[1] == 0) { +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + } else { +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + } + break; + + case PROC_READ_REGISTER: + proc->cmd[0] = writebuf[1]; + break; + + case PROC_WRITE_REGISTER: + ret = fts_write_reg(writebuf[1], writebuf[2]); + if (ret < 0) { + FTS_ERROR("PROC_WRITE_REGISTER write error"); + goto proc_write_err; + } + break; + + case PROC_READ_DATA: + writelen = buflen - 1; + memcpy(proc->cmd, writebuf + 1, writelen); + proc->cmd_len = writelen; + ret = fts_write(writebuf + 1, writelen); + if (ret < 0) { + FTS_ERROR("PROC_READ_DATA write error"); + goto proc_write_err; + } + break; + + case PROC_WRITE_DATA: + writelen = buflen - 1; + ret = fts_write(writebuf + 1, writelen); + if (ret < 0) { + FTS_ERROR("PROC_WRITE_DATA write error"); + goto proc_write_err; + } + break; + + case PROC_SET_SLAVE_ADDR: + break; + + case PROC_HW_RESET: + snprintf(tmp, 25, "%s", writebuf + 1); + tmp[buflen - 1] = '\0'; + if (strncmp(tmp, "focal_driver", 12) == 0) { + FTS_INFO("APK execute HW Reset"); + fts_reset_proc(0); + } + break; + + case PROC_SET_BOOT_MODE: + FTS_DEBUG("[APK]: PROC_SET_BOOT_MODE = %x", writebuf[1]); + if (0 == writebuf[1]) { + ts_data->fw_is_running = true; + } else { + ts_data->fw_is_running = false; + } + break; + case PROC_ENTER_TEST_ENVIRONMENT: + FTS_DEBUG("[APK]: PROC_ENTER_TEST_ENVIRONMENT = %x", writebuf[1]); + if (0 == writebuf[1]) { + fts_enter_test_environment(0); + } else { + fts_enter_test_environment(1); + } + break; + + default: + break; + } + + ret = buflen; +proc_write_err: + if ((buflen > PROC_BUF_SIZE) && writebuf) { + kfree(writebuf); + writebuf = NULL; + } + return ret; +} + +static ssize_t fts_debug_read( + struct file *filp, char __user *buff, size_t count, loff_t *ppos) +{ + int ret = 0; + int num_read_chars = 0; + int buflen = count; + u8 *readbuf = NULL; + u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; + struct fts_ts_data *ts_data = fts_data; + struct ftxxxx_proc *proc = &ts_data->proc; + + if ((buflen <= 0) || (buflen > PAGE_SIZE)) { + FTS_ERROR("apk proc read count(%d>%d) fail", buflen, (int)PAGE_SIZE); + return -EINVAL; + } + + if (buflen > PROC_BUF_SIZE) { + readbuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); + if (NULL == readbuf) { + FTS_ERROR("apk proc wirte buf zalloc fail"); + return -ENOMEM; + } + } else { + readbuf = tmpbuf; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + + switch (proc->opmode) { + case PROC_READ_REGISTER: + num_read_chars = 1; + ret = fts_read_reg(proc->cmd[0], &readbuf[0]); + if (ret < 0) { + FTS_ERROR("PROC_READ_REGISTER read error"); + goto proc_read_err; + } + break; + case PROC_WRITE_REGISTER: + break; + + case PROC_READ_DATA: + num_read_chars = buflen; + ret = fts_read(NULL, 0, readbuf, num_read_chars); + if (ret < 0) { + FTS_ERROR("PROC_READ_DATA read error"); + goto proc_read_err; + } + break; + + case PROC_WRITE_DATA: + break; + + default: + break; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + + if (copy_to_user(buff, readbuf, num_read_chars)) { + FTS_ERROR("copy to user error"); + ret = -EFAULT; + goto proc_read_err; + } + + ret = num_read_chars; +proc_read_err: + if ((buflen > PROC_BUF_SIZE) && readbuf) { + kfree(readbuf); + readbuf = NULL; + } + return ret; +} + +static const struct file_operations fts_proc_fops = { + .owner = THIS_MODULE, + .read = fts_debug_read, + .write = fts_debug_write, +}; +#else +static int fts_debug_write( + struct file *filp, const char __user *buff, unsigned long len, void *data) +{ + u8 *writebuf = NULL; + u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; + int buflen = count; + int writelen = 0; + int ret = 0; + char tmp[25]; + struct fts_ts_data *ts_data = fts_data; + struct ftxxxx_proc *proc = &ts_data->proc; + + if ((buflen <= 1) || (buflen > PAGE_SIZE)) { + FTS_ERROR("apk proc wirte count(%d>%d) fail", buflen, (int)PAGE_SIZE); + return -EINVAL; + } + + if (buflen > PROC_BUF_SIZE) { + writebuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); + if (NULL == writebuf) { + FTS_ERROR("apk proc wirte buf zalloc fail"); + return -ENOMEM; + } + } else { + writebuf = tmpbuf; + } + + if (copy_from_user(writebuf, buff, buflen)) { + FTS_ERROR("[APK]: copy from user error!!"); + ret = -EFAULT; + goto proc_write_err; + } + + proc->opmode = writebuf[0]; + switch (proc->opmode) { + case PROC_SET_TEST_FLAG: + FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x", writebuf[1]); + if (writebuf[1] == 0) { +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + } else { +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + } + break; + + case PROC_READ_REGISTER: + proc->cmd[0] = writebuf[1]; + break; + + case PROC_WRITE_REGISTER: + ret = fts_write_reg(writebuf[1], writebuf[2]); + if (ret < 0) { + FTS_ERROR("PROC_WRITE_REGISTER write error"); + goto proc_write_err; + } + break; + + case PROC_READ_DATA: + writelen = buflen - 1; + memcpy(proc->cmd, writebuf + 1, writelen); + proc->cmd_len = writelen; + ret = fts_write(writebuf + 1, writelen); + if (ret < 0) { + FTS_ERROR("PROC_READ_DATA write error"); + goto proc_write_err; + } + break; + + case PROC_WRITE_DATA: + writelen = buflen - 1; + ret = fts_write(writebuf + 1, writelen); + if (ret < 0) { + FTS_ERROR("PROC_WRITE_DATA write error"); + goto proc_write_err; + } + break; + + case PROC_SET_SLAVE_ADDR: + break; + + case PROC_HW_RESET: + snprintf(tmp, PAGE_SIZE, "%s", writebuf + 1); + tmp[buflen - 1] = '\0'; + if (strncmp(tmp, "focal_driver", 12) == 0) { + FTS_INFO("APK execute HW Reset"); + fts_reset_proc(0); + } + break; + + default: + break; + } + + ret = buflen; +proc_write_err: + if ((buflen > PROC_BUF_SIZE) && writebuf) { + kfree(writebuf); + writebuf = NULL; + } + return ret; +} + +static int fts_debug_read( + char *page, char **start, off_t off, int count, int *eof, void *data ) +{ + int ret = 0; + int num_read_chars = 0; + int buflen = count; + u8 *readbuf = NULL; + u8 tmpbuf[PROC_BUF_SIZE] = { 0 }; + struct fts_ts_data *ts_data = fts_data; + struct ftxxxx_proc *proc = &ts_data->proc; + + if ((buflen <= 0) || (buflen > PAGE_SIZE)) { + FTS_ERROR("apk proc read count(%d>%d) fail", buflen, (int)PAGE_SIZE); + return -EINVAL; + } + + if (buflen > PROC_BUF_SIZE) { + readbuf = (u8 *)kzalloc(buflen * sizeof(u8), GFP_KERNEL); + if (NULL == readbuf) { + FTS_ERROR("apk proc wirte buf zalloc fail"); + return -ENOMEM; + } + } else { + readbuf = tmpbuf; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + + switch (proc->opmode) { + case PROC_READ_REGISTER: + num_read_chars = 1; + ret = fts_read_reg(proc->cmd[0], &readbuf[0]); + if (ret < 0) { + FTS_ERROR("PROC_READ_REGISTER read error"); + goto proc_read_err; + } + break; + case PROC_WRITE_REGISTER: + break; + + case PROC_READ_DATA: + num_read_chars = buflen; + ret = fts_read(NULL, 0, readbuf, num_read_chars); + if (ret < 0) { + FTS_ERROR("PROC_READ_DATA read error"); + goto proc_read_err; + } + break; + + case PROC_WRITE_DATA: + break; + + default: + break; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + + if (copy_to_user(buff, readbuf, num_read_chars)) { + FTS_ERROR("copy to user error"); + ret = -EFAULT; + goto proc_read_err; + } + + ret = num_read_chars; +proc_read_err: + if ((buflen > PROC_BUF_SIZE) && readbuf) { + kfree(readbuf); + readbuf = NULL; + } + return ret; +} +#endif + +int fts_create_apk_debug_channel(struct fts_ts_data *ts_data) +{ + struct ftxxxx_proc *proc = &ts_data->proc; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + proc->proc_entry = proc_create(PROC_NAME, 0777, NULL, &fts_proc_fops); + if (NULL == proc->proc_entry) { + FTS_ERROR("create proc entry fail"); + return -ENOMEM; + } +#else + proc->proc_entry = create_proc_entry(PROC_NAME, 0777, NULL); + if (NULL == proc->proc_entry) { + FTS_ERROR("create proc entry fail"); + return -ENOMEM; + } + proc->proc_entry->write_proc = fts_debug_write; + proc->proc_entry->read_proc = fts_debug_read; +#endif + + FTS_INFO("Create proc entry success!"); + return 0; +} + +void fts_release_apk_debug_channel(struct fts_ts_data *ts_data) +{ + struct ftxxxx_proc *proc = &ts_data->proc; + + if (proc->proc_entry) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + proc_remove(proc->proc_entry); +#else + remove_proc_entry(PROC_NAME, NULL); +#endif + } +} + +/************************************************************************ + * sysfs interface + ***********************************************************************/ +/* fts_hw_reset interface */ +static ssize_t fts_hw_reset_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct input_dev *input_dev = fts_data->input_dev; + ssize_t count = 0; + + mutex_lock(&input_dev->mutex); + fts_reset_proc(0); + count = snprintf(buf, PAGE_SIZE, "hw reset executed\n"); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_hw_reset_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} + +/* fts_irq interface */ +static ssize_t fts_irq_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + struct irq_desc *desc = irq_to_desc(fts_data->irq); + + count = snprintf(buf, PAGE_SIZE, "irq_depth:%d\n", desc->depth); + + return count; +} + +static ssize_t fts_irq_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_INFO("enable irq"); + fts_irq_enable(); + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_INFO("disable irq"); + fts_irq_disable(); + } + mutex_unlock(&input_dev->mutex); + return count; +} + +/* fts_boot_mode interface */ +static ssize_t fts_bootmode_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_dev = fts_data->input_dev; + + FTS_FUNC_ENTER(); + mutex_lock(&input_dev->mutex); + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_INFO("[EX-FUN]set to boot mode"); + fts_data->fw_is_running = false; + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_INFO("[EX-FUN]set to fw mode"); + fts_data->fw_is_running = true; + } + mutex_unlock(&input_dev->mutex); + FTS_FUNC_EXIT(); + + return count; +} + +static ssize_t fts_bootmode_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + struct input_dev *input_dev = fts_data->input_dev; + + FTS_FUNC_ENTER(); + mutex_lock(&input_dev->mutex); + if (true == fts_data->fw_is_running) { + count = snprintf(buf, PAGE_SIZE, "tp is in fw mode\n"); + } else { + count = snprintf(buf, PAGE_SIZE, "tp is in boot mode\n"); + } + mutex_unlock(&input_dev->mutex); + FTS_FUNC_EXIT(); + + return count; +} + +/* fts_tpfwver interface */ +static ssize_t fts_tpfwver_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fts_ts_data *ts_data = fts_data; + struct input_dev *input_dev = ts_data->input_dev; + ssize_t num_read_chars = 0; + u8 fwver = 0; + + mutex_lock(&input_dev->mutex); + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + fts_read_reg(FTS_REG_FW_VER, &fwver); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + if ((fwver == 0xFF) || (fwver == 0x00)) + num_read_chars = snprintf(buf, PAGE_SIZE, "get tp fw version fail!\n"); + else + num_read_chars = snprintf(buf, PAGE_SIZE, "%02x\n", fwver); + + mutex_unlock(&input_dev->mutex); + return num_read_chars; +} + +static ssize_t fts_tpfwver_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} + +/* fts_rw_reg */ +static ssize_t fts_tprwreg_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count; + int i; + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + + if (rw_op.len < 0) { + count = snprintf(buf, PAGE_SIZE, "Invalid cmd line\n"); + } else if (rw_op.len == 1) { + if (RWREG_OP_READ == rw_op.type) { + if (rw_op.res == 0) { + count = snprintf(buf, PAGE_SIZE, "Read %02X: %02X\n", rw_op.reg, rw_op.val); + } else { + count = snprintf(buf, PAGE_SIZE, "Read %02X failed, ret: %d\n", rw_op.reg, rw_op.res); + } + } else { + if (rw_op.res == 0) { + count = snprintf(buf, PAGE_SIZE, "Write %02X, %02X success\n", rw_op.reg, rw_op.val); + } else { + count = snprintf(buf, PAGE_SIZE, "Write %02X failed, ret: %d\n", rw_op.reg, rw_op.res); + } + } + } else { + if (RWREG_OP_READ == rw_op.type) { + count = snprintf(buf, PAGE_SIZE, "Read Reg: [%02X]-[%02X]\n", rw_op.reg, rw_op.reg + rw_op.len); + count += snprintf(buf + count, PAGE_SIZE, "Result: "); + if (rw_op.res) { + count += snprintf(buf + count, PAGE_SIZE, "failed, ret: %d\n", rw_op.res); + } else { + if (rw_op.opbuf) { + for (i = 0; i < rw_op.len; i++) { + count += snprintf(buf + count, PAGE_SIZE, "%02X ", rw_op.opbuf[i]); + } + count += snprintf(buf + count, PAGE_SIZE, "\n"); + } + } + } else { + ; + count = snprintf(buf, PAGE_SIZE, "Write Reg: [%02X]-[%02X]\n", rw_op.reg, rw_op.reg + rw_op.len - 1); + count += snprintf(buf + count, PAGE_SIZE, "Write Data: "); + if (rw_op.opbuf) { + for (i = 1; i < rw_op.len; i++) { + count += snprintf(buf + count, PAGE_SIZE, "%02X ", rw_op.opbuf[i]); + } + count += snprintf(buf + count, PAGE_SIZE, "\n"); + } + if (rw_op.res) { + count += snprintf(buf + count, PAGE_SIZE, "Result: failed, ret: %d\n", rw_op.res); + } else { + count += snprintf(buf + count, PAGE_SIZE, "Result: success\n"); + } + } + /*if (rw_op.opbuf) { + kfree(rw_op.opbuf); + rw_op.opbuf = NULL; + }*/ + } + mutex_unlock(&input_dev->mutex); + + return count; +} + +static int shex_to_int(const char *hex_buf, int size) +{ + int i; + int base = 1; + int value = 0; + char single; + + for (i = size - 1; i >= 0; i--) { + single = hex_buf[i]; + + if ((single >= '0') && (single <= '9')) { + value += (single - '0') * base; + } else if ((single >= 'a') && (single <= 'z')) { + value += (single - 'a' + 10) * base; + } else if ((single >= 'A') && (single <= 'Z')) { + value += (single - 'A' + 10) * base; + } else { + return -EINVAL; + } + + base *= 16; + } + + return value; +} + + +static u8 shex_to_u8(const char *hex_buf, int size) +{ + return (u8)shex_to_int(hex_buf, size); +} +/* + * Format buf: + * [0]: '0' write, '1' read(reserved) + * [1-2]: addr, hex + * [3-4]: length, hex + * [5-6]...[n-(n+1)]: data, hex + */ +static int fts_parse_buf(const char *buf, size_t cmd_len) +{ + int length; + int i; + char *tmpbuf; + + rw_op.reg = shex_to_u8(buf + 1, 2); + length = shex_to_int(buf + 3, 2); + + if (buf[0] == '1') { + rw_op.len = length; + rw_op.type = RWREG_OP_READ; + FTS_DEBUG("read %02X, %d bytes", rw_op.reg, rw_op.len); + } else { + if (cmd_len < (length * 2 + 5)) { + pr_err("data invalided!\n"); + return -EINVAL; + } + FTS_DEBUG("write %02X, %d bytes", rw_op.reg, length); + + /* first byte is the register addr */ + rw_op.type = RWREG_OP_WRITE; + rw_op.len = length + 1; + } + + if (rw_op.len > 0) { + tmpbuf = (char *)kzalloc(rw_op.len, GFP_KERNEL); + if (!tmpbuf) { + FTS_ERROR("allocate memory failed!\n"); + return -ENOMEM; + } + + if (RWREG_OP_WRITE == rw_op.type) { + tmpbuf[0] = rw_op.reg & 0xFF; + FTS_DEBUG("write buffer: "); + for (i = 1; i < rw_op.len; i++) { + tmpbuf[i] = shex_to_u8(buf + 5 + i * 2 - 2, 2); + FTS_DEBUG("buf[%d]: %02X", i, tmpbuf[i] & 0xFF); + } + } + rw_op.opbuf = tmpbuf; + } + + return rw_op.len; +} + +static ssize_t fts_tprwreg_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_dev = fts_data->input_dev; + ssize_t cmd_length = 0; + + mutex_lock(&input_dev->mutex); + cmd_length = count - 1; + + if (rw_op.opbuf) { + kfree(rw_op.opbuf); + rw_op.opbuf = NULL; + } + + FTS_DEBUG("cmd len: %d, buf: %s", (int)cmd_length, buf); + /* compatible old ops */ + if (2 == cmd_length) { + rw_op.type = RWREG_OP_READ; + rw_op.len = 1; + rw_op.reg = shex_to_int(buf, 2); + } else if (4 == cmd_length) { + rw_op.type = RWREG_OP_WRITE; + rw_op.len = 1; + rw_op.reg = shex_to_int(buf, 2); + rw_op.val = shex_to_int(buf + 2, 2); + } else if (cmd_length < 5) { + FTS_ERROR("Invalid cmd buffer"); + mutex_unlock(&input_dev->mutex); + return -EINVAL; + } else { + rw_op.len = fts_parse_buf(buf, cmd_length); + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + if (rw_op.len < 0) { + FTS_ERROR("cmd buffer error!"); + + } else { + if (RWREG_OP_READ == rw_op.type) { + if (rw_op.len == 1) { + u8 reg, val; + reg = rw_op.reg & 0xFF; + rw_op.res = fts_read_reg(reg, &val); + rw_op.val = val; + } else { + char reg; + reg = rw_op.reg & 0xFF; + + rw_op.res = fts_read(®, 1, rw_op.opbuf, rw_op.len); + } + + if (rw_op.res < 0) { + FTS_ERROR("Could not read 0x%02x", rw_op.reg); + } else { + FTS_INFO("read 0x%02x, %d bytes successful", rw_op.reg, rw_op.len); + rw_op.res = 0; + } + + } else { + if (rw_op.len == 1) { + u8 reg, val; + reg = rw_op.reg & 0xFF; + val = rw_op.val & 0xFF; + rw_op.res = fts_write_reg(reg, val); + } else { + rw_op.res = fts_write(rw_op.opbuf, rw_op.len); + } + if (rw_op.res < 0) { + FTS_ERROR("Could not write 0x%02x", rw_op.reg); + + } else { + FTS_INFO("Write 0x%02x, %d bytes successful", rw_op.val, rw_op.len); + rw_op.res = 0; + } + } + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + mutex_unlock(&input_dev->mutex); + + return count; +} + +/* fts_upgrade_bin interface */ +static ssize_t fts_fwupgradebin_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return -EPERM; +} + +static ssize_t fts_fwupgradebin_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char fwname[FILE_NAME_LENGTH] = { 0 }; + struct input_dev *input_dev = fts_data->input_dev; + + if ((count <= 1) || (count >= FILE_NAME_LENGTH - 32)) { + FTS_ERROR("fw bin name's length(%d) fail", (int)count); + return -EINVAL; + } + memset(fwname, 0, sizeof(fwname)); + snprintf(fwname, FILE_NAME_LENGTH, "%s", buf); + fwname[count - 1] = '\0'; + + FTS_INFO("upgrade with bin file through sysfs node"); + mutex_lock(&input_dev->mutex); + fts_upgrade_bin(fwname, 0); + mutex_unlock(&input_dev->mutex); + + return count; +} + +/* fts_force_upgrade interface */ +static ssize_t fts_fwforceupg_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + return -EPERM; +} + +static ssize_t fts_fwforceupg_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + char fwname[FILE_NAME_LENGTH]; + struct input_dev *input_dev = fts_data->input_dev; + + if ((count <= 1) || (count >= FILE_NAME_LENGTH - 32)) { + FTS_ERROR("fw bin name's length(%d) fail", (int)count); + return -EINVAL; + } + memset(fwname, 0, sizeof(fwname)); + snprintf(fwname, FILE_NAME_LENGTH, "%s", buf); + fwname[count - 1] = '\0'; + + FTS_INFO("force upgrade through sysfs node"); + mutex_lock(&input_dev->mutex); + fts_upgrade_bin(fwname, 1); + mutex_unlock(&input_dev->mutex); + + return count; +} + +/* fts_driver_info interface */ +static ssize_t fts_driverinfo_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + struct fts_ts_data *ts_data = fts_data; + struct fts_ts_platform_data *pdata = ts_data->pdata; + struct input_dev *input_dev = ts_data->input_dev; + + mutex_lock(&input_dev->mutex); + count += snprintf(buf + count, PAGE_SIZE, "Driver Ver:%s\n", FTS_DRIVER_VERSION); + + count += snprintf(buf + count, PAGE_SIZE, "Resolution:(%d,%d)~(%d,%d)\n", + pdata->x_min, pdata->y_min, pdata->x_max, pdata->y_max); + + count += snprintf(buf + count, PAGE_SIZE, "Max Touchs:%d\n", pdata->max_touch_number); + + count += snprintf(buf + count, PAGE_SIZE, "reset gpio:%d,int gpio:%d,irq:%d\n", + pdata->reset_gpio, pdata->irq_gpio, ts_data->irq); + + count += snprintf(buf + count, PAGE_SIZE, "IC ID:0x%02x%02x\n", + ts_data->ic_info.ids.chip_idh, ts_data->ic_info.ids.chip_idl); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_driverinfo_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} + +/* fts_dump_reg interface */ +static ssize_t fts_dumpreg_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + u8 val = 0; + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + fts_read_reg(FTS_REG_POWER_MODE, &val); + count += snprintf(buf + count, PAGE_SIZE, "Power Mode:0x%02x\n", val); + + fts_read_reg(FTS_REG_FW_VER, &val); + count += snprintf(buf + count, PAGE_SIZE, "FW Ver:0x%02x\n", val); + + fts_read_reg(FTS_REG_LIC_VER, &val); + count += snprintf(buf + count, PAGE_SIZE, "LCD Initcode Ver:0x%02x\n", val); + + fts_read_reg(FTS_REG_IDE_PARA_VER_ID, &val); + count += snprintf(buf + count, PAGE_SIZE, "Param Ver:0x%02x\n", val); + + fts_read_reg(FTS_REG_IDE_PARA_STATUS, &val); + count += snprintf(buf + count, PAGE_SIZE, "Param status:0x%02x\n", val); + + fts_read_reg(FTS_REG_VENDOR_ID, &val); + count += snprintf(buf + count, PAGE_SIZE, "Vendor ID:0x%02x\n", val); + + fts_read_reg(FTS_REG_LCD_BUSY_NUM, &val); + count += snprintf(buf + count, PAGE_SIZE, "LCD Busy Number:0x%02x\n", val); + + fts_read_reg(FTS_REG_GESTURE_EN, &val); + count += snprintf(buf + count, PAGE_SIZE, "Gesture Mode:0x%02x\n", val); + + fts_read_reg(FTS_REG_CHARGER_MODE_EN, &val); + count += snprintf(buf + count, PAGE_SIZE, "charge stat:0x%02x\n", val); + + fts_read_reg(FTS_REG_INT_CNT, &val); + count += snprintf(buf + count, PAGE_SIZE, "INT count:0x%02x\n", val); + + fts_read_reg(FTS_REG_FLOW_WORK_CNT, &val); + count += snprintf(buf + count, PAGE_SIZE, "ESD count:0x%02x\n", val); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_dumpreg_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} + +/* fts_dump_reg interface */ +static ssize_t fts_tpbuf_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + int i = 0; + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + count += snprintf(buf + count, PAGE_SIZE, "touch point buffer:\n"); + for (i = 0; i < fts_data->pnt_buf_size; i++) { + count += snprintf(buf + count, PAGE_SIZE, "%02x ", fts_data->point_buf[i]); + } + count += snprintf(buf + count, PAGE_SIZE, "\n"); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_tpbuf_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} + +/* fts_log_level interface */ +static ssize_t fts_log_level_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + count += snprintf(buf + count, PAGE_SIZE, "log level:%d\n", + fts_data->log_level); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_log_level_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int value = 0; + struct input_dev *input_dev = fts_data->input_dev; + + FTS_FUNC_ENTER(); + mutex_lock(&input_dev->mutex); + sscanf(buf, "%d", &value); + FTS_DEBUG("log level:%d->%d", fts_data->log_level, value); + fts_data->log_level = value; + mutex_unlock(&input_dev->mutex); + FTS_FUNC_EXIT(); + + return count; +} + +static ssize_t fts_panel_vendor_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + count += snprintf(buf + count, PAGE_SIZE, "0x%02x\n", + fts_data->pdata->panel_vendor); + mutex_unlock(&input_dev->mutex); + + return count; +} + +/* get the fw version example:cat fw_version */ +static DEVICE_ATTR(fts_fw_version, S_IRUGO | S_IWUSR, fts_tpfwver_show, fts_tpfwver_store); + +/* read and write register(s) +* All data type is **HEX** +* Single Byte: +* read: echo 88 > rw_reg ---read register 0x88 +* write: echo 8807 > rw_reg ---write 0x07 into register 0x88 +* Multi-bytes: +* [0:rw-flag][1-2: reg addr, hex][3-4: length, hex][5-6...n-n+1: write data, hex] +* rw-flag: 0, write; 1, read +* read: echo 10005 > rw_reg ---read reg 0x00-0x05 +* write: echo 000050102030405 > rw_reg ---write reg 0x00-0x05 as 01,02,03,04,05 +* Get result: +* cat rw_reg +*/ +static DEVICE_ATTR(fts_rw_reg, S_IRUGO | S_IWUSR, fts_tprwreg_show, fts_tprwreg_store); +/* upgrade from fw bin file example:echo "*.bin" > fts_upgrade_bin */ +static DEVICE_ATTR(fts_upgrade_bin, S_IRUGO | S_IWUSR, fts_fwupgradebin_show, fts_fwupgradebin_store); +static DEVICE_ATTR(fts_force_upgrade, S_IRUGO | S_IWUSR, fts_fwforceupg_show, fts_fwforceupg_store); +static DEVICE_ATTR(fts_driver_info, S_IRUGO | S_IWUSR, fts_driverinfo_show, fts_driverinfo_store); +static DEVICE_ATTR(fts_dump_reg, S_IRUGO | S_IWUSR, fts_dumpreg_show, fts_dumpreg_store); +static DEVICE_ATTR(fts_hw_reset, S_IRUGO | S_IWUSR, fts_hw_reset_show, fts_hw_reset_store); +static DEVICE_ATTR(fts_irq, S_IRUGO | S_IWUSR, fts_irq_show, fts_irq_store); +static DEVICE_ATTR(fts_boot_mode, S_IRUGO | S_IWUSR, fts_bootmode_show, fts_bootmode_store); +static DEVICE_ATTR(fts_touch_point, S_IRUGO | S_IWUSR, fts_tpbuf_show, fts_tpbuf_store); +static DEVICE_ATTR(fts_log_level, S_IRUGO | S_IWUSR, fts_log_level_show, fts_log_level_store); +static DEVICE_ATTR(panel_vendor, S_IRUGO | S_IWUSR, fts_panel_vendor_show, NULL); + +/* add your attr in here*/ +static struct attribute *fts_attributes[] = { + &dev_attr_fts_fw_version.attr, + &dev_attr_fts_rw_reg.attr, + &dev_attr_fts_dump_reg.attr, + &dev_attr_fts_upgrade_bin.attr, + &dev_attr_fts_force_upgrade.attr, + &dev_attr_fts_driver_info.attr, + &dev_attr_fts_hw_reset.attr, + &dev_attr_fts_irq.attr, + &dev_attr_fts_boot_mode.attr, + &dev_attr_fts_touch_point.attr, + &dev_attr_fts_log_level.attr, + &dev_attr_panel_vendor.attr, + NULL +}; + +static struct attribute_group fts_attribute_group = { + .attrs = fts_attributes +}; + +int fts_create_sysfs(struct fts_ts_data *ts_data) +{ + int ret = 0; + + ret = sysfs_create_group(&ts_data->dev->kobj, &fts_attribute_group); + if (ret) { + FTS_ERROR("[EX]: sysfs_create_group() failed!!"); + sysfs_remove_group(&ts_data->dev->kobj, &fts_attribute_group); + return -ENOMEM; + } else { + FTS_INFO("[EX]: sysfs_create_group() succeeded!!"); + } + + return ret; +} + +int fts_remove_sysfs(struct fts_ts_data *ts_data) +{ + sysfs_remove_group(&ts_data->dev->kobj, &fts_attribute_group); + return 0; +} diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_ex_mode.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_ex_mode.c new file mode 100755 index 0000000000000000000000000000000000000000..bf37704819a2c7700db55b9b770fadfbc36d406e --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_ex_mode.c @@ -0,0 +1,318 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech ftxxxx TouchScreen driver. + * + * Copyright (c) 2012-2019, Focaltech Ltd. 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. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_ex_mode.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-31 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* 2.Private constant and macro definitions using #define +*****************************************************************************/ + +/***************************************************************************** +* 3.Private enumerations, structures and unions using typedef +*****************************************************************************/ +enum _ex_mode { + MODE_GLOVE = 0, + MODE_COVER, + MODE_CHARGER, +}; + +/***************************************************************************** +* 4.Static variables +*****************************************************************************/ + +/***************************************************************************** +* 5.Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* 6.Static function prototypes +*******************************************************************************/ +static int fts_ex_mode_switch(enum _ex_mode mode, u8 value) +{ + int ret = 0; + u8 m_val = 0; + + if (value) + m_val = 0x01; + else + m_val = 0x00; + + switch (mode) { + case MODE_GLOVE: + ret = fts_write_reg(FTS_REG_GLOVE_MODE_EN, m_val); + if (ret < 0) { + FTS_ERROR("MODE_GLOVE switch to %d fail", m_val); + } + break; + case MODE_COVER: + ret = fts_write_reg(FTS_REG_COVER_MODE_EN, m_val); + if (ret < 0) { + FTS_ERROR("MODE_COVER switch to %d fail", m_val); + } + break; + case MODE_CHARGER: + ret = fts_write_reg(FTS_REG_CHARGER_MODE_EN, m_val); + if (ret < 0) { + FTS_ERROR("MODE_CHARGER switch to %d fail", m_val); + } + break; + default: + FTS_ERROR("mode(%d) unsupport", mode); + ret = -EINVAL; + break; + } + + return ret; +} + +static ssize_t fts_glove_mode_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + u8 val = 0; + struct fts_ts_data *ts_data = fts_data; + struct input_dev *input_dev = ts_data->input_dev; + + mutex_lock(&input_dev->mutex); + fts_read_reg(FTS_REG_GLOVE_MODE_EN, &val); + count = snprintf(buf + count, PAGE_SIZE, "Glove Mode:%s\n", + ts_data->glove_mode ? "On" : "Off"); + count += snprintf(buf + count, PAGE_SIZE, "Glove Reg(0xC0):%d\n", val); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_glove_mode_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + struct fts_ts_data *ts_data = fts_data; + + if (FTS_SYSFS_ECHO_ON(buf)) { + if (!ts_data->glove_mode) { + FTS_DEBUG("enter glove mode"); + ret = fts_ex_mode_switch(MODE_GLOVE, ENABLE); + if (ret >= 0) { + ts_data->glove_mode = ENABLE; + } + } + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + if (ts_data->glove_mode) { + FTS_DEBUG("exit glove mode"); + ret = fts_ex_mode_switch(MODE_GLOVE, DISABLE); + if (ret >= 0) { + ts_data->glove_mode = DISABLE; + } + } + } + + FTS_DEBUG("glove mode:%d", ts_data->glove_mode); + return count; +} + + +static ssize_t fts_cover_mode_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + u8 val = 0; + struct fts_ts_data *ts_data = fts_data; + struct input_dev *input_dev = ts_data->input_dev; + + mutex_lock(&input_dev->mutex); + fts_read_reg(FTS_REG_COVER_MODE_EN, &val); + count = snprintf(buf + count, PAGE_SIZE, "Cover Mode:%s\n", + ts_data->cover_mode ? "On" : "Off"); + count += snprintf(buf + count, PAGE_SIZE, "Cover Reg(0xC1):%d\n", val); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_cover_mode_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + struct fts_ts_data *ts_data = fts_data; + + if (FTS_SYSFS_ECHO_ON(buf)) { + if (!ts_data->cover_mode) { + FTS_DEBUG("enter cover mode"); + ret = fts_ex_mode_switch(MODE_COVER, ENABLE); + if (ret >= 0) { + ts_data->cover_mode = ENABLE; + } + } + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + if (ts_data->cover_mode) { + FTS_DEBUG("exit cover mode"); + ret = fts_ex_mode_switch(MODE_COVER, DISABLE); + if (ret >= 0) { + ts_data->cover_mode = DISABLE; + } + } + } + + FTS_DEBUG("cover mode:%d", ts_data->cover_mode); + return count; +} + +static ssize_t fts_charger_mode_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + u8 val = 0; + struct fts_ts_data *ts_data = fts_data; + struct input_dev *input_dev = ts_data->input_dev; + + mutex_lock(&input_dev->mutex); + fts_read_reg(FTS_REG_CHARGER_MODE_EN, &val); + count = snprintf(buf + count, PAGE_SIZE, "Charger Mode:%s\n", + ts_data->charger_mode ? "On" : "Off"); + count += snprintf(buf + count, PAGE_SIZE, "Charger Reg(0x8B):%d\n", val); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_charger_mode_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + struct fts_ts_data *ts_data = fts_data; + + if (FTS_SYSFS_ECHO_ON(buf)) { + if (!ts_data->charger_mode) { + FTS_DEBUG("enter charger mode"); + ret = fts_ex_mode_switch(MODE_CHARGER, ENABLE); + if (ret >= 0) { + ts_data->charger_mode = ENABLE; + } + } + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + if (ts_data->charger_mode) { + FTS_DEBUG("exit charger mode"); + ret = fts_ex_mode_switch(MODE_CHARGER, DISABLE); + if (ret >= 0) { + ts_data->charger_mode = DISABLE; + } + } + } + + FTS_DEBUG("charger mode:%d", ts_data->glove_mode); + return count; +} + + +/* read and write charger mode + * read example: cat fts_glove_mode ---read glove mode + * write example:echo 1 > fts_glove_mode ---write glove mode to 01 + */ +static DEVICE_ATTR(fts_glove_mode, S_IRUGO | S_IWUSR, + fts_glove_mode_show, fts_glove_mode_store); + +static DEVICE_ATTR(glove_mode, S_IRUGO | S_IWUSR, + fts_glove_mode_show, fts_glove_mode_store); + +static DEVICE_ATTR(fts_cover_mode, S_IRUGO | S_IWUSR, + fts_cover_mode_show, fts_cover_mode_store); + +static DEVICE_ATTR(fts_charger_mode, S_IRUGO | S_IWUSR, + fts_charger_mode_show, fts_charger_mode_store); + +static struct attribute *fts_touch_mode_attrs[] = { + &dev_attr_fts_glove_mode.attr, + &dev_attr_fts_cover_mode.attr, + &dev_attr_fts_charger_mode.attr, + NULL, +}; + +static struct attribute_group fts_touch_mode_group = { + .attrs = fts_touch_mode_attrs, +}; + +int fts_ex_mode_recovery(struct fts_ts_data *ts_data) +{ + if (ts_data->glove_mode) { + fts_ex_mode_switch(MODE_GLOVE, ENABLE); + } + + if (ts_data->cover_mode) { + fts_ex_mode_switch(MODE_COVER, ENABLE); + } + + if (ts_data->charger_mode) { + fts_ex_mode_switch(MODE_CHARGER, ENABLE); + } + + return 0; +} + +int fts_ex_mode_init(struct fts_ts_data *ts_data) +{ + int ret = 0; + + ts_data->glove_mode = DISABLE; + ts_data->cover_mode = DISABLE; + ts_data->charger_mode = DISABLE; + + ret = sysfs_create_group(&ts_data->dev->kobj, &fts_touch_mode_group); + if (ret < 0) { + FTS_ERROR("create sysfs(ex_mode) fail"); + sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group); + return ret; + } else { + FTS_DEBUG("create sysfs(ex_mode) succeedfully"); + } + + if (ts_data->tct_touch_dev) { + ret = device_create_file(ts_data->tct_touch_dev, &dev_attr_glove_mode); + if (ret < 0) + FTS_DEBUG("Failed to create file glove_mode!"); + } else + FTS_DEBUG("no tct_touch_dev!"); + + return 0; +} + +int fts_ex_mode_exit(struct fts_ts_data *ts_data) +{ + sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group); + return 0; +} diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash.c new file mode 100755 index 0000000000000000000000000000000000000000..8a6bbad147224d3a857c6248ac076fc5d9f28dc5 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash.c @@ -0,0 +1,2026 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2012-2019, Focaltech Ltd. 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. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_flash.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" +#include "focaltech_flash.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define FTS_FW_REQUEST_SUPPORT 0 // MODIFIED by hongwei.tian, 2019-11-27,BUG-8596641 +/* Example: focaltech_ts_fw_tianma.bin */ +#define FTS_FW_NAME_PREX_WITH_REQUEST "focaltech_ts_fw_" + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +u8 fw_file[] = { +#include FTS_UPGRADE_FW_FILE +}; + +u8 fw_file2[] = { +#include FTS_UPGRADE_FW2_FILE +}; + +u8 fw_file3[] = { +#include FTS_UPGRADE_FW3_FILE +}; + +struct upgrade_module module_list[] = { + {FTS_MODULE_ID, FTS_MODULE_NAME, fw_file, sizeof(fw_file)}, + {FTS_MODULE2_ID, FTS_MODULE2_NAME, fw_file2, sizeof(fw_file2)}, + {FTS_MODULE3_ID, FTS_MODULE3_NAME, fw_file3, sizeof(fw_file3)}, +}; + +struct upgrade_func *upgrade_func_list[] = { + &upgrade_func_ft8716, +}; + +struct fts_upgrade *fwupgrade; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +static bool fts_fwupg_check_state( + struct fts_upgrade *upg, enum FW_STATUS rstate); + +/************************************************************************ +* Name: fts_fwupg_get_boot_state +* Brief: read boot id(rom/pram/bootloader), confirm boot environment +* Input: +* Output: +* Return: return 0 if success, otherwise return error code +***********************************************************************/ +static int fts_fwupg_get_boot_state( + struct fts_upgrade *upg, + enum FW_STATUS *fw_sts) +{ + int ret = 0; + u8 cmd[4] = { 0 }; + u32 cmd_len = 0; + u8 val[2] = { 0 }; + struct ft_chip_t *ids = NULL; + + FTS_INFO("**********read boot id**********"); + if ((!upg) || (!upg->func) || (!upg->ts_data) || (!fw_sts)) { + FTS_ERROR("upg/func/ts_data/fw_sts is null"); + return -EINVAL; + } + + if (upg->func->hid_supported) + fts_hid2std(); + + cmd[0] = FTS_CMD_START1; + cmd[1] = FTS_CMD_START2; + ret = fts_write(cmd, 2); + if (ret < 0) { + FTS_ERROR("write 55 aa cmd fail"); + return ret; + } + + msleep(FTS_CMD_START_DELAY); + cmd[0] = FTS_CMD_READ_ID; + cmd[1] = cmd[2] = cmd[3] = 0x00; + if (fts_data->ic_info.is_incell) + cmd_len = FTS_CMD_READ_ID_LEN_INCELL; + else + cmd_len = FTS_CMD_READ_ID_LEN; + ret = fts_read(cmd, cmd_len, val, 2); + if (ret < 0) { + FTS_ERROR("write 90 cmd fail"); + return ret; + } + FTS_INFO("read boot id:0x%02x%02x", val[0], val[1]); + + ids = &upg->ts_data->ic_info.ids; + if ((val[0] == ids->rom_idh) && (val[1] == ids->rom_idl)) { + FTS_INFO("tp run in romboot"); + *fw_sts = FTS_RUN_IN_ROM; + } else if ((val[0] == ids->pb_idh) && (val[1] == ids->pb_idl)) { + FTS_INFO("tp run in pramboot"); + *fw_sts = FTS_RUN_IN_PRAM; + } else if ((val[0] == ids->bl_idh) && (val[1] == ids->bl_idl)) { + FTS_INFO("tp run in bootloader"); + *fw_sts = FTS_RUN_IN_BOOTLOADER; + } + + return 0; +} + +static int fts_fwupg_reset_to_boot(struct fts_upgrade *upg) +{ + int ret = 0; + u8 reg = FTS_REG_UPGRADE; + + FTS_INFO("send 0xAA and 0x55 to FW, reset to boot environment"); + if (upg && upg->func && upg->func->is_reset_register_BC) { + reg = FTS_REG_UPGRADE2; + } + + ret = fts_write_reg(reg, FTS_UPGRADE_AA); + if (ret < 0) { + FTS_ERROR("write FC=0xAA fail"); + return ret; + } + msleep(FTS_DELAY_UPGRADE_AA); + + ret = fts_write_reg(reg, FTS_UPGRADE_55); + if (ret < 0) { + FTS_ERROR("write FC=0x55 fail"); + return ret; + } + + msleep(FTS_DELAY_UPGRADE_RESET); + return 0; +} + +/************************************************************************ +* Name: fts_fwupg_reset_to_romboot +* Brief: reset to romboot, to load pramboot +* Input: +* Output: +* Return: return 0 if success, otherwise return error code +***********************************************************************/ +static int fts_fwupg_reset_to_romboot(struct fts_upgrade *upg) +{ + int ret = 0; + int i = 0; + u8 cmd = FTS_CMD_RESET; + enum FW_STATUS state = FTS_RUN_IN_ERROR; + + ret = fts_write(&cmd, 1); + if (ret < 0) { + FTS_ERROR("pram/rom/bootloader reset cmd write fail"); + return ret; + } + mdelay(10); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + ret = fts_fwupg_get_boot_state(upg, &state); + if (FTS_RUN_IN_ROM == state) + break; + mdelay(5); + } + if (i >= FTS_UPGRADE_LOOP) { + FTS_ERROR("reset to romboot fail"); + return -EIO; + } + + return 0; +} + +u16 fts_crc16_calc_host(u8 *pbuf, u16 length) +{ + u16 ecc = 0; + u16 i = 0; + u16 j = 0; + + for ( i = 0; i < length; i += 2 ) { + ecc ^= ((pbuf[i] << 8) | (pbuf[i + 1])); + for (j = 0; j < 16; j ++) { + if (ecc & 0x01) + ecc = (u16)((ecc >> 1) ^ AL2_FCS_COEF); + else + ecc >>= 1; + } + } + + return ecc; +} + +static u16 fts_pram_ecc_calc_host(u8 *pbuf, u16 length) +{ + return fts_crc16_calc_host(pbuf, length); +} + +static int fts_pram_ecc_cal_algo( + struct fts_upgrade *upg, + u32 start_addr, + u32 ecc_length) +{ + int ret = 0; + int i = 0; + int ecc = 0; + u8 val[2] = { 0 }; + u8 tmp = 0; + u8 cmd[FTS_ROMBOOT_CMD_ECC_NEW_LEN] = { 0 }; + + FTS_INFO("read out pramboot checksum"); + if ((!upg) || (!upg->func)) { + FTS_ERROR("upg/func is null"); + return -EINVAL; + } + + cmd[0] = FTS_ROMBOOT_CMD_ECC; + cmd[1] = BYTE_OFF_16(start_addr); + cmd[2] = BYTE_OFF_8(start_addr); + cmd[3] = BYTE_OFF_0(start_addr); + cmd[4] = BYTE_OFF_16(ecc_length); + cmd[5] = BYTE_OFF_8(ecc_length); + cmd[6] = BYTE_OFF_0(ecc_length); + ret = fts_write(cmd, FTS_ROMBOOT_CMD_ECC_NEW_LEN); + if (ret < 0) { + FTS_ERROR("write pramboot ecc cal cmd fail"); + return ret; + } + + cmd[0] = FTS_ROMBOOT_CMD_ECC_FINISH; + for (i = 0; i < FTS_ECC_FINISH_TIMEOUT; i++) { + msleep(1); + ret = fts_read(cmd, 1, val, 1); + if (ret < 0) { + FTS_ERROR("ecc_finish read cmd fail"); + return ret; + } + if (upg->func->new_return_value_from_ic) { + tmp = FTS_ROMBOOT_CMD_ECC_FINISH_OK_A5; + } else { + tmp = FTS_ROMBOOT_CMD_ECC_FINISH_OK_00; + } + if (tmp == val[0]) + break; + } + if (i >= 100) { + FTS_ERROR("wait ecc finish fail"); + return -EIO; + } + + cmd[0] = FTS_ROMBOOT_CMD_ECC_READ; + ret = fts_read(cmd, 1, val, 2); + if (ret < 0) { + FTS_ERROR("read pramboot ecc fail"); + return ret; + } + + ecc = ((u16)(val[0] << 8) + val[1]) & 0x0000FFFF; + return ecc; +} + +static int fts_pram_ecc_cal_xor(void) +{ + int ret = 0; + u8 reg_val = 0; + + FTS_INFO("read out pramboot checksum"); + + ret = fts_read_reg(FTS_ROMBOOT_CMD_ECC, ®_val); + if (ret < 0) { + FTS_ERROR("read pramboot ecc fail"); + return ret; + } + + return (int)reg_val; +} + +static int fts_pram_ecc_cal(struct fts_upgrade *upg, u32 saddr, u32 len) +{ + if ((!upg) || (!upg->func)) { + FTS_ERROR("upg/func is null"); + return -EINVAL; + } + + if (ECC_CHECK_MODE_CRC16 == upg->func->pram_ecc_check_mode) { + return fts_pram_ecc_cal_algo(upg, saddr, len); + } else { + return fts_pram_ecc_cal_xor(); + } +} + +static int fts_pram_write_buf(struct fts_upgrade *upg, u8 *buf, u32 len) +{ + int ret = 0; + u32 i = 0; + u32 j = 0; + u32 offset = 0; + u32 remainder = 0; + u32 packet_number; + u32 packet_len = 0; + u8 packet_buf[FTS_FLASH_PACKET_LENGTH + FTS_CMD_WRITE_LEN] = { 0 }; + u8 ecc_tmp = 0; + int ecc_in_host = 0; + + FTS_INFO("write pramboot to pram"); + if ((!upg) || (!upg->func) || !buf) { + FTS_ERROR("upg/func/buf is null"); + return -EINVAL; + } + + FTS_INFO("pramboot len=%d", len); + if ((len < PRAMBOOT_MIN_SIZE) || (len > PRAMBOOT_MAX_SIZE)) { + FTS_ERROR("pramboot length(%d) fail", len); + return -EINVAL; + } + + packet_number = len / FTS_FLASH_PACKET_LENGTH; + remainder = len % FTS_FLASH_PACKET_LENGTH; + if (remainder > 0) + packet_number++; + packet_len = FTS_FLASH_PACKET_LENGTH; + + packet_buf[0] = FTS_ROMBOOT_CMD_WRITE; + for (i = 0; i < packet_number; i++) { + offset = i * FTS_FLASH_PACKET_LENGTH; + packet_buf[1] = BYTE_OFF_16(offset); + packet_buf[2] = BYTE_OFF_8(offset); + packet_buf[3] = BYTE_OFF_0(offset); + + /* last packet */ + if ((i == (packet_number - 1)) && remainder) + packet_len = remainder; + + packet_buf[4] = BYTE_OFF_8(packet_len); + packet_buf[5] = BYTE_OFF_0(packet_len); + + for (j = 0; j < packet_len; j++) { + packet_buf[FTS_CMD_WRITE_LEN + j] = buf[offset + j]; + if (ECC_CHECK_MODE_XOR == upg->func->pram_ecc_check_mode) { + ecc_tmp ^= packet_buf[FTS_CMD_WRITE_LEN + j]; + } + } + + ret = fts_write(packet_buf, packet_len + FTS_CMD_WRITE_LEN); + if (ret < 0) { + FTS_ERROR("pramboot write data(%d) fail", i); + return ret; + } + } + + if (ECC_CHECK_MODE_CRC16 == upg->func->pram_ecc_check_mode) { + ecc_in_host = (int)fts_pram_ecc_calc_host(buf, len); + } else { + ecc_in_host = (int)ecc_tmp; + } + + return ecc_in_host; +} + +static int fts_pram_start(void) +{ + u8 cmd = FTS_ROMBOOT_CMD_START_APP; + int ret = 0; + + FTS_INFO("remap to start pramboot"); + + ret = fts_write(&cmd, 1); + if (ret < 0) { + FTS_ERROR("write start pram cmd fail"); + return ret; + } + msleep(FTS_DELAY_PRAMBOOT_START); + + return 0; +} + +static int fts_pram_write_remap(struct fts_upgrade *upg) +{ + int ret = 0; + int ecc_in_host = 0; + int ecc_in_tp = 0; + u8 *pb_buf = NULL; + u32 pb_len = 0; + + FTS_INFO("write pram and remap"); + if (!upg || !upg->func || !upg->func->pramboot) { + FTS_ERROR("upg/func/pramboot is null"); + return -EINVAL; + } + + if (upg->func->pb_length < FTS_MIN_LEN) { + FTS_ERROR("pramboot length(%d) fail", upg->func->pb_length); + return -EINVAL; + } + + pb_buf = upg->func->pramboot; + pb_len = upg->func->pb_length; + + /* write pramboot to pram */ + ecc_in_host = fts_pram_write_buf(upg, pb_buf, pb_len); + if (ecc_in_host < 0) { + FTS_ERROR( "write pramboot fail"); + return ecc_in_host; + } + + /* read out checksum */ + ecc_in_tp = fts_pram_ecc_cal(upg, 0, pb_len); + if (ecc_in_tp < 0) { + FTS_ERROR( "read pramboot ecc fail"); + return ecc_in_tp; + } + + FTS_INFO("pram ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host); + /* pramboot checksum != fw checksum, upgrade fail */ + if (ecc_in_host != ecc_in_tp) { + FTS_ERROR("pramboot ecc check fail"); + return -EIO; + } + + /*start pram*/ + ret = fts_pram_start(); + if (ret < 0) { + FTS_ERROR("pram start fail"); + return ret; + } + + return 0; +} + +static int fts_pram_init(void) +{ + int ret = 0; + u8 reg_val = 0; + u8 wbuf[3] = { 0 }; + + FTS_INFO("pramboot initialization"); + + /* read flash ID */ + wbuf[0] = FTS_CMD_FLASH_TYPE; + ret = fts_read(wbuf, 1, ®_val, 1); + if (ret < 0) { + FTS_ERROR("read flash type fail"); + return ret; + } + + /* set flash clk */ + wbuf[0] = FTS_CMD_FLASH_TYPE; + wbuf[1] = reg_val; + wbuf[2] = 0x00; + ret = fts_write(wbuf, 3); + if (ret < 0) { + FTS_ERROR("write flash type fail"); + return ret; + } + + return 0; +} + +static int fts_pram_write_init(struct fts_upgrade *upg) +{ + int ret = 0; + bool state = 0; + enum FW_STATUS status = FTS_RUN_IN_ERROR; + + FTS_INFO("**********pram write and init**********"); + if ((NULL == upg) || (NULL == upg->func)) { + FTS_ERROR("upgrade/func is null"); + return -EINVAL; + } + + if (!upg->func->pramboot_supported) { + FTS_ERROR("ic not support pram"); + return -EINVAL; + } + + FTS_DEBUG("check whether tp is in romboot or not "); + /* need reset to romboot when non-romboot state */ + ret = fts_fwupg_get_boot_state(upg, &status); + if (status != FTS_RUN_IN_ROM) { + if (FTS_RUN_IN_PRAM == status) { + FTS_INFO("tp is in pramboot, need send reset cmd before upgrade"); + ret = fts_pram_init(); + if (ret < 0) { + FTS_ERROR("pramboot(before) init fail"); + return ret; + } + } + + FTS_INFO("tp isn't in romboot, need send reset to romboot"); + ret = fts_fwupg_reset_to_romboot(upg); + if (ret < 0) { + FTS_ERROR("reset to romboot fail"); + return ret; + } + } + + /* check the length of the pramboot */ + ret = fts_pram_write_remap(upg); + if (ret < 0) { + FTS_ERROR("pram write fail, ret=%d", ret); + return ret; + } + + FTS_DEBUG("after write pramboot, confirm run in pramboot"); + state = fts_fwupg_check_state(upg, FTS_RUN_IN_PRAM); + if (!state) { + FTS_ERROR("not in pramboot"); + return -EIO; + } + + ret = fts_pram_init(); + if (ret < 0) { + FTS_ERROR("pramboot init fail"); + return ret; + } + + return 0; +} + +static bool fts_fwupg_check_fw_valid(void) +{ + int ret = 0; + + ret = fts_wait_tp_to_valid(); + if (ret < 0) { + FTS_INFO("tp fw invaild"); + return false; + } + + FTS_INFO("tp fw vaild"); + return true; +} + +/************************************************************************ +* Name: fts_fwupg_check_state +* Brief: confirm tp run in which mode: romboot/pramboot/bootloader +* Input: +* Output: +* Return: return true if state is match, otherwise return false +***********************************************************************/ +static bool fts_fwupg_check_state( + struct fts_upgrade *upg, enum FW_STATUS rstate) +{ + int ret = 0; + int i = 0; + enum FW_STATUS cstate = FTS_RUN_IN_ERROR; + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + ret = fts_fwupg_get_boot_state(upg, &cstate); + /* FTS_DEBUG("fw state=%d, retries=%d", cstate, i); */ + if (cstate == rstate) + return true; + msleep(FTS_DELAY_READ_ID); + } + + return false; +} + +/************************************************************************ +* Name: fts_fwupg_reset_in_boot +* Brief: RST CMD(07), reset to romboot(bootloader) in boot environment +* Input: +* Output: +* Return: return 0 if success, otherwise return error code +***********************************************************************/ +int fts_fwupg_reset_in_boot(void) +{ + int ret = 0; + u8 cmd = FTS_CMD_RESET; + + FTS_INFO("reset in boot environment"); + ret = fts_write(&cmd, 1); + if (ret < 0) { + FTS_ERROR("pram/rom/bootloader reset cmd write fail"); + return ret; + } + + msleep(FTS_DELAY_UPGRADE_RESET); + return 0; +} + +/************************************************************************ +* Name: fts_fwupg_enter_into_boot +* Brief: enter into boot environment, ready for upgrade +* Input: +* Output: +* Return: return 0 if success, otherwise return error code +***********************************************************************/ +int fts_fwupg_enter_into_boot(void) +{ + int ret = 0; + bool fwvalid = false; + bool state = false; + struct fts_upgrade *upg = fwupgrade; + + FTS_INFO("***********enter into pramboot/bootloader***********"); + if ((!upg) || (NULL == upg->func)) { + FTS_ERROR("upgrade/func is null"); + return -EINVAL; + } + + fwvalid = fts_fwupg_check_fw_valid(); + if (fwvalid) { + ret = fts_fwupg_reset_to_boot(upg); + if (ret < 0) { + FTS_ERROR("enter into romboot/bootloader fail"); + return ret; + } + } else if (upg->func->read_boot_id_need_reset) { + ret = fts_fwupg_reset_in_boot(); + if (ret < 0) { + FTS_ERROR("reset before read boot id when fw invalid fail"); + return ret; + } + } + + if (upg->func->pramboot_supported) { + FTS_INFO("pram supported, write pramboot and init"); + /* pramboot */ + ret = fts_pram_write_init(upg); + if (ret < 0) { + FTS_ERROR("pram write_init fail"); + return ret; + } + } else { + FTS_DEBUG("pram not supported, confirm in bootloader"); + /* bootloader */ + state = fts_fwupg_check_state(upg, FTS_RUN_IN_BOOTLOADER); + if (!state) { + FTS_ERROR("fw not in bootloader, fail"); + return -EIO; + } + } + + return 0; +} + +/************************************************************************ + * Name: fts_fwupg_check_flash_status + * Brief: read status from tp + * Input: flash_status: correct value from tp + * retries: read retry times + * retries_delay: retry delay + * Output: + * Return: return true if flash status check pass, otherwise return false +***********************************************************************/ +static bool fts_fwupg_check_flash_status( + u16 flash_status, + int retries, + int retries_delay) +{ + int ret = 0; + int i = 0; + u8 cmd = 0; + u8 val[FTS_CMD_FLASH_STATUS_LEN] = { 0 }; + u16 read_status = 0; + + for (i = 0; i < retries; i++) { + cmd = FTS_CMD_FLASH_STATUS; + ret = fts_read(&cmd , 1, val, FTS_CMD_FLASH_STATUS_LEN); + read_status = (((u16)val[0]) << 8) + val[1]; + if (flash_status == read_status) { + /* FTS_DEBUG("[UPGRADE]flash status ok"); */ + return true; + } + /* FTS_DEBUG("flash status fail,ok:%04x read:%04x, retries:%d", flash_status, read_status, i); */ + msleep(retries_delay); + } + + return false; +} + +/************************************************************************ + * Name: fts_fwupg_erase + * Brief: erase flash area + * Input: delay - delay after erase + * Output: + * Return: return 0 if success, otherwise return error code + ***********************************************************************/ +int fts_fwupg_erase(u32 delay) +{ + int ret = 0; + u8 cmd = 0; + bool flag = false; + + FTS_INFO("**********erase now**********"); + + /*send to erase flash*/ + cmd = FTS_CMD_ERASE_APP; + ret = fts_write(&cmd, 1); + if (ret < 0) { + FTS_ERROR("erase cmd fail"); + return ret; + } + msleep(delay); + + /* read status 0xF0AA: success */ + flag = fts_fwupg_check_flash_status(FTS_CMD_FLASH_STATUS_ERASE_OK, + FTS_RETRIES_REASE, + FTS_RETRIES_DELAY_REASE); + if (!flag) { + FTS_ERROR("ecc flash status check fail"); + return -EIO; + } + + return 0; +} + +/************************************************************************ + * Name: fts_fwupg_ecc_cal + * Brief: calculate and get ecc from tp + * Input: saddr - start address need calculate ecc + * len - length need calculate ecc + * Output: + * Return: return data ecc of tp if success, otherwise return error code + ***********************************************************************/ +int fts_fwupg_ecc_cal(u32 saddr, u32 len) +{ + int ret = 0; + u32 i = 0; + u8 wbuf[FTS_CMD_ECC_CAL_LEN] = { 0 }; + u8 val[FTS_CMD_FLASH_STATUS_LEN] = { 0 }; + int ecc = 0; + int ecc_len = 0; + u32 packet_num = 0; + u32 packet_len = 0; + u32 remainder = 0; + u32 addr = 0; + u32 offset = 0; + struct fts_upgrade *upg = fwupgrade; + + FTS_INFO( "**********read out checksum**********"); + if ((NULL == upg) || (NULL == upg->func)) { + FTS_ERROR("upgrade/func is null"); + return -EINVAL; + } + + /* check sum init */ + wbuf[0] = FTS_CMD_ECC_INIT; + ret = fts_write(wbuf, 1); + if (ret < 0) { + FTS_ERROR("ecc init cmd write fail"); + return ret; + } + + packet_num = len / FTS_MAX_LEN_ECC_CALC; + remainder = len % FTS_MAX_LEN_ECC_CALC; + if (remainder) + packet_num++; + packet_len = FTS_MAX_LEN_ECC_CALC; + FTS_INFO("ecc calc num:%d, remainder:%d", packet_num, remainder); + + /* send commond to start checksum */ + wbuf[0] = FTS_CMD_ECC_CAL; + for (i = 0; i < packet_num; i++) { + offset = FTS_MAX_LEN_ECC_CALC * i; + addr = saddr + offset; + wbuf[1] = BYTE_OFF_16(addr); + wbuf[2] = BYTE_OFF_8(addr); + wbuf[3] = BYTE_OFF_0(addr); + + if ((i == (packet_num - 1)) && remainder) + packet_len = remainder; + wbuf[4] = BYTE_OFF_8(packet_len); + wbuf[5] = BYTE_OFF_0(packet_len); + + FTS_DEBUG("ecc calc startaddr:0x%04x, len:%d", addr, packet_len); + ret = fts_write(wbuf, FTS_CMD_ECC_CAL_LEN); + if (ret < 0) { + FTS_ERROR("ecc calc cmd write fail"); + return ret; + } + + msleep(packet_len / 256); + + /* read status if check sum is finished */ + ret = fts_fwupg_check_flash_status(FTS_CMD_FLASH_STATUS_ECC_OK, + FTS_RETRIES_ECC_CAL, + FTS_RETRIES_DELAY_ECC_CAL); + if (ret < 0) { + FTS_ERROR("ecc flash status read fail"); + return ret; + } + } + + ecc_len = 1; + if (ECC_CHECK_MODE_CRC16 == upg->func->fw_ecc_check_mode) { + ecc_len = 2; + } + + /* read out check sum */ + wbuf[0] = FTS_CMD_ECC_READ; + ret = fts_read(wbuf, 1, val, ecc_len); + if (ret < 0) { + FTS_ERROR( "ecc read cmd write fail"); + return ret; + } + + if (ECC_CHECK_MODE_CRC16 == upg->func->fw_ecc_check_mode) { + ecc = (int)((u16)(val[0] << 8) + val[1]); + } else { + ecc = (int)val[0]; + } + + return ecc; +} + +/************************************************************************ + * Name: fts_flash_write_buf + * Brief: write buf data to flash address + * Input: saddr - start address data write to flash + * buf - data buffer + * len - data length + * delay - delay after write + * Output: + * Return: return data ecc of host if success, otherwise return error code + ***********************************************************************/ +int fts_flash_write_buf( + u32 saddr, + u8 *buf, + u32 len, + u32 delay) +{ + int ret = 0; + u32 i = 0; + u32 j = 0; + u32 packet_number = 0; + u32 packet_len = 0; + u32 addr = 0; + u32 offset = 0; + u32 remainder = 0; + u8 packet_buf[FTS_FLASH_PACKET_LENGTH + FTS_CMD_WRITE_LEN] = { 0 }; + u8 ecc_tmp = 0; + int ecc_in_host = 0; + u8 cmd = 0; + u8 val[FTS_CMD_FLASH_STATUS_LEN] = { 0 }; + u16 read_status = 0; + u16 wr_ok = 0; + struct fts_upgrade *upg = fwupgrade; + + FTS_INFO( "**********write data to flash**********"); + if ((!upg) || (!upg->func || !buf || !len)) { + FTS_ERROR("upgrade/func/buf/len is invalid"); + return -EINVAL; + } + + FTS_INFO("data buf start addr=0x%x, len=0x%x", saddr, len); + packet_number = len / FTS_FLASH_PACKET_LENGTH; + remainder = len % FTS_FLASH_PACKET_LENGTH; + if (remainder > 0) + packet_number++; + packet_len = FTS_FLASH_PACKET_LENGTH; + FTS_INFO("write data, num:%d remainder:%d", packet_number, remainder); + + packet_buf[0] = FTS_CMD_WRITE; + for (i = 0; i < packet_number; i++) { + offset = i * FTS_FLASH_PACKET_LENGTH; + addr = saddr + offset; + packet_buf[1] = BYTE_OFF_16(addr); + packet_buf[2] = BYTE_OFF_8(addr); + packet_buf[3] = BYTE_OFF_0(addr); + + /* last packet */ + if ((i == (packet_number - 1)) && remainder) + packet_len = remainder; + + packet_buf[4] = BYTE_OFF_8(packet_len); + packet_buf[5] = BYTE_OFF_0(packet_len); + + for (j = 0; j < packet_len; j++) { + packet_buf[FTS_CMD_WRITE_LEN + j] = buf[offset + j]; + ecc_tmp ^= packet_buf[FTS_CMD_WRITE_LEN + j]; + } + + ret = fts_write(packet_buf, packet_len + FTS_CMD_WRITE_LEN); + if (ret < 0) { + FTS_ERROR("app write fail"); + return ret; + } + mdelay(delay); + + /* read status */ + wr_ok = FTS_CMD_FLASH_STATUS_WRITE_OK + addr / packet_len; + for (j = 0; j < FTS_RETRIES_WRITE; j++) { + cmd = FTS_CMD_FLASH_STATUS; + ret = fts_read(&cmd , 1, val, FTS_CMD_FLASH_STATUS_LEN); + read_status = (((u16)val[0]) << 8) + val[1]; + /* FTS_INFO("%x %x", wr_ok, read_status); */ + if (wr_ok == read_status) { + break; + } + mdelay(FTS_RETRIES_DELAY_WRITE); + } + } + + ecc_in_host = (int)ecc_tmp; + if (ECC_CHECK_MODE_CRC16 == upg->func->fw_ecc_check_mode) { + ecc_in_host = (int)fts_crc16_calc_host(buf, len); + } + + return ecc_in_host; +} + +/************************************************************************ + * Name: fts_flash_read_buf + * Brief: read data from flash + * Input: saddr - start address data write to flash + * buf - buffer to store data read from flash + * len - read length + * Output: + * Return: return 0 if success, otherwise return error code + * + * Warning: can't call this function directly, need call in boot environment + ***********************************************************************/ +int fts_flash_read_buf(u32 saddr, u8 *buf, u32 len) +{ + int ret = 0; + u32 i = 0; + u32 packet_number = 0; + u32 packet_len = 0; + u32 addr = 0; + u32 offset = 0; + u32 remainder = 0; + u8 wbuf[FTS_CMD_READ_LEN] = { 0 }; + + if ((NULL == buf) || (0 == len)) { + FTS_ERROR("buf is NULL or len is 0"); + return -EINVAL; + } + + packet_number = len / FTS_FLASH_PACKET_LENGTH; + remainder = len % FTS_FLASH_PACKET_LENGTH; + if (remainder > 0) { + packet_number++; + } + packet_len = FTS_FLASH_PACKET_LENGTH; + FTS_INFO("read packet_number:%d, remainder:%d", packet_number, remainder); + + wbuf[0] = FTS_CMD_READ; + for (i = 0; i < packet_number; i++) { + offset = i * FTS_FLASH_PACKET_LENGTH; + addr = saddr + offset; + wbuf[1] = BYTE_OFF_16(addr); + wbuf[2] = BYTE_OFF_8(addr); + wbuf[3] = BYTE_OFF_0(addr); + + /* last packet */ + if ((i == (packet_number - 1)) && remainder) + packet_len = remainder; + + ret = fts_write(wbuf, FTS_CMD_READ_LEN); + if (ret < 0) { + FTS_ERROR("pram/bootloader write 03 command fail"); + return ret; + } + + msleep(FTS_CMD_READ_DELAY); /* must wait, otherwise read wrong data */ + ret = fts_read(NULL, 0, buf + offset, packet_len); + if (ret < 0) { + FTS_ERROR("pram/bootloader read 03 command fail"); + return ret; + } + } + + return 0; +} + +/************************************************************************ + * Name: fts_flash_read + * Brief: + * Input: addr - address of flash + * len - length of read + * Output: buf - data read from flash + * Return: return 0 if success, otherwise return error code + ***********************************************************************/ +int fts_flash_read(u32 addr, u8 *buf, u32 len) +{ + int ret = 0; + + FTS_INFO("***********read flash***********"); + if ((NULL == buf) || (0 == len)) { + FTS_ERROR("buf is NULL or len is 0"); + return -EINVAL; + } + + ret = fts_fwupg_enter_into_boot(); + if (ret < 0) { + FTS_ERROR("enter into pramboot/bootloader fail"); + goto read_flash_err; + } + + ret = fts_flash_read_buf(addr, buf, len); + if (ret < 0) { + FTS_ERROR("read flash fail"); + goto read_flash_err; + } + +read_flash_err: + /* reset to normal boot */ + ret = fts_fwupg_reset_in_boot(); + if (ret < 0) { + FTS_ERROR("reset to normal boot fail"); + } + return ret; +} + +int fts_read_file(char *file_name, u8 **file_buf) +{ + int ret = 0; + char file_path[FILE_NAME_LENGTH] = { 0 }; + struct file *filp = NULL; + struct inode *inode; + mm_segment_t old_fs; + loff_t pos; + loff_t file_len = 0; + + if ((NULL == file_name) || (NULL == file_buf)) { + FTS_ERROR("filename/filebuf is NULL"); + return -EINVAL; + } + + snprintf(file_path, FILE_NAME_LENGTH, "%s%s", FTS_FW_BIN_FILEPATH, file_name); + filp = filp_open(file_path, O_RDONLY, 0); + if (IS_ERR(filp)) { + FTS_ERROR("open %s file fail", file_path); + return -ENOENT; + } + +#if 1 + inode = filp->f_inode; +#else + /* reserved for linux earlier verion */ + inode = filp->f_dentry->d_inode; +#endif + + file_len = inode->i_size; + *file_buf = (u8 *)vmalloc(file_len); + if (NULL == *file_buf) { + FTS_ERROR("file buf malloc fail"); + filp_close(filp, NULL); + return -ENOMEM; + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + ret = vfs_read(filp, *file_buf, file_len , &pos); + if (ret < 0) + FTS_ERROR("read file fail"); + FTS_INFO("file len:%d read len:%d pos:%d", (u32)file_len, ret, (u32)pos); + filp_close(filp, NULL); + set_fs(old_fs); + + return ret; +} + +int fts_upgrade_bin(char *fw_name, bool force) +{ + int ret = 0; + u32 fw_file_len = 0; + u8 *fw_file_buf = NULL; + struct fts_upgrade *upg = fwupgrade; + + FTS_INFO("start upgrade with fw bin"); + if ((!upg) || (!upg->func) || !upg->ts_data) { + FTS_ERROR("upgrade/func/ts_data is null"); + return -EINVAL; + } + + upg->ts_data->fw_loading = 1; + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + + ret = fts_read_file(fw_name, &fw_file_buf); + if ((ret < 0) || (ret < FTS_MIN_LEN) || (ret > FTS_MAX_LEN_FILE)) { + FTS_ERROR("read fw bin file(sdcard) fail, len:%d", fw_file_len); + goto err_bin; + } + + fw_file_len = ret; + FTS_INFO("fw bin file len:%d", fw_file_len); + if (force) { + if (upg->func->force_upgrade) { + ret = upg->func->force_upgrade(fw_file_buf, fw_file_len); + } else { + FTS_INFO("force_upgrade function is null, no upgrade"); + goto err_bin; + } + } else { +#if FTS_AUTO_LIC_UPGRADE_EN + if (upg->func->lic_upgrade) { + ret = upg->func->lic_upgrade(fw_file_buf, fw_file_len); + } else { + FTS_INFO("lic_upgrade function is null, no upgrade"); + } +#endif + if (upg->func->upgrade) { + ret = upg->func->upgrade(fw_file_buf, fw_file_len); + } else { + FTS_INFO("upgrade function is null, no upgrade"); + } + } + + if (ret < 0) { + FTS_ERROR("upgrade fw bin failed"); + fts_fwupg_reset_in_boot(); + goto err_bin; + } + + FTS_INFO("upgrade fw bin success"); + ret = 0; + +err_bin: +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + upg->ts_data->fw_loading = 0; + + if (fw_file_buf) { + vfree(fw_file_buf); + fw_file_buf = NULL; + } + return ret; +} + +int fts_enter_test_environment(bool test_state) +{ + return 0; +} +#if FTS_AUTO_LIC_UPGRADE_EN +static int fts_lic_get_vid_in_tp(u16 *vid) +{ + int ret = 0; + u8 val[2] = { 0 }; + + if (NULL == vid) { + FTS_ERROR("vid is NULL"); + return -EINVAL; + } + + ret = fts_read_reg(FTS_REG_VENDOR_ID, &val[0]); + if (fts_data->ic_info.is_incell) + ret = fts_read_reg(FTS_REG_MODULE_ID, &val[1]); + if (ret < 0) { + FTS_ERROR("read vid from tp fail"); + return ret; + } + + *vid = *(u16 *)val; + return 0; +} + +static int fts_lic_get_vid_in_host(struct fts_upgrade *upg, u16 *vid) +{ + u8 val[2] = { 0 }; + u8 *licbuf = NULL; + u32 conf_saddr = 0; + + if (!upg || !upg->func || !upg->lic || !vid) { + FTS_ERROR("upgrade/func/get_hlic_ver/lic/vid is null"); + return -EINVAL; + } + + if (upg->lic_length < FTS_MAX_LEN_SECTOR) { + FTS_ERROR("lic length(%x) fail", upg->lic_length); + return -EINVAL; + } + + licbuf = upg->lic; + conf_saddr = upg->func->fwcfgoff; + val[0] = licbuf[conf_saddr + FTS_CONIFG_VENDORID_OFF]; + if (fts_data->ic_info.is_incell) + val[1] = licbuf[conf_saddr + FTS_CONIFG_MODULEID_OFF]; + + *vid = *(u16 *)val; + return 0; +} + +static int fts_lic_get_ver_in_tp(u8 *ver) +{ + int ret = 0; + + if (NULL == ver) { + FTS_ERROR("ver is NULL"); + return -EINVAL; + } + + ret = fts_read_reg(FTS_REG_LIC_VER, ver); + if (ret < 0) { + FTS_ERROR("read lcd initcode ver from tp fail"); + return ret; + } + + return 0; +} + +static int fts_lic_get_ver_in_host(struct fts_upgrade *upg, u8 *ver) +{ + int ret = 0; + + if (!upg || !upg->func || !upg->func->get_hlic_ver || !upg->lic) { + FTS_ERROR("upgrade/func/get_hlic_ver/lic is null"); + return -EINVAL; + } + + ret = upg->func->get_hlic_ver(upg->lic); + if (ret < 0) { + FTS_ERROR("get host lcd initial code version fail"); + return ret; + } + + *ver = (u8)ret; + return ret; +} + +static bool fts_lic_need_upgrade(struct fts_upgrade *upg) +{ + int ret = 0; + u8 initcode_ver_in_tp = 0; + u8 initcode_ver_in_host = 0; + u16 vid_in_tp = 0; + u16 vid_in_host = 0; + bool fwvalid = false; + + fwvalid = fts_fwupg_check_fw_valid(); + if ( !fwvalid) { + FTS_INFO("fw is invalid, no upgrade lcd init code"); + return false; + } + + ret = fts_lic_get_vid_in_host(upg, &vid_in_host); + if (ret < 0) { + FTS_ERROR("vendor id in host invalid"); + return false; + } + + ret = fts_lic_get_vid_in_tp(&vid_in_tp); + if (ret < 0) { + FTS_ERROR("vendor id in tp invalid"); + return false; + } + + FTS_DEBUG("vid in tp:0x%04x, host:0x%04x", vid_in_tp, vid_in_host); + if (vid_in_tp != vid_in_host) { + FTS_INFO("vendor id in tp&host are different, no upgrade lic"); + return false; + } + + ret = fts_lic_get_ver_in_host(upg, &initcode_ver_in_host); + if (ret < 0) { + FTS_ERROR("init code in host invalid"); + return false; + } + + ret = fts_lic_get_ver_in_tp(&initcode_ver_in_tp); + if (ret < 0) { + FTS_ERROR("read reg0xE4 fail"); + return false; + } + + FTS_DEBUG("lcd initial code version in tp:%x, host:%x", + initcode_ver_in_tp, initcode_ver_in_host); + if (0xA5 == initcode_ver_in_tp) { + FTS_INFO("lcd init code ver is 0xA5, don't upgade init code"); + return false; + } else if (0xFF == initcode_ver_in_tp) { + FTS_DEBUG("lcd init code in tp is invalid, need upgrade init code"); + return true; + } else if (initcode_ver_in_tp < initcode_ver_in_host) + return true; + else + return false; +} + +static int fts_lic_upgrade(struct fts_upgrade *upg) +{ + int ret = 0; + bool hlic_upgrade = false; + int upgrade_count = 0; + u8 ver = 0; + + FTS_INFO("lcd initial code auto upgrade function"); + if ((!upg) || (!upg->func) || (!upg->func->lic_upgrade)) { + FTS_ERROR("lcd upgrade function is null"); + return -EINVAL; + } + + hlic_upgrade = fts_lic_need_upgrade(upg); + FTS_INFO("lcd init code upgrade flag:%d", hlic_upgrade); + if (hlic_upgrade) { + FTS_INFO("lcd initial code need upgrade, upgrade begin..."); + do { + FTS_INFO("lcd initial code upgrade times:%d", upgrade_count); + upgrade_count++; + + ret = upg->func->lic_upgrade(upg->lic, upg->lic_length); + if (ret < 0) { + fts_fwupg_reset_in_boot(); + } else { + fts_lic_get_ver_in_tp(&ver); + FTS_INFO("success upgrade to lcd initcode ver:%02x", ver); + break; + } + } while (upgrade_count < 2); + } else { + FTS_INFO("lcd initial code don't need upgrade"); + } + + return ret; +} +#endif /* FTS_AUTO_LIC_UPGRADE_EN */ + + +static int fts_param_get_ver_in_tp(u8 *ver) +{ + int ret = 0; + + if (NULL == ver) { + FTS_ERROR("ver is NULL"); + return -EINVAL; + } + + ret = fts_read_reg(FTS_REG_IDE_PARA_VER_ID, ver); + if (ret < 0) { + FTS_ERROR("read fw param ver from tp fail"); + return ret; + } + + if ((0x00 == *ver) || (0xFF == *ver)) { + FTS_INFO("param version in tp invalid"); + return -EIO; + } + + return 0; +} + +static int fts_param_get_ver_in_host(struct fts_upgrade *upg, u8 *ver) +{ + if ((!upg) || (!upg->func) || (!upg->fw) || (!ver)) { + FTS_ERROR("fts_data/upgrade/func/fw/ver is NULL"); + return -EINVAL; + } + + if (upg->fw_length < upg->func->paramcfgveroff) { + FTS_ERROR("fw len(%x) < paramcfg ver offset(%x)", + upg->fw_length, upg->func->paramcfgveroff); + return -EINVAL; + } + + FTS_INFO("fw paramcfg version offset:%x", upg->func->paramcfgveroff); + *ver = upg->fw[upg->func->paramcfgveroff]; + + if ((0x00 == *ver) || (0xFF == *ver)) { + FTS_INFO("param version in host invalid"); + return -EIO; + } + + return 0; +} + +/* + * return: < 0 : error + * == 0: no ide + * == 1: ide + */ +static int fts_param_ide_in_host(struct fts_upgrade *upg) +{ + u32 off = 0; + + if ((!upg) || (!upg->func) || (!upg->fw)) { + FTS_ERROR("fts_data/upgrade/func/fw is NULL"); + return -EINVAL; + } + + if (upg->fw_length < upg->func->paramcfgoff + FTS_FW_IDE_SIG_LEN) { + FTS_INFO("fw len(%x) < paramcfg offset(%x), no IDE", + upg->fw_length, upg->func->paramcfgoff + FTS_FW_IDE_SIG_LEN); + return 0; + } + + off = upg->func->paramcfgoff; + if (0 == memcmp(&upg->fw[off], FTS_FW_IDE_SIG, FTS_FW_IDE_SIG_LEN)) { + FTS_INFO("fw in host is IDE version"); + return 1; + } + + FTS_INFO("fw in host isn't IDE version"); + return 0; +} + +/* + * return: < 0 : error + * 0 : no ide + * 1 : ide + */ +static int fts_param_ide_in_tp(u8 *val) +{ + int ret = 0; + + ret = fts_read_reg(FTS_REG_IDE_PARA_STATUS, val); + if (ret < 0) { + FTS_ERROR("read IDE PARAM STATUS in tp fail"); + return ret; + } + + if ((*val != 0xFF) && ((*val & 0x80) == 0x80)) { + FTS_INFO("fw in tp is IDE version"); + return 1; + } + + FTS_INFO("fw in tp isn't IDE version"); + return 0; +} + +/************************************************************************ + * fts_param_need_upgrade - check fw paramcfg need upgrade or not + * + * Return: < 0 : error if paramcfg need upgrade + * 0 : no need upgrade + * 1 : need upgrade app + param + * 2 : need upgrade param + ***********************************************************************/ +static int fts_param_need_upgrade(struct fts_upgrade *upg) +{ + int ret = 0; + u8 val = 0; + int ide_in_host = 0; + int ide_in_tp = 0; + u8 ver_in_host = 0; + u8 ver_in_tp = 0; + bool fwvalid = false; + + fwvalid = fts_fwupg_check_fw_valid(); + if ( !fwvalid) { + FTS_INFO("fw is invalid, upgrade app+param"); + return 1; + } + + ide_in_host = fts_param_ide_in_host(upg); + if (ide_in_host < 0) { + FTS_INFO("fts_param_ide_in_host fail"); + return ide_in_host; + } + + ide_in_tp = fts_param_ide_in_tp(&val); + if (ide_in_tp < 0) { + FTS_INFO("fts_param_ide_in_tp fail"); + return ide_in_tp; + } + + if ((0 == ide_in_host) && (0 == ide_in_tp)) { + FTS_INFO("fw in host&tp are both no ide"); + return 0; + } else if (ide_in_host != ide_in_tp) { + FTS_INFO("fw in host&tp not equal, need upgrade app+param"); + return 1; + } else if ((1 == ide_in_host) && (1 == ide_in_tp)) { + FTS_INFO("fw in host&tp are both ide"); + if ((val & 0x7F) != 0x00) { + FTS_INFO("param invalid, need upgrade param"); + return 2; + } + + ret = fts_param_get_ver_in_host(upg, &ver_in_host); + if (ret < 0) { + FTS_ERROR("param version in host invalid"); + return ret; + } + + ret = fts_param_get_ver_in_tp(&ver_in_tp); + if (ret < 0) { + FTS_ERROR("get IDE param ver in tp fail"); + return ret; + } + + FTS_INFO("fw paramcfg version in tp:%x, host:%x", + ver_in_tp, ver_in_host); + if (ver_in_tp != ver_in_host) { + return 2; + } + } + + return 0; +} + +static int fts_fwupg_get_ver_in_tp(u8 *ver) +{ + int ret = 0; + + if (NULL == ver) { + FTS_ERROR("ver is NULL"); + return -EINVAL; + } + + ret = fts_read_reg(FTS_REG_FW_VER, ver); + if (ret < 0) { + FTS_ERROR("read fw ver from tp fail"); + return ret; + } + + return 0; +} + +static int fts_fwupg_get_ver_in_host(struct fts_upgrade *upg, u8 *ver) +{ + if ((!upg) || (!upg->func) || (!upg->fw) || (!ver)) { + FTS_ERROR("fts_data/upgrade/func/fw/ver is NULL"); + return -EINVAL; + } + + if (upg->fw_length < upg->func->fwveroff) { + FTS_ERROR("fw len(0x%0x) < fw ver offset(0x%x)", + upg->fw_length, upg->func->fwveroff); + return -EINVAL; + } + + FTS_INFO("fw version offset:0x%x", upg->func->fwveroff); + *ver = upg->fw[upg->func->fwveroff]; + return 0; +} + +static bool fts_fwupg_need_upgrade(struct fts_upgrade *upg) +{ + int ret = 0; + bool fwvalid = false; + u8 fw_ver_in_host = 0; + u8 fw_ver_in_tp = 0; + + fwvalid = fts_fwupg_check_fw_valid(); + if (fwvalid) { + ret = fts_fwupg_get_ver_in_host(upg, &fw_ver_in_host); + if (ret < 0) { + FTS_ERROR("get fw ver in host fail"); + return false; + } + + ret = fts_fwupg_get_ver_in_tp(&fw_ver_in_tp); + if (ret < 0) { + FTS_ERROR("get fw ver in tp fail"); + return false; + } + + FTS_INFO("fw version in tp:%x, host:%x", fw_ver_in_tp, fw_ver_in_host); + if (fw_ver_in_tp < fw_ver_in_host) { + return true; + } + } else { + FTS_INFO("fw invalid, need upgrade fw"); + return true; + } + + return false; +} + +/************************************************************************ + * Name: fts_fw_upgrade + * Brief: fw upgrade main entry, run in following steps + * 1. check fw version(A6), not equal, will upgrade app(+param) + * 2. if fw version equal, will check ide, will upgrade app(+param) + * in the follow situation + * a. host&tp IDE's type are not equal, will upgrade app+param + * b. host&tp are both IDE's type, and param's version are not + * equal, will upgrade param + * Input: + * Output: + * Return: return 0 if success, otherwise return error code + ***********************************************************************/ +int fts_fwupg_upgrade(struct fts_upgrade *upg) +{ + int ret = 0; + bool upgrade_flag = false; + int upgrade_count = 0; + u8 ver = 0; + + FTS_INFO("fw auto upgrade function"); + if ((NULL == upg) || (NULL == upg->func)) { + FTS_ERROR("upg/upg->func is null"); + return -EINVAL; + } + + upgrade_flag = fts_fwupg_need_upgrade(upg); + FTS_INFO("fw upgrade flag:%d", upgrade_flag); + do { + upgrade_count++; + if (upgrade_flag) { + FTS_INFO("upgrade fw app(times:%d)", upgrade_count); + if (upg->func->upgrade) { + ret = upg->func->upgrade(upg->fw, upg->fw_length); + if (ret < 0) { + fts_fwupg_reset_in_boot(); + } else { + fts_fwupg_get_ver_in_tp(&ver); + FTS_INFO("success upgrade to fw version %02x", ver); + break; + } + } else { + FTS_ERROR("upgrade func/upgrade is null, return immediately"); + ret = -ENODATA; + break; + } + } else { + if (upg->func->param_upgrade) { + ret = fts_param_need_upgrade(upg); + if (ret <= 0) { + FTS_INFO("param don't need upgrade"); + break; + } else if (1 == ret) { + FTS_INFO("force upgrade fw app(times:%d)", upgrade_count); + if (upg->func->upgrade) { + ret = upg->func->upgrade(upg->fw, upg->fw_length); + if (ret < 0) { + fts_fwupg_reset_in_boot(); + } else { + break; + } + } + } else if (2 == ret) { + FTS_INFO("upgrade param area(times:%d)", upgrade_count); + ret = upg->func->param_upgrade(upg->fw, upg->fw_length); + if (ret < 0) { + fts_fwupg_reset_in_boot(); + } else { + fts_param_get_ver_in_tp(&ver); + FTS_INFO("success upgrade to fw param version %02x", ver); + break; + } + } else + break; + } else { + break; + } + } + } while (upgrade_count < 2); + + return ret; +} + +/************************************************************************ + * fts_fwupg_auto_upgrade - upgrade main entry + ***********************************************************************/ +static void fts_fwupg_auto_upgrade(struct fts_upgrade *upg) +{ + int ret = 0; + + FTS_INFO("********************FTS enter upgrade********************"); + if (!upg || !upg->ts_data) { + FTS_ERROR("upg/ts_data is null"); + return ; + } + + ret = fts_fwupg_upgrade(upg); + if (ret < 0) + FTS_ERROR("**********tp fw(app/param) upgrade failed**********"); + else + FTS_INFO("**********tp fw(app/param) no upgrade/upgrade success**********"); + +#if FTS_AUTO_LIC_UPGRADE_EN + ret = fts_lic_upgrade(upg); + if (ret < 0) + FTS_ERROR("**********lcd init code upgrade failed**********"); + else + FTS_INFO("**********lcd init code no upgrade/upgrade success**********"); +#endif + + FTS_INFO("********************FTS exit upgrade********************"); +} + +static int fts_fwupg_get_vendorid(struct fts_upgrade *upg, int *vid) +{ + int ret = 0; + bool fwvalid = false; + u8 vendor_id = 0; + u8 module_id = 0; + u32 fwcfg_addr = 0; + u8 cfgbuf[FTS_HEADER_LEN] = { 0 }; + + FTS_INFO("read vendor id from tp"); + if ((!upg) || (!upg->func) || (!upg->ts_data) || (!vid)) { + FTS_ERROR("upgrade/func/ts_data/vid is null"); + return -EINVAL; + } + + fwvalid = fts_fwupg_check_fw_valid(); + if (fwvalid) { + ret = fts_read_reg(FTS_REG_VENDOR_ID, &vendor_id); + if (upg->ts_data->ic_info.is_incell) + ret = fts_read_reg(FTS_REG_MODULE_ID, &module_id); + } else { + fwcfg_addr = upg->func->fwcfgoff; + ret = fts_flash_read(fwcfg_addr, cfgbuf, FTS_HEADER_LEN); + vendor_id = cfgbuf[FTS_CONIFG_VENDORID_OFF]; + if (upg->ts_data->ic_info.is_incell) { + if ((cfgbuf[FTS_CONIFG_MODULEID_OFF] + + cfgbuf[FTS_CONIFG_MODULEID_OFF + 1]) == 0xFF) + module_id = cfgbuf[FTS_CONIFG_MODULEID_OFF]; + } + } + + if (ret < 0) { + FTS_ERROR("fail to get vendor id from tp"); + return ret; + } + + *vid = (int)((module_id << 8) + vendor_id); + return 0; +} + +static int fts_fwupg_get_module_info(struct fts_upgrade *upg) +{ + int ret = 0; + int i = 0; + struct upgrade_module *info = &module_list[0]; + /* MODIFIED-BEGIN by hongwei.tian, 2020-02-26,BUG-8956218*/ + struct fts_ts_data *ts_data = fts_data; + + if (!upg || !upg->ts_data) { + FTS_ERROR("upg/ts_data is null"); + return -EINVAL; + } + + /* MODIFIED-BEGIN by hongwei.tian, 2020-05-21,BUG-9467258*/ + if (ts_data->pdata->id0 == 0 && ts_data->pdata->id1 == 0) + { + FTS_INFO("load TP fw for TDT lcm"); + info = &module_list[1]; + } + else + { + FTS_INFO("load TP fw fordefault lcm"); + info = &module_list[0]; + } + /* MODIFIED-END by hongwei.tian,BUG-9467258*/ + /* MODIFIED-END by hongwei.tian,BUG-8956218*/ + + if (FTS_GET_MODULE_NUM > 1) { + /* support multi modules, must read correct module id(vendor id) */ + ret = fts_fwupg_get_vendorid(upg, &upg->module_id); + if (ret < 0) { + FTS_ERROR("get vendor id failed"); + return ret; + } + FTS_INFO("module id:%04x", upg->module_id); + for (i = 0; i < FTS_GET_MODULE_NUM; i++) { + info = &module_list[i]; + if (upg->module_id == info->id) { + FTS_INFO("module id match, get module info pass"); + break; + } + } + if (i >= FTS_GET_MODULE_NUM) { + FTS_ERROR("no module id match, don't get file"); + return -ENODATA; + } + } + + upg->module_info = info; + return 0; +} + +static int fts_get_fw_file_via_request_firmware(struct fts_upgrade *upg) +{ + int ret = 0; + const struct firmware *fw = NULL; + u8 *tmpbuf = NULL; + char fwname[FILE_NAME_LENGTH] = { 0 }; + + if (!upg || !upg->ts_data || !upg->ts_data->dev) { + FTS_ERROR("upg/ts_data/dev is null"); + return -EINVAL; + } + + snprintf(fwname, FILE_NAME_LENGTH, "%s%s.bin", \ + FTS_FW_NAME_PREX_WITH_REQUEST, \ + upg->module_info->vendor_name); + + ret = request_firmware(&fw, fwname, upg->ts_data->dev); + if (0 == ret) { + FTS_INFO("firmware(%s) request successfully", fwname); + tmpbuf = vmalloc(fw->size); + if (NULL == tmpbuf) { + FTS_ERROR("fw buffer vmalloc fail"); + ret = -ENOMEM; + } else { + memcpy(tmpbuf, fw->data, fw->size); + upg->fw = tmpbuf; + upg->fw_length = fw->size; + upg->fw_from_request = 1; + } + } else { + FTS_INFO("firmware(%s) request fail,ret=%d", fwname, ret); + } + + if (fw != NULL) { + release_firmware(fw); + fw = NULL; + } + + return ret; +} + +static int fts_get_fw_file_via_i(struct fts_upgrade *upg) +{ + upg->fw = upg->module_info->fw_file; + upg->fw_length = upg->module_info->fw_len; + upg->fw_from_request = 0; + + return 0; +} + +/***************************************************************************** + * Name: fts_fwupg_get_fw_file + * Brief: get fw image/file, + * If support muitl modules, please set FTS_GET_MODULE_NUM, and FTS_- + * MODULE_ID/FTS_MODULE_NAME; + * If get fw via .i file, please set FTS_FW_REQUEST_SUPPORT=0, and F- + * TS_MODULE_ID; will use module id to distingwish different modules; + * If get fw via reques_firmware(), please set FTS_FW_REQUEST_SUPPORT + * =1, and FTS_MODULE_NAME; fw file name will be composed of "focalt- + * ech_ts_fw_" & FTS_VENDOR_NAME; + * + * If have flash, module_id=vendor_id, If non-flash,module_id need + * transfer from LCD driver(gpio or lcm_id or ...); + * Input: + * Output: + * Return: return 0 if success, otherwise return error code + *****************************************************************************/ +static int fts_fwupg_get_fw_file(struct fts_upgrade *upg) +{ + int ret = 0; + bool get_fw_i_flag = false; + + FTS_DEBUG("get upgrade fw file"); + if (!upg || !upg->ts_data) { + FTS_ERROR("upg/ts_data is null"); + return -EINVAL; + } + + ret = fts_fwupg_get_module_info(upg); + if ((ret < 0) || (!upg->module_info)) { + FTS_ERROR("get module info fail"); + return ret; + } + + if (FTS_FW_REQUEST_SUPPORT) { + ret = fts_get_fw_file_via_request_firmware(upg); + if (ret != 0) { + get_fw_i_flag = true; + } + } else { + get_fw_i_flag = true; + } + + if (get_fw_i_flag) { + ret = fts_get_fw_file_via_i(upg); + } + + upg->lic = upg->fw; + upg->lic_length = upg->fw_length; + + FTS_INFO("upgrade fw file len:%d", upg->fw_length); + if ((upg->fw_length < FTS_MIN_LEN) + || (upg->fw_length > FTS_MAX_LEN_FILE)) { + FTS_ERROR("fw file len(%d) fail", upg->fw_length); + return -ENODATA; + } + + return ret; +} + +static void fts_fwupg_init_ic_detail(struct fts_upgrade *upg) +{ + if (upg && upg->func && upg->func->init) { + upg->func->init(upg->fw, upg->fw_length); + } +} + +/***************************************************************************** + * Name: fts_fwupg_work + * Brief: 1. get fw image/file + * 2. ic init if have + * 3. call upgrade main function(fts_fwupg_auto_upgrade) + * Input: + * Output: + * Return: + *****************************************************************************/ +static void fts_fwupg_work(struct work_struct *work) +{ + int ret = 0; + struct fts_upgrade *upg = fwupgrade; + +#if !FTS_AUTO_UPGRADE_EN + FTS_INFO("FTS_AUTO_UPGRADE_EN is disabled, not upgrade when power on"); + return ; +#endif + + FTS_INFO("fw upgrade work function"); + if (!upg || !upg->ts_data) { + FTS_ERROR("upg/ts_data is null"); + return ; + } + + upg->ts_data->fw_loading = 1; + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + + /* get fw */ + ret = fts_fwupg_get_fw_file(upg); + if (ret < 0) { + FTS_ERROR("get file fail, can't upgrade"); + } else { + /* ic init if have */ + fts_fwupg_init_ic_detail(upg); + /* run auto upgrade */ + fts_fwupg_auto_upgrade(upg); + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + upg->ts_data->fw_loading = 0; +} + +int fts_fwupg_init(struct fts_ts_data *ts_data) +{ + int i = 0; + int j = 0; + int ic_stype = 0; + struct upgrade_func *func = upgrade_func_list[0]; + int func_count = sizeof(upgrade_func_list) / sizeof(upgrade_func_list[0]); + + FTS_INFO("fw upgrade init function"); + + if (!ts_data || !ts_data->ts_workqueue) { + FTS_ERROR("ts_data/workqueue is NULL, can't run upgrade function"); + return -EINVAL; + } + + if (0 == func_count) { + FTS_ERROR("no upgrade function in tp driver"); + return -ENODATA; + } + + fwupgrade = (struct fts_upgrade *)kzalloc(sizeof(*fwupgrade), GFP_KERNEL); + if (NULL == fwupgrade) { + FTS_ERROR("malloc memory for upgrade fail"); + return -ENOMEM; + } + + ic_stype = ts_data->ic_info.ids.type; + if (1 == func_count) { + fwupgrade->func = func; + } else { + for (i = 0; i < func_count; i++) { + func = upgrade_func_list[i]; + for (j = 0; j < FTX_MAX_COMPATIBLE_TYPE; j++) { + if (0 == func->ctype[j]) + break; + else if (func->ctype[j] == ic_stype) { + FTS_INFO("match upgrade function,type:%x", (int)func->ctype[j]); + fwupgrade->func = func; + } + } + } + } + + if (NULL == fwupgrade->func) { + FTS_ERROR("no upgrade function match, can't upgrade"); + return -ENODATA; + } + + fwupgrade->ts_data = ts_data; + INIT_WORK(&ts_data->fwupg_work, fts_fwupg_work); + queue_work(ts_data->ts_workqueue, &ts_data->fwupg_work); + + return 0; +} + +int fts_fwupg_exit(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + if (fwupgrade) { + if (fwupgrade->fw_from_request) { + vfree(fwupgrade->fw); + fwupgrade->fw = NULL; + } + + kfree(fwupgrade); + fwupgrade = NULL; + } + FTS_FUNC_EXIT(); + return 0; +} diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash.h b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash.h new file mode 100755 index 0000000000000000000000000000000000000000..b76ae6a01cfa1dd83c9dd125f113f4c6cd978c22 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash.h @@ -0,0 +1,187 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/************************************************************************ +* Copyright (C) 2012-2019, Focaltech Systems (R)£¬All Rights Reserved. +* +* File Name: focaltech_flash.h +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-07 +* +* Abstract: +* +************************************************************************/ +#ifndef __LINUX_FOCALTECH_FLASH_H__ +#define __LINUX_FOCALTECH_FLASH_H__ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define FTS_CMD_RESET 0x07 +#define FTS_ROMBOOT_CMD_WRITE 0xAE +#define FTS_ROMBOOT_CMD_START_APP 0x08 +#define FTS_DELAY_PRAMBOOT_START 10 +#define FTS_ROMBOOT_CMD_ECC 0xCC + +#define FTS_CMD_READ 0x03 +#define FTS_CMD_READ_DELAY 1 +#define FTS_CMD_READ_LEN 4 +#define FTS_CMD_FLASH_TYPE 0x05 +#define FTS_CMD_FLASH_MODE 0x09 +#define FLASH_MODE_WRITE_FLASH_VALUE 0x0A +#define FLASH_MODE_UPGRADE_VALUE 0x0B +#define FLASH_MODE_LIC_VALUE 0x0C +#define FLASH_MODE_PARAM_VALUE 0x0D +#define FTS_CMD_ERASE_APP 0x61 +#define FTS_REASE_APP_DELAY 1350 +#define FTS_ERASE_SECTOR_DELAY 60 +#define FTS_RETRIES_REASE 50 +#define FTS_RETRIES_DELAY_REASE 200 +#define FTS_CMD_FLASH_STATUS 0x6A +#define FTS_CMD_FLASH_STATUS_LEN 2 +#define FTS_CMD_FLASH_STATUS_NOP 0x0000 +#define FTS_CMD_FLASH_STATUS_ECC_OK 0xF055 +#define FTS_CMD_FLASH_STATUS_ERASE_OK 0xF0AA +#define FTS_CMD_FLASH_STATUS_WRITE_OK 0x1000 +#define FTS_CMD_ECC_INIT 0x64 +#define FTS_CMD_ECC_CAL 0x65 +#define FTS_CMD_ECC_CAL_LEN 6 +#define FTS_RETRIES_ECC_CAL 10 +#define FTS_RETRIES_DELAY_ECC_CAL 50 +#define FTS_CMD_ECC_READ 0x66 +#define FTS_CMD_DATA_LEN 0xB0 +#define FTS_CMD_APP_DATA_LEN_INCELL 0x7A +#define FTS_CMD_DATA_LEN_LEN 4 +#define FTS_CMD_WRITE 0xBF +#define FTS_RETRIES_WRITE 100 +#define FTS_RETRIES_DELAY_WRITE 1 +#define FTS_CMD_WRITE_LEN 6 +#define FTS_DELAY_READ_ID 20 +#define FTS_DELAY_UPGRADE_RESET 80 +#define PRAMBOOT_MIN_SIZE 0x120 +#define PRAMBOOT_MAX_SIZE (64*1024) +#define FTS_FLASH_PACKET_LENGTH 32 /* max=128 */ +#define FTS_MAX_LEN_ECC_CALC 0xFFFE /* must be even */ +#define FTS_MIN_LEN 0x120 +#define FTS_MAX_LEN_FILE (128 * 1024) +#define FTS_MAX_LEN_APP (64 * 1024) +#define FTS_MAX_LEN_APP_PARAMS (32 * 1024) +#define FTS_MAX_LEN_SECTOR (4 * 1024) +#define FTS_CONIFG_VENDORID_OFF 0x04 +#define FTS_CONIFG_MODULEID_OFF 0x1E +#define FTS_CONIFG_PROJECTID_OFF 0x20 +#define FTS_APPINFO_OFF 0x100 +#define FTS_APPINFO_APPLEN_OFF 0x00 +#define FTS_APPINFO_APPLEN2_OFF 0x12 +#define FTS_REG_UPGRADE 0xFC +#define FTS_REG_UPGRADE2 0xBC +#define FTS_UPGRADE_AA 0xAA +#define FTS_UPGRADE_55 0x55 +#define FTS_DELAY_UPGRADE_AA 10 +#define FTS_UPGRADE_LOOP 30 +#define FTS_HEADER_LEN 32 +#define FTS_FW_BIN_FILEPATH "/sdcard/" +#define FTS_FW_IDE_SIG "IDE_" +#define FTS_FW_IDE_SIG_LEN 4 +#define MAX_MODULE_VENDOR_NAME_LEN 16 + +#define FTS_ROMBOOT_CMD_ECC_NEW_LEN 7 +#define FTS_ECC_FINISH_TIMEOUT 100 +#define FTS_ROMBOOT_CMD_ECC_FINISH 0xCE +#define FTS_ROMBOOT_CMD_ECC_FINISH_OK_A5 0xA5 +#define FTS_ROMBOOT_CMD_ECC_FINISH_OK_00 0x00 +#define FTS_ROMBOOT_CMD_ECC_READ 0xCD +#define AL2_FCS_COEF ((1 << 15) + (1 << 10) + (1 << 3)) + +#define FTS_APP_INFO_OFFSET 0x100 + +enum FW_STATUS { + FTS_RUN_IN_ERROR, + FTS_RUN_IN_APP, + FTS_RUN_IN_ROM, + FTS_RUN_IN_PRAM, + FTS_RUN_IN_BOOTLOADER, +}; + +enum FW_FLASH_MODE { + FLASH_MODE_APP, + FLASH_MODE_LIC, + FLASH_MODE_PARAM, + FLASH_MODE_ALL, +}; + +enum ECC_CHECK_MODE { + ECC_CHECK_MODE_XOR, + ECC_CHECK_MODE_CRC16, +}; + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +/* IC info */ +struct upgrade_func { + u64 ctype[FTX_MAX_COMPATIBLE_TYPE]; + u32 fwveroff; + u32 fwcfgoff; + u32 appoff; + u32 licoff; + u32 paramcfgoff; + u32 paramcfgveroff; + u32 paramcfg2off; + int pram_ecc_check_mode; + int fw_ecc_check_mode; + bool new_return_value_from_ic; + bool appoff_handle_in_ic; + bool is_reset_register_BC; + bool read_boot_id_need_reset; + bool hid_supported; + bool pramboot_supported; + u8 *pramboot; + u32 pb_length; + int (*init)(u8 *, u32); + int (*upgrade)(u8 *, u32); + int (*get_hlic_ver)(u8 *); + int (*lic_upgrade)(u8 *, u32); + int (*param_upgrade)(u8 *, u32); + int (*force_upgrade)(u8 *, u32); +}; + +struct upgrade_module { + int id; + char vendor_name[MAX_MODULE_VENDOR_NAME_LEN]; + u8 *fw_file; + u32 fw_len; +}; + +struct fts_upgrade { + struct fts_ts_data *ts_data; + struct upgrade_module *module_info; + struct upgrade_func *func; + int module_id; + bool fw_from_request; + u8 *fw; + u32 fw_length; + u8 *lic; + u32 lic_length; +}; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +extern struct upgrade_func upgrade_func_ft8716; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +int fts_fwupg_reset_in_boot(void); +int fts_fwupg_enter_into_boot(void); +int fts_fwupg_erase(u32 delay); +int fts_fwupg_ecc_cal(u32 saddr, u32 len); +int fts_flash_write_buf(u32 saddr, u8 *buf, u32 len, u32 delay); +int fts_fwupg_upgrade(struct fts_upgrade *upg); +#endif diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash/Makefile b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..a2042de39e835fa0b2ef276db977a7cd099198ad --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_upgrade_ft8716.o diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash/focaltech_upgrade_ft8716.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash/focaltech_upgrade_ft8716.c new file mode 100755 index 0000000000000000000000000000000000000000..7aa392f87036a7736184a766f530ba26ec9e6bd8 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_flash/focaltech_upgrade_ft8716.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2012-2019, Focaltech Ltd. 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. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_upgrade_ft8716.c +* +* Author: Focaltech Driver Team +* +* Created: 2017-11-22 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_flash.h" + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +u8 pb_file_ft8716[] = { +#include "../include/pramboot/FT8716_Pramboot_V0.5_20160723.i" +}; + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ + +static int fts_ft8716_upgrade_mode(enum FW_FLASH_MODE mode, u8 *buf, u32 len) +{ + int ret = 0; + u32 start_addr = 0; + u8 cmd[4] = { 0 }; + u32 delay = 0; + int ecc_in_host = 0; + int ecc_in_tp = 0; + + if ((NULL == buf) || (len < FTS_MIN_LEN)) { + FTS_ERROR("buffer/len(%x) is invalid", len); + return -EINVAL; + } + + /* enter into upgrade environment */ + ret = fts_fwupg_enter_into_boot(); + if (ret < 0) { + FTS_ERROR("enter into pramboot/bootloader fail,ret=%d", ret); + goto fw_reset; + } + + cmd[0] = FTS_CMD_FLASH_MODE; + cmd[1] = FLASH_MODE_UPGRADE_VALUE; + start_addr = upgrade_func_ft8716.appoff; + if (FLASH_MODE_PARAM == mode) { + cmd[1] = FLASH_MODE_PARAM_VALUE; + /* need add offset of app when use app part */ + start_addr += upgrade_func_ft8716.paramcfgoff; + } + FTS_INFO("flash mode:0x%02x, start addr=0x%04x", cmd[1], start_addr); + ret = fts_write(cmd, 2); + if (ret < 0) { + FTS_ERROR("upgrade mode(09) cmd write fail"); + goto fw_reset; + } + + delay = FTS_ERASE_SECTOR_DELAY * (len / FTS_MAX_LEN_SECTOR); + ret = fts_fwupg_erase(delay); + if (ret < 0) { + FTS_ERROR("erase cmd write fail"); + goto fw_reset; + } + + /* write app */ + ecc_in_host = fts_flash_write_buf(start_addr, buf, len, 1); + if (ecc_in_host < 0 ) { + FTS_ERROR("lcd initial code write fail"); + goto fw_reset; + } + + /* ecc */ + ecc_in_tp = fts_fwupg_ecc_cal(start_addr, len); + if (ecc_in_tp < 0 ) { + FTS_ERROR("ecc read fail"); + goto fw_reset; + } + + FTS_INFO("ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host); + if (ecc_in_tp != ecc_in_host) { + FTS_ERROR("ecc check fail"); + goto fw_reset; + } + + FTS_INFO("upgrade success, reset to normal boot"); + ret = fts_fwupg_reset_in_boot(); + if (ret < 0) { + FTS_ERROR("reset to normal boot fail"); + } + + msleep(400); + return 0; + +fw_reset: + return -EIO; +} + +/************************************************************************ +* Name: fts_ft8716_upgrade +* Brief: +* Input: +* Output: +* Return: return 0 if success, otherwise return error code +***********************************************************************/ +static int fts_ft8716_upgrade(u8 *buf, u32 len) +{ + int ret = 0; + u8 *tmpbuf = NULL; + u32 app_len = 0; + + FTS_INFO("fw app upgrade..."); + if (NULL == buf) { + FTS_ERROR("fw buf is null"); + return -EINVAL; + } + + if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_FILE)) { + FTS_ERROR("fw buffer len(%x) fail", len); + return -EINVAL; + } + + app_len = len; + tmpbuf = buf; + ret = fts_ft8716_upgrade_mode(FLASH_MODE_APP, tmpbuf, app_len); + if (ret < 0) { + FTS_INFO("fw upgrade fail,reset to normal boot"); + if (fts_fwupg_reset_in_boot() < 0) { + FTS_ERROR("reset to normal boot fail"); + } + return ret; + } + + return 0; +} + +/************************************************************************ + * Name: fts_ft8716_param_upgrade + * Brief: + * Input: buf - all.bin + * len - len of all.bin + * Output: + * Return: return 0 if success, otherwise return error code + ***********************************************************************/ +static int fts_ft8716_param_upgrade(u8 *buf, u32 len) +{ + int ret = 0; + u8 *tmpbuf = NULL; + u32 param_length = 0; + + FTS_INFO("parameter configure upgrade..."); + if (NULL == buf) { + FTS_ERROR("fw file buffer is null"); + return -EINVAL; + } + + if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_FILE)) { + FTS_ERROR("fw file buffer len(%x) fail", len); + return -EINVAL; + } + + tmpbuf = buf + upgrade_func_ft8716.paramcfgoff; + param_length = len - upgrade_func_ft8716.paramcfgoff; + ret = fts_ft8716_upgrade_mode(FLASH_MODE_PARAM, tmpbuf, param_length); + if (ret < 0) { + FTS_INFO("fw upgrade fail,reset to normal boot"); + if (fts_fwupg_reset_in_boot() < 0) { + FTS_ERROR("reset to normal boot fail"); + } + return ret; + } + + return 0; +} + +struct upgrade_func upgrade_func_ft8716 = { + .ctype = {0x05, 0x0F}, + .fwveroff = 0x010E, + .fwcfgoff = 0x1F80, + .appoff = 0x2000, + .paramcfgoff = 0x10000, /* -appoff */ + .paramcfgveroff = 0x10004, /* -appoff */ + .pramboot_supported = true, + .pramboot = pb_file_ft8716, + .pb_length = sizeof(pb_file_ft8716), + .pram_ecc_check_mode = ECC_CHECK_MODE_CRC16, + .hid_supported = false, + .upgrade = fts_ft8716_upgrade, + .param_upgrade = fts_ft8716_param_upgrade, +}; diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_gesture.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_gesture.c new file mode 100755 index 0000000000000000000000000000000000000000..a1479af9c86c9ef3d1ae0a129fbbddde95124075 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_gesture.c @@ -0,0 +1,508 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, Focaltech Ltd. 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. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_gestrue.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" +#if FTS_GESTURE_EN +/****************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define KEY_GESTURE_U 249 +#define KEY_GESTURE_UP KEY_UP +#define KEY_GESTURE_DOWN KEY_DOWN +#define KEY_GESTURE_LEFT KEY_LEFT +#define KEY_GESTURE_RIGHT KEY_RIGHT +#define KEY_GESTURE_O KEY_O +#define KEY_GESTURE_E KEY_E +#define KEY_GESTURE_M KEY_M +#define KEY_GESTURE_L KEY_L +#define KEY_GESTURE_W KEY_W +#define KEY_GESTURE_S KEY_S +#define KEY_GESTURE_V KEY_V +#define KEY_GESTURE_C KEY_C +#define KEY_GESTURE_Z KEY_Z + +#define GESTURE_LEFT 0x20 +#define GESTURE_RIGHT 0x21 +#define GESTURE_UP 0x22 +#define GESTURE_DOWN 0x23 +#define GESTURE_DOUBLECLICK 0x24 +#define GESTURE_O 0x30 +#define GESTURE_W 0x31 +#define GESTURE_M 0x32 +#define GESTURE_E 0x33 +#define GESTURE_L 0x44 +#define GESTURE_S 0x46 +#define GESTURE_V 0x54 +#define GESTURE_Z 0x41 +#define GESTURE_C 0x34 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +/* +* gesture_id - mean which gesture is recognised +* point_num - points number of this gesture +* coordinate_x - All gesture point x coordinate +* coordinate_y - All gesture point y coordinate +* mode - gesture enable/disable, need enable by host +* - 1:enable gesture function(default) 0:disable +* active - gesture work flag, +* always set 1 when suspend, set 0 when resume +*/ +struct fts_gesture_st { + u8 gesture_id; + u8 point_num; + u16 coordinate_x[FTS_GESTURE_POINTS_MAX]; + u16 coordinate_y[FTS_GESTURE_POINTS_MAX]; + u8 mode; + u8 active; +}; +extern u8 gesture_mode; + + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct fts_gesture_st fts_gesture_data; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +static ssize_t fts_gesture_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + u8 val = 0; + struct input_dev *input_dev = fts_data->input_dev; + + mutex_lock(&input_dev->mutex); + fts_read_reg(FTS_REG_GESTURE_EN, &val); + count = snprintf(buf, PAGE_SIZE, "Gesture Mode:%s\n", + fts_gesture_data.mode ? "On" : "Off"); + count += snprintf(buf + count, PAGE_SIZE, "Reg(0xD0)=%d\n", val); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_gesture_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_dev *input_dev = fts_data->input_dev; + mutex_lock(&input_dev->mutex); + if (FTS_SYSFS_ECHO_ON(buf)) { + FTS_DEBUG("enable gesture"); + fts_gesture_data.mode = ENABLE; + gesture_mode = 1; + } else if (FTS_SYSFS_ECHO_OFF(buf)) { + FTS_DEBUG("disable gesture"); + fts_gesture_data.mode = DISABLE; + gesture_mode = 0; + } + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_gesture_buf_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + int i = 0; + struct input_dev *input_dev = fts_data->input_dev; + struct fts_gesture_st *gesture = &fts_gesture_data; + + mutex_lock(&input_dev->mutex); + count = snprintf(buf, PAGE_SIZE, "Gesture ID:%d\n", gesture->gesture_id); + count += snprintf(buf + count, PAGE_SIZE, "Gesture PointNum:%d\n", + gesture->point_num); + count += snprintf(buf + count, PAGE_SIZE, "Gesture Points Buffer:\n"); + + /* save point data,max:6 */ + for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) { + count += snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i, + gesture->coordinate_x[i], gesture->coordinate_y[i]); + if ((i + 1) % 4 == 0) + count += snprintf(buf + count, PAGE_SIZE, "\n"); + } + count += snprintf(buf + count, PAGE_SIZE, "\n"); + mutex_unlock(&input_dev->mutex); + + return count; +} + +static ssize_t fts_gesture_buf_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} + + +/* sysfs gesture node + * read example: cat fts_gesture_mode ---read gesture mode + * write example:echo 1 > fts_gesture_mode --- write gesture mode to 1 + * + */ +static DEVICE_ATTR(fts_gesture_mode, S_IRUGO | S_IWUSR, fts_gesture_show, + fts_gesture_store); + +static DEVICE_ATTR(double_wakeup_enable, S_IRUGO | S_IWUSR, fts_gesture_show, + fts_gesture_store); +/* + * read example: cat fts_gesture_buf --- read gesture buf + */ +static DEVICE_ATTR(fts_gesture_buf, S_IRUGO | S_IWUSR, + fts_gesture_buf_show, fts_gesture_buf_store); + +static struct attribute *fts_gesture_mode_attrs[] = { + &dev_attr_fts_gesture_mode.attr, + &dev_attr_fts_gesture_buf.attr, + NULL, +}; + +static struct attribute_group fts_gesture_group = { + .attrs = fts_gesture_mode_attrs, +}; + +int fts_create_gesture_sysfs(struct device *dev) +{ + int ret = 0; + + ret = sysfs_create_group(&dev->kobj, &fts_gesture_group); + if (ret) { + FTS_ERROR("gesture sys node create fail"); + sysfs_remove_group(&dev->kobj, &fts_gesture_group); + return ret; + } + + return 0; +} + +static void fts_gesture_report(struct input_dev *input_dev, int gesture_id) +{ + int gesture; + + FTS_DEBUG("gesture_id:0x%x", gesture_id); + switch (gesture_id) { + case GESTURE_LEFT: + gesture = KEY_GESTURE_LEFT; + break; + case GESTURE_RIGHT: + gesture = KEY_GESTURE_RIGHT; + break; + case GESTURE_UP: + gesture = KEY_GESTURE_UP; + break; + case GESTURE_DOWN: + gesture = KEY_GESTURE_DOWN; + break; + case GESTURE_DOUBLECLICK: + gesture = KEY_GESTURE_U; + break; + case GESTURE_O: + gesture = KEY_GESTURE_O; + break; + case GESTURE_W: + gesture = KEY_GESTURE_W; + break; + case GESTURE_M: + gesture = KEY_GESTURE_M; + break; + case GESTURE_E: + gesture = KEY_GESTURE_E; + break; + case GESTURE_L: + gesture = KEY_GESTURE_L; + break; + case GESTURE_S: + gesture = KEY_GESTURE_S; + break; + case GESTURE_V: + gesture = KEY_GESTURE_V; + break; + case GESTURE_Z: + gesture = KEY_GESTURE_Z; + break; + case GESTURE_C: + gesture = KEY_GESTURE_C; + break; + default: + gesture = -1; + break; + } + /* report event key */ + if (gesture != -1) { + FTS_DEBUG("Gesture Code=%d", gesture); + input_report_key(input_dev, gesture, 1); + input_sync(input_dev); + input_report_key(input_dev, gesture, 0); + input_sync(input_dev); + } +} + +/***************************************************************************** +* Name: fts_gesture_readdata +* Brief: Read information about gesture: enable flag/gesture points..., if ges- +* ture enable, save gesture points' information, and report to OS. +* It will be called this function every intrrupt when FTS_GESTURE_EN = 1 +* +* gesture data length: 1(enable) + 1(reserve) + 2(header) + 6 * 4 +* Input: ts_data - global struct data +* data - gesture data buffer if non-flash, else NULL +* Output: +* Return: 0 - read gesture data successfully, the report data is gesture data +* 1 - tp not in suspend/gesture not enable in TP FW +* -Exx - error +*****************************************************************************/ +int fts_gesture_readdata(struct fts_ts_data *ts_data, u8 *data) +{ + int ret = 0; + int i = 0; + int index = 0; + u8 buf[FTS_GESTURE_DATA_LEN] = { 0 }; + struct input_dev *input_dev = ts_data->input_dev; + struct fts_gesture_st *gesture = &fts_gesture_data; + + if (!ts_data->suspended || (DISABLE == gesture->mode)) { + return 1; + } + + msleep(20); + + ret = fts_read_reg(FTS_REG_GESTURE_EN, &buf[0]); + if ((ret < 0) || (buf[0] != ENABLE)) { + FTS_DEBUG("gesture not enable in fw, don't process gesture"); + return 1; + } + + buf[2] = FTS_REG_GESTURE_OUTPUT_ADDRESS; + ret = fts_read(&buf[2], 1, &buf[2], FTS_GESTURE_DATA_LEN - 2); + if (ret < 0) { + FTS_ERROR("read gesture header data fail"); + return ret; + } + + /* init variable before read gesture point */ + memset(gesture->coordinate_x, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16)); + memset(gesture->coordinate_y, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16)); + gesture->gesture_id = buf[2]; + gesture->point_num = buf[3]; + FTS_DEBUG("gesture_id=%d, point_num=%d", + gesture->gesture_id, gesture->point_num); + + /* save point data,max:6 */ + for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) { + index = 4 * i + 4; + gesture->coordinate_x[i] = (u16)(((buf[0 + index] & 0x0F) << 8) + + buf[1 + index]); + gesture->coordinate_y[i] = (u16)(((buf[2 + index] & 0x0F) << 8) + + buf[3 + index]); + } + + /* report gesture to OS */ + fts_gesture_report(input_dev, gesture->gesture_id); + return 0; +} + +void fts_gesture_recovery(struct fts_ts_data *ts_data) +{ + if ((ENABLE == fts_gesture_data.mode) && (ENABLE == fts_gesture_data.active)) { + FTS_DEBUG("gesture recovery..."); + fts_write_reg(0xD1, 0xFF); + fts_write_reg(0xD2, 0xFF); + fts_write_reg(0xD5, 0xFF); + fts_write_reg(0xD6, 0xFF); + fts_write_reg(0xD7, 0xFF); + fts_write_reg(0xD8, 0xFF); + fts_write_reg(FTS_REG_GESTURE_EN, ENABLE); + } +} + +int fts_gesture_suspend(struct fts_ts_data *ts_data) +{ + int ret = 0; + int i = 0; + u8 state = 0xFF; + + FTS_INFO("gesture suspend..."); + /* gesture not enable, return immediately */ + if (fts_gesture_data.mode == DISABLE) { + FTS_DEBUG("gesture is disabled"); + return -EINVAL; + } + + for (i = 0; i < 5; i++) { + fts_write_reg(0xD1, 0xFF); + fts_write_reg(0xD2, 0xFF); + fts_write_reg(0xD5, 0xFF); + fts_write_reg(0xD6, 0xFF); + fts_write_reg(0xD7, 0xFF); + fts_write_reg(0xD8, 0xFF); + fts_write_reg(FTS_REG_GESTURE_EN, ENABLE); + msleep(1); + fts_read_reg(FTS_REG_GESTURE_EN, &state); + if (state == ENABLE) + break; + } + + if (i >= 5) { + FTS_ERROR("Enter into gesture(suspend) fail"); + fts_gesture_data.active = DISABLE; + return -EIO; + } + + ret = enable_irq_wake(ts_data->irq); + if (ret) { + FTS_DEBUG("enable_irq_wake(irq:%d) fail", ts_data->irq); + } + + fts_gesture_data.active = ENABLE; + FTS_INFO("Enter into gesture(suspend) successfully!"); + return 0; +} + +int fts_gesture_resume(struct fts_ts_data *ts_data) +{ + int ret = 0; + int i = 0; + u8 state = 0xFF; + + FTS_INFO("gesture resume..."); + /* gesture not enable, return immediately */ + if (fts_gesture_data.mode == DISABLE) { + FTS_DEBUG("gesture is disabled"); + return -EINVAL; + } + + if (fts_gesture_data.active == DISABLE) { + FTS_DEBUG("gesture active is disable, return immediately"); + return -EINVAL; + } + + fts_gesture_data.active = DISABLE; + for (i = 0; i < 5; i++) { + fts_write_reg(FTS_REG_GESTURE_EN, DISABLE); + msleep(1); + fts_read_reg(FTS_REG_GESTURE_EN, &state); + if (state == DISABLE) + break; + } + + if (i >= 5) { + FTS_ERROR("exit gesture(resume) fail"); + return -EIO; + } + + ret = disable_irq_wake(ts_data->irq); + if (ret) { + FTS_DEBUG("disable_irq_wake(irq:%d) fail", ts_data->irq); + } + + FTS_INFO("resume from gesture successfully"); + return 0; +} + +int fts_gesture_init(struct fts_ts_data *ts_data) +{ + struct input_dev *input_dev = ts_data->input_dev; + int error = 0; + + FTS_FUNC_ENTER(); + input_set_capability(input_dev, EV_KEY, KEY_POWER); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C); + + __set_bit(KEY_GESTURE_RIGHT, input_dev->keybit); + __set_bit(KEY_GESTURE_LEFT, input_dev->keybit); + __set_bit(KEY_GESTURE_UP, input_dev->keybit); + __set_bit(KEY_GESTURE_DOWN, input_dev->keybit); + __set_bit(KEY_GESTURE_U, input_dev->keybit); + __set_bit(KEY_GESTURE_O, input_dev->keybit); + __set_bit(KEY_GESTURE_E, input_dev->keybit); + __set_bit(KEY_GESTURE_M, input_dev->keybit); + __set_bit(KEY_GESTURE_W, input_dev->keybit); + __set_bit(KEY_GESTURE_L, input_dev->keybit); + __set_bit(KEY_GESTURE_S, input_dev->keybit); + __set_bit(KEY_GESTURE_V, input_dev->keybit); + __set_bit(KEY_GESTURE_C, input_dev->keybit); + __set_bit(KEY_GESTURE_Z, input_dev->keybit); + + fts_create_gesture_sysfs(ts_data->dev); + + if (ts_data->tct_touch_class) { + ts_data->tct_touch_gesture = + device_create(ts_data->tct_touch_class, NULL, 0, NULL, "gesture"); + if (ts_data->tct_touch_gesture) { + error = device_create_file(ts_data->tct_touch_gesture, &dev_attr_double_wakeup_enable); + if (error < 0) + FTS_DEBUG("Failed to create file double_wakeup_enable!"); + } else + FTS_DEBUG("Failed to create tct_touch_gesture!"); + } + + memset(&fts_gesture_data, 0, sizeof(struct fts_gesture_st)); + fts_gesture_data.mode = DISABLE; + fts_gesture_data.active = DISABLE; + + FTS_FUNC_EXIT(); + return 0; +} + +int fts_gesture_exit(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + sysfs_remove_group(&ts_data->dev->kobj, &fts_gesture_group); + FTS_FUNC_EXIT(); + return 0; +} +#endif diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_i2c.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_i2c.c new file mode 100755 index 0000000000000000000000000000000000000000..04e25f38a88077ed19b549c5c6d1b6c095353469 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_i2c.c @@ -0,0 +1,194 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. + * + */ + +/************************************************************************ +* +* File Name: focaltech_i2c.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-04 +* +* Abstract: i2c communication with TP +* +* Version: v1.0 +* +* Revision History: +* +************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define I2C_RETRY_NUMBER 3 +#define I2C_BUF_LENGTH 256 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ +int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen) +{ + int ret = 0; + int i = 0; + struct fts_ts_data *ts_data = fts_data; + struct i2c_msg msg_list[2]; + struct i2c_msg *msg = NULL; + int msg_num = 0; + + /* must have data when read */ + if (!ts_data || !ts_data->client || !data || !datalen + || (datalen >= I2C_BUF_LENGTH) || (cmdlen >= I2C_BUF_LENGTH)) { + FTS_ERROR("fts_data/client/cmdlen(%d)/data/datalen(%d) is invalid", + cmdlen, datalen); + return -EINVAL; + } + + mutex_lock(&ts_data->bus_lock); + memset(&msg_list[0], 0, sizeof(struct i2c_msg)); + memset(&msg_list[1], 0, sizeof(struct i2c_msg)); + memcpy(ts_data->bus_tx_buf, cmd, cmdlen); + msg_list[0].addr = ts_data->client->addr; + msg_list[0].flags = 0; + msg_list[0].len = cmdlen; + msg_list[0].buf = ts_data->bus_tx_buf; + msg_list[1].addr = ts_data->client->addr; + msg_list[1].flags = I2C_M_RD; + msg_list[1].len = datalen; + msg_list[1].buf = ts_data->bus_rx_buf; + if (cmd && cmdlen) { + msg = &msg_list[0]; + msg_num = 2; + } else { + msg = &msg_list[1]; + msg_num = 1; + } + + for (i = 0; i < I2C_RETRY_NUMBER; i++) { + ret = i2c_transfer(ts_data->client->adapter, msg, msg_num); + if (ret < 0) { + FTS_ERROR("i2c_transfer(read) fail,ret:%d", ret); + } else { + memcpy(data, ts_data->bus_rx_buf, datalen); + break; + } + } + + mutex_unlock(&ts_data->bus_lock); + return ret; +} + +int fts_write(u8 *writebuf, u32 writelen) +{ + int ret = 0; + int i = 0; + struct fts_ts_data *ts_data = fts_data; + struct i2c_msg msgs; + + if (!ts_data || !ts_data->client || !writebuf || !writelen + || (writelen >= I2C_BUF_LENGTH)) { + FTS_ERROR("fts_data/client/data/datalen(%d) is invalid", writelen); + return -EINVAL; + } + + mutex_lock(&ts_data->bus_lock); + memset(&msgs, 0, sizeof(struct i2c_msg)); + memcpy(ts_data->bus_tx_buf, writebuf, writelen); + msgs.addr = ts_data->client->addr; + msgs.flags = 0; + msgs.len = writelen; + msgs.buf = ts_data->bus_tx_buf; + for (i = 0; i < I2C_RETRY_NUMBER; i++) { + ret = i2c_transfer(ts_data->client->adapter, &msgs, 1); + if (ret < 0) { + FTS_ERROR("i2c_transfer(write) fail,ret:%d", ret); + } else { + break; + } + } + mutex_unlock(&ts_data->bus_lock); + return ret; +} + +int fts_read_reg(u8 addr, u8 *value) +{ + return fts_read(&addr, 1, value, 1); +} + +int fts_write_reg(u8 addr, u8 value) +{ + u8 buf[2] = { 0 }; + + buf[0] = addr; + buf[1] = value; + return fts_write(buf, sizeof(buf)); +} + +int fts_bus_init(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + ts_data->bus_tx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL); + if (NULL == ts_data->bus_tx_buf) { + FTS_ERROR("failed to allocate memory for bus_tx_buf"); + return -ENOMEM; + } + + ts_data->bus_rx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL); + if (NULL == ts_data->bus_rx_buf) { + FTS_ERROR("failed to allocate memory for bus_rx_buf"); + return -ENOMEM; + } + FTS_FUNC_EXIT(); + return 0; +} + +int fts_bus_exit(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + if (ts_data && ts_data->bus_tx_buf) { + kfree(ts_data->bus_tx_buf); + ts_data->bus_tx_buf = NULL; + } + + if (ts_data && ts_data->bus_rx_buf) { + kfree(ts_data->bus_rx_buf); + ts_data->bus_rx_buf = NULL; + } + FTS_FUNC_EXIT(); + return 0; +} diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_point_report_check.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_point_report_check.c new file mode 100755 index 0000000000000000000000000000000000000000..4852b8586428e7234296a0dfcc905b1377270776 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_point_report_check.c @@ -0,0 +1,136 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_point_report_check.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-11-16 +* +* Abstract: point report check function +* +* Version: v1.0 +* +* Revision History: +* +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +#if FTS_POINT_REPORT_CHECK_EN +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define POINT_REPORT_CHECK_WAIT_TIME 200 /* unit:ms */ + +/***************************************************************************** +* functions body +*****************************************************************************/ +/***************************************************************************** +* Name: fts_prc_func +* Brief: fts point report check work func, report whole up of points +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_prc_func(struct work_struct *work) +{ + struct fts_ts_data *ts_data = container_of(work, + struct fts_ts_data, prc_work.work); + struct input_dev *input_dev = ts_data->input_dev; +#if FTS_MT_PROTOCOL_B_EN + u32 finger_count = 0; + u32 max_touches = fts_data->pdata->max_touch_number; +#endif + + FTS_FUNC_ENTER(); + mutex_lock(&ts_data->report_mutex); + +#if FTS_MT_PROTOCOL_B_EN + for (finger_count = 0; finger_count < max_touches; finger_count++) { + input_mt_slot(input_dev, finger_count); + input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false); + } +#else + input_mt_sync(input_dev); +#endif + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); + + mutex_unlock(&ts_data->report_mutex); + + FTS_FUNC_EXIT(); +} + +/***************************************************************************** +* Name: fts_prc_queue_work +* Brief: fts point report check queue work, call it when interrupt comes +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_prc_queue_work(struct fts_ts_data *ts_data) +{ + cancel_delayed_work_sync(&ts_data->prc_work); + queue_delayed_work(ts_data->ts_workqueue, &ts_data->prc_work, + msecs_to_jiffies(POINT_REPORT_CHECK_WAIT_TIME)); +} + +/***************************************************************************** +* Name: fts_point_report_check_init +* Brief: +* Input: +* Output: +* Return: < 0: Fail to create esd check queue +*****************************************************************************/ +int fts_point_report_check_init(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + + if (ts_data->ts_workqueue) { + INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func); + } else { + FTS_ERROR("fts workqueue is NULL, can't run point report check function"); + return -EINVAL; + } + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_point_report_check_exit +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_point_report_check_exit(struct fts_ts_data *ts_data) +{ + FTS_FUNC_ENTER(); + + FTS_FUNC_EXIT(); + return 0; +} +#endif /* FTS_POINT_REPORT_CHECK_EN */ + diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/Makefile b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..062610eba31af9c5b7acc7ca6b8001c93defd1c0 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_test.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_test_ini.o +obj-$(CONFIG_TOUCHSCREEN_FTS) += supported_ic/ diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test.c new file mode 100755 index 0000000000000000000000000000000000000000..8cfecd1a43e8fc42cf77b9f2749a7b51f0b0e5f7 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test.c @@ -0,0 +1,2078 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2012-2019, FocalTech Systems, Ltd., 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. + * + */ + +/************************************************************************ +* +* File Name: focaltech_test.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-01 +* +* Modify: +* +* Abstract: create char device and proc node for the comm between APK and TP +* +************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_test.h" +#include + + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +struct fts_test *fts_ftest; + +struct test_funcs *test_func_list[] = { + &test_func_ft8716, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ +void sys_delay(int ms) +{ + msleep(ms); +} + +int focal_abs(int value) +{ + if (value < 0) + value = 0 - value; + + return value; +} + +void *fts_malloc(size_t size) +{ + return kzalloc(size, GFP_KERNEL); +} + +void fts_free_proc(void *p) +{ + return kfree(p); +} + +void print_buffer(int *buffer, int length, int line_num) +{ + int i = 0; + int j = 0; + int tmpline = 0; + char *tmpbuf = NULL; + int tmplen = 0; + int cnt = 0; + struct fts_test *tdata = fts_ftest; + + if (tdata && tdata->ts_data && (tdata->ts_data->log_level < 3)) { + return; + } + + if ((NULL == buffer) || (length <= 0)) { + FTS_TEST_DBG("buffer/length(%d) fail", length); + return; + } + + tmpline = line_num ? line_num : length; + tmplen = tmpline * 6 + 128; + tmpbuf = kzalloc(tmplen, GFP_KERNEL); + + for (i = 0; i < length; i = i + tmpline) { + cnt = 0; + for (j = 0; j < tmpline; j++) { + cnt += snprintf(tmpbuf + cnt, tmplen - cnt, "%5d ", buffer[i + j]); + if ((cnt >= tmplen) || ((i + j + 1) >= length)) + break; + } + FTS_TEST_DBG("%s", tmpbuf); + } + + if (tmpbuf) { + kfree(tmpbuf); + tmpbuf = NULL; + } +} + +/******************************************************************** + * test read/write interface + *******************************************************************/ +static int fts_test_bus_read( + u8 *cmd, int cmdlen, u8 *data, int datalen) +{ + int ret = 0; + + ret = fts_read(cmd, cmdlen, data, datalen); + if (ret < 0) + return ret; + else + return 0; +} + +static int fts_test_bus_write(u8 *writebuf, int writelen) +{ + int ret = 0; + + ret = fts_write(writebuf, writelen); + if (ret < 0) + return ret; + else + return 0; +} + +int fts_test_read_reg(u8 addr, u8 *val) +{ + return fts_test_bus_read(&addr, 1, val, 1); +} + +int fts_test_write_reg(u8 addr, u8 val) +{ + int ret; + u8 cmd[2] = {0}; + + cmd[0] = addr; + cmd[1] = val; + ret = fts_test_bus_write(cmd, 2); + + return ret; +} + +int fts_test_read(u8 addr, u8 *readbuf, int readlen) +{ + int ret = 0; + int i = 0; + int packet_length = 0; + int packet_num = 0; + int packet_remainder = 0; + int offset = 0; + int byte_num = readlen; + + packet_num = byte_num / BYTES_PER_TIME; + packet_remainder = byte_num % BYTES_PER_TIME; + if (packet_remainder) + packet_num++; + + if (byte_num < BYTES_PER_TIME) { + packet_length = byte_num; + } else { + packet_length = BYTES_PER_TIME; + } + /* FTS_TEST_DBG("packet num:%d, remainder:%d", packet_num, packet_remainder); */ + + ret = fts_test_bus_read(&addr, 1, &readbuf[offset], packet_length); + if (ret < 0) { + FTS_TEST_ERROR("read buffer fail"); + return ret; + } + for (i = 1; i < packet_num; i++) { + offset += packet_length; + if ((i == (packet_num - 1)) && packet_remainder) { + packet_length = packet_remainder; + } + + + ret = fts_test_bus_read(NULL, 0, &readbuf[offset], + packet_length); + if (ret < 0) { + FTS_TEST_ERROR("read buffer fail"); + return ret; + } + } + + return 0; +} + +int fts_test_write(u8 addr, u8 *writebuf, int writelen) +{ + int ret = 0; + int i = 0; + u8 *data = NULL; + int packet_length = 0; + int packet_num = 0; + int packet_remainder = 0; + int offset = 0; + int byte_num = writelen; + + data = fts_malloc(BYTES_PER_TIME + 1); + if (!data) { + FTS_TEST_ERROR("malloc memory for bus write data fail"); + return -ENOMEM; + } + + packet_num = byte_num / BYTES_PER_TIME; + packet_remainder = byte_num % BYTES_PER_TIME; + if (packet_remainder) + packet_num++; + + if (byte_num < BYTES_PER_TIME) { + packet_length = byte_num; + } else { + packet_length = BYTES_PER_TIME; + } + /* FTS_TEST_DBG("packet num:%d, remainder:%d", packet_num, packet_remainder); */ + + data[0] = addr; + for (i = 0; i < packet_num; i++) { + if (i != 0) { + data[0] = addr + 1; + } + if ((i == (packet_num - 1)) && packet_remainder) { + packet_length = packet_remainder; + } + memcpy(&data[1], &writebuf[offset], packet_length); + + ret = fts_test_bus_write(data, packet_length + 1); + if (ret < 0) { + FTS_TEST_ERROR("write buffer fail"); + fts_free(data); + return ret; + } + + offset += packet_length; + } + + fts_free(data); + return 0; +} + +/******************************************************************** + * test global function enter work/factory mode + *******************************************************************/ +int enter_work_mode(void) +{ + int ret = 0; + u8 mode = 0; + int i = 0; + int j = 0; + + FTS_TEST_FUNC_ENTER(); + + ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode); + if ((ret >= 0) && (0x00 == mode)) + return 0; + + for (i = 0; i < ENTER_WORK_FACTORY_RETRIES; i++) { + ret = fts_test_write_reg(DEVIDE_MODE_ADDR, 0x00); + if (ret >= 0) { + sys_delay(FACTORY_TEST_DELAY); + for (j = 0; j < 20; j++) { + ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode); + if ((ret >= 0) && (0x00 == mode)) { + FTS_TEST_INFO("enter work mode success"); + return 0; + } else + sys_delay(FACTORY_TEST_DELAY); + } + } + + sys_delay(50); + } + + if (i >= ENTER_WORK_FACTORY_RETRIES) { + FTS_TEST_ERROR("Enter work mode fail"); + return -EIO; + } + + FTS_TEST_FUNC_EXIT(); + return 0; +} + +int enter_factory_mode(void) +{ + int ret = 0; + u8 mode = 0; + int i = 0; + int j = 0; + + ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode); + if ((ret >= 0) && (0x40 == mode)) + return 0; + + for (i = 0; i < ENTER_WORK_FACTORY_RETRIES; i++) { + ret = fts_test_write_reg(DEVIDE_MODE_ADDR, 0x40); + if (ret >= 0) { + sys_delay(FACTORY_TEST_DELAY); + for (j = 0; j < 20; j++) { + ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode); + if ((ret >= 0) && (0x40 == mode)) { + FTS_TEST_INFO("enter factory mode success"); + sys_delay(200); + return 0; + } else + sys_delay(FACTORY_TEST_DELAY); + } + } + + sys_delay(50); + } + + if (i >= ENTER_WORK_FACTORY_RETRIES) { + FTS_TEST_ERROR("Enter factory mode fail"); + return -EIO; + } + + return 0; +} + +/* + * read_mass_data - read rawdata/short test data + * addr - register addr which read data from + * byte_num - read data length, unit:byte + * buf - save data + * + * return 0 if read data succuss, otherwise return error code + */ +int read_mass_data(u8 addr, int byte_num, int *buf) +{ + int ret = 0; + int i = 0; + u8 *data = NULL; + + data = (u8 *)fts_malloc(byte_num * sizeof(u8)); + if (NULL == data) { + FTS_TEST_SAVE_ERR("mass data buffer malloc fail\n"); + return -ENOMEM; + } + + /* read rawdata buffer */ + FTS_TEST_INFO("mass data len:%d", byte_num); + ret = fts_test_read(addr, data, byte_num); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read mass data fail\n"); + goto read_massdata_err; + } + + for (i = 0; i < byte_num; i = i + 2) { + buf[i >> 1] = (int)(short)((data[i] << 8) + data[i + 1]); + } + + ret = 0; +read_massdata_err: + fts_free(data); + return ret; +} + +int short_get_adcdata_incell(u8 retval, u8 ch_num, int byte_num, int *adc_buf) +{ + int ret = 0; + int times = 0; + u8 short_state = 0; + + FTS_TEST_FUNC_ENTER(); + + /* Start ADC sample */ + ret = fts_test_write_reg(FACTORY_REG_SHORT_TEST_EN, 0x01); + if (ret) { + FTS_TEST_SAVE_ERR("start short test fail\n"); + goto adc_err; + } + + sys_delay(ch_num * FACTORY_TEST_DELAY); + for (times = 0; times < FACTORY_TEST_RETRY; times++) { + ret = fts_test_read_reg(FACTORY_REG_SHORT_TEST_STATE, &short_state); + if ((ret >= 0) && (retval == short_state)) + break; + else + FTS_TEST_DBG("reg%x=%x,retry:%d", + FACTORY_REG_SHORT_TEST_STATE, short_state, times); + + sys_delay(FACTORY_TEST_RETRY_DELAY); + } + if (times >= FACTORY_TEST_RETRY) { + FTS_TEST_SAVE_ERR("short test timeout, ADC data not OK\n"); + ret = -EIO; + goto adc_err; + } + + ret = read_mass_data(FACTORY_REG_SHORT_ADDR, byte_num, adc_buf); + if (ret) { + FTS_TEST_SAVE_ERR("get short(adc) data fail\n"); + } + +adc_err: + FTS_TEST_FUNC_EXIT(); + return ret; +} + +/* + * wait_state_update - wait fw status update + */ +int wait_state_update(u8 retval) +{ + int ret = 0; + int times = 0; + u8 state = 0xFF; + + while (times++ < FACTORY_TEST_RETRY) { + sys_delay(FACTORY_TEST_DELAY); + /* Wait register status update */ + state = 0xFF; + ret = fts_test_read_reg(FACTORY_REG_PARAM_UPDATE_STATE, &state); + if ((ret >= 0) && (retval == state)) + break; + else + FTS_TEST_DBG("reg%x=%x,retry:%d", \ + FACTORY_REG_PARAM_UPDATE_STATE, state, times); + } + + if (times >= FACTORY_TEST_RETRY) { + FTS_TEST_SAVE_ERR("Wait State Update fail\n"); + return -EIO; + } + + return 0; +} + +/* + * start_scan - start to scan a frame + */ +int start_scan(void) +{ + int ret = 0; + u8 addr = 0; + u8 val = 0; + u8 finish_val = 0; + int times = 0; + struct fts_test *tdata = fts_ftest; + + if ((NULL == tdata) || (NULL == tdata->func)) { + FTS_TEST_SAVE_ERR("test/func is null\n"); + return -EINVAL; + } + + if (SCAN_SC == tdata->func->startscan_mode) { + /* sc ic */ + addr = FACTORY_REG_SCAN_ADDR2; + val = 0x01; + finish_val = 0x00; + } else { + addr = DEVIDE_MODE_ADDR; + val = 0xC0; + finish_val = 0x40; + } + + /* write register to start scan */ + ret = fts_test_write_reg(addr, val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write start scan mode fail\n"); + return ret; + } + + /* Wait for the scan to complete */ + while (times++ < FACTORY_TEST_RETRY) { + sys_delay(FACTORY_TEST_DELAY); + + ret = fts_test_read_reg(addr, &val); + if ((ret >= 0) && (val == finish_val)) { + break; + } else + FTS_TEST_DBG("reg%x=%x,retry:%d", addr, val, times); + } + + if (times >= FACTORY_TEST_RETRY) { + FTS_TEST_SAVE_ERR("scan timeout\n"); + return -EIO; + } + + return 0; +} + +static int read_rawdata( + u8 off_addr, + u8 off_val, + u8 rawdata_addr, + int byte_num, + int *data) +{ + int ret = 0; + + /* set line addr or rawdata start addr */ + ret = fts_test_write_reg(off_addr, off_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("wirte line/start addr fail\n"); + return ret; + } + + ret = read_mass_data(rawdata_addr, byte_num, data); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read rawdata fail\n"); + return ret; + } + + return 0; +} + +int get_rawdata(int *data) +{ + int ret = 0; + u8 val = 0; + u8 addr = 0; + u8 rawdata_addr = 0; + int byte_num = 0; + struct fts_test *tdata = fts_ftest; + + if ((NULL == tdata) || (NULL == tdata->func)) { + FTS_TEST_SAVE_ERR("test/func is null\n"); + return -EINVAL; + } + + /* enter factory mode */ + ret = enter_factory_mode(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("failed to enter factory mode,ret=%d\n", ret); + return ret; + } + + /* start scanning */ + ret = start_scan(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("scan fail\n"); + return ret; + } + + /* read rawdata */ + if (IC_HW_INCELL == tdata->func->hwtype) { + val = 0xAD; + addr = FACTORY_REG_LINE_ADDR; + rawdata_addr = FACTORY_REG_RAWDATA_ADDR; + } else if (IC_HW_MC_SC == tdata->func->hwtype) { + val = 0xAA; + addr = FACTORY_REG_LINE_ADDR; + rawdata_addr = FACTORY_REG_RAWDATA_ADDR_MC_SC; + } else { + val = 0x0; + addr = FACTORY_REG_RAWDATA_SADDR_SC; + rawdata_addr = FACTORY_REG_RAWDATA_ADDR_SC; + } + + byte_num = tdata->node.node_num * 2; + ret = read_rawdata(addr, val, rawdata_addr, byte_num, data); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read rawdata fail\n"); + return ret; + } + + return 0; +} + +/* + * chip_clb - auto clb + */ +int chip_clb(void) +{ + int ret = 0; + u8 val = 0; + int times = 0; + + /* start clb */ + ret = fts_test_write_reg(FACTORY_REG_CLB, 0x04); + if (ret) { + FTS_TEST_SAVE_ERR("write start clb fail\n"); + return ret; + } + + while (times++ < FACTORY_TEST_RETRY) { + sys_delay(FACTORY_TEST_RETRY_DELAY); + ret = fts_test_read_reg(FACTORY_REG_CLB, &val); + if ((0 == ret) && (0x02 == val)) { + /* clb ok */ + break; + } else + FTS_TEST_DBG("reg%x=%x,retry:%d", FACTORY_REG_CLB, val, times); + } + + if (times >= FACTORY_TEST_RETRY) { + FTS_TEST_SAVE_ERR("chip clb timeout\n"); + return -EIO; + } + + return 0; +} + +/* + * get_cb_incell - get cb data for incell IC + */ +int get_cb_incell(u16 saddr, int byte_num, int *cb_buf) +{ + int ret = 0; + int i = 0; + u8 cb_addr = 0; + u8 addr_h = 0; + u8 addr_l = 0; + int read_num = 0; + int packet_num = 0; + int packet_remainder = 0; + int offset = 0; + int addr = 0; + u8 *data = NULL; + + data = (u8 *)fts_malloc(byte_num * sizeof(u8)); + if (NULL == data) { + FTS_TEST_SAVE_ERR("cb buffer malloc fail\n"); + return -ENOMEM; + } + + packet_num = byte_num / BYTES_PER_TIME; + packet_remainder = byte_num % BYTES_PER_TIME; + if (packet_remainder) + packet_num++; + read_num = BYTES_PER_TIME; + + FTS_TEST_INFO("cb packet:%d,remainder:%d", packet_num, packet_remainder); + cb_addr = FACTORY_REG_CB_ADDR; + for (i = 0; i < packet_num; i++) { + offset = read_num * i; + addr = saddr + offset; + addr_h = (addr >> 8) & 0xFF; + addr_l = addr & 0xFF; + if ((i == (packet_num - 1)) && packet_remainder) { + read_num = packet_remainder; + } + + ret = fts_test_write_reg(FACTORY_REG_CB_ADDR_H, addr_h); + if (ret) { + FTS_TEST_SAVE_ERR("write cb addr high fail\n"); + goto TEST_CB_ERR; + } + ret = fts_test_write_reg(FACTORY_REG_CB_ADDR_L, addr_l); + if (ret) { + FTS_TEST_SAVE_ERR("write cb addr low fail\n"); + goto TEST_CB_ERR; + } + + ret = fts_test_read(cb_addr, data + offset, read_num); + if (ret) { + FTS_TEST_SAVE_ERR("read cb fail\n"); + goto TEST_CB_ERR; + } + } + + for (i = 0; i < byte_num; i++) { + cb_buf[i] = data[i]; + } + +TEST_CB_ERR: + fts_free(data); + return ret; +} + +int get_cb_sc(int byte_num, int *cb_buf, enum byte_mode mode) +{ + int ret = 0; + int i = 0; + int read_num = 0; + int packet_num = 0; + int packet_remainder = 0; + int offset = 0; + u8 cb_addr = 0; + u8 off_addr = 0; + struct fts_test *tdata = fts_ftest; + u8 *cb = NULL; + + if ((NULL == tdata) || (NULL == tdata->func)) { + FTS_TEST_SAVE_ERR("test/func is null\n"); + return -EINVAL; + } + + cb = (u8 *)fts_malloc(byte_num * sizeof(u8)); + if (NULL == cb) { + FTS_TEST_SAVE_ERR("malloc memory for cb buffer fail\n"); + return -ENOMEM; + } + + if (IC_HW_MC_SC == tdata->func->hwtype) { + cb_addr = FACTORY_REG_MC_SC_CB_ADDR; + off_addr = FACTORY_REG_MC_SC_CB_ADDR_OFF; + } else if (IC_HW_SC == tdata->func->hwtype) { + cb_addr = FACTORY_REG_SC_CB_ADDR; + off_addr = FACTORY_REG_SC_CB_ADDR_OFF; + } + + packet_num = byte_num / BYTES_PER_TIME; + packet_remainder = byte_num % BYTES_PER_TIME; + if (packet_remainder) + packet_num++; + read_num = BYTES_PER_TIME; + offset = 0; + + FTS_TEST_INFO("cb packet:%d,remainder:%d", packet_num, packet_remainder); + for (i = 0; i < packet_num; i++) { + if ((i == (packet_num - 1)) && packet_remainder) { + read_num = packet_remainder; + } + + ret = fts_test_write_reg(off_addr, offset); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write cb addr offset fail\n"); + goto cb_err; + } + + ret = fts_test_read(cb_addr, cb + offset, read_num); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read cb fail\n"); + goto cb_err; + } + + offset += read_num; + } + + if (DATA_ONE_BYTE == mode) { + for (i = 0; i < byte_num; i++) { + cb_buf[i] = cb[i]; + } + } else if (DATA_TWO_BYTE == mode) { + for (i = 0; i < byte_num; i = i + 2) { + cb_buf[i >> 1] = (int)(((int)(cb[i]) << 8) + cb[i + 1]); + } + } + + ret = 0; +cb_err: + fts_free(cb); + return ret; +} + +bool compare_data(int *data, int min, int max, int min_vk, int max_vk, bool key) +{ + int i = 0; + bool result = true; + struct fts_test *tdata = fts_ftest; + int rx = tdata->node.rx_num; + int node_va = tdata->node.node_num - tdata->node.key_num; + + if (!data || !tdata->node_valid) { + FTS_TEST_SAVE_ERR("data/node_valid is null\n"); + return false; + } + + for (i = 0; i < node_va; i++) { + if (0 == tdata->node_valid[i]) + continue; + + if ((data[i] < min) || (data[i] > max)) { + FTS_TEST_SAVE_ERR("test fail,node(%4d,%4d)=%5d,range=(%5d,%5d)\n", + i / rx + 1, i % rx + 1, data[i], min, max); + result = false; + } + } + + if (key) { + for (i = node_va; i < tdata->node.node_num; i++) { + if (0 == tdata->node_valid[i]) + continue; + + if ((data[i] < min_vk) || (data[i] > max_vk)) { + FTS_TEST_SAVE_ERR("test fail,node(%4d,%4d)=%5d,range=(%5d,%5d)\n", + i / rx + 1, i % rx + 1, + data[i], min_vk, max_vk); + result = false; + } + } + } + + return result; +} + +bool compare_array(int *data, int *min, int *max, bool key) +{ + int i = 0; + bool result = true; + struct fts_test *tdata = fts_ftest; + int rx = tdata->node.rx_num; + int node_num = tdata->node.node_num; + + if (!data || !min || !max || !tdata->node_valid) { + FTS_TEST_SAVE_ERR("data/min/max/node_valid is null\n"); + return false; + } + + if (!key) { + node_num -= tdata->node.key_num; + } + for (i = 0; i < node_num; i++) { + if (0 == tdata->node_valid[i]) + continue; + + if ((data[i] < min[i]) || (data[i] > max[i])) { + FTS_TEST_SAVE_ERR("test fail,node(%4d,%4d)=%5d,range=(%5d,%5d)\n", + i / rx + 1, i % rx + 1, data[i], min[i], max[i]); + result = false; + } + } + + return result; +} + +/* + * show_data - show and save test data to testresult.txt + */ +void show_data(int *data, bool key) +{ +#if TXT_SUPPORT + int i = 0; + int j = 0; + struct fts_test *tdata = fts_ftest; + int node_num = tdata->node.node_num; + int tx_num = tdata->node.tx_num; + int rx_num = tdata->node.rx_num; + + FTS_TEST_FUNC_ENTER(); + for (i = 0; i < tx_num; i++) { + FTS_TEST_SAVE_INFO("Ch/Tx_%02d: ", i + 1); + for (j = 0; j < rx_num; j++) { + FTS_TEST_SAVE_INFO("%5d, ", data[i * rx_num + j]); + } + FTS_TEST_SAVE_INFO("\n"); + } + + if (key) { + FTS_TEST_SAVE_INFO("Ch/Tx_%02d: ", tx_num + 1); + for (i = tx_num * rx_num; i < node_num; i++) { + FTS_TEST_SAVE_INFO("%5d, ", data[i]); + } + FTS_TEST_SAVE_INFO("\n"); + } + FTS_TEST_FUNC_EXIT(); +#endif +} + +/* mc_sc only */ +/* Only V3 Pattern has mapping & no-mapping */ +int mapping_switch(u8 mapping) +{ + int ret = 0; + u8 val = 0xFF; + struct fts_test *tdata = fts_ftest; + + if (tdata->v3_pattern) { + ret = fts_test_read_reg(FACTORY_REG_NOMAPPING, &val); + if (ret < 0) { + FTS_TEST_ERROR("read 0x54 register fail"); + return ret; + } + + if (val != mapping) { + ret = fts_test_write_reg(FACTORY_REG_NOMAPPING, mapping); + if (ret < 0) { + FTS_TEST_ERROR("write 0x54 register fail"); + return ret; + } + sys_delay(FACTORY_TEST_DELAY); + } + } + + return 0; +} + +bool get_fw_wp(u8 wp_ch_sel, enum wp_type water_proof_type) +{ + bool fw_wp_state = false; + + switch (water_proof_type) { + case WATER_PROOF_ON: + /* bit5: 0-check in wp on, 1-not check */ + fw_wp_state = !(wp_ch_sel & 0x20); + break; + case WATER_PROOF_ON_TX: + /* Bit6: 0-check Rx+Tx in wp mode 1-check one channel + Bit2: 0-check Tx in wp mode; 1-check Rx in wp mode + */ + fw_wp_state = (!(wp_ch_sel & 0x40) || !(wp_ch_sel & 0x04)); + break; + case WATER_PROOF_ON_RX: + fw_wp_state = (!(wp_ch_sel & 0x40) || (wp_ch_sel & 0x04)); + break; + case WATER_PROOF_OFF: + /* bit7: 0-check in wp off, 1-not check */ + fw_wp_state = !(wp_ch_sel & 0x80); + break; + case WATER_PROOF_OFF_TX: + /* Bit1-0: 00-check Tx in non-wp mode + 01-check Rx in non-wp mode + 10:check Rx+Tx in non-wp mode + */ + fw_wp_state = ((0x0 == (wp_ch_sel & 0x03)) || (0x02 == (wp_ch_sel & 0x03))); + break; + case WATER_PROOF_OFF_RX: + fw_wp_state = ((0x01 == (wp_ch_sel & 0x03)) || (0x02 == (wp_ch_sel & 0x03))); + break; + default: + break; + } + + return fw_wp_state; +} + +int get_cb_mc_sc(u8 wp, int byte_num, int *cb_buf, enum byte_mode mode) +{ + int ret = 0; + + /* 1:waterproof 0:non-waterproof */ + ret = fts_test_write_reg(FACTORY_REG_MC_SC_MODE, wp); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get mc_sc mode fail\n"); + return ret; + } + + /* read cb */ + ret = get_cb_sc(byte_num, cb_buf, mode); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get sc cb fail\n"); + return ret; + } + + return 0; +} + +int get_rawdata_mc_sc(enum wp_type wp, int *data) +{ + int ret = 0; + u8 val = 0; + u8 addr = 0; + u8 rawdata_addr = 0; + int byte_num = 0; + struct fts_test *tdata = fts_ftest; + + if ((NULL == tdata) || (NULL == tdata->func)) { + FTS_TEST_SAVE_ERR("test/func is null\n"); + return -EINVAL; + } + + addr = FACTORY_REG_LINE_ADDR; + rawdata_addr = FACTORY_REG_RAWDATA_ADDR_MC_SC; + if (WATER_PROOF_ON == wp) { + val = 0xAC; + } else { + val = 0xAB; + } + + byte_num = tdata->sc_node.node_num * 2; + ret = read_rawdata(addr, val, rawdata_addr, byte_num, data); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read rawdata fail\n"); + return ret; + } + + return 0; +} + +int get_rawdata_mc(u8 fre, u8 fir, int *rawdata) +{ + int ret = 0; + int i = 0; + + if (NULL == rawdata ) { + FTS_TEST_SAVE_ERR("rawdata buffer is null\n"); + return -EINVAL; + } + + /* set frequecy high/low */ + ret = fts_test_write_reg(FACTORY_REG_FRE_LIST, fre); + if (ret < 0) { + FTS_TEST_SAVE_ERR("set frequecy fail,ret=%d\n", ret); + return ret; + } + + /* fir enable/disable */ + ret = fts_test_write_reg(FACTORY_REG_FIR, 1); + if (ret < 0) { + FTS_TEST_SAVE_ERR("set fir fail,ret=%d\n", fir); + return ret; + } + + /* get rawdata */ + for (i = 0; i < 3; i++) { + /* lost 3 frames, in order to obtain stable data */ + ret = get_rawdata(rawdata); + } + if (ret < 0) { + FTS_TEST_SAVE_ERR("get rawdata fail,ret=%d\n", ret); + return ret; + } + + return 0; +} + +int short_get_adc_data_mc(u8 retval, int byte_num, int *adc_buf, u8 mode) +{ + int ret = 0; + int i = 0; + u8 short_state = 0; + + FTS_TEST_FUNC_ENTER(); + /* select short test mode & start test */ + ret = fts_test_write_reg(FACTROY_REG_SHORT_TEST_EN, mode); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write short test mode fail\n"); + goto test_err; + } + + for (i = 0; i < FACTORY_TEST_RETRY; i++) { + sys_delay(FACTORY_TEST_RETRY_DELAY); + + ret = fts_test_read_reg(FACTROY_REG_SHORT_TEST_EN, &short_state); + if ((ret >= 0) && (retval == short_state)) + break; + else + FTS_TEST_DBG("reg%x=%x,retry:%d", + FACTROY_REG_SHORT_TEST_EN, short_state, i); + } + if (i >= FACTORY_TEST_RETRY) { + FTS_TEST_SAVE_ERR("short test timeout, ADC data not OK\n"); + ret = -EIO; + goto test_err; + } + + ret = read_mass_data(FACTORY_REG_SHORT_ADDR_MC, byte_num, adc_buf); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get short(adc) data fail\n"); + } + + FTS_TEST_DBG("adc data:\n"); + print_buffer(adc_buf, byte_num / 2, 0); +test_err: + FTS_TEST_FUNC_EXIT(); + return ret; +} + +bool compare_mc_sc(bool tx_check, bool rx_check, int *data, int *min, int *max) +{ + int i = 0; + bool result = true; + struct fts_test *tdata = fts_ftest; + + if (rx_check) { + for (i = 0; i < tdata->sc_node.rx_num; i++) { + if (0 == tdata->node_valid_sc[i]) + continue; + + if ((data[i] < min[i]) || (data[i] > max[i])) { + FTS_TEST_SAVE_ERR("test fail,rx%d=%5d,range=(%5d,%5d)\n", + i + 1, data[i], min[i], max[i]); + result = false; + } + } + } + + if (tx_check) { + for (i = tdata->sc_node.rx_num; i < tdata->sc_node.node_num; i++) { + if (0 == tdata->node_valid_sc[i]) + continue; + + if ((data[i] < min[i]) || (data[i] > max[i])) { + FTS_TEST_SAVE_INFO("test fail,tx%d=%5d,range=(%5d,%5d)\n", + i - tdata->sc_node.rx_num + 1, + data[i], min[i], max[i]); + result = false; + } + } + } + + return result; +} + +void show_data_mc_sc(int *data) +{ + int i = 0; + struct fts_test *tdata = fts_ftest; + + FTS_TEST_SAVE_INFO("SCap Rx: "); + for (i = 0; i < tdata->sc_node.rx_num; i++) { + FTS_TEST_SAVE_INFO( "%5d, ", data[i]); + } + FTS_TEST_SAVE_INFO("\n"); + + FTS_TEST_SAVE_INFO("SCap Tx: "); + for (i = tdata->sc_node.rx_num; i < tdata->sc_node.node_num; i++) { + FTS_TEST_SAVE_INFO( "%5d, ", data[i]); + } + FTS_TEST_SAVE_INFO("\n"); +} +/* mc_sc end*/ + +#if CSV_SUPPORT || TXT_SUPPORT +static int fts_test_save_test_data(char *file_name, char *data_buf, int len) +{ + struct file *pfile = NULL; + char filepath[128]; + loff_t pos; + mm_segment_t old_fs; + + FTS_TEST_FUNC_ENTER(); + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "%s%s", FTS_INI_FILE_PATH, file_name); + if (NULL == pfile) { + pfile = filp_open(filepath, O_TRUNC | O_CREAT | O_RDWR, 0); + } + if (IS_ERR(pfile)) { + FTS_TEST_ERROR("error occured while opening file %s.", filepath); + return -EIO; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_write(pfile, data_buf, len, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + + FTS_TEST_FUNC_EXIT(); + return 0; +} +#endif + +static int fts_test_malloc_free_data_txt(struct fts_test *tdata, bool allocate) +{ +#if TXT_SUPPORT + if (true == allocate) { + tdata->testresult = vmalloc(TXT_BUFFER_LEN); + if (NULL == tdata->testresult) { + FTS_TEST_ERROR("tdata->testresult malloc fail\n"); + return -ENOMEM; + } + + tdata->testresult_len = 0; + FTS_TEST_SAVE_INFO("FW version:0x%02x\n", tdata->fw_ver); + FTS_TEST_SAVE_INFO("tx_num:%d, rx_num:%d, key_num:%d\n", + tdata->node.tx_num, tdata->node.rx_num, + tdata->node.key_num); + } else { + if (tdata->testresult) { + vfree(tdata->testresult); + tdata->testresult = NULL; + } + } +#endif + return 0; +} + +static void fts_test_save_data_csv(struct fts_test *tdata) +{ +#if CSV_SUPPORT + int i = 0; + int j = 0; + int k = 0; + int tx = 0; + int rx = 0; + int node_num = 0; + int offset = 0; + int start_line = 11; + int data_count = 0; + char *csv_buffer = NULL; + char *line2_buffer = NULL; + int csv_length = 0; + int line2_length = 0; + int csv_item_count = 0; + struct fts_test_data *td = &tdata->testdata; + struct item_info *info = NULL; + char file_name[128]; + struct timespec ts; + struct tm tm; + + FTS_TEST_INFO("save data in csv format"); + csv_buffer = vmalloc(CSV_BUFFER_LEN); + if (!csv_buffer) { + FTS_TEST_ERROR("csv_buffer malloc fail\n"); + return ; + } + + line2_buffer = vmalloc(CSV_LINE2_BUFFER_LEN); + if (!line2_buffer) { + FTS_TEST_ERROR("line2_buffer malloc fail\n"); + goto csv_save_err; + } + + FTS_TEST_INFO("test item count:%d", td->item_count); + /* line 1 */ + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "ECC, 85, 170, IC Name, %s, IC Code, %x\n", \ + tdata->ini.ic_name, \ + (tdata->ini.ic_code >> IC_CODE_OFFSET)); + + /* line 2 */ + for (i = 0; i < td->item_count; i++) { + info = &td->info[i]; + if (info->mc_sc) { + node_num = tdata->sc_node.node_num; + /* set max len of tx/rx to column */ + rx = (tdata->sc_node.tx_num > tdata->sc_node.rx_num) + ? tdata->sc_node.tx_num : tdata->sc_node.rx_num; + } else { + if (info->key_support && (tdata->node.key_num > 0)) + node_num = (tdata->node.tx_num + 1) * tdata->node.rx_num; + else + node_num = tdata->node.tx_num * tdata->node.rx_num; + rx = tdata->node.rx_num; + } + + if (info->datalen > node_num) { + data_count = (info->datalen - 1 ) / node_num + 1; + tx = (node_num - 1 ) / rx + 1; + } else { + data_count = 1; + tx = ((info->datalen - 1) / rx) + 1; + } + + for (j = 1; j <= data_count; j++) { + line2_length += snprintf(line2_buffer + line2_length, \ + CSV_LINE2_BUFFER_LEN - line2_length, \ + "%s, %d, %d, %d, %d, %d, ", \ + info->name, info->code, tx, rx, + start_line, j); + start_line += tx; + csv_item_count++; + } + } + + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "TestItem Num, %d, ", \ + csv_item_count); + + if (line2_length > 0) { + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "%s", line2_buffer); + } + + /* line 3 ~ 10 "\n" */ + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "\n\n\n\n\n\n\n\n\n"); + + /* line 11 ~ data area */ + for (i = 0; i < td->item_count; i++) { + info = &td->info[i]; + if (!info->data) { + FTS_TEST_ERROR("test item data is null"); + return; + } + + if (info->mc_sc) { + offset = 0; + for (j = 0; j < info->datalen; j++) { + for (k = 0; k < tdata->sc_node.node_num; k++) { + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "%d, ", info->data[offset + k]); + if ((k + 1) == tdata->sc_node.rx_num) { + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "\n"); + } + } + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "\n"); + offset += k; + j += k; + } + } else { + for (j = 0; j < info->datalen; j++) { + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, \ + "%d, ", info->data[j]); + if (((j + 1) % tdata->node.rx_num) == 0) { + csv_length += snprintf(csv_buffer + csv_length, \ + CSV_BUFFER_LEN - csv_length, + "\n"); + } + } + } + } + + getnstimeofday(&ts); + time_to_tm(ts.tv_sec, 0, &tm); + memset(file_name, 0, sizeof(file_name)); + sprintf(file_name, "%s-%d%02d%02d%02d%02d%02d.csv", FTS_CSV_FILE_NAME, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + FTS_TEST_INFO("csv length:%d", csv_length); + fts_test_save_test_data(file_name, csv_buffer, csv_length); + +csv_save_err: + if (csv_buffer) { + vfree(csv_buffer); + csv_buffer = NULL; + } +#endif +} + +static void fts_test_save_result_txt(struct fts_test *tdata) +{ +#if TXT_SUPPORT + char file_name[128]; + struct timespec ts; + struct tm tm; + + getnstimeofday(&ts); + time_to_tm(ts.tv_sec, 0, &tm); + + if (!tdata || !tdata->testresult) { + FTS_TEST_ERROR("test result is null"); + return; + } + memset(file_name, 0, sizeof(file_name)); + sprintf(file_name, "%s-%d%02d%02d%02d%02d%02d.txt", FTS_TXT_FILE_NAME, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + FTS_TEST_INFO("test result length in txt:%d", tdata->testresult_len); + fts_test_save_test_data(file_name, tdata->testresult, + tdata->testresult_len); +#endif +} + +/***************************************************************************** +* Name: fts_test_save_data +* Brief: Save test data. +* If multi-data of MC, length of data package must be tx*rx,(tx+1)*rx +* If multi-data of MC-SC, length of data package should be (tx+rx)*2 +* Need fill 0 when no actual data +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_test_save_data(char *name, int code, int *data, int datacnt, + bool mc_sc, bool key, bool result) +{ + int datalen = datacnt; + struct fts_test *tdata = fts_ftest; + struct fts_test_data *td = &tdata->testdata; + struct item_info *info = &td->info[td->item_count]; + + if (!name || !data) { + FTS_TEST_ERROR("name/data is null"); + return ; + } + + strncpy(info->name, name, TEST_ITEM_NAME_MAX); + info->code = code; + info->mc_sc = mc_sc; + info->key_support = key; + info->result = result; + if (datalen <= 0) { + if (mc_sc) { + datalen = tdata->sc_node.node_num * 2; + } else { + if (key && (tdata->node.key_num > 0)) + datalen = (tdata->node.tx_num + 1) * tdata->node.rx_num; + else + datalen = tdata->node.tx_num * tdata->node.rx_num; + + } + } + + FTS_TEST_DBG("name:%s,len:%d", name, datalen); + info->data = fts_malloc(datalen * sizeof(int)); + if (!info->data) { + FTS_TEST_ERROR("malloc memory for item(%d) data fail", td->item_count); + info->datalen = 0; + return ; + } + memcpy(info->data, data, datalen * sizeof(int)); + info->datalen = datalen; + + td->item_count++; +} + +static void fts_test_free_data(struct fts_test *tdata) +{ + int i = 0; + struct fts_test_data *td = &tdata->testdata; + + for (i = 0; i < td->item_count; i++) { + if (td->info[i].data) { + fts_free(td->info[i].data); + } + } +} + +static int fts_test_malloc_free_incell(struct fts_test *tdata, bool allocate) +{ + struct incell_threshold *thr = &tdata->ic.incell.thr; + int buflen = tdata->node.node_num * sizeof(int); + + if (true == allocate) { + FTS_TEST_INFO("buflen:%d", buflen); + fts_malloc_r(thr->rawdata_min, buflen); + fts_malloc_r(thr->rawdata_max, buflen); + if (tdata->func->rawdata2_support) { + fts_malloc_r(thr->rawdata2_min, buflen); + fts_malloc_r(thr->rawdata2_max, buflen); + } + fts_malloc_r(thr->cb_min, buflen); + fts_malloc_r(thr->cb_max, buflen); + } else { + fts_free(thr->rawdata_min); + fts_free(thr->rawdata_max); + if (tdata->func->rawdata2_support) { + fts_free(thr->rawdata2_min); + fts_free(thr->rawdata2_max); + } + fts_free(thr->cb_min); + fts_free(thr->cb_max); + } + + return 0; +} + +static int fts_test_malloc_free_mc_sc(struct fts_test *tdata, bool allocate) +{ + struct mc_sc_threshold *thr = &tdata->ic.mc_sc.thr; + int buflen = tdata->node.node_num * sizeof(int); + int buflen_sc = tdata->sc_node.node_num * sizeof(int); + + if (true == allocate) { + fts_malloc_r(thr->rawdata_h_min, buflen); + fts_malloc_r(thr->rawdata_h_max, buflen); + if (tdata->func->rawdata2_support) { + fts_malloc_r(thr->rawdata_l_min, buflen); + fts_malloc_r(thr->rawdata_l_max, buflen); + } + fts_malloc_r(thr->tx_linearity_max, buflen); + fts_malloc_r(thr->tx_linearity_min, buflen); + fts_malloc_r(thr->rx_linearity_max, buflen); + fts_malloc_r(thr->rx_linearity_min, buflen); + + fts_malloc_r(thr->scap_cb_off_min, buflen_sc); + fts_malloc_r(thr->scap_cb_off_max, buflen_sc); + fts_malloc_r(thr->scap_cb_on_min, buflen_sc); + fts_malloc_r(thr->scap_cb_on_max, buflen_sc); + + fts_malloc_r(thr->scap_rawdata_off_min, buflen_sc); + fts_malloc_r(thr->scap_rawdata_off_max, buflen_sc); + fts_malloc_r(thr->scap_rawdata_on_min, buflen_sc); + fts_malloc_r(thr->scap_rawdata_on_max, buflen_sc); + + fts_malloc_r(thr->panel_differ_min, buflen); + fts_malloc_r(thr->panel_differ_max, buflen); + } else { + fts_free(thr->rawdata_h_min); + fts_free(thr->rawdata_h_max); + if (tdata->func->rawdata2_support) { + fts_free(thr->rawdata_l_min); + fts_free(thr->rawdata_l_max); + } + fts_free(thr->tx_linearity_max); + fts_free(thr->tx_linearity_min); + fts_free(thr->rx_linearity_max); + fts_free(thr->rx_linearity_min); + + fts_free(thr->scap_cb_off_min); + fts_free(thr->scap_cb_off_max); + fts_free(thr->scap_cb_on_min); + fts_free(thr->scap_cb_on_max); + + fts_free(thr->scap_rawdata_off_min); + fts_free(thr->scap_rawdata_off_max); + fts_free(thr->scap_rawdata_on_min); + fts_free(thr->scap_rawdata_on_max); + + fts_free(thr->panel_differ_min); + fts_free(thr->panel_differ_max); + } + + return 0; +} + +static int fts_test_malloc_free_sc(struct fts_test *tdata, bool allocate) +{ + struct sc_threshold *thr = &tdata->ic.sc.thr; + int buflen = tdata->node.node_num * sizeof(int); + + if (true == allocate) { + fts_malloc_r(thr->rawdata_min, buflen); + fts_malloc_r(thr->rawdata_max, buflen); + fts_malloc_r(thr->cb_min, buflen); + fts_malloc_r(thr->cb_max, buflen); + fts_malloc_r(thr->dcb_sort, buflen); + fts_malloc_r(thr->dcb_base, buflen); + } else { + fts_free(thr->rawdata_min); + fts_free(thr->rawdata_max); + fts_free(thr->cb_min); + fts_free(thr->cb_max); + fts_free(thr->dcb_sort); + fts_free(thr->dcb_base); + } + + return 0; +} + +static int fts_test_malloc_free_thr(struct fts_test *tdata, bool allocate) +{ + int ret = 0; + + if ((NULL == tdata) || (NULL == tdata->func)) { + FTS_TEST_SAVE_ERR("tdata/func is NULL\n"); + return -EINVAL; + } + + if (true == allocate) { + fts_malloc_r(tdata->node_valid, tdata->node.node_num * sizeof(int)); + fts_malloc_r(tdata->node_valid_sc, tdata->sc_node.node_num * sizeof(int)); + } else { + fts_free(tdata->node_valid); + fts_free(tdata->node_valid_sc); + } + + switch (tdata->func->hwtype) { + case IC_HW_INCELL: + ret = fts_test_malloc_free_incell(tdata, allocate); + break; + case IC_HW_MC_SC: + ret = fts_test_malloc_free_mc_sc(tdata, allocate); + break; + case IC_HW_SC: + ret = fts_test_malloc_free_sc(tdata, allocate); + break; + default: + FTS_TEST_SAVE_ERR("test ic type(%d) fail\n", tdata->func->hwtype); + ret = -EINVAL; + break; + } + + return ret; +} + +/* default enable all test item */ +static void fts_test_init_item(struct fts_test *tdata) +{ + switch (tdata->func->hwtype) { + case IC_HW_INCELL: + tdata->ic.incell.u.tmp = 0xFFFFFFFF; + break; + case IC_HW_MC_SC: + tdata->ic.mc_sc.u.tmp = 0xFFFFFFFF; + break; + case IC_HW_SC: + tdata->ic.sc.u.tmp = 0xFFFFFFFF; + break; + } +} + +static int get_tx_rx_num(u8 tx_rx_reg, u8 *ch_num, u8 ch_num_max) +{ + int ret = 0; + int i = 0; + + for (i = 0; i < 3; i++) { + ret = fts_test_read_reg(tx_rx_reg, ch_num); + if ((ret < 0) || (*ch_num > ch_num_max)) { + sys_delay(50); + } else + break; + } + + if (i >= 3) { + FTS_TEST_ERROR("get channel num fail"); + return -EIO; + } + + return 0; +} +static int get_key_num(int *key_num_en, int max_key_num) +{ + int ret = 0; + u8 key_en = 0; + + if (!max_key_num) { + FTS_TEST_DBG("not support key, don't read key num register"); + return 0; + } + + ret = fts_test_read_reg(FACTORY_REG_LEFT_KEY, &key_en); + if (ret >= 0) { + if (key_en & 0x01) { + (*key_num_en)++; + } + + if (key_en & 0x02) { + (*key_num_en)++; + } + + if (key_en & 0x04) { + (*key_num_en)++; + } + } + + ret = fts_test_read_reg(FACTORY_REG_RIGHT_KEY, &key_en); + if (ret >= 0) { + if (key_en & 0x01) { + (*key_num_en)++; + } + + if (key_en & 0x02) { + (*key_num_en)++; + } + + if (key_en & 0x04) { + (*key_num_en)++; + } + } + + if (*key_num_en > max_key_num) { + FTS_TEST_ERROR("get key num, fw:%d > max:%d", *key_num_en, max_key_num); + return -EIO; + } + + return ret; +} + +static int get_channel_num(struct fts_test *tdata) +{ + int ret = 0; + u8 tx_num = 0; + u8 rx_num = 0; + int key_num = 0; + + /* node structure */ + if (IC_HW_SC == tdata->func->hwtype) { + ret = get_tx_rx_num(FACTORY_REG_CH_NUM_SC, &tx_num, NUM_MAX_SC); + if (ret < 0) { + FTS_TEST_ERROR("get channel number fail"); + return ret; + } + + ret = get_tx_rx_num(FACTORY_REG_KEY_NUM_SC, &rx_num, KEY_NUM_MAX); + if (ret < 0) { + FTS_TEST_ERROR("get key number fail"); + return ret; + } + + tdata->node.tx_num = 2; + tdata->node.rx_num = tx_num / 2; + tdata->node.channel_num = tx_num; + tdata->node.node_num = tx_num; + key_num = rx_num; + } else { + ret = get_tx_rx_num(FACTORY_REG_CHX_NUM, &tx_num, TX_NUM_MAX); + if (ret < 0) { + FTS_TEST_ERROR("get tx_num fail"); + return ret; + } + + ret = get_tx_rx_num(FACTORY_REG_CHY_NUM, &rx_num, RX_NUM_MAX); + if (ret < 0) { + FTS_TEST_ERROR("get rx_num fail"); + return ret; + } + + if (IC_HW_INCELL == tdata->func->hwtype) { + ret = get_key_num(&key_num, tdata->func->key_num_total); + if (ret < 0) { + FTS_TEST_ERROR("get key_num fail"); + return ret; + } + } else if (IC_HW_MC_SC == tdata->func->hwtype) { + key_num = tdata->func->key_num_total; + } + tdata->node.tx_num = tx_num; + tdata->node.rx_num = rx_num; + if (IC_HW_INCELL == tdata->func->hwtype) + tdata->node.channel_num = tx_num * rx_num; + else if (IC_HW_MC_SC == tdata->func->hwtype) + tdata->node.channel_num = tx_num + rx_num; + tdata->node.node_num = tx_num * rx_num; + } + + /* key */ + tdata->node.key_num = key_num; + tdata->node.node_num += tdata->node.key_num; + + /* sc node structure */ + tdata->sc_node = tdata->node; + if (IC_HW_MC_SC == tdata->func->hwtype) { + if (tdata->v3_pattern) { + ret = get_tx_rx_num(FACTORY_REG_CHX_NUM_NOMAP, &tx_num, TX_NUM_MAX); + if (ret < 0) { + FTS_TEST_ERROR("get no-mappint tx_num fail"); + return ret; + } + + ret = get_tx_rx_num(FACTORY_REG_CHY_NUM_NOMAP, &rx_num, TX_NUM_MAX); + if (ret < 0) { + FTS_TEST_ERROR("get no-mapping rx_num fail"); + return ret; + } + + tdata->sc_node.tx_num = tx_num; + tdata->sc_node.rx_num = rx_num; + } + tdata->sc_node.channel_num = tx_num + rx_num; + tdata->sc_node.node_num = tx_num + rx_num; + } + + if (tdata->node.tx_num > TX_NUM_MAX) { + FTS_TEST_ERROR("tx num(%d) fail", tdata->node.tx_num); + return -EIO; + } + + if (tdata->node.rx_num > RX_NUM_MAX) { + FTS_TEST_ERROR("rx num(%d) fail", tdata->node.rx_num); + return -EIO; + } + + FTS_TEST_INFO("node_num:%d, tx:%d, rx:%d, key:%d", + tdata->node.node_num, tdata->node.tx_num, + tdata->node.rx_num, tdata->node.key_num); + return 0; +} + +static int fts_test_init_basicinfo(struct fts_test *tdata) +{ + int ret = 0; + u8 val = 0; + + if ((NULL == tdata) || (NULL == tdata->func)) { + FTS_TEST_SAVE_ERR("tdata/func is NULL\n"); + return -EINVAL; + } + + fts_test_read_reg(REG_FW_VERSION, &val); + tdata->fw_ver = val; + + if (IC_HW_INCELL == tdata->func->hwtype) { + fts_test_read_reg(REG_VA_TOUCH_THR, &val); + tdata->va_touch_thr = val; + fts_test_read_reg(REG_VKEY_TOUCH_THR, &val); + tdata->vk_touch_thr = val; + } + + /* enter factory mode */ + ret = enter_factory_mode(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("enter factory mode fail\n"); + return ret; + } + + if (IC_HW_MC_SC == tdata->func->hwtype) { + fts_test_read_reg(FACTORY_REG_PATTERN, &val); + tdata->v3_pattern = (1 == val) ? true : false; + fts_test_read_reg(FACTORY_REG_NOMAPPING, &val); + tdata->mapping = val; + } + + /* enter into factory mode and read tx/rx num */ + ret = get_channel_num(tdata); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get channel number fail\n"); + return ret; + } + + return ret; +} + +static int fts_test_main_init(void) +{ + int ret = 0; + struct fts_test *tdata = fts_ftest; + + FTS_TEST_FUNC_ENTER(); + /* Init fts_test_data to 0 before test, */ + memset(&tdata->testdata, 0, sizeof(struct fts_test_data)); + + /* get basic information: tx/rx num ... */ + ret = fts_test_init_basicinfo(tdata); + if (ret < 0) { + FTS_TEST_ERROR("test init basicinfo fail"); + return ret; + } + + /* allocate memory for test threshold */ + ret = fts_test_malloc_free_thr(tdata, true); + if (ret < 0) { + FTS_TEST_ERROR("test malloc for threshold fail"); + return ret; + } + + /* default enable all test item */ + fts_test_init_item(tdata); + + ret = fts_test_malloc_free_data_txt(tdata, true); + if (ret < 0) { + FTS_TEST_ERROR("allocate memory for test data(txt) fail"); + return ret; + } + + /* allocate test data buffer */ + tdata->buffer_length = (tdata->node.tx_num + 1) * tdata->node.rx_num; + tdata->buffer_length *= sizeof(int) * 2; + FTS_TEST_INFO("test buffer length:%d", tdata->buffer_length); + tdata->buffer = (int *)fts_malloc(tdata->buffer_length); + if (NULL == tdata->buffer) { + FTS_TEST_ERROR("test buffer(%d) malloc fail", tdata->buffer_length); + return -ENOMEM; + } + memset(tdata->buffer, 0, tdata->buffer_length); + + FTS_TEST_FUNC_EXIT(); + return ret; +} + +static int fts_test_main_exit(void) +{ + struct fts_test *tdata = fts_ftest; + + FTS_TEST_FUNC_ENTER(); + fts_test_save_data_csv(tdata); + fts_test_save_result_txt(tdata); + + /* free memory */ + fts_test_malloc_free_data_txt(tdata, false); + fts_test_malloc_free_thr(tdata, false); + + /* free test data */ + fts_test_free_data(tdata); + + /*free test data buffer*/ + fts_free(tdata->buffer); + + FTS_TEST_FUNC_EXIT(); + return 0; +} + + +/* + * fts_test_get_testparams - get test parameter from ini + */ +static int fts_test_get_testparams(char *config_name) +{ + int ret = 0; + + ret = fts_test_get_testparam_from_ini(config_name); + + return ret; +} + +static int fts_test_start(void) +{ + int testresult = 0; + struct fts_test *tdata = fts_ftest; + + tdata->testdata.item_count = 0; + if (tdata && tdata->func && tdata->func->start_test) { + testresult = tdata->func->start_test(); + } else { + FTS_TEST_ERROR("test func/start_test func is null"); + } + + return testresult; +} + +/* + * fts_test_entry - test main entry + * + * warning - need disable irq & esdcheck before call this function + * + */ + +static bool g_test_result = false; +static int fts_test_entry(char *ini_file_name) +{ + int ret = 0; + + /* test initialize */ + g_test_result = false; + ret = fts_test_main_init(); + if (ret < 0) { + FTS_TEST_ERROR("fts_test_main_init fail"); + goto test_err; + } + + /*Read parse configuration file*/ + FTS_TEST_SAVE_INFO("ini_file_name:%s\n", ini_file_name); + ret = fts_test_get_testparams(ini_file_name); + if (ret < 0) { + FTS_TEST_ERROR("get testparam fail"); + goto test_err; + } + + /* Start testing according to the test configuration */ + if (true == fts_test_start()) { + g_test_result = true; + FTS_TEST_SAVE_INFO("\n\n=======Tp test pass.\n"); + } else { + FTS_TEST_SAVE_INFO("\n\n=======Tp test failure.\n"); + } + + ret = 0; +test_err: + fts_test_main_exit(); + enter_work_mode(); + return ret; +} + +static ssize_t fts_test_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + + count = snprintf(buf, PAGE_SIZE, "TEST RESULT:%s\n", + g_test_result ? "Pass" : "Fail"); + + return count; +} + +static ssize_t fts_test_store( + struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + char fwname[128] = {0}; + struct fts_ts_data *ts_data = fts_data; + struct input_dev *input_dev; + + if (ts_data->suspended) { + FTS_INFO("In suspend, no test, return now"); + return -EINVAL; + } + + input_dev = ts_data->input_dev; + memset(fwname, 0, sizeof(fwname)); + sprintf(fwname, "%s", buf); + fwname[count - 1] = '\0'; + FTS_TEST_DBG("fwname:%s.", fwname); + + mutex_lock(&input_dev->mutex); + disable_irq(ts_data->irq); + +#if defined(FTS_ESDCHECK_EN) && (FTS_ESDCHECK_EN) + fts_esdcheck_switch(DISABLE); +#endif + + ret = fts_enter_test_environment(1); + if (ret < 0) { + FTS_ERROR("enter test environment fail"); + } else { + fts_test_entry(fwname); + } + ret = fts_enter_test_environment(0); + if (ret < 0) { + FTS_ERROR("enter normal environment fail"); + } + +#if defined(FTS_ESDCHECK_EN) && (FTS_ESDCHECK_EN) + fts_esdcheck_switch(ENABLE); +#endif + + enable_irq(ts_data->irq); + mutex_unlock(&input_dev->mutex); + + return count; +} + +/* test from test.ini +* example:echo "***.ini" > fts_test +*/ +static DEVICE_ATTR(fts_test, S_IRUGO | S_IWUSR, fts_test_show, fts_test_store); + +static struct attribute *fts_test_attributes[] = { + &dev_attr_fts_test.attr, + NULL +}; + +static struct attribute_group fts_test_attribute_group = { + .attrs = fts_test_attributes +}; + +static int fts_test_func_init(struct fts_ts_data *ts_data) +{ + int i = 0; + int j = 0; + int ic_stype = ts_data->ic_info.ids.type; + struct test_funcs *func = test_func_list[0]; + int func_count = sizeof(test_func_list) / sizeof(test_func_list[0]); + + FTS_TEST_INFO("init test function"); + if (0 == func_count) { + FTS_TEST_SAVE_ERR("test functions list is NULL, fail\n"); + return -ENODATA; + } + + fts_ftest = (struct fts_test *)kzalloc(sizeof(*fts_ftest), GFP_KERNEL); + if (NULL == fts_ftest) { + FTS_TEST_ERROR("malloc memory for test fail"); + return -ENOMEM; + } + + for (i = 0; i < func_count; i++) { + func = test_func_list[i]; + for (j = 0; j < FTX_MAX_COMPATIBLE_TYPE; j++) { + if (0 == func->ctype[j]) + break; + else if (func->ctype[j] == ic_stype) { + FTS_TEST_INFO("match test function,type:%x", (int)func->ctype[j]); + fts_ftest->func = func; + } + } + } + if (NULL == fts_ftest->func) { + FTS_TEST_ERROR("no test function match, can't test"); + return -ENODATA; + } + + fts_ftest->ts_data = fts_data; + return 0; +} + +int fts_test_init(struct fts_ts_data *ts_data) +{ + int ret = 0; + + FTS_TEST_FUNC_ENTER(); + /* get test function, must be the first step */ + ret = fts_test_func_init(ts_data); + if (ret < 0) { + FTS_TEST_SAVE_ERR("test functions init fail"); + return ret; + } + + ret = sysfs_create_group(&ts_data->dev->kobj, &fts_test_attribute_group); + if (0 != ret) { + FTS_TEST_ERROR("sysfs(test) create fail"); + sysfs_remove_group(&ts_data->dev->kobj, &fts_test_attribute_group); + } else { + FTS_TEST_DBG("sysfs(test) create successfully"); + } + FTS_TEST_FUNC_EXIT(); + + return ret; +} + +int fts_test_exit(struct fts_ts_data *ts_data) +{ + FTS_TEST_FUNC_ENTER(); + + sysfs_remove_group(&ts_data->dev->kobj, &fts_test_attribute_group); + fts_free(fts_ftest); + FTS_TEST_FUNC_EXIT(); + return 0; +} diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test.h b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test.h new file mode 100755 index 0000000000000000000000000000000000000000..30143e7f09f79316361d7bc4ab120ffb0792cf59 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test.h @@ -0,0 +1,588 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/************************************************************************ +* Copyright (C) 2012-2019, Focaltech Systems (R)£¬All Rights Reserved. +* +* File Name: focaltech_test.h +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-01 +* +* Abstract: test entry for all IC +* +************************************************************************/ +#ifndef _TEST_LIB_H +#define _TEST_LIB_H + +/***************************************************************************** +* Included header files +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include //iic +#include //msleep +#include +#include +#include + +#include "../focaltech_core.h" +#include "focaltech_test_ini.h" + +/***************************************************************************** +* Macro definitions using #define +*****************************************************************************/ +#define FTS_INI_FILE_PATH "/mnt/sdcard/" +#define FTS_CSV_FILE_NAME "testdata" +#define FTS_TXT_FILE_NAME "testresult" +#define false 0 +#define true 1 +#define TEST_ICSERIES_LEN (8) +#define TEST_ICSERIES(x) ((x) >> TEST_ICSERIES_LEN) + +#define TEST_OPEN_MAX_VALUE (255) +#define BYTES_PER_TIME (32) /* max:128 */ +/* CSV & TXT */ +#define CSV_LINE2_BUFFER_LEN (1024) +#define CSV_BUFFER_LEN (1024*80*5) +#define TXT_BUFFER_LEN (1024*80*5) + +/*----------------------------------------------------------- +Test Status +-----------------------------------------------------------*/ +#define RESULT_NULL 0 +#define RESULT_PASS 1 +#define RESULT_NG 2 + +#define TX_NUM_MAX 60 +#define RX_NUM_MAX 60 +#define NUM_MAX ((TX_NUM_MAX)*(RX_NUM_MAX)) +#define NUM_MAX_SC (144) +#define KEY_NUM_MAX 6 +#define TEST_ITEM_COUNT_MAX 32 +#define TEST_ITEM_NAME_MAX 32 +#define TEST_SHORT_RES_MAX 0xFFFF + +/* + * factory test registers + */ +#define ENTER_WORK_FACTORY_RETRIES 5 + +#define START_SCAN_RETRIES_INCELL 20 +#define START_SCAN_RETRIES_DELAY_INCELL 16 +#define FACTORY_TEST_RETRY 50 +#define FACTORY_TEST_DELAY 18 +#define FACTORY_TEST_RETRY_DELAY 100 + +#define DEVIDE_MODE_ADDR 0x00 +#define REG_FW_VERSION 0xA6 +#define REG_VA_TOUCH_THR 0x80 +#define REG_VKEY_TOUCH_THR 0x82 + +#define FACTORY_REG_LINE_ADDR 0x01 +#define FACTORY_REG_CHX_NUM 0x02 +#define FACTORY_REG_CHY_NUM 0x03 +#define FACTORY_REG_CLB 0x04 +#define FACTORY_REG_DATA_SELECT 0x06 +#define FACTORY_REG_RAWBUF_SELECT 0x09 +#define FACTORY_REG_KEY_CBWIDTH 0x0B +#define FACTORY_REG_PARAM_UPDATE_STATE 0x0E +#define FACTORY_REG_SHORT_TEST_EN 0x0F +#define FACTORY_REG_SHORT_TEST_STATE 0x10 +#define FACTORY_REG_LCD_NOISE_START 0x11 +#define FACTORY_REG_LCD_NOISE_FRAME 0x12 +#define FACTORY_REG_LCD_NOISE_NUMBER 0x13 +#define FACTORY_REG_LCD_NOISE_TTHR 0x14 +#define FACTORY_REG_OPEN_START 0x15 +#define FACTORY_REG_OPEN_STATE 0x16 +#define FACTORY_REG_OPEN_IDLE 0x03 +#define FACTORY_REG_OPEN_BUSY 0x01 +#define FACTORY_REG_CB_ADDR_H 0x18 +#define FACTORY_REG_CB_ADDR_L 0x19 +#define FACTORY_REG_LCD_NOISE_STATE 0x1E +#define FACTORY_REG_KEYSHORT_EN 0x2E +#define FACTORY_REG_KEYSHORT_STATE 0x2F + +#define FACTORY_REG_LEFT_KEY 0x1E +#define FACTORY_REG_RIGHT_KEY 0x1F +#define FACTORY_REG_OPEN_REG20 0x20 +#define FACTORY_REG_OPEN_REG21 0x21 +#define FACTORY_REG_OPEN_REG22 0x22 +#define FACTORY_REG_OPEN_REG23 0x23 +#define FACTORY_REG_OPEN_REG86 0x86 +#define FACTORY_REG_K1 0x31 +#define FACTORY_REG_K2 0x32 +#define FACTORY_REG_RAWDATA_ADDR 0x6A +#define FACTORY_REG_CB_ADDR 0x6E +#define FACTORY_REG_SHORT_ADDR 0x89 +#define FACTORY_REG_RAWDATA_TEST_EN 0x9E +#define FACTORY_REG_CB_TEST_EN 0x9F +#define FACTORY_REG_OPEN_TEST_EN 0xA0 + +/* mc_sc */ +#define FACTORY_REG_FRE_LIST 0x0A +#define FACTORY_REG_NORMALIZE 0x16 +#define FACTORY_REG_RAWDATA_ADDR_MC_SC 0x36 +#define FACTORY_REG_PATTERN 0x53 +#define FACTORY_REG_NOMAPPING 0x54 +#define FACTORY_REG_CHX_NUM_NOMAP 0x55 +#define FACTORY_REG_CHY_NUM_NOMAP 0x56 +#define FACTORY_REG_WC_SEL 0x09 +#define FACTORY_REG_MC_SC_MODE 0x44 +#define FACTORY_REG_MC_SC_CB_ADDR_OFF 0x45 +#define FACTORY_REG_MC_SC_CB_ADDR 0x4E +#define FACTROY_REG_SHORT_TEST_EN 0x07 +#define FACTROY_REG_SHORT_CA 0x01 +#define FACTROY_REG_SHORT_CC 0x02 +#define FACTROY_REG_SHORT_CG 0x03 +#define FACTROY_REG_SHORT_OFFSET 0x04 +#define FACTROY_REG_SHORT_AB_CH 0x58 +#define FACTROY_REG_SHORT_DELAY 0x5A +#define FACTORY_REG_SHORT_ADDR_MC 0xF4 +#define FACTORY_REG_FIR 0xFB + +/* sc */ +#define FACTORY_REG_SCAN_ADDR2 0x08 +#define FACTORY_REG_CH_NUM_SC 0x0A +#define FACTORY_REG_KEY_NUM_SC 0x0B +#define FACTORY_REG_SC_CB_ADDR_OFF 0x33 +#define FACTORY_REG_SC_CB_ADDR 0x39 +#define FACTORY_REG_RAWDATA_SADDR_SC 0x34 +#define FACTORY_REG_RAWDATA_ADDR_SC 0x35 +#define FACTORY_REG_CB_SEL 0x41 +#define FACTORY_REG_FMODE 0xAE + +#define TEST_RETVAL_00 0x00 +#define TEST_RETVAL_AA 0xAA + +/***************************************************************************** +* enumerations, structures and unions +*****************************************************************************/ +struct item_info { + char name[TEST_ITEM_NAME_MAX]; + int code; + int *data; + int datalen; + int result; + int mc_sc; + int key_support; +}; + +struct fts_test_data { + int item_count; + struct item_info info[TEST_ITEM_COUNT_MAX]; +}; + +/* incell */ +struct incell_testitem { + u32 short_test : 1; + u32 open_test : 1; + u32 cb_test : 1; + u32 rawdata_test : 1; + u32 lcdnoise_test : 1; + u32 keyshort_test : 1; +}; + +struct incell_threshold_b { + int short_res_min; + int short_res_vk_min; + int open_cb_min; + int open_k1_check; + int open_k1_value; + int open_k2_check; + int open_k2_value; + int cb_min; + int cb_max; + int cb_vkey_check; + int cb_min_vk; + int cb_max_vk; + int rawdata_min; + int rawdata_max; + int rawdata_vkey_check; + int rawdata_min_vk; + int rawdata_max_vk; + int lcdnoise_frame; + int lcdnoise_coefficient; + int lcdnoise_coefficient_vkey; + int open_nmos; + int keyshort_k1; + int keyshort_cb_max; + int rawdata2_min; + int rawdata2_max; +}; + +struct incell_threshold { + struct incell_threshold_b basic; + int *rawdata_min; + int *rawdata_max; + int *rawdata2_min; + int *rawdata2_max; + int *cb_min; + int *cb_max; +}; + +struct incell_test { + struct incell_threshold thr; + union { + int tmp; + struct incell_testitem item; + } u; +}; + +/* mc_sc */ +enum mapping_type { + MAPPING = 0, + NO_MAPPING = 1, +}; + +struct mc_sc_testitem { + u32 rawdata_test : 1; + u32 rawdata_uniformity_test : 1; + u32 scap_cb_test : 1; + u32 scap_rawdata_test : 1; + u32 short_test : 1; + u32 panel_differ_test : 1; +}; + +struct mc_sc_threshold_b { + int rawdata_h_min; + int rawdata_h_max; + int rawdata_set_hfreq; + int rawdata_l_min; + int rawdata_l_max; + int rawdata_set_lfreq; + int uniformity_check_tx; + int uniformity_check_rx; + int uniformity_check_min_max; + int uniformity_tx_hole; + int uniformity_rx_hole; + int uniformity_min_max_hole; + int scap_cb_off_min; + int scap_cb_off_max; + int scap_cb_wp_off_check; + int scap_cb_on_min; + int scap_cb_on_max; + int scap_cb_wp_on_check; + int scap_rawdata_off_min; + int scap_rawdata_off_max; + int scap_rawdata_wp_off_check; + int scap_rawdata_on_min; + int scap_rawdata_on_max; + int scap_rawdata_wp_on_check; + int short_cg; + int short_cc; + int panel_differ_min; + int panel_differ_max; + +}; + +struct mc_sc_threshold { + struct mc_sc_threshold_b basic; + int *rawdata_h_min; + int *rawdata_h_max; + int *rawdata_l_min; + int *rawdata_l_max; + int *tx_linearity_max; + int *tx_linearity_min; + int *rx_linearity_max; + int *rx_linearity_min; + int *scap_cb_off_min; + int *scap_cb_off_max; + int *scap_cb_on_min; + int *scap_cb_on_max; + int *scap_rawdata_off_min; + int *scap_rawdata_off_max; + int *scap_rawdata_on_min; + int *scap_rawdata_on_max; + int *panel_differ_min; + int *panel_differ_max; +}; + +struct mc_sc_test { + struct mc_sc_threshold thr; + union { + u32 tmp; + struct mc_sc_testitem item; + } u; +}; + +/* sc */ +struct sc_testitem { + u32 rawdata_test : 1; + u32 cb_test : 1; + u32 delta_cb_test : 1; +}; + +struct sc_threshold_b { + int rawdata_min; + int rawdata_max; + int cb_min; + int cb_max; + int dcb_base; + int dcb_differ_max; + int dcb_key_check; + int dcb_key_differ_max; + int dcb_ds1; + int dcb_ds2; + int dcb_ds3; + int dcb_ds4; + int dcb_ds5; + int dcb_ds6; + int dcb_critical_check; + int dcb_cs1; + int dcb_cs2; + int dcb_cs3; + int dcb_cs4; + int dcb_cs5; + int dcb_cs6; +}; + +struct sc_threshold { + struct sc_threshold_b basic; + int *rawdata_min; + int *rawdata_max; + int *cb_min; + int *cb_max; + int *dcb_sort; + int *dcb_base; +}; + +struct sc_test { + struct sc_threshold thr; + union { + u32 tmp; + struct sc_testitem item; + } u; +}; + +enum test_hw_type { + IC_HW_INCELL = 1, + IC_HW_MC_SC, + IC_HW_SC, +}; + +enum test_scan_mode { + SCAN_NORMAL = 0, + SCAN_SC, +}; + +struct fts_test_node { + int channel_num; + int tx_num; + int rx_num; + int node_num; + int key_num; +}; + +struct fts_test { + struct fts_ts_data *ts_data; + struct fts_test_node node; + struct fts_test_node sc_node; + u8 fw_ver; + u8 va_touch_thr; + u8 vk_touch_thr; + bool key_support; + bool v3_pattern; + u8 mapping; + u8 normalize; + int test_num; + int *buffer; + int buffer_length; + int *node_valid; + int *node_valid_sc; + int basic_thr_count; + int code1; + int code2; + int offset; + union { + struct incell_test incell; + struct mc_sc_test mc_sc; + struct sc_test sc; + } ic; + + struct test_funcs *func; + struct fts_test_data testdata; + char *testresult; + int testresult_len; + struct ini_data ini; +}; + +struct test_funcs { + u64 ctype[FTX_MAX_COMPATIBLE_TYPE]; + enum test_hw_type hwtype; + int startscan_mode; + int key_num_total; + bool rawdata2_support; + bool force_touch; + int (*param_init)(void); + int (*init)(void); + int (*start_test)(void); +}; + +enum byte_mode { + DATA_ONE_BYTE, + DATA_TWO_BYTE, +}; +/* mc_sc */ +enum normalize_type { + NORMALIZE_OVERALL, + NORMALIZE_AUTO, +}; + +enum wp_type { + WATER_PROOF_OFF = 0, + WATER_PROOF_ON = 1, + WATER_PROOF_ON_TX, + WATER_PROOF_ON_RX, + WATER_PROOF_OFF_TX, + WATER_PROOF_OFF_RX, +}; +/* mc end */ + +/* sc */ +enum factory_mode { + FACTORY_NORMAL, + FACTORY_TESTMODE_1, + FACTORY_TESTMODE_2, +}; + +enum dcb_sort_num { + DCB_SORT_MIN = 1, + DCB_SORT_MAX = 6, +}; + +struct dcb_sort_d { + int ch_num; + int deviation; + int critical; + int min; + int max; +}; +/* sc end */ + +enum csv_itemcode_incell { + CODE_ENTER_FACTORY_MODE = 0, + CODE_RAWDATA_TEST = 7, + CODE_CB_TEST = 12, + CODE_SHORT_TEST = 15, + CODE_OPEN_TEST = 25, + CODE_LCD_NOISE_TEST = 27, +}; + +enum csv_itemcode_mc_sc { + CODE_M_RAWDATA_TEST = 7, + CODE_M_SCAP_CB_TEST = 9, + CODE_M_SCAP_RAWDATA_TEST = 10, + CODE_M_WEAK_SHORT_CIRCUIT_TEST = 15, + CODE_M_RAWDATA_UNIFORMITY_TEST = 16, + CODE_M_PANELDIFFER_TEST = 20, +}; + +enum csv_itemcode_sc { + CODE_S_RAWDATA_TEST = 7, + CODE_S_CB_TEST = 13, + CODE_S_DCB_TEST = 14, +}; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +extern struct test_funcs test_func_ft8716; + +extern struct fts_test *fts_ftest; + +void sys_delay(int ms); +int focal_abs(int value); +void print_buffer(int *buffer, int length, int line_num); +int fts_test_read_reg(u8 addr, u8 *val); +int fts_test_write_reg(u8 addr, u8 val); +int fts_test_read(u8 addr, u8 *readbuf, int readlen); +int fts_test_write(u8 addr, u8 *writebuf, int writelen); +int enter_work_mode(void); +int enter_factory_mode(void); +int read_mass_data(u8 addr, int byte_num, int *buf); +int chip_clb(void); +int wait_state_update(u8 retval); +int get_cb_incell(u16 saddr, int byte_num, int *cb_buf); +int short_get_adcdata_incell(u8 retval, u8 ch_num, int byte_num, int *adc_buf); +int start_scan(void); +int get_rawdata(int *data); +int get_cb_sc(int byte_num, int *cb_buf, enum byte_mode mode); +bool compare_data(int *data, int min, int max, int min_vk, int max_vk, bool key); +bool compare_array(int *data, int *min, int *max, bool key); +void show_data(int *data, bool key); +/* mc_sc */ +int mapping_switch(u8 mapping); +bool get_fw_wp(u8 wp_channel_select, enum wp_type water_proof_type); +int get_cb_mc_sc(u8 wp, int byte_num, int *cb_buf, enum byte_mode mode); +int get_rawdata_mc_sc(enum wp_type wp, int *data); +int get_rawdata_mc(u8 fre, u8 fir, int *rawdata); +int short_get_adc_data_mc(u8 retval, int byte_num, int *adc_buf, u8 mode); +bool compare_mc_sc(bool, bool, int *, int *, int *); +void show_data_mc_sc(int *data); +void *fts_malloc(size_t size); +void fts_free_proc(void *p); +void fts_test_save_data(char *name, int code, int *data, int datacnt, + bool mc_sc, bool key, bool result); + +#define fts_malloc_r(p, size) do {\ + if (NULL == p) {\ + p = fts_malloc(size);\ + if (NULL == p) {\ + return -ENOMEM;\ + }\ + }\ +} while(0) + +#define fts_free(p) do {\ + if (p) {\ + fts_free_proc(p);\ + p = NULL;\ + }\ +} while(0) + +#define CSV_SUPPORT 1 +#define TXT_SUPPORT 1 + +#define FTS_TEST_DBG(fmt, args...) do { \ +printk("[FTS_TS][TEST]%s:"fmt"\n", __func__, ##args); \ +} while (0) + +#define FTS_TEST_FUNC_ENTER() do { \ + printk("[FTS_TS][TEST]%s: Enter\n", __func__); \ +} while (0) + +#define FTS_TEST_FUNC_EXIT() do { \ + printk("[FTS_TS][TEST]%s: Exit(%d)\n", __func__, __LINE__); \ +} while (0) + +#define FTS_TEST_INFO(fmt, args...) do { \ + printk(KERN_ERR "[FTS_TS/I][TEST]%s:"fmt"\n", __func__, ##args); \ +} while (0) + +#define FTS_TEST_ERROR(fmt, args...) do { \ + printk(KERN_ERR "[FTS_TS/E][TEST]%s:"fmt"\n", __func__, ##args); \ +} while (0) + +#define FTS_TEST_SAVE_INFO(fmt, args...) do { \ + if (fts_ftest->testresult) { \ + fts_ftest->testresult_len += snprintf( \ + fts_ftest->testresult + fts_ftest->testresult_len, \ + TXT_BUFFER_LEN, \ + fmt, ##args);\ + } \ +} while (0) + +#define FTS_TEST_SAVE_ERR(fmt, args...) do { \ + if (fts_ftest->testresult && (fts_ftest->testresult_len < TXT_BUFFER_LEN)) { \ + fts_ftest->testresult_len += snprintf( \ + fts_ftest->testresult + fts_ftest->testresult_len, \ + TXT_BUFFER_LEN, \ + fmt, ##args);\ + } \ + printk(KERN_ERR "[FTS_TS/E][TEST]%s:"fmt"\n", __func__, ##args);\ +} while (0) +#endif diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test_ini.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test_ini.c new file mode 100755 index 0000000000000000000000000000000000000000..6e72c2efb82491f8cfacc6aa8543cba1c90906d4 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test_ini.c @@ -0,0 +1,1316 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/************************************************************************ +* Copyright (C) 2012-2019, Focaltech Systems (R)£¬All Rights Reserved. +* +* File Name: focaltech_test_ini.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-01 +* +* Abstract: parsing function of INI file +* +************************************************************************/ +#include "focaltech_test.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +struct ini_ic_type ic_types[] = { + {"FT5X46", 0x54000002}, + {"FT5X46i", 0x54010002}, + {"FT5526", 0x54020002}, + {"FT3X17", 0x54030002}, + {"FT5436", 0x54040002}, + {"FT3X27", 0x54050002}, + {"FT5526i", 0x54060002}, + {"FT5416", 0x54070002}, + {"FT5426", 0x54080002}, + {"FT5435", 0x54090002}, + {"FT7681", 0x540A0002}, + {"FT7661", 0x540B0002}, + {"FT7511", 0x540C0002}, + {"FT7421", 0x540D0002}, + {"FT7311", 0x54100002}, + {"FT3327DQQ-001", 0x41000082}, + {"FT5446DQS-W01", 0x40000082}, + + {"FT5452", 0x55000081}, + {"FT3518", 0x55010081}, + {"FT3558", 0x55020081}, + {"FT3528", 0x55030081}, + {"FT5536", 0x55040081}, + + {"FT5472", 0x8F000083}, + {"FT5446U", 0x8F010083}, + {"FT5456U", 0x8F020083}, + {"FT3417U", 0x8F030083}, + {"FT5426U", 0x8F040083}, + {"FT3428", 0x8F050083}, + {"FT3437U", 0x8F060083}, + + {"FT5822", 0x58000001}, + {"FT5626", 0x58010001}, + {"FT5726", 0x58020001}, + {"FT5826B", 0x58030001}, + {"FT3617", 0x58040001}, + {"FT3717", 0x58050001}, + {"FT7811", 0x58060001}, + {"FT5826S", 0x58070001}, + {"FT3517U", 0x58090001}, + {"FT3557", 0x580A0001}, + + {"FT6X36", 0x63000003}, + {"FT3X07", 0x63010003}, + {"FT6416", 0x63020003}, + {"FT6336G/U", 0x63030003}, + {"FT7401", 0x63040003}, + {"FT3407U", 0x63050003}, + {"FT6236U", 0x63060003}, + {"FT6436U", 0x63070003}, + + {"FT3267", 0x63080004}, + {"FT3367", 0x63090004}, + + {"FT6216", 0x64000084}, + {"FT7302", 0x64010084}, + {"FT7202", 0x64020084}, + {"FT3308", 0x64030084}, + + {"FT8607", 0x81000009}, + {"FT8716", 0x82000005}, + {"FT8716U", 0x44000005}, + {"FT8716F", 0x8A000005}, + {"FT8613", 0x4500000C}, + + {"FT8736", 0x83000006}, + + {"FT8006M", 0x87000007}, + {"FT8201", 0x87010010}, + {"FT7250", 0x87020007}, + + {"FT8006U", 0x8900000B}, + {"FT8006S", 0x8901000B}, + + {"FT8719", 0x8E00000D}, + {"FT8615", 0x9100000F}, + + {"FT8739", 0x8D00000E}, + + {"FT8006P", 0x93000011}, + + {"FT7251", 0x8C000012}, + {"FT7252", 0x92000013}, + + {"FT8613S", 0x94000014}, +}; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +/* Works only for digits and letters, but small and fast */ +#define TOLOWER(x) ((x) | 0x20) +static int fts_strncmp(const char *cs, const char *ct, int count) +{ + u8 c1 = 0, c2 = 0; + + while (count) { + if ((cs == NULL) || (ct == NULL)) + return -1; + c1 = TOLOWER(*cs++); + c2 = TOLOWER(*ct++); + if (c1 != c2) + return c1 < c2 ? -1 : 1; + if (!c1) + break; + count--; + } + + return 0; +} + +static int isspace(int x) +{ + if (x == ' ' || x == '\t' || x == '\n' || x == '\f' || x == '\b' || x == '\r') + return 1; + else + return 0; +} + +static int isdigit(int x) +{ + if (x <= '9' && x >= '0') + return 1; + else + return 0; +} + +static long fts_atol(char *nptr) +{ + int c; /* current char */ + long total; /* current total */ + int sign; /* if ''-'', then negative, otherwise positive */ + /* skip whitespace */ + while ( isspace((int)(unsigned char)*nptr) ) + ++nptr; + c = (int)(unsigned char) * nptr++; + sign = c; /* save sign indication */ + if (c == '-' || c == '+') + c = (int)(unsigned char) * nptr++; /* skip sign */ + total = 0; + while (isdigit(c)) { + total = 10 * total + (c - '0'); /* accumulate digit */ + c = (int)(unsigned char) * nptr++; /* get next char */ + } + if (sign == '-') + return -total; + else + return total; /* return result, negated if necessary */ +} + +static int fts_atoi(char *nptr) +{ + return (int)fts_atol(nptr); +} + +static int fts_test_get_ini_size(char *config_name) +{ + struct file *pfile = NULL; + struct inode *inode = NULL; + off_t fsize = 0; + char filepath[128]; + + FTS_TEST_FUNC_ENTER(); + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "%s%s", FTS_INI_FILE_PATH, config_name); + + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(pfile)) { + FTS_TEST_ERROR("error occured while opening file %s.", filepath); + return -EIO; + } + +#if 1 + inode = pfile->f_inode; +#else + /* reserved for linux earlier verion */ + inode = pfile->f_dentry->d_inode; +#endif + fsize = inode->i_size; + filp_close(pfile, NULL); + + FTS_TEST_FUNC_ENTER(); + + return fsize; +} + +static int fts_test_read_ini_data(char *config_name, char *config_buf) +{ + struct file *pfile = NULL; + struct inode *inode = NULL; + off_t fsize = 0; + char filepath[128]; + loff_t pos = 0; + mm_segment_t old_fs; + + FTS_TEST_FUNC_ENTER(); + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "%s%s", FTS_INI_FILE_PATH, config_name); + if (NULL == pfile) { + pfile = filp_open(filepath, O_RDONLY, 0); + } + if (IS_ERR(pfile)) { + FTS_TEST_ERROR("error occured while opening file %s.", filepath); + return -EIO; + } + +#if 1 + inode = pfile->f_inode; +#else + /* reserved for linux earlier verion */ + inode = pfile->f_dentry->d_inode; +#endif + fsize = inode->i_size; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, config_buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + + FTS_TEST_FUNC_EXIT(); + return 0; +} + +static int fts_test_get_ini_default(struct ini_data *ini, char *fwname) +{ + int ret = 0; + int inisize = 0; + + inisize = fts_test_get_ini_size(fwname); + FTS_TEST_DBG("ini file size:%d", inisize); + if (inisize <= 0) { + FTS_TEST_ERROR("get ini file size fail"); + return -ENODATA; + } + + ini->data = vmalloc(inisize + 1); + if (NULL == ini->data) { + FTS_TEST_ERROR("malloc memory for ini data fail"); + return -ENOMEM; + } + memset(ini->data, 0, inisize + 1); + ini->length = inisize + 1; + + ret = fts_test_read_ini_data(fwname, ini->data); + if (ret) { + FTS_TEST_ERROR("read ini file fail"); + return -ENODATA; + } + ini->data[inisize] = '\n'; /* last line is null line */ + + return 0; +} + +static int fts_test_get_ini_via_request_firmware(struct ini_data *ini, char *fwname) +{ + int ret = 0; + const struct firmware *fw = NULL; + struct device *dev = &fts_data->input_dev->dev; + + ret = request_firmware(&fw, fwname, dev); + if (0 == ret) { + FTS_TEST_INFO("firmware request(%s) success", fwname); + ini->data = vmalloc(fw->size + 1); + if (NULL == ini->data) { + FTS_TEST_ERROR("ini->data buffer vmalloc fail"); + ret = -ENOMEM; + } else { + memcpy(ini->data, fw->data, fw->size); + ini->data[fw->size] = '\n'; + ini->length = fw->size + 1; + } + } else { + FTS_TEST_INFO("firmware request(%s) fail,ret=%d", fwname, ret); + } + + if (fw != NULL) { + release_firmware(fw); + fw = NULL; + } + + return ret; +} + + +static void str_space_remove(char *str) +{ + char *t = str; + char *s = str; + + while (*t != '\0') { + if (*t != ' ') { + *s = *t; + s++; + } + t++; + } + + *s = '\0'; +} + +static void print_ini_data(struct ini_data *ini) +{ + int i = 0; + int j = 0; + struct ini_section *section = NULL; + struct ini_keyword *keyword = NULL; + struct fts_test *tdata = fts_ftest; + + if (tdata && tdata->ts_data && (tdata->ts_data->log_level < 10)) { + return; + } + + if (!ini || !ini->tmp) { + FTS_TEST_DBG("ini is null"); + return; + } + + FTS_TEST_DBG("section num:%d, keyword num total:%d", + ini->section_num, ini->keyword_num_total); + for (i = 0; i < ini->section_num; i++) { + section = &ini->section[i]; + FTS_TEST_DBG("section name:[%s] keyword num:%d", + section->name, section->keyword_num); + for (j = 0; j < section->keyword_num; j++) { + keyword = §ion->keyword[j]; + FTS_TEST_DBG("%s=%s", keyword->name, keyword->value); + } + } +} + +static int ini_get_line(char *filedata, char *line_data, int *line_len) +{ + int i = 0; + int line_length = 0; + int type; + + /* get a line data */ + for (i = 0; i < MAX_INI_LINE_LEN; i++) { + if (('\n' == filedata[i]) || ('\r' == filedata[i])) { + line_data[line_length++] = '\0'; + if (('\n' == filedata[i + 1]) || ('\r' == filedata[i + 1])) { + line_length++; + } + break; + } else { + line_data[line_length++] = filedata[i]; + } + } + + if (i >= MAX_INI_LINE_LEN) { + FTS_TEST_ERROR("line length(%d)>max(%d)", line_length, MAX_INI_LINE_LEN); + return -ENODATA; + } + + /* remove space */ + str_space_remove(line_data); + + /* confirm line type */ + if (('\0' == line_data[0]) || ('#' == line_data[0])) { + type = LINE_OTHER; + } else if ('[' == line_data[0]) { + type = LINE_SECTION; + } else { + type = LINE_KEYWORD; /* key word */ + } + + *line_len = line_length; + return type; +} + +static int ini_parse_keyword(struct ini_data *ini, char *line_buffer) +{ + int i = 0; + int offset = 0; + int length = strlen(line_buffer); + struct ini_section *section = NULL; + + for (i = 0; i < length; i++) { + if (line_buffer[i] == '=') + break; + } + + if ((i == 0) || (i >= length)) { + FTS_TEST_ERROR("mark(=)in keyword line fail"); + return -ENODATA; + } + + if ((ini->section_num > 0) && (ini->section_num < MAX_INI_SECTION_NUM)) { + section = &ini->section[ini->section_num - 1]; + } + + if (NULL == section) { + FTS_TEST_ERROR("section is null"); + return -ENODATA; + } + + offset = ini->keyword_num_total; + if (offset > MAX_KEYWORD_NUM) { + FTS_TEST_ERROR("keyword num(%d)>max(%d),please check MAX_KEYWORD_NUM", + ini->keyword_num_total, MAX_KEYWORD_NUM); + return -ENODATA; + } + memcpy(ini->tmp[offset].name, &line_buffer[0], i); + ini->tmp[offset].name[i] = '\0'; + memcpy(ini->tmp[offset].value, &line_buffer[i + 1], length - i - 1); + ini->tmp[offset].value[length - i - 1] = '\0'; + section->keyword_num++; + ini->keyword_num_total++; + + return 0; +} + +static int ini_parse_section(struct ini_data *ini, char *line_buffer) +{ + int length = strlen(line_buffer); + struct ini_section *section = NULL; + + if ((length <= 2) || (length > MAX_KEYWORD_NAME_LEN)) { + FTS_TEST_ERROR("section line length fail"); + return -EINVAL; + } + + if ((ini->section_num < 0) || (ini->section_num > MAX_INI_SECTION_NUM)) { + FTS_TEST_ERROR("section_num(%d) fail", ini->section_num); + return -EINVAL; + } + section = &ini->section[ini->section_num]; + memcpy(section->name, line_buffer + 1, length - 2); + section->name[length - 2] = '\0'; + FTS_TEST_INFO("section:%s, keyword offset:%d", + section->name, ini->keyword_num_total); + section->keyword = (struct ini_keyword *)&ini->tmp[ini->keyword_num_total]; + section->keyword_num = 0; + ini->section_num++; + if (ini->section_num > MAX_INI_SECTION_NUM) { + FTS_TEST_ERROR("section num(%d)>max(%d), please check MAX_INI_SECTION_NUM", + ini->section_num, MAX_INI_SECTION_NUM); + return -ENOMEM; + } + + return 0; +} + +static int ini_init_inidata(struct ini_data *ini) +{ + int pos = 0; + int ret = 0; + char line_buffer[MAX_INI_LINE_LEN] = { 0 }; + int line_len = 0; + + if (!ini || !ini->data || !ini->tmp) { + FTS_TEST_DBG("ini/data/tmp is null"); + return -EINVAL; + } + + while (pos < ini->length) { + ret = ini_get_line(ini->data + pos, line_buffer, &line_len); + if (ret < 0) { + FTS_TEST_ERROR("ini_get_line fail"); + return ret; + } else if (ret == LINE_KEYWORD) { + ret = ini_parse_keyword(ini, line_buffer); + if (ret < 0) { + FTS_TEST_ERROR("ini_parse_keyword fail"); + return ret; + } + } else if (ret == LINE_SECTION) { + ret = ini_parse_section(ini, line_buffer); + if (ret < 0) { + FTS_TEST_ERROR("ini_parse_section fail"); + return ret; + } + } + + pos += line_len; + } + + print_ini_data(ini); + return 0; +} + +static int ini_get_key(char *section_name, char *key_name, char *value) +{ + int i = 0; + int j = 0; + struct ini_data *ini = &fts_ftest->ini; + struct ini_section *section; + struct ini_keyword *keyword; + int key_len = 0; + int log_level = fts_ftest->ts_data->log_level; + + if (log_level >= 10) { + FTS_TEST_DBG("section name:%s, key name:%s", section_name, key_name); + FTS_TEST_DBG("section num:%d", ini->section_num); + } + + for (i = 0; i < ini->section_num; i++) { + section = &ini->section[i]; + key_len = strlen(section_name); + if (key_len != strlen(section->name)) + continue; + if (fts_strncmp(section->name, section_name, key_len) != 0) + continue; + + if (log_level >= 10) { + FTS_TEST_DBG("section name:%s keyword num:%d", + section->name, section->keyword_num); + } + for (j = 0; j < section->keyword_num; j++) { + keyword = §ion->keyword[j]; + key_len = strlen(key_name); + if (key_len == strlen(keyword->name)) { + if (0 == fts_strncmp(keyword->name, key_name, key_len)) { + key_len = strlen(keyword->value); + memcpy(value, keyword->value, key_len); + if (log_level >= 3) { + FTS_TEST_DBG("section:%s,%s=%s", + section_name, key_name, value); + } + + return key_len; + } + } + } + } + + return -ENODATA; +} + +/* return keyword's value length if success */ +static int ini_get_string_value(char *section_name, char *key_name, char *rval) +{ + if (!section_name || !key_name || !rval) { + FTS_TEST_ERROR("section_name/key_name/rval is null"); + return -EINVAL; + } + + return ini_get_key(section_name, key_name, rval); +} + +int get_keyword_value(char *section, char *name, int *value) +{ + int ret = 0; + char str[MAX_KEYWORD_VALUE_LEN] = { 0 }; + + ret = ini_get_string_value(section, name, str); + if (ret > 0) { + /* search successfully, so change value, otherwise keep default */ + *value = fts_atoi(str); + } + + return ret; +} + +static void fts_init_buffer(int *buffer, int value, int len, bool key_check, int key_value, int key_len) +{ + int i = 0; + int va_len = 0; + + if (NULL == buffer) { + FTS_TEST_ERROR("buffer is null\n"); + return; + } + + va_len = len - key_len; + if (va_len < 0) { + FTS_TEST_ERROR("total len(0x%x) less key len(0x%x)\n", len, key_len); + return; + } + + for (i = 0; i < len; i++) { + buffer[i] = value; + } + + if (key_check) { + for (i = 0; i < key_len; i++) { + buffer[va_len + i] = key_value; + } + } + +} + +static int get_test_item(char name[][MAX_KEYWORD_NAME_LEN], int length, int *val) +{ + int i = 0; + int ret = 0; + int tmpval = 0; + + if (length > TEST_ITEM_COUNT_MAX) { + FTS_TEST_SAVE_ERR("test item count(%d) > max(%d)\n", + length, TEST_ITEM_COUNT_MAX); + return -EINVAL; + } + + FTS_TEST_INFO("test items in total of driver:%d", length); + *val = 0; + for (i = 0; i < length; i++) { + tmpval = 0; + ret = get_value_testitem(name[i], &tmpval); + if (ret < 0) { + FTS_TEST_DBG("test item:%s not found", name[i]); + } else { + FTS_TEST_DBG("test item:%s=%d", name[i], tmpval); + *val |= (tmpval << i); + } + } + + return 0; +} + +static int get_basic_threshold(char name[][MAX_KEYWORD_NAME_LEN], int length, int *val) +{ + int i = 0; + int ret = 0; + struct fts_test *tdata = fts_ftest; + int log_level = tdata->ts_data->log_level; + + FTS_TEST_INFO("basic_thr string length(%d), count(%d)\n", length, tdata->basic_thr_count); + if (length > fts_ftest->basic_thr_count) { + FTS_TEST_SAVE_ERR("basic_thr string length > count\n"); + return -EINVAL; + } + + for (i = 0; i < length; i++) { + ret = get_value_basic(name[i], &val[i]); + if (log_level >= 3) { + if (ret < 0) { + FTS_TEST_DBG("basic thr:%s not found", name[i]); + } else { + FTS_TEST_DBG("basic thr:%s=%d", name[i], val[i]); + } + } + } + + return 0; +} + +static void get_detail_threshold(char *key_name, bool is_prex, int *thr) +{ + char str[MAX_KEYWORD_VALUE_LEN] = { 0 }; + char str_temp[MAX_KEYWORD_NAME_LEN] = { 0 }; + char str_tmp[MAX_KEYWORD_VALUE_ONE_LEN] = { 0 }; + struct fts_test *tdata = fts_ftest; + int divider_pos = 0; + int index = 0; + int i = 0; + int j = 0; + int k = 0; + int tx_num = 0; + int rx_num = 0; + + if (!key_name || !thr) { + FTS_TEST_ERROR("key_name/thr is null"); + return; + } + + if (is_prex) { + tx_num = tdata->node.tx_num; + rx_num = tdata->node.rx_num; + } + for (i = 0; i < tx_num + 1; i++) { + if (is_prex) { + snprintf(str_temp, MAX_KEYWORD_NAME_LEN, "%s%d", key_name, (i + 1)); + } else { + snprintf(str_temp, MAX_KEYWORD_NAME_LEN, "%s", key_name); + } + divider_pos = ini_get_string_value("SpecialSet", str_temp, str); + if (divider_pos <= 0) + continue; + index = 0; + k = 0; + memset(str_tmp, 0, sizeof(str_tmp)); + for (j = 0; j < divider_pos; j++) { + if (',' == str[j]) { + thr[i * rx_num + k] = (short)(fts_atoi(str_tmp)); + index = 0; + memset(str_tmp, 0x00, sizeof(str_tmp)); + k++; + } else { + if (' ' == str[j]) + continue; + str_tmp[index] = str[j]; + index++; + } + } + } +} + +static int init_node_valid(void) +{ + char str[MAX_KEYWORD_NAME_LEN] = {0}; + int i = 0; + int j = 0; + int chy = 0; + int node_num = 0; + int cnt = 0; + struct fts_test *tdata = fts_ftest; + + if (!tdata || !tdata->node_valid || !tdata->node_valid_sc) { + FTS_TEST_ERROR("tdata/node_valid/node_valid_sc is null"); + return -EINVAL; + } + + chy = tdata->node.rx_num; + node_num = tdata->node.node_num; + fts_init_buffer(tdata->node_valid, 1 , node_num, false, 0, 0); + if ((tdata->func->hwtype == IC_HW_INCELL) || (tdata->func->hwtype == IC_HW_MC_SC)) { + for (cnt = 0; cnt < node_num; cnt++) { + i = cnt / chy + 1; + j = cnt % chy + 1; + snprintf(str, MAX_KEYWORD_NAME_LEN, "InvalidNode[%d][%d]", i, j); + get_keyword_value("INVALID_NODE", str, &tdata->node_valid[cnt]); + } + } + + if (tdata->func->hwtype == IC_HW_MC_SC) { + chy = tdata->sc_node.rx_num; + node_num = tdata->sc_node.node_num; + fts_init_buffer(tdata->node_valid_sc, 1, node_num, false, 0, 0); + + for (cnt = 0; cnt < node_num; cnt++) { + i = (cnt >= chy) ? 2 : 1; + j = (cnt >= chy) ? (cnt - chy + 1) : (cnt + 1); + snprintf(str, MAX_KEYWORD_NAME_LEN, "InvalidNodeS[%d][%d]", i, j); + get_keyword_value("INVALID_NODES", str, &tdata->node_valid_sc[cnt]); + } + } + + print_buffer(tdata->node_valid, tdata->node.node_num, tdata->node.rx_num); + print_buffer(tdata->node_valid_sc, tdata->sc_node.node_num, tdata->sc_node.rx_num); + return 0; +} + +/* incell */ +static int get_test_item_incell(void) +{ + int ret = 0; + char item_name[][MAX_KEYWORD_NAME_LEN] = TEST_ITEM_INCELL; + int length = sizeof(item_name) / MAX_KEYWORD_NAME_LEN; + int item_val = 0; + + ret = get_test_item(item_name, length, &item_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get test item fail\n"); + return ret; + } + + fts_ftest->ic.incell.u.tmp = item_val; + return 0; +} + +static char bthr_name_incell[][MAX_KEYWORD_NAME_LEN] = BASIC_THRESHOLD_INCELL; +static int get_test_threshold_incell(void) +{ + int ret = 0; + int length = sizeof(bthr_name_incell) / MAX_KEYWORD_NAME_LEN; + struct fts_test *tdata = fts_ftest; + struct incell_threshold *thr = &tdata->ic.incell.thr; + int node_num = tdata->node.node_num; + int key_num = tdata->node.key_num; + bool raw_key_check = thr->basic.rawdata_vkey_check; + bool cb_key_check = thr->basic.cb_vkey_check; + + tdata->basic_thr_count = sizeof(struct incell_threshold_b) / sizeof(int); + /* get standard basic threshold */ + ret = get_basic_threshold(bthr_name_incell, length, (int *)&thr->basic); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get basic thr fail\n"); + return ret; + } + + /* basic special set by ic */ + if (tdata->func->param_init) { + ret = tdata->func->param_init(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("special basic thr init fail\n"); + return ret; + } + } + + /* init buffer */ + fts_init_buffer(thr->rawdata_max, thr->basic.rawdata_max, node_num, raw_key_check, thr->basic.rawdata_max_vk, key_num); + fts_init_buffer(thr->rawdata_min, thr->basic.rawdata_min, node_num, raw_key_check, thr->basic.rawdata_min_vk, key_num); + if (tdata->func->rawdata2_support) { + fts_init_buffer(thr->rawdata2_max, thr->basic.rawdata2_max, node_num, false, 0, 0); + fts_init_buffer(thr->rawdata2_min, thr->basic.rawdata2_min, node_num, false, 0, 0); + } + fts_init_buffer(thr->cb_max, thr->basic.cb_max, node_num, cb_key_check, thr->basic.cb_max_vk, key_num); + fts_init_buffer(thr->cb_min, thr->basic.cb_min, node_num, cb_key_check, thr->basic.cb_min_vk, key_num); + + /* detail threshold */ + get_detail_threshold("RawData_Max_Tx", true, thr->rawdata_max); + get_detail_threshold("RawData_Min_Tx", true, thr->rawdata_min); + get_detail_threshold("CB_Max_Tx", true, thr->cb_max); + get_detail_threshold("CB_Min_Tx", true, thr->cb_min); + + return 0; +} + +static void print_thr_incell(void) +{ + struct fts_test *tdata = fts_ftest; + struct incell_threshold *thr = &tdata->ic.incell.thr; + + if (tdata->ts_data->log_level < 3) { + return; + } + + FTS_TEST_DBG("short_res_min:%d", thr->basic.short_res_min); + FTS_TEST_DBG("short_res_vk_min:%d", thr->basic.short_res_vk_min); + FTS_TEST_DBG("open_cb_min:%d", thr->basic.open_cb_min); + FTS_TEST_DBG("open_k1_check:%d", thr->basic.open_k1_check); + FTS_TEST_DBG("open_k1_value:%d", thr->basic.open_k1_value); + FTS_TEST_DBG("open_k2_check:%d", thr->basic.open_k2_check); + FTS_TEST_DBG("open_k2_value:%d", thr->basic.open_k2_value); + FTS_TEST_DBG("cb_min:%d", thr->basic.cb_min); + FTS_TEST_DBG("cb_max:%d", thr->basic.cb_max); + FTS_TEST_DBG("cb_vkey_check:%d", thr->basic.cb_vkey_check); + FTS_TEST_DBG("cb_min_vk:%d", thr->basic.cb_min_vk); + FTS_TEST_DBG("cb_max_vk:%d", thr->basic.cb_max_vk); + FTS_TEST_DBG("rawdata_min:%d", thr->basic.rawdata_min); + FTS_TEST_DBG("rawdata_max:%d", thr->basic.rawdata_max); + FTS_TEST_DBG("rawdata_vkey_check:%d", thr->basic.rawdata_vkey_check); + FTS_TEST_DBG("rawdata_min_vk:%d", thr->basic.rawdata_min_vk); + FTS_TEST_DBG("rawdata_max_vk:%d", thr->basic.rawdata_max_vk); + FTS_TEST_DBG("lcdnoise_frame:%d", thr->basic.lcdnoise_frame); + FTS_TEST_DBG("lcdnoise_coefficient:%d", thr->basic.lcdnoise_coefficient); + FTS_TEST_DBG("lcdnoise_coefficient_vkey:%d", thr->basic.lcdnoise_coefficient_vkey); + + FTS_TEST_DBG("open_nmos:%d", thr->basic.open_nmos); + FTS_TEST_DBG("keyshort_k1:%d", thr->basic.keyshort_k1); + FTS_TEST_DBG("keyshort_cb_max:%d", thr->basic.keyshort_cb_max); + FTS_TEST_DBG("rawdata2_min:%d", thr->basic.rawdata2_min); + FTS_TEST_DBG("rawdata2_max:%d", thr->basic.rawdata2_max); + + + print_buffer(thr->rawdata_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->rawdata_max, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->cb_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->cb_max, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->rawdata2_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->rawdata2_max, tdata->node.node_num, tdata->node.rx_num); +} + +static int ini_init_test_incell(void) +{ + int ret = 0; + + ret = get_test_item_incell(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get incell test item fail\n"); + return ret; + } + + + ret = get_test_threshold_incell(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get incell threshold fail\n"); + return ret; + } + + print_thr_incell(); + return 0; +} + +/* mc_sc */ +static int get_test_item_mc_sc(void) +{ + int ret = 0; + char item_name[][MAX_KEYWORD_NAME_LEN] = TEST_ITEM_MC_SC; + int length = sizeof(item_name) / MAX_KEYWORD_NAME_LEN; + int item_val = 0; + + ret = get_test_item(item_name, length, &item_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get test item fail\n"); + return ret; + } + + fts_ftest->ic.mc_sc.u.tmp = item_val; + FTS_TEST_INFO("test item:0x%x in ini", fts_ftest->ic.mc_sc.u.tmp); + return 0; +} + +static char bthr_name_mc_sc[][MAX_KEYWORD_NAME_LEN] = BASIC_THRESHOLD_MC_SC; +static int get_test_threshold_mc_sc(void) +{ + int ret = 0; + int length = sizeof(bthr_name_mc_sc) / MAX_KEYWORD_NAME_LEN; + struct fts_test *tdata = fts_ftest; + struct mc_sc_threshold *thr = &tdata->ic.mc_sc.thr; + int node_num = tdata->node.node_num; + int sc_num = tdata->sc_node.node_num; + + tdata->basic_thr_count = sizeof(struct mc_sc_threshold_b) / sizeof(int); + /* get standard basic threshold */ + ret = get_basic_threshold(bthr_name_mc_sc, length, (int *)&thr->basic); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get basic thr fail\n"); + return ret; + } + + /* basic special set by ic */ + if (tdata->func->param_init) { + ret = tdata->func->param_init(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("special basic thr init fail\n"); + return ret; + } + } + + /* init buffer */ + fts_init_buffer(thr->rawdata_h_min, thr->basic.rawdata_h_min, node_num, false, 0, 0); + fts_init_buffer(thr->rawdata_h_max, thr->basic.rawdata_h_max, node_num, false, 0, 0); + if (tdata->func->rawdata2_support) { + fts_init_buffer(thr->rawdata_l_min, thr->basic.rawdata_l_min, node_num, false, 0, 0); + fts_init_buffer(thr->rawdata_l_max, thr->basic.rawdata_l_max, node_num, false, 0, 0); + } + fts_init_buffer(thr->tx_linearity_max, thr->basic.uniformity_tx_hole, node_num, false, 0, 0); + fts_init_buffer(thr->tx_linearity_min, 0, node_num, false, 0, 0); + fts_init_buffer(thr->rx_linearity_max, thr->basic.uniformity_rx_hole, node_num, false, 0, 0); + fts_init_buffer(thr->rx_linearity_min, 0, node_num, false, 0, 0); + fts_init_buffer(thr->scap_cb_off_min, thr->basic.scap_cb_off_min, sc_num, false, 0, 0); + fts_init_buffer(thr->scap_cb_off_max, thr->basic.scap_cb_off_max, sc_num, false, 0, 0); + fts_init_buffer(thr->scap_cb_on_min, thr->basic.scap_cb_on_min, sc_num, false, 0, 0); + fts_init_buffer(thr->scap_cb_on_max, thr->basic.scap_cb_on_max, sc_num, false, 0, 0); + fts_init_buffer(thr->scap_rawdata_off_min, thr->basic.scap_rawdata_off_min, sc_num, false, 0, 0); + fts_init_buffer(thr->scap_rawdata_off_max, thr->basic.scap_rawdata_off_max, sc_num, false, 0, 0); + fts_init_buffer(thr->scap_rawdata_on_min, thr->basic.scap_rawdata_on_min, sc_num, false, 0, 0); + fts_init_buffer(thr->scap_rawdata_on_max, thr->basic.scap_rawdata_on_max, sc_num, false, 0, 0); + fts_init_buffer(thr->panel_differ_min, thr->basic.panel_differ_min, node_num, false, 0, 0); + fts_init_buffer(thr->panel_differ_max, thr->basic.panel_differ_max, node_num, false, 0, 0); + + /* detail threshold */ + get_detail_threshold("RawData_Min_High_Tx", true, thr->rawdata_h_min); + get_detail_threshold("RawData_Max_High_Tx", true, thr->rawdata_h_max); + if (tdata->func->rawdata2_support) { + get_detail_threshold("RawData_Min_Low_Tx", true, thr->rawdata_l_min); + get_detail_threshold("RawData_Max_Low_Tx", true, thr->rawdata_l_max); + } + get_detail_threshold("Tx_Linearity_Max_Tx", true, thr->tx_linearity_max); + get_detail_threshold("Rx_Linearity_Max_Tx", true, thr->rx_linearity_max); + get_detail_threshold("ScapCB_OFF_Min_", true, thr->scap_cb_off_min); + get_detail_threshold("ScapCB_OFF_Max_", true, thr->scap_cb_off_max); + get_detail_threshold("ScapCB_ON_Min_", true, thr->scap_cb_on_min); + get_detail_threshold("ScapCB_ON_Max_", true, thr->scap_cb_on_max); + get_detail_threshold("ScapRawData_OFF_Min_", true, thr->scap_rawdata_off_min); + get_detail_threshold("ScapRawData_OFF_Max_", true, thr->scap_rawdata_off_max); + get_detail_threshold("ScapRawData_ON_Min_", true, thr->scap_rawdata_on_min); + get_detail_threshold("ScapRawData_ON_Max_", true, thr->scap_rawdata_on_max); + get_detail_threshold("Panel_Differ_Min_Tx", true, thr->panel_differ_min); + get_detail_threshold("Panel_Differ_Max_Tx", true, thr->panel_differ_max); + + return 0; +} + +static void print_thr_mc_sc(void) +{ + struct fts_test *tdata = fts_ftest; + struct mc_sc_threshold *thr = &tdata->ic.mc_sc.thr; + + if (tdata->ts_data->log_level < 3) { + return; + } + + FTS_TEST_DBG("rawdata_h_min:%d", thr->basic.rawdata_h_min); + FTS_TEST_DBG("rawdata_h_max:%d", thr->basic.rawdata_h_max); + FTS_TEST_DBG("rawdata_set_hfreq:%d", thr->basic.rawdata_set_hfreq); + FTS_TEST_DBG("rawdata_l_min:%d", thr->basic.rawdata_l_min); + FTS_TEST_DBG("rawdata_l_max:%d", thr->basic.rawdata_l_max); + FTS_TEST_DBG("rawdata_set_lfreq:%d", thr->basic.rawdata_set_lfreq); + FTS_TEST_DBG("uniformity_check_tx:%d", thr->basic.uniformity_check_tx); + FTS_TEST_DBG("uniformity_check_rx:%d", thr->basic.uniformity_check_rx); + FTS_TEST_DBG("uniformity_check_min_max:%d", thr->basic.uniformity_check_min_max); + FTS_TEST_DBG("uniformity_tx_hole:%d", thr->basic.uniformity_tx_hole); + FTS_TEST_DBG("uniformity_rx_hole:%d", thr->basic.uniformity_rx_hole); + FTS_TEST_DBG("uniformity_min_max_hole:%d", thr->basic.uniformity_min_max_hole); + FTS_TEST_DBG("scap_cb_off_min:%d", thr->basic.scap_cb_off_min); + FTS_TEST_DBG("scap_cb_off_max:%d", thr->basic.scap_cb_off_max); + FTS_TEST_DBG("scap_cb_wp_off_check:%d", thr->basic.scap_cb_wp_off_check); + FTS_TEST_DBG("scap_cb_on_min:%d", thr->basic.scap_cb_on_min); + FTS_TEST_DBG("scap_cb_on_max:%d", thr->basic.scap_cb_on_max); + FTS_TEST_DBG("scap_cb_wp_on_check:%d", thr->basic.scap_cb_wp_on_check); + FTS_TEST_DBG("scap_rawdata_off_min:%d", thr->basic.scap_rawdata_off_min); + FTS_TEST_DBG("scap_rawdata_off_max:%d", thr->basic.scap_rawdata_off_max); + FTS_TEST_DBG("scap_rawdata_wp_off_check:%d", thr->basic.scap_rawdata_wp_off_check); + FTS_TEST_DBG("scap_rawdata_on_min:%d", thr->basic.scap_rawdata_on_min); + FTS_TEST_DBG("scap_rawdata_on_max:%d", thr->basic.scap_rawdata_on_max); + FTS_TEST_DBG("scap_rawdata_wp_on_check:%d", thr->basic.scap_rawdata_wp_on_check); + FTS_TEST_DBG("short_cg:%d", thr->basic.short_cg); + FTS_TEST_DBG("short_cc:%d", thr->basic.short_cc); + FTS_TEST_DBG("panel_differ_min:%d", thr->basic.panel_differ_min); + FTS_TEST_DBG("panel_differ_max:%d", thr->basic.panel_differ_max); + + print_buffer(thr->rawdata_h_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->rawdata_h_max, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->rawdata_l_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->rawdata_l_max, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->scap_cb_off_min, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->scap_cb_off_max, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->scap_cb_on_min, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->scap_cb_on_max, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->scap_rawdata_off_min, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->scap_rawdata_off_max, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->scap_rawdata_on_min, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->scap_rawdata_on_max, tdata->sc_node.node_num, tdata->sc_node.rx_num); + print_buffer(thr->panel_differ_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->panel_differ_max, tdata->node.node_num, tdata->node.rx_num); +} + +static int ini_init_test_mc_sc(void) +{ + int ret = 0; + + ret = get_test_item_mc_sc(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get mc_sc test item fail\n"); + return ret; + } + + ret = get_test_threshold_mc_sc(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get mc_sc threshold fail\n"); + return ret; + } + + print_thr_mc_sc(); + return 0; +} + +/* sc */ +static int get_test_item_sc(void) +{ + int ret = 0; + char item_name[][MAX_KEYWORD_NAME_LEN] = TEST_ITEM_SC; + int length = sizeof(item_name) / MAX_KEYWORD_NAME_LEN; + int item_val = 0; + + ret = get_test_item(item_name, length, &item_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get test item fail\n"); + return ret; + } + + fts_ftest->ic.sc.u.tmp = item_val; + return 0; +} + +static char bthr_name_sc[][MAX_KEYWORD_NAME_LEN] = BASIC_THRESHOLD_SC; +static int get_test_threshold_sc(void) +{ + int ret = 0; + int length = sizeof(bthr_name_sc) / MAX_KEYWORD_NAME_LEN; + struct fts_test *tdata = fts_ftest; + struct sc_threshold *thr = &tdata->ic.sc.thr; + int node_num = tdata->node.node_num; + + tdata->basic_thr_count = sizeof(struct sc_threshold_b) / sizeof(int); + /* get standard basic threshold */ + ret = get_basic_threshold(bthr_name_sc, length, (int *)&thr->basic); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get basic thr fail\n"); + return ret; + } + + /* basic special set by ic */ + if (tdata->func->param_init) { + ret = tdata->func->param_init(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("special basic thr init fail\n"); + return ret; + } + } + + /* init buffer */ + fts_init_buffer(thr->rawdata_min, thr->basic.rawdata_min, node_num, false, 0, 0); + fts_init_buffer(thr->rawdata_max, thr->basic.rawdata_max, node_num, false, 0, 0); + fts_init_buffer(thr->cb_min, thr->basic.cb_min, node_num, false, 0, 0); + fts_init_buffer(thr->cb_max, thr->basic.cb_max, node_num, false, 0, 0); + fts_init_buffer(thr->dcb_sort, 0, node_num, false, 0, 0); + fts_init_buffer(thr->dcb_base, thr->basic.dcb_base, node_num, false, 0, 0); + + /* detail threshold */ + get_detail_threshold("RawDataTest_Min", false, thr->rawdata_min); + get_detail_threshold("RawDataTest_Max", false, thr->rawdata_max); + get_detail_threshold("CbTest_Min", false, thr->cb_min); + get_detail_threshold("CbTest_Max", false, thr->cb_max); + get_detail_threshold("DeltaCxTest_Sort", false, thr->dcb_sort); + get_detail_threshold("DeltaCbTest_Base", false, thr->dcb_base); + + return 0; +} + +static void print_thr_sc(void) +{ + struct fts_test *tdata = fts_ftest; + struct sc_threshold *thr = &tdata->ic.sc.thr; + + if (tdata->ts_data->log_level < 3) { + return; + } + + FTS_TEST_DBG("rawdata_min:%d", thr->basic.rawdata_min); + FTS_TEST_DBG("rawdata_max:%d", thr->basic.rawdata_max); + FTS_TEST_DBG("cb_min:%d", thr->basic.cb_min); + FTS_TEST_DBG("cb_max:%d", thr->basic.cb_max); + FTS_TEST_DBG("dcb_differ_max:%d", thr->basic.dcb_differ_max); + FTS_TEST_DBG("dcb_key_check:%d", thr->basic.dcb_key_check); + FTS_TEST_DBG("dcb_key_differ_max:%d", thr->basic.dcb_key_differ_max); + FTS_TEST_DBG("dcb_ds1:%d", thr->basic.dcb_ds1); + FTS_TEST_DBG("dcb_ds2:%d", thr->basic.dcb_ds2); + FTS_TEST_DBG("dcb_ds3:%d", thr->basic.dcb_ds3); + FTS_TEST_DBG("dcb_ds4:%d", thr->basic.dcb_ds4); + FTS_TEST_DBG("dcb_ds5:%d", thr->basic.dcb_ds5); + FTS_TEST_DBG("dcb_ds6:%d", thr->basic.dcb_ds6); + FTS_TEST_DBG("dcb_critical_check:%d", thr->basic.dcb_critical_check); + FTS_TEST_DBG("dcb_cs1:%d", thr->basic.dcb_cs1); + FTS_TEST_DBG("dcb_cs2:%d", thr->basic.dcb_cs2); + FTS_TEST_DBG("dcb_cs3:%d", thr->basic.dcb_cs3); + FTS_TEST_DBG("dcb_cs4:%d", thr->basic.dcb_cs4); + FTS_TEST_DBG("dcb_cs5:%d", thr->basic.dcb_cs5); + FTS_TEST_DBG("dcb_cs6:%d", thr->basic.dcb_cs6); + + print_buffer(thr->rawdata_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->rawdata_max, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->cb_min, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->cb_max, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->dcb_sort, tdata->node.node_num, tdata->node.rx_num); + print_buffer(thr->dcb_base, tdata->node.node_num, tdata->node.rx_num); +} + +static int ini_init_test_sc(void) +{ + int ret = 0; + + ret = get_test_item_sc(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get sc test item fail\n"); + return ret; + } + + ret = get_test_threshold_sc(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get sc threshold fail\n"); + return ret; + } + + print_thr_sc(); + return 0; +} + +static u32 ini_get_ic_code(char *ic_name) +{ + int i = 0; + int type_size = 0; + int ini_icname_len = 0; + int ic_types_len = 0; + + ini_icname_len = strlen(ic_name); + type_size = sizeof(ic_types) / sizeof(ic_types[0]); + for (i = 0; i < type_size; i++) { + ic_types_len = strlen(ic_name); + if (ini_icname_len == ic_types_len) { + if (0 == strncmp(ic_name, ic_types[i].ic_name, ic_types_len)) + return ic_types[i].ic_type; + } + } + + FTS_TEST_ERROR("no IC type match"); + return 0; +} + + +static void ini_init_interface(struct ini_data *ini) +{ + char str[MAX_KEYWORD_VALUE_LEN] = { 0 }; + u32 value = 0; + struct fts_test *tdata = fts_ftest; + + /* IC type */ + ini_get_string_value("Interface", "IC_Type", str); + snprintf(ini->ic_name, MAX_IC_NAME_LEN, "%s", str); + + value = ini_get_ic_code(str); + ini->ic_code = value; + FTS_TEST_INFO("ic name:%s, ic code:%x", ini->ic_name, ini->ic_code); + + if (IC_HW_MC_SC == tdata->func->hwtype) { + get_value_interface("Normalize_Type", &value); + tdata->normalize = (u8)value; + FTS_TEST_DBG("normalize:%d", tdata->normalize); + } +} + +static int ini_init_test(struct ini_data *ini) +{ + int ret = 0; + struct fts_test *tdata = fts_ftest; + + /* interface init */ + ini_init_interface(ini); + + /* node valid */ + ret = init_node_valid(); + if (ret < 0) { + FTS_TEST_ERROR("init node valid fail"); + return ret; + } + + switch (tdata->func->hwtype) { + case IC_HW_INCELL: + ret = ini_init_test_incell(); + break; + case IC_HW_MC_SC: + ret = ini_init_test_mc_sc(); + break; + case IC_HW_SC: + ret = ini_init_test_sc(); + break; + default: + FTS_TEST_SAVE_ERR("test ic type(%d) fail\n", tdata->func->hwtype); + ret = -EINVAL; + break; + } + + return ret; +} + +/* + * fts_test_get_testparam_from_ini - get test parameters from ini + * + * read, parse the configuration file, initialize the test variable + * + * return 0 if succuss, else errro code + */ +int fts_test_get_testparam_from_ini(char *config_name) +{ + int ret = 0; + struct ini_data *ini = &fts_ftest->ini; + + ret = fts_test_get_ini_via_request_firmware(ini, config_name); + if (ret != 0) { + ret = fts_test_get_ini_default(ini, config_name); + if (ret < 0) { + FTS_TEST_ERROR("get ini(default) fail"); + goto get_ini_err; + } + } + + ini->keyword_num_total = 0; + ini->section_num = 0; + + ini->tmp = vmalloc(sizeof(struct ini_keyword) * MAX_KEYWORD_NUM); + if (NULL == ini->tmp) { + FTS_TEST_ERROR("malloc memory for ini tmp fail"); + ret = -ENOMEM; + goto get_ini_err; + } + memset(ini->tmp, 0, sizeof(struct ini_keyword) * MAX_KEYWORD_NUM); + + /* parse ini data to get keyword name&value */ + ret = ini_init_inidata(ini); + if (ret < 0) { + FTS_TEST_ERROR("ini_init_inidata fail"); + goto get_ini_err; + } + + /* parse threshold & test item */ + ret = ini_init_test(ini); + if (ret < 0) { + FTS_TEST_ERROR("ini init fail"); + goto get_ini_err; + } + + ret = 0; +get_ini_err: + if (ini->tmp) { + vfree(ini->tmp); + ini->tmp = NULL; + } + + if (ini->data) { + vfree(ini->data); + ini->data = NULL; + } + + return ret; +} diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test_ini.h b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test_ini.h new file mode 100755 index 0000000000000000000000000000000000000000..1f6e977397e52b010e9f0dc25e6e5c77ef96d7f3 --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/focaltech_test_ini.h @@ -0,0 +1,140 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/************************************************************************ +* Copyright (C) 2012-2019, Focaltech Systems (R)£¬All Rights Reserved. +* +* File Name: focaltech_test_ini.h +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-01 +* +* Abstract: parsing function of INI file +* +************************************************************************/ +#ifndef _INI_H +#define _INI_H +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define MAX_KEYWORD_NUM (1000) +#define MAX_KEYWORD_NAME_LEN (50) +#define MAX_KEYWORD_VALUE_LEN (512) +#define MAX_KEYWORD_VALUE_ONE_LEN (16) +#define MAX_INI_LINE_LEN (MAX_KEYWORD_NAME_LEN + MAX_KEYWORD_VALUE_LEN) +#define MAX_INI_SECTION_NUM (20) +#define MAX_IC_NAME_LEN (32) +#define MAX_TEST_ITEM (20) +#define IC_CODE_OFFSET (16) + +/***************************************************************************** +* enumerations, structures and unions +*****************************************************************************/ +struct ini_ic_type { + char ic_name[MAX_IC_NAME_LEN]; + u32 ic_type; +}; + +enum line_type { + LINE_SECTION = 1, + LINE_KEYWORD = 2 , + LINE_OTHER = 3, +}; + +struct ini_keyword { + char name[MAX_KEYWORD_NAME_LEN]; + char value[MAX_KEYWORD_VALUE_LEN]; +}; + +struct ini_section { + char name[MAX_KEYWORD_NAME_LEN]; + int keyword_num; + /* point to ini.tmp, don't need free */ + struct ini_keyword *keyword; +}; + +struct ini_data { + char *data; + int length; + int keyword_num_total; + int section_num; + struct ini_section section[MAX_INI_SECTION_NUM]; + struct ini_keyword *tmp; + char ic_name[MAX_IC_NAME_LEN]; + u32 ic_code; +}; + +#define TEST_ITEM_INCELL { \ + "SHORT_CIRCUIT_TEST", \ + "OPEN_TEST", \ + "CB_TEST", \ + "RAWDATA_TEST", \ + "LCD_NOISE_TEST", \ + "KEY_SHORT_TEST", \ +} + +#define BASIC_THRESHOLD_INCELL { \ + "ShortCircuit_ResMin", "ShortCircuit_VkResMin", \ + "OpenTest_CBMin", "OpenTest_Check_K1", "OpenTest_K1Threshold", "OpenTest_Check_K2", "OpenTest_K2Threshold", \ + "CBTest_Min", "CBTest_Max", \ + "CBTest_VKey_Check", "CBTest_Min_Vkey", "CBTest_Max_Vkey", \ + "RawDataTest_Min", "RawDataTest_Max", \ + "RawDataTest_VKey_Check", "RawDataTest_Min_VKey", "RawDataTest_Max_VKey", \ + "LCD_NoiseTest_Frame", "LCD_NoiseTest_Coefficient", "LCD_NoiseTest_Coefficient_key", \ +} + + +#define TEST_ITEM_MC_SC { \ + "RAWDATA_TEST", \ + "UNIFORMITY_TEST", \ + "SCAP_CB_TEST", \ + "SCAP_RAWDATA_TEST", \ + "WEAK_SHORT_CIRCUIT_TEST", \ + "PANEL_DIFFER_TEST", \ +} + +#define BASIC_THRESHOLD_MC_SC { \ + "RawDataTest_High_Min", "RawDataTest_High_Max", "RawDataTest_HighFreq", \ + "RawDataTest_Low_Min", "RawDataTest_Low_Max", "RawDataTest_LowFreq", \ + "UniformityTest_Check_Tx", "UniformityTest_Check_Rx","UniformityTest_Check_MinMax", \ + "UniformityTest_Tx_Hole", "UniformityTest_Rx_Hole", "UniformityTest_MinMax_Hole", \ + "SCapCbTest_OFF_Min", "SCapCbTest_OFF_Max", "ScapCBTest_SetWaterproof_OFF", \ + "SCapCbTest_ON_Min", "SCapCbTest_ON_Max", "ScapCBTest_SetWaterproof_ON", \ + "SCapRawDataTest_OFF_Min", "SCapRawDataTest_OFF_Max", "SCapRawDataTest_SetWaterproof_OFF", \ + "SCapRawDataTest_ON_Min", "SCapRawDataTest_ON_Max", "SCapRawDataTest_SetWaterproof_ON", \ + "WeakShortTest_CG", "WeakShortTest_CC", \ + "PanelDifferTest_Min", "PanelDifferTest_Max", \ +} + +#define TEST_ITEM_SC { \ + "CB_TEST", \ + "DELTA_CB_TEST", \ + "RAWDATA_TEST", \ +} + +#define BASIC_THRESHOLD_SC { \ + "RawDataTest_Min", "RawDataTest_Max", \ + "CbTest_Min", "CbTest_Max", \ + "DeltaCbTest_Base", "DeltaCbTest_Differ_Max", \ + "DeltaCbTest_Include_Key_Test", "DeltaCbTest_Key_Differ_Max", \ + "DeltaCbTest_Deviation_S1", "DeltaCbTest_Deviation_S2", "DeltaCbTest_Deviation_S3", \ + "DeltaCbTest_Deviation_S4", "DeltaCbTest_Deviation_S5", "DeltaCbTest_Deviation_S6", \ + "DeltaCbTest_Set_Critical", "DeltaCbTest_Critical_S1", "DeltaCbTest_Critical_S2", \ + "DeltaCbTest_Critical_S3", "DeltaCbTest_Critical_S4", \ + "DeltaCbTest_Critical_S5", "DeltaCbTest_Critical_S6", \ +} + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +int fts_test_get_testparam_from_ini(char *config_name); +int get_keyword_value(char *section, char *name, int *value); + +#define get_value_interface(name, value) \ + get_keyword_value("Interface", name, value) +#define get_value_basic(name, value) \ + get_keyword_value("Basic_Threshold", name, value) +#define get_value_detail(name, value) \ + get_keyword_value("SpecialSet", name, value) +#define get_value_testitem(name, value) \ + get_keyword_value("TestItem", name, value) +#endif /* _INI_H */ diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/supported_ic/Makefile b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/supported_ic/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..fba54030a01fd6270459b4a6bf0fb171e10cfc3e --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/supported_ic/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_test_ft8716.o diff --git a/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/supported_ic/focaltech_test_ft8716.c b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/supported_ic/focaltech_test_ft8716.c new file mode 100755 index 0000000000000000000000000000000000000000..7d75b51aa03bedd8c3eab4a829f614ca1e4cddae --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/focaltech_test/supported_ic/focaltech_test_ft8716.c @@ -0,0 +1,619 @@ +/* Copyright (C) 2019 Tcl Corporation Limited */ +/************************************************************************ +* Copyright (C) 2012-2019, Focaltech Systems (R), All Rights Reserved. +* +* File Name: Focaltech_test_ft8716.c +* +* Author: Focaltech Driver Team +* +* Created: 2017-12-01 +* +* Abstract: +* +************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "../focaltech_test.h" + +/******************************************************************************* +* Private constant and macro definitions using #define +*******************************************************************************/ +#define CODE2_SHORT_TEST 14 +#define CODE2_OPEN_TEST 24 +#define CODE2_LCD_NOISE_TEST 15 + +/******************************************************************************* +* Private enumerations, structures and unions using typedef +*******************************************************************************/ + +/******************************************************************************* +* Static variables +*******************************************************************************/ + +/******************************************************************************* +* Global variable or extern global variabls/functions +*******************************************************************************/ + +/******************************************************************************* +* Static function prototypes +*******************************************************************************/ +static int ft8716_short_test(struct fts_test *tdata, bool *test_result) +{ + int ret = 0; + int i = 0; + bool tmp_result = false; + int byte_num = 0; + int ch_num = 0; + int min = 0; + int max = 0; + int tmp_adc = 0; + int *adcdata = NULL; + struct incell_threshold *thr = &tdata->ic.incell.thr; + + FTS_TEST_FUNC_ENTER(); + FTS_TEST_SAVE_INFO("\n============ Test Item: Short Circuit Test\n"); + memset(tdata->buffer, 0, tdata->buffer_length); + adcdata = tdata->buffer; + + ret = enter_factory_mode(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("enter factory mode fail,ret=%d\n", ret); + goto test_err; + } + + byte_num = tdata->node.node_num * 2; + ch_num = tdata->node.rx_num; + ret = short_get_adcdata_incell(TEST_RETVAL_AA, ch_num, byte_num, adcdata); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get adc data fail\n"); + goto test_err; + } + + /* calculate resistor */ + for (i = 0; i < tdata->node.node_num; i++) { + tmp_adc = adcdata[i]; + if (tmp_adc < 50) { + adcdata[i] = -1; + continue; + } else if (tmp_adc < 200) { + tmp_adc = 200; + } + + adcdata[i] = 252000 / (tmp_adc - 120) - 60; + } + + /* save */ + show_data(adcdata, true); + + /* compare */ + min = thr->basic.short_res_min; + max = TEST_SHORT_RES_MAX; + tmp_result = compare_data(adcdata, min, max, min, max, true); + + ret = 0; +test_err: + if (tmp_result) { + *test_result = true; + FTS_TEST_SAVE_INFO("------ Short Circuit Test PASS\n"); + } else { + *test_result = false; + FTS_TEST_SAVE_INFO("------ Short Circuit Test NG\n"); + } + + /*save test data*/ + fts_test_save_data("Short Circuit Test", CODE2_SHORT_TEST, + adcdata, 0, false, true, *test_result); + FTS_TEST_FUNC_EXIT(); + return ret; +} + +static int ft8716_open_test(struct fts_test *tdata, bool *test_result) +{ + int ret = 0; + bool tmp_result = false; + int byte_num = 0; + u8 reg20_val = 0; + u8 reg21_val = 0; + u8 k1 = 0; + u8 k2 = 0; + int min = 0; + int max = 0; + int *opendata = NULL; + struct incell_threshold *thr = &tdata->ic.incell.thr; + + FTS_TEST_FUNC_ENTER(); + FTS_TEST_SAVE_INFO("\n============ Test Item: Open Test\n"); + memset(tdata->buffer, 0, tdata->buffer_length); + opendata = tdata->buffer; + + ret = enter_factory_mode(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("enter factory mode fail,ret=%d\n", ret); + goto test_err; + } + + /* backup defaul value */ + ret = fts_test_read_reg(FACTORY_REG_OPEN_REG20, ®20_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read reg 0x20 fail\n"); + goto test_err; + } + ret = fts_test_read_reg(FACTORY_REG_OPEN_REG21, ®21_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read reg 0x21 fail\n"); + goto test_err; + } + if (thr->basic.open_k1_check) { + ret = fts_test_read_reg(FACTORY_REG_K1, &k1); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read k1 fail\n"); + goto test_err; + } + } + if (thr->basic.open_k2_check) { + ret = fts_test_read_reg(FACTORY_REG_K2, &k2); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read k2 fail\n"); + goto test_err; + } + } + + /* open test enable */ + ret = fts_test_write_reg(FACTORY_REG_OPEN_TEST_EN, 0x01); + if (ret < 0) { + FTS_TEST_SAVE_ERR("open test enable fail\n"); + goto test_err; + } + + /* set open test environment */ + ret = fts_test_write_reg(FACTORY_REG_OPEN_REG20, 0x01); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write reg 0x20 fail\n"); + goto restore_reg; + } + + ret = fts_test_write_reg(FACTORY_REG_OPEN_REG21, 0x01); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write reg 0x21 fail\n"); + goto restore_reg; + } + + if (thr->basic.open_k1_check) { + ret = fts_test_write_reg(FACTORY_REG_K1, thr->basic.open_k1_value); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write reg k1 fail\n"); + goto restore_reg; + } + } + + if (thr->basic.open_k2_check) { + ret = fts_test_write_reg(FACTORY_REG_K2, thr->basic.open_k2_value); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write reg k2 fail\n"); + goto restore_reg; + } + } + + /* wait fw state update before clb */ + ret = wait_state_update(TEST_RETVAL_00); + if (ret < 0) { + FTS_TEST_SAVE_ERR("wait state update fail\n"); + goto restore_reg; + } + /* auto clb */ + ret = chip_clb(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("auto clb fail\n"); + goto restore_reg; + } + + /* get cb data */ + byte_num = tdata->node.tx_num * tdata->node.rx_num; + ret = get_cb_incell(0, byte_num, opendata); + if (ret) { + FTS_TEST_SAVE_ERR("get CB fail\n"); + goto restore_reg; + } + + /* save */ + show_data(opendata, false); + + /* compare */ + min = thr->basic.open_cb_min; + max = TEST_OPEN_MAX_VALUE; + tmp_result = compare_data(opendata, min, max, 0, 0, false); + +restore_reg: + ret = fts_test_write_reg(FACTORY_REG_OPEN_REG20, reg20_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("restore reg 0x20 fail\n"); + } + + ret = fts_test_write_reg(FACTORY_REG_OPEN_REG21, reg21_val); + if (ret < 0) { + FTS_TEST_SAVE_ERR("restore reg 0x21 fail\n"); + } + + if (thr->basic.open_k1_check) { + ret = fts_test_write_reg(FACTORY_REG_K1, k1); + if (ret < 0) { + FTS_TEST_SAVE_ERR("restore reg k1 fail\n"); + } + } + + if (thr->basic.open_k2_check) { + ret = fts_test_write_reg(FACTORY_REG_K2, k2); + if (ret < 0) { + FTS_TEST_SAVE_ERR("restore reg k2 fail\n"); + } + } + + /* open test disable */ + ret = fts_test_write_reg(FACTORY_REG_OPEN_TEST_EN, 0x00); + if (ret < 0) { + FTS_TEST_SAVE_ERR("open test disable fail\n"); + } + + /* wait fw state update before clb */ + ret = wait_state_update(TEST_RETVAL_00); + if (ret < 0) { + FTS_TEST_SAVE_ERR("wait state update fail\n"); + } + /* auto clb */ + ret = chip_clb(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("auto clb fail\n"); + } + +test_err: + if (tmp_result) { + *test_result = true; + FTS_TEST_SAVE_INFO("------ Open Test PASS\n"); + } else { + *test_result = false; + FTS_TEST_SAVE_INFO("------ Open Test NG\n"); + } + + /* save test data */ + fts_test_save_data("Open Test", CODE2_OPEN_TEST, + opendata, 0, false, false, *test_result); + + FTS_TEST_FUNC_EXIT(); + return ret; +} + +static int ft8716_cb_test(struct fts_test *tdata, bool *test_result) +{ + int ret = 0; + bool tmp_result = false; + bool key_check = false; + int byte_num = 0; + int *cbdata = NULL; + struct incell_threshold *thr = &tdata->ic.incell.thr; + + FTS_TEST_FUNC_ENTER(); + FTS_TEST_SAVE_INFO("\n============ Test Item: CB Test\n"); + memset(tdata->buffer, 0, tdata->buffer_length); + cbdata = tdata->buffer; + key_check = thr->basic.cb_vkey_check; + + if (!thr->cb_min || !thr->cb_max || !test_result) { + FTS_TEST_SAVE_ERR("cb_min/max test_result is null\n"); + ret = -EINVAL; + goto test_err; + } + + ret = enter_factory_mode(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("enter factory mode fail,ret=%d\n", ret); + goto test_err; + } + + /* cb test enable */ + ret = fts_test_write_reg(FACTORY_REG_CB_TEST_EN, 0x01); + if (ret < 0) { + FTS_TEST_SAVE_ERR("cb test enable fail\n"); + goto test_err; + } + + /* auto clb */ + ret = chip_clb(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("auto clb fail\n"); + goto test_err; + } + + byte_num = tdata->node.node_num; + ret = get_cb_incell(0, byte_num, cbdata); + if (ret < 0) { + FTS_TEST_SAVE_ERR("get cb fail\n"); + goto test_err; + } + + /* save */ + show_data(cbdata, key_check); + + /* compare */ + tmp_result = compare_array(cbdata, thr->cb_min, thr->cb_max, key_check); + +test_err: + /* cb test disable */ + ret = fts_test_write_reg(FACTORY_REG_CB_TEST_EN, 0x00); + if (ret < 0) { + FTS_TEST_SAVE_ERR("cb test disable fail\n"); + } + + if (tmp_result) { + *test_result = true; + FTS_TEST_SAVE_INFO("------ CB Test PASS\n"); + } else { + *test_result = false; + FTS_TEST_SAVE_INFO("------ CB Test NG\n"); + } + + /* save test data */ + fts_test_save_data("CB Test", CODE_CB_TEST, + cbdata, 0, false, key_check, *test_result); + + FTS_TEST_FUNC_EXIT(); + return ret; +} + +static int ft8716_rawdata_test(struct fts_test *tdata, bool *test_result) +{ + int ret = 0; + int i = 0; + bool tmp_result = false; + bool key_check = false; + int *rawdata = NULL; + struct incell_threshold *thr = &tdata->ic.incell.thr; + + FTS_TEST_FUNC_ENTER(); + FTS_TEST_SAVE_INFO("\n============ Test Item: RawData Test\n"); + memset(tdata->buffer, 0, tdata->buffer_length); + rawdata = tdata->buffer; + key_check = thr->basic.rawdata_vkey_check; + + if (!thr->rawdata_min || !thr->rawdata_max || !test_result) { + FTS_TEST_SAVE_ERR("rawdata_min/max test_result is null\n"); + ret = -EINVAL; + goto test_err; + } + + ret = enter_factory_mode(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("enter factory mode fail,ret=%d\n", ret); + goto test_err; + } + + /* rawdata test enable */ + ret = fts_test_write_reg(FACTORY_REG_RAWDATA_TEST_EN, 0x01); + if (ret < 0) { + FTS_TEST_SAVE_ERR("rawdata test enable fail\n"); + goto test_err; + } + + /* read rawdata */ + for (i = 0 ; i < 3; i++) { + ret = get_rawdata(rawdata); + } + if (ret < 0) { + FTS_TEST_SAVE_ERR("get RawData fail,ret=%d\n", ret); + goto test_err; + } + + /* save */ + show_data(rawdata, key_check); + + /* compare */ + tmp_result = compare_array(rawdata, + thr->rawdata_min, + thr->rawdata_max, + key_check); + +test_err: + /* rawdata test disble */ + ret = fts_test_write_reg(FACTORY_REG_RAWDATA_TEST_EN, 0x00); + if (ret < 0) { + FTS_TEST_SAVE_ERR("rawdata test disable fail\n"); + } + + if (tmp_result) { + *test_result = true; + FTS_TEST_SAVE_INFO("------ RawData Test PASS\n"); + } else { + *test_result = false; + FTS_TEST_SAVE_INFO("------ RawData Test NG\n"); + } + + /* save test data */ + fts_test_save_data("RawData Test", CODE_RAWDATA_TEST, + rawdata, 0, false, key_check, *test_result); + + FTS_TEST_FUNC_EXIT(); + return ret; +} + +static int ft8716_lcdnoise_test(struct fts_test *tdata, bool *test_result) +{ + int ret = 0; + int i = 0; + bool tmp_result = false; + int byte_num = 0; + u8 old_mode = 0; + u8 status = 0; + int frame_num = 0; + int max = 0; + int max_vk = 0; + int *lcdnoise = NULL; + struct incell_threshold *thr = &tdata->ic.incell.thr; + + FTS_TEST_FUNC_ENTER(); + FTS_TEST_SAVE_INFO("\n============ Test Item: LCD Noise Test\n"); + memset(tdata->buffer, 0, tdata->buffer_length); + lcdnoise = tdata->buffer; + + ret = enter_factory_mode(); + if (ret < 0) { + FTS_TEST_SAVE_ERR("enter factory mode fail,ret=%d\n", ret); + goto test_err; + } + + ret = fts_test_read_reg(FACTORY_REG_DATA_SELECT, &old_mode); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read reg06 fail\n"); + goto test_err; + } + + ret = fts_test_write_reg(FACTORY_REG_DATA_SELECT, 0x01); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write 1 to reg06 fail\n"); + goto restore_reg; + } + + ret = fts_test_write_reg(FACTORY_REG_LINE_ADDR, 0xAD); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write reg01 fail\n"); + goto restore_reg; + } + + frame_num = thr->basic.lcdnoise_frame; + ret = fts_test_write_reg(FACTORY_REG_LCD_NOISE_FRAME, frame_num / 4); + if (ret < 0) { + FTS_TEST_SAVE_INFO("write frame num fail\n"); + goto restore_reg; + } + + /* start test */ + ret = fts_test_write_reg(FACTORY_REG_LCD_NOISE_START, 0x01); + if (ret < 0) { + FTS_TEST_SAVE_INFO("start lcdnoise test fail\n"); + goto restore_reg; + } + + /* check test status */ + sys_delay(frame_num * FACTORY_TEST_DELAY / 2); + for (i = 0; i < FACTORY_TEST_RETRY; i++) { + status = 0xFF; + ret = fts_test_read_reg(FACTORY_REG_LCD_NOISE_START, &status); + if ((ret >= 0) && (TEST_RETVAL_AA == status)) { + break; + } else { + FTS_TEST_DBG("reg%x=%x,retry:%d\n", + FACTORY_REG_LCD_NOISE_START, status, i); + } + sys_delay(FACTORY_TEST_RETRY_DELAY); + } + if (i >= FACTORY_TEST_RETRY) { + FTS_TEST_SAVE_ERR("lcdnoise test timeout\n"); + goto restore_reg; + } + /* read lcdnoise */ + byte_num = tdata->node.node_num * 2; + ret = read_mass_data(FACTORY_REG_RAWDATA_ADDR, byte_num, lcdnoise); + if (ret < 0) { + FTS_TEST_SAVE_ERR("read rawdata fail\n"); + goto restore_reg; + } + + /* save */ + show_data(lcdnoise, true); + + /* compare */ + max = thr->basic.lcdnoise_coefficient * tdata->va_touch_thr * 32 / 100; + max_vk = thr->basic.lcdnoise_coefficient_vkey * tdata->vk_touch_thr * 32 / 100; + tmp_result = compare_data(lcdnoise, 0, max, 0, max_vk, true); + +restore_reg: + ret = fts_test_write_reg(FACTORY_REG_LCD_NOISE_START, 0x00); + if (ret < 0) { + FTS_TEST_SAVE_ERR("write 0 to reg11 fail\n"); + } + + ret = fts_test_write_reg(FACTORY_REG_DATA_SELECT, old_mode); + if (ret < 0) { + FTS_TEST_SAVE_ERR("restore reg06 fail\n"); + } +test_err: + if (tmp_result) { + *test_result = true; + FTS_TEST_SAVE_INFO("------ LCD Noise Test PASS\n"); + } else { + *test_result = false; + FTS_TEST_SAVE_INFO("------ LCD Noise Test NG\n"); + } + + /* save test data */ + fts_test_save_data("LCD Noise Test", CODE2_LCD_NOISE_TEST, + lcdnoise, 0, false, true, *test_result); + FTS_TEST_FUNC_EXIT(); + return ret; +} + +static int start_test_ft8716(void) +{ + int ret = 0; + struct fts_test *tdata = fts_ftest; + struct incell_testitem *test_item = &tdata->ic.incell.u.item; + bool temp_result = false; + bool test_result = true; + + FTS_TEST_FUNC_ENTER(); + FTS_TEST_INFO("test item:0x%x", fts_ftest->ic.incell.u.tmp); + + if (!tdata || !tdata->buffer) { + FTS_TEST_ERROR("tdata is null"); + return -EINVAL; + } + + /* short test */ + if (true == test_item->short_test) { + ret = ft8716_short_test(tdata, &temp_result); + if ((ret < 0) || (false == temp_result)) { + test_result = false; + } + } + + /* open test */ + if (true == test_item->open_test) { + ret = ft8716_open_test(tdata, &temp_result); + if ((ret < 0) || (false == temp_result)) { + test_result = false; + } + } + + /* cb test */ + if (true == test_item->cb_test) { + ret = ft8716_cb_test(tdata, &temp_result); + if ((ret < 0) || (false == temp_result)) { + test_result = false; + } + } + + /* rawdata test */ + if (true == test_item->rawdata_test) { + ret = ft8716_rawdata_test(tdata, &temp_result); + if ((ret < 0) || (false == temp_result)) { + test_result = false; + } + } + + /* lcd noise test */ + if (true == test_item->lcdnoise_test) { + ret = ft8716_lcdnoise_test(tdata, &temp_result); + if ((ret < 0) || (false == temp_result)) { + test_result = false; + } + } + + return test_result; +} + +struct test_funcs test_func_ft8716 = { + .ctype = {0x0D, 0x0F}, + .hwtype = IC_HW_INCELL, + .key_num_total = 4, + .start_test = start_test_ft8716, +}; diff --git a/drivers/input/touchscreen/focaltech_touch_n10/include/firmware/FT8716_FW_CSOT_NMOS_FHD_5inch_PM85_T_V5D_D02_20180718_app.i b/drivers/input/touchscreen/focaltech_touch_n10/include/firmware/FT8716_FW_CSOT_NMOS_FHD_5inch_PM85_T_V5D_D02_20180718_app.i new file mode 100644 index 0000000000000000000000000000000000000000..e6e9a7fd5d83a40d908eab71d31d2b2c201cbf7e --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/include/firmware/FT8716_FW_CSOT_NMOS_FHD_5inch_PM85_T_V5D_D02_20180718_app.i @@ -0,0 +1,2787 @@ +0x2, 0x15,0xb8,0x2, 0xa0,0xba,0x1b,0xa, 0x30,0x22,0x22,0x2, 0x0, 0x19,0x0, 0x1, +0x1, 0x0, 0x22,0x2, 0x57,0x2c,0xeb,0xaa,0x8, 0x32,0xff,0x2, 0x54,0xe7,0xa2,0x93, +0xe4,0x33,0x22,0x2, 0x1a,0x3e,0x2, 0x3f,0x7a,0xff,0xff,0x2, 0x57,0xf1,0xca,0x3b, +0x7d,0x72,0x7d,0x63,0x7d,0x27,0x12,0x6, 0x48,0x7d,0x36,0x7d,0x27,0x12,0x6, 0xc5, +0xda,0x3b,0x22,0x2, 0x58,0x1d,0x7f,0x71,0xa9,0xd6,0xcb,0x69,0x30,0x0, 0x4, 0x7e, +0x6f,0x4f,0x9d,0x79,0x36,0x0, 0x4, 0x69,0x30,0x0, 0x6, 0x7e,0x6f,0x4f,0x9d,0x79, +0x36,0x0, 0x6, 0x69,0x30,0x0, 0x8, 0x7e,0x6f,0x4f,0x9d,0x79,0x36,0x0, 0x8, 0x7e, +0x7b,0xa0,0x7c,0x6a,0x6c,0x77,0x7e,0x6f,0x4f,0x9d,0x79,0x36,0x0, 0xe, 0x7c,0x4b, +0x6c,0x55,0xe5,0x27,0xa, 0x3b,0x4d,0x32,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0x10, +0x29,0x77,0x0, 0x2, 0xa, 0x37,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x29,0x57, +0x0, 0x4, 0x7c,0x46,0x4c,0x57,0x7e,0x2f,0x4f,0x9d,0x2e,0x54,0x0, 0xe, 0xb, 0x2a, +0x30,0x4d,0x32,0x1b,0x2a,0x30,0x29,0x77,0x0, 0x1, 0x7c,0x47,0x6c,0x55,0x29,0x77, +0x0, 0x3, 0x7c,0x64,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0xa, 0x7e,0xb, 0x70,0x7c, +0x47,0x29,0x70,0x0, 0x1, 0xa, 0x37,0x2d,0x32,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, +0xc, 0x6d,0x11,0x7e,0x1f,0x4f,0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0x30,0x12,0xa, +0x5e,0xa9,0xc6,0xcb,0x22,0x1, 0x2, 0x4, 0x8, 0x10,0x20,0x40,0x80,0xb2,0x86,0x22, +0xae,0x24,0x51,0xdb,0xfd,0xf0,0x2, 0xf, 0x87,0xa0,0x78,0x5f,0xe0,0x1f,0x5d,0xa2, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x87,0xa6, +0xca,0x3b,0x7f,0x30,0x7e,0x3b,0xb0,0xf5,0x2d,0x29,0xb3,0x0, 0x1, 0xbe,0xb1,0x2d, +0x28,0x2, 0xf5,0x2d,0x69,0x13,0x0, 0x6, 0x6d,0x0, 0x7e,0x34,0x0, 0xf2,0x74,0xff, +0x12,0x16,0x5a,0x7f,0x3, 0x12,0xa, 0x6, 0xa9,0xd6,0xcb,0x75,0x2b,0x0, 0x80,0x33, +0x75,0x2c,0x0, 0x80,0x23,0x7e,0x11,0x2b,0x74,0xb, 0xac,0x1b,0xe5,0x2c,0xa, 0x1b, +0x2d,0x1, 0x3e,0x4, 0x69,0x13,0x0, 0x6, 0x2d,0x10,0x6d,0x0, 0xb, 0xa, 0x30,0x6e, +0x34,0xff,0xff,0x1b,0xa, 0x30,0x5, 0x2c,0x29,0x73,0x0, 0x1, 0xbe,0x71,0x2c,0x38, +0xd4,0x5, 0x2b,0x7e,0x3b,0x70,0xbe,0x71,0x2b,0x38,0xc5,0x69,0x33,0x0, 0x6, 0x7e, +0xf, 0x4f,0x9d,0x79,0x30,0x0, 0x4, 0xe5,0x2d,0xa, 0x2b,0x7d,0x32,0x7c,0x67,0x6c, +0x77,0x2d,0x32,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0xc, 0x6d,0x11,0x7e,0x1f,0x4f, +0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0xd0,0x12,0xa, 0x5e,0x75,0x2b,0x0, 0xe5,0x2b, +0xbe,0xb0,0x4, 0x50,0x17,0x7e,0xa1,0x2b,0x74,0x4, 0xa4,0x7e,0x1f,0x4f,0x9d,0x69, +0x11,0x0, 0x26,0x60,0x44,0x1e,0x14,0x14,0x78,0xfb,0x80,0x3d,0xe5,0x2b,0xbe,0xb0, +0x8, 0x50,0x1b,0xe5,0x2b,0xa, 0x5b,0x1b,0x56,0x3e,0x54,0x3e,0x54,0x7e,0x1f,0x4f, +0x9d,0x69,0x11,0x0, 0x28,0x60,0x22,0x1e,0x14,0x14,0x78,0xfb,0x80,0x1b,0xe5,0x2b, +0xa, 0x5b,0x9e,0x54,0x0, 0x8, 0x3e,0x54,0x3e,0x54,0x7e,0x1f,0x4f,0x9d,0x69,0x11, +0x0, 0x2a,0x60,0x5, 0x1e,0x14,0x14,0x78,0xfb,0x5e,0x14,0x0, 0xf, 0x7e,0xa1,0x2b, +0x74,0x2, 0xa4,0x69,0x33,0x0, 0x6, 0x2d,0x35,0x6d,0x22,0x1b,0x1a,0x10,0x5, 0x2b, +0xe5,0x2b,0xbe,0xb0,0xb, 0x40,0x87,0xa9,0xc6,0xcb,0xda,0x3b,0x22,0x6d,0x33,0x7e, +0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x12,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x14,0xb, +0xa, 0x30,0x5e,0x60,0x7f,0x1b,0xa, 0x30,0xe5,0x40,0x54,0x1f,0xa, 0x2b,0x7e,0xf, +0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0xe5,0x41, +0x54,0x1, 0xa, 0x2b,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x7e,0xf, +0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0xe5,0x42, +0x54,0x3, 0xa, 0x2b,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24, +0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30, +0x7e,0x35,0x3e,0xbe,0x34,0x0, 0x2, 0x78,0x63,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, +0x14,0xb, 0xa, 0x30,0x4e,0x60,0x80,0x1b,0xa, 0x30,0xe5,0x43,0x54,0x1f,0x7c,0x4b, +0x6c,0x55,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b, +0xa, 0x30,0xe5,0x44,0x54,0x1, 0xa, 0x5b,0xc4,0x23,0x54,0xe0,0x7c,0xab,0xe4,0x7e, +0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x35,0x1b,0xa, 0x30,0xe5, +0x45,0x54,0x3, 0xa, 0x5b,0x3, 0x3, 0x54,0xc0,0x7c,0xab,0xe4,0x7e,0xf, 0x4f,0xa1, +0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x35,0x1b,0xa, 0x30,0x22,0x7f,0x21,0xa9, +0xd6,0xcb,0x69,0x30,0x0, 0x4, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0x4, 0x69,0x30, +0x0, 0x8, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0x6, 0x69,0x30,0x0, 0x6, 0x7e,0x7f, +0x4f,0x9d,0x79,0x37,0x0, 0x8, 0x29,0x70,0x0, 0x1, 0x7c,0x47,0x6c,0x55,0x7e,0xb, +0x70,0xa, 0x37,0x2d,0x32,0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0xc, 0x29,0x70,0x0, +0x2, 0xa, 0x37,0x1b,0x34,0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0xa, 0x69,0x30,0x0, +0xa, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0xe, 0x69,0x30,0x0, 0xc, 0x7e,0x7f,0x4f, +0x9d,0x79,0x37,0x0, 0x10,0x69,0x30,0x0, 0xe, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, +0x12,0x69,0x30,0x0, 0x10,0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0x30,0x29,0x70,0x0, +0x3, 0x7c,0x27,0x6c,0x33,0x7e,0x1f,0x4f,0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0xa0, +0x12,0xa, 0x5e,0x7e,0x1f,0x4f,0x9d,0x69,0x11,0x0, 0x1a,0x7a,0x2b,0x30,0x69,0x11, +0x0, 0x1c,0x39,0x32,0x0, 0x1, 0x69,0x11,0x0, 0x16,0x79,0x12,0x0, 0x2, 0x69,0x11, +0x0, 0x18,0x79,0x12,0x0, 0x4, 0x69,0x11,0x0, 0x22,0x79,0x12,0x0, 0x6, 0x69,0x11, +0x0, 0x24,0x79,0x12,0x0, 0x8, 0x69,0x11,0x0, 0x1e,0x79,0x12,0x0, 0xa, 0x69,0x31, +0x0, 0x20,0x79,0x32,0x0, 0xc, 0xa9,0xc6,0xcb,0x22,0xca,0x3b,0x7a,0x25,0x51,0x7f, +0x30,0x7a,0x35,0x4f,0xa2,0xac,0x92,0xb, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31, +0x0, 0x4, 0x5e,0x34,0x10,0x0, 0x7a,0x37,0x49,0x63,0xc2,0xc, 0x12,0xc, 0x17,0xa2, +0xb, 0x92,0xac,0xa9,0xd3,0xcb,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f, +0x6f,0x79,0x30,0x0, 0x6, 0x7e,0xf, 0x4f,0x6f,0x69,0x30,0x0, 0x6, 0x4d,0x33,0x78, +0xf4,0x7e,0x35,0x4f,0x2e,0x34,0x80,0x0, 0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0x6f,0x69, +0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6d,0x33,0x80,0x20,0x7d,0x23,0x3e,0x24,0x7f, +0x3, 0x2d,0x12,0xb, 0xa, 0x20,0x7e,0xf, 0x4f,0x6f,0x1b,0xa, 0x20,0x7e,0xf, 0x4f, +0x6f,0x69,0x20,0x0, 0x8, 0x4d,0x22,0x68,0xf4,0xb, 0x34,0xbe,0x35,0x51,0x40,0xdb, +0xa9,0xc5,0xcb,0xa9,0xc3,0xcb,0x7e,0x37,0x49,0x63,0x2e,0x34,0xff,0xff,0x92,0xc, +0x12,0xc, 0x17,0xda,0x3b,0x22,0xca,0x3b,0x7a,0x25,0x51,0x7f,0x30,0x7a,0x35,0x4f, +0xa2,0xac,0x92,0xb, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x4, 0x5e,0x34, +0x10,0x0, 0x7a,0x37,0x49,0x63,0xc2,0xc, 0x12,0xc, 0x17,0xa2,0xb, 0x92,0xac,0xd2, +0xcd,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x73,0x79,0x30,0x0, 0x6, +0x7e,0xf, 0x4f,0x73,0x69,0x30,0x0, 0x6, 0x4d,0x33,0x78,0xf4,0x7e,0x35,0x4f,0x2e, +0x34,0x80,0x0, 0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0x73,0x69,0x31,0x0, 0x8, 0x4d,0x33, +0x68,0xf4,0x6d,0x33,0x80,0x20,0x7d,0x23,0x3e,0x24,0x7f,0x3, 0x2d,0x12,0xb, 0xa, +0x20,0x7e,0xf, 0x4f,0x73,0x1b,0xa, 0x20,0x7e,0xf, 0x4f,0x73,0x69,0x20,0x0, 0x8, +0x4d,0x22,0x68,0xf4,0xb, 0x34,0xbe,0x35,0x51,0x40,0xdb,0xa9,0xc5,0xcb,0xc2,0xcd, +0x7e,0x37,0x49,0x63,0x2e,0x34,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17,0xda,0x3b,0x22, +0xca,0x79,0x7c,0xab,0x6d,0x77,0x7e,0xf, 0x4f,0xa1,0x69,0x30,0x0, 0x6, 0x5e,0x34, +0x0, 0x2, 0x68,0x18,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b,0xa, +0x30,0x74,0x3, 0x7a,0xb3,0x4f,0x55,0x75,0x13,0x3, 0x80,0x3, 0xe4,0x80,0x5a,0x4c, +0xaa,0x68,0x54,0x80,0x44,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x6, 0x5e,0x34,0x0, +0x1, 0x78,0xa, 0xe4,0x7a,0xb3,0x4f,0x55,0x75,0x13,0x0, 0x80,0x3c,0x7e,0x34,0x0, +0x1, 0x12,0x53,0x12,0xb, 0x74,0xbe,0x74,0x3, 0xe8,0x28,0x1d,0x7e,0xf, 0x4f,0xa1, +0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70,0x4, 0x1b,0xa, 0x30,0x74,0x2, 0x7a, +0xb3,0x4f,0x55,0x75,0x13,0x2, 0xe4,0x80,0x10,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, +0xe, 0x5e,0x34,0x0, 0x3, 0x78,0xae,0x74,0x1, 0xda,0x79,0x22,0xca,0x79,0x7c,0xab, +0x6d,0x77,0x7e,0xf, 0x4f,0xa1,0x69,0x30,0x0, 0x6, 0x5e,0x34,0x0, 0x2, 0x68,0x18, +0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70,0x4, 0x1b,0xa, 0x30,0x74,0x2, 0x7a, +0xb3,0x4f,0x55,0x75,0x13,0x2, 0x80,0x3, 0xe4,0x80,0x5a,0x4c,0xaa,0x68,0x54,0x80, +0x44,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x6, 0x5e,0x34,0x0, 0x1, 0x78,0xa, 0xe4, +0x7a,0xb3,0x4f,0x55,0x75,0x13,0x0, 0x80,0x3c,0x7e,0x34,0x0, 0x1, 0x12,0x53,0x12, +0xb, 0x74,0xbe,0x74,0x3, 0xe8,0x28,0x1d,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0xe, +0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b,0xa, 0x30,0x74,0x3, 0x7a,0xb3,0x4f,0x55,0x75, +0x13,0x3, 0xe4,0x80,0x10,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0xe, 0x5e,0x34,0x0, +0x8, 0x68,0xae,0x74,0x1, 0xda,0x79,0x22,0xca,0x3b,0x7d,0x72,0x7d,0x63,0xa2,0xac, +0x92,0x3, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x4, 0x5e,0x34,0x10,0x0, +0x7a,0x37,0x49,0x49,0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x3, 0x92,0xac,0xa9,0xd3,0xcb, +0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x6f,0x79,0x30,0x0, 0x6, 0x7e, +0xf, 0x4f,0x6f,0x69,0x30,0x0, 0x6, 0x4d,0x33,0x78,0xf4,0x7d,0x36,0x2e,0x34,0x80, +0x0, 0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0x6f,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4, +0x1b,0x1a,0x70,0x7e,0x1f,0x4f,0x6f,0x69,0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0xa9, +0xc5,0xcb,0xa9,0xc3,0xcb,0x7e,0x37,0x49,0x49,0x2e,0x34,0xff,0xff,0x92,0xc, 0x12, +0xc, 0x17,0xda,0x3b,0x22,0xca,0x3b,0x7d,0x72,0x7d,0x63,0xa2,0xac,0x92,0x3, 0xc2, +0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x4, 0x5e,0x34,0x10,0x0, 0x7a,0x37,0x49, +0x49,0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x3, 0x92,0xac,0xd2,0xcd,0xa9,0xd5,0xcb,0x7e, +0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x73,0x79,0x30,0x0, 0x6, 0x7e,0xf, 0x4f,0x73,0x69, +0x30,0x0, 0x6, 0x4d,0x33,0x78,0xf4,0x7d,0x36,0x2e,0x34,0x80,0x0, 0x1b,0xa, 0x30, +0x7e,0x1f,0x4f,0x73,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4,0x1b,0x1a,0x70,0x7e, +0x1f,0x4f,0x73,0x69,0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0xa9,0xc5,0xcb,0xc2,0xcd, +0x7e,0x37,0x49,0x49,0x2e,0x34,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17,0xda,0x3b,0x22, +0xca,0x3b,0x7d,0x73,0xa2,0xac,0x92,0x0, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x61, +0x0, 0x4, 0x5e,0x64,0x10,0x0, 0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x0, 0x92,0xac,0xa9, +0xd3,0xcb,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x6f,0x79,0x30,0x0, +0x6, 0x7e,0x1f,0x4f,0x6f,0x69,0x11,0x0, 0x6, 0x4d,0x11,0x78,0xf4,0x1b,0x1a,0x70, +0x7e,0xf, 0x4f,0x6f,0x69,0x30,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6d,0x33,0x1b,0xa, +0x30,0x7e,0x1f,0x4f,0x6f,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4,0x69,0x71,0x0, +0x2, 0xa9,0xc5,0xcb,0xa9,0xc3,0xcb,0x2e,0x64,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17, +0x7d,0x37,0xda,0x3b,0x22,0x7e,0x8, 0x1, 0x63,0x7e,0x34,0x0, 0x18,0xe4,0x12,0x16, +0x5a,0xa9,0xd1,0xcb,0xd2,0xcc,0x7e,0x34,0x0, 0x4, 0x7e,0x8, 0x1, 0x63,0x74,0xc, +0x12,0xa, 0xb5,0xa9,0xd1,0xcb,0xc2,0xcc,0x6c,0xaa,0x7e,0x70,0x2, 0xac,0x7a,0x7e, +0x8, 0x1, 0x63,0x2d,0x13,0xb, 0xa, 0x20,0x7c,0x45,0x6c,0x55,0xb, 0xa, 0x30,0xa, +0x36,0x4d,0x32,0x1b,0xa, 0x30,0xb, 0xa0,0xbe,0xa0,0xc, 0x40,0xdd,0x22,0xff,0xff, +0xca,0x3b,0x7d,0x73,0xa2,0xac,0x92,0x0, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x61, +0x0, 0x4, 0x5e,0x64,0x10,0x0, 0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x0, 0x92,0xac,0xd2, +0xcd,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x73,0x79,0x30,0x0, 0x6, +0x7e,0x1f,0x4f,0x73,0x69,0x11,0x0, 0x6, 0x4d,0x11,0x78,0xf4,0x1b,0x1a,0x70,0x7e, +0xf, 0x4f,0x73,0x69,0x30,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6d,0x33,0x1b,0xa, 0x30, +0x7e,0x1f,0x4f,0x73,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4,0x69,0x71,0x0, 0x2, +0xa9,0xc5,0xcb,0xc2,0xcd,0x2e,0x64,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17,0x7d,0x37, +0xda,0x3b,0x22,0xa9,0xd6,0xcb,0x69,0x30,0x0, 0x6, 0x7e,0x2f,0x4f,0x9d,0x79,0x32, +0x0, 0x4, 0x69,0x30,0x0, 0x8, 0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0x8, 0x29,0x70, +0x0, 0x2, 0x7c,0x47,0x6c,0x55,0x29,0x70,0x0, 0x3, 0xa, 0x37,0x2d,0x32,0x7e,0x2f, +0x4f,0x9d,0x79,0x32,0x0, 0xc, 0x7e,0xb, 0x70,0x7c,0x47,0x29,0x70,0x0, 0x1, 0xa, +0x37,0x2d,0x32,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0xa, 0x29,0x70,0x0, 0x4, 0xa, +0x37,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0xe, 0x29,0xb0,0x0, 0x5, 0x54,0x1, 0x7c, +0x2b,0x6c,0x33,0x7e,0x1f,0x4f,0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0xc0,0x12,0xa, +0x5e,0xa9,0xc6,0xcb,0x22,0xa9,0xd6,0xcb,0xc2,0x31,0x69,0x30,0x0, 0x4, 0x7e,0x2f, +0x4f,0x9d,0x79,0x32,0x0, 0x4, 0x69,0x30,0x0, 0x6, 0x7e,0x2f,0x4f,0x9d,0x79,0x32, +0x0, 0x6, 0x69,0x30,0x0, 0x8, 0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0x8, 0x7e,0xb, +0x70,0x7c,0x47,0x6c,0x55,0x29,0x70,0x0, 0x1, 0xa, 0x37,0x2d,0x32,0x7e,0x2f,0x4f, +0x9d,0x79,0x32,0x0, 0xc, 0x29,0x70,0x0, 0x2, 0xa, 0x37,0x7e,0x2f,0x4f,0x9d,0x79, +0x32,0x0, 0xe, 0x29,0xb0,0x0, 0x3, 0x54,0x1, 0xa, 0x5b,0x7c,0xab,0xe4,0x7e,0x1f, +0x4f,0x9d,0x1b,0x1a,0x50,0x69,0x30,0x0, 0xa, 0x12,0xa, 0x5e,0xa9,0xc6,0xcb,0x22, +0xa9,0xd6,0xcb,0x69,0x20,0x0, 0x4, 0x7e,0x2f,0x4f,0x9d,0x79,0x22,0x0, 0x4, 0x69, +0x20,0x0, 0x8, 0x7e,0x2f,0x4f,0x9d,0x79,0x22,0x0, 0x8, 0x7e,0xb, 0x50,0xa, 0x55, +0x7c,0xab,0xe4,0x29,0x50,0x0, 0x1, 0xa, 0x25,0x2d,0x25,0x7e,0x2f,0x4f,0x9d,0x79, +0x22,0x0, 0xc, 0x29,0x50,0x0, 0x2, 0xa, 0x25,0x7e,0xf, 0x4f,0x9d,0x79,0x20,0x0, +0xe, 0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0xa, 0x6d,0x11,0x7e,0x1f,0x4f,0x9d,0x1b, +0x1a,0x10,0x7e,0x34,0x0, 0x40,0x12,0xa, 0x5e,0xa9,0xc6,0xcb,0x22,0xca,0x3b,0x6c, +0xaa,0x7e,0x90,0x2, 0xac,0x9a,0x7f,0x70,0x2d,0xf4,0xb, 0x7a,0x40,0x5e,0x80,0x3, +0x1b,0x7a,0x40,0x7e,0x90,0x6, 0xac,0x9a,0x7c,0xb9,0x7f,0x71,0x60,0xd, 0x1e,0xf4, +0x1e,0xe4,0x50,0x4, 0x4e,0xf4,0x80,0x0, 0x14,0x78,0xf3,0x7d,0x4f,0x5e,0x44,0x0, +0x3f,0x7d,0x74,0x7c,0xef,0x6c,0xff,0x3e,0x74,0x3e,0x74,0x7e,0xd0,0x2, 0xac,0xda, +0x7f,0x60,0x2d,0xd6,0xb, 0x6a,0xf0,0x4d,0xf7,0x1b,0x6a,0xf0,0xb, 0xa0,0xbe,0xa0, +0x4, 0x40,0xae,0xda,0x3b,0x22,0x7f,0x10,0xa9,0xd6,0xcb,0x69,0x11,0x0, 0x2, 0x7e, +0x2f,0x4f,0x9d,0x79,0x12,0x0, 0x4, 0x69,0x11,0x0, 0x4, 0x7e,0x2f,0x4f,0x9d,0x79, +0x12,0x0, 0x6, 0x69,0x11,0x0, 0x6, 0x7e,0x2f,0x4f,0x9d,0x79,0x12,0x0, 0x8, 0x7e, +0x1b,0x30,0xa, 0x3, 0x7e,0x14,0x1, 0x0, 0xad,0x10,0x29,0x71,0x0, 0x1, 0xa, 0x37, +0x2d,0x31,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0xc, 0x6d,0x11,0x7e,0x1f,0x4f,0x9d, +0x1b,0x1a,0x10,0x7e,0x34,0x0, 0x60,0x12,0xa, 0x5e,0xa9,0xc6,0xcb,0x22,0xa9,0xd7, +0xcb,0x7d,0x23,0x4e,0x50,0x1, 0x7e,0xf, 0x4f,0x9d,0xb, 0xa, 0x30,0x4d,0x32,0x1b, +0xa, 0x30,0x80,0x1e,0x7e,0xf, 0x4f,0x9d,0xb, 0xa, 0x30,0x7d,0x23,0x5e,0x24,0x0, +0x8, 0xbe,0x24,0x0, 0x8, 0x78,0xb, 0xa9,0xd7,0xcb,0x4e,0x70,0x4, 0x1b,0xa, 0x30, +0xd2,0x31,0x7e,0xf, 0x4f,0x9d,0xb, 0xa, 0x30,0x7d,0x23,0x5e,0x24,0x80,0x0, 0xbe, +0x24,0x80,0x0, 0x78,0xcf,0x4e,0x60,0x40,0x1b,0xa, 0x30,0x6d,0x11,0x7e,0x1f,0x4f, +0x9d,0x1b,0x1a,0x10,0x22,0x7e,0x24,0x0, 0x1, 0x7e,0x7f,0x4f,0x77,0x79,0x27,0x0, +0x6, 0x7e,0x7f,0x4f,0x77,0x69,0x27,0x0, 0x6, 0x4d,0x22,0x78,0xf4,0x5e,0x60,0x7f, +0x1b,0x7a,0x30,0x7e,0x1f,0x4f,0x77,0x69,0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6c, +0xaa,0x80,0x20,0x6d,0x44,0x7e,0x1f,0x4f,0x77,0x1b,0x1a,0x40,0x7e,0x1f,0x4f,0x77, +0x69,0x41,0x0, 0x8, 0x4d,0x44,0x68,0xf4,0x69,0x41,0x0, 0x2, 0x1b,0xa, 0x40,0xb, +0x15,0xb, 0xa0,0xbc,0xba,0x38,0xdc,0x22,0xca,0x79,0x7c,0xab,0x6c,0x99,0x80,0x2d, +0x7e,0xf0,0x2, 0xac,0xf9,0x7f,0x60,0x2d,0xd7,0xb, 0x6a,0xf0,0x5e,0xf4,0xfc,0x0, +0x1b,0x6a,0xf0,0x7f,0x71,0x2d,0xf7,0xb, 0x7a,0xe0,0x7e,0xf0,0x2, 0xac,0xf9,0x7f, +0x60,0x2d,0xd7,0xb, 0x6a,0xf0,0x4d,0xfe,0x1b,0x6a,0xf0,0xb, 0x90,0xbc,0xa9,0x38, +0xcf,0xda,0x79,0x22,0xb, 0x38,0x20,0x5e,0x50,0xc0,0x1b,0x38,0x20,0xb, 0xa, 0x20, +0x5e,0x40,0x7, 0x1b,0xa, 0x20,0xe5,0x2e,0xa, 0x5b,0xb, 0x38,0x20,0x4d,0x25,0x1b, +0x38,0x20,0xe5,0x2d,0xa, 0x3b,0x7d,0x23,0x7c,0x45,0x6c,0x55,0x3e,0x24,0x3e,0x24, +0x3e,0x24,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xa9,0xd6,0xcb,0x54,0x3f, +0x5e,0x70,0x1f,0x7e,0x14,0x0, 0x1, 0x7e,0x7f,0x4f,0x9d,0x79,0x17,0x0, 0x2, 0x7c, +0x2b,0x6c,0x33,0xa, 0x37,0x2d,0x31,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0x32,0x7e, +0xf, 0x4f,0x9d,0x79,0x20,0x0, 0x14,0xa9,0xc6,0xcb,0x12,0x7, 0xb5,0x2, 0xd, 0x59, +0x30,0x2a,0x31,0xa9,0xd2,0xea,0xa9,0xc2,0xea,0x6d,0x33,0x7e,0xf, 0x4f,0xa1,0x79, +0x30,0x0, 0x16,0x7e,0x34,0x1, 0x2c,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x18,0xc2, +0x2a,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x14,0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b, +0xa, 0x30,0xc2,0x29,0x22,0xa2,0xac,0x92,0x8, 0x7e,0xf, 0x4f,0xa1,0xb, 0xa, 0x30, +0x5e,0x34,0x10,0x0, 0x68,0xb, 0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x10,0x1b,0xa, +0x30,0xc2,0xac,0x7e,0xf, 0x4f,0xa1,0xb, 0x16,0xb, 0xa, 0x30,0x4e,0x60,0x10,0x1b, +0xa, 0x30,0xa2,0x8, 0x92,0xac,0x22,0xa2,0xac,0x92,0xd, 0xc2,0xac,0x7e,0xf, 0x4f, +0xa1,0x30,0xc, 0xa, 0xb, 0x16,0xb, 0xa, 0x30,0x4e,0x60,0x10,0x80,0x8, 0xb, 0x16, +0xb, 0xa, 0x30,0x5e,0x60,0xef,0x1b,0xa, 0x30,0xa2,0xd, 0x92,0xac,0x22,0xb, 0xa, +0x30,0x5e,0x34,0xfc,0x7f,0x1b,0xa, 0x30,0xa, 0x2b,0x5e,0x24,0x0, 0x7, 0x3e,0x24, +0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0xb, 0xa, 0x30,0x4d, +0x32,0x1b,0xa, 0x30,0x22,0xa9,0xd7,0xca,0x7e,0x24,0x0, 0x1, 0x7e,0xf, 0x4f,0xa5, +0x1b,0xa, 0x20,0x7e,0x24,0x9, 0x60,0x7e,0xf, 0x4f,0xa5,0x79,0x20,0x0, 0x2, 0x7e, +0xf, 0x4f,0xa5,0x79,0x30,0x0, 0x4, 0x22,0xb, 0xa, 0x20,0x5e,0x24,0x80,0x1f,0x1b, +0xa, 0x20,0x7d,0x23,0x5e,0x40,0x3, 0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e, +0x24,0xb, 0xa, 0x30,0x2d,0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30,0x5e,0x60,0xc7, +0x1b,0xa, 0x30,0x54,0x7, 0xa, 0x3b,0x7d,0x23,0x7c,0x45,0x6c,0x55,0x3e,0x24,0x3e, +0x24,0x3e,0x24,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xca,0x3b,0x7d,0x72, +0x7a,0xd, 0x2d,0x7d,0x63,0x7e,0xd, 0x2d,0x7d,0x27,0x12,0x3, 0xfa,0x7d,0x36,0x7e, +0xd, 0x2d,0x7d,0x27,0x12,0x4, 0x96,0xda,0x3b,0x22,0xb, 0xa, 0x30,0x5e,0x60,0x9f, +0x1b,0xa, 0x30,0x54,0x3, 0xa, 0x5b,0xc4,0x23,0x54,0xe0,0x7c,0xab,0xe4,0xb, 0xa, +0x30,0x4d,0x35,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30,0x5e,0x70,0xe7,0x1b,0xa, 0x30, +0x54,0x3, 0xa, 0x2b,0x3e,0x24,0x3e,0x24,0x3e,0x24,0xb, 0xa, 0x30,0x4d,0x32,0x1b, +0xa, 0x30,0x22,0x7c,0xa7,0xb, 0xa, 0x30,0x5e,0x60,0x40,0x60,0x3, 0x4e,0x60,0x80, +0x7c,0xba,0x54,0x3f,0x7c,0x4b,0x6c,0x55,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, +0x50,0x54,0xe0,0x1b,0xa, 0x50,0x7d,0x52,0x5e,0x54,0x0, 0x1f,0xb, 0xa, 0x20,0x4d, +0x25,0x1b,0xa, 0x20,0x79,0x30,0x0, 0x2, 0x22,0x7e,0xb3,0x1, 0x73,0xb4,0xe7,0x12, +0x7e,0xb3,0x1, 0x74,0xb4,0x16,0xb, 0x7e,0xb3,0x1, 0x70,0x54,0x1, 0xb4,0x1, 0x2, +0x80,0xfe,0x22,0xb, 0xa, 0x30,0x5e,0x60,0xf, 0x1b,0xa, 0x30,0xa, 0x5b,0xc4,0x54, +0xf0,0x7c,0xab,0xe4,0xb, 0xa, 0x30,0x4d,0x35,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30, +0x5e,0x60,0xfc,0x1b,0xa, 0x30,0x54,0x3, 0x7c,0x4b,0x6c,0x55,0xb, 0xa, 0x30,0x4d, +0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x20,0x5e,0x50,0xfc,0x1b,0xa, 0x20,0x7d,0x23, +0x5e,0x24,0x0, 0x3, 0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xd2,0x2a,0xd2, +0x29,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x14,0xb, 0xa, 0x30,0x4e,0x70,0x2, 0x1b, +0xa, 0x30,0x22,0x7d,0x23,0xb, 0xa, 0x30,0x5e,0x34,0xf8,0x0, 0x1b,0xa, 0x30,0x4d, +0x32,0x1b,0xa, 0x30,0x22,0x7d,0x23,0xb, 0xa, 0x30,0x5e,0x34,0xf8,0x0, 0x1b,0xa, +0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30,0x5e,0x70,0x3, 0x70,0x3, 0x4e, +0x70,0xc, 0x1b,0xa, 0x30,0x22,0x70,0x8f,0x0, 0xff,0xe0,0x1f,0x4, 0xa7,0x24,0x87, +0x2, 0xa9,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46,0x54,0x53,0x38,0x37,0x31,0x36,0x50,0x30,0x30, +0x31,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30,0x30,0x31,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, +0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, +0x1, 0x9, 0x9, 0x12,0x1e,0x12,0x1e,0x5, 0x4, 0x1, 0xe, 0x1, 0xe, 0x0, 0xc, 0x0, +0xc, 0x1, 0xe, 0x1, 0xe, 0x1, 0x0, 0xc, 0x0, 0xd, 0x0, 0xe, 0x0, 0xf, 0x0, 0x10, +0x0, 0x11,0x0, 0x12,0x0, 0x13,0x0, 0x14,0x0, 0x15,0x0, 0x16,0x0, 0x17,0x0, 0x18, +0x0, 0x19,0x0, 0x1a,0x0, 0x1b,0x0, 0x1c,0x0, 0x1d,0x0, 0x1e,0x0, 0x1f,0x0, 0x20, +0x0, 0x21,0x0, 0x22,0x0, 0x23,0x0, 0x24,0x0, 0x25,0x0, 0x26,0x0, 0x27,0x0, 0x28, +0x0, 0x29,0x0, 0x2a,0x0, 0x2b,0x0, 0x2c,0x0, 0x2d,0x0, 0x2e,0x0, 0x2f,0x0, 0x30, +0x0, 0x31,0x0, 0x32,0x0, 0x33,0x0, 0x34,0x0, 0x35,0x0, 0x36,0x0, 0x37,0x0, 0x38, +0x0, 0x39,0x0, 0x3a,0x0, 0x3b,0x0, 0x3c,0x0, 0x3d,0x0, 0x3e,0x0, 0x3f,0x0, 0x40, +0x0, 0x41,0x0, 0x42,0x0, 0x43,0x0, 0x44,0x0, 0x45,0x0, 0x46,0x0, 0x47,0x0, 0x48, +0x0, 0x49,0x0, 0x4a,0x0, 0x4b,0x0, 0x4c,0x0, 0x4d,0x0, 0x4e,0x0, 0x4f,0x0, 0x50, +0x0, 0x51,0x0, 0x52,0x0, 0x53,0x0, 0x54,0x0, 0x55,0x0, 0x56,0x0, 0x57,0x0, 0x58, +0x0, 0x59,0x0, 0x5a,0x0, 0x5b,0x0, 0x5c,0x0, 0x5d,0x0, 0x5e,0x0, 0x5f,0x0, 0x60, +0x0, 0x61,0x0, 0x62,0x0, 0x63,0x0, 0x64,0x0, 0x65,0x0, 0x66,0x0, 0x67,0x0, 0x68, +0x0, 0x69,0x0, 0x6a,0x0, 0x6b,0x0, 0x6c,0x0, 0x6d,0x0, 0x6e,0x0, 0x6f,0x0, 0x70, +0x0, 0x71,0x0, 0x72,0x0, 0x73,0x0, 0x74,0x0, 0x75,0x0, 0x76,0x0, 0x77,0x0, 0x78, +0x0, 0x79,0x0, 0x7a,0x0, 0x7b,0x0, 0x7c,0x0, 0x7d,0x0, 0x7e,0x0, 0x7f,0x0, 0x80, +0x0, 0x81,0x0, 0x82,0x0, 0x83,0x0, 0x84,0x0, 0x85,0x0, 0x86,0x0, 0x87,0x0, 0x88, +0x0, 0x89,0x0, 0x8a,0x0, 0x8b,0x0, 0x8c,0x0, 0x8d,0x0, 0x8e,0x0, 0x8f,0x0, 0x90, +0x0, 0x91,0x0, 0x92,0x0, 0x93,0x0, 0x94,0x0, 0x95,0x0, 0x96,0x0, 0x97,0x0, 0x98, +0x0, 0x99,0x0, 0x9a,0x0, 0x9b,0x0, 0x9c,0x0, 0x9d,0x0, 0x9e,0x0, 0x9f,0x0, 0xa0, +0x0, 0xa1,0x0, 0xa2,0x0, 0xa3,0x0, 0xa4,0x0, 0xa5,0x0, 0xa6,0x0, 0xa7,0x0, 0xa8, +0x0, 0xa9,0x0, 0xaa,0x0, 0xab,0x0, 0xac,0x0, 0xad,0x0, 0xae,0x0, 0xaf,0x0, 0xb0, +0x0, 0xb1,0x0, 0xb2,0x0, 0xb3,0x0, 0xb4,0x0, 0xb5,0x0, 0xb6,0x0, 0xb7,0x0, 0xb8, +0x0, 0xb9,0x0, 0xba,0x0, 0xbb,0x0, 0xbc,0x0, 0xbd,0x0, 0xbe,0x0, 0xbf,0x0, 0xc0, +0x0, 0xc1,0x0, 0xc2,0x0, 0xc3,0x0, 0xc4,0x0, 0xc5,0x0, 0xc6,0x0, 0xc7,0x0, 0xc8, +0x0, 0xc9,0x0, 0xca,0x0, 0xcb,0x0, 0xcc,0x0, 0xcd,0x0, 0xce,0x0, 0xcf,0x0, 0xd0, +0x0, 0xd1,0x0, 0xd2,0x0, 0xd3,0x0, 0xd4,0x0, 0xd5,0x0, 0xd6,0x0, 0xd7,0x0, 0xd8, +0x0, 0xd9,0x0, 0xda,0x0, 0xdb,0x0, 0xdc,0x0, 0xdd,0x0, 0xde,0x0, 0xdf,0x0, 0xe0, +0x0, 0xe1,0x0, 0xe2,0x0, 0xe3,0x0, 0xe4,0x0, 0xe5,0x0, 0xe6,0x0, 0xe7,0x0, 0xe8, +0x0, 0xe9,0x0, 0xea,0x0, 0xeb,0x0, 0xec,0x0, 0xed,0x0, 0xee,0x0, 0xef,0x0, 0xf0, +0x0, 0xf1,0x0, 0xf2,0x0, 0xf3,0x0, 0xf4,0x0, 0xf5,0x0, 0xf6,0x0, 0xf7,0x0, 0xf8, +0x0, 0xf9,0x0, 0xfa,0x0, 0xfb,0x0, 0xfc,0x0, 0xfd,0x0, 0xfe,0x0, 0xff,0x1, 0x0, +0x1, 0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x4, 0x1, 0x5, 0x1, 0x6, 0x1, 0x7, 0x1, 0x8, +0x1, 0x9, 0x1, 0xa, 0x1, 0xb, 0x1, 0xc, 0x1, 0xd, 0x1, 0xe, 0x1, 0xf, 0x1, 0x10, +0x1, 0x11,0x1, 0x12,0x1, 0x13,0x1, 0x14,0x1, 0x15,0x1, 0x16,0x1, 0x17,0x1, 0x18, +0x1, 0x19,0x1, 0x19,0x1, 0x18,0x1, 0x17,0x1, 0x16,0x1, 0x15,0x1, 0x14,0x1, 0x13, +0x1, 0x12,0x1, 0x11,0x1, 0x10,0x1, 0xf, 0x1, 0xe, 0x1, 0xd, 0x1, 0xc, 0x1, 0xb, +0x1, 0xa, 0x1, 0x9, 0x1, 0x8, 0x1, 0x7, 0x1, 0x6, 0x1, 0x5, 0x1, 0x4, 0x1, 0x3, +0x1, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0xff,0x0, 0xfe,0x0, 0xfd,0x0, 0xfc,0x0, 0xfb, +0x0, 0xfa,0x0, 0xf9,0x0, 0xf8,0x0, 0xf7,0x0, 0xf6,0x0, 0xf5,0x0, 0xf4,0x0, 0xf3, +0x0, 0xf2,0x0, 0xf1,0x0, 0xf0,0x0, 0xef,0x0, 0xee,0x0, 0xed,0x0, 0xec,0x0, 0xeb, +0x0, 0xea,0x0, 0xe9,0x0, 0xe8,0x0, 0xe7,0x0, 0xe6,0x0, 0xe5,0x0, 0xe4,0x0, 0xe3, +0x0, 0xe2,0x0, 0xe1,0x0, 0xe0,0x0, 0xdf,0x0, 0xde,0x0, 0xdd,0x0, 0xdc,0x0, 0xdb, +0x0, 0xda,0x0, 0xd9,0x0, 0xd8,0x0, 0xd7,0x0, 0xd6,0x0, 0xd5,0x0, 0xd4,0x0, 0xd3, +0x0, 0xd2,0x0, 0xd1,0x0, 0xd0,0x0, 0xcf,0x0, 0xce,0x0, 0xcd,0x0, 0xcc,0x0, 0xcb, +0x0, 0xca,0x0, 0xc9,0x0, 0xc8,0x0, 0xc7,0x0, 0xc6,0x0, 0xc5,0x0, 0xc4,0x0, 0xc3, +0x0, 0xc2,0x0, 0xc1,0x0, 0xc0,0x0, 0xbf,0x0, 0xbe,0x0, 0xbd,0x0, 0xbc,0x0, 0xbb, +0x0, 0xba,0x0, 0xb9,0x0, 0xb8,0x0, 0xb7,0x0, 0xb6,0x0, 0xb5,0x0, 0xb4,0x0, 0xb3, +0x0, 0xb2,0x0, 0xb1,0x0, 0xb0,0x0, 0xaf,0x0, 0xae,0x0, 0xad,0x0, 0xac,0x0, 0xab, +0x0, 0xaa,0x0, 0xa9,0x0, 0xa8,0x0, 0xa7,0x0, 0xa6,0x0, 0xa5,0x0, 0xa4,0x0, 0xa3, +0x0, 0xa2,0x0, 0xa1,0x0, 0xa0,0x0, 0x9f,0x0, 0x9e,0x0, 0x9d,0x0, 0x9c,0x0, 0x9b, +0x0, 0x9a,0x0, 0x99,0x0, 0x98,0x0, 0x97,0x0, 0x96,0x0, 0x95,0x0, 0x94,0x0, 0x93, +0x0, 0x92,0x0, 0x91,0x0, 0x90,0x0, 0x8f,0x0, 0x8e,0x0, 0x8d,0x0, 0x8c,0x0, 0x8b, +0x0, 0x8a,0x0, 0x89,0x0, 0x88,0x0, 0x87,0x0, 0x86,0x0, 0x85,0x0, 0x84,0x0, 0x83, +0x0, 0x82,0x0, 0x81,0x0, 0x80,0x0, 0x7f,0x0, 0x7e,0x0, 0x7d,0x0, 0x7c,0x0, 0x7b, +0x0, 0x7a,0x0, 0x79,0x0, 0x78,0x0, 0x77,0x0, 0x76,0x0, 0x75,0x0, 0x74,0x0, 0x73, +0x0, 0x72,0x0, 0x71,0x0, 0x70,0x0, 0x6f,0x0, 0x6e,0x0, 0x6d,0x0, 0x6c,0x0, 0x6b, +0x0, 0x6a,0x0, 0x69,0x0, 0x68,0x0, 0x67,0x0, 0x66,0x0, 0x65,0x0, 0x64,0x0, 0x63, +0x0, 0x62,0x0, 0x61,0x0, 0x60,0x0, 0x5f,0x0, 0x5e,0x0, 0x5d,0x0, 0x5c,0x0, 0x5b, +0x0, 0x5a,0x0, 0x59,0x0, 0x58,0x0, 0x57,0x0, 0x56,0x0, 0x55,0x0, 0x54,0x0, 0x53, +0x0, 0x52,0x0, 0x51,0x0, 0x50,0x0, 0x4f,0x0, 0x4e,0x0, 0x4d,0x0, 0x4c,0x0, 0x4b, +0x0, 0x4a,0x0, 0x49,0x0, 0x48,0x0, 0x47,0x0, 0x46,0x0, 0x45,0x0, 0x44,0x0, 0x43, +0x0, 0x42,0x0, 0x41,0x0, 0x40,0x0, 0x3f,0x0, 0x3e,0x0, 0x3d,0x0, 0x3c,0x0, 0x3b, +0x0, 0x3a,0x0, 0x39,0x0, 0x38,0x0, 0x37,0x0, 0x36,0x0, 0x35,0x0, 0x34,0x0, 0x33, +0x0, 0x32,0x0, 0x31,0x0, 0x30,0x0, 0x2f,0x0, 0x2e,0x0, 0x2d,0x0, 0x2c,0x0, 0x2b, +0x0, 0x2a,0x0, 0x29,0x0, 0x28,0x0, 0x27,0x0, 0x26,0x0, 0x25,0x0, 0x24,0x0, 0x23, +0x0, 0x22,0x0, 0x21,0x0, 0x20,0x0, 0x1f,0x0, 0x1e,0x0, 0x1d,0x0, 0x1c,0x0, 0x1b, +0x0, 0x1a,0x0, 0x19,0x0, 0x18,0x0, 0x17,0x0, 0x16,0x0, 0x15,0x0, 0x14,0x0, 0x13, +0x0, 0x12,0x0, 0x11,0x0, 0x10,0x0, 0xf, 0x0, 0xe, 0x0, 0xd, 0x0, 0xc, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x18,0x19,0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, +0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, +0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x18,0x19,0x2, 0x5, 0x0, 0x0, 0x0, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, +0x18,0x19,0x2, 0x5, 0x1, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, +0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, +0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x18,0x19,0x2, 0x5, 0x2, 0x0, 0x0, 0x0, 0x5, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x1, 0xa, +0x1e,0x20,0x8, 0x0, 0x64,0xd, 0xac,0x0, 0xc8,0x2, 0x26,0x1, 0xf4,0x1, 0xf4,0x3, +0x20,0x3, 0x20,0x3, 0x20,0x1, 0x90,0x1, 0x90,0xa, 0x0, 0x2, 0x26,0x1, 0xa, 0x6, +0x21,0x3c,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,0x1, 0x0, 0x1, 0x87,0x1, 0x0, 0x5d,0x1, 0xe0, +0x0, 0x1, 0x0, 0x15,0x2, 0x1, 0x4, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d,0x0, 0x0, 0x0, 0x0, 0x0, 0xff,0x0, 0xff,0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x40,0x3, 0xc0,0x4, 0x38,0x2, 0x1c, +0x3e,0x3e,0x1, 0xe0,0x1, 0xe0,0x0, 0xf0,0x0, 0xf0,0x7, 0x80,0x3, 0xc0,0x40,0x40, +0x1, 0xfe,0x1, 0xfe,0x1, 0x0, 0x1, 0x0, 0x12,0x2, 0x58,0x3, 0x20,0x0, 0xc8,0x0, +0x0, 0x7, 0xd0,0x1, 0x2c,0x0, 0x43,0x0, 0x4, 0x1, 0x5, 0x2, 0x2, 0x4, 0x4, 0x6, +0x80,0x0, 0xc8,0x13,0x88,0x10,0x3, 0x6, 0x1, 0x2c,0x2, 0x58,0x3, 0x20,0x1f,0x40, +0x28,0x1, 0x5e,0x2, 0xbc,0x0, 0x14,0x19,0x5, 0xf, 0x4, 0x4c,0x2, 0x26,0x8, 0x98, +0x0, 0x64,0x4, 0xa, 0x5, 0x0, 0x0, 0x4, 0x38,0x0, 0x0, 0x7, 0x80,0x0, 0x32,0x1, +0xf4,0x1, 0xf4,0x3, 0x20,0x0, 0xc8,0x0, 0x6c,0x0, 0x1e,0x0, 0x80,0x2, 0x1c,0x1, +0xe0,0x0, 0x64,0x7, 0xd0,0x1, 0xe0,0x2, 0x1c,0x0, 0x64,0x7, 0xd0,0x0, 0x0, 0x4, +0x38,0x0, 0x0, 0x7, 0x80,0x0, 0x64,0x0, 0xa0,0x0, 0xa0,0x9, 0xc4,0x1, 0x2c,0xc2, +0xd5,0x7c,0xb4,0x30,0xe7,0x8, 0xb2,0xd5,0x6e,0x24,0xff,0xff,0xb, 0x24,0x7c,0xb6, +0x30,0xe7,0x12,0xb2,0xd5,0x6e,0x34,0xff,0xff,0xb, 0x34,0x8d,0x32,0x6e,0x24,0xff, +0xff,0xb, 0x24,0x80,0x2, 0x8d,0x32,0x30,0xd5,0x6, 0x6e,0x34,0xff,0xff,0xb, 0x34, +0x22,0x7d,0x51,0xad,0x3, 0x7d,0x2, 0x7d,0x21,0xad,0x5, 0x2d,0x12,0xad,0x35,0x2d, +0x21,0x22,0x7d,0x2, 0xad,0x31,0xad,0x10,0x2d,0x21,0x22,0x6d,0x0, 0x74,0x10,0x4d, +0x0, 0x78,0xb, 0x4d,0x22,0x78,0x27,0x8d,0x31,0x7d,0x12,0x6d,0x22,0x22,0x7d,0x43, +0x7d,0x32,0x6d,0x22,0x2f,0x11,0x2d,0x44,0x50,0x2, 0xa5,0xf, 0xbf,0x10,0x40,0x4, +0x9f,0x10,0xb, 0x90,0x14,0x78,0xed,0x7f,0x1, 0x6d,0x22,0x7d,0x34,0x22,0x7d,0x41, +0x7d,0x13,0x8d,0x24,0x7d,0x2, 0x2f,0x0, 0x40,0x4, 0xbd,0x4, 0x40,0x4, 0x9d,0x4, +0xb, 0x14,0x14,0x78,0xf1,0x7d,0x23,0x7d,0x31,0x7d,0x10,0x6d,0x0, 0x22,0xc2,0xd5, +0x7c,0xb0,0x30,0xe7,0x8, 0xb2,0xd5,0x9f,0x22,0x9f,0x20,0x7f,0x2, 0x7c,0xb4,0x30, +0xe7,0x13,0xb2,0xd5,0x9f,0x22,0x9f,0x21,0x7f,0x12,0x12,0x14,0xed,0x9f,0x22,0x9f, +0x20,0x7f,0x2, 0x80,0x3, 0x12,0x14,0xed,0x30,0xd5,0x6, 0x9f,0x22,0x9f,0x21,0x7f, +0x12,0x22,0x6c,0xaa,0x4d,0x11,0x68,0x1a,0x1e,0x54,0x68,0xe, 0xb, 0x38,0x20,0x1b, +0x18,0x20,0xb, 0x35,0xb, 0x15,0x1b,0x54,0x78,0xf2,0x50,0x6, 0x7e,0x39,0x40,0x7a, +0x19,0x40,0x22,0x6c,0xaa,0x4d,0x11,0x68,0x1e,0x1e,0x54,0x50,0xc, 0x7e,0x1b,0x0, +0x7a,0x19,0x0, 0x68,0x12,0xb, 0x1c,0xb, 0x14,0xb, 0x1a,0x0, 0x1b,0x18,0x0, 0xb, +0x1d,0xb, 0x15,0x1b,0x54,0x78,0xf2,0x22,0x75,0x84,0x1, 0x7e,0x44,0x7f,0xff,0xe4, +0x7a,0x49,0xb0,0x1b,0x44,0x78,0xf9,0x7e,0xf8,0x4f,0xb1,0xc2,0x20,0xc2,0x21,0xc2, +0x22,0xc2,0x2c,0xc2,0x23,0xd2,0x24,0xc2,0x25,0xc2,0x26,0xc2,0x2d,0xc2,0x27,0xd2, +0x28,0xc2,0x17,0xc2,0x18,0xc2,0x19,0xc2,0x1a,0xc2,0xe, 0xc2,0xf, 0xc2,0x10,0xc2, +0x11,0xc2,0x12,0xc2,0x13,0xc2,0x14,0xc2,0x15,0xc2,0x16,0xc2,0x2e,0xc2,0x2f,0xd2, +0x29,0xc2,0x2a,0x75,0x13,0x0, 0x75,0x14,0x1, 0x7e,0x4, 0x0, 0xff,0x7e,0x14,0x18, +0xb8,0xb, 0xa, 0x40,0x5d,0x44,0x68,0x1a,0x69,0x20,0x0, 0x2, 0xb, 0xe, 0xb, 0x44, +0x80,0xa, 0x7e,0xb, 0xb0,0x7a,0x29,0xb0,0xb, 0x24,0xb, 0xc, 0x1b,0x44,0x78,0xf2, +0x80,0xdf,0x2, 0x1f,0xff,0xca,0xf8,0x7f,0x20,0x80,0xa, 0x7e,0x1b,0xf0,0x7a,0x2b, +0xf0,0xb, 0x34,0xb, 0x54,0x69,0xff,0xff,0xfc,0x7d,0xef,0x1b,0xe4,0x79,0xef,0xff, +0xfc,0x4d,0xff,0x78,0xe6,0x7f,0x10,0xda,0xf8,0x22,0x7d,0x43,0x7f,0x10,0x80,0x7, +0x1b,0x44,0x7a,0xb, 0xb0,0xb, 0x14,0x4d,0x44,0x78,0xf5,0x22,0x7d,0x23,0xbe,0x24, +0x0, 0x0, 0x48,0x3, 0x7d,0x32,0x22,0x6d,0x33,0x9d,0x32,0x22,0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2c,0xf9,0x1, 0x0, 0x1, 0x2c, +0xff,0x1, 0x0, 0x1, 0x2d,0x1, 0x5, 0x0, 0x3, 0x31,0x8c,0x0, 0x0, 0x0, 0x0, 0x6, +0x31,0x8f,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x31,0x95,0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x4f,0xab,0x1, 0x0, 0x2, 0x4e,0x47,0x0, 0x0, 0x0, 0x1, 0x4d, +0x77,0xff,0x0, 0x8, 0x4c,0x3e,0x5, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0xc, +0x4c,0x6e,0x3, 0x3, 0x0, 0x3, 0x0, 0x0, 0x3, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, +0x4f,0xad,0x0, 0x0, 0x1, 0x4e,0x97,0x0, 0x0, 0x1, 0x4e,0xdb,0xff,0x0, 0x1, 0x4e, +0xdc,0xff,0x0, 0x2, 0x4f,0xa9,0x0, 0x0, 0x0, 0x1, 0x4f,0x1b,0x0, 0x0, 0x1, 0x49, +0xe9,0xff,0x0, 0x1, 0x4a,0x1, 0x0, 0x0, 0x2, 0x4a,0x2, 0x0, 0x0, 0x0, 0x4, 0x4a, +0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4a,0x76,0x0, 0x0, 0x1, 0x4f,0x8a,0x1, 0x0, +0x1, 0x4f,0x8b,0x0, 0x0, 0x1, 0x4f,0x93,0x0, 0x0, 0x2, 0x4d,0x75,0x0, 0x0, 0x0, +0x2, 0x4e,0x4c,0x0, 0x5, 0x0, 0x1, 0x4e,0x91,0xff,0x0, 0x1, 0x4e,0x92,0xff,0x0, +0x1, 0x4c,0xfa,0x64,0x0, 0x1, 0x4f,0xb0,0x0, 0x0, 0x1, 0x4f,0x4b,0x0, 0x0, 0x1, +0x4f,0x50,0x5, 0x0, 0x1, 0x4f,0x54,0x4, 0x0, 0x1, 0x4f,0x55,0x1, 0x0, 0x1, 0x4f, +0x59,0x0, 0x0, 0x1, 0x4f,0x98,0x1, 0x0, 0x1, 0x4f,0xb1,0x1, 0x0, 0x4, 0x4f,0x9d, +0x0, 0x0, 0x90,0x0, 0x0, 0x4, 0x4f,0x6f,0x0, 0x0, 0x94,0x0, 0x0, 0x4, 0x4f,0x73, +0x0, 0x0, 0x98,0x0, 0x0, 0x4, 0x4f,0x77,0x0, 0x0, 0x9c,0x0, 0x0, 0x4, 0x1, 0x5f, +0x0, 0x0, 0x80,0x0, 0x0, 0x4, 0x4f,0xa1,0x0, 0x0, 0x91,0x0, 0x0, 0x4, 0x4f,0xa5, +0x0, 0x0, 0x92,0x0, 0x0, 0x0, 0x3, 0xe8,0x0, 0x51,0x0, 0x3, 0x3, 0x20,0x0, 0x50, +0x0, 0x3, 0x2, 0x58,0x0, 0x4e,0x0, 0x4, 0x1, 0xc2,0x0, 0x4b,0x0, 0x4, 0x1, 0x40, +0x0, 0x47,0x0, 0x4, 0x0, 0xc8,0x0, 0x44,0x0, 0x4, 0x0, 0x78,0x0, 0x3e,0x0, 0x5, +0x0, 0x64,0x0, 0x3c,0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x12,0x1f,0xf8,0x7a,0xb3,0x4f,0x6e,0xe4,0x7a,0xb3,0x4d,0xeb,0x2, 0x1a,0x33, +0x12,0x1d,0x19,0x74,0x1f,0x7a,0xb3,0x44,0x7f,0x7a,0xb3,0x44,0x80,0x22,0xca,0x7b, +0xca,0x6b,0xca,0x5b,0xca,0x4b,0xca,0x2b,0xca,0x1b,0xca,0xb, 0xc0,0xd0,0xc0,0x83, +0xc0,0x82,0x12,0x1b,0xde,0x5e,0x34,0x80,0x0, 0x68,0x28,0xb, 0xa, 0x30,0x5e,0x34, +0x80,0x0, 0x68,0x1f,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x6e,0x70,0x40,0x1b,0xa, +0x30,0x7e,0xf, 0x4f,0xa1,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x80,0x12,0x1b,0xe7, +0x12,0x1f,0xf1,0x12,0x1b,0xde,0x5e,0x34,0x0, 0x2, 0x68,0x17,0xb, 0xa, 0x30,0x5e, +0x34,0x0, 0x2, 0x68,0xe, 0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x70,0x2, 0x12,0x1b,0xe7, +0x12,0x1f,0xf1,0x12,0x1b,0xde,0x5e,0x34,0x0, 0x1, 0x68,0x20,0xb, 0xa, 0x30,0x5e, +0x34,0x0, 0x1, 0x68,0x17,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x70,0x1, 0x1b,0xa, 0x30, +0x12,0x33,0xd7,0x12,0x1b,0xed,0x4e,0x70,0x1, 0x1b,0xa, 0x30,0x12,0x1b,0xde,0x5e, +0x34,0x0, 0x8, 0x68,0x17,0xb, 0xa, 0x30,0x5e,0x34,0x0, 0x8, 0x68,0xe, 0xb, 0x15, +0xb, 0xa, 0x30,0x4e,0x70,0x8, 0x1b,0xa, 0x30,0x12,0x33,0xb5,0x12,0x1b,0xde,0x5e, +0x34,0x0, 0x4, 0x68,0x17,0xb, 0xa, 0x30,0x5e,0x34,0x0, 0x4, 0x68,0xe, 0xb, 0x15, +0xb, 0xa, 0x30,0x4e,0x70,0x4, 0x1b,0xa, 0x30,0x12,0x33,0x9a,0x12,0x1b,0xde,0x5e, +0x34,0x40,0x0, 0x68,0x31,0xb, 0xa, 0x30,0x5e,0x34,0x40,0x0, 0x68,0x28,0xb, 0x15, +0xb, 0xa, 0x30,0x4e,0x60,0x40,0x1b,0xa, 0x30,0xd2,0xf, 0x7e,0xb3,0x4f,0x49,0xbe, +0xb0,0xc8,0x50,0x5, 0x4, 0x7a,0xb3,0x4f,0x49,0x7e,0xb3,0x4f,0x49,0xb4,0x1, 0x6, +0x12,0x1a,0x33,0x12,0x1c,0xa, 0x12,0x1b,0xde,0x5e,0x34,0x20,0x0, 0x68,0x19,0xb, +0xa, 0x30,0x5e,0x34,0x20,0x0, 0x68,0x10,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x20, +0x1b,0xa, 0x30,0xd2,0xf, 0x12,0x1c,0xa, 0x12,0x1b,0xde,0x5e,0x34,0x10,0x0, 0x68, +0x26,0xb, 0xa, 0x30,0x7d,0x23,0x5e,0x24,0x10,0x0, 0x68,0x1b,0x5e,0x34,0x8, 0x0, +0x2e,0x34,0xff,0xff,0x92,0x14,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x8, 0x1b,0xa, +0x30,0x12,0xa3,0x17,0x12,0xa4,0x14,0x12,0x1b,0xde,0x5e,0x34,0x0, 0x40,0x68,0x29, +0xb, 0xa, 0x30,0x5e,0x34,0x0, 0x40,0x68,0x20,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x70, +0x40,0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0xa, 0x5e,0x34,0xf, 0xc0, +0x12,0x1f,0x16,0x1e,0x34,0x7a,0x73,0x4f,0x4c,0xd0,0x82,0xd0,0x83,0xd0,0xd0,0xda, +0xb, 0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b,0xda,0x6b,0xda,0x7b,0x32,0x7e,0xf, +0x4f,0xa1,0x69,0x30,0x0, 0x4, 0x22,0x1b,0xa, 0x30,0x12,0x1b,0xf9,0x7e,0xf, 0x4f, +0xa1,0x2e,0x14,0x0, 0x14,0xb, 0xa, 0x30,0x22,0xd2,0xe, 0xd2,0x12,0x12,0x33,0x91, +0x5e,0x34,0x0, 0x1, 0x78,0x3, 0x2, 0x33,0xab,0x22,0x30,0x2a,0x16,0xa9,0xd2,0xea, +0xa9,0xc2,0xea,0x12,0xac,0x93,0xc2,0x2a,0x12,0x1b,0xed,0x12,0x1f,0xea,0xc2,0x29, +0x2, 0x33,0xc6,0x22,0xe4,0x7a,0xb3,0x3, 0xd2,0x12,0xad,0x98,0x12,0xac,0xaa,0xe4, +0x7a,0xb3,0x3, 0xd9,0x12,0x1b,0xed,0x12,0x1f,0xea,0xc2,0x2, 0x12,0x1c,0x4f,0x12, +0xa3,0x66,0xbe,0xb0,0x1, 0x68,0x3, 0x12,0xa3,0x56,0xd2,0x2, 0x2, 0x1c,0x4f,0xa2, +0xac,0x92,0x3, 0xc2,0xac,0x7e,0xf, 0x4f,0xa1,0x30,0x2, 0xa, 0xb, 0x16,0xb, 0xa, +0x30,0x4e,0x70,0x3, 0x80,0x8, 0xb, 0x16,0xb, 0xa, 0x30,0x5e,0x70,0xfc,0x1b,0xa, +0x30,0xa2,0x3, 0x92,0xac,0x22,0xca,0x3b,0xc2,0x2, 0x12,0x1c,0x4f,0xc2,0xf, 0x30, +0xe, 0x11,0xc2,0xe, 0x12,0x3e,0x74,0x12,0x2f,0x59,0x12,0x3d,0x1f,0x12,0x4f,0x55, +0x12,0x1a,0x33,0xd2,0x2, 0x12,0x1c,0x4f,0xc2,0x1, 0x12,0xa1,0x68,0x30,0x10,0x39, +0xc2,0x10,0x7e,0x3f,0x4f,0xa1,0x69,0x33,0x0, 0x6, 0x7d,0x23,0x5e,0x24,0x0, 0x1, +0x68,0x27,0x5e,0x34,0x0, 0x2, 0x68,0x5, 0x12,0xac,0x6e,0x80,0xe, 0x75,0x13,0x1, +0x74,0x1, 0x7a,0xb3,0x4f,0x55,0x7f,0x3, 0x12,0x1f,0xe3,0x12,0x3d,0x1f,0xe5,0x13, +0x12,0x2f,0xb7,0x74,0x1f,0x7a,0xb3,0x44,0x80,0xd2,0x1, 0x12,0xa1,0x68,0xda,0x3b, +0x22,0x74,0x5, 0x7a,0xb3,0x4f,0x97,0x12,0x1c,0x76,0x7e,0xb3,0x44,0x7f,0x60,0x11, +0x80,0xa, 0x7e,0x34,0x9, 0xc4,0x12,0x1d,0x19,0x12,0x1c,0x76,0x12,0x6a,0x89,0x50, +0xf1,0x7e,0xb3,0x44,0x80,0x60,0x11,0x80,0xa, 0x7e,0x34,0x9, 0xc4,0x12,0x1d,0x19, +0x12,0x1c,0x76,0x12,0x69,0x35,0x50,0xf1,0x22,0x6d,0x22,0x7a,0x27,0x4f,0x5d,0x7a, +0x37,0x4f,0x5f,0x22,0x12,0x49,0x69,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x74,0x12,0x40, +0x9c,0x12,0x1c,0xe1,0x7e,0x34,0x9, 0xc4,0x12,0x1d,0x19,0x7e,0xb3,0x4d,0xeb,0x30, +0xe7,0x5b,0x7e,0xb3,0x4d,0xfc,0x70,0x5, 0xc2,0x2, 0x12,0x45,0xf2,0x12,0x1c,0x76, +0x30,0x12,0x8, 0xc2,0x12,0x12,0x3d,0xc, 0x12,0x1c,0x24,0x7e,0xb3,0x4d,0xfc,0x70, +0x5, 0x12,0x70,0xf4,0x80,0x6, 0x12,0x71,0xb, 0x12,0x71,0xd2,0x7e,0xb3,0x44,0x7e, +0xb4,0x1, 0x17,0x12,0x77,0x8, 0x74,0x2, 0x12,0x9d,0x1a,0x12,0xaa,0xce,0x12,0x48, +0x3, 0x12,0x9c,0x2c,0x12,0x6c,0x5, 0x12,0x21,0x6, 0x12,0x51,0xa6,0x7e,0xb3,0x4d, +0xfc,0x70,0xa, 0x7e,0xb3,0x4d,0xeb,0x54,0x7f,0x7a,0xb3,0x4d,0xeb,0x12,0x51,0x35, +0x80,0x85,0xd2,0x2c,0xd2,0x2, 0x12,0x45,0xf2,0x2, 0x1d,0xac,0xe4,0x7a,0xb3,0x4f, +0x94,0x6d,0x33,0x7a,0x37,0x4f,0x95,0x22,0x7e,0x34,0x13,0x85,0x12,0x1d,0xf2,0x12, +0x1d,0x19,0x12,0x55,0x15,0x12,0x34,0x8a,0x12,0x1f,0xf8,0x7a,0xb3,0x4f,0x6e,0x7e, +0x34,0xd, 0xac,0x2, 0x1a,0x30,0x7a,0x37,0x3f,0xed,0xe4,0x7a,0xb3,0x4f,0xae,0x7e, +0x34,0x13,0x95,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0x30,0x7a,0x37,0x3f,0xf7,0x7e,0x34, +0x13,0x97,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0x30,0x22,0x90,0x13,0x7f,0xe4,0x93,0x7a, +0xb3,0x3f,0xe9,0x12,0x1f,0xd9,0x7e,0x34,0x13,0x89,0x12,0x1d,0xf2,0x7a,0x37,0x3f, +0xeb,0x7e,0x34,0x13,0x8b,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xed,0x7e,0x34,0x13,0x8d, +0x12,0x1d,0xf2,0x12,0x1f,0xa2,0x7a,0x37,0x3f,0xef,0x7e,0x34,0x13,0x8f,0x12,0x1d, +0xf2,0x7a,0x37,0x3f,0xf1,0x7e,0x34,0x13,0x91,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xf3, +0x7e,0x34,0x13,0x93,0x12,0x1d,0xf2,0x12,0x1f,0xa2,0x7a,0x37,0x3f,0xf5,0x12,0x1d, +0xdf,0x12,0x1f,0xa2,0x7a,0x37,0x3f,0xf9,0x90,0x13,0xc9,0xe4,0x93,0x7a,0xb3,0x3f, +0xfd,0x90,0x13,0x82,0xe4,0x93,0x7a,0xb3,0x3f,0xfe,0x7e,0x34,0x13,0x83,0x12,0x1d, +0xf2,0x7a,0x37,0x3f,0xff,0x7e,0x34,0x13,0x99,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xfb, +0xe4,0x7a,0xb3,0x40,0x1, 0x7a,0xb3,0x40,0x2, 0x7a,0xb3,0x40,0x3, 0x7a,0xb3,0x40, +0x4, 0x7a,0xb3,0x40,0x5, 0x7a,0xb3,0x40,0x6, 0x7a,0xb3,0x40,0x7, 0x7a,0xb3,0x40, +0x8, 0x7a,0xb3,0x40,0x9, 0x7a,0xb3,0x40,0xa, 0x22,0x7e,0x34,0x13,0x89,0x12,0x1d, +0xf2,0x12,0x1f,0x16,0x7a,0x73,0x4d,0x79,0x7e,0x34,0x13,0x8b,0x12,0x1d,0xf2,0x12, +0x1f,0xb1,0x7a,0x73,0x4d,0x7a,0x7e,0x34,0x13,0x8f,0x12,0x1d,0xf2,0x12,0x1f,0x16, +0x7a,0x73,0x4d,0x7b,0x7e,0x34,0x13,0x91,0x12,0x1d,0xf2,0x12,0x1f,0xb1,0x7a,0x73, +0x4d,0x7c,0x7e,0x34,0x13,0x99,0x12,0x1d,0xf2,0x12,0x1f,0x16,0x7a,0x73,0x4d,0x7e, +0x7e,0x34,0x0, 0x6a,0xca,0x39,0x7e,0x34,0x13,0x9d,0x7e,0x24,0x0, 0xff,0x7e,0x8, +0x4d,0x7f,0x12,0x16,0x35,0x1b,0xfd,0x22,0x6e,0x34,0xff,0xff,0xb, 0x34,0x7a,0x37, +0x3f,0xf9,0x7e,0x37,0x3f,0xeb,0x1e,0x34,0x1e,0x34,0x1e,0x34,0x1e,0x34,0x1e,0x34, +0x22,0x7e,0x34,0x13,0x89,0x12,0x1d,0xf2,0x12,0x1f,0xd5,0x7e,0x34,0x13,0x8b,0x12, +0x1d,0xf2,0x12,0x1d,0xd6,0x12,0x1f,0x8, 0x12,0x1f,0xa9,0x7a,0x73,0x4d,0x7a,0x22, +0x7e,0xb3,0x4d,0xc9,0xb4,0x1, 0x5, 0x12,0x1f,0x21,0x80,0xf, 0x7e,0xb3,0x40,0x3, +0xb4,0x1, 0x5, 0x12,0x1f,0xbc,0x80,0x3, 0x12,0x59,0xf7,0x7e,0xb3,0x4f,0xae,0x70, +0x17,0x7e,0xb3,0x3f,0xdd,0x70,0x11,0x7e,0xb3,0x40,0x3, 0x70,0xb, 0x7e,0x34,0x13, +0x9b,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xeb,0x12,0x9d,0x9e,0x68,0x16,0x7e,0x34,0x13, +0x8f,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xf1,0x7e,0x34,0x13,0x91,0x12,0x1d,0xf2,0x7a, +0x37,0x3f,0xf3,0x7e,0x34,0x13,0x8d,0x12,0x1d,0xf2,0x12,0x1f,0xa2,0x7a,0x37,0x3f, +0xef,0x22,0x6e,0x34,0xff,0xff,0xb, 0x34,0x22,0x7a,0x73,0x4d,0x79,0x7e,0x37,0x3f, +0xed,0xe, 0x34,0xe, 0x34,0xe, 0x34,0xe, 0x34,0xe, 0x34,0x22,0x7e,0x34,0x0, 0x96, +0x12,0x1f,0xd5,0x7e,0x34,0x0, 0x78,0x12,0x1d,0xd6,0x12,0x1f,0x8, 0x12,0x1f,0xa9, +0x7a,0x73,0x4d,0x7a,0x22,0x7a,0x37,0x3f,0xeb,0x90,0x13,0x81,0xe4,0x93,0x7a,0xb3, +0x3f,0xea,0x22,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b,0xa, 0x30, +0x22,0x5e,0x70,0xfe,0x1b,0xa, 0x30,0x22,0x74,0x1, 0x7a,0xb3,0x4d,0xa0,0x22,0x12, +0x55,0x15,0x12,0x1e,0xaa,0x12,0x34,0x8a,0x12,0x3e,0x68,0x12,0x1a,0x21,0x7e,0xb3, +0x4d,0xa0,0x24,0xfd,0x68,0x9, 0xb, 0xb1,0x78,0xf4,0x12,0x20,0x24,0x80,0xef,0x12, +0x1d,0x24,0x80,0xea,0x30,0x2c,0xf, 0x7e,0xb3,0x4d,0xe7,0xb4,0x1, 0x8, 0x74,0x1, +0x7a,0xb3,0x44,0x7e,0x80,0x3, 0x12,0x4a,0x4b,0xc2,0x2c,0x7e,0xb3,0x4f,0x6e,0xb4, +0x1, 0x2, 0x80,0x2, 0x1, 0xcd,0x12,0x54,0xb0,0x12,0x69,0xbd,0x12,0x2b,0xbd,0x12, +0x1c,0xe1,0x7e,0x34,0x13,0x87,0x12,0x1d,0xf2,0x12,0x1d,0x19,0x12,0x71,0xb, 0x7e, +0xb3,0x24,0x26,0x70,0x2, 0x80,0x24,0x12,0x77,0x8, 0x7e,0xb3,0x4d,0x9d,0xb4,0x1, +0x2, 0xd2,0x86,0x12,0x7d,0x75,0x7e,0xb3,0x40,0x2, 0x70,0x6, 0x12,0x1f,0x40,0x12, +0xaa,0xce,0x12,0x6c,0x5, 0x7e,0xb3,0x24,0x26,0x70,0xb, 0x12,0x92,0x4d,0x12,0x51, +0x54,0x12,0xa8,0x55,0x80,0xa5,0x74,0x1, 0x12,0x20,0xe2,0x12,0x21,0x6, 0x12,0x81, +0xf7,0x12,0x5b,0x39,0x12,0x5f,0xd5,0x74,0x2, 0x12,0x20,0xe2,0x12,0x88,0x18,0x74, +0x3, 0x12,0x20,0xe2,0x12,0x5c,0x7, 0x74,0x4, 0x12,0x20,0xe2,0x12,0x5d,0xb8,0x12, +0x60,0xef,0x12,0x54,0x8a,0x12,0xa6,0x95,0x12,0x51,0x5d,0x1, 0x3b,0xd2,0x2, 0x12, +0x45,0xf2,0x2, 0x20,0xd5,0x12,0xa7,0xd9,0x7e,0xb3,0x4d,0x9d,0xb4,0x1, 0x2, 0xd2, +0x86,0x22,0x1b,0xb1,0x68,0x10,0x14,0x68,0x13,0x14,0x68,0x16,0x24,0x3, 0x78,0x15, +0xe4,0x7a,0xb3,0x3f,0xe7,0x22,0x12,0x0, 0xa, 0x2, 0x8f,0xc4,0x12,0x8c,0xb7,0x2, +0x62,0xb7,0x2, 0x90,0x8d,0x22,0xc2,0x23,0x7e,0xb3,0x40,0x1, 0x70,0x3, 0x12,0x7e, +0xae,0x12,0x23,0x3d,0x12,0x27,0x28,0x12,0x25,0x87,0x12,0x23,0x3d,0x12,0x27,0x79, +0x12,0x23,0x3d,0x12,0x85,0x18,0x12,0x23,0x3d,0x12,0x23,0x89,0x12,0x23,0x3d,0x2, +0x21,0x32,0xca,0x3b,0xc2,0x0, 0x7e,0xd3,0x3e,0x53,0xa, 0x3d,0x3e,0x34,0xca,0x39, +0x7e,0x18,0x3c,0xc9,0x7e,0x8, 0x44,0x87,0x12,0x16,0x35,0x1b,0xfd,0x6c,0x11,0x75, +0x27,0x0, 0x6c,0xcc,0x41,0x16,0x7e,0x44,0x3, 0xff,0x7e,0xe0,0xff,0x6c,0xff,0x80, +0x64,0x7c,0xbf,0x12,0x5b,0xf5,0x60,0x5b,0x74,0x2, 0xac,0xbf,0x9, 0x5, 0x44,0x87, +0xbe,0x0, 0xff,0x68,0x4e,0x9, 0x5, 0x44,0x88,0xa, 0x10,0x7e,0x70,0x2, 0xac,0x7c, +0x9, 0x3, 0x4e,0x9f,0xa, 0x30,0x12,0x7c,0x3, 0x8, 0x4, 0x9d,0x31,0x80,0x4, 0x6d, +0x33,0x9d,0x32,0x74,0x2, 0xac,0xbf,0x9, 0x5, 0x44,0x87,0xa, 0xf0,0x74,0x2, 0xac, +0xbc,0x9, 0x5, 0x4e,0x9e,0xa, 0x10,0x7d,0x21,0x9d,0x2f,0xbe,0x24,0x0, 0x0, 0x8, +0x4, 0x9d,0x1f,0x80,0x4, 0x6d,0x11,0x9d,0x12,0x2d,0x13,0xbd,0x41,0x28,0x4, 0x7d, +0x41,0x7c,0xef,0xb, 0xf0,0xbc,0xdf,0x38,0x98,0xbe,0xe0,0xff,0x68,0x46,0x7e,0x70, +0x2, 0xac,0x7e,0x9, 0xb3,0x44,0x87,0x9, 0x73,0x44,0x88,0x12,0x23,0x82,0x7d,0x13, +0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x44,0x87,0x12,0x80,0xaf,0xbd,0x13,0x48,0x25,0x7e, +0x70,0x2, 0xac,0x7e,0x9, 0x3, 0x44,0x87,0x7e,0xa1,0x27,0x74,0x2, 0xa4,0x19,0x5, +0x44,0xc3,0x9, 0x3, 0x44,0x88,0x19,0x5, 0x44,0xc4,0x74,0xff,0x19,0xb3,0x44,0x87, +0xb, 0x10,0x5, 0x27,0xb, 0xc0,0x7e,0x3, 0x4e,0xda,0xbc,0xc, 0x28,0x2, 0x21,0x56, +0x7c,0xc1,0x41,0xb4,0x6d,0x0, 0x7e,0xe0,0xff,0x6c,0xff,0x80,0x5a,0x7c,0xbf,0x12, +0x5b,0xf5,0x60,0x51,0x7e,0x30,0x2, 0xac,0x3f,0x9, 0xb1,0x44,0x87,0xbe,0xb0,0xff, +0x68,0x43,0x9, 0x71,0x44,0x88,0x12,0x23,0x82,0x7d,0x43,0xc2,0x0, 0xbd,0x4, 0x58, +0x2, 0xd2,0x0, 0x30,0x0, 0x2f,0x7e,0xb3,0x40,0x2, 0x60,0x14,0x7e,0x73,0x3f,0xde, +0xbe,0x70,0x2, 0x40,0xb, 0x7e,0x37,0x3e,0x59,0x12,0x6f,0xf0,0xbd,0x34,0x18,0x15, +0x7e,0x70,0x2, 0xac,0x7f,0x9, 0xb3,0x44,0x87,0xf5,0x28,0x9, 0xb3,0x44,0x88,0xf5, +0x29,0x7d,0x4, 0x7c,0xef,0xb, 0xf0,0xbc,0xdf,0x38,0xa2,0xbe,0xe0,0xff,0x68,0x22, +0x7e,0xa1,0x28,0x7e,0x31,0x27,0x74,0x2, 0xac,0x3b,0x19,0xa1,0x44,0xc3,0xe5,0x29, +0x19,0xb1,0x44,0xc4,0x7e,0xa0,0xff,0x7e,0x30,0x2, 0xac,0x3e,0x19,0xa1,0x44,0x87, +0x5, 0x27,0xb, 0xc0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbc,0x28,0x2, 0x41,0x24,0x90, +0x13,0x80,0xe4,0x93,0x7c,0xab,0x74,0x2, 0xa4,0xca,0x59,0x7e,0x18,0x44,0xc3,0x7e, +0x8, 0x44,0x87,0x12,0x16,0x35,0x1b,0xfd,0x7e,0xd1,0x27,0x12,0x3c,0xcc,0x7e,0x8, +0x4e,0x9e,0x74,0xff,0x12,0x16,0x5a,0xbe,0xd0,0x0, 0x28,0x37,0xa, 0x3d,0x3e,0x34, +0xca,0x39,0x7e,0x18,0x44,0x87,0x7e,0x8, 0x3c,0xc9,0x12,0x16,0x35,0x1b,0xfd,0xa, +0x3d,0x3e,0x34,0xca,0x39,0x7e,0x18,0x44,0x87,0x7e,0x8, 0x4e,0x9e,0x12,0x16,0x35, +0x1b,0xfd,0x6c,0xcc,0x80,0x9, 0xd2,0x6, 0x7c,0xbc,0x12,0x26,0xfa,0xb, 0xc0,0xbc, +0xdc,0x38,0xf3,0x7a,0xd3,0x4e,0xda,0x7a,0xd3,0x3e,0x53,0x90,0x13,0x7f,0xe4,0x93, +0xbe,0xb3,0x3e,0x53,0x50,0x4, 0x7a,0xb3,0x3e,0x53,0xda,0x3b,0x22,0xca,0x79,0x6c, +0xff,0x6c,0xee,0x80,0x2c,0x7c,0xbe,0x12,0x5b,0xf5,0x60,0x23,0x7e,0x34,0x0, 0x2, +0xca,0x39,0xac,0x7e,0x2e,0x34,0x3c,0xc9,0x6d,0x22,0x7e,0x30,0x2, 0xac,0x3f,0x2e, +0x14,0x3c,0xc9,0x6d,0x0, 0x12,0x16,0x35,0x1b,0xfd,0xd2,0x6, 0x12,0x27,0x71,0xb, +0xe0,0x12,0x5f,0xd8,0x38,0xcf,0x7a,0xf3,0x3e,0x53,0xda,0x79,0x22,0xe5,0x2b,0x7e, +0x71,0x2c,0x12,0x7d,0x3c,0xb, 0x1a,0x30,0x22,0x7e,0xb3,0x40,0x2, 0x60,0x2, 0xa1, +0x86,0x12,0xad,0xf3,0x78,0x2, 0xa1,0x86,0x7e,0xa3,0x3e,0x53,0xbe,0xa0,0x1, 0x78, +0x1b,0x7e,0xb3,0x3e,0x69,0x70,0x15,0x7e,0xb3,0x3c,0xc9,0x7a,0xb3,0x4e,0x9b,0x7e, +0xb3,0x3c,0xca,0x7a,0xb3,0x4e,0x9c,0xe4,0x7a,0xb3,0x4e,0x9d,0xbe,0xa0,0x0, 0x28, +0x3e,0xc2,0x0, 0x6c,0x11,0x80,0x21,0x12,0xad,0x3b,0x7e,0x73,0x4e,0x9b,0xa, 0x27, +0x1a,0x39,0x12,0xad,0xc4,0x58,0xf, 0x7e,0x73,0x4e,0x9c,0xa, 0x27,0x1a,0x30,0x12, +0xad,0xc4,0x58,0x2, 0xd2,0x0, 0xb, 0x10,0x12,0x26,0xe5,0x38,0xda,0x30,0x0, 0xc, +0x7e,0xb3,0x4e,0x9d,0xbe,0xb0,0xc8,0x50,0xb, 0x4, 0x80,0x4, 0xe4,0x80,0x1, 0xe4, +0x7a,0xb3,0x4e,0x9d,0x7e,0x73,0x3e,0x53,0xbe,0x70,0x2, 0x50,0x2, 0xa1,0x86,0x7e, +0xb3,0x3f,0xde,0xb4,0x1, 0x2, 0x80,0x2, 0xa1,0x86,0x6d,0xee,0x6c,0x11,0x80,0x18, +0x12,0xad,0x3b,0x12,0x26,0xae,0xbd,0xde,0x8, 0xc, 0x7d,0xed,0x7a,0x93,0x3e,0x5b, +0x7a,0x3, 0x3e,0x5c,0x7c,0x81,0xb, 0x10,0x12,0x26,0xe5,0x38,0xe3,0x6c,0x11,0xa1, +0x7f,0xbc,0x81,0x78,0x2, 0xa1,0x7d,0x7e,0x30,0x2, 0xac,0x31,0x9, 0xb1,0x3c,0xc9, +0xf5,0x2b,0x9, 0xb1,0x3c,0xca,0xf5,0x2c,0x7e,0xa3,0x3e,0x5b,0x7a,0xa1,0x2d,0x7e, +0xb3,0x3e,0x5c,0xf5,0x2e,0xbe,0xa1,0x2b,0x28,0x4, 0xe5,0x2b,0x80,0x2, 0xe5,0x2d, +0xf5,0x27,0xe5,0x2d,0xbe,0xb1,0x2b,0x50,0x4, 0xe5,0x2b,0x80,0x2, 0xe5,0x2d,0xf5, +0x29,0xe5,0x2e,0xbe,0xb1,0x2c,0x28,0x4, 0xe5,0x2c,0x80,0x2, 0xe5,0x2e,0xf5,0x28, +0xe5,0x2e,0xbe,0xb1,0x2c,0x50,0x5, 0x7e,0xa1,0x2c,0x80,0x3, 0x7e,0xa1,0x2e,0x7a, +0xa1,0x2a,0xe5,0x27,0x1a,0xfb,0xe5,0x29,0x1a,0x1b,0x9d,0x1f,0xb, 0x14,0x7c,0xb3, +0xf5,0x2f,0xe5,0x28,0x1a,0x1b,0x1a,0x5a,0x9d,0x51,0xb, 0x54,0xf5,0x30,0x12,0x23, +0x7d,0x7d,0xf3,0xe5,0x30,0xbe,0xb1,0x2f,0x50,0x4c,0xe5,0x28,0xbe,0xb0,0x0, 0x8, +0x2, 0x15,0x28,0x7e,0x73,0x40,0x12,0xa, 0xc7,0x1b,0xc4,0xe5,0x2a,0x1a,0x1b,0xbd, +0x1c,0x58,0x2, 0x5, 0x2a,0x7e,0x91,0x29,0x12,0x23,0x7d,0x7d,0xe3,0x80,0x1f,0x1b, +0x90,0x6d,0xdd,0x7e,0x1, 0x2a,0x80,0xa, 0x12,0x26,0xec,0x8, 0x3, 0x12,0x26,0xae, +0x1b,0x0, 0xe5,0x28,0xbc,0xb0,0x8, 0xf0,0xbd,0xde,0x58,0x2, 0x7d,0xed,0xe5,0x27, +0xbc,0xb9,0x48,0xdb,0x80,0x4a,0xe5,0x27,0xbe,0xb0,0x0, 0x8, 0x2, 0x15,0x27,0x7e, +0x73,0x40,0x11,0xa, 0xc7,0x1b,0xc4,0xe5,0x29,0x1a,0x1b,0xbd,0x1c,0x58,0x2, 0x5, +0x29,0x7e,0x1, 0x2a,0x12,0x23,0x7d,0x7d,0xe3,0x80,0x1f,0x1b,0x0, 0x6d,0xdd,0x7e, +0x91,0x29,0x80,0xa, 0x12,0x26,0xec,0x8, 0x3, 0x12,0x26,0xae,0x1b,0x90,0xe5,0x27, +0xbc,0xb9,0x8, 0xf0,0xbd,0xde,0x58,0x2, 0x7d,0xed,0xe5,0x28,0xbc,0xb0,0x48,0xdb, +0x7d,0x3f,0x3e,0x34,0x3e,0x34,0x7e,0x24,0x0, 0xa, 0x12,0x14,0x9f,0xbd,0x3e,0x58, +0xc, 0x7e,0x73,0x4e,0x9d,0xbe,0x70,0x28,0x50,0x3, 0x12,0xad,0xec,0xb, 0x10,0x12, +0x26,0xe5,0x28,0x2, 0x81,0x41,0x22,0xca,0xd8,0xca,0x79,0xc2,0x0, 0xc2,0x1, 0xc2, +0x4, 0xd2,0x2, 0xd2,0x3, 0x6c,0xdd,0x80,0x41,0x12,0xac,0xf1,0x12,0x26,0xcd,0x50, +0x4, 0xd2,0x1, 0x80,0x33,0xd2,0x0, 0xd2,0x4, 0x7e,0x73,0x40,0x12,0xa, 0x27,0x1b, +0x24,0xa, 0x3e,0xbd,0x32,0x58,0x2, 0xc2,0x2, 0x4c,0xff,0x78,0x8, 0x7c,0xbf,0x4, +0x12,0x26,0xb8,0x18,0x13,0x7e,0xb3,0x40,0x11,0x14,0xbc,0xbf,0x78,0x8, 0x7c,0xbf, +0x14,0x12,0x26,0xb8,0x18,0x2, 0xc2,0x3, 0xb, 0xd0,0x7e,0xb3,0x3e,0x53,0xbc,0xbd, +0x38,0xb7,0xa2,0x4, 0x82,0x3, 0x92,0x3, 0xa2,0x4, 0x82,0x2, 0x92,0x2, 0xc2,0x3, +0x70,0xe, 0x7e,0xb3,0x4e,0x9a,0xbe,0xb0,0x0, 0x28,0x5, 0x14,0x7a,0xb3,0x4e,0x9a, +0xa2,0x24,0x92,0x6, 0x12,0x7f,0xff,0x92,0x5, 0x30,0x1, 0x6, 0xa2,0x5, 0x92,0x1, +0x92,0x24,0x7e,0x73,0x4e,0x9a,0xbe,0x70,0x0, 0x28,0x5, 0x20,0x3, 0x2, 0xc2,0x1, +0xa2,0x3, 0x82,0x0, 0x82,0x1, 0x50,0x2, 0xc2,0x0, 0xa2,0x0, 0x82,0x1, 0x50,0x29, +0x7e,0xb3,0x4e,0x99,0xb4,0x1, 0x4, 0xc2,0x1, 0x80,0x1e,0xb4,0x2, 0x7, 0x20,0x2, +0x4, 0xc2,0x1, 0x80,0x14,0x70,0x12,0x7e,0x27,0x3e,0x59,0x7e,0x34,0x0, 0x5, 0xad, +0x32,0xbe,0x37,0x3e,0x61,0x8, 0x2, 0xc2,0x1, 0x30,0x1, 0x2, 0xc2,0x0, 0x30,0x1, +0x4, 0x74,0x2, 0x80,0x12,0x30,0x0, 0xe, 0x74,0x1, 0x7a,0xb3,0x4e,0x99,0x74,0x8, +0x7a,0xb3,0x4e,0x9a,0x80,0x5, 0xe4,0x7a,0xb3,0x4e,0x99,0x6c,0xdd,0x80,0x22,0x12, +0xac,0xf1,0x12,0x26,0xcd,0x50,0x5, 0x20,0x1, 0x2, 0x80,0xc, 0x7c,0xbf,0x7c,0x7e, +0x12,0x26,0xcd,0x40,0xa, 0x20,0x0, 0x7, 0xc2,0x6, 0x7c,0xbd,0x12,0x26,0xfa,0xb, +0xd0,0x7e,0x73,0x3e,0x53,0xbc,0x7d,0x38,0xd6,0xda,0x79,0xda,0xd8,0x22,0x7c,0xb9, +0x7c,0x70,0x12,0x23,0x82,0x7d,0xd3,0x22,0x7c,0x7e,0x12,0x23,0x82,0x7e,0xf4,0x0, +0x3, 0xad,0xf3,0x7c,0xbf,0x7c,0x7e,0x12,0x23,0x82,0xbd,0x3f,0x22,0x7c,0xa7,0x7c, +0x7b,0x90,0x14,0x28,0xe4,0x93,0xbc,0xb7,0x78,0x9, 0x7c,0xba,0x12,0x96,0xb4,0x50, +0x2, 0xd3,0x22,0xc3,0x22,0x7e,0x73,0x3e,0x53,0xbc,0x71,0x22,0x7c,0xb9,0x7c,0x70, +0x12,0x23,0x82,0xbd,0x3d,0x22,0xd2,0x6, 0x7c,0xb3,0x7c,0x7b,0xc4,0x23,0x54,0x1f, +0x7c,0xab,0x12,0x58,0xc1,0x30,0x6, 0xf, 0xa, 0x3a,0x2e,0x34,0x3d,0x41,0x7e,0x39, +0xa0,0x4c,0xba,0x7a,0x39,0xb0,0x22,0x64,0xff,0xa, 0x2a,0x2e,0x24,0x3d,0x41,0x7e, +0x29,0x70,0x5c,0x7b,0x7a,0x29,0x70,0x22,0x12,0x7f,0xa8,0x28,0x3a,0x7e,0xb3,0x3f, +0xde,0x70,0x34,0x7e,0x37,0x3e,0x55,0xbe,0x34,0x0, 0x26,0x28,0x2f,0x7e,0xb3,0x4f, +0x93,0xbe,0xb0,0x2, 0x50,0x26,0x4, 0x7a,0xb3,0x4f,0x93,0x6c,0x33,0x80,0x9, 0xc2, +0x6, 0x7c,0xb3,0x12,0x26,0xfa,0xb, 0x30,0x7e,0x23,0x3e,0x53,0xbc,0x23,0x38,0xef, +0xe4,0x7a,0xb3,0x3e,0x53,0x80,0x5, 0xe4,0x7a,0xb3,0x4f,0x93,0x2, 0x23,0x3d,0xc2, +0x6, 0x7c,0xbf,0x12,0x26,0xfa,0xb, 0xf0,0x22,0xca,0xf8,0xc2,0x0, 0xc2,0x1, 0x12, +0xad,0xf3,0x68,0x70,0x7e,0xb3,0x3e,0x53,0x70,0x5, 0x12,0x98,0xde,0x80,0x65,0x12, +0x97,0x1, 0x92,0x1, 0x12,0x98,0xfd,0x92,0x0, 0x30,0x0, 0x13,0x7e,0x34,0x14,0x55, +0x12,0x1d,0xf2,0x7a,0x37,0x4f,0x91,0x74,0x1, 0x7a,0xb3,0x4f,0x8d,0x80,0x14,0x30, +0x1, 0x19,0x7e,0x34,0x14,0x55,0x12,0x1d,0xf2,0x7a,0x37,0x4f,0x91,0x74,0x1, 0x7a, +0xb3,0x4f,0x8e,0x74,0x1, 0x7a,0xb3,0x4f,0x8c,0x80,0x3, 0x12,0x98,0xde,0x7e,0xb3, +0x4f,0x8d,0x60,0xe, 0x6c,0xff,0x80,0x3, 0x12,0x27,0x6f,0x12,0x27,0xf7,0x38,0xf8, +0x80,0x12,0x7e,0xb3,0x4f,0x8e,0x60,0xc, 0x6c,0xff,0x80,0x3, 0x12,0x27,0x6f,0x12, +0x27,0xf7,0x38,0xf8,0xda,0xf8,0x22,0x7e,0x73,0x3e,0x53,0xbc,0x7f,0x22,0xca,0x3b, +0x7e,0xf3,0x4f,0x55,0x7e,0x30,0x27,0xac,0x3f,0x9, 0xb1,0x4b,0xa2,0xf5,0x2b,0x9, +0xb1,0x4b,0xa3,0xf5,0x2c,0x7e,0x4, 0x0, 0x27,0xca,0x9, 0x2e,0x14,0x4b,0xa2,0x6d, +0x0, 0x7e,0x18,0x4e,0x1c,0x12,0x16,0x35,0x1b,0xfd,0x74,0x27,0xac,0xbf,0x9, 0xe5, +0x4b,0xa6,0x7e,0xd0,0xb5,0xac,0xde,0x2e,0x64,0x1, 0x0, 0xe4,0x12,0x4f,0xc9,0x12, +0x2a,0x16,0x5e,0x24,0x1, 0x0, 0x68,0x9, 0x5e,0x60,0xfe,0x12,0x2a,0x24,0x12,0x30, +0x19,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x1, 0x68,0x2e,0x5e,0x70,0xfe,0x7a,0x37,0x2d, +0x6, 0x7e,0xb3,0x4e,0x1c,0x12,0x30,0x1, 0x50,0xc, 0x7e,0xb3,0x4e,0x1c,0x12,0x30, +0x7a,0x12,0x2a,0x90,0x80,0x12,0x7e,0xa1,0x2b,0x7e,0x70,0x27,0xac,0x7f,0x19,0xa3, +0x4b,0xa2,0xe5,0x2b,0x7a,0xb3,0x4e,0x1c,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x2, 0x68, +0x2e,0x5e,0x70,0xfd,0x7a,0x37,0x2d,0x6, 0x7e,0xb3,0x4e,0x1d,0x12,0x31,0x14,0x50, +0xc, 0x7e,0xb3,0x4e,0x1d,0x12,0x2d,0x3a,0x12,0x2a,0x90,0x80,0x12,0x7e,0xa1,0x2c, +0x7e,0x70,0x27,0xac,0x7f,0x19,0xa3,0x4b,0xa3,0xe5,0x2c,0x7a,0xb3,0x4e,0x1d,0x12, +0x2a,0x16,0x5e,0x24,0x0, 0x4, 0x68,0x34,0x5e,0x70,0xfb,0x12,0x2a,0x1d,0x12,0x2a, +0x57,0x7e,0x30,0x2c,0xac,0x3e,0x12,0x2c,0x5b,0x74,0x1, 0x7e,0x70,0x27,0xac,0x7f, +0x12,0xad,0xce,0x12,0x2c,0x62,0x12,0x2a,0x2b,0x12,0x2d,0x1b,0x12,0x2d,0x31,0x49, +0x25,0x0, 0xdf,0x12,0x0, 0x2e,0x12,0x31,0xd, 0x12,0x50,0x44,0x12,0x2a,0x16,0x5e, +0x24,0x0, 0x8, 0x68,0xe, 0x5e,0x70,0xf7,0x7a,0x37,0x2d,0x6, 0x7e,0xb3,0x4e,0x1f, +0x12,0x30,0xc6,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x10,0x68,0xf, 0x5e,0x70,0xef,0x12, +0x2a,0x24,0x12,0x2a,0x57,0x12,0x2a,0x2b,0x12,0x2d,0x1b,0x12,0x2a,0x16,0x5e,0x24, +0x0, 0x20,0x68,0x41,0x5e,0x70,0xdf,0x7a,0x37,0x2d,0x6, 0x4e,0x60,0x2, 0x12,0x2a, +0x1d,0x12,0x2a,0x57,0x12,0x2c,0x62,0x12,0x2a,0x4b,0x74,0xa, 0xac,0xbf,0x12,0xad, +0x76,0x12,0x2a,0x4b,0x7e,0x70,0x27,0xac,0x7f,0x12,0xad,0x81,0x7c,0xbf,0x12,0xa8, +0x61,0x12,0x2d,0x31,0x49,0x25,0x0, 0xdf,0x12,0x0, 0x2e,0x12,0x2a,0x45,0x7e,0x24, +0x0, 0x10,0x12,0xc, 0xcc,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x40,0x68,0xc, 0x5e,0x70, +0xbf,0x12,0x2a,0x24,0x12,0x4e,0x89,0x12,0x46,0xa, 0x12,0x2a,0x16,0x5e,0x24,0x0, +0x80,0x68,0xa, 0x5e,0x70,0x7f,0x7a,0x37,0x2d,0x6, 0x12,0x3f,0x7a,0x12,0x2a,0x16, +0x5e,0x24,0x2, 0x0, 0x68,0x3b,0x5e,0x60,0xfd,0x7a,0x37,0x2d,0x6, 0x74,0x27,0xac, +0xbf,0x49,0xe5,0x4b,0xa9,0xb, 0xe4,0x7e,0xf7,0x4e,0x45,0xad,0xef,0xbe,0x78,0x7f, +0xff,0x28,0x4, 0x7e,0x78,0x7f,0xff,0x7e,0x8, 0x0, 0x69,0x12,0x2d,0x22,0x7e,0x8, +0x0, 0xa5,0x12,0x2d,0x22,0x7e,0x8, 0x0, 0x69,0x7d,0x3f,0x12,0xa9,0x1d,0x12,0xc, +0xcc,0x12,0x2a,0x16,0x5e,0x24,0x4, 0x0, 0x68,0x7, 0x5e,0x60,0xfb,0x7a,0x37,0x2d, +0x6, 0x12,0x2a,0x16,0x5e,0x24,0x10,0x0, 0x68,0x7, 0x5e,0x60,0xef,0x7a,0x37,0x2d, +0x6, 0x12,0x2a,0x16,0x5e,0x24,0x20,0x0, 0x68,0x9, 0x5e,0x60,0xdf,0x12,0x2a,0x24, +0x12,0x50,0x4b,0xda,0x3b,0x22,0x7e,0x37,0x2d,0x6, 0x7d,0x23,0x22,0x7a,0x37,0x2d, +0x6, 0x4e,0x60,0x10,0x7a,0x37,0x2d,0x6, 0x7c,0xbf,0x22,0x7e,0x30,0x2c,0xac,0x3e, +0x2e,0x14,0x0, 0xe7,0x6d,0x0, 0x74,0xa, 0xac,0xbf,0x49,0x35,0x4c,0x4e,0x49,0x25, +0x4c,0x4c,0x12,0x9, 0xad,0x7d,0x36,0x2e,0x34,0x0, 0x6, 0x7e,0x30,0x2c,0xac,0x3e, +0x2e,0x14,0x0, 0xe7,0x6d,0x0, 0x22,0xca,0xf8,0x7c,0xfb,0x12,0x2a,0x90,0x7e,0xa3, +0x4e,0x1e,0x7e,0x70,0x27,0xac,0x7f,0x19,0xa3,0x4b,0xa4,0x6c,0xaa,0x7e,0x50,0x2, +0xac,0x5a,0x49,0x42,0x4e,0x23,0x7e,0x70,0x27,0xac,0x7f,0x2d,0x32,0x59,0x43,0x4b, +0xa9,0xb, 0xa0,0xbe,0xa0,0x10,0x40,0xe5,0x7c,0xbf,0x12,0x4a,0xe0,0xda,0xf8,0x22, +0x12,0xad,0xdc,0x68,0x42,0xe5,0x13,0x60,0x3e,0x7e,0xb3,0x4e,0x1c,0x7e,0x73,0x4e, +0x1d,0x12,0xa1,0x8f,0x7d,0x23,0x7e,0x34,0x0, 0x3, 0xad,0x32,0x7e,0x24,0x0, 0xa, +0x8d,0x32,0x6c,0xaa,0x7e,0x50,0x2, 0xac,0x5a,0x49,0x12,0x4e,0x23,0xbd,0x13,0x28, +0xf, 0x59,0x32,0x4e,0x23,0x7e,0x27,0x2d,0x6, 0x4e,0x50,0x20,0x7a,0x27,0x2d,0x6, +0xb, 0xa0,0xbe,0xa0,0x10,0x78,0xdd,0x22,0xca,0x79,0x7c,0xeb,0xbe,0xe0,0x4, 0x40, +0x2, 0x61,0xad,0x74,0x27,0xac,0xbe,0x9, 0xf5,0x4b,0xa6,0xbe,0xf0,0x3, 0x40,0x2, +0x61,0xad,0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x4c,0x3f,0x54,0x3f,0xa, 0x3b,0x74,0x2c, +0xac,0xbf,0x59,0x35,0x0, 0xdb,0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x4c,0x3e,0x54,0x1f, +0x7c,0x6b,0x6c,0x77,0x12,0x2b,0xb6,0x74,0x2c,0xac,0xbf,0x59,0x35,0x0, 0xdd,0x12, +0x2c,0x56,0x74,0x1, 0x7e,0x70,0x27,0xac,0x7e,0x12,0xad,0xce,0x7e,0x30,0x2c,0xac, +0x3f,0x12,0x2a,0x50,0x7e,0x70,0x27,0xac,0x7e,0x12,0xad,0x81,0x7e,0x30,0x2c,0xac, +0x3f,0x12,0x30,0x73,0x74,0x27,0xac,0xbe,0x9, 0x75,0x4b,0xa2,0xa, 0x37,0x12,0x2b, +0xb6,0x12,0xd, 0xd3,0x12,0x2d,0x74,0x74,0x27,0xac,0xbe,0x9, 0x75,0x4b,0xa3,0xa, +0x37,0x12,0x2b,0xb6,0x12,0xd, 0xe5,0x12,0x2d,0x74,0x74,0xa, 0xac,0xbe,0x12,0x2c, +0x71,0x7e,0x30,0x2c,0xac,0x3f,0x12,0x2a,0x50,0x74,0xa, 0xac,0xbe,0x12,0xad,0x76, +0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xef,0x6d,0x0, 0x74,0x27,0xac,0xbe,0x9, +0xb5,0x4b,0xa5,0x12,0xc, 0xaa,0xe4,0x12,0x4f,0xc9,0x7e,0x70,0xb5,0xac,0x7f,0x2e, +0x34,0x1, 0x0, 0x12,0x2c,0x56,0x7e,0x24,0x0, 0x16,0x12,0xc, 0xcc,0xda,0x79,0x22, +0xa, 0x37,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x22,0x7e,0x24,0x4d, +0x79,0x30,0x21,0x7a,0xc2,0x21,0x7e,0x29,0x70,0x12,0x2b,0xb0,0x7a,0x37,0x3f,0xeb, +0x9, 0x72,0x0, 0x1, 0x12,0x2b,0xb0,0x7a,0x37,0x3f,0xed,0x9, 0x72,0x0, 0x2, 0x12, +0x2b,0xb0,0x7a,0x37,0x3f,0xf1,0x9, 0x72,0x0, 0x3, 0x12,0x2b,0xb0,0x7a,0x37,0x3f, +0xf3,0x9, 0x72,0x0, 0x5, 0x12,0x2b,0xb0,0x7a,0x37,0x3f,0xfb,0x9, 0x72,0x0, 0x40, +0x7a,0x73,0x40,0x1, 0x9, 0x72,0x0, 0x41,0xbe,0x73,0x40,0x3, 0x68,0x28,0x7a,0x73, +0x40,0x3, 0x74,0x1, 0x7a,0xb3,0x40,0x4, 0x7e,0xb3,0x40,0x3, 0xb4,0x1, 0xf, 0x7e, +0x73,0x40,0x1, 0x7a,0x73,0x4d,0x78,0xe4,0x7a,0xb3,0x40,0x1, 0x80,0x8, 0x7e,0x73, +0x4d,0x78,0x7a,0x73,0x40,0x1, 0x7e,0x73,0x40,0x1, 0x7a,0x73,0x4d,0xb9,0x7e,0x37, +0x3f,0xeb,0x7a,0x37,0x4d,0xe9,0x4d,0x33,0x78,0xb, 0x7e,0x34,0x13,0x89,0x12,0x1d, +0xf2,0x7a,0x37,0x4d,0xe9,0x22,0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xdb,0x6d, +0x0, 0x22,0x7e,0x30,0x2c,0xac,0x3e,0x2e,0x14,0x0, 0xdf,0x6d,0x0, 0x74,0xa, 0xac, +0xbf,0x9, 0xb5,0x4c,0x46,0x2, 0xd, 0x73,0x12,0x2d,0x12,0x7d,0x1, 0x5e,0x4, 0x0, +0x1, 0x78,0xa, 0xe4,0x7a,0xb3,0x4f,0x55,0x75,0x13,0x0, 0x80,0x31,0x5e,0x14,0x0, +0x2, 0x78,0x7, 0x74,0x1, 0x12,0x2d,0x29,0x80,0x24,0x7e,0xb3,0x4f,0x55,0xbe,0xb0, +0x1, 0x68,0x2, 0x70,0x19,0x12,0x2d,0x9, 0x68,0xb, 0x74,0x2, 0x7a,0xb3,0x4f,0x55, +0x75,0x13,0x2, 0x80,0x9, 0x74,0x3, 0x7a,0xb3,0x4f,0x55,0x75,0x13,0x3, 0x74,0x1, +0x12,0x2a,0xd8,0x7e,0xb3,0x4f,0x55,0x24,0x0, 0x68,0x2d,0x24,0xfd,0x68,0x16,0x4, +0x78,0x2a,0x12,0x2d,0x12,0x5e,0x14,0x0, 0x2, 0x68,0x2d,0x12,0x2d,0x9, 0x78,0x28, +0x74,0x1, 0x2, 0x5, 0xbc,0x12,0x2d,0x12,0x5e,0x14,0x0, 0x2, 0x68,0x1a,0x12,0x2d, +0x9, 0x68,0x15,0x74,0x1, 0x2, 0x5, 0x30,0xe4,0x2, 0x2a,0xd8,0x7e,0xf, 0x4f,0xa1, +0x12,0x1f,0xe3,0x74,0x1, 0x12,0x2d,0x29,0x22,0x69,0x31,0x0, 0xe, 0x5e,0x34,0x0, +0x8, 0x22,0x7e,0x1f,0x4f,0xa1,0x69,0x11,0x0, 0x6, 0x22,0x7e,0x24,0x0, 0x4, 0x2, +0xc, 0xcc,0x7e,0x37,0x4e,0x43,0x2, 0xc, 0x88,0x7a,0xb3,0x4f,0x55,0x75,0x13,0x1, +0x22,0x7d,0x36,0xb, 0x35,0x74,0x2c,0xac,0xbe,0x22,0xca,0x3b,0x7c,0xfb,0x6c,0xee, +0x74,0x27,0xac,0xbe,0x19,0xf5,0x4b,0xa3,0xb, 0xe0,0xbe,0xe0,0x4, 0x78,0xf1,0x7e, +0x64,0x1, 0x0, 0x6c,0xee,0x7e,0x30,0x2c,0xac,0x3e,0x12,0x2d,0x79,0xa, 0x3f,0x12, +0x2b,0xb6,0x12,0xd, 0xe5,0x12,0x2d,0x31,0x49,0x25,0x0, 0xdf,0x12,0x30,0xb9,0x40, +0xe4,0xda,0x3b,0x22,0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xdf,0x6d,0x0, 0x22, +0xca,0x3b,0x7e,0x73,0x4f,0x55,0xa, 0x27,0x12,0x4e,0x80,0x12,0xaa,0x22,0x6d,0x22, +0x7a,0x1d,0x27,0x7e,0x38,0x44,0x8d,0x7e,0x73,0x40,0x13,0x7a,0x73,0x44,0x88,0x7e, +0x73,0x40,0x14,0x7a,0x73,0x44,0x89,0x7e,0x73,0x4e,0x1d,0x7a,0x73,0x44,0x8a,0x7e, +0x73,0x4e,0x14,0x7a,0x73,0x44,0x8b,0x7e,0x73,0x4e,0x15,0x7a,0x73,0x44,0x8c,0x7e, +0x8, 0x44,0x8d,0x7e,0x34,0x0, 0x8, 0xe4,0x12,0x16,0x5a,0x7e,0x34,0x0, 0x20,0xca, +0x39,0x7e,0x18,0x4e,0x23,0x7e,0x8, 0x44,0x95,0x12,0x16,0x35,0x1b,0xfd,0x74,0x5, +0x7a,0xb3,0x4e,0x1d,0xe4,0x7a,0xb3,0x4e,0x14,0x74,0x2, 0x7a,0xb3,0x4e,0x15,0xe4, +0x7a,0xb3,0x44,0x87,0x7e,0x34,0x0, 0x2, 0x12,0x2f,0xa, 0x59,0x35,0x4e,0x23,0x12, +0x2f,0x12,0xb4,0x10,0xef,0x12,0x2f,0x1c,0x7a,0xb3,0x44,0x87,0x7e,0xa3,0x44,0x87, +0x4c,0xaa,0x78,0xd, 0x7e,0xb3,0x44,0x85,0x54,0x1, 0xb4,0x1, 0x4, 0x74,0x1, 0x80, +0x12,0xbe,0xa0,0x1, 0x78,0x14,0x7e,0xb3,0x44,0x85,0x54,0x2, 0x1e,0xb0,0xb4,0x1, +0x9, 0x74,0x4, 0x7a,0xb3,0x40,0x13,0xe4,0x80,0x34,0xbe,0xa0,0x2, 0x78,0x16,0x7e, +0xb3,0x44,0x85,0x54,0x4, 0x1e,0xb0,0x1e,0xb0,0xb4,0x1, 0x9, 0xe4,0x7a,0xb3,0x40, +0x13,0x74,0x1, 0x80,0x19,0xbe,0xa0,0x3, 0x78,0x3a,0x7e,0xb3,0x44,0x85,0x54,0x8, +0xc4,0x23,0x54,0x1f,0xb4,0x1, 0x2d,0xe4,0x7a,0xb3,0x40,0x13,0x74,0x4, 0x7a,0xb3, +0x40,0x14,0x7e,0x34,0x13,0x85,0x12,0x1d,0xf2,0x12,0x1d,0x19,0x12,0x6b,0x8f,0x12, +0x1c,0xe1,0x12,0x2f,0xa, 0x7e,0x1d,0x27,0x2d,0x35,0xb, 0x1a,0x10,0x7f,0x13,0x2d, +0x35,0x1b,0x1a,0x10,0x12,0x2f,0x12,0xb4,0x4, 0x2, 0x80,0x2, 0xc1,0xc, 0xe4,0x7a, +0xb3,0x44,0x87,0x12,0x2f,0xa, 0x7f,0x13,0x2d,0x35,0xb, 0x1a,0x10,0x7e,0x1d,0x27, +0x2d,0x35,0x1b,0x1a,0x10,0x12,0x2f,0x12,0x7e,0x73,0x44,0x87,0xbe,0x70,0x4, 0x40, +0xe2,0x7e,0x73,0x44,0x88,0x7a,0x73,0x40,0x13,0x7e,0x73,0x44,0x89,0x7a,0x73,0x40, +0x14,0x7e,0x73,0x44,0x8a,0x7a,0x73,0x4e,0x1d,0x7e,0x73,0x44,0x8b,0x7a,0x73,0x4e, +0x14,0x7e,0x73,0x44,0x8c,0x7a,0x73,0x4e,0x15,0x7e,0x34,0x0, 0x20,0xca,0x39,0x7e, +0x18,0x44,0x95,0x7e,0x8, 0x4e,0x23,0x12,0x16,0x35,0x1b,0xfd,0x12,0x2f,0x1c,0x7a, +0xb3,0x4e,0x1a,0x7a,0xb3,0x4e,0x19,0xda,0x3b,0x22,0x7e,0xa3,0x44,0x87,0x74,0x2, +0xa4,0x22,0x7e,0xb3,0x44,0x87,0x4, 0x7a,0xb3,0x44,0x87,0x22,0x7e,0xb3,0x4e,0x1d, +0x12,0x2d,0x3a,0x7e,0x37,0x2d,0x6, 0x4e,0x60,0x1, 0x7a,0x37,0x2d,0x6, 0x4e,0x70, +0x20,0x7a,0x37,0x2d,0x6, 0x12,0x27,0xfe,0xe4,0x22,0xca,0xf8,0x12,0xa2,0x4c,0x7e, +0xf0,0x1, 0x7c,0xbf,0x12,0x2a,0xd8,0xb, 0xf0,0xbe,0xf0,0x4, 0x78,0xf4,0xe5,0x13, +0x70,0x4, 0xe4,0x12,0x2a,0xd8,0xda,0xf8,0x22,0x7e,0xf, 0x4f,0xa1,0x69,0x30,0x0, +0x6, 0x5e,0x34,0x0, 0x1, 0x68,0x18,0x12,0x33,0x7b,0x5e,0x34,0x0, 0x2, 0x68,0x3, +0x12,0xac,0x6e,0x74,0x3, 0x12,0xa9,0x6f,0x74,0x1, 0x12,0x2a,0xd8,0x80,0x33,0x12, +0xa7,0xd9,0x75,0x13,0x0, 0xe4,0x7a,0xb3,0x4f,0x55,0x74,0x1, 0x12,0xa9,0x6f,0xe4, +0x12,0x2a,0xd8,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0xa, 0xb, 0xa, 0x30,0x4e,0x60, +0x10,0x1b,0xa, 0x30,0xe4,0x7a,0xb3,0x4f,0x4c,0x12,0x1b,0xed,0x12,0x1f,0xf1,0x12, +0x35,0x1, 0xe5,0x13,0x2, 0x2f,0xb7,0x7c,0xab,0x12,0x4f,0x8c,0x1b,0xa0,0x68,0x12, +0x1b,0xa0,0x68,0x13,0x1b,0xa0,0x68,0x14,0x2e,0xa0,0x3, 0x78,0x12,0x12,0xa2,0x87, +0x80,0xd, 0x12,0xa2,0x9c,0x80,0x8, 0x12,0xa2,0x66,0x80,0x3, 0x12,0xa2,0xe1,0x2, +0x2f,0xe2,0xe4,0x7a,0xb3,0x3, 0xda,0x6c,0xaa,0x80,0xd, 0x12,0xa6,0x48,0x2e,0xb3, +0x3, 0xda,0x7a,0xb3,0x3, 0xda,0xb, 0xa0,0x7e,0xb3,0x3, 0xcf,0xbc,0xba,0x38,0xeb, +0x22,0x7c,0x7b,0x74,0x8, 0xac,0x7b,0xbe,0x34,0x0, 0x5a,0x38,0x2, 0xc3,0x22,0xbe, +0x34,0x0, 0x1e,0x50,0x2, 0xc3,0x22,0xd3,0x22,0x7c,0x7b,0x74,0x27,0xac,0xb7,0x9, +0x95,0x4b,0xa6,0x7e,0x63,0x4e,0x14,0x74,0x2, 0xac,0xb7,0x19,0x65,0x4c,0x3e,0x7e, +0x63,0x4e,0x15,0x74,0x2, 0xac,0xb7,0x19,0x65,0x4c,0x3f,0x74,0x2, 0xac,0x7b,0x2e, +0x34,0x4c,0x3e,0x7e,0x14,0x0, 0x2d,0x12,0x15,0x72,0x7e,0x30,0x2c,0xac,0x39,0x7d, +0x31,0x2e,0x34,0x0, 0xdb,0x12,0x30,0x73,0x12,0xb, 0x44,0x7e,0x70,0xb5,0xac,0x79, +0x2e,0x34,0x1, 0x0, 0x7e,0x30,0x2c,0xac,0x39,0x12,0x2c,0x5b,0x7e,0x24,0x0, 0x2, +0x2, 0xc, 0xcc,0x2e,0x14,0x0, 0xdd,0x6d,0x0, 0x22,0xca,0x3b,0x7c,0xfb,0x6c,0xee, +0x74,0x27,0xac,0xbe,0x19,0xf5,0x4b,0xa2,0xb, 0xe0,0xbe,0xe0,0x4, 0x78,0xf1,0x7e, +0x64,0x1, 0x0, 0x6c,0xee,0x7e,0x30,0x2c,0xac,0x3e,0x12,0x30,0x73,0xa, 0x3f,0x12, +0x2b,0xb6,0x12,0xd, 0xd3,0x7d,0x36,0xb, 0x34,0x74,0x2c,0xac,0xbe,0x49,0x25,0x0, +0xdd,0x12,0x30,0xb9,0x40,0xdf,0xda,0x3b,0x22,0x12,0x0, 0x2e,0x2e,0x64,0x0, 0xb5, +0xb, 0xe0,0xbe,0xe0,0x3, 0x22,0xca,0x3b,0x7c,0xfb,0x6c,0xee,0x74,0x27,0xac,0xbe, +0x19,0xf5,0x4b,0xa5,0xb, 0xe0,0xbe,0xe0,0x4, 0x78,0xf1,0x7e,0x64,0x1, 0xa, 0x6c, +0xee,0x7e,0x30,0x2c,0xac,0x3e,0x2e,0x14,0x0, 0xef,0x6d,0x0, 0x7c,0xbf,0x12,0xc, +0xaa,0x12,0x31,0xd, 0x49,0x25,0x0, 0xef,0x12,0x6, 0x48,0x12,0x31,0xd, 0x49,0x25, +0x0, 0xef,0x12,0x6, 0xc5,0x12,0x30,0xbc,0x40,0xd7,0xda,0x3b,0x22,0x7d,0x36,0x74, +0x2c,0xac,0xbe,0x22,0x7c,0x7b,0x74,0x8, 0xac,0x7b,0xbe,0x34,0x0, 0x12,0x50,0x2, +0xc3,0x22,0xd3,0x22,0xca,0x79,0x7c,0xeb,0xbe,0xe0,0xfa,0x78,0x6, 0x7e,0xb3,0x2c, +0xff,0x41,0xc9,0xbe,0xe0,0xfc,0x78,0x4, 0x74,0x1, 0x41,0xc9,0xbe,0xe0,0x5b,0x38, +0x8, 0xa, 0x3e,0x9, 0xb3,0x4d,0xeb,0x41,0xc9,0xbe,0xe0,0x6a,0x68,0x5, 0xbe,0xe0, +0x6b,0x78,0x22,0x12,0x40,0x18,0x7e,0x37,0x2c,0xfc,0x7d,0x23,0xb, 0x24,0x7a,0x27, +0x2c,0xfc,0x2e,0x37,0x31,0x74,0x7e,0x39,0xf0,0xbe,0xe0,0x6b,0x78,0x3, 0x75,0xf, +0x6a,0x7c,0xbf,0x41,0xc9,0xbe,0xe0,0x6e,0x68,0x5, 0xbe,0xe0,0x6f,0x78,0x22,0x12, +0x3f,0xc1,0x7e,0x37,0x2c,0xfa,0x7d,0x23,0xb, 0x24,0x7a,0x27,0x2c,0xfa,0x2e,0x37, +0x2d,0x8, 0x7e,0x39,0xf0,0xbe,0xe0,0x6f,0x78,0x3, 0x75,0xf, 0x6e,0x7c,0xbf,0x41, +0xc9,0xbe,0xe0,0x6c,0x68,0x5, 0xbe,0xe0,0x6d,0x78,0x1f,0x7e,0x37,0x31,0x72,0x7d, +0x23,0xb, 0x24,0x7a,0x27,0x31,0x72,0x2e,0x37,0x2d,0x4, 0x7e,0x39,0xf0,0xbe,0xe0, +0x6d,0x78,0x3, 0x75,0xf, 0x6c,0x7c,0xbf,0x41,0xc9,0xbe,0xe0,0x89,0x68,0x5, 0xbe, +0xe0,0x8a,0x78,0x1f,0x7e,0x37,0x31,0x78,0x7d,0x23,0xb, 0x24,0x7a,0x27,0x31,0x78, +0x2e,0x37,0x31,0x76,0x7e,0x39,0xf0,0xbe,0xe0,0x8a,0x78,0x3, 0x75,0xf, 0x89,0x7c, +0xbf,0x41,0xc9,0xbe,0xe0,0x70,0x40,0xc, 0xbe,0xe0,0x7f,0x38,0x7, 0x7c,0xbe,0x12, +0x32,0xcc,0x41,0xc9,0xbe,0xe0,0x81,0x68,0x5, 0xbe,0xe0,0x82,0x78,0x26,0x7e,0x24, +0xe, 0x6, 0x7e,0xb3,0x4e,0x2, 0xa, 0x3b,0x2d,0x32,0x6d,0x22,0x2e,0x24,0x0, 0xff, +0x7e,0x1b,0xf0,0x4, 0x7a,0xb3,0x4e,0x2, 0xbe,0xe0,0x82,0x78,0x3, 0x75,0xf, 0x81, +0x7c,0xbf,0x41,0xc9,0xbe,0xe0,0x86,0x78,0x6, 0x7e,0xb3,0x2d,0x1, 0x41,0xc9,0xbe, +0xe0,0x87,0x78,0x6, 0x7e,0xb3,0x2c,0xf9,0x80,0x7f,0xbe,0xe0,0x88,0x78,0x1a,0x7e, +0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x10,0x5e,0x34,0x38,0x0, 0xa, 0x56,0x1e,0x54,0x1e, +0x54,0x1e,0x54,0x5e,0x54,0x0, 0x7, 0x80,0x60,0xbe,0xe0,0x90,0x40,0xc, 0xbe,0xe0, +0x94,0x38,0x7, 0x7c,0xbe,0x12,0x52,0x9b,0x80,0x4f,0xbe,0xe0,0x99,0x68,0x5, 0xbe, +0xe0,0x9a,0x78,0x1d,0x7e,0xa3,0x2c,0xfe,0x7c,0xba,0x4, 0x7a,0xb3,0x2c,0xfe,0xa, +0x3a,0x9, 0xf3,0x31,0x7a,0xbe,0xe0,0x9a,0x78,0x3, 0x75,0xf, 0x99,0x7c,0xbf,0x80, +0x28,0xbe,0xe0,0x9b,0x78,0x6, 0x7e,0xb3,0x2d,0x0, 0x80,0x1d,0xbe,0xe0,0xf6,0x78, +0x6, 0x7e,0xb3,0x4f,0x94,0x80,0x12,0xbe,0xe0,0xf7,0x78,0xc, 0x7e,0x57,0x4f,0x95, +0x7e,0x44,0x0, 0x64,0x8d,0x54,0x80,0x1, 0xe4,0xda,0x79,0x22,0x7c,0x6b,0x7e,0x70, +0xff,0x7c,0xb6,0x24,0x8c,0xbe,0xb0,0xa, 0x40,0x2, 0x61,0x78,0x7e,0xa0,0x3, 0xa4, +0x90,0x32,0xe4,0x73,0x2, 0x33,0x22,0x2, 0x33,0x78,0x2, 0x33,0x2, 0x2, 0x33,0x10, +0x2, 0x33,0x19,0x2, 0x33,0x2b,0x2, 0x33,0x47,0x2, 0x33,0x36,0x2, 0x33,0x4c,0x2, +0x33,0x4c,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0xe, 0x5e,0x34,0x0, 0x4, 0x80,0x68, +0x7e,0x1f,0x4f,0xa1,0x12,0x2d,0x9, 0x80,0x5f,0x12,0x33,0x91,0x5e,0x34,0x0, 0x2, +0x80,0x56,0x12,0x33,0x91,0x5e,0x34,0x0, 0x1, 0x80,0x4d,0x12,0x33,0x91,0x5e,0x34, +0x4, 0x0, 0xa, 0x36,0x80,0xb, 0x12,0x33,0x91,0x5e,0x34,0x8, 0x0, 0xa, 0x36,0x1e, +0x34,0x1e,0x34,0x1e,0x34,0x80,0x31,0x7e,0x71,0xef,0x80,0x2c,0x7e,0x73,0x4f,0x4a, +0x7c,0xb7,0x4, 0x7a,0xb3,0x4f,0x4a,0xa, 0x27,0x9, 0x72,0x1, 0x63,0x7e,0xb3,0x4e, +0xf, 0x4, 0x7a,0xb3,0x4e,0xf, 0x70,0x9, 0x7e,0xb3,0x4e,0xe, 0x4, 0x7a,0xb3,0x4e, +0xe, 0xa5,0xbe,0x7d,0x3, 0x75,0xf, 0x7c,0x7c,0xb7,0x22,0x2e,0x14,0x0, 0x14,0xb, +0xa, 0x30,0x4e,0x70,0x1, 0x1b,0xa, 0x30,0x75,0x13,0x1, 0x74,0x1, 0x7a,0xb3,0x4f, +0x55,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x6, 0x22,0xd2,0x10,0xd2,0x12,0x12,0x33, +0x91,0x5e,0x34,0x0, 0x2, 0x68,0x3, 0x2, 0x33,0xab,0x22,0x12,0xb, 0xb0,0x20,0x29, +0x3, 0x2, 0x33,0xc6,0x22,0xd2,0x10,0xd2,0x12,0x12,0x33,0x91,0x5e,0x34,0x0, 0x2, +0x78,0x3, 0x2, 0x33,0xab,0x22,0x12,0xb, 0xe5,0x12,0xa3,0x56,0x74,0x2, 0x7a,0xb3, +0x3, 0xd3,0x7a,0xb3,0x3, 0xd4,0x22,0xd2,0xe, 0xd2,0x12,0x12,0x33,0x91,0x5e,0x34, +0x0, 0x1, 0x68,0x8, 0xe4,0x7a,0xb3,0x4f,0x49,0x2, 0x33,0xab,0x22,0x7c,0x7b,0x6c, +0xaa,0x12,0x34,0x4c,0x78,0x9, 0x7c,0xb7,0x12,0x58,0x28,0x7c,0xab,0x80,0xa, 0xb4, +0x4, 0x7, 0x7c,0xb7,0x12,0x31,0x24,0x7c,0xab,0x7c,0xba,0x22,0x30,0x90,0x19,0xc2, +0x90,0xe5,0x8, 0x70,0x9, 0x75,0x8, 0x1, 0xe5,0x91,0xf5,0xf, 0x80,0x11,0x7e,0x71, +0x91,0xe5,0xf, 0x12,0x34,0x37,0x5, 0xf, 0x30,0x91,0xb, 0xc2,0x91,0x5, 0xf, 0xe5, +0xf, 0x12,0x33,0xed,0xf5,0x91,0x22,0x7c,0x6b,0x12,0x34,0x4c,0x78,0x5, 0x7c,0xb6, +0x2, 0x53,0x51,0xb4,0x4, 0x5, 0x7c,0xb6,0x2, 0x38,0x14,0x22,0x7e,0xb3,0x4d,0xeb, +0xc4,0x54,0x7, 0x22,0xca,0x3b,0x7e,0x3f,0x4f,0xa1,0x69,0x33,0x0, 0x6, 0x5e,0x34, +0x0, 0x1, 0x68,0x10,0x7f,0x3, 0x12,0x33,0x7b,0x5e,0x34,0x0, 0x2, 0x68,0x18,0x12, +0xac,0x6e,0x80,0x13,0x75,0x13,0x0, 0xe4,0x7a,0xb3,0x4f,0x55,0x7f,0x3, 0x12,0x1b, +0xf1,0x12,0x1f,0xf1,0x12,0x35,0x1, 0xda,0x3b,0x22,0x12,0x67,0xd0,0x12,0x6f,0xf7, +0x12,0x68,0x59,0x12,0x4a,0x73,0x12,0x70,0xb3,0x12,0x1d,0xfa,0x12,0x34,0xe6,0x12, +0x34,0xa8,0x12,0x98,0xc2,0x2, 0x34,0x54,0x12,0x34,0xda,0x7e,0x8, 0x3e,0x89,0x12, +0x34,0xd5,0x7e,0x8, 0x3f,0x3d,0x12,0x34,0xd5,0x7e,0x8, 0x3e,0xe3,0x74,0xff,0x12, +0x16,0x5a,0x7e,0x8, 0x3f,0x97,0x12,0x8c,0x6d,0x7e,0x8, 0x3f,0xdd,0x7e,0x34,0x0, +0xc, 0xe4,0x2, 0x16,0x5a,0x74,0xff,0x12,0x16,0x5a,0x90,0x13,0x7f,0xe4,0x93,0x7c, +0x7b,0x74,0x9, 0xac,0x7b,0x22,0x7e,0x8, 0x3c,0xc9,0x7e,0x34,0x1, 0xa1,0xe4,0x12, +0x16,0x5a,0x90,0x13,0x80,0x12,0x34,0xde,0x7e,0x8, 0x3d,0x45,0x74,0xff,0x2, 0x16, +0x5a,0x7e,0xb3,0x4f,0x55,0x7e,0x70,0x1, 0x12,0x35,0x21,0x7e,0x70,0x1, 0x12,0x35, +0x69,0x12,0xad,0xe4,0x12,0x35,0x75,0x12,0x35,0x8e,0x5e,0x70,0xef,0x1b,0xa, 0x30, +0x22,0x12,0x35,0x29,0x7e,0xb3,0x4f,0x55,0x22,0x70,0xc, 0x12,0x35,0x84,0x12,0xd, +0x8d,0x12,0x35,0x9d,0x2, 0x4, 0x96,0x22,0x12,0x35,0x8e,0x4e,0x70,0x10,0x1b,0xa, +0x30,0x12,0xad,0xe4,0x12,0x35,0x75,0x74,0x14,0x12,0x53,0x95,0x7e,0xb3,0x4f,0x55, +0x7e,0x73,0x4c,0x6e,0x12,0x35,0x75,0x7e,0xb3,0x4f,0x55,0x7e,0x73,0x4c,0x6f,0x12, +0x35,0x21,0x7e,0x73,0x4c,0x70,0x2, 0x35,0x69,0x70,0x9, 0x12,0x35,0x84,0x12,0x35, +0x9a,0x2, 0x4, 0x96,0x22,0x70,0xc, 0x12,0x35,0x84,0x12,0xc, 0xea,0x12,0x35,0x9d, +0x2, 0x4, 0x96,0x22,0x5e,0x70,0x3, 0x7e,0x8, 0x0, 0x57,0x7c,0xb7,0x22,0x7e,0xf, +0x4f,0xa1,0x2e,0x14,0x0, 0x10,0xb, 0xa, 0x30,0x22,0x12,0xd, 0x7, 0x7e,0x37,0x0, +0x57,0x7a,0x37,0x0, 0x93,0x7e,0x34,0x0, 0x2, 0x7e,0x8, 0x0, 0x57,0x7e,0x24,0x0, +0x1, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x2, 0x7e,0x8, 0x0, 0x93,0x7e,0x24,0x0, 0x1, +0x22,0x30,0x0, 0x5, 0x43,0xc3,0x80,0x80,0x3, 0x53,0xc3,0x7f,0x30,0x0, 0x5, 0x43, +0xc2,0x80,0x80,0x3, 0x53,0xc2,0x7f,0x7e,0xf, 0x4f,0xa1,0x30,0x0, 0x8, 0x12,0x35, +0x92,0x4e,0x60,0xc4,0x80,0x6, 0x12,0x35,0x92,0x5e,0x60,0x3b,0x1b,0xa, 0x30,0x22, +0x12,0x37,0x7d,0x12,0xa7,0xdc,0x12,0x36,0x53,0x12,0x36,0x14,0xa9,0xd6,0xeb,0x74, +0x1, 0x7e,0x70,0x82,0x12,0x36,0x6f,0xa9,0xc6,0xeb,0xd2,0x0, 0x12,0x36,0x14,0xd2, +0x0, 0x2, 0x35,0xc1,0xa9,0xd0,0xce,0x30,0x0, 0x4, 0xa9,0xd5,0xc9,0x22,0xa9,0xc5, +0xc9,0x22,0x12,0x37,0xb3,0x40,0x6, 0x12,0x37,0xa8,0x12,0x0, 0x12,0x12,0x36,0x53, +0x12,0x36,0x5b,0x80,0x3, 0x12,0x36,0xf0,0x30,0x16,0xfa,0x7e,0xb3,0x4f,0x51,0xbe, +0xb0,0x0, 0x28,0x5, 0x14,0x7a,0xb3,0x4f,0x51,0xd2,0x0, 0x12,0x36,0x5b,0xd2,0x0, +0x2, 0x35,0xc1,0xc2,0x0, 0x12,0x35,0xc1,0xc2,0x0, 0x22,0xa2,0x0, 0xa9,0x92,0xcb, +0xa2,0x0, 0xa9,0x92,0xca,0xa2,0x0, 0xa9,0x91,0xcb,0x22,0xe4,0x7e,0x70,0xff,0x7c, +0x6b,0x7e,0xb3,0x4f,0x4b,0xb4,0x81,0x72,0xa5,0xbe,0x0, 0x2, 0x80,0x66,0xa5,0xbe, +0x1, 0x22,0xc2,0xaf,0xa, 0x27,0x5e,0x24,0x0, 0x2, 0x68,0x2, 0xd2,0x95,0x7a,0x71, +0xcd,0xa9,0xd0,0xce,0xa9,0xc6,0xc9,0xa9,0xd0,0xce,0xa9,0xc7,0xc9,0xa9,0xd1,0x87, +0xd2,0xaf,0x80,0x40,0xa5,0xbe,0x2, 0x1d,0xc2,0xaf,0x7a,0x71,0xcd,0x12,0x0, 0x1e, +0x70,0xf, 0xa9,0xd0,0xce,0xa9,0xc7,0xc9,0xa9,0xd0,0xce,0xa9,0xd6,0xc9,0xa9,0xd1, +0x87,0xd2,0xaf,0x80,0x1f,0xa5,0xbe,0x3, 0x21,0xc2,0xaf,0x7a,0x71,0xcd,0x12,0x0, +0x1e,0x70,0xf, 0xa9,0xd0,0xce,0xa9,0xd7,0xc9,0xa9,0xd0,0xce,0xa9,0xc6,0xc9,0xa9, +0xd1,0x87,0xd2,0xaf,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe4,0x7a,0xb3,0x4f,0x4b,0x22, +0x80,0xe, 0x12,0x37,0x7d,0x12,0x37,0xb3,0x40,0x19,0x20,0x16,0x16,0x12,0x36,0x6b, +0x12,0x0, 0x1e,0x70,0xed,0x12,0x37,0x7d,0x12,0xa1,0x31,0x74,0x2, 0x7e,0x70,0x7, +0x2, 0x36,0x6f,0x22,0xca,0xf8,0x7e,0x34,0x1a,0x15,0x7e,0x24,0x0, 0xff,0x7e,0x14, +0x49,0x49,0x74,0xc, 0x12,0x15,0x93,0x7e,0x57,0x31,0x78,0x4d,0x55,0x78,0x4b,0x12, +0x40,0x8b,0x7c,0xba,0x30,0xe0,0x20,0x7d,0x14,0xb, 0x44,0x2e,0x17,0x31,0x76,0x12, +0x40,0x79,0x19,0x41,0x49,0x49,0x7d,0x14,0xb, 0x44,0x2e,0x17,0x31,0x76,0x12,0x40, +0x79,0x19,0x41,0x49,0x49,0x80,0x2, 0xb, 0x45,0x12,0x40,0x83,0x78,0xd4,0x7d,0x43, +0x6c,0xff,0xa, 0x5f,0x9, 0x75,0x49,0x49,0x7d,0x54,0xb, 0x44,0x2e,0x57,0x31,0x76, +0x7a,0x59,0x70,0xb, 0xf0,0xbe,0xf0,0xc, 0x78,0xe8,0xda,0xf8,0x22,0x74,0x81,0x7a, +0xb3,0x4f,0x4b,0x22,0x80,0xe, 0x12,0x37,0x7d,0x12,0x37,0xb3,0x40,0x19,0x20,0x16, +0x16,0x12,0x36,0x6b,0x12,0x0, 0x1e,0x70,0xed,0x12,0x37,0x7d,0x12,0xa1,0x31,0x74, +0x2, 0x7e,0x70,0x7, 0x2, 0x36,0x6f,0x22,0x80,0x3, 0x12,0x37,0x84,0x12,0x37,0xb3, +0x50,0xf8,0x22,0x30,0xe, 0x3, 0x12,0x1c,0xa, 0x7e,0xb3,0x3, 0xd3,0x70,0x6, 0x7e, +0xb3,0x3, 0xd4,0x60,0x2, 0xd3,0x22,0xc3,0x22,0x20,0x16,0x6, 0x12,0xa7,0xd0,0x12, +0x0, 0x12,0x30,0x1d,0x3, 0x12,0x1c,0x24,0x12,0x37,0xb3,0x40,0x6, 0x12,0x37,0xa8, +0x2, 0x0, 0x12,0x22,0x7e,0xa3,0x4d,0xef,0xbe,0xa0,0x5, 0x78,0x8, 0x74,0x1, 0x7a, +0xb3,0x4d,0xef,0x80,0x18,0xbe,0xa0,0x4, 0x78,0x19,0x74,0x1, 0x7a,0xb3,0x4d,0xef, +0x7e,0x34,0x13,0x85,0x12,0x1d,0xf2,0x12,0x1a,0x30,0x12,0x1c,0xe1,0x74,0x2, 0x7a, +0xb3,0x4d,0xef,0x22,0xca,0x79,0x7c,0xf7,0x7c,0xeb,0xbe,0xe0,0xfa,0x78,0x4, 0x7a, +0xf3,0x2c,0xff,0x4c,0xee,0x78,0x7, 0x7c,0xbf,0x12,0x53,0xb1,0x81,0x1d,0xbe,0xe0, +0xf, 0x78,0xe, 0x74,0x1, 0x7a,0xb3,0x4d,0xfa,0x7a,0xb3,0x4d,0xfb,0xd2,0x20,0x81, +0x3c,0xbe,0xe0,0x2e,0x78,0xe, 0x74,0x1, 0x7a,0xb3,0x4e,0x19,0x7a,0xb3,0x4e,0x1a, +0xd2,0x20,0x81,0x3c,0xbe,0xe0,0x12,0x78,0x6, 0x7a,0xf3,0x4d,0xfd,0x81,0x3c,0xbe, +0xe0,0x11,0x78,0x34,0xbe,0xf0,0x1, 0x78,0x1f,0x7e,0xb3,0x4d,0xfc,0x60,0x2, 0x81, +0x3c,0x74,0x1, 0x7a,0xb3,0x4d,0xfc,0xe4,0x7a,0xb3,0x4d,0xfe,0x7e,0xb3,0x4d,0xeb, +0x44,0x80,0x7a,0xb3,0x4d,0xeb,0x81,0x3c,0x4c,0xff,0x68,0x2, 0x81,0x3c,0x7e,0x1f, +0x22,0xe0,0x7a,0x37,0x31,0x74,0x81,0x3c,0xbe,0xe0,0x99,0x68,0x5, 0xbe,0xe0,0x9a, +0x78,0x1d,0x7e,0xa3,0x2d,0x0, 0x7c,0xba,0x4, 0x7a,0xb3,0x2d,0x0, 0xa, 0x3a,0x19, +0xf3,0x31,0x7a,0xbe,0xe0,0x9a,0x68,0x2, 0x81,0x3c,0x75,0xf, 0x99,0x81,0x3c,0xbe, +0xe0,0x9b,0x78,0xa, 0x7a,0xf3,0x2d,0x0, 0x7a,0xf3,0x2c,0xfe,0x81,0x3c,0xbe,0xe0, +0x1, 0x78,0xe, 0x12,0x3d,0x5, 0x7a,0xf3,0x4d,0xec,0x7c,0xbf,0x12,0x3c,0xd8,0x81, +0x1d,0xbe,0xe0,0x5b,0x28,0x2, 0x61,0x1d,0xbe,0xe0,0x30,0x78,0x11,0x7e,0x73,0x4e, +0x1b,0xbc,0x7f,0x78,0x2, 0x81,0x3c,0xbe,0xf0,0x4, 0x40,0x2, 0x81,0x3c,0xbe,0xe0, +0x20,0x40,0xc, 0xbe,0xe0,0x22,0x38,0x7, 0xbe,0xf0,0x3, 0x28,0x2, 0x81,0x3c,0x7c, +0xbe,0x24,0xf9,0xbe,0xb0,0x29,0x40,0x2, 0x21,0x9d,0x7e,0xa0,0x3, 0xa4,0x90,0x39, +0x22,0x73,0x2, 0x3c,0x3c,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x3c, +0x3c,0x2, 0x3c,0x3c,0x2, 0x3c,0x3c,0x2, 0x3c,0x3c,0x2, 0x39,0x9d,0x2, 0x3c,0x3c, +0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, +0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39, +0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d, +0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, +0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x3c, +0x3c,0x2, 0x3c,0x3c,0x2, 0x3c,0x3c,0x2, 0x39,0x9d,0x2, 0x3c,0x3c,0xa, 0x3e,0x19, +0xf3,0x4d,0xeb,0x7c,0xbe,0x1b,0xb2,0xbe,0xb0,0x34,0x40,0x2, 0x41,0xd8,0x7e,0xa0, +0x3, 0xa4,0x90,0x39,0xb6,0x73,0x2, 0x3a,0x52,0x2, 0x3a,0xd8,0x2, 0x3a,0x52,0x2, +0x3a,0xd8,0x2, 0x3a,0x56,0x2, 0x3a,0x52,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a, +0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8, +0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, +0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0x9e,0x2, 0x3a,0xd8,0x2, 0x3a,0xab,0x2, 0x3a, +0xd8,0x2, 0x3a,0xbe,0x2, 0x3a,0x52,0x2, 0x3a,0x52,0x2, 0x3a,0x5b,0x2, 0x3a,0x5b, +0x2, 0x3a,0x5b,0x2, 0x3a,0xd8,0x2, 0x3a,0xcd,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, +0x3a,0xd8,0x2, 0x3a,0x64,0x2, 0x3a,0x64,0x2, 0x3a,0x64,0x2, 0x3a,0xd8,0x2, 0x3a, +0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0x52,0x2, 0x3a,0x6d, +0x2, 0x3a,0x76,0x2, 0x3a,0x7f,0x2, 0x3a,0x88,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, +0x3a,0x91,0xd2,0x20,0x41,0xd8,0x12,0x0, 0xfd,0x80,0x7d,0x7e,0x37,0x2d,0x6, 0x4e, +0x60,0x20,0x80,0x34,0x7e,0x37,0x2d,0x6, 0x4e,0x60,0x1, 0x80,0x2b,0x7e,0x37,0x2d, +0x6, 0x4e,0x70,0x1, 0x80,0x22,0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x2, 0x80,0x19,0x7e, +0x37,0x2d,0x6, 0x4e,0x70,0x4, 0x80,0x10,0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x8, 0x80, +0x7, 0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x10,0x7a,0x37,0x2d,0x6, 0x80,0x3a,0x7e,0x73, +0x4e,0x3, 0x12,0x3c,0x3f,0x7a,0x37,0x2c,0xfa,0x80,0x2d,0x7e,0x73,0x4e,0x5, 0x12, +0x3c,0x3f,0x3e,0x34,0x7a,0x37,0x31,0x72,0x7a,0x37,0x2d,0x2, 0x80,0x1a,0x7e,0x73, +0x4e,0x7, 0x12,0x3c,0x3f,0x3e,0x34,0x7a,0x37,0x2c,0xfc,0x80,0xb, 0x7e,0x73,0x4e, +0xe, 0x12,0x3c,0x3f,0x7a,0x73,0x4f,0x4a,0xbe,0xe0,0x38,0x40,0x1c,0xbe,0xe0,0x56, +0x38,0x17,0xa, 0x3e,0x5e,0x34,0x0, 0x1, 0xbe,0x34,0x0, 0x1, 0x78,0xb, 0x7e,0x37, +0x2d,0x6, 0x4e,0x70,0x20,0x7a,0x37,0x2d,0x6, 0xbe,0xe0,0x58,0x40,0xb, 0x7e,0x37, +0x2d,0x6, 0x4e,0x60,0x2, 0x7a,0x37,0x2d,0x6, 0xbe,0xe0,0xa, 0x68,0x2, 0x81,0x1d, +0x7e,0x37,0x2d,0x6, 0x4e,0x60,0x4, 0x7a,0x37,0x2d,0x6, 0x81,0x1d,0xbe,0xe0,0x6c, +0x68,0x5, 0xbe,0xe0,0x6d,0x78,0x2a,0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x80,0x7a,0x37, +0x2d,0x6, 0x7e,0x37,0x2d,0x2, 0x7d,0x23,0xb, 0x24,0x7a,0x27,0x2d,0x2, 0x2e,0x37, +0x2d,0x4, 0x7a,0x39,0xf0,0xbe,0xe0,0x6d,0x68,0x2, 0x81,0x1d,0x75,0xf, 0x6c,0x81, +0x1d,0xbe,0xe0,0x6e,0x68,0x5, 0xbe,0xe0,0x6f,0x78,0x49,0x7e,0x37,0x2d,0x6, 0x4e, +0x70,0x40,0x7a,0x37,0x2d,0x6, 0x7e,0x63,0x4e,0x3, 0x6c,0x77,0x7e,0xb3,0x4e,0x4, +0xa, 0x2b,0x2d,0x23,0x4, 0x7a,0xb3,0x4e,0x4, 0x70,0x9, 0x7e,0xb3,0x4e,0x3, 0x4, +0x7a,0xb3,0x4e,0x3, 0x7a,0x27,0x2c,0xfa,0x12,0x3f,0xc1,0x7e,0x27,0x2c,0xfa,0x7e, +0x37,0x2d,0x8, 0x2d,0x32,0x7a,0x39,0xf0,0xbe,0xe0,0x6f,0x68,0x2, 0x81,0x1d,0x75, +0xf, 0x6e,0x80,0x79,0xbe,0xe0,0x70,0x40,0xe, 0xbe,0xe0,0x7f,0x38,0x9, 0x7c,0xbe, +0x7c,0x7f,0x12,0x51,0xf, 0x80,0x66,0xbe,0xe0,0x86,0x78,0xf, 0x7c,0xbf,0x54,0x7, +0x7a,0xb3,0x2d,0x1, 0x53,0xc3,0xf8,0x42,0xc3,0x80,0x52,0xbe,0xe0,0x87,0x78,0xf, +0x7c,0xbf,0x54,0x3, 0x7a,0xb3,0x2c,0xf9,0x53,0xc2,0xfc,0x42,0xc2,0x80,0x3e,0xbe, +0xe0,0x88,0x78,0x21,0x5e,0xf0,0x7, 0x12,0x35,0x8e,0x5e,0x60,0xc7,0x1b,0xa, 0x30, +0xa, 0x3f,0x7d,0x23,0x7c,0x45,0x6c,0x55,0x12,0x3c,0x4b,0x12,0x35,0x8e,0x4d,0x32, +0x1b,0xa, 0x30,0x80,0x18,0xbe,0xe0,0xf6,0x78,0x6, 0x7a,0xf3,0x4f,0x94,0x80,0xd, +0xbe,0xe0,0xf7,0x78,0x8, 0x74,0x64,0xac,0xbf,0x7a,0x57,0x4f,0x95,0x30,0x20,0xa, +0x7e,0xb3,0x4d,0xf9,0x44,0x1, 0x7a,0xb3,0x4d,0xf9,0x7e,0x37,0x2d,0x6, 0x4d,0x33, +0x68,0xa, 0x7e,0xb3,0x4d,0xf9,0x44,0x2, 0x7a,0xb3,0x4d,0xf9,0xda,0x79,0x22,0x7c, +0x47,0x6c,0x55,0xa, 0x3f,0x2d,0x32,0x22,0xb, 0x18,0x20,0x3e,0x24,0x3e,0x24,0x3e, +0x24,0x22,0x7c,0x67,0x7c,0x7b,0xa5,0xbf,0x0, 0xd, 0xbe,0x60,0x0, 0x28,0x5, 0xe4, +0x7a,0xb3,0x3f,0xe4,0x2, 0x3c,0xb3,0xa5,0xbe,0x0, 0x1b,0x6c,0xaa,0x80,0xe, 0x7e, +0x60,0xff,0x7e,0x50,0x9, 0xac,0x5a,0x19,0x62,0x3f,0x41,0xb, 0xa0,0x90,0x13,0x7f, +0xe4,0x93,0xbc,0xba,0x38,0xe9,0x6c,0xaa,0x80,0x24,0x7e,0x30,0x9, 0xac,0x3a,0x2e, +0x14,0x3e,0x89,0x12,0x3c,0x48,0x3e,0x24,0x1b,0x18,0x20,0x7e,0x30,0x9, 0xac,0x3a, +0x2e,0x14,0x3e,0x8b,0x12,0x3c,0x48,0x3e,0x24,0x1b,0x18,0x20,0xb, 0xa0,0xbc,0x7a, +0x38,0xd8,0x22,0x12,0x3c,0xcc,0x7e,0x8, 0x49,0xeb,0xe4,0x12,0x16,0x5a,0x90,0x13, +0x7f,0x12,0x3c,0xd0,0x7e,0x8, 0x49,0xd3,0xe4,0x2, 0x16,0x5a,0x90,0x13,0x7f,0xe4, +0x93,0x7c,0x7b,0x74,0x2, 0xac,0x7b,0x22,0x24,0x52,0x68,0x6, 0x4, 0x78,0x25,0x2, +0x3d,0x5, 0x7e,0x63,0x40,0xf, 0x7e,0x73,0x40,0x10,0xac,0x76,0x3e,0x34,0x7a,0x37, +0x2c,0xfc,0x1e,0x34,0xa, 0x36,0x7a,0x73,0x4e,0x7, 0x7e,0x37,0x2c,0xfc,0x1e,0x34, +0x7a,0x73,0x4e,0x8, 0x22,0x6d,0x33,0x7a,0x37,0x2c,0xfc,0x22,0x12,0x3d,0x5, 0xd2, +0x2, 0x12,0x45,0xf2,0x12,0x2c,0x78,0xe5,0x13,0x12,0x2f,0xb7,0x2, 0x3d,0x1f,0x7e, +0x1f,0x22,0xe0,0x7a,0x37,0x31,0x74,0x7e,0x63,0x4f,0x55,0xa, 0x6, 0x12,0x3e,0x5f, +0x2e,0x24,0x31,0x9d,0x7a,0x27,0x2d,0x8, 0x6d,0x22,0x7a,0x27,0x2c,0xfa,0x7e,0x24, +0x40,0x22,0x7a,0x27,0x2d,0x4, 0x7e,0x24,0x0, 0x27,0xca,0x29,0x7e,0x70,0x27,0xac, +0x67,0x2e,0x34,0x4b,0xa2,0x6d,0x22,0x7e,0x8, 0x4e,0x1c,0x12,0x16,0x35,0x1b,0xfd, +0x7e,0x34,0x0, 0x2, 0xca,0x39,0x7e,0x63,0x4f,0x55,0xac,0x67,0x2e,0x34,0x4c,0x3e, +0x6d,0x22,0x7e,0x8, 0x4e,0x14,0x12,0x16,0x35,0x1b,0xfd,0x7e,0xa3,0x4f,0x55,0x74, +0xa, 0xa4,0x49,0x35,0x4c,0x4a,0x7a,0x37,0x4e,0x21,0x7e,0xb3,0x4f,0x55,0x12,0xa9, +0x2, 0x7e,0xb3,0x4f,0x55,0x12,0xa8,0x61,0x7e,0xb3,0x4f,0x55,0x12,0x50,0xb7,0x12, +0x3d,0xd6,0x9, 0x75,0x4c,0x6e,0x7a,0x73,0x4e,0xb, 0x12,0x3d,0xd6,0x9, 0x75,0x4c, +0x6f,0x7a,0x73,0x4e,0xc, 0x12,0x3d,0xd6,0x9, 0x75,0x4c,0x70,0x7a,0x73,0x4e,0xd, +0x7e,0x73,0x4f,0x55,0x7a,0x73,0x4e,0x1b,0x2, 0x3d,0xcb,0xe5,0x13,0x7a,0xb3,0x4d, +0xf7,0x22,0x7e,0x8, 0x0, 0x57,0x7e,0xa3,0x4f,0x55,0x74,0x3, 0xa4,0x22,0x12,0x1b, +0xed,0x12,0x1f,0xea,0x12,0xa1,0xa6,0x7e,0xb3,0x40,0x21,0x7e,0x37,0x40,0x1d,0x60, +0xe, 0x7a,0x37,0x0, 0xa1,0x7e,0x37,0x40,0x1f,0x7a,0x37,0x0, 0x65,0x80,0xc, 0x7a, +0x37,0x0, 0x65,0x7e,0x37,0x40,0x1f,0x7a,0x37,0x0, 0xa1,0x7e,0x37,0x0, 0x63,0x4e, +0x70,0x2, 0x7a,0x37,0x0, 0x63,0x7e,0x37,0x0, 0x9f,0x4e,0x70,0x2, 0x7a,0x37,0x0, +0x9f,0x12,0x3d,0xd2,0x9, 0xb5,0x4c,0x6e,0x12,0xc, 0xea,0x12,0x3d,0xd2,0x9, 0xb5, +0x4c,0x6f,0x12,0xd, 0x8d,0x12,0x3d,0xd2,0x12,0x50,0xd5,0x7e,0x37,0x0, 0x57,0x7a, +0x37,0x0, 0x93,0x6d,0x33,0x7e,0x8, 0x0, 0x53,0x7e,0x24,0x0, 0x1e,0x12,0x3, 0xfa, +0x6d,0x33,0x7e,0x8, 0x0, 0x8f,0x7e,0x24,0x0, 0x1e,0x2, 0x4, 0x96,0xa, 0xf, 0x7e, +0x14,0x2, 0x3c,0xad,0x10,0x7d,0x21,0x22,0x12,0x3d,0xde,0x12,0x3e,0x74,0x12,0x0, +0x26,0x2, 0x2f,0x3a,0xca,0x3b,0x7e,0x38,0x1, 0x63,0x12,0x7, 0xb5,0x7e,0xa3,0x1, +0x73,0xbe,0xa0,0xff,0x68,0x2a,0x7e,0x63,0x1, 0x74,0xbe,0x60,0xff,0x68,0x21,0x7e, +0x73,0x1, 0x75,0xbe,0x70,0xff,0x68,0x18,0x4c,0xaa,0x68,0x14,0x4c,0x66,0x68,0x10, +0x4c,0x77,0x68,0xc, 0x7a,0xa3,0x4d,0x9c,0x7a,0x63,0x4d,0x98,0x7a,0x73,0x4d,0x99, +0xc2,0x11,0x7e,0xb3,0x1, 0x75,0xbe,0xb0,0x3, 0x28,0xf, 0x74,0x4, 0x7a,0xb3,0x4f, +0x50,0x7a,0xb3,0x2d,0x1, 0x75,0xc3,0x84,0xd2,0x11,0xc2,0x13,0x7c,0xba,0x54,0xf0, +0xb4,0xe0,0x2, 0xd2,0x13,0x7e,0x8, 0x0, 0x87,0x69,0x33,0x0, 0x4, 0x12,0x3f,0x6f, +0x12,0x0, 0x6, 0x7e,0x8, 0x0, 0x89,0x29,0xb3,0x0, 0x6, 0x12,0x3f,0x66,0x12,0xd, +0xa5,0x7e,0x8, 0x0, 0xc3,0x69,0x33,0x0, 0x1, 0x12,0x3f,0x6f,0x12,0x0, 0x6, 0x7e, +0x8, 0x0, 0xc5,0x29,0xb3,0x0, 0x3, 0x12,0x3f,0x66,0x12,0xd, 0xa5,0x7e,0x8, 0x0, +0x8b,0x69,0x33,0x0, 0xa, 0x12,0x3f,0x6f,0x12,0x0, 0x6, 0x7e,0x8, 0x0, 0x8d,0x29, +0xb3,0x0, 0xc, 0x12,0x3f,0x66,0x12,0xd, 0xa5,0x7e,0x8, 0x0, 0xc7,0x69,0x33,0x0, +0x7, 0x12,0x3f,0x6f,0x12,0x0, 0x6, 0x7e,0x8, 0x0, 0xc9,0x29,0xb3,0x0, 0x9, 0x12, +0x3f,0x66,0x12,0xd, 0xa5,0x7e,0x34,0x0, 0x1a,0x7e,0x8, 0x0, 0x87,0x7e,0x24,0x0, +0x4, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x1a,0x7e,0x8, 0x0, 0xc3,0x7e,0x24,0x0, 0x4, +0x12,0x4, 0x96,0xda,0x3b,0x22,0x54,0xc0,0x23,0x23,0x54,0x3, 0xa, 0x3b,0x22,0x7d, +0x23,0x7c,0x45,0x6c,0x55,0xa, 0x36,0x4d,0x32,0x22,0xca,0x3b,0x7e,0x67,0x40,0x15, +0x7e,0x77,0x40,0x17,0x74,0x1, 0x12,0x4f,0xc9,0x7e,0xb3,0x40,0x21,0x7e,0x34,0x1, +0x0, 0x7e,0x8, 0x40,0x22,0x7d,0x26,0x60,0xb, 0x12,0x4, 0x96,0x12,0x3f,0xb0,0x12, +0x3, 0xfa,0x80,0x9, 0x12,0x3, 0xfa,0x12,0x3f,0xb0,0x12,0x4, 0x96,0xda,0x3b,0x22, +0x7e,0x34,0x1, 0x0, 0x7d,0x16,0x3e,0x14,0x2e,0x14,0x40,0x22,0x6d,0x0, 0x7d,0x27, +0x22,0x7e,0x37,0x44,0x81,0xbe,0x37,0x2c,0xfa,0x38,0x4c,0x7d,0x23,0x2e,0x24,0x0, +0xc, 0xbe,0x27,0x2c,0xfa,0x38,0x9, 0x2e,0x34,0x0, 0xb, 0x7a,0x37,0x2c,0xfa,0x22, +0x7e,0xa3,0x44,0x85,0x7e,0x24,0x0, 0x2, 0x7d,0x42,0x7e,0x37,0x2c,0xfa,0x9e,0x37, +0x44,0x81,0x8d,0x32,0x7c,0xb7,0x60,0x1a,0x1e,0xa0,0x14,0x78,0xfb,0x80,0x13,0x7c, +0xba,0x20,0xe0,0x13,0x7d,0x24,0x2e,0x27,0x2c,0xfa,0x7a,0x27,0x2c,0xfa,0x1e,0xa0, +0xb, 0x70,0xbe,0x70,0x4, 0x40,0xe8,0x22,0xca,0xf8,0x7e,0x34,0x1a,0x9, 0x7e,0x24, +0x0, 0xff,0x7e,0x14,0x49,0x55,0x74,0xc, 0x12,0x15,0x93,0x7e,0x57,0x2c,0xfc,0x4d, +0x55,0x78,0x3b,0x12,0x40,0x8b,0x7c,0xba,0x30,0xe0,0x10,0x12,0x40,0x71,0x19,0x41, +0x49,0x55,0x12,0x40,0x71,0x19,0x41,0x49,0x55,0x80,0x2, 0xb, 0x45,0x12,0x40,0x83, +0x78,0xe4,0x7d,0x43,0x6c,0xff,0xa, 0x5f,0x9, 0x75,0x49,0x55,0x7d,0x54,0xb, 0x44, +0x2e,0x57,0x31,0x74,0x7a,0x59,0x70,0xb, 0xf0,0xbe,0xf0,0xc, 0x78,0xe8,0xda,0xf8, +0x22,0x7d,0x14,0xb, 0x44,0x2e,0x17,0x31,0x74,0x7e,0x19,0x40,0x7c,0x35,0xb, 0x50, +0xa, 0x13,0x22,0x1e,0xa0,0xb, 0xf0,0xbe,0xf0,0x4, 0x22,0x7e,0xa3,0x44,0x85,0x7e, +0x37,0x44,0x81,0x3e,0x34,0x6c,0x55,0x7d,0x43,0x6c,0xff,0x22,0x30,0x20,0x76,0xc2, +0x20,0x12,0x37,0xe4,0xd2,0x2, 0x12,0x45,0xf2,0x7e,0x73,0x4e,0x1b,0xbe,0x73,0x4f, +0x55,0x68,0x7, 0x7a,0x73,0x4f,0x55,0x12,0x3d,0xc, 0x7e,0xb3,0x4e,0x9, 0xbe,0xb3, +0x40,0x13,0x68,0x14,0x54,0x5, 0x7a,0xb3,0x4e,0x9, 0x7e,0x73,0x4e,0x9, 0x7a,0x73, +0x40,0x13,0x12,0x70,0x9f,0x12,0xa8,0x90,0x7e,0xb3,0x4e,0xa, 0xbe,0xb3,0x40,0x14, +0x68,0x14,0x54,0x5, 0x7a,0xb3,0x4e,0xa, 0x7e,0x73,0x4e,0xa, 0x7a,0x73,0x40,0x14, +0x12,0x70,0x9f,0x12,0xa8,0x90,0x7e,0xb3,0x4d,0xf9,0x54,0xfe,0x7a,0xb3,0x4d,0xf9, +0x7e,0xb3,0x4d,0xfa,0x60,0x3, 0x12,0x41,0x33,0x7e,0xb3,0x4e,0x19,0x60,0x3, 0x12, +0x2d,0x80,0x12,0x1c,0x24,0x7e,0x37,0x2d,0x6, 0x4d,0x33,0x68,0x15,0xd2,0x2, 0x12, +0x45,0xf2,0x12,0x27,0xfe,0x7e,0xb3,0x4d,0xf9,0x54,0xfd,0x7a,0xb3,0x4d,0xf9,0x2, +0x1c,0x24,0x22,0xca,0x3b,0x6d,0x33,0x7a,0x37,0x31,0x78,0x7e,0x8, 0x2d,0xa, 0x12, +0x68,0x80,0x12,0x4f,0xc9,0x7e,0x34,0x1, 0x0, 0x12,0x7, 0x40,0x7a,0x37,0x44,0xd9, +0x7e,0x34,0x1, 0x1, 0x12,0x7, 0x40,0x7a,0x37,0x44,0xdd,0x7e,0x34,0x1, 0x2, 0x12, +0x7, 0x40,0x7a,0x37,0x44,0xdf,0x7e,0x34,0x1, 0x6, 0x12,0x7, 0x40,0x7a,0x37,0x44, +0xdb,0x7e,0x34,0x1, 0x0, 0x6d,0x22,0x12,0xae,0x1b,0x6d,0x22,0x12,0xae,0x13,0x7e, +0x24,0x7, 0x8, 0x12,0xae,0xb, 0x7e,0x24,0x7, 0x8, 0x12,0xae,0x3, 0x7e,0x24,0x6, +0x88,0x12,0xad,0xfb,0x7e,0x24,0x6, 0x88,0x12,0x6, 0xc5,0x12,0xad,0x69,0x12,0x6, +0x48,0x12,0xad,0x69,0x12,0x6, 0xc5,0x6d,0x33,0x12,0x7, 0x40,0x7a,0x37,0x44,0xcf, +0x7e,0x34,0x0, 0x1, 0x12,0x7, 0x40,0x7a,0x37,0x44,0xd1,0x7e,0x34,0x0, 0x2, 0x12, +0x7, 0x40,0x7a,0x37,0x44,0xd3,0x7e,0x34,0x0, 0x8, 0x12,0x7, 0x40,0x7a,0x37,0x44, +0xd5,0x7e,0x34,0x0, 0x17,0x12,0x7, 0x40,0x7a,0x37,0x44,0xd7,0x12,0xad,0x15,0x5e, +0x50,0xe0,0x4e,0x50,0xa, 0x12,0xad,0x12,0x5e,0x50,0xe0,0x4e,0x50,0xa, 0x12,0x6, +0xc5,0x12,0xad,0x5c,0x12,0x6, 0x48,0x12,0xad,0x5c,0x12,0x6, 0xc5,0x12,0xad,0x1c, +0x12,0x6, 0x48,0x12,0xad,0x1c,0x12,0x6, 0xc5,0x12,0xad,0xb8,0x12,0x6, 0x48,0x12, +0xad,0xb8,0x12,0x6, 0xc5,0x12,0xad,0x4f,0x12,0x6, 0x48,0x12,0xad,0x4f,0x12,0x6, +0xc5,0x12,0xac,0xc6,0xe4,0x12,0x16,0x5a,0x6d,0x66,0x80,0x34,0x12,0xac,0xbd,0x7e, +0xb3,0x40,0x21,0x70,0x14,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78, +0xfb,0x12,0x45,0xe7,0x12,0x47,0xf5,0x80,0x12,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, +0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad,0x34,0x12,0xac,0x65,0xb, 0x64, +0x12,0xad,0x48,0xbd,0x36,0x38,0xc5,0x7e,0xb3,0x40,0x13,0x54,0x1, 0xb4,0x1, 0xb, +0x7e,0x37,0x44,0x87,0x4e,0x70,0x1, 0x7a,0x37,0x44,0x87,0x12,0xac,0x34,0xca,0x39, +0x7e,0x18,0xc, 0xd0,0x7e,0x8, 0x2d,0xa, 0x12,0x16,0x35,0x1b,0xfd,0x7e,0x34,0x0, +0x1, 0x61,0x4c,0x12,0xac,0xc6,0xe4,0x12,0x16,0x5a,0x7e,0x73,0x40,0x10,0xa, 0x27, +0x7e,0x35,0x27,0xad,0x32,0x7d,0x63,0x80,0x61,0x12,0xac,0xbd,0x7e,0x73,0x40,0xd, +0xa, 0x37,0xbe,0x35,0x27,0x28,0x22,0x7e,0xb3,0x40,0x21,0x70,0xe, 0x7d,0x57,0x12, +0x45,0xde,0x60,0x3b,0x3e,0x14,0x14,0x78,0xfb,0x80,0x34,0x7d,0x57,0x12,0x45,0xde, +0x60,0x19,0x3e,0x14,0x14,0x78,0xfb,0x80,0x12,0x7e,0xb3,0x40,0x21,0x70,0x14,0x7d, +0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad, +0x34,0x80,0x12,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12, +0x45,0xe7,0x12,0x47,0xf5,0x12,0xac,0x65,0xb, 0x64,0x7e,0x25,0x27,0xb, 0x24,0x12, +0xad,0x48,0xad,0x32,0xbd,0x36,0x38,0x91,0x7e,0xb3,0x40,0x13,0x54,0x4, 0xb4,0x4, +0xb, 0x7e,0x37,0x44,0x87,0x4e,0x70,0x4, 0x7a,0x37,0x44,0x87,0x12,0xac,0x34,0xca, +0x39,0x12,0xad,0x2b,0x12,0x16,0x35,0x1b,0xfd,0x12,0xad,0xb0,0x7e,0x8, 0x2d,0xa, +0x7e,0x18,0x44,0xe1,0x12,0x50,0xdc,0x7e,0x35,0x27,0xb, 0x34,0x7a,0x35,0x27,0x7e, +0x73,0x40,0xf, 0xa, 0x37,0xbe,0x35,0x27,0x28,0x2, 0x41,0x93,0x6d,0x33,0x81,0xe, +0x12,0xac,0xc6,0xe4,0x12,0x16,0x5a,0x7e,0x65,0x27,0x80,0x61,0x12,0xac,0xbd,0x7e, +0x37,0x40,0x15,0xbd,0x36,0x28,0x22,0x7e,0xb3,0x40,0x21,0x70,0xe, 0x7d,0x57,0x12, +0x45,0xde,0x60,0x3b,0x3e,0x14,0x14,0x78,0xfb,0x80,0x34,0x7d,0x57,0x12,0x45,0xde, +0x60,0x19,0x3e,0x14,0x14,0x78,0xfb,0x80,0x12,0x7e,0xb3,0x40,0x21,0x70,0x14,0x7d, +0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad, +0x34,0x80,0x12,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12, +0x45,0xe7,0x12,0x47,0xf5,0x12,0xac,0x65,0x12,0xad,0x48,0x2d,0x63,0x7e,0xa3,0x40, +0x10,0x7e,0xb3,0x40,0xf, 0xa4,0xbd,0x56,0x38,0x92,0x7e,0xb3,0x40,0x14,0x54,0x1, +0xb4,0x1, 0xb, 0x7e,0x37,0x44,0xab,0x4e,0x70,0x1, 0x7a,0x37,0x44,0xab,0x12,0xac, +0x34,0xca,0x39,0x12,0xad,0x2b,0x12,0x16,0x35,0x1b,0xfd,0x12,0xad,0xb0,0x7e,0x8, +0x2d,0xa, 0x7e,0x18,0x44,0xe1,0x12,0x50,0xdc,0x7e,0x35,0x27,0xb, 0x34,0x7a,0x35, +0x27,0x12,0xad,0x48,0xbe,0x35,0x27,0x28,0x2, 0x61,0x60,0x12,0xac,0xc6,0xe4,0x12, +0x16,0x5a,0x7e,0xb3,0x40,0x14,0x54,0x4, 0xb4,0x4, 0xb, 0x7e,0x37,0x44,0xab,0x4e, +0x70,0x4, 0x7a,0x37,0x44,0xab,0x12,0xac,0x34,0xca,0x39,0x12,0xad,0x2b,0x12,0x16, +0x35,0x1b,0xfd,0x12,0xad,0xb0,0x7e,0x8, 0x2d,0xa, 0x7e,0x18,0x44,0xe1,0x12,0x50, +0xdc,0x6d,0x66,0x7d,0x26,0x3e,0x24,0x49,0x32,0x2d,0xa, 0xbe,0x34,0x2, 0x0, 0x28, +0xf, 0x7d,0x12,0x2e,0x14,0x2d,0xa, 0x9e,0x34,0x2, 0x0, 0x1b,0x18,0x30,0x80,0x6, +0x6d,0x33,0x59,0x32,0x2d,0xa, 0xb, 0x64,0xbe,0x64,0x2, 0x34,0x78,0xd5,0x7e,0x34, +0x2d,0xa, 0x7a,0x37,0x31,0x76,0xe4,0x7a,0xb3,0x4d,0xfb,0x7a,0xb3,0x4d,0xfa,0x12, +0xad,0x15,0x12,0xad,0x12,0x12,0x6, 0xc5,0x7e,0x34,0x0, 0x1, 0x7e,0x27,0x44,0xd1, +0x12,0x6, 0x48,0x7e,0x34,0x0, 0x1, 0x7e,0x27,0x44,0xd1,0x12,0x6, 0xc5,0x7e,0x34, +0x0, 0x2, 0x7e,0x27,0x44,0xd3,0x12,0x6, 0x48,0x7e,0x34,0x0, 0x2, 0x7e,0x27,0x44, +0xd3,0x12,0x6, 0xc5,0x7e,0x34,0x0, 0x8, 0x7e,0x27,0x44,0xd5,0x12,0x6, 0x48,0x7e, +0x34,0x0, 0x8, 0x7e,0x27,0x44,0xd5,0x12,0x6, 0xc5,0x7e,0x34,0x0, 0x17,0x7e,0x27, +0x44,0xd7,0x12,0x6, 0x48,0x7e,0x34,0x0, 0x17,0x7e,0x27,0x44,0xd7,0x12,0x6, 0xc5, +0x7e,0x34,0x1, 0x0, 0x7e,0x27,0x44,0xd9,0x12,0xae,0x1b,0x7e,0x27,0x44,0xd9,0x12, +0xae,0x13,0x7e,0x27,0x44,0xdd,0x12,0xae,0xb, 0x7e,0x27,0x44,0xdd,0x12,0xae,0x3, +0x7e,0x27,0x44,0xdf,0x12,0xad,0xfb,0x7e,0x27,0x44,0xdf,0x12,0x6, 0xc5,0x7e,0x34, +0x1, 0x6, 0x7e,0x27,0x44,0xdb,0x12,0x6, 0x48,0x7e,0x34,0x1, 0x6, 0x7e,0x27,0x44, +0xdb,0x12,0x6, 0xc5,0x6d,0x66,0x80,0x5e,0x12,0xac,0xbd,0x7e,0x37,0x40,0x15,0xbd, +0x36,0x28,0x22,0x7e,0xb3,0x40,0x21,0x70,0xe, 0x7d,0x57,0x12,0x45,0xde,0x60,0x3b, +0x3e,0x14,0x14,0x78,0xfb,0x80,0x34,0x7d,0x57,0x12,0x45,0xde,0x60,0x19,0x3e,0x14, +0x14,0x78,0xfb,0x80,0x12,0x7e,0xb3,0x40,0x21,0x70,0x14,0x7d,0x57,0x12,0x45,0xde, +0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad,0x34,0x80,0x12,0x7d, +0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0x47, +0xf5,0x12,0xac,0x65,0xb, 0x64,0x7e,0x37,0x40,0x17,0x2e,0x37,0x40,0x15,0xbd,0x36, +0x38,0x96,0x7e,0x34,0x1, 0x16,0x7e,0x8, 0x44,0x87,0x12,0x47,0xfc,0x7e,0x34,0x1, +0x16,0x7e,0x8, 0x44,0xab,0x12,0xad,0xd5,0x12,0x70,0xaa,0x12,0xa8,0x90,0x12,0x37, +0x14,0xda,0x3b,0x22,0x7e,0x35,0x3e,0x3e,0x34,0x49,0x23,0x40,0x22,0x7a,0x25,0x40, +0x7f,0x3, 0x2e,0x15,0x3e,0x7e,0xb, 0x70,0x19,0x72,0x1, 0x7b,0x7d,0x52,0x5e,0x54, +0x0, 0xf, 0x7e,0x14,0x0, 0x1, 0x22,0x7d,0x27,0x1e,0x24,0x1e,0x24,0x1e,0x24,0x1e, +0x24,0x22,0x80,0x6, 0x30,0xe, 0x3, 0x12,0x1c,0xa, 0x7e,0xb3,0x3, 0xd2,0xbe,0xb0, +0x1, 0x68,0xf1,0x30,0x2, 0x3, 0x2, 0xb, 0xe5,0x22,0xca,0x3b,0x7f,0x30,0x7c,0xab, +0xbe,0xa0,0x4, 0x40,0x2, 0xe1,0xf2,0x74,0x27,0xa4,0x9, 0xb5,0x4b,0xa6,0xf5,0x46, +0xe4,0x12,0x4f,0xc9,0x7e,0xe7,0x40,0x15,0x7e,0xf7,0x40,0x17,0x2d,0xfe,0x7f,0x13, +0x2d,0x3f,0x7a,0x1d,0x42,0x7e,0x8, 0x46,0xf1,0x7e,0x34,0x0, 0x48,0xe4,0x12,0x16, +0x5a,0x7e,0xb3,0x40,0x21,0x60,0x63,0x6d,0x33,0x80,0x33,0x7e,0x35,0x3e,0x3e,0x34, +0x49,0x23,0x40,0x22,0x7a,0x25,0x40,0x7f,0x3, 0x2e,0x15,0x3e,0x7e,0xb, 0x70,0x19, +0x72,0x2, 0x95,0x12,0x45,0xdc,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe9, +0x3e,0x24,0x2e,0x24,0x47,0x15,0x12,0xac,0x65,0x7e,0x35,0x3e,0xb, 0x34,0x7a,0x35, +0x3e,0xbe,0xe5,0x3e,0x38,0xc5,0x7a,0xe5,0x3e,0x80,0x18,0x12,0x45,0xc4,0x60,0x5, +0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe9,0x12,0xac,0x5f,0x7e,0x35,0x3e,0xb, 0x34, +0x7a,0x35,0x3e,0xbe,0xf5,0x3e,0x38,0xe3,0x80,0x6a,0x6d,0x33,0x80,0x15,0x12,0x45, +0xc4,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe9,0x12,0xac,0x5f,0x7e,0x35, +0x3e,0xb, 0x34,0x7a,0x35,0x3e,0xbe,0xe5,0x3e,0x38,0xe3,0x80,0x3f,0x7e,0xe5,0x3e, +0x3e,0xe4,0x49,0x3e,0x40,0x22,0x7a,0x35,0x40,0x7f,0x3, 0x2e,0x15,0x3e,0x7e,0xb, +0x50,0x19,0x53,0x2, 0x95,0x7d,0x53,0x5e,0x54,0x0, 0xf, 0x7e,0x24,0x0, 0x1, 0x60, +0x5, 0x3e,0x24,0x14,0x78,0xfb,0x12,0x1f,0x18,0x3e,0x34,0x2e,0x34,0x47,0x15,0xb, +0x38,0xe0,0x4d,0xe2,0x1b,0x38,0xe0,0x7e,0xe5,0x3e,0xb, 0xe4,0x7a,0xe5,0x3e,0xbe, +0xf5,0x3e,0x38,0xb9,0x7e,0x7d,0x42,0xb, 0x7a,0x20,0x7d,0x32,0x7a,0x73,0x1, 0x7b, +0x7f,0x27,0x2e,0x54,0x0, 0x0, 0x12,0xac,0x7c,0x7a,0x53,0x1, 0x7c,0x5e,0x34,0x3, +0xf0,0x12,0x1f,0x18,0x7a,0x73,0x1, 0x7d,0x69,0x27,0x0, 0x4, 0x7d,0x32,0x7a,0x73, +0x2, 0x95,0x7f,0x27,0xb, 0x56,0x12,0xac,0x7c,0x7a,0x53,0x2, 0x96,0x5e,0x34,0x3, +0xf0,0x12,0x1f,0x18,0x7a,0x73,0x2, 0x97,0x7e,0xb3,0x40,0x13,0x54,0x5, 0xa, 0x3b, +0x4e,0x37,0x46,0xf1,0x7a,0x37,0x46,0xf1,0x7e,0xb3,0x40,0x14,0x54,0x5, 0xa, 0x3b, +0x4e,0x37,0x47,0x15,0x7a,0x37,0x47,0x15,0x12,0xad,0x8c,0x2e,0x74,0x0, 0x16,0x7d, +0x37,0x7e,0x8, 0x46,0xf1,0x12,0x47,0xfc,0x7d,0x37,0x7e,0x8, 0x47,0x15,0x12,0xad, +0xd5,0x12,0xad,0x8c,0x2e,0x74,0x0, 0x28,0x6d,0x33,0x7a,0x35,0x3e,0x7e,0x35,0x3e, +0x9, 0x53,0x1, 0x7c,0x7c,0x25,0x6c,0x33,0x9, 0x53,0x1, 0x7b,0x12,0xac,0xcf,0x7a, +0x35,0x3e,0xbe,0x34,0x1, 0x1a,0x40,0xe5,0x7d,0x37,0x7e,0x8, 0x47,0x39,0x7e,0x24, +0x0, 0x8d,0x12,0x3, 0xfa,0x6d,0x33,0x7a,0x35,0x3e,0x7e,0x35,0x3e,0x9, 0x53,0x2, +0x96,0x7c,0x25,0x6c,0x33,0x9, 0x53,0x2, 0x95,0x12,0xac,0xcf,0x7a,0x35,0x3e,0xbe, +0x34,0x1, 0x1a,0x40,0xe5,0x7d,0x37,0x7e,0x8, 0x47,0x39,0x7e,0x24,0x0, 0x8d,0x12, +0x4, 0x96,0xda,0x3b,0x22,0x3e,0x24,0x2e,0x24,0x44,0x87,0x22,0x7e,0x24,0x0, 0x12, +0x2, 0x3, 0xfa,0xca,0xf8,0x7e,0x14,0x1a,0x6, 0x7e,0x4, 0x0, 0xff,0x69,0x30,0x0, +0x1, 0x7e,0xb, 0x50,0x7a,0x37,0x44,0x88,0x7a,0x53,0x44,0x87,0xc2,0x0, 0x6d,0xcc, +0x7e,0xb4,0xff,0xff,0x20,0x1f,0x2, 0x21,0x45,0x7e,0xd4,0x4, 0x68,0xca,0xd9,0x7e, +0x1f,0x22,0xe0,0x7e,0x8, 0x28,0x91,0x12,0x16,0x35,0x1b,0xfd,0x6d,0xaa,0x7d,0xda, +0x80,0x26,0x7d,0x2d,0x3e,0x24,0x49,0x12,0x28,0x91,0xbe,0x14,0x0, 0x0, 0x8, 0x6, +0x49,0x32,0x28,0x91,0x80,0x4, 0x6d,0x33,0x9d,0x31,0x59,0x32,0x28,0x91,0xbd,0x3c, +0x28,0x4, 0x7d,0xc3,0x7d,0xbd,0xb, 0xd4,0x7e,0x37,0x44,0x81,0xbd,0x3d,0x38,0xd2, +0x7e,0x37,0x31,0x8a,0xbd,0x3c,0x50,0x4, 0x7a,0xc7,0x31,0x8a,0x7e,0x37,0x31,0x80, +0xbd,0x3c,0x50,0x10,0xbe,0xb4,0xff,0xff,0x68,0xa, 0x7e,0x37,0x31,0x88,0xb, 0x34, +0x7a,0x37,0x31,0x88,0x7e,0x73,0x40,0x10,0xa, 0x27,0x7d,0x3b,0x8d,0x32,0x7c,0xf5, +0xbe,0xf0,0x0, 0x40,0x7, 0xbe,0xf0,0x1d,0x38,0x2, 0xd2,0x0, 0x7d,0xda,0x7d,0x3d, +0x3e,0x34,0x49,0x23,0x31,0x7a,0xbd,0x2c,0x50,0x51,0xbe,0xb4,0xff,0xff,0x68,0x4b, +0x9, 0xbd,0x31,0x8c,0xb4,0x1, 0x25,0x49,0x23,0x31,0x95,0xbd,0x2b,0x78,0x10,0x7d, +0xa3,0x2e,0xa4,0x31,0x8f,0xb, 0xa8,0x20,0xb, 0x24,0x1b,0xa8,0x20,0x80,0x32,0x4d, +0xdd,0x78,0x14,0x30,0x0, 0x25,0x80,0xf, 0x80,0x21,0x80,0xb, 0x4d,0xdd,0x78,0x7, +0x30,0x0, 0x18,0x80,0x2, 0x80,0x14,0x59,0xb3,0x31,0x95,0x7e,0x24,0x0, 0x1, 0x59, +0x23,0x31,0x8f,0x74,0x1, 0x19,0xbd,0x31,0x8c,0x80,0x6, 0x74,0x1, 0x19,0xbd,0x44, +0x87,0x49,0xa3,0x31,0x82,0x49,0x23,0x31,0x8f,0xbd,0x2a,0x28,0x4, 0x59,0x23,0x31, +0x82,0x9, 0xbd,0x44,0x87,0xb4,0x1, 0x11,0x6d,0x22,0x59,0x23,0x31,0x95,0x6d,0xaa, +0x59,0xa3,0x31,0x8f,0xe4,0x19,0xbd,0x31,0x8c,0xb, 0xd4,0xbe,0xd4,0x0, 0x3, 0x68, +0x2, 0x1, 0xae,0x80,0x1a,0x7e,0x8, 0x31,0x8c,0x7e,0x34,0x0, 0x3, 0xe4,0x12,0x16, +0x5a,0x7e,0x8, 0x31,0x8f,0x12,0x49,0x62,0x7e,0x8, 0x31,0x95,0x12,0x49,0x62,0xda, +0xf8,0x22,0x7e,0x34,0x0, 0x6, 0x2, 0x16,0x5a,0xe4,0x7a,0xb3,0x4d,0x9e,0x6d,0x33, +0x7a,0x37,0x31,0x72,0x7e,0x73,0x4d,0xf1,0x7a,0x73,0x44,0x7e,0x12,0x49,0x98,0x12, +0x3d,0xc, 0x7e,0x34,0x4, 0x68,0xca,0x39,0x7e,0x1f,0x22,0xdc,0x7e,0xf, 0x22,0xe0, +0x12,0x16,0x35,0x1b,0xfd,0x2, 0x1c,0x24,0x7e,0x8, 0x3, 0xaf,0x7e,0x34,0x0, 0x20, +0xe4,0x12,0x16,0x5a,0x7e,0x34,0x0, 0x1, 0x7a,0x37,0x3, 0xaf,0x7a,0xb3,0x3, 0xb1, +0x74,0x1, 0x7a,0xb3,0x3, 0xb2,0xe4,0x7a,0xb3,0x3, 0xb3,0x7e,0xb3,0x4f,0x4d,0xb4, +0x1, 0x3f,0x7e,0x34,0x0, 0x2, 0x12,0x4a,0x28,0x7a,0xb3,0x3, 0xbb,0x7e,0x73,0x4f, +0x4c,0x1e,0x34,0xb, 0x34,0x7a,0x73,0x3, 0xbc,0x74,0x1, 0x7a,0xb3,0x3, 0xbd,0xe4, +0x7a,0xb3,0x3, 0xbe,0x7e,0x34,0x0, 0x2, 0x12,0x4a,0x38,0x7e,0x73,0x4f,0x4c,0x1e, +0x34,0xb, 0x34,0x7a,0x73,0x3, 0xc4,0x7a,0xb3,0x3, 0xc5,0x7a,0xb3,0x3, 0xc6,0x80, +0xe, 0x7e,0x34,0x0, 0x1, 0x12,0x4a,0x28,0x7a,0xb3,0x3, 0xbb,0x12,0x4a,0x38,0x7e, +0x34,0x0, 0x1, 0x7a,0x37,0x3, 0xc7,0x74,0x1, 0x7a,0xb3,0x3, 0xc9,0x7a,0xb3,0x3, +0xca,0x74,0x2, 0x7a,0xb3,0x3, 0xcb,0x22,0x7a,0x37,0x3, 0xb7,0x74,0x1, 0x7a,0xb3, +0x3, 0xb9,0x7a,0xb3,0x3, 0xba,0xe4,0x22,0x7a,0x37,0x3, 0xbf,0x74,0x1, 0x7a,0xb3, +0x3, 0xc1,0x7a,0xb3,0x3, 0xc2,0x7a,0xb3,0x3, 0xc3,0x22,0xe4,0x7a,0xb3,0x4d,0x9e, +0x74,0x1, 0x7a,0xb3,0x4f,0x55,0x7a,0xb3,0x44,0x7e,0x12,0x56,0xc6,0x12,0x49,0x98, +0x12,0x2f,0x59,0x12,0x3d,0x1f,0x7e,0x34,0xd, 0xac,0x12,0x1d,0x19,0x12,0x8f,0xab, +0x2, 0x1a,0x33,0x7e,0x34,0x0, 0x27,0xca,0x39,0x7e,0x34,0x12,0xe2,0x7e,0x24,0x0, +0xff,0x7e,0x8, 0x4b,0xa2,0x12,0x16,0x35,0x1b,0xfd,0x7e,0x34,0x0, 0x27,0xca,0x39, +0x7e,0x34,0x13,0x9, 0x7e,0x24,0x0, 0xff,0x7e,0x8, 0x4b,0xc9,0x12,0x16,0x35,0x1b, +0xfd,0x7e,0x34,0x0, 0x27,0xca,0x39,0x7e,0x34,0x13,0x30,0x7e,0x24,0x0, 0xff,0x7e, +0x8, 0x4b,0xf0,0x12,0x16,0x35,0x1b,0xfd,0x7e,0x34,0x0, 0x27,0xca,0x39,0x7e,0x34, +0x13,0x57,0x7e,0x24,0x0, 0xff,0x7e,0x8, 0x4c,0x17,0x12,0x16,0x35,0x1b,0xfd,0x6c, +0x88,0x7c,0xb8,0x12,0x4a,0xe0,0xb, 0x80,0xbe,0x80,0x4, 0x40,0xf4,0x2, 0x49,0x98, +0x7c,0x9b,0x12,0xa9,0x38,0x7e,0x50,0xa, 0xac,0x59,0x59,0x32,0x4c,0x48,0x74,0x27, +0xac,0xb9,0x49,0x5, 0x4b,0xa7,0x59,0x2, 0x4c,0x4a,0x49,0x15,0x4b,0xa9,0xb, 0x14, +0xad,0x10,0x6d,0x0, 0x59,0x12,0x4c,0x4e,0x59,0x2, 0x4c,0x4c,0x12,0x4b,0x33,0x7c, +0xab,0x7e,0x70,0xa, 0xac,0x79,0x19,0xa3,0x4c,0x46,0x74,0x27,0xac,0xb9,0x49,0x35, +0x4b,0xa9,0xb, 0x34,0x12,0x4b,0x33,0x7c,0xab,0x7e,0x70,0xa, 0xac,0x79,0x19,0xa3, +0x4c,0x47,0x22,0xe4,0x80,0x5, 0xb, 0x34,0x1e,0x34,0x4, 0xbe,0x34,0x0, 0x10,0x38, +0xf5,0x22,0xca,0x3b,0x7c,0xeb,0xc2,0x2, 0x7e,0x70,0x27,0xac,0x7e,0x9, 0xf3,0x4b, +0xa6,0x12,0x4f,0xbf,0x4c,0xee,0x68,0x18,0xd2,0x2, 0xe4,0x19,0xb3,0x4b,0xa4,0x7c, +0xbe,0x12,0x4a,0xe0,0x12,0x4f,0x8c,0x12,0xa2,0xf9,0x12,0x2f,0xe2,0x12,0x4f,0xfc, +0xa2,0x2, 0xda,0x3b,0x22,0xca,0x79,0x7c,0xfb,0xd2,0x0, 0xc2,0x1, 0x6d,0x33,0x7a, +0x37,0x4f,0x44,0x74,0x27,0xac,0xbf,0x9, 0xe5,0x4b,0xa4,0x7c,0xbf,0x12,0x4b,0x42, +0x92,0x1, 0xd2,0x0, 0x30,0x0, 0x7, 0x7c,0xbf,0x7c,0x7f,0x12,0x4b,0xca,0x7e,0xb3, +0x4e,0x19,0x70,0xc, 0x7c,0xbf,0x12,0xa9,0xac,0x92,0x30,0x20,0x30,0x2, 0xc2,0x0, +0x30,0x1, 0x12,0x74,0x27,0xac,0xbf,0x19,0xe5,0x4b,0xa4,0x7c,0xbf,0x12,0x4a,0xe0, +0x7c,0xbf,0x12,0x4f,0xa5,0xa2,0x0, 0xda,0x79,0x22,0xca,0x3b,0x7c,0xf7,0x7c,0xeb, +0x75,0x2c,0x9, 0x7e,0x34,0x2, 0x0, 0x7a,0x35,0x2f,0x75,0x39,0x0, 0x7e,0x34,0x16, +0x7c,0x7e,0x24,0x0, 0xff,0x7e,0x14,0x44,0xb5,0x7e,0x54,0x2, 0x3c,0x12,0x15,0x95, +0x6d,0x66,0x80,0xe, 0x7e,0x34,0x7f,0xff,0x7d,0x26,0x3e,0x24,0x59,0x32,0x11,0x38, +0xb, 0x64,0x7e,0x37,0x44,0x81,0x7d,0x23,0xb, 0x26,0xbd,0x26,0x38,0xe6,0x2e,0x34, +0x0, 0x8, 0x12,0x4e,0x89,0xe4,0x12,0x16,0x5a,0x12,0x4e,0x7e,0x12,0xaa,0x22,0x6d, +0x22,0x7a,0x1d,0x31,0x7e,0x37,0x44,0x81,0x2e,0x34,0x44,0xb5,0x7a,0x1d,0x35,0x7e, +0xb3,0x4f,0x94,0xb4,0x1, 0xa, 0x7e,0x37,0x4f,0x95,0x12,0x1f,0x18,0x7a,0x35,0x2f, +0x74,0xa, 0xac,0xbe,0x49,0x25,0x4c,0x48,0x7e,0x35,0x2f,0xad,0x32,0x9, 0xb5,0x4c, +0x46,0x60,0xc, 0x1e,0x34,0x1e,0x24,0x50,0x3, 0x4e,0x60,0x80,0x14,0x78,0xf4,0x7a, +0x35,0x2f,0xe5,0x2c,0xa, 0x5b,0x1b,0x54,0xf5,0x2b,0xa1,0xcc,0xe5,0x2b,0x7e,0x34, +0x0, 0x1, 0x60,0x5, 0x3e,0x34,0x14,0x78,0xfb,0x7a,0x35,0x2d,0x7e,0x34,0x9, 0xc4, +0x12,0x1d,0x19,0xe5,0x2b,0xbe,0xb0,0x7, 0x58,0x1b,0x6d,0x66,0x80,0x12,0x7e,0x35, +0x2d,0x7c,0x67,0x12,0x3e,0x5d,0x12,0x4e,0xa2,0x4c,0x76,0x7a,0x29,0x70,0xb, 0x64, +0x12,0x4e,0x77,0x38,0xe9,0x6d,0x66,0x12,0x4f,0x7f,0x4e,0x35,0x2d,0x1b,0xa, 0x30, +0x12,0x4e,0x70,0x78,0xf2,0x12,0x4e,0x87,0x12,0x46,0xa, 0x5, 0x39,0xe5,0x39,0x54, +0x1, 0xb4,0x1, 0x8, 0x74,0x1, 0x7a,0xb3,0x4f,0x98,0x80,0xe, 0x7e,0x73,0x4f,0x4c, +0xa, 0x37,0x1e,0x34,0xb, 0x34,0x7a,0x73,0x4f,0x98,0x12,0x1c,0x24,0xd2,0x2, 0x12, +0x45,0xf2,0xe5,0x2b,0xbe,0xb0,0x7, 0x58,0x65,0x6d,0x66,0x80,0x5c,0x7d,0x26,0x3e, +0x24,0x49,0x32,0xc, 0xd0,0x7d,0x3, 0x12,0x4e,0x68,0x8, 0x7, 0x7d,0x13,0x9e,0x15, +0x2f,0x80,0x4, 0x6d,0x11,0x9d,0x10,0x12,0x4e,0x5f,0x8, 0x5, 0x9e,0x15,0x2f,0x80, +0x4, 0x6d,0x11,0x9d,0x10,0x7a,0x15,0x3c,0xbe,0x15,0x3a,0x40,0x11,0x59,0x32,0x11, +0x38,0x12,0x4e,0x7e,0x2d,0x36,0x9, 0x73,0x31,0x9d,0x19,0x76,0x44,0xb5,0x7d,0x36, +0x12,0x4e,0x98,0x50,0x12,0x7e,0x55,0x2d,0x64,0xff,0x12,0x4e,0x7e,0x7d,0x23,0x12, +0x4e,0xa2,0x5c,0x7b,0x7a,0x29,0x70,0xb, 0x64,0x12,0x4e,0x77,0x38,0x9f,0x6d,0x66, +0x7e,0x27,0x44,0x81,0x2d,0x26,0x3e,0x24,0x49,0x32,0xc, 0xd0,0x7d,0x3, 0x12,0x4e, +0x68,0x8, 0x7, 0x7d,0x13,0x9e,0x15,0x2f,0x80,0x4, 0x6d,0x11,0x9d,0x10,0x12,0x4e, +0x5f,0x8, 0x5, 0x9e,0x15,0x2f,0x80,0x4, 0x6d,0x11,0x9d,0x10,0x7a,0x15,0x3c,0xbe, +0x15,0x3a,0x40,0x18,0x59,0x32,0x11,0x38,0x7d,0x6, 0x3e,0x4, 0x7e,0x1d,0x31,0x2d, +0x30,0xb, 0x1a,0x10,0x7e,0x1d,0x35,0x2d,0x30,0x1b,0x1a,0x10,0x7e,0x37,0x44,0x81, +0x2d,0x36,0x12,0x4e,0x98,0x50,0xf, 0x7e,0x25,0x2d,0x6e,0x24,0xff,0xff,0x12,0x4f, +0x7f,0x5d,0x32,0x1b,0xa, 0x30,0x12,0x4e,0x70,0x78,0x95,0x30,0xe, 0x2, 0xc1,0x5c, +0x30,0xf, 0x2, 0xc1,0x5c,0x30,0x10,0x2, 0xc1,0x5c,0x15,0x2b,0xe5,0x2b,0xbe,0xb0, +0x1, 0x48,0x2, 0x81,0x6c,0x7e,0xb3,0x4e,0xb, 0xbe,0xb0,0x2, 0x68,0x6f,0x12,0xad, +0xdc,0x68,0x6a,0x7e,0x8, 0x11,0x38,0x74,0xa, 0xac,0xbe,0x12,0x4e,0xb2,0x6d,0x66, +0x80,0x23,0x7d,0x26,0x3e,0x24,0x49,0x32,0x11,0x38,0xbe,0x34,0x3, 0xe8,0x28,0x13, +0xbe,0x34,0x3e,0x80,0x50,0xd, 0x9, 0x76,0x44,0xb5,0x12,0x3e,0x5d,0x2d,0x26,0x19, +0x72,0x31,0x9d,0xb, 0x64,0x12,0x4e,0x77,0x38,0xd8,0x6d,0x66,0x7e,0x27,0x44,0x81, +0x2d,0x26,0x3e,0x24,0x49,0x32,0x11,0x38,0xbe,0x34,0x3, 0xe8,0x28,0x1a,0xbe,0x34, +0x3e,0x80,0x50,0x14,0x7d,0x6, 0x3e,0x4, 0x7e,0x1d,0x35,0x2d,0x30,0xb, 0x1a,0x10, +0x7e,0x1d,0x31,0x2d,0x30,0x1b,0x1a,0x10,0x12,0x4e,0x70,0x78,0xcf,0x74,0x1, 0x7a, +0xb3,0x4f,0x98,0x12,0x4e,0x87,0x12,0x46,0xa, 0x12,0x4f,0x55,0xda,0x3b,0x22,0x7a, +0x15,0x3a,0x49,0x12,0x11,0x38,0x7d,0x1, 0x9e,0x5, 0x2f,0xbe,0x4, 0x0, 0x0, 0x22, +0xb, 0x64,0xbe,0x64,0x0, 0x4, 0x22,0x7e,0x37,0x44,0x81,0xbd,0x36,0x22,0xa, 0x2f, +0x7e,0x34,0x2, 0x3c,0xad,0x32,0x22,0x7c,0xbe,0xa, 0xf, 0x7e,0x14,0x2, 0x3c,0xad, +0x10,0x2e,0x14,0x31,0x9d,0x6d,0x0, 0x22,0x3e,0x34,0x49,0x33,0xc, 0xd0,0xbe,0x35, +0x2f,0x22,0x2d,0x26,0x2e,0x24,0x31,0x9d,0x7e,0x29,0x70,0x22,0x7e,0xa1,0x2f,0x74, +0xa, 0xa4,0x49,0x35,0x4c,0x48,0x7d,0xb3,0x7f,0x70,0x7d,0x3b,0x12,0x4b,0x33,0x7c, +0x7b,0xa, 0x57,0x2e,0x54,0x0, 0xb, 0x7e,0x18,0x0, 0x1, 0x60,0x5, 0x2f,0x11,0x14, +0x78,0xfb,0x74,0x4, 0x2f,0x11,0x14,0x78,0xfb,0x7d,0x1b,0x12,0x14,0xeb,0x7f,0x61, +0xbe,0xb4,0x0, 0x10,0x68,0x6e,0x7e,0x73,0x40,0xf, 0x7a,0x73,0x46,0xf1,0x7e,0x73, +0x40,0x10,0x7a,0x73,0x46,0xf2,0x74,0xb, 0x7a,0xb3,0x46,0xf3,0x7d,0xaf,0x7a,0xa7, +0x46,0xf5,0x7a,0xa7,0x46,0xf9,0xbe,0xb4,0x0, 0x2, 0x38,0xd, 0xe4,0x7a,0xb3,0x46, +0xf3,0x7e,0xd4,0x0, 0x10,0x8d,0xdb,0x6d,0xcc,0x7e,0x8, 0x46,0xf1,0x7d,0x3d,0x12, +0x9, 0x50,0x7e,0x47,0x44,0x81,0x7e,0xa0,0x4, 0x7d,0x34,0x3e,0x34,0x7f,0x57,0x2d, +0xb3,0xb, 0x5a,0x10,0x7f,0x16,0x12,0x14,0xe2,0x7e,0xb3,0x46,0xf3,0x60,0xc, 0x1e, +0x34,0x1e,0x24,0x50,0x3, 0x4e,0x60,0x80,0x14,0x78,0xf4,0x1b,0x5a,0x30,0xb, 0x44, +0x1b,0xa0,0x78,0xd5,0x22,0xe4,0x7a,0xb3,0x4f,0x5a,0x2, 0x4f,0x5d,0x6d,0x33,0x7a, +0x37,0x4f,0x9a,0x22,0xe4,0x7a,0xb3,0x4d,0x9e,0xd2,0x16,0x12,0x4f,0x5d,0x2, 0x4f, +0x71,0x12,0x33,0x91,0x5e,0x34,0x0, 0x1, 0x68,0x4, 0xd2,0x1e,0xc2,0x1b,0x22,0x7d, +0x36,0x3e,0x34,0x7e,0xd, 0x31,0x2d,0x13,0xb, 0xa, 0x30,0x22,0xe4,0x7a,0xb3,0x3, +0xcf,0x12,0xad,0x98,0x7a,0xb3,0x3, 0xd2,0x12,0xac,0xaa,0xe4,0x7a,0xb3,0x3, 0xd9, +0x7a,0xb3,0x3, 0xda,0x22,0xca,0x3b,0x7c,0xeb,0x74,0x27,0xac,0xbe,0x9, 0xf5,0x4b, +0xa6,0x12,0x4f,0xbf,0xe5,0x13,0x12,0x2f,0xb7,0x12,0x4f,0xfc,0xda,0x3b,0x22,0x7e, +0xd0,0xb5,0xac,0xdf,0x2e,0x64,0x1, 0x0, 0x22,0x7c,0xab,0x7e,0x8, 0x0, 0x63,0x7c, +0xba,0x12,0xd, 0xf7,0x7e,0x8, 0x0, 0x9f,0x12,0xd, 0xf7,0x7e,0x34,0x0, 0x8, 0x7e, +0x8, 0x0, 0x63,0x7e,0x24,0x0, 0x1, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x8, 0x7e,0x8, +0x0, 0x9f,0x7e,0x24,0x0, 0x1, 0x2, 0x4, 0x96,0x2, 0x4f,0x64,0xe4,0x12,0x4f,0xc9, +0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xdb,0x6d,0x0, 0x74,0x1, 0x7e,0x70,0x27, +0xac,0x7e,0x9, 0x73,0x4b,0xa4,0x12,0xd, 0x23,0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14, +0x0, 0xdf,0x6d,0x0, 0x74,0xa, 0xac,0xbe,0x9, 0xb5,0x4c,0x46,0x12,0xd, 0x73,0x7d, +0x36,0xb, 0x35,0x74,0x2c,0xac,0xbf,0x49,0x25,0x0, 0xdf,0x12,0x0, 0x2e,0x7d,0x36, +0x74,0x2c,0xac,0xbf,0x49,0x25,0x0, 0xdb,0x2, 0x0, 0x2e,0x7c,0x9b,0x74,0x3, 0xac, +0xb9,0x9, 0x85,0x4c,0x6e,0xbe,0x83,0x4e,0xb, 0x68,0x8, 0x7e,0x83,0x4e,0xb, 0x19, +0x85,0x4c,0x6e,0x9, 0x85,0x4c,0x6f,0xbe,0x83,0x4e,0xc, 0x68,0x8, 0x7e,0x83,0x4e, +0xc, 0x19,0x85,0x4c,0x6f,0x9, 0x85,0x4c,0x70,0xbe,0x83,0x4e,0xd, 0x68,0x8, 0x7e, +0x83,0x4e,0xd, 0x19,0x85,0x4c,0x70,0x7e,0x8, 0x0, 0x57,0x12,0x50,0x98,0x9, 0xb5, +0x4c,0x70,0x12,0x35,0x9a,0x2, 0x4, 0x96,0x9, 0xb5,0x4c,0x6e,0x12,0xc, 0xea,0x7e, +0x8, 0x0, 0x57,0x74,0x3, 0xac,0xb9,0x9, 0xb5,0x4c,0x6f,0x12,0xd, 0x8d,0x7e,0x8, +0x0, 0x57,0x74,0x3, 0xac,0xb9,0x22,0x7c,0x9b,0x12,0x50,0xae,0x12,0x50,0x98,0x12, +0x50,0xd5,0x4c,0x99,0x78,0x9, 0x7e,0x8, 0x0, 0x57,0x74,0x1, 0x12,0xc, 0xea,0x12, +0x35,0x9d,0x2, 0x4, 0x96,0x9, 0xb5,0x4c,0x70,0x2, 0xd, 0x7, 0x6d,0x55,0x80,0x29, +0x7d,0xf5,0x3e,0xf4,0x7f,0x61,0x2d,0xdf,0xb, 0x6a,0x40,0xbe,0x44,0x0, 0x64,0x28, +0x16,0x2d,0xf1,0x7d,0xe0,0xb, 0x7a,0xd0,0xbe,0xd4,0x0, 0x64,0x50,0x2, 0x80,0x4, +0xbd,0xd4,0x28,0x3, 0x1b,0x7a,0x40,0xb, 0x54,0xbe,0x55,0x29,0x40,0xd2,0x22,0x24, +0x8a,0x78,0x21,0x7e,0xf, 0x4f,0xa1,0xa5,0xbf,0x0, 0xc, 0x2e,0x14,0x0, 0xe, 0xb, +0xa, 0x30,0x5e,0x70,0xfb,0x80,0xa, 0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70, +0x4, 0x1b,0xa, 0x30,0x22,0x12,0x3d,0xcb,0x7e,0x73,0x4f,0x4c,0x7a,0x73,0x4d,0xf2, +0x7e,0x73,0x4d,0xf1,0x7a,0x73,0x44,0x7e,0xe4,0x7a,0xb3,0x3f,0xde,0x7a,0xb3,0x3f, +0xdd,0x2, 0x51,0x54,0x7e,0x73,0x4d,0xa0,0x7a,0x73,0x4f,0x6e,0x22,0x2, 0x51,0x54, +0x7e,0x34,0x4, 0x68,0xca,0x39,0x7e,0x1f,0x22,0xe0,0x7e,0x8, 0x28,0x91,0x12,0x16, +0x35,0x1b,0xfd,0x6d,0x33,0x7d,0x13,0x3e,0x14,0x49,0x1, 0x28,0x91,0xbe,0x4, 0x0, +0x0, 0x8, 0x6, 0x49,0x21,0x28,0x91,0x80,0x4, 0x6d,0x22,0x9d,0x20,0x59,0x21,0x28, +0x91,0x49,0x1, 0x24,0x29,0xbd,0x20,0x28,0x4, 0x59,0x21,0x24,0x29,0xb, 0x34,0xbe, +0x34,0x2, 0x34,0x40,0xd0,0x22,0x7e,0x37,0x31,0x9b,0x7a,0x73,0x4d,0xff,0x7e,0xb3, +0x4d,0xfc,0xb4,0x1, 0x2, 0x80,0x2, 0x41,0x88,0x7e,0xb3,0x4d,0xeb,0x44,0x80,0x7a, +0xb3,0x4d,0xeb,0x7e,0xa7,0x31,0x9b,0xbe,0xa4,0x0, 0x5, 0x38,0x30,0x6d,0xdd,0x7a, +0xd7,0x31,0x8a,0x7a,0xd7,0x31,0x88,0x7e,0x8, 0x31,0x82,0x7e,0x34,0x0, 0x6, 0xe4, +0x12,0x16,0x5a,0x7e,0x34,0x4, 0x68,0x7d,0x1d,0xad,0x13,0x2e,0x14,0x24,0x29,0x6d, +0x0, 0xe4,0x12,0x16,0x5a,0xb, 0xd4,0xbe,0xd4,0x0, 0x2, 0x78,0xe6,0x7e,0xa7,0x31, +0x9b,0xb, 0xa4,0x7a,0xa7,0x31,0x9b,0xbe,0xa4,0x0, 0x5, 0x28,0x5, 0xd2,0x1f,0x12, +0x51,0x60,0x7e,0x73,0x4d,0xfd,0xa, 0xa7,0x3e,0xa4,0x3e,0xa4,0x2e,0xa4,0x0, 0x5, +0xbe,0xa7,0x31,0x9b,0x78,0x74,0x6d,0xdd,0x4d,0xdd,0x78,0x4, 0x6d,0xbb,0x80,0xa, +0x7d,0x3d,0x1b,0x34,0x3e,0x34,0x49,0xb3,0x24,0x29,0xbe,0xd4,0x2, 0x34,0x78,0x4, +0x6d,0xcc,0x80,0x8, 0x7d,0xcd,0x3e,0xc4,0x49,0xcc,0x24,0x2b,0x7d,0x3b,0x2d,0x3c, +0x7e,0x24,0x0, 0xa, 0x8d,0x32,0x7d,0x3d,0x3e,0x34,0x2e,0x34,0x24,0x29,0xb, 0x38, +0xa0,0x2d,0xa2,0x1b,0x38,0xa0,0xb, 0xd4,0xbe,0xd4,0x2, 0x34,0x78,0xba,0xc2,0x1f, +0xe4,0x7a,0xb3,0x4d,0xfc,0x6d,0xaa,0x7a,0xa7,0x2c,0xfc,0x7e,0x34,0x24,0x29,0x7a, +0x37,0x31,0x74,0x7a,0xa7,0x31,0x9b,0x22,0xc2,0x1f,0x7e,0xa7,0x31,0x9b,0x4d,0xaa, +0x68,0x8, 0x6d,0xaa,0x7a,0xa7,0x31,0x9b,0xd2,0x12,0x22,0x24,0x6f,0x68,0x12,0x14, +0x68,0x14,0x14,0x68,0x16,0x14,0x68,0x18,0xb, 0xb2,0x78,0x19,0x7e,0xb3,0x1, 0x76, +0x22,0x7e,0xb3,0x1, 0x77,0x22,0x7e,0xb3,0x1, 0x78,0x22,0x7e,0xb3,0x1, 0x79,0x22, +0x7e,0xb3,0x1, 0x7a,0x22,0x74,0xfe,0x22,0x24,0xab,0x68,0x10,0x24,0xef,0x68,0x1c, +0x24,0xde,0x68,0x26,0x24,0xde,0x78,0x2f,0x74,0x5, 0x80,0x2d,0x7e,0xb3,0x4f,0xab, +0xb4,0x5, 0x2a,0x12,0x53,0xe, 0x12,0x54,0x42,0x2, 0x53,0x4e,0x7e,0xb3,0x4f,0xab, +0xb4,0x5, 0x1a,0x12,0x53,0xe, 0x75,0xe9,0xff,0x22,0x7e,0xb3,0x4f,0xab,0xb4,0x5, +0xc, 0x12,0x53,0xe, 0x2, 0x53,0x31,0x74,0x1, 0x7a,0xb3,0x4f,0xab,0x22,0x7e,0x34, +0x0, 0x1, 0x7d,0x23,0x80,0x12,0x7e,0x30,0x4, 0x80,0x5, 0x74,0xfa,0x12,0x53,0x95, +0x7c,0x23,0x1b,0x30,0xa5,0xba,0x0, 0xf3,0x7d,0x32,0x1b,0x24,0x4d,0x33,0x78,0xe6, +0x22,0x2, 0x53,0x34,0x75,0xe7,0x6b,0xe4,0x7e,0x34,0x1, 0x4, 0x7e,0x24,0x0, 0xff, +0x7a,0x1b,0xb0,0x7e,0x34,0x1, 0x5, 0x7a,0x1b,0xb0,0x75,0xe9,0xff,0x22,0x2, 0x53, +0x34,0x7c,0xa7,0x7c,0x3b,0xa5,0xbb,0x0, 0x7, 0x7c,0xba,0x12,0x53,0xb1,0x80,0x25, +0xbe,0x30,0xeb,0x68,0x4, 0xa5,0xbb,0xec,0x9, 0x7c,0xb3,0x7c,0x7a,0x12,0x54,0x6, +0x80,0x13,0xbe,0x30,0x80,0x40,0xe, 0xbe,0x30,0xef,0x38,0x9, 0x7c,0xb3,0x24,0x80, +0x7c,0x7a,0x12,0x53,0xd9,0xa5,0xbb,0xfc,0x5, 0x7c,0xba,0x2, 0x52,0xc8,0x74,0x1, +0x7a,0xb3,0x4f,0xab,0x22,0x7c,0xab,0x80,0xf, 0x7e,0x70,0x2, 0x80,0x1, 0x0, 0x7c, +0x67,0x1b,0x70,0xa5,0xbe,0x0, 0xf7,0x0, 0x7c,0x6a,0x1b,0xa0,0xa5,0xbe,0x0, 0xe9, +0x22,0x7a,0xb3,0x4d,0xeb,0xc4,0x54,0x7, 0xbe,0xb0,0x4, 0x68,0x3, 0xb4,0x2, 0x4, +0x74,0x3, 0x80,0x7, 0x60,0x3, 0xb4,0x1, 0x7, 0x74,0x1, 0x7a,0xb3,0x4d,0xa0,0x22, +0x12,0x1f,0xf8,0xe4,0x7a,0xb3,0x4d,0xeb,0x22,0x7c,0x6b,0x2e,0x60,0xdd,0x68,0x25, +0x2e,0x60,0xfd,0x68,0x20,0x1b,0x61,0x68,0x1c,0x2e,0x60,0xfa,0x68,0x17,0x1b,0x60, +0x68,0x13,0x80,0x0, 0xa, 0x2b,0x19,0x72,0x4d,0x79,0xd2,0x21,0xb4,0x25,0x6, 0xd2, +0x22,0x7a,0x73,0x4d,0x77,0x22,0xbe,0xb0,0xeb,0x68,0x3, 0xb4,0xec,0x33,0x7e,0x27, +0x4e,0x47,0x4d,0x22,0x78,0xe, 0xa5,0xbf,0xaa,0xa, 0x7e,0x24,0x0, 0x1, 0x7a,0x27, +0x4e,0x47,0x15,0xf, 0x7e,0x27,0x4e,0x47,0xbe,0x24,0x0, 0x1, 0x78,0x10,0xa5,0xbf, +0x9, 0x6, 0x7e,0x34,0x0, 0x2, 0x80,0x2, 0x6d,0x33,0x7a,0x37,0x4e,0x47,0x75,0xf, +0xea,0x22,0x7e,0x14,0xf7,0xf0,0x7e,0x4, 0x0, 0xff,0x7e,0x34,0x47,0x52,0x7e,0x24, +0x55,0x50,0x79,0x30,0x0, 0x2, 0x1b,0xa, 0x20,0x7e,0x34,0x45,0x20,0x7e,0x24,0x41, +0x44,0x79,0x30,0x0, 0x6, 0x79,0x20,0x0, 0x4, 0x7e,0x34,0x99,0x33,0x7e,0x24,0x66, +0xcc,0x79,0x30,0x0, 0xa, 0x79,0x20,0x0, 0x8, 0x7e,0x34,0x41,0x47,0x7e,0x24,0x46, +0x4c,0x79,0x30,0x0, 0xe, 0x79,0x20,0x0, 0xc, 0x22,0x7e,0x73,0x3e,0x68,0x7a,0x73, +0x3e,0x69,0x7e,0x73,0x3f,0xdd,0x7a,0x73,0x3f,0xde,0xe4,0x7a,0xb3,0x3f,0xe1,0x7e, +0x73,0x4f,0x4c,0x7a,0x73,0x4d,0xa4,0x7e,0x73,0x40,0x2, 0x7a,0x73,0x49,0xe9,0x22, +0x7e,0xb3,0x4f,0xac,0x4, 0x7a,0xb3,0x4f,0xac,0x7e,0x73,0x4f,0xac,0x7a,0x73,0x4d, +0x8a,0x22,0x7e,0x37,0x4f,0x5d,0xb, 0x34,0x7a,0x37,0x4f,0x5d,0x7e,0x37,0x4f,0x5f, +0xbe,0x37,0x4f,0x5d,0x28,0x3, 0x2, 0x54,0xdd,0x22,0x2, 0x54,0xc2,0xe5,0x9a,0x60, +0x5, 0xd2,0x9c,0xa9,0xd6,0xdf,0x22,0xca,0x7b,0xca,0x6b,0xca,0x5b,0xca,0x4b,0xca, +0x2b,0xca,0x1b,0xca,0xb, 0xc0,0xd0,0xc0,0x83,0xc0,0x82,0xc2,0x8f,0x12,0x54,0xda, +0xd0,0x82,0xd0,0x83,0xd0,0xd0,0xda,0xb, 0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b, +0xda,0x6b,0xda,0x7b,0x32,0xe4,0x12,0x57,0xc3,0x12,0x57,0x12,0x12,0x55,0x9d,0x12, +0x55,0x92,0x12,0x56,0xfb,0x7e,0x34,0x0, 0x1c,0x12,0xc, 0x65,0x7e,0x34,0x9, 0xc4, +0x12,0x1d,0x19,0x12,0x56,0xe1,0x12,0x56,0xd0,0x12,0x56,0xdb,0x12,0x56,0xd5,0x12, +0x57,0x6, 0x12,0x57,0xe1,0x12,0x55,0xb3,0x12,0xa1,0x38,0x12,0x55,0x6d,0x12,0x56, +0x49,0xd2,0xaf,0x12,0x56,0x8, 0x90,0xe, 0x73,0xe4,0x93,0xca,0xb8,0x90,0xe, 0x74, +0xe4,0x93,0x7c,0x7b,0x7e,0x24,0x1, 0x33,0xda,0xb8,0x2, 0xb, 0x7b,0x2, 0x55,0x70, +0xd2,0x0, 0x12,0x36,0x14,0xa9,0xd0,0xcb,0xa9,0xc6,0xca,0x12,0x57,0x1f,0xa9,0xd3, +0x9e,0xa9,0xc3,0xb9,0xc2,0x8a,0xd2,0xaa,0x2, 0x55,0x8b,0xa9,0xd0,0x9e,0xa9,0xd7, +0x9e,0x22,0xc2,0x8d,0xc2,0x8f,0x12,0x56,0x0, 0xa9,0xc0,0x93,0x22,0x75,0xec,0xff, +0x75,0xee,0xff,0x75,0xeb,0x23,0x75,0xac,0xc0,0x12,0x57,0xd1,0xa9,0xd5,0xad,0xa9, +0xc5,0xed,0x22,0xe4,0x7a,0xb3,0x4d,0xeb,0x7e,0x8, 0x4b,0x21,0x12,0x56,0xe8,0x7e, +0x8, 0x4b,0x5f,0x7e,0x34,0x0, 0x3e,0x12,0x16,0x5a,0x7e,0x18,0x4b,0x21,0x7a,0x1f, +0x4b,0x9d,0x12,0x55,0xe5,0x2, 0x55,0xd8,0x75,0x8, 0x0, 0x75,0xf, 0x0, 0x7e,0xb3, +0x4d,0xeb,0xf5,0x91,0x22,0x2, 0x55,0xe8,0xc2,0x92,0x12,0x56,0x0, 0x90,0xe, 0x6, +0xe4,0x93,0x54,0xfe,0xf5,0x92,0xd2,0xe8,0xc2,0xc0,0xa9,0xd4,0x95,0xd2,0xad,0x22, +0x75,0x91,0x0, 0xc2,0x90,0xc2,0x91,0x22,0x6c,0x77,0xa9,0xc7,0xb3,0xa9,0xc6,0xb3, +0xd2,0xc8,0x43,0xed,0xf, 0xc2,0xea,0xb, 0x70,0xbe,0x70,0x3, 0x28,0x3, 0x7e,0x70, +0x3, 0xa, 0x57,0x3e,0x54,0x3e,0x54,0x3e,0x54,0x3e,0x54,0x2e,0x54,0x0, 0x3, 0xf5, +0xb3,0xa9,0xd1,0xb4,0xa9,0xc0,0xb4,0x12,0x56,0xf1,0x2, 0x56,0x3d,0xa9,0xc5,0xca, +0xa9,0xc7,0x94,0xe4,0x7a,0xb3,0x4f,0xb0,0x22,0xa9,0xd2,0xea,0xa9,0xc2,0xea,0x6d, +0x33,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x10,0x12,0x35,0x8e,0x4e,0x34,0xdc,0xe, +0x1b,0xa, 0x30,0x7e,0x34,0x1, 0xc2,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x1e,0x7e, +0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70,0x10,0x1b,0xa, 0x30, +0x12,0xac,0x93,0x12,0xb, 0xe5,0x7e,0x34,0xff,0xff,0x7e,0xf, 0x4f,0xa1,0x79,0x30, +0x0, 0x2, 0x6d,0x33,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x14,0x7e,0xf, 0x4f,0xa1, +0x79,0x30,0x0, 0x4, 0x7e,0x34,0xf0,0x4f,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x4, +0xd2,0x2, 0x12,0x1c,0x4f,0x53,0xc3,0xf8,0x75,0xc3,0x85,0x53,0xc2,0xfc,0x43,0xc2, +0x81,0xd2,0xac,0x2, 0x56,0xc6,0x90,0x13,0x7e,0xe4,0x93,0x7a,0xb3,0x4f,0x4d,0x22, +0xc2,0x88,0xd2,0xa8,0x22,0xa9,0xd5,0xcd,0xd2,0x99,0x22,0xa9,0xd6,0xcd,0xd2,0x98, +0x22,0xa9,0xd0,0x99,0xa9,0xc6,0xdf,0x22,0x7e,0x34,0x0, 0x3e,0x74,0xff,0x2, 0x16, +0x5a,0xa9,0xd7,0x94,0x74,0xa5,0x7a,0xb3,0x4f,0xb0,0x22,0xa9,0xc3,0xcb,0xc2,0xcd, +0xc2,0xcc,0xa9,0xd6,0xea,0x22,0x75,0x9a,0x2f,0xa9,0xd1,0x99,0xd2,0x9c,0xa9,0xd6, +0xdf,0x22,0xa9,0xc5,0xcb,0xa9,0xd1,0xcb,0xa9,0xd2,0xca,0xa9,0xd2,0xcb,0x22,0xa9, +0xd0,0x9e,0xa9,0xd4,0x9e,0x75,0x9d,0x0, 0x75,0x9c,0x20,0x22,0xca,0xb8,0xca,0x39, +0x12,0x57,0x1f,0x12,0x55,0x8b,0x7e,0x37,0x4f,0x44,0xb, 0x34,0x7a,0x37,0x4f,0x44, +0x7e,0x37,0x4f,0x56,0xb, 0x34,0x7a,0x37,0x4f,0x56,0x7e,0xb3,0x4d,0xa0,0xb4,0x1, +0x40,0x7e,0xb3,0x4f,0x58,0x4, 0x7a,0xb3,0x4f,0x58,0x7e,0x73,0x4f,0x58,0xbe,0x70, +0xa, 0x28,0x2e,0xe4,0x7a,0xb3,0x4f,0x58,0x7e,0x73,0x4f,0x4f,0xbe,0x73,0x4f,0xac, +0x78,0x8, 0x7e,0x37,0x4f,0x46,0xb, 0x34,0x80,0xa, 0x7e,0x73,0x4f,0xac,0x7a,0x73, +0x4f,0x4f,0x6d,0x33,0x7a,0x37,0x4f,0x46,0xbe,0x34,0x0, 0xfa,0x28,0x3, 0x75,0xe9, +0xff,0x7e,0xb3,0x4f,0x48,0x60,0x5, 0x14,0x7a,0xb3,0x4f,0x48,0x7e,0xb3,0x4f,0x48, +0x70,0x2, 0xd2,0x16,0x7e,0x37,0x4f,0x9a,0xb, 0x34,0x7a,0x37,0x4f,0x9a,0x7e,0x37, +0x4f,0x52,0xbe,0x34,0x0, 0x0, 0x28,0x6, 0x1b,0x34,0x7a,0x37,0x4f,0x52,0xda,0x39, +0xda,0xb8,0x32,0xa9,0xc5,0xca,0xbe,0xb0,0x8, 0x50,0x2, 0xf5,0xcc,0x75,0xe6,0x0, +0x22,0xa9,0xc5,0xca,0x75,0xed,0x8f,0x75,0xad,0xb0,0xa9,0xc7,0x94,0xa9,0xd4,0x94, +0x22,0xc2,0x8e,0x43,0x89,0x20,0x75,0x8d,0x1, 0x75,0x8b,0x0, 0xd2,0x8e,0xd2,0xab, +0x22,0xca,0x7b,0xca,0x6b,0xca,0x5b,0xca,0x4b,0xca,0x2b,0xca,0x1b,0xca,0xb, 0xc0, +0xd0,0xc0,0x83,0xc0,0x82,0x12,0x34,0xc, 0xd0,0x82,0xd0,0x83,0xd0,0xd0,0xda,0xb, +0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b,0xda,0x6b,0xda,0x7b,0x32,0x12,0x58,0x24, +0x75,0x8, 0x0, 0x32,0xa9,0xc0,0x93,0x22,0xb4,0xfa,0x5, 0x7e,0xb3,0x2c,0xff,0x22, +0x70,0x5, 0x7e,0xb3,0x4d,0xeb,0x22,0xbe,0xb0,0x3, 0x38,0x13,0x30,0x2b,0x6, 0x7e, +0x18,0x4b,0x21,0x80,0x4, 0x7e,0x18,0x4b,0x5f,0x7a,0x1f,0x4b,0x9d,0x80,0x5, 0xbe, +0xb0,0x6e,0x38,0xe, 0xa, 0x1b,0x7e,0x1f,0x4b,0x9d,0x2d,0x31,0x1b,0x34,0x7e,0x1b, +0xb0,0x22,0xbe,0xb0,0xeb,0x68,0x3, 0xb4,0xec,0x3, 0x2, 0x58,0x98,0xbe,0xb0,0x80, +0x40,0xc, 0xbe,0xb0,0xef,0x38,0x7, 0xa, 0x3b,0x9, 0xb3,0x4c,0xf9,0x22,0xb4,0xfc, +0x5, 0x7e,0xb3,0x4d,0xa0,0x22,0xb4,0xfe,0xc, 0x7e,0xa3,0x4f,0x55,0x74,0x27,0xa4, +0x9, 0xb5,0x4b,0xa3,0x22,0x74,0xff,0x22,0xb4,0xeb,0x3, 0x75,0x10,0x0, 0xe5,0x10, +0xa, 0x3b,0x2e,0x34,0x0, 0x16,0x12,0x58,0xcb,0x7c,0xab,0x5, 0x10,0xe5,0x10,0xb4, +0x3, 0x9, 0x75,0x10,0x0, 0x6d,0x33,0x7a,0x37,0x4e,0x47,0x75,0xf, 0xeb,0x7c,0xba, +0x22,0x7c,0xb7,0x54,0x7, 0xa, 0x3b,0x2e,0x34,0x0, 0xf5,0x7a,0x71,0x82,0x7a,0x61, +0x83,0xe4,0x93,0x22,0x74,0x1, 0x7a,0xb3,0x4f,0xae,0x7e,0xb3,0x4d,0xc9,0xb4,0x1, +0x6, 0xe4,0x7a,0xb3,0x4f,0xae,0x22,0x7e,0xb4,0x13,0x81,0x7d,0x3b,0x12,0x58,0xcb, +0x7c,0x7b,0x1e,0x70,0x7a,0x73,0x3f,0xea,0x7e,0xa4,0x0, 0x96,0x7a,0xa7,0x3f,0xeb, +0x7e,0x34,0x0, 0x8c,0x7a,0x37,0x3f,0xed,0x12,0xaa,0xea,0x7e,0xa3,0x3e,0x53,0xbe, +0xa0,0x0, 0x38,0x2, 0x21,0xa7,0xbe,0xa0,0x8, 0x28,0x1f,0x7e,0x37,0x3e,0x59,0xbe, +0x34,0x1, 0x90,0x58,0x15,0x7d,0x3b,0x12,0x58,0xcb,0x1e,0xb0,0xa, 0x3b,0x7d,0x2a, +0x7e,0x14,0x0, 0x8c,0x7e,0x4, 0x0, 0x82,0x80,0x66,0xbe,0xa0,0x6, 0x28,0x1b,0x7e, +0x37,0x3e,0x59,0xbe,0x34,0x1, 0xf4,0x58,0x11,0x7d,0x3b,0x12,0x58,0xcb,0xa, 0x3b, +0x7e,0x24,0x0, 0xa0,0x7d,0x1a,0x7d,0xa, 0x80,0x46,0xbe,0xa0,0x4, 0x28,0x1f,0x7e, +0xa7,0x3e,0x59,0xbe,0xa4,0x2, 0x58,0x58,0x15,0x7d,0x3b,0x12,0x58,0xcb,0xa, 0x3b, +0x7e,0x24,0x0, 0xb4,0x7e,0x14,0x0, 0xaa,0x7e,0x4, 0x0, 0xc8,0x80,0x22,0xbe,0xa0, +0x2, 0x28,0x24,0x7e,0xa7,0x3e,0x59,0xbe,0xa4,0x3, 0x20,0x58,0x1a,0x7d,0x3b,0x12, +0x58,0xcb,0xa, 0x3b,0x7e,0x24,0x0, 0xdc,0x7e,0x14,0x0, 0xd2,0x7e,0x4, 0x0, 0xe6, +0x12,0x59,0xd8,0x80,0x7, 0x80,0x0, 0xe4,0x7a,0xb3,0x4f,0xae,0x7e,0xb3,0x4f,0xae, +0x70,0x23,0x90,0x13,0x81,0xe4,0x93,0xa, 0x3b,0x7e,0x14,0x13,0x89,0x12,0x5d,0x9f, +0x7e,0x14,0x13,0x8b,0x12,0x59,0xfd,0x7e,0x54,0x13,0x95,0x7e,0x44,0x0, 0xff,0xb, +0x2a,0x0, 0x2, 0x59,0xd8,0xd2,0x21,0x22,0x7a,0x73,0x3f,0xea,0x7a,0x27,0x3f,0xeb, +0x7a,0x17,0x3f,0xed,0x7a,0x7, 0x3f,0xf7,0x6d,0x33,0x9d,0x30,0x12,0x1f,0xe, 0x12, +0x1f,0xa9,0x7a,0x73,0x4d,0x7a,0x22,0x12,0x9d,0xa6,0x2, 0x58,0xd4,0x7e,0x4, 0x0, +0xff,0xb, 0xa, 0x10,0x22,0x7d,0x13,0x9f,0x11,0x7e,0xf4,0x14,0xa, 0x7e,0xe4,0x0, +0xff,0xb, 0x7a,0x0, 0x7e,0xf4,0x14,0x1a,0x7e,0xe4,0x0, 0xff,0xb, 0x7a,0xf0,0x7e, +0xd4,0x14,0x1c,0x7e,0xc4,0x0, 0xff,0xb, 0x6a,0xe0,0x90,0xe, 0x5a,0xe4,0x93,0x70, +0x3, 0x7d,0x31,0x22,0x90,0x14,0x7, 0xe4,0x93,0xb4,0x1, 0x6, 0x7e,0x83,0x40,0x11, +0x80,0x4, 0x7e,0x83,0x40,0x12,0x12,0x5d,0xa7,0xbe,0x14,0x0, 0x3f,0x38,0x1a,0x7e, +0x24,0x0, 0x3f,0x9d,0x21,0x7e,0x14,0x14,0x20,0x12,0x5b,0x1b,0x12,0x5b,0x2d,0x48, +0x2, 0x7f,0x10,0x9f,0x1, 0x7f,0x10,0x61,0x12,0x7d,0x54,0x9e,0x54,0x0, 0x3f,0xbd, +0x51,0x38,0x43,0x7d,0x54,0x9e,0x54,0x0, 0x1f,0xbd,0x51,0x40,0x1d,0x7d,0x34,0x9e, +0x34,0x0, 0x40,0x12,0x5b,0x13,0x90,0x14,0x1f,0x12,0x5b,0x30,0x48,0x4, 0x7f,0x10, +0x1b,0x1c,0xa, 0xb, 0x7d,0x1f,0x9d,0x10,0x80,0x16,0xbd,0x41,0x50,0x74,0x7e,0xb3, +0x44,0x86,0xbe,0xb0,0x0, 0x28,0x6b,0x7d,0x34,0xb, 0x34,0x12,0x5b,0x13,0x7d,0x1f, +0x6d,0x0, 0x2f,0x10,0x80,0x5c,0x7d,0x50,0x1b,0x54,0xbd,0x51,0x40,0x1f,0x7d,0x30, +0x9d,0x31,0x6d,0x22,0x7e,0x14,0x14,0x24,0x12,0x59,0xfd,0x12,0x14,0xe2,0x12,0x5b, +0x26,0x7d,0x1e,0x1b,0x14,0x6d,0x0, 0x9f,0x1, 0x7f,0x10,0x80,0x19,0x7d,0x31,0x9d, +0x30,0x6d,0x22,0x7e,0x14,0x14,0x26,0x12,0x59,0xfd,0x12,0x14,0xe2,0x12,0x5b,0x26, +0x7d,0x1e,0x6d,0x0, 0x2f,0x10,0x12,0x5b,0x2d,0x58,0x4, 0x7f,0x10,0x80,0x13,0x90, +0x14,0x1f,0xe4,0x93,0xa, 0xb, 0x7d,0x1f,0x9d,0x10,0x6d,0x0, 0xbf,0x10,0x8, 0x2, +0x7f,0x10,0x22,0x7d,0x21,0x9d,0x23,0x7e,0x14,0x14,0x22,0x7e,0x4, 0x0, 0xff,0xb, +0xa, 0x30,0xad,0x32,0x6d,0x22,0x7c,0x76,0x7c,0x65,0x1a,0x24,0x22,0x90,0x14,0x1e, +0xe4,0x93,0xa, 0x1b,0x6d,0x0, 0xbf,0x10,0x22,0xca,0xf8,0x12,0x5f,0xdf,0x40,0x2, +0x61,0xd9,0x7e,0xb3,0x24,0x26,0xb4,0x1, 0x2, 0x80,0x2, 0x61,0xd9,0x6c,0xff,0x61, +0xd2,0x74,0x9, 0xac,0xbf,0x49,0x35,0x3d,0x45,0x12,0x5c,0x83,0x7d,0xb3,0x74,0x9, +0xac,0xbf,0x49,0x35,0x3d,0x47,0x12,0x5a,0x5, 0x7d,0xa3,0x7e,0x34,0x14,0xc, 0x7e, +0x24,0x0, 0xff,0xb, 0x1a,0x40,0x7e,0x73,0x4d,0xbd,0x12,0x5b,0xec,0x12,0x5b,0xdc, +0x7d,0x3b,0x6d,0x22,0xbf,0x10,0x40,0x41,0x7e,0x34,0x14,0x1a,0x7e,0x24,0x0, 0xff, +0xb, 0x1a,0x50,0x7e,0x73,0x4d,0xbf,0x12,0x5b,0xe3,0x12,0x5b,0xdc,0x7d,0x3a,0x6d, +0x22,0xbf,0x10,0x40,0x24,0x7e,0x73,0x4d,0xbe,0x12,0x5b,0xec,0x12,0x5b,0xdc,0x7d, +0x3b,0x6d,0x22,0xbf,0x10,0x38,0x12,0x7e,0x73,0x4d,0xc0,0x12,0x5b,0xe3,0x12,0x5b, +0xdc,0x7d,0x3a,0x6d,0x22,0xbf,0x10,0x28,0x7, 0xc2,0x6, 0x7c,0xbf,0x12,0x26,0xfa, +0xb, 0xf0,0x12,0x27,0xf7,0x28,0x2, 0x61,0x51,0xda,0xf8,0x22,0x7c,0x36,0x7c,0x25, +0xa, 0x4, 0x22,0xa, 0x37,0x6d,0x22,0x7d,0x15,0x2, 0x14,0xe2,0xa, 0x37,0x6d,0x22, +0x7d,0x14,0x2, 0x14,0xe2,0x7c,0x7b,0xc4,0x23,0x54,0x1f,0xa, 0x2b,0x9, 0xa2,0x3d, +0x41,0x12,0x58,0xc1,0x5c,0xba,0x22,0xca,0xf8,0x7e,0xb3,0x3f,0xdd,0x70,0x17,0xe4, +0x7a,0xb3,0x3f,0xe6,0x12,0x5f,0xe7,0x28,0x1f,0x74,0x1, 0x7a,0xb3,0x3f,0xe2,0xe4, +0x7a,0xb3,0x3f,0xe5,0x80,0x12,0x74,0x1, 0x7a,0xb3,0x3f,0xe6,0x7e,0xb3,0x3f,0xde, +0x70,0x6, 0x74,0x1, 0x7a,0xb3,0x3f,0xe1,0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e, +0x89,0x7e,0x8, 0x3e,0xe3,0x12,0x16,0x35,0x1b,0xfd,0x90,0xe, 0x5a,0xe4,0x93,0xbe, +0xb0,0x0, 0x28,0x2c,0x6c,0xff,0x80,0x1f,0x74,0x9, 0xac,0xbf,0x49,0x35,0x3e,0x89, +0x12,0x5c,0x83,0x74,0x9, 0xac,0xbf,0x59,0x35,0x3e,0xe3,0x49,0x35,0x3e,0x8b,0x12, +0x5a,0x5, 0x12,0x5d,0xaf,0xb, 0xf0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xd8, +0xda,0xf8,0x22,0x7e,0x14,0x14,0x8, 0x12,0x5d,0x9f,0x7e,0x14,0x14,0xc, 0x7e,0x4, +0x0, 0xff,0xb, 0xa, 0xd0,0x7e,0x14,0x14,0xe, 0x7e,0x4, 0x0, 0xff,0xb, 0xa, 0xc0, +0x90,0xe, 0x5a,0xe4,0x93,0x70,0x1, 0x22,0x90,0x14,0x7, 0xe4,0x93,0xb4,0x1, 0x6, +0x7e,0x83,0x40,0x12,0x80,0x4, 0x7e,0x83,0x40,0x11,0x12,0x5d,0xa7,0xbe,0x34,0x0, +0x3f,0x38,0x22,0x7e,0xe4,0x0, 0x3f,0x9d,0xe3,0x7e,0x34,0x14,0x12,0x12,0x5d,0x76, +0x7c,0x76,0x7c,0x65,0x7f,0x71,0x12,0x5d,0x6e,0xbf,0x71,0x40,0x2, 0x7f,0x71,0x9f, +0x17,0x7f,0x71,0xa1,0x6b,0x7d,0x54,0x9e,0x54,0x0, 0x3f,0xbd,0x53,0x38,0x2c,0x7d, +0xe3,0x9d,0xe5,0x7e,0x34,0x14,0x14,0x12,0x5d,0x76,0x7c,0x76,0x7c,0x65,0x7f,0x71, +0x90,0x14,0x11,0xe4,0x93,0xa, 0x3b,0xbf,0x71,0x40,0x4, 0x7f,0x71,0x1b,0x7c,0xa, +0x2b,0x7d,0x3d,0x9d,0x32,0x6d,0x22,0x2f,0x71,0x80,0x50,0x7d,0x52,0x1b,0x54,0xbd, +0x53,0x40,0x17,0x7d,0xf5,0x9d,0xf3,0x6d,0xee,0x7e,0x34,0x14,0x16,0x12,0x5d,0x86, +0x1b,0x34,0x6d,0x22,0x9f,0x17,0x7f,0x71,0x80,0x11,0x7d,0xf3,0x9d,0xf2,0x6d,0xee, +0x7e,0x34,0x14,0x18,0x12,0x5d,0x86,0x6d,0x22,0x2f,0x71,0x12,0x5d,0x6e,0x6d,0x22, +0xbf,0x71,0x50,0x4, 0x7f,0x71,0x80,0x13,0x90,0x14,0x11,0xe4,0x93,0xa, 0x2b,0x7d, +0x3d,0x9d,0x32,0x6d,0x22,0xbf,0x71,0x28,0x2, 0x7f,0x71,0x7d,0x3f,0x22,0x90,0x14, +0x10,0xe4,0x93,0xa, 0x3b,0x22,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0xf0,0xad,0xfe,0x6d, +0xee,0x7d,0x3f,0x7d,0x2e,0x22,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0x10,0x7f,0x17,0x12, +0x14,0xe2,0x7f,0x71,0x7c,0x76,0x7c,0x65,0xa, 0x24,0x7f,0x71,0x7d,0x3c,0x22,0x7e, +0x4, 0x0, 0xff,0xb, 0xa, 0x20,0x22,0x7e,0x90,0x40,0xac,0x89,0x1b,0x44,0x22,0x74, +0x9, 0xac,0xbf,0x59,0x35,0x3e,0xe5,0x22,0xca,0xd8,0xca,0x79,0x7e,0x34,0x14,0x1a, +0x12,0x5f,0xef,0x90,0xe, 0x5a,0xe4,0x93,0x60,0x68,0x7e,0xb3,0x44,0x86,0x60,0x62, +0x6c,0xff,0x80,0x55,0x7e,0x70,0x9, 0xac,0x7f,0x9, 0xe3,0x3e,0xe7,0x5e,0xe0,0xf, +0x49,0x23,0x3e,0xe5,0xbd,0x2d,0x40,0x3f,0x49,0xc3,0x3e,0x89,0x7d,0x3c,0x12,0x96, +0xc8,0x7c,0xdb,0x7e,0x73,0x44,0x86,0xbc,0x7d,0x28,0x20,0x7e,0x70,0x2, 0xac,0x7d, +0x2e,0x34,0x14,0x29,0x12,0x1d,0xf2,0x74,0x9, 0xac,0xbf,0x59,0x35,0x3e,0xe3,0x7e, +0x34,0x14,0x31,0x12,0x1d,0xf2,0x12,0x5d,0xaf,0x80,0xc, 0x7d,0x3d,0x1b,0x34,0x12, +0x5d,0xaf,0x7c,0xbe,0x12,0x96,0x75,0xb, 0xf0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf, +0x38,0xa2,0xda,0x79,0xda,0xd8,0x22,0xca,0x79,0x6c,0xff,0xc2,0x0, 0x7e,0xb3,0x40, +0x2, 0x60,0x6, 0x7e,0xd4,0x1, 0xc2,0x80,0x4, 0x7e,0xd4,0x3, 0xe8,0x7e,0xb3,0x40, +0x3, 0xb4,0x1, 0x4, 0x7e,0xd4,0x0, 0xf0,0x7e,0xc7,0x3e,0x59,0x6c,0xee,0xc1,0xe2, +0xc2,0x0, 0x7c,0xbe,0x12,0x7d,0x20,0x7d,0xb3,0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x3c, +0xc9,0x12,0x80,0xaf,0xbd,0x3b,0x58,0x4, 0xd2,0x0, 0x80,0x37,0x74,0x2, 0xac,0xbe, +0x9, 0xb5,0x3c,0xc9,0x12,0x5e,0xf8,0x50,0x4, 0xd2,0x0, 0x80,0x26,0x7e,0x73,0x3f, +0xde,0xbe,0x73,0x3e,0x53,0x78,0x1c,0x7e,0xa7,0x4f,0xa9,0xe, 0xa4,0xbd,0xac,0x58, +0x12,0x7c,0xbe,0x7e,0x70,0x1, 0x12,0x5f,0x3, 0x7d,0x1d,0x6d,0x0, 0xbf,0x10,0x8, +0x2, 0xd2,0x0, 0x30,0x0, 0x2a,0x7c,0xbe,0x12,0x5b,0xf5,0x60,0x23,0x7e,0xa4,0x0, +0x9, 0xca,0xa9,0x7e,0x70,0x9, 0xac,0x7e,0x2e,0x34,0x3d,0x45,0x6d,0x22,0x7e,0x30, +0x9, 0xac,0x3f,0x2e,0x14,0x3e,0x89,0x6d,0x0, 0x12,0x16,0x35,0x1b,0xfd,0xb, 0xf0, +0xb, 0xe0,0x12,0x5f,0xd8,0x28,0x2, 0xc1,0x60,0x7a,0x73,0x3e,0x68,0x7a,0xf3,0x3f, +0xdd,0x7a,0xc7,0x4f,0xa9,0xda,0x79,0x22,0x7c,0xab,0x12,0x5f,0xcd,0x78,0x2, 0xd3, +0x22,0xc3,0x22,0x7c,0x67,0x7c,0x7b,0x7e,0x50,0x2, 0xac,0x57,0x9, 0xa2,0x3c,0xc9, +0x9, 0x72,0x3c,0xca,0x12,0x5f,0xcd,0x78,0x3, 0x9f,0x11,0x22,0x7c,0xba,0x2, 0x5f, +0x21,0x7c,0x16,0x7c,0x7, 0x7c,0x9b,0x7e,0xb3,0x40,0x11,0xf5,0x2a,0x7e,0xb3,0x40, +0x12,0xf5,0x2b,0x9f,0x77,0xa, 0x31,0xa, 0x19,0x9d,0x13,0x7c,0x83,0x80,0x7d,0x7a, +0x81,0x28,0xbe,0x80,0x0, 0x58,0xc, 0x1a,0x58,0x1a,0x19,0x9d,0x15,0xa, 0x59,0x2d, +0x51,0xf5,0x28,0xe5,0x2a,0xbc,0xb8,0x18,0xc, 0x1a,0x59,0x1a,0x18,0x9d,0x15,0xa, +0x59,0x9d,0x51,0xf5,0x28,0xa, 0x11,0xa, 0x50,0x9d,0x51,0xf5,0x27,0x80,0x3d,0x85, +0x27,0x29,0xe5,0x27,0xbe,0xb0,0x0, 0x58,0xe, 0xe5,0x27,0x1a,0x5b,0x1a,0x10,0x9d, +0x15,0xa, 0x50,0x2d,0x51,0xf5,0x29,0xe5,0x2b,0xbe,0xb1,0x27,0x18,0xe, 0x1a,0x30, +0xe5,0x27,0x1a,0x1b,0x9d,0x13,0xa, 0x50,0x9d,0x51,0xf5,0x29,0xe5,0x28,0x7e,0x71, +0x29,0x12,0x23,0x82,0x1a,0x26,0x1a,0x24,0x2f,0x71,0x5, 0x27,0xa, 0x21,0xa, 0x30, +0x2d,0x32,0xe5,0x27,0x1a,0x1b,0xbd,0x13,0x8, 0xb5,0xb, 0x80,0xa, 0x11,0xa, 0x59, +0x2d,0x51,0x1a,0x18,0xbd,0x15,0x18,0x2, 0xe1,0x3f,0x7f,0x17,0x22,0x90,0x14,0x28, +0xe4,0x93,0xbc,0xba,0x22,0x2, 0x5e,0x37,0x7e,0x73,0x3e,0x53,0xbc,0x7e,0x22,0x7e, +0x73,0x40,0x3, 0x2e,0x70,0xff,0x22,0x7e,0x73,0x3f,0xde,0xbe,0x70,0x0, 0x22,0x7e, +0x24,0x0, 0xff,0xb, 0x1a,0xd0,0x22,0xca,0x79,0x7c,0xfb,0x7f,0x51,0x7f,0x40,0x74, +0x9, 0xac,0xbf,0x9, 0xb5,0x3e,0xe8,0xf5,0x37,0x74,0x9, 0xac,0xbf,0x9, 0xb5,0x3e, +0xe9,0xc4,0x54,0xf0,0xf5,0x38,0x74,0x9, 0xac,0xbf,0x9, 0xe5,0x3e,0xe7,0x7e,0x73, +0x3f,0xe9,0xbc,0x7e,0x28,0x58,0x7e,0xb3,0x3f,0xe4,0x70,0x28,0x75,0x39,0xf, 0x7e, +0x8, 0x0, 0x37,0xa, 0x3e,0x2e,0x34,0x4b,0xd, 0x6d,0x22,0x74,0x1, 0x12,0x60,0xa8, +0x75,0x39,0x20,0x7e,0x8, 0x0, 0x38,0xa, 0x3e,0x2e,0x34,0x4b,0x17,0x74,0x10,0x12, +0x60,0xa8,0x80,0xe, 0xa, 0x3e,0x9, 0xb3,0x4b,0xd, 0xf5,0x37,0x9, 0xb3,0x4b,0x17, +0xf5,0x38,0x74,0x7, 0xac,0xbe,0x9, 0xb5,0x3f,0x97,0xb4,0x1, 0x11,0xe4,0xa, 0x3e, +0x19,0xb3,0x4b,0xd, 0x19,0xb3,0x4b,0x17,0x75,0x37,0x0, 0x75,0x38,0x0, 0x7e,0xb3, +0x3f,0xfd,0xb4,0xff,0x16,0x85,0x36,0x37,0x75,0x37,0x0, 0x74,0x9, 0xac,0xbf,0x9, +0xb5,0x3e,0xe7,0xbe,0xb0,0xff,0x68,0x3, 0x75,0x37,0x1, 0xe5,0x37,0x7a,0x4b,0xb0, +0xe5,0x38,0x7a,0x5b,0xb0,0xda,0x79,0x22,0x7c,0x9b,0x7e,0x1b,0xa0,0x4c,0xaa,0x78, +0x7, 0x7e,0xb, 0xb0,0x7a,0x1b,0xb0,0x22,0xa, 0xda,0x7e,0xb, 0x80,0xa, 0xe8,0x7d, +0xfe,0x9d,0xfd,0xbe,0xf4,0x0, 0x0, 0x8, 0x4, 0x9d,0xed,0x80,0x4, 0x6d,0xee,0x9d, +0xef,0xe5,0x39,0xa, 0xfb,0xbd,0xef,0x8, 0xf, 0xbc,0x8a,0x7c,0xba,0x28,0x4, 0x2c, +0xb9,0x80,0x2, 0x9c,0xb9,0x7a,0x1b,0xb0,0x7e,0x1b,0x70,0x7a,0xb, 0x70,0x22,0xca, +0x3b,0x75,0x29,0x0, 0x75,0x2a,0x0, 0x75,0x2b,0x0, 0x75,0x2c,0x0, 0x75,0x2e,0x0, +0x75,0x2f,0x3, 0x7e,0x38,0x4b,0x21,0x7e,0x18,0x3f,0x97,0x7a,0x1d,0x32,0xe4,0x39, +0xb3,0x0, 0x1, 0x7e,0xb3,0x3f,0xe6,0x70,0xe, 0x7e,0xb3,0x3f,0xe2,0x70,0x8, 0x7e, +0xb3,0x3f,0xe3,0x70,0x2, 0x41,0x85,0x30,0x2b,0x6, 0x7e,0x38,0x4b,0x5f,0x80,0x4, +0x7e,0x38,0x4b,0x21,0x7f,0x3, 0x12,0x56,0xe8,0x75,0x27,0x0, 0x41,0x3e,0x7e,0xa1, +0x27,0x74,0x9, 0xa4,0x49,0xc5,0x3e,0xe3,0x49,0x45,0x3e,0xe5,0x7a,0x45,0x30,0x9, +0xb5,0x3e,0xe7,0xf5,0x2d,0x90,0x13,0x7f,0xe4,0x93,0xbe,0xb1,0x2d,0x38,0x2, 0x41, +0x3c,0x7e,0xa1,0x2d,0x5e,0xa0,0xf, 0x74,0x7, 0xa4,0x7e,0x1d,0x32,0x2d,0x35,0x7e, +0x1b,0xb0,0xf5,0x2f,0xbe,0xb0,0x3, 0x78,0x2, 0x41,0x3c,0xe5,0x2f,0xb4,0x1, 0x30, +0x75,0x28,0x0, 0x80,0x21,0x7e,0x71,0x28,0x74,0x9, 0xac,0x7b,0x9, 0xb3,0x4a,0xb7, +0x54,0xf, 0xbe,0xb1,0x2d,0x78,0xd, 0x49,0xc3,0x4a,0xb3,0x49,0xd3,0x4a,0xb5,0x7a, +0xd5,0x30,0x80,0xc, 0x5, 0x28,0x90,0x13,0x7f,0xe4,0x93,0xbe,0xb1,0x28,0x38,0xd5, +0x85,0x29,0x36,0x7e,0x8, 0x0, 0x2b,0x7e,0x18,0x0, 0x2c,0xe5,0x27,0x12,0x5f,0xf7, +0x5e,0xc4,0xf, 0xff,0x7e,0xd5,0x30,0x5e,0xd4,0xf, 0xff,0x7a,0xd5,0x30,0x7e,0x91, +0x27,0x74,0x9, 0xac,0x9b,0x9, 0x74,0x3e,0xe7,0xa, 0x57,0xc4,0x54,0xf0,0x7c,0xab, +0xe4,0x7d,0xd5,0x2e,0xd5,0x30,0x7a,0xd5,0x30,0xbe,0x70,0xff,0x68,0x1a,0xe5,0x2f, +0xbe,0xb0,0x1, 0x68,0x2, 0x5, 0x29,0x5, 0x2e,0xe5,0x2f,0xa, 0x5b,0x3, 0x3, 0x54, +0xc0,0x7c,0xab,0xe4,0x2d,0xc5,0x80,0x4, 0x2e,0xc4,0xc0,0x0, 0x7e,0x71,0x2a,0x74, +0x6, 0xac,0x7b,0x7f,0x3, 0x2d,0x13,0x79,0xc0,0x0, 0x2, 0x7e,0x25,0x30,0x7f,0x3, +0x2d,0x13,0x79,0x20,0x0, 0x4, 0xe5,0x2b,0x7f,0x3, 0x2d,0x13,0x39,0xb0,0x0, 0x6, +0xe5,0x2c,0x2d,0x37,0x7d,0x26,0x39,0xb1,0x0, 0x7, 0x5, 0x2a,0x5, 0x27,0x7e,0x73, +0x3f,0xe9,0xbe,0x71,0x27,0x28,0x2, 0x21,0x3e,0xe5,0x29,0x39,0xb3,0x0, 0x1, 0x7e, +0x73,0x3f,0xdf,0x7a,0x3b,0x70,0xe5,0x2e,0xbe,0xb0,0x0, 0x38,0x6, 0x7e,0xb3,0x3f, +0xe3,0x60,0x7, 0xb2,0x2b,0xc2,0x86,0x12,0x67,0xbe,0x7e,0xb3,0x3f,0xe2,0x60,0x6, +0x7e,0xd, 0x32,0x12,0x8c,0x6d,0xe4,0x7a,0xb3,0x3f,0xe6,0x7a,0xb3,0x3f,0xe2,0x7a, +0xb3,0x3f,0xe3,0x80,0x2, 0xd2,0x86,0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e,0xe3, +0x7e,0x8, 0x4a,0xb3,0x12,0x16,0x35,0x1b,0xfd,0xe5,0x2e,0x70,0xc, 0x12,0x34,0xda, +0x7e,0x8, 0x4a,0xb3,0x74,0xff,0x12,0x16,0x5a,0xda,0x3b,0x22,0x90,0x13,0x7f,0xe4, +0x93,0x7c,0xab,0x74,0x9, 0xa4,0x22,0xca,0x79,0x7e,0xf3,0x3f,0xdd,0x7e,0xe3,0x3f, +0xde,0x7c,0xbf,0x7c,0x7e,0x12,0x3c,0x52,0x7c,0xbf,0x12,0x63,0x4e,0x4c,0xee,0x78, +0x17,0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e,0x89,0x7e,0x8, 0x3f,0x3d,0x12,0x16, +0x35,0x1b,0xfd,0x12,0x62,0xfe,0x80,0xe, 0x7e,0xb3,0x3f,0xe4,0x70,0x8, 0x12,0x62, +0xfe,0x7c,0xbf,0x12,0x64,0xa0,0x7c,0xbf,0x12,0x92,0x5c,0xda,0x79,0x22,0x7e,0xa3, +0x3f,0xdd,0x6c,0x77,0x80,0x43,0x7e,0x90,0x9, 0xac,0x97,0x9, 0x64,0x3f,0x41,0x7e, +0x50,0x7, 0xac,0x56,0x9, 0xb2,0x3f,0x97,0x70,0x2d,0x7e,0x30,0x1, 0x7e,0x50,0x9, +0xac,0x56,0x19,0x32,0x49,0x72,0x49,0x14,0x3e,0x89,0x59,0x12,0x49,0x73,0x49,0x14, +0x3e,0x8b,0x59,0x12,0x49,0x75,0xe4,0x19,0xb2,0x49,0x77,0x19,0xb2,0x49,0x6f,0x19, +0xb2,0x49,0x70,0x19,0xb2,0x49,0x71,0xb, 0x70,0xbc,0xa7,0x38,0xb9,0x22,0xca,0x79, +0x7c,0xeb,0x90,0x13,0x7f,0xe4,0x93,0x7c,0xfb,0x7e,0x70,0x9, 0xac,0x7f,0x7e,0x8, +0x44,0x87,0x74,0xff,0x12,0x16,0x5a,0xe4,0x6c,0x77,0x7c,0x6e,0x12,0x63,0xd0,0x7c, +0x7e,0x7c,0x6f,0x12,0x63,0xd0,0x7c,0x1b,0x6c,0x0, 0x80,0x3a,0x6c,0x99,0x80,0x17, +0x74,0x9, 0xac,0xb9,0x9, 0xa5,0x44,0x8b,0x7e,0x30,0x9, 0xac,0x30,0x9, 0x81,0x3e, +0x8d,0xbc,0x8a,0x68,0x6, 0xb, 0x90,0xbc,0x19,0x38,0xe5,0xbc,0x19,0x78,0x15,0x7e, +0x70,0x9, 0xac,0x70,0x12,0x67,0xb6,0xac,0x31,0x2e,0x14,0x44,0x87,0x74,0x9, 0x12, +0x15,0x72,0xb, 0x10,0xb, 0x0, 0xbc,0xf0,0x38,0xc2,0x74,0x9, 0xac,0xbf,0xca,0x59, +0x7e,0x18,0x44,0x87,0x7e,0x8, 0x3f,0x3d,0x12,0x16,0x35,0x1b,0xfd,0xda,0x79,0x22, +0x7e,0x8, 0x44,0x87,0xca,0x69,0xca,0xf8,0x7f,0x70,0x7c,0x86,0x7c,0xf7,0x7c,0xab, +0x6c,0x99,0x81,0x92,0x7c,0x3f,0x81,0x8a,0x7e,0x10,0x9, 0xac,0x19,0x9, 0x20,0x3f, +0x41,0x7e,0x10,0x9, 0xac,0x13,0x9, 0xb0,0x3e,0x8d,0xbc,0xb2,0x68,0x2, 0x81,0x88, +0xbe,0x20,0xff,0x78,0x2, 0x81,0x88,0x7e,0xd0,0x7, 0xac,0xd2,0x9, 0xb6,0x3f,0x97, +0x70,0xa, 0x7d,0x30,0x2e,0x34,0x3e,0x89,0x6d,0x22,0x80,0xb, 0x7e,0x70,0x9, 0xac, +0x79,0x2e,0x34,0x3f,0x3d,0x6d,0x22,0x29,0x11,0x0, 0x4, 0x7e,0xd0,0x9, 0xac,0xda, +0x7f,0x67,0x2d,0xd6,0x39,0x16,0x0, 0x4, 0xb, 0x1a,0x0, 0x7e,0xd0,0x9, 0xac,0xda, +0x7f,0x67,0x2d,0xd6,0x1b,0x6a,0x0, 0x69,0x1, 0x0, 0x2, 0x7e,0xd0,0x9, 0xac,0xda, +0x7f,0x67,0x2d,0xd6,0x79,0x6, 0x0, 0x2, 0x7e,0x10,0x9, 0xac,0x13,0x9, 0x10,0x3e, +0x8e,0x7e,0xd0,0x9, 0xac,0xda,0x7f,0x67,0x2d,0xd6,0x39,0x16,0x0, 0x5, 0x7e,0x10, +0x9, 0xac,0x13,0x9, 0x10,0x3e,0x8f,0x7e,0xd0,0x9, 0xac,0xda,0x7f,0x67,0x2d,0xd6, +0x39,0x16,0x0, 0x6, 0xb, 0xa0,0x80,0x8, 0xb, 0x30,0xbc,0x83,0x28,0x2, 0x61,0xe8, +0xb, 0x90,0x12,0x67,0xae,0x28,0x2, 0x61,0xe4,0x7c,0xba,0xda,0xf8,0xda,0x69,0x22, +0xca,0x3b,0x7c,0xfb,0x6c,0xee,0xa1,0x42,0x6c,0xdd,0x80,0x16,0x74,0x9, 0xac,0xbd, +0x9, 0x65,0x3f,0x41,0x74,0x9, 0xac,0xbe,0x9, 0x75,0x3e,0x8d,0xbc,0x67,0x68,0xb, +0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbd,0x38,0xe1,0x90,0x13,0x7f,0xe4,0x93, +0xbc,0xbd,0x28,0x74,0x7e,0x50,0x9, 0xac,0x5d,0x9, 0xc2,0x3f,0x41,0x49,0x42,0x3f, +0x3f,0x74,0x9, 0xac,0xbe,0x49,0xa5,0x3e,0x8b,0x7d,0x3a,0x9d,0x34,0xbe,0x34,0x0, +0x0, 0x8, 0x4, 0x9d,0xa4,0x80,0x4, 0x6d,0xaa,0x9d,0xa3,0x49,0x42,0x3f,0x3d,0x49, +0xb5,0x3e,0x89,0x7d,0x3b,0x9d,0x34,0xbe,0x34,0x0, 0x0, 0x8, 0x4, 0x9d,0xb4,0x80, +0x4, 0x6d,0xbb,0x9d,0xb3,0x2d,0xba,0x74,0x7, 0xac,0xbc,0x9, 0xb5,0x3f,0x97,0xb4, +0x1, 0xe, 0x6d,0xaa,0x74,0x2, 0xac,0xbc,0x59,0xa5,0x49,0xd3,0x59,0xa5,0x49,0xeb, +0x7d,0x3b,0x7c,0xbd,0x7c,0x5e,0x7c,0x4c,0x12,0x66,0x9e,0x7c,0xbd,0x12,0x65,0x4b, +0xb, 0xe0,0xbc,0xfe,0x28,0x2, 0x81,0xa8,0xda,0x3b,0x22,0x2, 0x65,0x4e,0xca,0x3b, +0x7c,0xd4,0x7c,0xe5,0x7c,0xfb,0x7d,0xf3,0x7e,0x17,0x3f,0xfb,0xbd,0x13,0x38,0x6, +0x7e,0xd4,0x1, 0x0, 0x80,0x17,0x6d,0x22,0x7c,0x56,0x7c,0x67,0x6c,0x77,0x12,0x14, +0xeb,0x7d,0xd3,0xbe,0xd4,0x0, 0x10,0x50,0x4, 0x7e,0xd4,0x0, 0x10,0x74,0x2, 0xac, +0xbd,0x49,0x45,0x49,0xeb,0xbd,0x4f,0x28,0x6, 0x49,0xd5,0x49,0xd3,0x80,0x4, 0x59, +0xd5,0x49,0xd3,0x59,0xf5,0x49,0xeb,0xbe,0xd4,0x1, 0x0, 0x28,0x4, 0x7e,0xd4,0x1, +0x0, 0x7e,0xb3,0x40,0x2, 0x60,0xb, 0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x2, 0x40,0x2, +0x1e,0xd4,0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x5, 0x28,0x2, 0x1e,0xd4,0xbe,0xd4,0x0, +0x20,0x50,0x11,0x7e,0x70,0x9, 0xac,0x7d,0x9, 0xb3,0x49,0x77,0xb4,0x1, 0x5, 0xe4, +0x19,0xb3,0x49,0x77,0xbe,0xd4,0x0, 0x40,0x28,0xc, 0x7e,0xa0,0x1, 0x7e,0x70,0x9, +0xac,0x7d,0x19,0xa3,0x49,0x77,0x7c,0xbe,0x7c,0x7d,0x12,0x92,0xb3,0x7d,0x13,0x7e, +0xb3,0x40,0x2, 0x60,0x2, 0x1e,0xd4,0x7e,0x70,0x9, 0xac,0x7f,0x49,0x3, 0x3f,0x3d, +0x7e,0xd0,0x9, 0xac,0xde,0x49,0x26,0x3e,0x89,0x7d,0xe2,0x9d,0xe0,0xbe,0xe4,0x0, +0x0, 0x8, 0x6, 0x7d,0xf2,0x9d,0xf0,0x80,0x4, 0x6d,0xff,0x9d,0xfe,0x12,0x66,0x8f, +0xbd,0x20,0x28,0xf, 0x7d,0xe3,0x2e,0xe4,0x3f,0x3d,0x7d,0xc0,0x2d,0xcf,0x1b,0xe8, +0xc0,0x80,0xf, 0x74,0x9, 0xac,0xbf,0x7d,0xe5,0x2e,0xe4,0x3f,0x3d,0x9d,0xf, 0x1b, +0xe8,0x0, 0x7e,0x50,0x9, 0xac,0x5f,0x49,0x32,0x3f,0x3f,0x7e,0xd0,0x9, 0xac,0xde, +0x49,0xe6,0x3e,0x8b,0x7d,0xe, 0x9d,0x3, 0xbe,0x4, 0x0, 0x0, 0x8, 0x6, 0x7d,0xfe, +0x9d,0xf3,0x80,0x4, 0x6d,0xff,0x9d,0xf0,0x12,0x66,0x8f,0xbd,0xe3,0x28,0xf, 0x7d, +0xe2,0x2e,0xe4,0x3f,0x3f,0x7d,0x23,0x2d,0x2f,0x1b,0xe8,0x20,0x80,0xe, 0x7e,0x50, +0x9, 0xac,0x5f,0x2e,0x24,0x3f,0x3f,0x9d,0x3f,0x1b,0x28,0x30,0xda,0x3b,0x22,0x7d, +0x5d,0xad,0x5f,0x7c,0xba,0x7c,0xa9,0xa, 0x48,0x7d,0xf5,0x5d,0xf1,0x22,0xca,0x3b, +0x7c,0xab,0x7d,0x3, 0x7e,0x20,0x10,0x7d,0x30,0x7e,0x90,0x9, 0xac,0x95,0x9, 0x34, +0x3e,0x8f,0xbe,0x30,0x10,0x28,0x2, 0x7c,0x23,0xbe,0x20,0x20,0x28,0x3, 0x7e,0x20, +0x20,0x49,0xe4,0x3e,0x89,0xbe,0xe4,0x6, 0x50,0x40,0x20,0x7e,0x33,0x40,0x11,0x12, +0x67,0x9a,0xbd,0xef,0x38,0x15,0x49,0xe4,0x3e,0x8b,0xbe,0xe4,0x6, 0x50,0x40,0xb, +0x7e,0x33,0x40,0x12,0x12,0x67,0x9a,0xbd,0xef,0x28,0x3, 0x7e,0x20,0x8, 0x7e,0xf0, +0x10,0xac,0xf2,0xbd,0x70,0x40,0x5d,0x7e,0xf0,0x9, 0xac,0xf4,0x9, 0xb7,0x49,0x77, +0x70,0x52,0x7e,0xd0,0x8, 0xac,0xd2,0xbd,0x60,0x50,0x3c,0x9, 0xb7,0x49,0x70,0x70, +0x1f,0x9, 0xb7,0x49,0x71,0xbe,0xb0,0x0, 0x28,0xc, 0x7d,0x37,0x2e,0x34,0x49,0x71, +0x14,0x7a,0x39,0xb0,0x80,0x6, 0x74,0x1, 0x19,0xb7,0x49,0x70,0x6d,0x33,0x80,0x34, +0x9, 0xb7,0x49,0x71,0xbe,0xb0,0x14,0x50,0x2b,0x7d,0x37,0x2e,0x34,0x49,0x71,0x4, +0x7a,0x39,0xb0,0x6d,0x33,0x80,0x1d,0xe4,0x19,0xb7,0x49,0x71,0x19,0xb7,0x49,0x70, +0x6d,0x33,0x80,0x10,0x6c,0x33,0x7e,0xf0,0x9, 0xac,0xf4,0x19,0x37,0x49,0x71,0xe4, +0x19,0xb7,0x49,0x70,0x7e,0x30,0x8, 0xac,0x23,0xbd,0x10,0x40,0x2a,0x7e,0x70,0x9, +0xac,0x7a,0x49,0x33,0x3f,0x3d,0x59,0x34,0x3e,0x89,0x74,0x9, 0xa4,0x49,0x35,0x3f, +0x3f,0x74,0x9, 0xac,0xb5,0x59,0x35,0x3e,0x8b,0x7e,0xa0,0x1, 0x7e,0x70,0x9, 0xac, +0x74,0x19,0xa3,0x49,0x6f,0x6d,0x33,0xda,0x3b,0x22,0x7e,0xf0,0x40,0xac,0xf3,0x7d, +0xf7,0x9e,0xf4,0x0, 0x65,0x3e,0xf4,0x3e,0xf4,0x3e,0xf4,0x3e,0xf4,0x22,0x90,0x13, +0x7f,0xe4,0x93,0xbc,0xb9,0x22,0x2e,0x34,0x3e,0x89,0x7e,0x30,0x9, 0x22,0x7e,0xb3, +0x4b,0xa1,0x4, 0x7a,0xb3,0x4b,0xa1,0x7e,0x73,0x4b,0xa1,0x7a,0x73,0x4d,0x88,0x22, +0xe4,0x7a,0xb3,0x4d,0xeb,0x90,0xe, 0x73,0x93,0x7a,0xb3,0x4d,0xed,0x90,0xe, 0x74, +0xe4,0x93,0x7a,0xb3,0x4d,0xee,0x90,0x13,0x7f,0xe4,0x93,0x7a,0xb3,0x4d,0xf0,0xe4, +0x7a,0xb3,0x4d,0xf1,0x74,0x1, 0x7a,0xb3,0x4d,0xf6,0x12,0x3d,0xcb,0xe4,0x7a,0xb3, +0x4d,0xf9,0x7e,0x73,0x4c,0x71,0x7a,0x73,0x4e,0xb, 0x7e,0x73,0x4c,0x72,0x7a,0x73, +0x4e,0xc, 0x7e,0x73,0x4c,0x73,0x7a,0x73,0x4e,0xd, 0x7e,0x73,0x4c,0x40,0x7a,0x73, +0x4e,0x14,0x7e,0x73,0x4c,0x41,0x7a,0x73,0x4e,0x15,0x90,0xe, 0x77,0x93,0x7a,0xb3, +0x4e,0x9, 0x90,0xe, 0x78,0xe4,0x93,0x7a,0xb3,0x4e,0xa, 0x74,0x1, 0x7a,0xb3,0x4e, +0x1b,0x7e,0x34,0x14,0x60,0x12,0x1d,0xf2,0x7a,0x37,0x4e,0x45,0x74,0x2, 0x7a,0xb3, +0x4d,0xf4,0x74,0x17,0x7a,0xb3,0x4e,0x18,0x22,0x7e,0x18,0x15,0xa0,0x7a,0x1f,0x22, +0xdc,0x7e,0x18,0x4, 0x0, 0x7a,0x1f,0x22,0xe0,0x7e,0xf, 0x22,0xdc,0x12,0x68,0x80, +0x7e,0xf, 0x22,0xe0,0x7e,0x34,0x4, 0x68,0x12,0x16,0x5a,0x7a,0xb3,0x24,0x26,0x22, +0x7e,0x34,0x4, 0x68,0xe4,0x2, 0x16,0x5a,0xca,0x3b,0xf5,0x2f,0x7f,0x31,0x7a,0xd, +0x2b,0x7e,0x18,0xc, 0xd0,0x7a,0x1d,0x32,0x12,0x1c,0x24,0x7e,0xd, 0x2b,0x12,0x68, +0x80,0x30,0x1, 0xc, 0x7e,0x18,0x11,0x38,0x7a,0x1d,0x36,0x7f,0x3, 0x12,0x68,0x80, +0xe4,0x68,0x3, 0x12,0x1c,0x24,0xd2,0x2, 0x12,0x45,0xf2,0x30,0x1, 0x29,0x6d,0x33, +0x80,0x1d,0x12,0x69,0x23,0x7e,0xd, 0x36,0x2d,0x12,0xb, 0xa, 0x50,0x7d,0x23,0x3e, +0x24,0x7f,0x3, 0x2d,0x12,0xb, 0xa, 0x20,0x2d,0x25,0x1b,0xa, 0x20,0xb, 0x34,0x7a, +0x35,0x30,0x12,0x69,0x2b,0x38,0xdb,0x6d,0x33,0x80,0x1f,0x12,0x69,0x23,0x7e,0xd, +0x32,0x2d,0x12,0xb, 0xa, 0x20,0x3e,0x34,0x7e,0xd, 0x2b,0x2d,0x13,0xb, 0xa, 0x30, +0x2d,0x32,0x1b,0xa, 0x30,0x7e,0x35,0x30,0xb, 0x34,0x7a,0x35,0x30,0x12,0x69,0x2b, +0x38,0xd9,0x7e,0xd, 0x2b,0x12,0x4e,0xac,0x30,0x1, 0x5, 0x7f,0x3, 0x12,0x4e,0xac, +0xda,0x3b,0x22,0x7e,0x35,0x30,0x7d,0x23,0x3e,0x24,0x22,0x7e,0x37,0x44,0x81,0xb, +0x36,0xbe,0x35,0x30,0x22,0xca,0xf8,0xc2,0x0, 0x7e,0xf3,0x4f,0x55,0x20,0xe, 0x6, +0x20,0xf, 0x3, 0x30,0x10,0x3, 0xc3,0x80,0x71,0x7e,0x24,0x0, 0x1, 0x7c,0xbf,0x60, +0x5, 0x3e,0x24,0x14,0x78,0xfb,0x7e,0x73,0x44,0x80,0x6c,0x66,0x5c,0x75,0x4d,0x33, +0x68,0x57,0x7c,0xbf,0x12,0x6b,0x73,0x50,0x2, 0xd2,0x0, 0xd2,0x2, 0x12,0x45,0xf2, +0xe4,0x7c,0x7f,0x12,0x71,0xda,0xa2,0x0, 0x92,0x1, 0x7e,0xf, 0x22,0xdc,0x7e,0x18, +0x1a,0x8, 0x7c,0xbf,0x12,0x68,0x88,0x20,0xe, 0x6, 0x20,0xf, 0x3, 0x30,0x10,0x3, +0xc3,0x80,0x27,0x12,0x1c,0x24,0x12,0x6a,0x82,0x60,0x5, 0x3e,0x34,0x14,0x78,0xfb, +0x6e,0x70,0xff,0x5e,0x73,0x44,0x80,0x7a,0x73,0x44,0x80,0x12,0x4f,0x55,0x12,0x69, +0xbd,0x7c,0xbf,0x12,0x6a,0xf9,0xd3,0x80,0x1, 0xd3,0xda,0xf8,0x22,0x7e,0x73,0x4d, +0x83,0x7e,0xb3,0x4d,0x9e,0x70,0x3a,0xe5,0x13,0x70,0x1d,0x7e,0x63,0x4d,0x81,0xbe, +0x60,0x14,0x28,0x5, 0x7e,0x60,0x14,0x80,0x7, 0xa5,0xbe,0x0, 0x3, 0x7e,0x60,0x1, +0xa, 0x26,0x7e,0x34,0x0, 0x64,0x80,0x74,0xe5,0x13,0xb4,0x3, 0x2, 0x80,0x44,0x12, +0x6a,0x7b,0xb4,0x1, 0x6, 0x7e,0x34,0x1, 0xf4,0x80,0x61,0x7e,0x34,0x3, 0xe8,0x80, +0x5b,0xe5,0x13,0x70,0xe, 0x7e,0x63,0x4d,0x82,0xbe,0x60,0x7f,0x28,0x53,0x7e,0x60, +0x7f,0x80,0x4e,0x7e,0x63,0x4f,0x99,0xbe,0x60,0x3b,0x40,0x12,0x12,0x6a,0x7b,0xb4, +0x1, 0x6, 0x7e,0x34,0x1, 0xf4,0x80,0x26,0x7e,0x34,0x3, 0xe8,0x80,0x20,0xe5,0x13, +0xb4,0x3, 0x8, 0x7e,0x73,0x4d,0xb8,0xa, 0x37,0x80,0x15,0x30,0x1b,0x18,0x12,0x6a, +0x7b,0xb4,0x1, 0x6, 0x7e,0x34,0x1, 0xf4,0x80,0x4, 0x7e,0x34,0x3, 0xe8,0x8d,0x32, +0x1b,0x34,0x7c,0x67,0x80,0xb, 0xa, 0x27,0x7e,0x34,0x3, 0xe8,0x12,0x14,0x9f,0x7c, +0x67,0x7e,0x73,0x4d,0xa5,0xac,0x67,0x7e,0x24,0x0, 0x18,0x12,0x14,0x9f,0x7a,0x73, +0x4f,0x48,0xc2,0x16,0x6d,0x33,0x7a,0x37,0x4f,0x44,0x22,0x7e,0xb3,0x4f,0x4d,0xa, +0x27,0x22,0x7e,0x34,0x0, 0x1, 0x7c,0xbf,0x22,0xca,0xf8,0x7e,0xf3,0x4f,0x55,0x20, +0xe, 0x6, 0x20,0xf, 0x3, 0x30,0x10,0x3, 0xc3,0x80,0x5b,0x12,0x6a,0x82,0x60,0x5, +0x3e,0x34,0x14,0x78,0xfb,0x7e,0x53,0x44,0x7f,0x6c,0x44,0x5c,0x57,0x4d,0x22,0x68, +0x44,0x7e,0xb3,0x4e,0x19,0x70,0x8, 0x4e,0x73,0x44,0x80,0x7a,0x73,0x44,0x80,0xd2, +0x2, 0x12,0x45,0xf2,0x7c,0xbf,0x12,0x4b,0x75,0x40,0x3, 0xc3,0x80,0x28,0x20,0xe, +0x6, 0x20,0xf, 0x3, 0x30,0x10,0x3, 0xc3,0x80,0x1c,0x12,0x6a,0x82,0x60,0x5, 0x3e, +0x34,0x14,0x78,0xfb,0x6e,0x70,0xff,0x5e,0x73,0x44,0x7f,0x7a,0x73,0x44,0x7f,0x12, +0x69,0xbd,0xd3,0x80,0x1, 0xd3,0xda,0xf8,0x22,0xc2,0x1, 0x12,0x6b,0x73,0x50,0x2, +0xd2,0x1, 0x7e,0x37,0x44,0x81,0x6c,0xaa,0x90,0xe, 0x77,0xe4,0x93,0x20,0xe0,0x4, +0x4c,0xaa,0x68,0x57,0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x5, 0xbe,0xa0,0x1, 0x68,0x4b, +0x90,0xe, 0x78,0xe4,0x93,0x20,0xe0,0x5, 0xbe,0xa0,0x2, 0x68,0x3e,0x1e,0xb0,0x1e, +0xb0,0x20,0xe0,0x5, 0xbe,0xa0,0x3, 0x68,0x32,0x30,0x1, 0x1c,0xa, 0x2a,0x2d,0x23, +0x3e,0x24,0x49,0x12,0x15,0xa0,0xbe,0x14,0xb, 0xb8,0x40,0x1c,0x49,0x22,0x1a,0x8, +0xbe,0x24,0xb, 0xb8,0x50,0x15,0x80,0x10,0xa, 0x2a,0x2d,0x23,0x3e,0x24,0x49,0x22, +0x15,0xa0,0xbe,0x24,0xb, 0xb8,0x50,0x3, 0x2, 0x6b,0x8f,0xb, 0xa0,0xbe,0xa0,0x4, +0x40,0x96,0x22,0x7c,0xab,0xd2,0x2, 0x7e,0xb3,0x4f,0x4d,0x70,0x4, 0xc2,0x2, 0x80, +0xb, 0x4c,0xaa,0x68,0x5, 0xbe,0xa0,0x3, 0x78,0x2, 0xc2,0x2, 0xa2,0x2, 0x22,0x74, +0x1f,0x7a,0xb3,0x44,0x7f,0x22,0x7e,0x37,0x44,0x81,0x6c,0xaa,0x90,0xe, 0x77,0xe4, +0x93,0x20,0xe0,0x4, 0x4c,0xaa,0x68,0x25,0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x5, 0xbe, +0xa0,0x1, 0x68,0x19,0x90,0xe, 0x78,0xe4,0x93,0x20,0xe0,0x5, 0xbe,0xa0,0x2, 0x68, +0xc, 0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x9, 0xbe,0xa0,0x3, 0x78,0x4, 0xb, 0x34,0x80, +0x22,0x7d,0x23,0x3e,0x24,0x49,0x42,0x8, 0x68,0x12,0x6b,0xfb,0x2d,0x24,0x1b,0xa, +0x20,0x7d,0x23,0x3e,0x24,0x12,0x6b,0xfb,0xbe,0x24,0xf, 0xa0,0x50,0x3, 0x12,0x6b, +0x8f,0xb, 0x34,0xb, 0xa0,0xbe,0xa0,0x4, 0x40,0xa2,0x22,0x7e,0xf, 0x22,0xdc,0x2d, +0x12,0xb, 0xa, 0x20,0x22,0xca,0xf8,0x12,0x6e,0x85,0x12,0x6c,0x8a,0x12,0x6c,0x78, +0x40,0x5, 0xe4,0x7a,0xb3,0x3e,0x82,0x7e,0xb3,0x3e,0x82,0x60,0xb, 0xe4,0x7a,0xb3, +0x4f,0x84,0x74,0x1f,0x7a,0xb3,0x44,0x80,0x12,0x6c,0x78,0x40,0x6, 0x12,0x76,0xad, +0x12,0xac,0x2a,0x7e,0xb3,0x3e,0x85,0x60,0x6, 0x74,0x2, 0x7a,0xb3,0x4f,0x8b,0x7e, +0xf3,0x4f,0x8b,0xbe,0xf0,0x0, 0x28,0x23,0xe5,0x13,0xb4,0x1, 0x14,0x7e,0xb3,0x4d, +0x9e,0xb4,0x1, 0xd, 0x7e,0xb3,0x4f,0x99,0xbe,0xb0,0x3c,0x68,0x4, 0x70,0xc, 0x80, +0x0, 0x7c,0xbf,0x14,0x7a,0xb3,0x4f,0x8b,0x12,0x6b,0x96,0x7e,0xb3,0x3e,0x88,0x60, +0x4, 0xe4,0x12,0x73,0xab,0xda,0xf8,0x22,0xe5,0x13,0x70,0xc, 0x7e,0x73,0x4f,0x54, +0xbe,0x73,0x4f,0x5a,0x40,0x2, 0xc3,0x22,0xd3,0x22,0x12,0x93,0xb2,0x12,0x94,0x82, +0x12,0x6d,0xc9,0x2, 0x6c,0x96,0x7e,0xb3,0x3e,0x82,0xb4,0x1, 0x18,0x12,0x6d,0xbf, +0xbe,0x73,0x4f,0x84,0x28,0xc, 0xe4,0x7a,0xb3,0x3e,0x82,0x7e,0xb3,0x4f,0x84,0x4, +0x80,0x4, 0xe4,0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x84,0x7e,0xb3,0x3e,0x82,0x70,0x53, +0x12,0x6d,0xb8,0x78,0x15,0x7e,0xb3,0x3e,0x83,0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x86, +0x4, 0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x86,0x80,0x18,0xbe,0xa0,0x1, 0x78,0x13,0x7e, +0xb3,0x3e,0x84,0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x87,0x4, 0x80,0x1, 0xe4,0x7a,0xb3, +0x4f,0x87,0x7e,0x73,0x4f,0x86,0xbe,0x70,0x3, 0x50,0x9, 0x7e,0x73,0x4f,0x87,0xbe, +0x70,0x3, 0x40,0xf, 0x74,0x1, 0x7a,0xb3,0x3e,0x82,0xe4,0x7a,0xb3,0x4f,0x86,0x7a, +0xb3,0x4f,0x87,0x7e,0xb3,0x3e,0x85,0xb4,0x1, 0x18,0x12,0x6d,0xbf,0xbe,0x73,0x4f, +0x85,0x28,0xc, 0xe4,0x7a,0xb3,0x3e,0x85,0x7e,0xb3,0x4f,0x85,0x4, 0x80,0x4, 0xe4, +0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x85,0x7e,0xb3,0x3e,0x85,0x70,0x53,0x12,0x6d,0xb8, +0x78,0x15,0x7e,0xb3,0x3e,0x86,0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x88,0x4, 0x80,0x1, +0xe4,0x7a,0xb3,0x4f,0x88,0x80,0x18,0xbe,0xa0,0x1, 0x78,0x13,0x7e,0xb3,0x3e,0x87, +0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x89,0x4, 0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x89,0x7e, +0x73,0x4f,0x88,0xbe,0x70,0x3, 0x50,0x9, 0x7e,0x73,0x4f,0x89,0xbe,0x70,0x3, 0x40, +0xf, 0x74,0x1, 0x7a,0xb3,0x3e,0x85,0xe4,0x7a,0xb3,0x4f,0x88,0x7a,0xb3,0x4f,0x89, +0x7e,0xb3,0x3e,0x88,0xb4,0x1, 0x1a,0x7e,0x73,0x3e,0x72,0xbe,0x73,0x4f,0x8a,0x28, +0xc, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x4f,0x8a,0x4, 0x80,0x6, 0x74,0x1, 0x80, +0x2, 0x74,0x1, 0x7a,0xb3,0x4f,0x8a,0x22,0x7e,0xa3,0x24,0x27,0x4c,0xaa,0x22,0xe4, +0x7a,0xb3,0x3e,0x88,0x7e,0x73,0x3e,0x73,0x22,0x7e,0x47,0x3e,0x5d,0x7e,0x7, 0x3f, +0xef,0x7e,0x34,0x0, 0x6, 0xad,0x30,0x7e,0x14,0x0, 0x4, 0x12,0x6e,0x7d,0x8, 0x5, +0x7e,0xa0,0x4, 0x80,0x1d,0x7d,0x30,0x3e,0x34,0x12,0x6e,0x7b,0x8, 0x5, 0x7e,0xa0, +0x3, 0x80,0xf, 0x7d,0x30,0x12,0x6e,0x7b,0x8, 0x5, 0x7e,0xa0,0x2, 0x80,0x3, 0x7e, +0xa0,0x1, 0x7e,0xb3,0x3e,0x7f,0x60,0x3, 0x7e,0xa0,0x4, 0xa, 0x2a,0x7e,0x14,0x14, +0x37,0x7e,0x4, 0x0, 0xff,0xb, 0xa, 0x30,0xad,0x32,0x12,0x70,0xe6,0x7e,0xb3,0x3e, +0x53,0xbe,0xb0,0x0, 0x28,0x28,0x7e,0xb3,0x3e,0x74,0x70,0x22,0x7e,0x37,0x3e,0x70, +0xbe,0x34,0x0, 0x2, 0x48,0x9, 0x12,0x6f,0xf0,0x7a,0x37,0x3e,0x70,0x80,0xf, 0x7e, +0x63,0x3e,0x72,0x7e,0x70,0x2, 0xac,0x67,0x7c,0xb7,0x7a,0xb3,0x3e,0x72,0x7e,0xb3, +0x4d,0x9e,0xb4,0x1, 0xe, 0x7e,0x27,0x3e,0x70,0x7e,0x34,0x0, 0x5, 0xad,0x32,0x7a, +0x37,0x3e,0x70,0x7e,0xb3,0x4e,0x49,0xbe,0xb0,0x0, 0x28,0xe, 0x7e,0x34,0x0, 0x1, +0x7a,0x37,0x3e,0x70,0x74,0x1, 0x7a,0xb3,0x3e,0x72,0x22,0x3e,0x34,0x7d,0x21,0x12, +0x14,0x9f,0xbd,0x34,0x22,0x12,0x99,0x43,0x12,0x6e,0xb5,0x12,0x9c,0x5c,0x2, 0x6e, +0x91,0x7e,0x27,0x44,0x81,0x1e,0x24,0x1e,0x24,0xe4,0x7a,0xb3,0x3e,0x7f,0x7e,0x37, +0x3e,0x55,0xbd,0x32,0x38,0x8, 0x7e,0x37,0x3e,0x57,0xbd,0x32,0x28,0x6, 0x74,0x1, +0x7a,0xb3,0x3e,0x7f,0x22,0xe4,0x7a,0xb3,0x3e,0x75,0x7a,0xb3,0x3e,0x78,0x7a,0xb3, +0x3e,0x76,0x7a,0xb3,0x3e,0x77,0x7a,0xb3,0x3e,0x79,0x7a,0xb3,0x3e,0x7a,0x7e,0x73, +0x3e,0x54,0xbe,0x70,0x0, 0x28,0x35,0x12,0xac,0xe0,0x12,0x14,0x9f,0xbe,0x37,0x3e, +0x5d,0x8, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x75,0x7e,0x7, 0x3f,0xf5,0x7d,0x30,0x12, +0x6f,0xe4,0x8, 0x3, 0x12,0x6f,0xdd,0x7d,0x30,0x3e,0x34,0x3e,0x34,0x7d,0x21,0x12, +0x6f,0xe8,0x8, 0x8, 0xd2,0x2d,0x6d,0x33,0x7a,0x37,0x4d,0x75,0x7e,0x37,0x3e,0x63, +0xbe,0x34,0x1, 0xf4,0x8, 0x2d,0x30,0x23,0x2a,0x30,0x2d,0x1b,0x12,0x6f,0xdd,0x7e, +0x37,0x4d,0x75,0xb, 0x34,0x7a,0x37,0x4d,0x75,0xbe,0x34,0x0, 0x5, 0x28,0x8, 0xc2, +0x2d,0x6d,0x33,0x7a,0x37,0x4d,0x75,0x12,0x76,0xbd,0xbe,0x34,0x0, 0x64,0x28,0x3, +0x12,0x6f,0xdd,0x7e,0xa3,0x3e,0x54,0xbe,0xa0,0x0, 0x28,0x49,0x12,0xac,0xe0,0x12, +0x14,0x9f,0xbe,0x37,0x3e,0x5d,0x8, 0x1a,0x7e,0x73,0x24,0x27,0xa5,0xbf,0x0, 0x8, +0x74,0x1, 0x7a,0xb3,0x3e,0x76,0x80,0xa, 0xa5,0xbf,0x1, 0x6, 0x74,0x1, 0x7a,0xb3, +0x3e,0x77,0x7e,0x37,0x3f,0xf5,0x12,0x6f,0xe4,0x8, 0x1a,0x7e,0x73,0x24,0x27,0xa5, +0xbf,0x0, 0x8, 0x74,0x1, 0x7a,0xb3,0x3e,0x79,0x80,0xa, 0xa5,0xbf,0x1, 0x6, 0x74, +0x1, 0x7a,0xb3,0x3e,0x7a,0x7e,0xb3,0x3e,0x75,0xbe,0xb0,0x1, 0x68,0x10,0x7e,0xb3, +0x3e,0x76,0xbe,0xb0,0x1, 0x68,0x7, 0x7e,0xb3,0x3e,0x77,0xb4,0x1, 0x29,0xbe,0xa0, +0x0, 0x28,0x24,0xbe,0xa0,0x3, 0x50,0x1f,0x7e,0xb3,0x3e,0x53,0xb4,0x1, 0x18,0x90, +0x14,0x28,0xe4,0x93,0xbe,0xb3,0x3c,0xc9,0x68,0xd, 0xe4,0x7a,0xb3,0x3e,0x75,0x7a, +0xb3,0x3e,0x76,0x7a,0xb3,0x3e,0x77,0xe4,0x7a,0xb3,0x3e,0x7b,0x22,0x74,0x1, 0x7a, +0xb3,0x3e,0x78,0x22,0xad,0x31,0x7d,0x24,0x12,0x14,0x9f,0xbe,0x37,0x3e,0x63,0x22, +0x7e,0x24,0x0, 0x2, 0x2, 0x14,0x9f,0x7e,0x34,0x4, 0x71,0xca,0x39,0x7e,0x34,0xe, +0x71,0x7e,0x24,0x0, 0xff,0x7e,0x8, 0x40,0xd, 0x12,0x16,0x35,0x1b,0xfd,0x7e,0x37, +0x40,0x17,0x2e,0x37,0x40,0x15,0x7a,0x37,0x44,0x81,0x90,0xe, 0x77,0xe4,0x93,0xca, +0xb8,0x90,0xe, 0x78,0xe4,0x93,0x7c,0x7b,0xda,0xb8,0x12,0x70,0x4a,0x90,0x14,0x7, +0xe4,0x93,0x70,0x6, 0x7e,0x63,0x40,0x10,0x80,0x4, 0x7e,0x63,0x40,0xf, 0x7e,0x70, +0x40,0xac,0x67,0x1b,0x34,0x7a,0x37,0x44,0x83,0x22,0x7c,0x6b,0x7c,0x56,0x5e,0x50, +0x4, 0x1e,0x50,0xa, 0x45,0x7c,0xb6,0x54,0x1, 0xa, 0x5b,0x2d,0x54,0x7c,0xab,0x7c, +0x67,0x5e,0x60,0x4, 0x1e,0x60,0xa, 0x26,0x7c,0xb7,0x54,0x1, 0xa, 0x3b,0x2d,0x32, +0x7c,0xb7,0xa, 0x4b,0x3e,0x44,0x3e,0x44,0xa, 0x5a,0x2d,0x54,0x7c,0xab,0x7a,0xa3, +0x44,0x85,0xe4,0x7a,0xb3,0x44,0x86,0x7e,0x70,0x4, 0x7c,0xba,0x30,0xe0,0x9, 0x7e, +0xb3,0x44,0x86,0x4, 0x7a,0xb3,0x44,0x86,0x1e,0xa0,0x1b,0x70,0x78,0xec,0x22,0x7e, +0xb3,0x40,0x13,0x7e,0x73,0x40,0x14,0x12,0x70,0x4a,0x7e,0xb3,0x40,0x13,0x7e,0x73, +0x40,0x14,0x22,0x7e,0x34,0x14,0x33,0x12,0x1d,0xf2,0x7a,0x37,0x3e,0x6c,0x7e,0x34, +0x14,0x35,0x12,0x1d,0xf2,0x7a,0x37,0x3e,0x6e,0x7e,0x34,0x14,0x37,0x12,0x1d,0xf2, +0x12,0x70,0xe6,0x90,0x14,0x3a,0xe4,0x93,0x7a,0xb3,0x3e,0x73,0xe4,0x7a,0xb3,0x3e, +0x7c,0x7a,0xb3,0x3e,0x7d,0x22,0x7a,0x37,0x3e,0x70,0x90,0x14,0x39,0xe4,0x93,0x7a, +0xb3,0x3e,0x72,0x22,0xca,0xf8,0x6c,0xff,0x12,0x71,0xb, 0xb, 0xf0,0x7e,0x73,0x3, +0xda,0xbc,0x7f,0x38,0xf3,0x12,0x71,0xd2,0xda,0xf8,0x22,0xca,0xd8,0xca,0x79,0xd2, +0x0, 0x12,0x37,0xb3,0x50,0xfb,0x7e,0xe3,0x3, 0xd9,0x7a,0xe3,0x24,0x27,0x7e,0xd3, +0x3, 0xda,0xa, 0x3e,0x9, 0xb3,0x3, 0xd3,0x60,0x31,0xa, 0x3b,0x1b,0x34,0x7c,0xa7, +0x7a,0xa3,0x4e,0x16,0xb4,0x1, 0x4, 0x74,0x1, 0x80,0x1, 0xe4,0x7a,0xb3,0x24,0x26, +0xe4,0xa, 0x3e,0x19,0xb3,0x3, 0xd3,0x9, 0xf3,0x3, 0xd5,0x7c,0xbe,0x7c,0x7f,0x12, +0x71,0xda,0x7e,0xb3,0x3, 0xd9,0x4, 0x7a,0xb3,0x3, 0xd9,0x7e,0x73,0x3, 0xda,0xbe, +0x73,0x3, 0xd9,0x38,0x6, 0x12,0x1c,0x76,0x12,0xa7,0xe7,0x7e,0xb3,0x24,0x26,0xbe, +0xb0,0x1, 0x68,0x7, 0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x38,0x74,0xa, 0xac,0xbf,0x49, +0x35,0x4c,0x48,0x7e,0xf, 0x22,0xd8,0x12,0x4e,0xb6,0x7c,0xbe,0x7c,0x7f,0x12,0x77, +0x51,0x92,0x0, 0x7e,0xb3,0x4f,0x4d,0x70,0xc, 0xbe,0xe0,0x1, 0x40,0x7, 0xe4,0x7a, +0xb3,0x24,0x26,0xc2,0x0, 0x30,0x0, 0xb, 0x12,0x72,0x78,0x7a,0xe3,0x4e,0x17,0x7a, +0xf3,0x4f,0x59,0x7e,0xb3,0x4f,0x6e,0xb4,0x1, 0x3, 0x12,0x72,0xb, 0x7c,0xbd,0x14, +0xbc,0xbe,0x78,0x3, 0x12,0xb, 0xe5,0x12,0x76,0x9e,0x12,0x6c,0x78,0xda,0x79,0xda, +0xd8,0x22,0x7e,0xb3,0x4e,0x17,0x7e,0x73,0x4f,0x59,0x14,0x68,0x1d,0x4, 0x78,0x1a, +0x7e,0x8, 0xc, 0xd0,0x7a,0xf, 0x22,0xd8,0x7e,0x8, 0x15,0xa0,0x7a,0xf, 0x22,0xdc, +0xa5,0xbf,0x3, 0x16,0x7e,0x18,0x1e,0x70,0x80,0xc, 0x7e,0x18,0x11,0x38,0x7a,0x1f, +0x22,0xd8,0x7e,0x18,0x1a,0x8, 0x7a,0x1f,0x22,0xdc,0x22,0x6d,0x22,0x7d,0x32,0x7d, +0x52,0x3e,0x54,0x7e,0xf, 0x22,0xd8,0x12,0x72,0x6c,0x28,0x2, 0xb, 0x34,0xb, 0x24, +0xbe,0x24,0x0, 0x14,0x78,0xe9,0xbe,0x34,0x0, 0x5, 0x38,0x6, 0xe4,0x7a,0xb3,0x4e, +0x97,0x22,0x7e,0x24,0x0, 0x14,0x80,0xd, 0x7d,0x52,0x3e,0x54,0x12,0x72,0x6c,0x28, +0x2, 0xb, 0x34,0xb, 0x24,0x7e,0x57,0x44,0x81,0xbd,0x52,0x38,0xeb,0xbe,0x34,0x0, +0xb4,0x28,0x7, 0x7e,0xb3,0x4e,0x97,0x4, 0x80,0x1, 0xe4,0x7a,0xb3,0x4e,0x97,0x7e, +0x73,0x4e,0x97,0xbe,0x70,0x4, 0x40,0x3, 0x75,0xe9,0xff,0x22,0x2d,0x51,0x7d,0x40, +0xb, 0x2a,0x50,0xbe,0x54,0x3e,0x80,0x22,0xca,0xf8,0x7e,0xb3,0x44,0x7e,0x70,0xd, +0x7e,0xf, 0x22,0xe0,0x7e,0x1f,0x22,0xd8,0x12,0x73,0xc, 0x80,0x14,0x7e,0x1f,0x22, +0xdc,0x7a,0x1d,0x27,0x7e,0xf, 0x22,0xe0,0x7e,0x1f,0x22,0xd8,0x74,0x1, 0x12,0x73, +0x20,0x7e,0x37,0x44,0x81,0x90,0xe, 0x59,0xe4,0x93,0x70,0x13,0x6c,0xff,0x6d,0x22, +0x7d,0x53,0x12,0x72,0xf9,0x1b,0xa, 0x20,0x12,0x72,0xf1,0x78,0xf1,0x80,0x2f,0x6c, +0xff,0x7e,0xb3,0x44,0x7e,0xb4,0x1, 0x14,0x7d,0x53,0x3e,0x54,0x7e,0xf, 0x22,0xdc, +0x2d,0x15,0xb, 0xa, 0x40,0x12,0x73,0x2, 0x9d,0x24,0x80,0x7, 0x7d,0x53,0x3e,0x54, +0x12,0x73,0x2, 0x12,0x72,0xfb,0x1b,0xa, 0x20,0x12,0x72,0xf1,0x78,0xd3,0xda,0xf8, +0x22,0xb, 0x34,0xb, 0xf0,0xbe,0xf0,0x4, 0x22,0x3e,0x54,0x7e,0xf, 0x22,0xe0,0x2d, +0x15,0x22,0x7e,0xf, 0x22,0xd8,0x2d,0x15,0xb, 0xa, 0x20,0x22,0x12,0x73,0x7b,0x7a, +0x37,0x44,0x8b,0x12,0x73,0x74,0x7e,0x34,0x0, 0x20,0x12,0x73,0x50,0x2, 0x8, 0xe5, +0x7c,0xab,0x7f,0x61,0x7f,0x70,0x12,0x73,0xa2,0xe4,0x12,0x16,0x5a,0x7e,0xb3,0x40, +0x10,0x7a,0xb3,0x44,0x88,0x7e,0xb3,0x40,0xf, 0x7a,0xb3,0x44,0x87,0xe4,0x12,0x73, +0x9b,0x12,0x73,0x69,0x7a,0xa3,0x44,0x8a,0x6d,0x33,0x12,0x73,0x50,0x2, 0x8, 0xe5, +0x7a,0x37,0x44,0x91,0x7e,0x8, 0x44,0x87,0x22,0x12,0x73,0x7b,0x12,0x73,0x69,0x7e, +0x34,0x0, 0x10,0x12,0x73,0x50,0x2, 0x8, 0xe5,0x7a,0x37,0x44,0x8b,0x7e,0x1d,0x27, +0x7a,0x37,0x44,0x8d,0x7d,0x3f,0x7a,0x37,0x44,0x8f,0x22,0x7f,0x61,0x7f,0x70,0x7e, +0x8, 0x44,0x87,0x7e,0x34,0x0, 0xc, 0xe4,0x12,0x16,0x5a,0x7e,0x73,0x40,0x10,0x7a, +0x73,0x44,0x88,0x7e,0x73,0x40,0xf, 0x7a,0x73,0x44,0x87,0x7a,0xb3,0x44,0x89,0x7d, +0x3d,0x22,0x7e,0x8, 0x44,0x87,0x7e,0x34,0x0, 0xc, 0x22,0xca,0x3b,0x7c,0xcb,0x12, +0x73,0xa2,0xe4,0x12,0x16,0x5a,0x7e,0x8, 0x44,0x93,0x7e,0x34,0x0, 0x5, 0x12,0x16, +0x5a,0x7e,0xe3,0x40,0xf, 0x7e,0xd3,0x40,0x10,0x7e,0xb7,0x44,0x81,0x7e,0x97,0x3e, +0x70,0x7d,0xa9,0x3e,0xa4,0x3e,0xa4,0x4c,0xcc,0x78,0x6c,0x7a,0xd3,0x44,0x88,0x7a, +0xe3,0x44,0x87,0x7e,0x84,0x8, 0x68,0x7a,0x87,0x44,0x8b,0x7e,0x1f,0x22,0xdc,0x7d, +0x83,0x7a,0x87,0x44,0x8d,0x7e,0x1f,0x22,0xdc,0x7d,0x83,0x7a,0x87,0x44,0x8f,0x7d, +0x39,0x7c,0xb7,0xf5,0x27,0x7e,0x8, 0x44,0x87,0x7e,0x18,0x44,0x93,0x7d,0x59,0x12, +0x0, 0x46,0x6c,0xff,0x7d,0x3b,0x3e,0x34,0x49,0x83,0x8, 0x68,0xbd,0xa8,0x58,0x10, +0x7e,0xf, 0x22,0xdc,0x2d,0x13,0xb, 0xa, 0x20,0x2d,0x2a,0x1b,0xa, 0x20,0x80,0x10, +0x6d,0x22,0x9d,0x2a,0xbd,0x28,0x8, 0x8, 0x12,0x74,0x96,0x9d,0x3a,0x1b,0xa, 0x30, +0x12,0x74,0x8e,0x78,0xcf,0x80,0x44,0xbe,0xc0,0x1, 0x78,0x3f,0x6c,0xff,0x80,0x24, +0x6c,0x77,0x80,0x1a,0x7c,0xbf,0xac,0xbd,0xa, 0x87,0x2d,0x85,0x3e,0x84,0x7e,0xf, +0x22,0xdc,0x2d,0x18,0xb, 0xa, 0x80,0x2d,0x89,0x1b,0xa, 0x80,0xb, 0x70,0xbc,0xd7, +0x38,0xe2,0xb, 0xf0,0xbc,0xef,0x38,0xd8,0x6c,0xff,0x7d,0x3b,0x3e,0x34,0x12,0x74, +0x96,0x2d,0x3a,0x1b,0xa, 0x30,0x12,0x74,0x8e,0x78,0xef,0xda,0x3b,0x22,0xb, 0xb4, +0xb, 0xf0,0xbe,0xf0,0x4, 0x22,0x7e,0xf, 0x22,0xdc,0x2d,0x13,0xb, 0xa, 0x30,0x22, +0xca,0x3b,0x7c,0x45,0x7c,0x57,0x7c,0x7b,0x75,0x44,0x0, 0x7e,0xe0,0xff,0xc2,0x5, +0x7e,0xf4,0x7f,0xff,0xbc,0x67,0x28,0x4, 0x7c,0xd7,0x80,0x2, 0x7c,0xd6,0xbc,0x67, +0x50,0x4, 0x7c,0xa7,0x80,0x2, 0x7c,0xa6,0xbc,0x45,0x28,0x4, 0x7c,0xc5,0x80,0x2, +0x7c,0xc4,0xbc,0x45,0x50,0x4, 0x7c,0xb5,0x80,0x2, 0x7c,0xb4,0xf5,0x45,0x7a,0xd1, +0x46,0x7a,0xc1,0x47,0x7a,0xa1,0x48,0x85,0x45,0x49,0xd2,0x5, 0xbe,0x51,0x47,0x78, +0xa, 0xe5,0x46,0xbc,0xb7,0x50,0xc, 0xc2,0x5, 0x80,0x8, 0xe5,0x46,0xbc,0xb6,0x50, +0x2, 0xc2,0x5, 0x30,0x5, 0x2, 0xc1,0x17,0x7c,0xda,0xc1,0x17,0x12,0x73,0xa2,0x74, +0xff,0x12,0x16,0x5a,0x30,0x5, 0x79,0xa, 0x2c,0xb, 0x24,0xe5,0x49,0xa, 0x3b,0xbd, +0x23,0x18,0x3, 0x12,0x76,0x83,0xa, 0xd, 0xb, 0x4, 0xe5,0x48,0xa, 0x1b,0xbd,0x1, +0x18,0xc, 0xa, 0x5d,0xb, 0x54,0x7a,0xb3,0x44,0x8b,0x7a,0xc3,0x44,0x8c,0xbd,0x1, +0x18,0xb, 0xbd,0x23,0x18,0x7, 0xa, 0x3d,0xb, 0x34,0x12,0x76,0x76,0x7e,0xe4,0x80, +0x1, 0x6c,0xff,0x12,0x76,0x69,0x68,0xe, 0x12,0x76,0x4c,0x68,0x9, 0x12,0x76,0x90, +0x8, 0x4, 0x7d,0xe3,0x7c,0xef,0xb, 0xf0,0xbe,0xf0,0x3, 0x78,0xe6,0x12,0x76,0x5c, +0x78,0x7, 0x12,0x76,0x54,0x78,0x2, 0xc1,0x25,0xe5,0x49,0xbe,0xb1,0x47,0x78,0x7, +0x12,0x76,0x54,0x78,0x2, 0xc1,0x25,0xbe,0xe0,0xff,0x78,0x2, 0xc1,0x17,0x80,0x71, +0xa, 0x2c,0xb, 0x24,0xe5,0x49,0xa, 0x3b,0xbd,0x23,0x18,0x3, 0x12,0x76,0x83,0xa, +0xd, 0x1b,0x4, 0xe5,0x46,0xa, 0x1b,0xbd,0x1, 0x48,0xc, 0xa, 0x5d,0x1b,0x54,0x7a, +0xb3,0x44,0x8b,0x7a,0xc3,0x44,0x8c,0xbd,0x1, 0x48,0xb, 0xbd,0x23,0x18,0x7, 0xa, +0x3d,0x1b,0x34,0x12,0x76,0x76,0x7e,0xe4,0x80,0x1, 0x6c,0xff,0x12,0x76,0x69,0x68, +0xe, 0x12,0x76,0x4c,0x68,0x9, 0x12,0x76,0x90,0x8, 0x4, 0x7d,0xe3,0x7c,0xef,0xb, +0xf0,0xbe,0xf0,0x3, 0x78,0xe6,0x12,0x76,0x5c,0x78,0x5, 0x12,0x76,0x44,0x68,0x35, +0xe5,0x49,0xbe,0xb1,0x47,0x78,0x5, 0x12,0x76,0x44,0x68,0x29,0xbe,0xe0,0xff,0x68, +0x16,0x7e,0x71,0x44,0x74,0x2, 0xac,0x7b,0x59,0xe3,0x4c,0xda,0x9, 0xd4,0x44,0x87, +0x7c,0xca,0x5, 0x44,0x7e,0xe0,0xff,0xe5,0x45,0xa, 0x2b,0xb, 0x24,0xa, 0x3c,0xbd, +0x32,0x68,0x2, 0xa1,0xc, 0x6c,0xff,0x80,0x10,0x74,0x2, 0xac,0xbf,0x49,0xe5,0x4c, +0xda,0xbd,0xef,0x58,0x2, 0x7d,0xfe,0xb, 0xf0,0xe5,0x44,0xbc,0xbf,0x38,0xea,0x7d, +0x3f,0xda,0x3b,0x22,0x9, 0xb4,0x44,0x87,0xbe,0xb1,0x46,0x22,0x9, 0x72,0x44,0x88, +0xbe,0x70,0xff,0x22,0x9, 0xb4,0x44,0x87,0xbe,0xb1,0x48,0x22,0x7e,0x90,0x4, 0xac, +0x9e,0x9, 0xa4,0x44,0x88,0xbe,0xa1,0x49,0x22,0x7e,0x50,0x4, 0xac,0x5f,0x9, 0xb2, +0x44,0x87,0xbe,0xb0,0xff,0x22,0x7a,0x73,0x44,0x8f,0xa, 0x3c,0xb, 0x34,0x7a,0x73, +0x44,0x90,0x22,0x7a,0xd3,0x44,0x87,0xa, 0x1c,0xb, 0x14,0x7a,0x33,0x44,0x88,0x22, +0x12,0x23,0x82,0x74,0x4, 0xac,0xbf,0x59,0x35,0x44,0x89,0xbd,0x3e,0x22,0x7e,0xb3, +0x4f,0x5a,0xbe,0xb0,0xc8,0x50,0x5, 0x4, 0x7a,0xb3,0x4f,0x5a,0x22,0x7e,0x18,0x8, +0x68,0x7a,0x1d,0x27,0x7e,0x1f,0x22,0xdc,0x7f,0x1, 0x2, 0x73,0x59,0x6d,0x22,0x7d, +0x32,0x80,0x12,0x7d,0x52,0x12,0x72,0xf9,0xb, 0xa, 0x10,0xbe,0x14,0xff,0xb0,0x58, +0x2, 0xb, 0x34,0xb, 0x24,0x7e,0x17,0x44,0x81,0xbd,0x12,0x38,0xe6,0x22,0x7e,0x8, +0x8, 0x68,0x7e,0x1f,0x22,0xe0,0x12,0x73,0xc, 0x7e,0x37,0x44,0x81,0x7e,0x50,0x4, +0x7d,0x3, 0x3e,0x4, 0x7e,0x2f,0x22,0xe0,0x2d,0x50,0xb, 0x2a,0x10,0x59,0x10,0x8, +0x68,0xb, 0x34,0x1b,0x50,0x78,0xe9,0x22,0x12,0x77,0x47,0x12,0x76,0xde,0x12,0x77, +0x1b,0x2, 0x77,0x14,0x74,0x1, 0x7a,0xb3,0x4f,0xb1,0x22,0xca,0x3b,0x7e,0xf3,0x40, +0x10,0x7e,0xe3,0x40,0x11,0x7e,0xd3,0x40,0x12,0x6c,0xcc,0x80,0x13,0x7c,0x3c,0xac, +0x3f,0x3e,0x14,0x2e,0x14,0x4, 0x0, 0x6d,0x0, 0x7c,0xbd,0x12,0x95,0x4f,0xb, 0xc0, +0xbc,0xec,0x38,0xe9,0xda,0x3b,0x22,0xe4,0x7a,0xb3,0x3e,0x80,0x7a,0xb3,0x3e,0x81, +0x22,0x7c,0x67,0x7c,0x7b,0xd2,0x1, 0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x51,0x7c,0xb6, +0x12,0x6b,0x73,0x50,0x4a,0x7e,0xa3,0x4d,0xf4,0xbe,0xa0,0x2, 0x40,0x37,0x7e,0xb3, +0x4d,0xfc,0x70,0x2d,0x7e,0x63,0x4f,0xad,0xa, 0x26,0x2e,0x24,0x0, 0xe, 0x7a,0x51, +0x82,0x7a,0x41,0x83,0xe4,0x93,0x24,0xff,0x92,0x1, 0x7c,0xb6,0x4, 0x7a,0xb3,0x4f, +0xad,0x7e,0x63,0x4f,0xad,0xbe,0x60,0x4, 0x40,0x15,0xe4,0x7a,0xb3,0x4f,0xad,0x80, +0xe, 0xd2,0x1, 0x80,0xa, 0xbc,0xa7,0x78,0x4, 0xd2,0x1, 0x80,0x2, 0xc2,0x1, 0xa2, +0x1, 0x22,0xca,0x79,0x7c,0xeb,0x75,0x2f,0x0, 0x6c,0x11,0x12,0xad,0x2, 0x7a,0x57, +0x3e,0x61,0x12,0xad,0x2, 0x7a,0x57,0x3e,0x63,0xe4,0x7a,0xb3,0x3e,0x65,0x7a,0xb3, +0x3e,0x66,0x7e,0xf4,0x0, 0x1, 0x7e,0xa0,0xff,0xbe,0xe0,0x1, 0x78,0x8, 0x7e,0xb3, +0x4e,0xdb,0xf5,0x30,0x80,0x6, 0x7e,0xb3,0x4e,0xdc,0xf5,0x30,0x6c,0x33,0x90,0xe, +0x77,0xe4,0x93,0x20,0xe0,0x7, 0x4c,0x33,0x78,0x3, 0x2, 0x78,0xa0,0x1e,0xb0,0x1e, +0xb0,0x20,0xe0,0x7, 0xbe,0x30,0x1, 0x78,0x2, 0x1, 0xa0,0x90,0xe, 0x78,0xe4,0x93, +0x20,0xe0,0x7, 0xbe,0x30,0x2, 0x78,0x2, 0x1, 0xa0,0x1e,0xb0,0x1e,0xb0,0x20,0xe0, +0x5, 0xbe,0x30,0x3, 0x68,0x7a,0xe5,0x30,0xb4,0xff,0x6, 0x7e,0x47,0x3f,0xf3,0x80, +0x1f,0xe5,0x30,0xbc,0xb3,0x7e,0x27,0x3f,0xf3,0x78,0x6, 0x7e,0x34,0x0, 0x3, 0x80, +0x4, 0x7e,0x34,0x0, 0x5, 0xad,0x32,0x7e,0x24,0x0, 0x4, 0x12,0x14,0x9f,0x7d,0x43, +0xa, 0xe3,0x2e,0xe7,0x44,0x81,0x3e,0xe4,0x7e,0x1f,0x22,0xe0,0x2d,0x3e,0xb, 0x1a, +0xe0,0xbd,0x4e,0x18,0x8, 0xbd,0xfe,0x58,0x4, 0x7c,0xa3,0x7d,0xfe,0x7e,0x37,0x3f, +0xf5,0xbd,0x3e,0x48,0xb, 0x7c,0x1, 0x2e,0x0, 0x2b,0x7c,0xb3,0xa5,0xf6,0xb, 0x10, +0x7e,0x37,0x3e,0x61,0xbd,0x3e,0x58,0x8, 0x7a,0xe7,0x3e,0x61,0x7a,0x33,0x3e,0x65, +0x7e,0x37,0x3e,0x63,0xbd,0x3e,0x8, 0x8, 0x7a,0xe7,0x3e,0x63,0x7a,0x33,0x3e,0x66, +0xb, 0x30,0xa5,0xbb,0x4, 0x2, 0x80,0x3, 0x2, 0x77,0xee,0xbe,0xa0,0x4, 0x50,0x6, +0x75,0x2f,0x1, 0x7a,0xa1,0x27,0xbe,0xe0,0x1, 0x78,0x6, 0x7a,0xa3,0x4e,0xdb,0x80, +0x4, 0x7a,0xa3,0x4e,0xdc,0xe5,0x2f,0xa, 0x5b,0x7e,0x3, 0x3e,0x53,0xa, 0x70,0x2d, +0x75,0x90,0x13,0x80,0xe4,0x93,0xbc,0xbf,0x50,0x2, 0x7c,0xfb,0x7c,0x30,0x80,0x2a, +0x12,0x26,0xf6,0x90,0x14,0x28,0xe4,0x93,0x7c,0xb, 0x74,0x2, 0xac,0xb3,0x19,0x5, +0x3c,0xc9,0x7c,0x3, 0x9e,0x3, 0x3e,0x53,0x2e,0x0, 0x27,0xa5,0xe6,0x7c,0xab,0x7e, +0x70,0x2, 0xac,0x73,0x19,0xa3,0x3c,0xca,0xb, 0x30,0xbc,0xf3,0x38,0xd2,0x7a,0xf3, +0x3e,0x53,0xa, 0x21,0x7e,0xa3,0x3e,0x54,0xa, 0x3a,0x2d,0x32,0x7c,0x27,0x90,0x13, +0x80,0xe4,0x93,0xbc,0xb2,0x50,0x2, 0x7c,0x2b,0x7c,0x3a,0x80,0x20,0x90,0x14,0x28, +0xe4,0x93,0x12,0x79,0x58,0x19,0xa0,0x3d,0x5, 0x7c,0x13,0x9e,0x13,0x3e,0x54,0x2e, +0x10,0x2b,0xa5,0xe7,0x12,0x79,0x58,0x19,0xa0,0x3d,0x6, 0xb, 0x30,0xbc,0x23,0x38, +0xdc,0x7a,0x23,0x3e,0x54,0xda,0x79,0x22,0x7c,0xab,0x7e,0x10,0x2, 0xac,0x13,0x22, +0x7c,0xa7,0x7e,0x73,0x40,0x10,0xac,0x7b,0xa, 0x2a,0x2d,0x32,0x22,0xca,0x3b,0x7c, +0xf5,0x7c,0xe6,0x7c,0xd7,0x7c,0xcb,0x75,0x35,0x0, 0x75,0x36,0x0, 0x75,0x37,0x0, +0x75,0x38,0x0, 0x75,0x39,0x0, 0x75,0x3a,0x0, 0x75,0x3d,0x0, 0x7e,0x37,0x3f,0xff, +0x7a,0x35,0x3e,0x6c,0xaa,0x12,0x7b,0xf7,0xe4,0x19,0xb3,0x3d,0x4b,0x7e,0x13,0x40, +0xf, 0x7e,0xb3,0x40,0x10,0xf5,0x34,0x12,0x7d,0x4a,0xf5,0x33,0x12,0x7d,0x14,0x7a, +0x35,0x3e,0x7e,0x37,0x3f,0xff,0xbe,0x35,0x3e,0x8, 0x3, 0x7a,0x35,0x3e,0xe5,0x32, +0x7c,0x71,0x7c,0x6c,0x7e,0x8, 0x0, 0x37,0x12,0x7c,0xc, 0xf5,0x35,0xe5,0x33,0x7e, +0x71,0x34,0x7c,0x6d,0x7e,0x8, 0x0, 0x38,0x12,0x7c,0xc, 0xf5,0x36,0xe5,0x37,0x7e, +0x71,0x38,0x12,0x7d,0x3c,0x7a,0x37,0x44,0x8d,0x7e,0x34,0x23,0x34,0x7a,0x37,0x44, +0x8f,0xe5,0x37,0x7a,0xb3,0x44,0x87,0xe5,0x38,0x7a,0xb3,0x44,0x88,0xe5,0x35,0x7a, +0xb3,0x44,0x89,0xe5,0x36,0x7a,0xb3,0x44,0x8a,0x7e,0x73,0x3f,0xea,0x7a,0x73,0x44, +0x8b,0xe4,0x7a,0xb3,0x44,0x8c,0x7e,0x8, 0x44,0x87,0x12,0x8, 0x73,0x7e,0x37,0x23, +0x34,0x7d,0x23,0x6d,0x33,0x7e,0xb7,0x23,0x36,0x6d,0xaa,0x2f,0x51,0x7e,0x37,0x23, +0x38,0x6d,0x22,0x7d,0x3, 0x6d,0x11,0x7e,0x37,0x23,0x3a,0x2f,0x10,0x7a,0x1d,0x2c, +0x7e,0x37,0x23,0x3c,0x7d,0x23,0x6d,0x33,0x7e,0x97,0x23,0x3e,0x6d,0x88,0x2f,0x41, +0x7f,0x65,0xe5,0x35,0xa, 0x4b,0xe5,0x37,0xa, 0x5b,0x2d,0x54,0xf5,0x39,0xe5,0x36, +0xa, 0x4b,0xe5,0x38,0xa, 0x5b,0x2d,0x54,0xf5,0x3a,0x85,0x37,0x30,0x61,0x39,0x85, +0x38,0x31,0x61,0x2e,0xe5,0x30,0x7e,0x71,0x31,0x12,0x7d,0x32,0x9d,0x32,0x7a,0x35, +0x3b,0xbe,0x34,0x0, 0x0, 0x18,0x2, 0x61,0x2c,0x7e,0x35,0x3e,0xbe,0x35,0x3b,0x18, +0x2, 0x5, 0x3d,0xe5,0x32,0xa, 0x1b,0xe5,0x30,0x12,0x7c,0x1, 0x8, 0x4, 0x9d,0x31, +0x80,0x4, 0x6d,0x33,0x9d,0x32,0xbe,0x34,0x0, 0x1, 0x18,0x19,0xe5,0x33,0xa, 0x1b, +0xe5,0x31,0x12,0x7c,0x1, 0x8, 0x4, 0x9d,0x31,0x80,0x4, 0x6d,0x33,0x9d,0x32,0xbe, +0x34,0x0, 0x1, 0x8, 0x67,0xbe,0xc0,0x3, 0x40,0x9, 0xbe,0xd0,0x3, 0x40,0x4, 0xd2, +0x0, 0x80,0x2, 0xc2,0x0, 0xe5,0x30,0x7e,0x71,0x31,0x7c,0x6e,0x12,0xaa,0x2b,0x7c, +0x9b,0xbe,0x90,0x2, 0x68,0x5, 0xbe,0x90,0x3, 0x78,0x8, 0x7e,0x35,0x3b,0xe, 0x34, +0x7a,0x35,0x3b,0xbe,0x90,0x2, 0x68,0xa, 0xbe,0x90,0x1, 0x68,0x5, 0xbe,0x90,0x3, +0x78,0x2a,0x7e,0xf5,0x3b,0x12,0x7b,0xd7,0xe5,0x30,0x12,0x7b,0xde,0x7f,0x1, 0x7e, +0x1d,0x2c,0x9f,0x10,0x7a,0x1d,0x2c,0x12,0x7b,0xd7,0xe5,0x31,0x12,0x7b,0xde,0x9f, +0x41,0x12,0x7b,0xd7,0x9f,0x51,0x1a,0x26,0x1a,0x24,0x9f,0x61,0x5, 0x31,0xe5,0x3a, +0xbe,0xb1,0x31,0x28,0x2, 0x41,0x74,0x5, 0x30,0xe5,0x39,0xbe,0xb1,0x30,0x28,0x2, +0x41,0x6f,0xbe,0x58,0x0, 0x0, 0x78,0x2, 0xb, 0x5c,0xbe,0x68,0x0, 0x0, 0x78,0x2, +0xb, 0x6c,0x74,0x6, 0x7e,0x1d,0x2c,0x2f,0x11,0x14,0x78,0xfb,0x7a,0x1d,0x2c,0x7f, +0x5, 0x12,0x7b,0xe5,0x7e,0xd0,0x9, 0xac,0xdf,0x59,0x36,0x3d,0x45,0x74,0x6, 0x2f, +0x44,0x14,0x78,0xfb,0x7f,0x14,0x7f,0x6, 0x12,0x7b,0xe5,0x59,0x36,0x3d,0x47,0x7e, +0xb3,0x3f,0xfe,0x60,0xd, 0x1e,0xd4,0x1e,0xc4,0x50,0x4, 0x4e,0xd4,0x80,0x0, 0x14, +0x78,0xf3,0xbe,0x68,0x0, 0x7f,0x28,0x4, 0x7e,0x68,0x0, 0x7f,0x7d,0x3d,0x7c,0xa7, +0x12,0x7b,0xf7,0x7e,0xa1,0x3d,0x12,0x7b,0xed,0x74,0x9, 0xac,0xbf,0x9, 0x75,0x3d, +0x4b,0xbe,0x70,0x2d,0x28,0x6, 0x7e,0xa0,0x2d,0x12,0x7b,0xed,0x7e,0xa1,0x32,0x7e, +0x70,0x9, 0xac,0x7f,0x19,0xa3,0x3d,0x4c,0x7e,0xa1,0x33,0x7e,0x70,0x9, 0xac,0x7f, +0x19,0xa3,0x3d,0x4d,0xda,0x3b,0x22,0x7d,0x3f,0x1a,0x26,0x1a,0x24,0x22,0xa, 0x1b, +0x6d,0x0, 0x2, 0x14,0xd1,0x12,0x14,0xed,0x2e,0x18,0x0, 0x20,0x22,0x7e,0x70,0x9, +0xac,0x7f,0x19,0xa3,0x3d,0x4b,0x22,0x7e,0x70,0x9, 0xac,0x7f,0x19,0xa3,0x3d,0x4a, +0x22,0xa, 0x3b,0x7d,0x23,0x9d,0x21,0xbe,0x24,0x0, 0x0, 0x22,0xca,0xf8,0x7c,0xf6, +0x7c,0x87,0x7c,0x9b,0xa, 0x2f,0x7d,0x32,0x3e,0x34,0xb, 0x34,0x7c,0xb7,0xbc,0xf9, +0x38,0x14,0xa, 0xf8,0x1b,0xf4,0xa, 0x3f,0x9d,0xf3,0xa, 0x39,0xbd,0x3f,0x18,0x6, +0x7c,0xab,0xa, 0x39,0x80,0x1d,0xbc,0xf9,0x28,0xd, 0xa, 0x39,0xa, 0x5f,0x2d,0x53, +0xb, 0x54,0x7c,0xab,0xe4,0x80,0x10,0xa, 0x3f,0xa, 0x58,0x2d,0x53,0xa, 0x39,0x9d, +0x53,0x7c,0xab,0x9d,0x32,0x7c,0xb7,0x7a,0xb, 0xb0,0x7c,0xba,0xda,0xf8,0x22,0xca, +0x3b,0x6c,0xff,0x6c,0xee,0xa1,0x8, 0x12,0x7d,0x4a,0xf5,0x33,0x75,0x2b,0x3, 0x75, +0x2c,0x3, 0x12,0x7d,0x14,0x7d,0xe3,0x7e,0xf7,0x3f,0xff,0xbd,0xfe,0x8, 0x2, 0x7d, +0xef,0x7e,0x73,0x40,0xf, 0x7a,0x71,0x27,0x7e,0xb3,0x40,0x10,0xf5,0x28,0xe5,0x32, +0x7e,0x61,0x2b,0x7e,0x8, 0x0, 0x2d,0x12,0x7c,0xc, 0xf5,0x29,0xe5,0x33,0x7e,0x71, +0x28,0x7e,0x61,0x2c,0x7e,0x8, 0x0, 0x2e,0x12,0x7c,0xc, 0x7c,0xab,0x7a,0xa1,0x2a, +0xe5,0x29,0xa, 0x4b,0xe5,0x2d,0xa, 0xfb,0x2d,0xf4,0x7d,0x3f,0x7c,0xb7,0xf5,0x2f, +0xa, 0x4a,0xe5,0x2e,0xa, 0x5b,0x2d,0x54,0xf5,0x30,0x75,0x31,0x0, 0x7e,0xd1,0x2d, +0x80,0x26,0x7e,0xc1,0x2e,0x80,0x19,0x7c,0xbd,0x7c,0x7c,0x12,0x7d,0x32,0x7d,0xd3, +0x9d,0xd2,0xbe,0xd4,0x0, 0x0, 0x8, 0x6, 0xbd,0xed,0x18,0x2, 0x5, 0x31,0xb, 0xc0, +0xe5,0x30,0xbc,0xbc,0x38,0xe1,0xb, 0xd0,0xe5,0x2f,0xbc,0xbd,0x38,0xd4,0xbe,0xf1, +0x31,0x50,0x3, 0x7e,0xf1,0x31,0xb, 0xe0,0x12,0x5f,0xd8,0x28,0x2, 0x81,0x67,0x7c, +0xbf,0xda,0x3b,0x22,0x7c,0xbe,0x12,0x7d,0x20,0x7e,0x24,0x0, 0x3, 0x2, 0x14,0x9f, +0x7c,0xab,0x7e,0x70,0x2, 0xac,0x7a,0x9, 0xb3,0x3c,0xc9,0x9, 0x73,0x3c,0xca,0x2, +0x23,0x82,0x12,0x23,0x82,0x7e,0x53,0x3f,0xea,0xa, 0x25,0x22,0x12,0x79,0x60,0x7d, +0x13,0x3e,0x14,0x7e,0x1f,0x22,0xe0,0x2d,0x31,0x22,0x7e,0x70,0x2, 0xac,0x7e,0x9, +0xb3,0x3c,0xc9,0xf5,0x32,0x9, 0xb3,0x3c,0xca,0x22,0x7e,0x37,0x3e,0x59,0xbe,0x34, +0x1, 0x5e,0x58,0xa, 0x12,0x7f,0xb0,0x50,0x5, 0x12,0x7c,0x5f,0x80,0x2, 0x74,0xff, +0x7a,0xb3,0x3, 0xfe,0x22,0x7e,0xb3,0x40,0x1, 0x70,0x6, 0xe4,0x7a,0xb3,0x40,0x2, +0x22,0x7e,0xb3,0x40,0x2, 0x70,0x1b,0x12,0x5f,0xe7,0x28,0x6, 0x7e,0x34,0x0, 0xf, +0x80,0xc, 0x7e,0x37,0x4e,0x4c,0xbe,0x34,0x0, 0x5, 0x28,0x6, 0x1b,0x34,0x7a,0x37, +0x4e,0x4c,0xe4,0x7a,0xb3,0x3e,0x68,0x74,0x1, 0x12,0x9d,0x1a,0x12,0xaa,0xea,0x74, +0x1, 0x12,0x77,0xb2,0x12,0x7e,0xae,0x12,0x23,0x3d,0x12,0x7d,0x5a,0xc2,0x0, 0x12, +0x7d,0xd2,0x7e,0xb3,0x24,0x26,0xb4,0x1, 0x8, 0x7e,0x73,0x3e,0x53,0x7a,0x73,0x3e, +0x67,0x22,0xca,0xf8,0xc2,0x4, 0xc2,0x5, 0xc2,0x6, 0x7e,0xb3,0x3e,0x53,0x70,0x3, +0x12,0x7f,0xb8,0x7e,0x34,0x2, 0xbc,0x12,0x7e,0xb9,0x7a,0xb3,0x4e,0x49,0x7e,0x37, +0x4e,0x4c,0x12,0x7f,0xf, 0x92,0x1, 0x7e,0xb3,0x40,0x2, 0x70,0x62,0x7e,0xa3,0x4e, +0x49,0xbe,0xa0,0x0, 0x38,0x2, 0xc1,0xa4,0xbe,0xa0,0x4, 0x28,0x2, 0xc1,0xa4,0xd2, +0x2, 0x20,0x2, 0x2, 0xc1,0xa4,0xbe,0xa0,0x4, 0x78,0x5, 0x7e,0xf0,0x2, 0x80,0x17, +0xbe,0xa0,0x3, 0x78,0x5, 0x7e,0xf0,0x3, 0x80,0xd, 0xbe,0xa0,0x2, 0x78,0x5, 0x7e, +0xf0,0x5, 0x80,0x3, 0x7e,0xf0,0x8, 0x7c,0xbf,0x12,0x9c,0x66,0x92,0x3, 0x12,0x7f, +0xd7,0x92,0x4, 0xd2,0x5, 0x30,0x3, 0x9, 0x30,0x4, 0x6, 0x30,0x5, 0x3, 0x12,0x7e, +0xa7,0x30,0x1, 0x50,0x30,0x4, 0x4d,0x30,0x5, 0x4a,0x12,0x7e,0xa7,0x80,0x45,0x7e, +0x73,0x4e,0x49,0xbe,0x70,0x0, 0x28,0x7, 0x12,0x7e,0xa7,0x6d,0x33,0x80,0x12,0x7e, +0xb3,0x3e,0x53,0x70,0x12,0x74,0x1, 0x7a,0xb3,0x40,0x2, 0x7e,0x37,0x4e,0x95,0xb, +0x34,0x7a,0x37,0x4e,0x95,0x80,0x2, 0xd2,0x6, 0x20,0x6, 0xd, 0x7e,0x37,0x4e,0x95, +0xbe,0x34,0xe, 0x10,0x50,0x3, 0x30,0x0, 0xb, 0xe4,0x7a,0xb3,0x40,0x2, 0x6d,0x33, +0x7a,0x37,0x4e,0x95,0xda,0xf8,0x22,0x74,0x2, 0x7a,0xb3,0x40,0x2, 0x22,0x7e,0xb3, +0x4f,0x6e,0xb4,0x1, 0x3, 0x2, 0x9a,0x5b,0x22,0x7d,0x23,0x12,0x7f,0xa8,0x28,0x4b, +0x7e,0x37,0x3e,0x59,0xbd,0x32,0x8, 0x4, 0xd2,0x1a,0xe4,0x22,0x30,0x1a,0x2, 0xe4, +0x22,0x12,0x7f,0x80,0x50,0x32,0x7e,0x27,0x3f,0xed,0x7d,0x32,0x3e,0x34,0xbe,0x37, +0x3e,0x59,0x48,0x3, 0x74,0x1, 0x22,0x7d,0x32,0x3e,0x34,0x3e,0x34,0xbe,0x37,0x3e, +0x59,0x48,0x3, 0x74,0x2, 0x22,0x7e,0x34,0x0, 0x6, 0xad,0x32,0xbe,0x37,0x3e,0x59, +0x48,0x3, 0x74,0x3, 0x22,0x74,0x4, 0x22,0x74,0xff,0x22,0xc2,0x1a,0xe4,0x22,0x7c, +0x3b,0x7d,0x43,0xc2,0x7, 0x7e,0x23,0x4e,0x91,0xa, 0x22,0x7e,0x23,0x3e,0x5b,0x12, +0x7f,0x74,0x18,0x37,0x7e,0x23,0x4e,0x92,0xa, 0x22,0x7e,0x23,0x3e,0x5c,0x12,0x7f, +0x74,0x18,0x28,0x12,0x7f,0x80,0x50,0x23,0xbe,0x30,0x0, 0x28,0x1e,0x7e,0x57,0x4e, +0x93,0xb, 0x54,0x7a,0x57,0x4e,0x93,0x7e,0x37,0x4e,0x93,0xbd,0x34,0x40,0x12,0x6d, +0x33,0x7a,0x37,0x4e,0x93,0xd2,0x7, 0x80,0x8, 0x80,0x0, 0x6d,0x33,0x7a,0x37,0x4e, +0x93,0x7e,0x73,0x3e,0x5b,0x7a,0x73,0x4e,0x91,0x7e,0x73,0x3e,0x5c,0x7a,0x73,0x4e, +0x92,0xa2,0x7, 0x22,0xa, 0x32,0x9d,0x32,0x12,0x16,0x6c,0xbe,0x34,0x0, 0x1, 0x22, +0x7e,0xb3,0x3e,0x5b,0x7e,0x73,0x3e,0x5c,0x7c,0xab,0x4c,0x77,0x68,0x18,0x7e,0xb3, +0x40,0x12,0x14,0xbc,0xb7,0x68,0xf, 0x4c,0xaa,0x68,0xb, 0x7e,0xb3,0x40,0x11,0x14, +0xbc,0xba,0x68,0x2, 0xd3,0x22,0xc3,0x22,0x7e,0x73,0x3e,0x53,0xbe,0x70,0x0, 0x22, +0x7e,0x73,0x3e,0x53,0xbe,0x70,0x3, 0x22,0xe4,0x7a,0xb3,0x4e,0x4e,0x7a,0xb3,0x4e, +0x4b,0x7e,0x8, 0x4e,0x72,0x7e,0x34,0x0, 0x1f,0x12,0x16,0x5a,0x7e,0x8, 0x4e,0x4f, +0x7e,0x34,0x0, 0x23,0x2, 0x16,0x5a,0xca,0xf8,0xd2,0x7, 0x6c,0xff,0x80,0x13,0x7c, +0xbf,0x7e,0x70,0x1, 0x12,0x5f,0x3, 0xbe,0x18,0x2, 0xee,0x58,0x3, 0xc3,0x80,0xc, +0xb, 0xf0,0x7e,0x33,0x3e,0x53,0xbc,0x3f,0x38,0xe5,0xa2,0x7, 0xda,0xf8,0x22,0x6d, +0x22,0x6c,0x33,0x7e,0x44,0x7f,0xff,0x7c,0xb3,0x3e,0xb0,0x24,0x27,0xa, 0xfb,0x1b, +0xf8,0x40,0x90,0xe, 0x77,0xe4,0x93,0x20,0xe0,0x4, 0x4c,0x33,0x68,0x39,0x1e,0xb0, +0x1e,0xb0,0x20,0xe0,0x5, 0xbe,0x30,0x1, 0x68,0x2d,0x90,0xe, 0x78,0xe4,0x93,0x20, +0xe0,0x5, 0xbe,0x30,0x2, 0x68,0x20,0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x5, 0xbe,0x30, +0x3, 0x68,0x14,0xa, 0xe3,0x2e,0xe7,0x44,0x81,0x3e,0xe4,0x7e,0x6f,0x22,0xe0,0x2d, +0xde,0xb, 0x6a,0x0, 0x1b,0xf8,0x0, 0xb, 0x30,0xa5,0xbb,0x4, 0xa6,0x7d,0x34,0x6c, +0x33,0x7c,0xb3,0x3e,0xb0,0x24,0x27,0xa, 0xb, 0xb, 0x8, 0x0, 0xbe,0x4, 0x7f,0xff, +0x68,0x8, 0xbd,0x3, 0x58,0x2, 0x7d,0x30,0x2d,0x20,0xb, 0x30,0xa5,0xbb,0x4, 0xe1, +0xbe,0x34,0x0, 0x0, 0x58,0x4, 0x7e,0x34,0x0, 0x1, 0x20,0x6, 0x5, 0x7e,0xa0,0x4, +0x80,0x3, 0x7e,0xa0,0x3, 0xa, 0x1a,0xad,0x13,0xbe,0x17,0x3e,0x61,0x8, 0xe, 0x7e, +0x27,0x3e,0x61,0xbe,0x24,0x3, 0xe8,0x8, 0x4, 0xd2,0x23,0xc3,0x22,0xd3,0x22,0x7e, +0x37,0x3f,0xeb,0x7e,0x53,0x40,0x11,0xbc,0x5b,0x38,0x4, 0x7e,0x37,0x3f,0xf1,0x22, +0x7f,0x20,0xb, 0x2a,0x10,0xb, 0x1a,0x0, 0x1b,0x2a,0x0, 0x1b,0x1a,0x10,0x22,0xca, +0x3b,0x6c,0xff,0x6c,0xee,0x7e,0xb3,0x40,0x11,0xf5,0x2b,0x7e,0xd3,0x40,0x12,0xe4, +0x7a,0xb3,0x3, 0xff,0x7e,0xb3,0x24,0x26,0xb4,0x1, 0x2, 0x80,0x2, 0x21,0xf4,0x6c, +0xcc,0x21,0xe2,0x7e,0x70,0x2, 0xac,0x7c,0x12,0x81,0xfa,0x75,0x27,0x3, 0x75,0x28, +0x3, 0xe5,0x29,0x12,0x5e,0xf8,0x50,0xf, 0x75,0x27,0x0, 0x75,0x28,0x0, 0x7c,0xbc, +0x7c,0x7e,0x12,0x87,0x28,0x21,0xde,0xe5,0x29,0x7e,0x71,0x2a,0x12,0x23,0x82,0xbe, +0x37,0x3f,0xed,0x58,0x2, 0x21,0xe0,0x7e,0x73,0x3e,0x53,0xbe,0x70,0x5, 0x28,0x6, +0x75,0x27,0x2, 0x75,0x28,0x2, 0xe5,0x29,0xbe,0xb0,0x1, 0x68,0x9, 0xe5,0x2b,0x24, +0xfe,0xbe,0xb1,0x29,0x78,0x3, 0x75,0x27,0x2, 0xe5,0x2a,0xbe,0xb0,0x1, 0x68,0x9, +0x7c,0xbd,0x24,0xfe,0xbe,0xb1,0x2a,0x78,0x3, 0x75,0x28,0x2, 0xe5,0x29,0x60,0x8, +0xe5,0x2b,0x14,0xbe,0xb1,0x29,0x78,0x3, 0x75,0x27,0x2, 0xe5,0x2a,0x60,0x8, 0x7c, +0xbd,0x14,0xbe,0xb1,0x2a,0x78,0x3, 0x75,0x28,0x2, 0xc2,0x0, 0xe5,0x29,0x7e,0x71, +0x2a,0x7c,0x6c,0x12,0xaa,0x2b,0xbe,0xb0,0xff,0x68,0x6, 0x75,0x27,0x2, 0x75,0x28, +0x2, 0x7c,0xbc,0x7e,0x8, 0x0, 0x27,0x7e,0x18,0x0, 0x28,0x12,0x87,0xc1,0x7e,0xb3, +0x40,0x2, 0x60,0x6, 0x75,0x27,0x4, 0x75,0x28,0x4, 0xe5,0x27,0x7e,0x71,0x28,0x7c, +0x6c,0x7c,0x5e,0x12,0x79,0x6d,0x7e,0x70,0x9, 0xac,0x7e,0x9, 0x53,0x3d,0x4b,0xbc, +0x5f,0x28,0x2, 0x7c,0xf5,0x90,0x14,0x7, 0xe4,0x93,0xb4,0x1, 0x11,0x7d,0x13,0x2e, +0x14,0x3d,0x45,0x6d,0x0, 0x2e,0x34,0x3d,0x47,0x6d,0x22,0x12,0x80,0xc0,0xb, 0xe0, +0xb, 0xc0,0x7e,0x73,0x3e,0x53,0xbc,0x7c,0x28,0x2, 0x1, 0xf3,0x7a,0xe3,0x3e,0x53, +0x7a,0xf3,0x3, 0xff,0xda,0x3b,0x22,0x2, 0x80,0xcf,0x9, 0xb3,0x3c,0xc9,0xf5,0x29, +0x9, 0xb3,0x3c,0xca,0xf5,0x2a,0x22,0xca,0x3b,0x7c,0xfb,0xc2,0x2, 0xc2,0x3, 0xc2, +0x4, 0x7e,0x94,0x0, 0x51,0x7e,0xe3,0x3e,0x53,0xe4,0x7a,0xb3,0x4c,0xba,0x7a,0xb3, +0x4c,0xbb,0x7a,0xb3,0x4c,0x7c,0x7e,0x8, 0x4c,0xbc,0x12,0x84,0xfa,0xe4,0x12,0x16, +0x5a,0x12,0x84,0xfa,0x3e,0x34,0x7e,0x8, 0x4c,0x7d,0xe4,0x12,0x16,0x5a,0xbe,0xe0, +0x2, 0x50,0x2, 0x81,0xe1,0x6c,0xdd,0x81,0xdb,0x74,0x2, 0x7c,0x7d,0xac,0x7b,0x12, +0x81,0xfa,0x90,0x14,0x28,0xe4,0x93,0xbe,0xb1,0x29,0x78,0x2, 0x81,0xd9,0x4c,0xdd, +0x68,0x8, 0xa, 0x8d,0x9, 0xb8,0x4c,0xbc,0x70,0xa, 0xa, 0x3d,0xb, 0x34,0xa, 0x8d, +0x19,0x78,0x4c,0xbc,0xa, 0x5d,0xb, 0x54,0xf5,0x27,0x81,0xd2,0x7e,0xa1,0x27,0x74, +0x2, 0x7c,0x7a,0xac,0x7b,0x9, 0xb3,0x3c,0xc9,0xf5,0x2b,0x9, 0xb3,0x3c,0xca,0xf5, +0x2c,0x90,0x14,0x28,0xe4,0x93,0xbe,0xb1,0x2b,0x78,0x2, 0x81,0xd0,0xe5,0x2b,0xa, +0x2b,0xe5,0x29,0x12,0x85,0x1, 0x8, 0x6, 0x7d,0x50,0x9d,0x52,0x80,0x4, 0x6d,0x55, +0x9d,0x53,0xf5,0x2d,0xe5,0x2c,0xa, 0x2b,0xe5,0x2a,0x12,0x85,0x1, 0x8, 0x6, 0x7d, +0x80,0x9d,0x82,0x80,0x4, 0x6d,0x88,0x9d,0x83,0x7d,0x38,0x7c,0xc7,0xe5,0x2d,0xbe, +0xb0,0x6, 0x40,0x2, 0x81,0xd0,0xbe,0xc0,0x6, 0x40,0x2, 0x81,0xd0,0xe5,0x29,0x7e, +0x71,0x2a,0x12,0x23,0x82,0x7a,0x35,0x2f,0x12,0x23,0x7d,0x7d,0x83,0x7e,0x25,0x2f, +0xbd,0x28,0x8, 0x4, 0x7d,0x38,0x80,0x3, 0x7e,0x35,0x2f,0x7a,0x35,0x31,0xbd,0x28, +0x58,0x4, 0x7d,0x38,0x80,0x3, 0x7e,0x35,0x2f,0x7a,0x35,0x33,0x75,0x2e,0x0, 0xe5, +0x2d,0xbe,0xb0,0x1, 0x38,0x21,0xbe,0xc0,0x1, 0x38,0x1c,0x7c,0xbf,0x30,0xe0,0x17, +0x7e,0xb3,0x4c,0x7c,0x4, 0x7a,0xb3,0x4c,0x7c,0x75,0x2e,0x1, 0x7e,0xb3,0x4c,0xba, +0x4, 0x7a,0xb3,0x4c,0xba,0x81,0x74,0xe5,0x2d,0xbe,0xb0,0x1, 0x38,0x7, 0xbe,0xc0, +0x1, 0x38,0x2, 0x81,0x74,0xe5,0x2d,0xbe,0xb0,0x6, 0x40,0x2, 0x81,0x74,0xbe,0xc0, +0x6, 0x40,0x2, 0x81,0x74,0x7c,0xbf,0x20,0xe1,0x2, 0x81,0x74,0xc2,0x3, 0xe5,0x2d, +0xbe,0xb0,0x2, 0x28,0x5, 0xbe,0xc0,0x2, 0x38,0x2, 0xd2,0x3, 0x12,0x85,0xc, 0x12, +0x74,0xa0,0x7d,0x13,0x1a,0x2, 0x1a,0x0, 0x7a,0xd, 0x3b,0x7d,0x38,0x2e,0x35,0x2f, +0x12,0x6f,0xf0,0x7a,0x35,0x35,0xc2,0x2, 0xbe,0x8, 0x7f,0xff,0x78,0x5, 0x9f,0x11, +0x7a,0x1d,0x3b,0x7e,0x35,0x35,0x7a,0x35,0x44,0x12,0x85,0xc, 0x7e,0xd, 0x3b,0x12, +0x85,0xf1,0x92,0x4, 0x12,0xa0,0x41,0x92,0x1, 0x7e,0x35,0x33,0x12,0x84,0xe7,0x20, +0x1, 0x1a,0xe5,0x2d,0xbe,0xb0,0x4, 0x38,0x13,0xbe,0xc0,0x4, 0x38,0xe, 0xa, 0x2c, +0xe5,0x2d,0xa, 0x3b,0x12,0x84,0xf3,0x18,0x3, 0x12,0x84,0xe4,0x85,0x2a,0x44,0x85, +0x2b,0x45,0x85,0x2c,0x46,0x7e,0x8, 0x0, 0x3f,0x7e,0x18,0x0, 0x41,0xe5,0x29,0x12, +0x87,0x6c,0xe5,0x2d,0xa, 0x4b,0xbe,0x45,0x41,0x8, 0x7, 0xa, 0x3c,0xbe,0x35,0x41, +0x18,0x8, 0x12,0x84,0xef,0x18,0x3, 0x7e,0x95,0x3f,0x7e,0x5, 0x41,0xbe,0x4, 0x0, +0x3, 0x78,0x5, 0x7e,0x35,0x33,0x80,0x14,0xbe,0x4, 0x0, 0x4, 0x78,0x5, 0x7e,0x35, +0x35,0x80,0x9, 0xbe,0x4, 0x0, 0x5, 0x78,0x6, 0x7e,0x35,0x31,0x12,0x84,0xe7,0x7e, +0xb3,0x4d,0xc9,0xb4,0x1, 0x4, 0x7e,0x94,0x0, 0x3c,0x7e,0xb3,0x40,0x2, 0x60,0x18, +0x12,0x84,0xe4,0xe5,0x2d,0xbe,0xb0,0x2, 0x38,0xe, 0xbe,0xc0,0x2, 0x38,0x9, 0x12, +0x84,0xef,0x18,0x4, 0x7e,0x94,0x0, 0x32,0x7d,0x19,0x1a,0x2, 0x1a,0x0, 0x7e,0x1d, +0x37,0x12,0x14,0xd1,0x7e,0x8, 0x0, 0x64,0x12,0x15,0x3e,0x7f,0x1, 0x7e,0x1d,0x3b, +0xbf,0x10,0x8, 0x2, 0xd2,0x2, 0x30,0x4, 0x5, 0x20,0x3, 0x2, 0xc2,0x2, 0x30,0x2, +0x3, 0x75,0x2e,0x2, 0xe5,0x2e,0xbe,0xb0,0x0, 0x28,0x55,0xe5,0x27,0xa, 0x4b,0x9, +0x14,0x4c,0xbc,0xa5,0xb9,0x0, 0xc, 0xa, 0x3d,0x9, 0xa3,0x4c,0xbc,0x19,0xa4,0x4c, +0xbc,0x80,0x3d,0xa, 0x3d,0x9, 0x53,0x4c,0xbc,0x7a,0x51,0x43,0xbc,0x51,0x28,0x3, +0x7a,0x11,0x43,0x75,0x28,0x0, 0x80,0x23,0x9, 0x64,0x4c,0xbc,0xe5,0x28,0xa, 0xb, +0x9, 0x30,0x4c,0xbc,0xbc,0x36,0x68,0xa, 0xa, 0x3d,0x9, 0x63,0x4c,0xbc,0xbc,0x36, +0x78,0x7, 0x7e,0xa1,0x43,0x19,0xa0,0x4c,0xbc,0x5, 0x28,0xbe,0xe1,0x28,0x38,0xd8, +0x5, 0x27,0xbe,0xe1,0x27,0x28,0x2, 0x41,0x7c,0xb, 0xd0,0xbc,0xed,0x28,0x2, 0x41, +0x49,0xda,0x3b,0x22,0x7e,0x35,0x31,0x1a,0x26,0x1a,0x24,0x7a,0x1d,0x37,0x22,0xa, +0x2c,0x7d,0x34,0x2d,0x32,0xbe,0x34,0x0, 0x6, 0x22,0x90,0x13,0x80,0x93,0xa, 0x3b, +0x22,0xa, 0xb, 0x7d,0x30,0x9d,0x32,0xbe,0x34,0x0, 0x0, 0x22,0xe5,0x29,0x7e,0x71, +0x2a,0x7e,0x61,0x2b,0x7e,0x51,0x2c,0x22,0xca,0xd8,0xca,0x79,0xc2,0x0, 0x7e,0xe0, +0x3, 0xe4,0x7a,0xb3,0x4c,0xb9,0x7e,0xd3,0x3f,0xde,0x12,0x9f,0x8, 0x7e,0xf3,0x3e, +0x53,0xbe,0xf0,0x1, 0x38,0x2, 0xa1,0xe2,0x7c,0xbe,0x12,0x82,0x7, 0x4c,0xdd,0x78, +0x4, 0xc2,0x0, 0x80,0x5f,0xbe,0xd0,0x1, 0x28,0xd, 0x7e,0x73,0x4c,0xfa,0xbe,0x70, +0x6, 0x28,0x4, 0xc2,0x0, 0x80,0x4d,0xc2,0x0, 0x7e,0x53,0x3e,0x53,0xbc,0x5d,0x78, +0x11,0x12,0x87,0x8, 0x50,0x5, 0x7e,0xe0,0x3, 0x80,0x3, 0x7e,0xe0,0x1, 0xd2,0x0, +0x80,0x32,0x7e,0x43,0x4c,0xba,0xa, 0x34,0xa, 0x25,0x7d,0x12,0x9d,0x13,0xb, 0x14, +0xa, 0x3d,0xbd,0x31,0x78,0x7, 0x7e,0xe0,0x1, 0xd2,0x0, 0x80,0x17,0x7e,0x73,0x4c, +0x7c,0xa, 0x37,0x9d,0x23,0xb, 0x24,0x7e,0x73,0x4c,0xfb,0xbd,0x32,0x78,0x5, 0x7e, +0xe0,0x41,0xd2,0x0, 0x30,0x0, 0x5, 0x7c,0xbe,0x12,0x82,0x7, 0x7e,0x8, 0x4c,0xbc, +0x12,0x9d,0xb3,0x7a,0xb3,0x4c,0xb9,0x7e,0xa3,0x4c,0xb9,0x7a,0xa3,0x3e,0x53,0x74, +0x2, 0xa4,0xca,0x59,0x7e,0x18,0x4c,0x7d,0x7e,0x8, 0x3c,0xc9,0x12,0x16,0x35,0x1b, +0xfd,0x7e,0x73,0x3e,0x53,0x7a,0x73,0x4c,0xfb,0x12,0x9e,0x7f,0x7a,0xb3,0x4c,0xfa, +0x80,0xa, 0x74,0x64,0x7a,0xb3,0x4c,0xfa,0x7a,0xf3,0x4c,0xfb,0xda,0x79,0xda,0xd8, +0x22,0xca,0x79,0x7f,0x60,0x7c,0xf5,0x7c,0xe6,0x12,0x86,0x58,0x7d,0xb3,0x7c,0xbe, +0x7c,0x7f,0x12,0x86,0x58,0x2d,0x3b,0x12,0x6f,0xf0,0x7d,0xa3,0x7e,0x25,0x44,0x7d, +0x12,0x9d,0x1a,0xbe,0x14,0x0, 0x0, 0x8, 0x6, 0x7d,0x32,0x9d,0x3a,0x80,0x4, 0x6d, +0x33,0x9d,0x31,0x7d,0x12,0x1a,0x2, 0x1a,0x0, 0x9f,0x6, 0xbe,0x14,0x0, 0x0, 0x8, +0x6, 0x7d,0xd, 0x9d,0x20,0x80,0x4, 0x6d,0x22,0x9d,0x21,0x7e,0x14,0x0, 0x3, 0xad, +0x13,0xbd,0x12,0x58,0xf, 0xbe,0x24,0x0, 0x64,0x8, 0x9, 0xbe,0x34,0x0, 0x46,0x8, +0x3, 0xd3,0x80,0x1, 0xc3,0xda,0x79,0x22,0xca,0x79,0x7c,0x8b,0x7e,0xb3,0x40,0x11, +0xf5,0x49,0x7e,0x93,0x40,0x12,0x7e,0x4, 0x80,0x1, 0x7c,0xf7,0x1a,0x18,0x1b,0x14, +0x7c,0xe3,0xc1,0xf7,0x7a,0xe1,0x47,0xbe,0xe0,0x0, 0x58,0xc, 0x1a,0x5e,0x1a,0x18, +0x9d,0x15,0x1a,0x58,0x2d,0x51,0xf5,0x47,0xe5,0x49,0xbc,0xbe,0x18,0xc, 0x1a,0x58, +0x1a,0x1e,0x9d,0x15,0x1a,0x58,0x9d,0x51,0xf5,0x47,0x1a,0x5f,0x1b,0x54,0xf5,0x46, +0x80,0x47,0x85,0x46,0x48,0xe5,0x46,0xbe,0xb0,0x0, 0x58,0xe, 0xe5,0x46,0x1a,0x5b, +0x1a,0x1f,0x9d,0x15,0x1a,0x5f,0x2d,0x51,0xf5,0x48,0xbe,0x91,0x46,0x18,0xe, 0x1a, +0x3f,0xe5,0x46,0x1a,0x1b,0x9d,0x13,0x1a,0x5f,0x9d,0x51,0xf5,0x48,0xbe,0x81,0x47, +0x78,0x5, 0xbe,0xf1,0x48,0x68,0x10,0xe5,0x47,0x7e,0x71,0x48,0x12,0x23,0x82,0x7d, +0xf3,0xbd,0xf0,0x8, 0x2, 0x7d,0xf, 0x5, 0x46,0x1a,0xef,0xb, 0xe4,0xe5,0x46,0x1a, +0x1b,0xbd,0x1e,0x8, 0xad,0xb, 0xe0,0x1a,0x58,0xb, 0x54,0x1a,0x1e,0xbd,0x15,0x18, +0x2, 0xc1,0x74,0x7d,0x30,0xda,0x79,0x22,0x6c,0xaa,0x80,0x12,0x7e,0x70,0x9, 0xac, +0x7a,0x9, 0xb3,0x3d,0x4b,0xbe,0xb0,0x10,0x28,0x2, 0xd3,0x22,0xb, 0xa0,0x7e,0xb3, +0x3e,0x69,0xbc,0xba,0x38,0xe6,0xc3,0x22,0x7c,0x57,0x12,0x3c,0xd1,0x9, 0x63,0x3c, +0xca,0x90,0x14,0x7, 0xe4,0x93,0x70,0x6, 0x7e,0xa3,0x40,0x10,0x80,0x4, 0x7e,0xa3, +0x40,0xf, 0x7e,0x70,0x40,0xac,0x67,0x2e,0x34,0x0, 0x20,0x7e,0x90,0x9, 0xac,0x95, +0x59,0x34,0x3d,0x45,0x7e,0x70,0x40,0xac,0x7a,0x2e,0x34,0x0, 0x20,0x59,0x34,0x3d, +0x47,0x74,0xff,0x19,0xb4,0x3d,0x4b,0x19,0xb4,0x3d,0x4a,0x22,0x7c,0x9b,0x7f,0x71, +0x7f,0x60,0x7e,0x34,0x19,0xd6,0x7e,0x24,0x0, 0xff,0x7e,0x14,0x44,0x87,0x74,0x30, +0x12,0x15,0x93,0x7e,0x58,0x44,0x87,0x7c,0xb9,0x7e,0x71,0x44,0x12,0x23,0x82,0x7d, +0x3, 0xe5,0x45,0x7e,0x71,0x46,0x12,0x23,0x82,0x2d,0x30,0xe, 0x34,0x7f,0x5, 0x7e, +0x50,0x8, 0xb, 0xa, 0x50,0xbd,0x53,0x58,0xf, 0x69,0x30,0x0, 0x2, 0x1b,0x6a,0x30, +0x69,0x30,0x0, 0x4, 0x1b,0x7a,0x30,0x22,0x2e,0x14,0x0, 0x6, 0x1b,0x50,0x78,0xe2, +0x22,0x7c,0xab,0x7e,0xb3,0x3e,0x69,0x7e,0x93,0x3e,0x53,0x60,0x4a,0xb4,0x1, 0x5, +0xbe,0x90,0x2, 0x68,0x42,0x74,0x9, 0xa4,0x9, 0xa5,0x3d,0x4b,0xbe,0x90,0x1, 0x78, +0x24,0xbe,0xa0,0x19,0x28,0x7, 0x74,0x6, 0x7a,0xb, 0xb0,0x80,0x27,0xbe,0xa0,0x14, +0x28,0x7, 0x74,0x5, 0x7a,0xb, 0xb0,0x80,0x1b,0xbe,0xa0,0xa, 0x28,0x19,0x74,0x4, +0x7a,0xb, 0xb0,0x80,0xf, 0xbe,0x90,0x2, 0x78,0xd, 0xbe,0xa0,0x14,0x28,0x8, 0x74, +0x4, 0x7a,0xb, 0xb0,0x7a,0x1b,0xb0,0x22,0xca,0x3b,0xc2,0x0, 0x7e,0x8, 0x44,0xad, +0x7e,0x34,0x0, 0xa, 0xe4,0x12,0x16,0x5a,0x7e,0x18,0x3f,0x97,0x7a,0x1d,0x27,0x6c, +0xdd,0x80,0x19,0x7e,0xa0,0xff,0x12,0x8b,0xd1,0x74,0xff,0xa, 0x3d,0x19,0xb3,0x44, +0x9b,0xe4,0x19,0xb3,0x44,0x87,0x19,0xb3,0x44,0x91,0xb, 0xd0,0x90,0x13,0x7f,0xe4, +0x93,0xbc,0xbd,0x38,0xde,0x7e,0xa3,0x3f,0xdd,0x4c,0xaa,0x78,0x33,0x7e,0xb3,0x4f, +0x1b,0x70,0x2, 0x61,0x66,0x6c,0xdd,0x80,0x1c,0x7e,0x44,0x7f,0xff,0x7e,0x30,0x7, +0xac,0x3d,0x7e,0x1d,0x27,0x2d,0x31,0x79,0x41,0x0, 0x2, 0x7e,0x30,0x7, 0xac,0x3d, +0x12,0x8b,0xc7,0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbd,0x38,0xdb,0x61,0x66, +0x7e,0xb3,0x4f,0x1b,0x70,0x47,0xbe,0xa0,0x0, 0x28,0x42,0x6c,0xdd,0x80,0x34,0x74, +0x9, 0xac,0xbd,0x49,0x35,0x3e,0x89,0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30,0x0, 0x2, +0x74,0x9, 0xac,0xbd,0x49,0x35,0x3e,0x8b,0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30,0x0, +0x4, 0x74,0x1, 0xa, 0x3d,0x19,0xb3,0x44,0x87,0x74,0x9, 0xac,0xbd,0x19,0xd5,0x3e, +0x8d,0xb, 0xd0,0x7e,0x73,0x3f,0xdd,0xbc,0x7d,0x38,0xc4,0x61,0x66,0x6c,0xdd,0x80, +0x19,0x7e,0x34,0x7f,0xff,0x12,0x8b,0xbf,0x59,0x32,0x22,0xe4,0x59,0x32,0x22,0xe6, +0x59,0x32,0x23,0xc, 0x59,0x32,0x23,0xe, 0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0xbc, +0xbd,0x38,0xde,0x7e,0x73,0x4f,0x1b,0xbe,0x73,0x3f,0xdd,0x28,0x9, 0xbe,0x70,0x2, +0x40,0x4, 0xd2,0x0, 0x80,0x2, 0xc2,0x0, 0x6c,0xdd,0x21,0xdd,0x6c,0xff,0x21,0xd0, +0x74,0x7, 0xac,0xbf,0x7e,0x7d,0x27,0x2d,0xf5,0x69,0x7, 0x0, 0x2, 0xbe,0x4, 0x7f, +0xff,0x78,0x2, 0x21,0xce,0xa, 0x1f,0x9, 0xb1,0x44,0x91,0x60,0x2, 0x21,0xce,0x30, +0x0, 0x6c,0x74,0x2, 0xac,0xbf,0x49,0x45,0x4f,0x30,0xbe,0x44,0x7f,0xff,0x68,0x5e, +0x49,0x45,0x4f,0x30,0x69,0x27,0x0, 0x2, 0x7d,0x32,0x9d,0x34,0x2d,0x32,0x49,0x45, +0x4f,0x1c,0x69,0x57,0x0, 0x4, 0x7d,0x25,0x9d,0x24,0x2d,0x25,0xbe,0x34,0x0, 0x0, +0x58,0x2, 0x6d,0x33,0xbe,0x24,0x0, 0x0, 0x58,0x2, 0x6d,0x22,0x7e,0xa3,0x40,0x11, +0x12,0x8b,0xdb,0xbd,0x43,0x18,0x6, 0x7d,0x35,0x9e,0x34,0x0, 0x21,0x7e,0xa3,0x40, +0x12,0x12,0x8b,0xdb,0xbd,0x42,0x18,0x6, 0x7d,0x25,0x9e,0x24,0x0, 0x21,0x74,0x2, +0xac,0xbd,0x3e,0x54,0x59,0x35,0x22,0xe4,0x59,0x25,0x22,0xe6,0x80,0x12,0x74,0x2, +0xac,0xbd,0x3e,0x54,0x59,0x5, 0x22,0xe4,0x69,0x7, 0x0, 0x4, 0x59,0x5, 0x22,0xe6, +0xa, 0xd, 0x19,0xf0,0x44,0x9b,0x74,0x1, 0x19,0xb1,0x44,0x91,0x80,0xd, 0xb, 0xf0, +0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x28,0x2, 0x21,0x20,0xb, 0xd0,0x7e,0x73,0x4f, +0x1b,0xbc,0x7d,0x28,0x2, 0x21,0x1c,0x6c,0xdd,0x80,0x1f,0x74,0x7, 0xac,0xbd,0x7e, +0x1d,0x27,0x2d,0x35,0x69,0x41,0x0, 0x2, 0x74,0x2, 0xac,0xbd,0x59,0x45,0x4f,0x30, +0x69,0x31,0x0, 0x4, 0x59,0x35,0x4f,0x1c,0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0x7c, +0xab,0xbc,0xad,0x38,0xd6,0x6c,0xdd,0x80,0x2b,0xa, 0x3d,0x9, 0xb3,0x44,0x9b,0xb4, +0xff,0x20,0x6c,0xff,0x80,0x18,0xa, 0x4f,0x9, 0xb4,0x44,0x91,0x70,0xe, 0xa, 0x3d, +0x19,0xf3,0x44,0x9b,0x74,0x1, 0x19,0xb4,0x44,0x91,0x80,0x6, 0xb, 0xf0,0xbc,0xaf, +0x38,0xe4,0xb, 0xd0,0xbc,0xad,0x38,0xd1,0x6c,0xdd,0x80,0x1a,0x7e,0x70,0x9, 0xac, +0x7d,0x49,0x13,0x3e,0x89,0x12,0x8b,0xbf,0x59,0x12,0x23,0xc, 0x49,0x33,0x3e,0x8b, +0x59,0x32,0x23,0xe, 0xb, 0xd0,0x7e,0x73,0x3f,0xdd,0xbc,0x7d,0x38,0xde,0x7e,0x34, +0x22,0xe4,0x7a,0x37,0x44,0xa7,0x7e,0x34,0x23,0xc, 0x7a,0x37,0x44,0xa9,0x7e,0x34, +0x23,0x34,0x7a,0x37,0x44,0xab,0x7e,0x73,0x4f,0x1b,0x7a,0x73,0x44,0xa5,0x7e,0x73, +0x3f,0xdd,0x7a,0x73,0x44,0xa6,0x7e,0x8, 0x44,0xa5,0x12,0x1, 0x20,0x6c,0xdd,0x61, +0x2c,0x7e,0xa0,0xff,0x6c,0xff,0x80,0x19,0x7e,0x70,0x2, 0xac,0x7f,0x49,0x23,0x23, +0x34,0xa, 0x3d,0xbd,0x32,0x78,0x8, 0xa, 0x3f,0x9, 0xa3,0x44,0x9b,0x80,0xb, 0xb, +0xf0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xde,0xbe,0xa0,0xff,0x68,0x5b,0x12, +0x8b,0xd1,0x74,0x1, 0xa, 0x4a,0x19,0xb4,0x44,0x87,0x7e,0x70,0x7, 0xac,0x7a,0x7e, +0xd, 0x27,0x2d,0x13,0x69,0x30,0x0, 0x4, 0xbe,0x37,0x44,0x83,0x38,0x1e,0x7e,0x70, +0x9, 0xac,0x7d,0x49,0x33,0x3e,0x8b,0xbe,0x37,0x44,0x83,0x28,0xf, 0xe4,0xa, 0x4a, +0x19,0xb4,0x44,0x87,0x74,0x1, 0xa, 0x4d,0x19,0xb4,0x44,0xad,0x7e,0x70,0x9, 0xac, +0x7d,0x49,0x33,0x3e,0x89,0x79,0x30,0x0, 0x2, 0x7e,0x70,0x9, 0xac,0x7d,0x49,0x43, +0x3e,0x8b,0x7e,0x30,0x7, 0xac,0x3a,0x12,0x8b,0xc7,0xb, 0xd0,0x7e,0xb3,0x3f,0xdd, +0xbc,0xbd,0x28,0x2, 0x41,0xa1,0x6c,0xdd,0x80,0x23,0xa, 0x3d,0x9, 0xb3,0x44,0x87, +0xbe,0xb0,0x1, 0x68,0x16,0x7e,0x34,0x7f,0xff,0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30, +0x0, 0x2, 0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30,0x0, 0x4, 0xb, 0xd0,0x90,0x13,0x7f, +0xe4,0x93,0xbc,0xbd,0x38,0xd4,0x6c,0xee,0x7e,0xc3,0x3f,0xdd,0x6c,0xdd,0x80,0x2a, +0xa, 0x3d,0x9, 0xb3,0x44,0xad,0x70,0x20,0x7e,0x34,0x0, 0x9, 0xca,0x39,0xac,0x7d, +0x2e,0x34,0x3e,0x89,0x6d,0x22,0x7e,0x30,0x9, 0xac,0x3e,0x2e,0x14,0x3e,0x89,0x6d, +0x0, 0x12,0x16,0x35,0x1b,0xfd,0xb, 0xe0,0xb, 0xd0,0xbc,0xcd,0x38,0xd2,0x7a,0xe3, +0x3f,0xdd,0x7e,0x73,0x3f,0xdd,0x7a,0x73,0x4f,0x1b,0x7e,0xd, 0x27,0x7e,0x18,0x44, +0x87,0x12,0x8b,0xe5,0xda,0x3b,0x22,0x74,0x7, 0xac,0xbd,0x7e,0xd, 0x27,0x22,0x7e, +0x50,0x2, 0xac,0x5d,0x3e,0x24,0x22,0x7e,0x1d,0x27,0x2d,0x31,0x79,0x41,0x0, 0x4, +0x22,0x7e,0x70,0x9, 0xac,0x7d,0x19,0xa3,0x3e,0x8d,0x22,0x74,0x40,0xa4,0x7d,0x45, +0x9e,0x44,0x0, 0x20,0x22,0xca,0x79,0x7e,0xa3,0x3f,0xdd,0x6c,0x99,0x80,0x6e,0xa, +0xf9,0x2d,0xf3,0x7d,0xe2,0x7e,0x7b,0xb0,0xb4,0x1, 0x2b,0x12,0x8c,0x65,0x2d,0xf7, +0x29,0xb7,0x0, 0x1, 0xb4,0x1, 0x6, 0x74,0x3, 0x39,0xb7,0x0, 0x1, 0x12,0x8c,0x65, +0x2d,0xf7,0x29,0x87,0x0, 0x1, 0xbe,0x80,0x3, 0x78,0x3, 0xe4,0x80,0x2e,0x4c,0x88, +0x78,0x2d,0x74,0x2, 0x80,0x26,0x12,0x8c,0x65,0x2d,0xf7,0x29,0xb7,0x0, 0x1, 0xbe, +0xb0,0x2, 0x68,0x2, 0x70,0x14,0x74,0x1, 0x7a,0x7b,0xb0,0x7c,0x8a,0xb, 0xa0,0x7e, +0xf0,0x9, 0xac,0xf8,0x19,0x97,0x3e,0x8d,0x80,0x5, 0x74,0x3, 0x7a,0x7b,0xb0,0x12, +0x8c,0x65,0x2d,0xf7,0x7e,0x7b,0xb0,0x39,0xb7,0x0, 0x1, 0xb, 0x90,0x12,0x67,0xae, +0x38,0x8d,0xda,0x79,0x22,0x7e,0xf0,0x7, 0xac,0xf9,0x7f,0x70,0x22,0xca,0xf8,0x6c, +0xaa,0x80,0x38,0x7e,0xf0,0x3, 0x7e,0x90,0x7, 0xac,0x9a,0x7f,0x10,0x2d,0x34,0x7a, +0x1b,0xf0,0x74,0x3, 0x7f,0x10,0x2d,0x34,0x39,0xb1,0x0, 0x1, 0x7e,0x34,0x7f,0xff, +0x7f,0x70,0x2d,0xf4,0x79,0x37,0x0, 0x2, 0x7f,0x70,0x2d,0xf4,0x79,0x37,0x0, 0x4, +0xe4,0x7f,0x10,0x2d,0x34,0x39,0xb1,0x0, 0x6, 0xb, 0xa0,0x90,0x13,0x7f,0xe4,0x93, +0xbc,0xba,0x38,0xbf,0xda,0xf8,0x22,0xca,0xd8,0xca,0x79,0x6d,0xee,0x7d,0xfe,0x7e, +0x73,0x3f,0xdd,0x7c,0xd7,0x7e,0xa3,0x4d,0x9e,0x4c,0xaa,0x78,0x1b,0x7e,0xb3,0x4a, +0x76,0xb4,0x1, 0x14,0x4c,0x77,0x68,0x10,0x7e,0xb3,0x3f,0xde,0x70,0x2, 0xe1,0x41, +0xbe,0xb3,0x3f,0xdd,0x78,0x2, 0xe1,0x41,0x7a,0xa3,0x4a,0x76,0xc2,0x26,0x7e,0x68, +0x3e,0x89,0x4c,0xdd,0x68,0x6, 0x7e,0xb3,0x3f,0xde,0x70,0x2b,0x6c,0xff,0x80,0x1e, +0x74,0x2, 0xac,0xbf,0x59,0xe5,0x4a,0x62,0x7e,0xa0,0xff,0x7e,0x70,0x9, 0xac,0x7f, +0x19,0xa3,0x4a,0xc, 0x74,0x1, 0xa, 0x3f,0x19,0xb3,0x4a,0x77,0xb, 0xf0,0x90,0x13, +0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xd9,0xc2,0x25,0x7e,0xb3,0x49,0xe9,0x60,0x6, 0x7e, +0xb3,0x40,0x2, 0x60,0x7, 0x12,0x8f,0xf1,0x50,0x2, 0xd2,0x25,0x12,0x8f,0x6f,0x6c, +0xff,0xc1,0xda,0x74,0x9, 0xac,0xbf,0x9, 0xe5,0x3e,0x8d,0x5e,0xe0,0xf, 0x12,0x8f, +0x46,0x38,0x2, 0xc1,0xd8,0x74,0x7, 0xac,0xbe,0x9, 0xb5,0x3f,0x97,0xbe,0xb0,0x1, +0x78,0x2, 0xc1,0xbb,0x6c,0x11,0xc1,0xae,0x7e,0x70,0x9, 0xac,0x71,0x9, 0x3, 0x4a, +0xc, 0x7a,0x1, 0x27,0xbc,0xe, 0x68,0x2, 0xc1,0xac,0x49,0x23,0x4a,0xa, 0x74,0x9, +0xac,0xbf,0x7f,0x56,0x2d,0xb5,0x69,0xe5,0x0, 0x2, 0x7d,0x5e,0x9d,0x52,0xbe,0x54, +0x0, 0x0, 0x8, 0x4, 0x9d,0xe2,0x80,0x4, 0x6d,0xee,0x9d,0xe5,0x74,0x9, 0xac,0xb1, +0x49,0x25,0x4a,0x8, 0x74,0x9, 0xac,0xbf,0x7f,0x56,0x2d,0xb5,0xb, 0x5a,0x50,0x7d, +0x35,0x12,0x85,0x5, 0x8, 0x6, 0x9d,0x52,0x7d,0x45,0x80,0x4, 0x6d,0x44,0x9d,0x43, +0x2d,0x4e,0x12,0x8f,0x4e,0x49,0xf5,0x4a,0x62,0x59,0x45,0x4a,0x62,0xe5,0x27,0xa, +0xeb,0x9, 0xbe,0x4a,0x77,0xbe,0xb0,0x0, 0x28,0x10,0x2e,0xe4,0x4a,0x77,0x14,0x7a, +0xe9,0xb0,0xbe,0x44,0x1, 0x40,0x50,0x2, 0xc1,0xd8,0xbe,0xf4,0x0, 0x32,0x28,0x8, +0xbe,0x44,0x0, 0x32,0x28,0x2, 0xd2,0x26,0xbe,0xf4,0x0, 0x1e,0x28,0xa, 0x7d,0x5f, +0x2e,0x54,0x1, 0x40,0xbd,0x54,0x40,0x3a,0xbe,0xf4,0x0, 0x1e,0x28,0x15,0xbe,0x44, +0x0, 0x1e,0x28,0xf, 0x12,0x8f,0x5f,0x50,0x2, 0xc1,0xd8,0xbe,0xf4,0x0, 0x3c,0x28, +0x2, 0xc1,0xd8,0x7d,0x5f,0x2e,0x54,0x0, 0x1e,0xbd,0x54,0x50,0x15,0xbe,0xf4,0x0, +0x1e,0x28,0xf, 0x12,0x8f,0x5f,0x50,0x2, 0xc1,0xd8,0xbe,0xf4,0x0, 0x3c,0x28,0x2, +0xc1,0xd8,0x30,0x25,0x2, 0xc1,0xd8,0xbe,0x44,0x0, 0xb4,0x28,0x56,0x7e,0x70,0x7, +0xac,0x7e,0x9, 0xb3,0x3f,0x97,0x70,0x4, 0x74,0x3, 0x80,0x2, 0x74,0x1, 0x19,0xb3, +0x3f,0x97,0x7e,0x0, 0x3, 0x7e,0xa1,0x27,0x74,0x7, 0xa4,0x19,0x5, 0x3f,0x98,0xbe, +0xd0,0x0, 0x28,0x2f,0x1b,0xd0,0x7e,0x70,0x9, 0xac,0x7f,0x2e,0x34,0x3e,0x89,0x7e, +0x14,0x44,0x87,0x74,0x9, 0x12,0x15,0x72,0x7e,0x70,0x9, 0xac,0x7d,0x12,0x67,0xb6, +0xac,0x3f,0x12,0x8f,0x56,0x7e,0x34,0x44,0x87,0x7e,0x30,0x9, 0xac,0x3d,0x12,0x8f, +0x56,0x1b,0xf0,0x12,0x8f,0x4e,0x59,0x45,0x4a,0x62,0x80,0x2c,0xb, 0x10,0x90,0x13, +0x7f,0xe4,0x93,0xbc,0xb1,0x28,0x2, 0xa1,0x68,0x80,0x1d,0x6d,0xee,0x74,0x2, 0xac, +0xbe,0x59,0xe5,0x4a,0x62,0x7e,0x0, 0xff,0x74,0x9, 0xac,0xbe,0x19,0x5, 0x4a,0xc, +0x74,0x1, 0xa, 0xee,0x19,0xbe,0x4a,0x77,0xb, 0xf0,0xbc,0xdf,0x28,0x2, 0xa1,0x43, +0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e,0x89,0x7e,0x8, 0x4a,0x8, 0x12,0x16,0x35, +0x1b,0xfd,0x6c,0xff,0x80,0x39,0x7e,0x70,0x9, 0xac,0x7f,0x9, 0xe3,0x4a,0xc, 0x12, +0x8f,0x46,0x28,0x29,0x7e,0x50,0x7, 0xac,0x5e,0x9, 0xb2,0x3f,0x97,0xbe,0xb0,0x1, +0x68,0x3, 0xb4,0x3, 0x18,0x6d,0x22,0x74,0x2, 0xac,0xbe,0x59,0x25,0x4a,0x62,0x74, +0xff,0x19,0xb3,0x4a,0xc, 0x74,0x1, 0xa, 0x3e,0x19,0xb3,0x4a,0x77,0xb, 0xf0,0x90, +0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xbe,0x7a,0xd3,0x3f,0xdd,0xe4,0x7a,0xb3,0x49, +0xea,0xda,0x79,0xda,0xd8,0x22,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbe,0x22,0x7e,0x1, +0x27,0x74,0x2, 0xac,0xb0,0x22,0x2e,0x14,0x3e,0x89,0x74,0x9, 0x2, 0x15,0x72,0x74, +0x9, 0xac,0xbf,0x7f,0x16,0x2d,0x35,0x29,0x1, 0x0, 0x6, 0xbe,0x0, 0x14,0x22,0x7e, +0x73,0x3f,0xde,0xbe,0x73,0x3f,0xdd,0x78,0x17,0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x1, +0x40,0xe, 0x7e,0x37,0x49,0xe7,0xbe,0x34,0x0, 0x14,0x38,0xe, 0xb, 0x34,0x80,0x6, +0x7e,0x37,0x49,0xe7,0x1e,0x34,0x7a,0x37,0x49,0xe7,0x7e,0xb3,0x3f,0xdd,0x70,0x6, +0x6d,0x33,0x7a,0x37,0x49,0xe7,0x7e,0x37,0x49,0xe7,0x22,0x7e,0x8, 0x49,0x65,0x7e, +0x34,0x0, 0xa, 0x74,0x8, 0x12,0x16,0x5a,0x7e,0x8, 0x49,0xc9,0x7e,0x34,0x0, 0xa, +0xe4,0x2, 0x16,0x5a,0x7e,0xa3,0x3f,0xde,0xbe,0xa0,0x0, 0x38,0x23,0xbe,0xa3,0x3f, +0xdd,0x50,0x18,0x7e,0xb3,0x3f,0xe7,0xbe,0xb3,0x4a,0x0, 0x28,0x13,0x7e,0xb3,0x4a, +0x0, 0x4, 0x7a,0xb3,0x4a,0x0, 0x7a,0xa3,0x3f,0xdd,0x22,0xe4,0x7a,0xb3,0x4a,0x0, +0x22,0x7e,0x73,0x3f,0xde,0xbe,0x73,0x3f,0xdd,0x78,0x7d,0x7e,0xb3,0x3f,0xdd,0xb4, +0x1, 0x76,0x7e,0xb3,0x4a,0x1, 0xbe,0xb0,0x2, 0x38,0x13,0x4, 0x7a,0xb3,0x4a,0x1, +0x7e,0x37,0x3e,0x89,0x7a,0x37,0x4a,0x4, 0x7e,0x37,0x3e,0x8b,0x80,0x69,0x7e,0x37, +0x4a,0x2, 0xbe,0x34,0x6, 0xa4,0x50,0x4e,0x7e,0x27,0x3e,0x89,0x7d,0x12,0x9e,0x17, +0x4a,0x4, 0xbe,0x14,0x0, 0x0, 0x8, 0x8, 0x7d,0x32,0x9e,0x37,0x4a,0x4, 0x80,0x4, +0x6d,0x33,0x9d,0x31,0x2e,0x37,0x4a,0x2, 0x7a,0x37,0x4a,0x2, 0x7e,0x37,0x3e,0x8b, +0x7d,0x3, 0x9e,0x7, 0x4a,0x6, 0xbe,0x4, 0x0, 0x0, 0x8, 0x8, 0x7d,0x13,0x9e,0x17, +0x4a,0x6, 0x80,0x4, 0x6d,0x11,0x9d,0x10,0x2e,0x17,0x4a,0x2, 0x7a,0x17,0x4a,0x2, +0x7a,0x27,0x4a,0x4, 0x80,0x11,0xd3,0x22,0xe4,0x7a,0xb3,0x4a,0x1, 0x6d,0x33,0x7a, +0x37,0x4a,0x2, 0x7a,0x37,0x4a,0x4, 0x7a,0x37,0x4a,0x6, 0xc3,0x22,0xca,0x79,0x7e, +0xb3,0x3f,0xdd,0x7e,0x18,0x3f,0x97,0x70,0x11,0x12,0x8f,0xab,0x7e,0x8, 0x4a,0xa9, +0x7e,0x34,0x0, 0xa, 0xe4,0x12,0x16,0x5a,0x41,0x40,0x6c,0xaa,0x41,0x35,0x7e,0xf0, +0x9, 0xac,0xfa,0x9, 0x37,0x3e,0xe7,0xc2,0x0, 0xc2,0x1, 0x49,0xe7,0x3e,0xe3,0x4d, +0xee,0x68,0x11,0x7e,0xd4,0x14,0xc, 0x7e,0xc4,0x0, 0xff,0xb, 0x6a,0xf0,0x1b,0xf4, +0xbd,0xef,0x78,0x2, 0xd2,0x0, 0x49,0xf7,0x3e,0xe5,0x4d,0xff,0x68,0x11,0x7e,0xd4, +0x14,0x1a,0x7e,0xc4,0x0, 0xff,0xb, 0x6a,0x0, 0x1b,0x4, 0xbd,0xf0,0x78,0x2, 0xd2, +0x1, 0xbe,0x30,0xff,0x78,0x2, 0x41,0x33,0x7e,0x10,0x7, 0xac,0x13,0x7f,0x61,0x2d, +0xd0,0x7e,0x6b,0xb0,0xb4,0x2, 0x2, 0x80,0x2, 0x41,0x6, 0x7e,0x10,0x4, 0xac,0x13, +0x49,0xd0,0x4a,0x81,0x7d,0xce,0x9d,0xcd,0xbe,0xc4,0x0, 0x0, 0x8, 0x6, 0x7d,0x4e, +0x9d,0x4d,0x80,0x4, 0x6d,0x44,0x9d,0x4c,0x49,0xb0,0x4a,0x83,0x7d,0xcf,0x9d,0xcb, +0xbe,0xc4,0x0, 0x0, 0x8, 0x6, 0x7d,0xf, 0x9d,0xb, 0x80,0x4, 0x6d,0x0, 0x9d,0xc, +0x7e,0x23,0x3f,0xdd,0xbe,0x20,0x8, 0x40,0x8, 0x74,0xf, 0xa, 0xca,0x19,0xbc,0x49, +0x65,0xa, 0xca,0x9, 0xbc,0x4a,0xa9,0x70,0xe, 0x7d,0xc0,0x2d,0xc4,0xbe,0xc4,0x0, +0x4, 0x50,0x4, 0x6d,0x0, 0x7d,0x40,0xa, 0xca,0x9, 0x2c,0x49,0x65,0xa, 0xc2,0xbd, +0xc4,0x28,0x56,0xbd,0xc0,0x28,0x52,0x20,0x0, 0x9, 0x7e,0xf0,0x9, 0xac,0xfa,0x59, +0xd7,0x3e,0xe3,0x20,0x1, 0x12,0x7e,0xf0,0x4, 0xac,0xf3,0x49,0xd7,0x4a,0x83,0x7e, +0xf0,0x9, 0xac,0xfa,0x59,0xd7,0x3e,0xe5,0xa, 0xda,0x2e,0xd4,0x49,0xc9,0x7e,0xd9, +0xb0,0x4, 0x7a,0xd9,0xb0,0xa, 0xda,0x9, 0xbd,0x49,0xc9,0xbe,0xb0,0x32,0x50,0x2, +0x41,0x33,0xa, 0xda,0x9, 0xbd,0x49,0x65,0xbe,0xb0,0x8, 0x50,0x76,0xa, 0xda,0x2e, +0xd4,0x49,0x65,0x4, 0x7a,0xd9,0xb0,0x80,0x6a,0x74,0x1, 0xa, 0xda,0x19,0xbd,0x4a, +0xa9,0x12,0x92,0x43,0x7e,0xf0,0x4, 0xac,0xf3,0x59,0xf7,0x4a,0x83,0xbe,0x20,0x8, +0x40,0xa, 0x74,0x3, 0xa, 0xda,0x19,0xbd,0x49,0x65,0x80,0x11,0xbe,0x20,0x1, 0x28, +0xc, 0xa, 0xda,0x2e,0xd4,0x49,0x65,0x7c,0xb2,0x14,0x7a,0xd9,0xb0,0xe4,0xa, 0xda, +0x19,0xbd,0x49,0xc9,0x80,0x2d,0x7e,0xf0,0x7, 0xac,0xf3,0x7f,0x61,0x2d,0xd7,0x7e, +0x6b,0xb0,0x70,0x9, 0x12,0x92,0x43,0x59,0xf7,0x4a,0x83,0x80,0x16,0x7e,0xf0,0x7, +0xac,0xf3,0x7f,0x71,0x2d,0xf7,0x7e,0x7b,0xb0,0xb4,0x1, 0x7, 0xe4,0xa, 0xfa,0x19, +0xbf,0x4a,0xa9,0xb, 0xa0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xba,0x28,0x2, 0x1, 0xae, +0xda,0x79,0x22,0x7e,0xf0,0x4, 0xac,0xf3,0x59,0xe7,0x4a,0x81,0x22,0x7e,0xb3,0x49, +0xea,0xbe,0xb0,0xfa,0x50,0x5, 0x4, 0x7a,0xb3,0x49,0xea,0x22,0x6c,0xaa,0x80,0x49, +0x7e,0x50,0x9, 0xac,0x5a,0x49,0x32,0x3f,0x3d,0x12,0x1f,0x18,0x59,0x32,0x3e,0x89, +0x7e,0x50,0x9, 0xac,0x5a,0x49,0x32,0x3f,0x3f,0x12,0x1f,0x18,0x59,0x32,0x3e,0x8b, +0x7e,0x90,0x9, 0xac,0x9a,0x9, 0xb4,0x3f,0x41,0x19,0xb4,0x3e,0x8d,0x7e,0x90,0x9, +0xac,0x9a,0x9, 0xb4,0x3f,0x42,0x19,0xb4,0x3e,0x8e,0x7e,0x90,0x9, 0xac,0x9a,0x9, +0xb4,0x3f,0x43,0x19,0xb4,0x3e,0x8f,0xb, 0xa0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xba, +0x38,0xae,0x22,0x7c,0x17,0x7c,0xab,0x7e,0x14,0xff,0xfc,0x7e,0x3, 0x3f,0xdd,0x7e, +0x90,0x9, 0xac,0x91,0x9, 0xb4,0x49,0x72,0xb4,0x1, 0x49,0xa5,0xb8,0x1, 0xc, 0xbe, +0x14,0xff,0x0, 0x28,0x10,0x7e,0x14,0xff,0x0, 0x80,0xa, 0xbe,0x14,0xff,0xe0,0x28, +0x4, 0x7e,0x14,0xff,0xe0,0x49,0x34,0x49,0x73,0x7e,0x50,0x9, 0xac,0x5a,0x49,0x22, +0x3e,0x89,0x12,0x93,0x9c,0x8, 0x3, 0x12,0x93,0xa6,0x7e,0x70,0x9, 0xac,0x71,0x49, +0x33,0x49,0x75,0x7e,0x50,0x9, 0xac,0x5a,0x49,0x22,0x3e,0x8b,0x12,0x93,0x9c,0x8, +0x3, 0x12,0x93,0xa6,0x7e,0x70,0x9, 0xac,0x71,0x49,0x23,0x49,0x73,0x7e,0x70,0x9, +0xac,0x7a,0x49,0x33,0x3e,0x89,0x12,0x93,0x92,0x18,0x16,0x74,0x9, 0xac,0x1b,0x49, +0x20,0x49,0x75,0x7e,0x70,0x9, 0xac,0x7a,0x49,0x33,0x3e,0x8b,0x12,0x93,0x92,0x8, +0x4, 0x7e,0x14,0xff,0xfc,0x7e,0x50,0x9, 0xac,0x5a,0x49,0x2, 0x3e,0x89,0xbe,0x4, +0x6, 0x50,0x40,0x37,0x7e,0x63,0x40,0x11,0x7e,0x70,0x40,0xac,0x67,0x9e,0x34,0x0, +0x65,0x12,0x2b,0xb4,0xbd,0x3, 0x38,0x23,0x49,0x32,0x3e,0x8b,0xbe,0x34,0x6, 0x50, +0x40,0x19,0x7e,0x3, 0x40,0x12,0x7e,0x10,0x40,0xac,0x1, 0x9e,0x4, 0x0, 0x65,0x3e, +0x4, 0x3e,0x4, 0x3e,0x4, 0x3e,0x4, 0xbd,0x30,0x28,0x4, 0x7e,0x14,0xff,0xff,0x7d, +0x31,0x22,0x9d,0x32,0x12,0x16,0x6c,0xbe,0x34,0x4, 0x0, 0x22,0x9d,0x32,0x12,0x16, +0x6c,0xbe,0x34,0x1, 0x0, 0x22,0x6c,0x0, 0x7e,0x70,0x9, 0xac,0x71,0x19,0x3, 0x49, +0x72,0x22,0x74,0x1, 0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x3e,0x74,0xb4,0x1, 0x5, 0xe4, +0x7a,0xb3,0x3e,0x88,0x12,0x5f,0xe7,0x28,0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3, +0x24,0x26,0x70,0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x4f,0x8c,0xb4,0x1, 0x5, +0xe4,0x7a,0xb3,0x3e,0x88,0x12,0x94,0x17,0x7e,0xb3,0x4d,0xc9,0x70,0xa, 0x12,0x7f, +0xa8,0x28,0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x4d,0x9e,0xb4,0x1, 0x17,0x7e, +0x73,0x4f,0x99,0xbe,0x70,0x3c,0x50,0xe, 0xbe,0x70,0x0, 0x28,0x9, 0xe5,0x13,0x60, +0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x22,0xc2,0x0, 0x12,0x5f,0xdf,0x50,0x30,0x6c,0x66, +0x80,0x1b,0x74,0x2, 0xac,0xb6,0x9, 0x55,0x3c,0xc9,0x9, 0x45,0x3c,0xca,0x7c,0xb5, +0x7c,0x74,0x12,0x7f,0x88,0x50,0x4, 0xd2,0x0, 0x80,0xa, 0xb, 0x60,0x7e,0x73,0x3e, +0x53,0xbc,0x76,0x38,0xdd,0x20,0x0, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x88,0x7e,0xb3, +0x40,0x4, 0xb4,0x1, 0x27,0x7e,0xb3,0x4f,0xaf,0x4, 0x7a,0xb3,0x4f,0xaf,0x7e,0x73, +0x4f,0xaf,0xbe,0x70,0x50,0x50,0xe, 0x7e,0x34,0x14,0x37,0x12,0x1d,0xf2,0x3e,0x34, +0x7a,0x37,0x3e,0x70,0x22,0xe4,0x7a,0xb3,0x40,0x4, 0x80,0x0, 0xe4,0x7a,0xb3,0x4f, +0xaf,0x22,0xd2,0x0, 0xe4,0x7a,0xb3,0x3e,0x82,0x7a,0xb3,0x3e,0x85,0x7e,0xb3,0x3e, +0x75,0xb4,0x1, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x82,0x12,0x6d,0xb8,0x78,0x14,0xe4, +0x7a,0xb3,0x3e,0x83,0x7e,0xb3,0x3e,0x76,0xb4,0x1, 0x1f,0x74,0x1, 0x7a,0xb3,0x3e, +0x83,0x80,0x17,0xbe,0xa0,0x1, 0x78,0x12,0xe4,0x7a,0xb3,0x3e,0x84,0x7e,0xb3,0x3e, +0x77,0xb4,0x1, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x84,0x7e,0xb3,0x3e,0x78,0xb4,0x1, +0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x85,0x4c,0xaa,0x78,0x14,0xe4,0x7a,0xb3,0x3e,0x86, +0x7e,0xb3,0x3e,0x79,0xb4,0x1, 0x1f,0x74,0x1, 0x7a,0xb3,0x3e,0x86,0x80,0x17,0xbe, +0xa0,0x1, 0x78,0x12,0xe4,0x7a,0xb3,0x3e,0x87,0x7e,0xb3,0x3e,0x7a,0xb4,0x1, 0x6, +0x74,0x1, 0x7a,0xb3,0x3e,0x87,0x7e,0xb3,0x3e,0x7e,0x70,0xb, 0xe4,0x7a,0xb3,0x3e, +0x82,0x7a,0xb3,0x3e,0x85,0xc2,0x0, 0x7e,0xb3,0x24,0x26,0x70,0xb, 0xe4,0x7a,0xb3, +0x3e,0x82,0x7a,0xb3,0x3e,0x85,0xc2,0x0, 0x7e,0xb3,0x3e,0x80,0xb4,0x1, 0xb, 0xe4, +0x7a,0xb3,0x3e,0x82,0x7a,0xb3,0x3e,0x85,0xc2,0x0, 0x20,0x0, 0x11,0xe4,0x7a,0xb3, +0x3e,0x83,0x7a,0xb3,0x3e,0x84,0x7a,0xb3,0x3e,0x86,0x7a,0xb3,0x3e,0x87,0x22,0xca, +0xd8,0xca,0x79,0x7c,0xfb,0x7f,0x70,0xc2,0x0, 0x6c,0xdd,0x9f,0x55,0x6d,0x11,0x7d, +0xc1,0x7d,0x91,0x7d,0xd1,0x7e,0x4, 0x7f,0xff,0x6c,0xee,0x80,0x21,0x12,0x96,0x62, +0xb, 0x1a,0x30,0x12,0x16,0x6c,0x7d,0x93,0xbd,0xc9,0x58,0x2, 0x7d,0xc9,0xbd,0x9, +0x8, 0x2, 0x7d,0x9, 0x7d,0x39,0x1a,0x26,0x1a,0x24,0x2f,0x51,0xb, 0xe0,0xbc,0xfe, +0x38,0xdb,0xbe,0xc4,0x0, 0x1e,0x58,0xa, 0x7e,0xb3,0x3e,0x69,0x70,0x4, 0x6d,0x33, +0xc1,0x5d,0xbe,0xc4,0x4, 0xb0,0x8, 0x2, 0xd2,0x0, 0xbe,0xc4,0x4, 0xb0,0x8, 0x11, +0x7e,0xc4,0x0, 0xa0,0x7e,0xb3,0x4d,0xc9,0xb4,0x1, 0x38,0x7e,0xc4,0x2, 0x58,0x80, +0x32,0xbe,0xc4,0x3, 0x20,0x8, 0x11,0x7e,0xc4,0x0, 0x96,0x7e,0xb3,0x4d,0xc9,0xb4, +0x1, 0x21,0x7e,0xc4,0x2, 0x26,0x80,0x1b,0xbe,0xc4,0x0, 0x0, 0x8, 0x11,0x7e,0xc4, +0x0, 0x8c,0x7e,0xb3,0x4d,0xc9,0xb4,0x1, 0xa, 0x7e,0xc4,0x1, 0xc2,0x80,0x4, 0x6d, +0x33,0x80,0x6a,0xbd,0xc, 0x8, 0x5, 0x30,0x0, 0x2, 0x7d,0xc0,0xa, 0x1f,0x12,0x96, +0x6b,0x9f,0x55,0x6c,0xee,0x80,0x1d,0x12,0x96,0x62,0xb, 0x1a,0xd0,0x7d,0x3d,0x12, +0x16,0x6c,0x7d,0x93,0xbd,0x19,0x8, 0xa, 0x7d,0x3d,0x1a,0x26,0x1a,0x24,0x2f,0x51, +0xb, 0xd0,0xb, 0xe0,0xbc,0xfe,0x38,0xdf,0x6d,0x11,0xbe,0xd0,0x0, 0x28,0x5, 0xa, +0x1d,0x12,0x96,0x6b,0xbd,0x1c,0x8, 0x4, 0x7d,0x1c,0x80,0xa, 0x6d,0x0, 0x9d,0xc, +0xbd,0x1, 0x8, 0x2, 0x7d,0x10,0x6c,0xee,0x80,0xd, 0x12,0x96,0x62,0xb, 0x1a,0xd0, +0x9d,0xd1,0x1b,0x1a,0xd0,0xb, 0xe0,0xbc,0xfe,0x38,0xef,0x7d,0x31,0xda,0x79,0xda, +0xd8,0x22,0x74,0x2, 0xac,0xbe,0x7f,0x17,0x2d,0x35,0x22,0x6d,0x0, 0x7f,0x15,0x12, +0x15,0x3e,0x7d,0x13,0x22,0x7c,0xab,0x7e,0x8, 0x3f,0x97,0x90,0x13,0x7f,0xe4,0x93, +0xbc,0xba,0x28,0x2f,0x7e,0x70,0x7, 0xac,0x7a,0x7f,0x70,0x2d,0xf3,0x7e,0x7b,0xb0, +0xbe,0xb0,0x2, 0x68,0x3, 0xb4,0x1, 0xe, 0x74,0x1, 0x7a,0x7b,0xb0,0x74,0x3, 0x2d, +0x13,0x39,0xb0,0x0, 0x1, 0x22,0x74,0x3, 0x7a,0x7b,0xb0,0x2d,0x31,0x7d,0x20,0x39, +0xb1,0x0, 0x1, 0x22,0x7e,0xa3,0x44,0x85,0x60,0x5, 0x1e,0xa0,0x14,0x78,0xfb,0x7c, +0xba,0x30,0xe0,0x2, 0xd3,0x22,0xc3,0x22,0x7d,0x43,0x6c,0xaa,0x6c,0x77,0x7e,0x63, +0x44,0x85,0x7c,0xb7,0x60,0x5, 0x1e,0x60,0x14,0x78,0xfb,0x7c,0xb6,0x30,0xe0,0xf, +0x7e,0x50,0x40,0xac,0x57,0x2e,0x24,0x0, 0x20,0xbd,0x24,0x68,0x9, 0xb, 0xa0,0xb, +0x70,0xbe,0x70,0x4, 0x40,0xd8,0xa5,0xbf,0x4, 0x4, 0x7e,0xa3,0x44,0x86,0x7c,0xba, +0x22,0xca,0x3b,0x7e,0xe3,0x40,0xf, 0x7e,0xd3,0x40,0x10,0xc2,0x2, 0x7e,0x34,0x14, +0x51,0x12,0x5f,0xef,0x7e,0x17,0x3e,0x59,0xbd,0x1d,0x58,0x4, 0x7d,0xd1,0xe, 0xd4, +0x6c,0xcc,0x2, 0x98,0x97,0x7e,0x30,0x2, 0xac,0x3c,0x9, 0xb1,0x3c,0xc9,0xf5,0x27, +0x9, 0x71,0x3c,0xca,0x7a,0x71,0x28,0x12,0x23,0x82,0x7d,0xc3,0xbd,0xdc,0x8, 0x3, +0x2, 0x98,0x95,0xbe,0xe1,0x27,0x38,0x3, 0x2, 0x98,0x95,0xbe,0xd1,0x28,0x38,0x3, +0x2, 0x98,0x95,0x7d,0x1c,0xe, 0x14,0x7d,0xec,0xe, 0xe4,0xe, 0xe4,0x2d,0xe1,0x6d, +0xff,0x12,0xad,0xa4,0x85,0x28,0x2c,0x80,0x2d,0x6c,0x99,0x7e,0xf1,0x27,0x80,0x1b, +0x7c,0xbf,0x7e,0x71,0x2c,0x12,0x98,0xaa,0x18,0x9, 0xbd,0xc0,0x48,0x5, 0x12,0x98, +0xba,0x80,0x6, 0xe5,0x2b,0xbc,0xbf,0x58,0x7, 0x1b,0xf0,0xbe,0xf0,0x0, 0x58,0xe0, +0x4c,0x99,0x68,0x9, 0x15,0x2c,0xe5,0x2c,0xbe,0xb0,0x0, 0x58,0xcc,0xa, 0x3e,0x1b, +0x34,0xe5,0x27,0xa, 0x1b,0xbd,0x13,0x58,0x3d,0x85,0x28,0x2c,0x80,0x31,0x6c,0x99, +0xe5,0x27,0xa, 0x1b,0xb, 0x14,0x7c,0x83,0x80,0x1b,0x7c,0xb8,0x7e,0x71,0x2c,0x12, +0x98,0xaa,0x18,0x9, 0xbd,0xc0,0x48,0x5, 0x12,0x98,0xb2,0x80,0x6, 0xe5,0x2a,0xbc, +0xb8,0x28,0x6, 0xb, 0x80,0xbc,0xe8,0x38,0xe1,0x4c,0x99,0x68,0x9, 0x15,0x2c,0xe5, +0x2c,0xbe,0xb0,0x0, 0x58,0xc8,0x12,0xad,0xa4,0xa, 0x3d,0x1b,0x34,0xe5,0x28,0xa, +0x1b,0xbd,0x13,0x48,0x3, 0x2, 0x98,0x7a,0xe5,0x28,0xa, 0x5b,0xb, 0x54,0xf5,0x29, +0x80,0x2a,0x6c,0x99,0x7e,0xf1,0x27,0x80,0x18,0x7c,0xbf,0x12,0x98,0xa7,0x18,0x9, +0xbd,0xc0,0x48,0x5, 0x12,0x98,0xba,0x80,0x6, 0xe5,0x2b,0xbc,0xbf,0x58,0x7, 0x1b, +0xf0,0xbe,0xf0,0x0, 0x58,0xe3,0x4c,0x99,0x68,0x7, 0x5, 0x29,0xbe,0xd1,0x29,0x38, +0xd1,0xa, 0x3e,0x1b,0x34,0xe5,0x27,0xa, 0x1b,0xbd,0x13,0x58,0x3d,0xe5,0x28,0xa, +0x5b,0xb, 0x54,0xf5,0x29,0x80,0x2e,0x6c,0x99,0xe5,0x27,0xa, 0x1b,0xb, 0x14,0x7c, +0x83,0x80,0x18,0x7c,0xb8,0x12,0x98,0xa7,0x18,0x9, 0xbd,0xc0,0x48,0x5, 0x12,0x98, +0xb2,0x80,0x6, 0xe5,0x2a,0xbc,0xb8,0x28,0x6, 0xb, 0x80,0xbc,0xe8,0x38,0xe4,0x4c, +0x99,0x68,0x7, 0x5, 0x29,0xbe,0xd1,0x29,0x38,0xcd,0x90,0x14,0x50,0xe4,0x93,0xa, +0x1b,0xbd,0x1f,0x38,0x10,0xd2,0x2, 0xe5,0x27,0x7a,0xb3,0x4f,0x8f,0xe5,0x28,0x7a, +0xb3,0x4f,0x90,0x80,0xd, 0xb, 0xc0,0x7e,0x73,0x3e,0x53,0xbc,0x7c,0x28,0x3, 0x2, +0x97,0x25,0xa2,0x2, 0xda,0x3b,0x22,0x7e,0x71,0x29,0x12,0x23,0x82,0x7d,0x3, 0xbd, +0xe0,0x22,0xb, 0xf4,0xb, 0x90,0x7a,0x81,0x2a,0x22,0xb, 0xf4,0xb, 0x90,0x7a,0xf1, +0x2b,0x22,0x6d,0x33,0x7a,0x37,0x4f,0x91,0xe4,0x7a,0xb3,0x4f,0x8f,0x7a,0xb3,0x4f, +0x90,0x7a,0xb3,0x4f,0x8c,0x7a,0xb3,0x4f,0x8d,0x7a,0xb3,0x4f,0x8e,0x22,0x7e,0x37, +0x4f,0x91,0xbe,0x34,0x0, 0x0, 0x28,0x7, 0x1b,0x34,0x7a,0x37,0x4f,0x91,0x22,0xe4, +0x7a,0xb3,0x4f,0x8d,0x7a,0xb3,0x4f,0x8e,0x7a,0xb3,0x4f,0x8c,0x22,0x7e,0x63,0x40, +0x10,0x7e,0x73,0x40,0xf, 0xac,0x76,0x7d,0x13,0x1e,0x14,0x7e,0x27,0x3e,0x57,0x2e, +0x27,0x3e,0x55,0xbd,0x21,0x38,0x16,0x1e,0x34,0x1e,0x34,0x7d,0x23,0x2e,0x24,0x0, +0x14,0xbe,0x27,0x3e,0x55,0x40,0x6, 0xbe,0x37,0x3e,0x57,0x50,0x2, 0xd3,0x22,0xc3, +0x22,0x7e,0x37,0x3e,0x57,0x2e,0x37,0x3e,0x55,0xbe,0x37,0x3e,0x6e,0x28,0x2, 0xd3, +0x22,0xc3,0x22,0xe4,0x7a,0xb3,0x3e,0x74,0x75,0x27,0x0, 0x75,0x28,0x0, 0x7e,0xb3, +0x40,0xf, 0xf5,0x29,0x7e,0xb3,0x40,0x10,0xf5,0x2a,0x7e,0x8, 0x0, 0x27,0x7e,0x37, +0x3f,0xed,0x12,0x99,0x88,0xe4,0x33,0x7a,0xb3,0x3e,0x74,0xe4,0x7a,0xb3,0x3e,0x7d, +0x12,0x99,0x31,0x33,0x7a,0xb3,0x3e,0x7d,0x74,0x1, 0x7a,0xb3,0x3e,0x7e,0x12,0x99, +0xc5,0xe4,0x33,0x7a,0xb3,0x3e,0x7e,0x22,0xca,0xd8,0xca,0x79,0x7d,0x43,0x7f,0x70, +0x12,0x7f,0xa8,0x28,0x2a,0x6c,0xff,0x80,0x21,0x12,0x9a,0x4e,0x7c,0xbe,0x7c,0x7d, +0x12,0x23,0x82,0x7d,0xd3,0x7f,0x7, 0x7c,0x7d,0x12,0x9c,0x37,0x50,0x7, 0xbd,0x4d, +0x58,0x6, 0xd3,0x80,0xb, 0xd3,0x80,0x8, 0xb, 0xf0,0x12,0x27,0xf7,0x38,0xda,0xc3, +0xda,0x79,0xda,0xd8,0x22,0xd2,0x0, 0x6c,0x99,0x80,0x31,0x74,0x2, 0xac,0xb9,0x9, +0x5, 0x4d,0x39,0x9, 0x15,0x4d,0x3a,0x12,0x9a,0x42,0x49,0x25,0x4c,0xfc,0x7d,0xf3, +0x9d,0xf2,0xbe,0xf4,0x0, 0x0, 0x8, 0x4, 0x7d,0x1f,0x80,0x4, 0x6d,0x11,0x9d,0x1f, +0xbe,0x17,0x3e,0x6c,0x28,0x4, 0xc2,0x0, 0x80,0xa, 0xb, 0x90,0x7e,0x83,0x4d,0x38, +0xbc,0x89,0x38,0xc7,0x20,0x0, 0x2d,0x6c,0x99,0x80,0x1d,0x74,0x2, 0xac,0xb9,0x9, +0x5, 0x3c,0xc9,0x9, 0x15,0x3c,0xca,0x12,0x9a,0x42,0x59,0x35,0x4c,0xfc,0x19,0x5, +0x4d,0x39,0x19,0x15,0x4d,0x3a,0xb, 0x90,0x7e,0x73,0x3e,0x53,0xbc,0x79,0x38,0xdb, +0x7a,0x73,0x4d,0x38,0x7e,0xb3,0x3e,0x53,0x70,0x5, 0xe4,0x7a,0xb3,0x4d,0x38,0xa2, +0x0, 0x22,0x7c,0xb0,0x7c,0x71,0x12,0x23,0x82,0x74,0x2, 0xac,0xb9,0x22,0x74,0x2, +0xac,0xbf,0x9, 0xe5,0x3c,0xc9,0x9, 0xd5,0x3c,0xca,0x22,0xca,0x3b,0x30,0x11,0x2, +0x61,0xbd,0x7e,0xb3,0x3e,0x53,0xf5,0x27,0x6c,0xff,0x61,0x1d,0x12,0x9a,0x4e,0x7e, +0x73,0x40,0xf, 0xbc,0x7e,0x78,0x2, 0x61,0x1b,0x12,0x9b,0xde,0x7d,0xc3,0x12,0x9b, +0xfe,0x4c,0xee,0x78,0x2, 0x6d,0xee,0x12,0x9b,0xc8,0x78,0x2, 0x6d,0xff,0x4c,0xdd, +0x78,0x2, 0x6d,0x0, 0x12,0x9b,0xc0,0x78,0x2, 0x6d,0x11,0xbe,0xe4,0x0, 0x46,0x8, +0x2, 0xb, 0xc0,0xbe,0xf4,0x0, 0x46,0x8, 0x2, 0xb, 0xc0,0xbe,0x4, 0x0, 0x46,0x8, +0x2, 0xb, 0xc0,0xbe,0x14,0x0, 0x46,0x8, 0x2, 0xb, 0xc0,0xbe,0xc0,0x2, 0x40,0x4, +0xd2,0x0, 0x80,0x2e,0x4c,0xee,0x68,0x16,0x7e,0xb3,0x40,0x11,0x14,0xbc,0xbe,0x68, +0xd, 0x4c,0xdd,0x68,0x9, 0x7e,0xb3,0x40,0x12,0x14,0xbc,0xbd,0x78,0x14,0xbe,0xc4, +0x1, 0x36,0x8, 0xe, 0xbe,0xc0,0x0, 0x28,0x9, 0x7e,0xb3,0x4f,0x6e,0xb4,0x1, 0x2, +0xd2,0x0, 0x20,0x0, 0x26,0x7d,0xd3,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x4, 0x7d,0x5d, +0x80,0xb, 0x7e,0xb3,0x4f,0x6e,0xb4,0x1, 0xb, 0x7d,0x5d,0xe, 0x54,0xe, 0x54,0xe, +0x54,0x12,0x9b,0xd0,0xc2,0x6, 0x7c,0xbf,0x12,0x26,0xfa,0xb, 0xf0,0xe5,0x27,0xbc, +0xbf,0x28,0x2, 0x41,0x6c,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x2, 0x80,0x2, 0x61,0xbd, +0x7e,0xb3,0x3e,0x54,0xf5,0x27,0x6c,0xff,0x80,0x7b,0x74,0x2, 0xac,0xbf,0x9, 0xe5, +0x3d,0x5, 0x9, 0xd5,0x3d,0x6, 0x7e,0x73,0x40,0xf, 0xbc,0x7e,0x68,0x65,0x12,0x9b, +0xde,0x12,0x9b,0xfe,0x4c,0xee,0x78,0x2, 0x6d,0xee,0x12,0x9b,0xc8,0x78,0x2, 0x6d, +0xff,0x4c,0xdd,0x78,0x2, 0x6d,0x0, 0x12,0x9b,0xc0,0x78,0x2, 0x6d,0x11,0xbe,0xe4, +0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0xf4,0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0x4, +0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0x14,0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0xc0, +0x2, 0x40,0x2, 0xd2,0x0, 0x20,0x0, 0x1b,0x12,0x16,0x6c,0x7d,0xd3,0x7d,0x5d,0xe, +0x54,0xe, 0x54,0x6e,0x54,0xff,0xff,0xb, 0x54,0x12,0x9b,0xd0,0xc2,0x6, 0x7c,0xbf, +0x12,0x26,0xfa,0xb, 0xf0,0xe5,0x27,0xbc,0xbf,0x28,0x2, 0x61,0x3a,0xda,0x3b,0x22, +0x7e,0xb3,0x40,0x10,0x14,0xbc,0xbd,0x22,0x7e,0xb3,0x40,0xf, 0x14,0xbc,0xbe,0x22, +0x7d,0xb4,0x3e,0xb4,0x7e,0x1f,0x22,0xe0,0x2d,0x3b,0x1b,0x1a,0x50,0x22,0x6c,0xcc, +0xc2,0x0, 0x7e,0x33,0x40,0x10,0x7c,0x9e,0xac,0x93,0xa, 0x5d,0x2d,0x45,0x7d,0x24, +0x3e,0x24,0x7e,0x5f,0x22,0xe0,0x7f,0x75,0x2d,0xf2,0xb, 0x7a,0x30,0x22,0xa, 0x53, +0x7d,0x14,0x9d,0x15,0x3e,0x14,0x2d,0x1b,0x7d,0xa, 0xb, 0xa, 0xe0,0x2d,0x54,0x3e, +0x54,0x7f,0x5, 0x2d,0x15,0xb, 0xa, 0xf0,0x7d,0x54,0x1b,0x54,0x3e,0x54,0x7f,0x5, +0x2d,0x15,0xb, 0xa, 0x0, 0x2d,0xb2,0x69,0x15,0x0, 0x2, 0x22,0x7e,0xb3,0x4f,0x6e, +0xb4,0x3, 0x3, 0x2, 0x9a,0x5b,0x22,0x7c,0x67,0x7e,0xb, 0x70,0xbc,0x7b,0x38,0x1a, +0x29,0x70,0x0, 0x2, 0xbc,0x7b,0x28,0x12,0x29,0x70,0x0, 0x1, 0xbc,0x76,0x38,0xa, +0x29,0x70,0x0, 0x3, 0xbc,0x76,0x28,0x2, 0xd3,0x22,0xc3,0x22,0xe4,0x7a,0xb3,0x3e, +0x7c,0x7a,0xb3,0x3e,0x7c,0x22,0x7c,0x5b,0x7e,0x73,0x4e,0x4e,0xa5,0xbf,0x0, 0xe, +0x7e,0x63,0x3e,0x5b,0xa, 0x17,0x19,0x61,0x4e,0x72,0x74,0x1, 0x80,0x20,0x7e,0xb3, +0x3e,0x5b,0x7e,0x8, 0x4e,0x72,0x12,0x9d,0x3, 0x40,0x17,0x7e,0x43,0x3e,0x5b,0x7e, +0x73,0x4e,0x4e,0xa, 0x37,0x19,0x43,0x4e,0x72,0x7e,0xb3,0x4e,0x4e,0x4, 0x7a,0xb3, +0x4e,0x4e,0x7e,0x73,0x4e,0x4b,0xa5,0xbf,0x0, 0xe, 0x7e,0x63,0x3e,0x5c,0xa, 0x17, +0x19,0x61,0x4e,0x4f,0x74,0x1, 0x80,0x20,0x7e,0xb3,0x3e,0x5c,0x7e,0x8, 0x4e,0x4f, +0x12,0x9d,0x3, 0x40,0x17,0x7e,0x43,0x3e,0x5c,0x7e,0x73,0x4e,0x4b,0xa, 0x37,0x19, +0x43,0x4e,0x4f,0x7e,0xb3,0x4e,0x4b,0x4, 0x7a,0xb3,0x4e,0x4b,0x7e,0xa3,0x4e,0x4e, +0xbc,0xa5,0x50,0x18,0x7e,0x73,0x4e,0x4b,0xbc,0x75,0x50,0x10,0x74,0x3, 0xac,0x5b, +0xe, 0x24,0xa, 0x17,0xa, 0x3a,0x2d,0x31,0xbd,0x32,0x48,0x5, 0x12,0x7f,0xb8,0xd3, +0x22,0xc3,0x22,0x6c,0x66,0x80,0xd, 0x7e,0xb, 0xa0,0xbc,0xab,0x78,0x2, 0xd3,0x22, +0xb, 0x14,0xb, 0x60,0xbc,0x76,0x38,0xef,0xc3,0x22,0x7c,0xab,0xbe,0xa0,0x1, 0x78, +0x41,0x12,0x1f,0xd9,0x7e,0x34,0x0, 0x78,0x7a,0x37,0x3f,0xeb,0x7e,0x34,0x0, 0x6e, +0x7a,0x37,0x3f,0xed,0x7e,0x34,0xff,0x88,0x7a,0x37,0x3f,0xef,0x7e,0x34,0x1, 0x2c, +0x7a,0x37,0x3f,0xf7,0x7e,0x34,0xfe,0xd4,0x7a,0x37,0x3f,0xf9,0x12,0x9d,0x9e,0x68, +0x4c,0x7e,0x34,0x2, 0x58,0x7a,0x37,0x3f,0xf1,0x7e,0x34,0x2, 0x26,0x7a,0x37,0x3f, +0xf3,0x22,0xbe,0xa0,0x2, 0x78,0x36,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x18,0x74,0x5c, +0x7a,0xb3,0x3f,0xea,0x7e,0x34,0x0, 0x5c,0x7a,0x37,0x3f,0xeb,0x7a,0x37,0x3f,0xed, +0x7e,0x34,0xff,0xa4,0x80,0x13,0x12,0x1f,0xd9,0x7e,0x34,0x1, 0x2c,0x7a,0x37,0x3f, +0xeb,0x7a,0x37,0x3f,0xed,0x7e,0x34,0xfe,0xd4,0x7a,0x37,0x3f,0xef,0x22,0x7e,0xb3, +0x4d,0x7d,0xbe,0xb0,0xaa,0x22,0x7e,0x8, 0x4f,0xae,0x7e,0x34,0x0, 0x1, 0x74,0xff, +0x2, 0x16,0x5a,0xca,0x79,0x7f,0x70,0x7e,0x3, 0x40,0x10,0x7e,0x93,0x3e,0x53,0x7e, +0x6f,0x22,0xe0,0x6c,0x11,0x6c,0x88,0x6c,0xff,0x80,0xd, 0xa, 0x1f,0x12,0x9e,0x77, +0xbc,0x78,0x40,0x2, 0x7c,0x87,0xb, 0xf0,0xbc,0x9f,0x38,0xef,0x7e,0xf0,0x1, 0xc1, +0x64,0x75,0x29,0x0, 0x6d,0xbb,0x6d,0x99,0x7d,0xa9,0x6c,0xee,0x80,0x3a,0x7e,0x30, +0x2, 0xac,0x3e,0x9, 0xb1,0x3c,0xc9,0xf5,0x27,0x9, 0xb1,0x3c,0xca,0xf5,0x28,0xa, +0x1e,0x12,0x9e,0x77,0xbc,0x7f,0x78,0x1e,0x5, 0x29,0xe5,0x27,0xa, 0x1b,0x2d,0xa1, +0xe5,0x28,0xa, 0x1b,0x2d,0x91,0xe5,0x27,0x7e,0x71,0x28,0x12,0x23,0x82,0x7d,0x83, +0xbd,0xb8,0x58,0x2, 0x7d,0xb8,0xb, 0xe0,0xbc,0x9e,0x38,0xc2,0xe5,0x29,0xbe,0xb0, +0x0, 0x28,0x2f,0xe5,0x29,0xa, 0x8b,0x7d,0x3a,0x8d,0x38,0x7d,0xa3,0x8d,0x98,0x12, +0x9e,0x6f,0x19,0xa1,0x4c,0x7d,0x7d,0x39,0x12,0x9e,0x6f,0x19,0xa1,0x4c,0x7e,0xa, +0x30,0xad,0x3a,0x7d,0x13,0x2d,0x19,0x3e,0x14,0x7f,0x16,0x2d,0x31,0x1b,0x1a,0xb0, +0xb, 0x10,0xb, 0xf0,0xbc,0x8f,0x40,0x2, 0xa1,0xe1,0x7c,0xb1,0xda,0x79,0x22,0x7c, +0xa7,0x7e,0x30,0x2, 0xac,0x31,0x22,0x7f,0x17,0x2d,0x31,0x7e,0x1b,0x70,0x22,0xca, +0x3b,0x7e,0xa0,0x64,0x6c,0x77,0x80,0x6c,0xa, 0x27,0xb, 0x24,0x7c,0x65,0x80,0x5a, +0x7e,0xf0,0x2, 0xac,0xf6,0x9, 0xb7,0x3c,0xc9,0xa, 0xb, 0x7e,0xd0,0x2, 0xac,0xd7, +0x9, 0xb6,0x3c,0xc9,0xa, 0x2b,0x7d,0x12,0x9d,0x10,0xbe,0x14,0x0, 0x0, 0x8, 0x4, +0x9d,0x20,0x80,0x4, 0x6d,0x22,0x9d,0x21,0x9, 0x47,0x3c,0xca,0xa, 0x44,0x9, 0x46, +0x3c,0xca,0xa, 0x14,0x7d,0x1, 0x9d,0x4, 0xbe,0x4, 0x0, 0x0, 0x8, 0x4, 0x9d,0x14, +0x80,0x4, 0x6d,0x11,0x9d,0x10,0x7c,0x43,0xbc,0x45,0x50,0x4, 0x7c,0x35,0x80,0x2, +0x7c,0x34,0xbc,0xa3,0x28,0x2, 0x7c,0xa3,0xb, 0x60,0x7e,0x23,0x3e,0x53,0xbc,0x26, +0x38,0x9e,0xb, 0x70,0x7e,0xb3,0x3e,0x53,0xbc,0xb7,0x38,0x8c,0xbe,0xa0,0x64,0x78, +0x2, 0x6c,0xaa,0x7c,0xba,0xda,0x3b,0x22,0xca,0x3b,0x75,0x29,0xff,0x6c,0xff,0x7e, +0xc0,0xff,0x6c,0xee,0x6c,0x99,0x6c,0x88,0x7e,0xf4,0x7f,0xff,0x6c,0xdd,0x80,0x69, +0x7e,0x70,0x2, 0xac,0x7d,0x9, 0xb3,0x3c,0xc9,0xf5,0x27,0x9, 0x73,0x3c,0xca,0x7a, +0x71,0x28,0x12,0x23,0x82,0x7d,0x3, 0xbd,0xf, 0x58,0x2, 0x7d,0xf0,0xe5,0x27,0xbe, +0xb1,0x29,0x50,0x3, 0x85,0x27,0x29,0xe5,0x27,0xbc,0xbf,0x28,0x3, 0x7e,0xf1,0x27, +0xe5,0x28,0xbc,0xbc,0x50,0x3, 0x7e,0xc1,0x28,0xe5,0x28,0xbc,0xbe,0x28,0x3, 0x7e, +0xe1,0x28,0xe5,0x29,0xa, 0x5b,0xa, 0x1f,0x9d,0x15,0xbe,0x14,0x0, 0x7, 0x18,0xc, +0xa, 0x5c,0xa, 0x1e,0x9d,0x15,0xbe,0x14,0x0, 0x7, 0x8, 0xb, 0x7e,0x14,0x1, 0xf4, +0x7a,0x17,0x4c,0xf8,0x2, 0xa0,0x3e,0xb, 0xd0,0x7e,0x73,0x3e,0x53,0xbc,0x7d,0x38, +0x8f,0x7d,0x3f,0x3e,0x34,0x12,0x7d,0x19,0x7d,0x3, 0x7c,0xdc,0x80,0x1c,0x7e,0xc1, +0x29,0x80,0x11,0x7c,0xbc,0x7c,0x7d,0x12,0x23,0x82,0xbd,0x30,0x8, 0x2, 0xb, 0x90, +0xb, 0x80,0xb, 0xc0,0xbc,0xfc,0x50,0xeb,0xb, 0xd0,0xbc,0xed,0x50,0xe0,0x7e,0x73, +0x3f,0xde,0xbe,0x70,0x3, 0x40,0x12,0x7e,0x17,0x4c,0xf8,0xbe,0x14,0x3, 0xe8,0x50, +0x2d,0xb, 0x14,0x7a,0x17,0x4c,0xf8,0x80,0x25,0xbe,0x70,0x1, 0x38,0x20,0x7e,0x17, +0x4c,0xf8,0xbe,0x14,0x0, 0x2, 0x28,0x6, 0x1b,0x15,0x7a,0x17,0x4c,0xf8,0x7e,0x17, +0x4c,0x7a,0xbe,0x14,0x1, 0xf4,0x50,0x6, 0xb, 0x14,0x7a,0x17,0x4c,0x7a,0x7e,0x73, +0x3e,0x53,0xbe,0x70,0x1, 0x40,0x37,0x7e,0x30,0x2, 0xac,0x38,0x74,0x3, 0xac,0xb9, +0xbd,0x51,0x8, 0x14,0x6d,0x11,0x7a,0x17,0x4c,0xf8,0x7e,0x17,0x4c,0x7a,0xbe,0x14, +0x1, 0xf4,0x50,0x1a,0xb, 0x14,0x80,0x12,0x7e,0x17,0x4c,0xf8,0xbe,0x14,0x3, 0xe8, +0x50,0x6, 0xb, 0x15,0x7a,0x17,0x4c,0xf8,0x6d,0x11,0x7a,0x17,0x4c,0x7a,0xda,0x3b, +0x22,0xd2,0x5, 0x12,0x7f,0xb0,0x50,0x2, 0xc3,0x22,0x7e,0x8, 0x44,0x87,0x7e,0x34, +0x0, 0x3c,0xe4,0x12,0x16,0x5a,0x6c,0xaa,0x80,0x17,0x7e,0x90,0x2, 0xac,0x9a,0x9, +0xb4,0x3c,0xc9,0x19,0xb4,0x44,0x87,0x9, 0xb4,0x3c,0xca,0x19,0xb4,0x44,0x88,0xb, +0xa0,0x7e,0x73,0x3e,0x53,0xbc,0x7a,0x38,0xe1,0x6c,0xaa,0x80,0x36,0xa, 0x2a,0xb, +0x24,0x7c,0x65,0x80,0x28,0x7e,0x50,0x2, 0xac,0x56,0x9, 0x12,0x44,0x87,0x7e,0x30, +0x2, 0xac,0x3a,0x9, 0xb1,0x44,0x87,0xbc,0xb1,0x78,0x2, 0xc2,0x5, 0x9, 0x52,0x44, +0x88,0x9, 0xb1,0x44,0x88,0xbc,0xb5,0x78,0x2, 0xc2,0x5, 0xb, 0x60,0xbc,0x76,0x38, +0xd4,0xb, 0xa0,0xbc,0x7a,0x38,0xc6,0xa2,0x5, 0x22,0xca,0x7b,0xca,0x6b,0xca,0x5b, +0xca,0x4b,0xca,0x2b,0xca,0x1b,0xca,0xb, 0xc0,0xd0,0xc0,0x83,0xc0,0x82,0xa9,0x31, +0xcd,0xc, 0xa9,0x31,0xe5,0x8, 0x12,0xa1,0x31,0xc2,0x95,0xa9,0xc1,0xcd,0xa9,0x30, +0xcd,0x7, 0xa9,0x30,0xe5,0x3, 0xa9,0xc0,0xcd,0xa9,0x32,0xcd,0x7, 0xa9,0x32,0xe5, +0x3, 0xa9,0xc2,0xcd,0xa9,0x35,0xcd,0xe, 0xa9,0x35,0xe5,0xa, 0xa9,0xc5,0xcd,0xe4, +0x7e,0x70,0x3, 0x12,0x35,0x75,0xa9,0x36,0xcd,0x7, 0xa9,0x36,0xe5,0x3, 0xa9,0xc6, +0xcd,0xa9,0x37,0xcd,0x7, 0xa9,0x37,0xe5,0x3, 0xa9,0xc7,0xcd,0xd0,0x82,0xd0,0x83, +0xd0,0xd0,0xda,0xb, 0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b,0xda,0x6b,0xda,0x7b, +0x32,0xa9,0xd5,0xea,0xa9,0xc5,0xea,0x22,0x75,0xb7,0x0, 0x75,0xb8,0x0, 0x75,0xf7, +0x0, 0x75,0xf8,0x0, 0xa9,0xd0,0xb7,0xd2,0xb8,0xa9,0xd5,0xb7,0xd2,0xbd,0xa9,0xd0, +0xf7,0xd2,0xf8,0xa9,0xd4,0xb7,0xc2,0xbc,0xa9,0xc2,0xb7,0xc2,0xba,0xa9,0xc1,0xb7, +0xc2,0xb9,0xa9,0xc3,0xb7,0xc2,0xbb,0x22,0xa2,0xac,0x92,0x2, 0xc2,0xac,0x7e,0xf, +0x4f,0xa1,0x30,0x1, 0xa, 0xb, 0x16,0xb, 0xa, 0x30,0x4e,0x70,0xc, 0x80,0x8, 0xb, +0x16,0xb, 0xa, 0x30,0x5e,0x70,0xf3,0x1b,0xa, 0x30,0xa2,0x2, 0x92,0xac,0x22,0xa, +0x7, 0xa, 0x1b,0x2d,0x10,0x3e,0x14,0x3e,0x14,0x3e,0x14,0x3e,0x14,0x6d,0x0, 0x7e, +0x18,0xbb,0x80,0x2, 0x15,0x3e,0x7e,0x8, 0x0, 0x53,0x7e,0x34,0x0, 0x3c,0xe4,0x12, +0x16,0x5a,0x7e,0x34,0x1, 0x5, 0x7a,0x37,0x0, 0x53,0x7e,0x34,0x20,0x0, 0x7a,0x37, +0x0, 0x55,0x6d,0x33,0x7a,0x37,0x0, 0x57,0x7e,0x34,0x1, 0xe0,0x7a,0x37,0x0, 0x59, +0x7e,0x34,0x28,0x30,0x7a,0x37,0x0, 0x5b,0x7e,0x34,0x18,0x1e,0x7a,0x37,0x0, 0x5d, +0x7e,0x34,0x66,0x6, 0x7a,0x37,0x0, 0x5f,0x7e,0x34,0x73,0x0, 0x7a,0x37,0x0, 0x61, +0x7e,0x34,0x14,0x2, 0x7a,0x37,0x0, 0x63,0x6d,0x33,0x7a,0x37,0x0, 0x67,0x7a,0x37, +0x0, 0x69,0x7a,0x37,0x0, 0x6b,0x7a,0x37,0x0, 0x6d,0x7a,0x37,0x0, 0x7f,0x7e,0x34, +0x38,0x1, 0x7a,0x37,0x0, 0x81,0x7e,0x34,0x4, 0x1, 0x7a,0x37,0x0, 0x83,0x7e,0x34, +0x6, 0x3, 0x7a,0x37,0x0, 0x85,0x6d,0x33,0x7a,0x37,0x0, 0x87,0x7a,0x37,0x0, 0x89, +0x7a,0x37,0x0, 0x8b,0x7a,0x37,0x0, 0x8d,0x7e,0x34,0x0, 0x3c,0xca,0x39,0x7e,0x18, +0x0, 0x53,0x7e,0x8, 0x0, 0x8f,0x12,0x16,0x35,0x1b,0xfd,0x22,0x6c,0xaa,0x7e,0x30, +0x2c,0xac,0x3a,0x12,0x2c,0x5b,0x7e,0x34,0x0, 0x2c,0xe4,0x12,0x16,0x5a,0xb, 0xa0, +0xbe,0xa0,0x3, 0x40,0xe9,0x22,0x7e,0x34,0x0, 0x2, 0x7e,0x24,0xc, 0xd0,0x7e,0x14, +0x11,0x38,0x7e,0x57,0x3, 0xbf,0x12,0xa2,0xb4,0x74,0x2, 0x2, 0xa2,0x7e,0x7a,0xb3, +0x3, 0xd5,0x7a,0xb3,0x3, 0xd6,0x22,0x6d,0x33,0x7e,0x24,0xc, 0xd0,0x7e,0x14,0x11, +0x38,0x7e,0x57,0x3, 0xaf,0x12,0xa2,0xb4,0xe4,0x2, 0xa2,0x7e,0x7e,0x34,0x0, 0x1, +0x7e,0x24,0xc, 0xd0,0x7e,0x14,0x11,0x38,0x7e,0x57,0x3, 0xb7,0x12,0xa2,0xb4,0x74, +0x1, 0x2, 0xa2,0x7e,0x7c,0x1b,0x7d,0x43,0x7e,0xa3,0x3, 0xcf,0xbe,0xa0,0x5, 0x50, +0x1e,0x7e,0x70,0x7, 0xac,0x7a,0x59,0x43,0x3, 0xdb,0x59,0x23,0x3, 0xdd,0x59,0x13, +0x3, 0xdf,0x19,0x13,0x3, 0xe1,0x7c,0xba,0x4, 0x7a,0xb3,0x3, 0xcf,0xc3,0x22,0xd3, +0x22,0x7e,0x34,0x0, 0x3, 0x7e,0x24,0xc, 0xd0,0x7e,0x14,0x11,0x38,0x7e,0x57,0x3, +0xc7,0x12,0xa2,0xb4,0x74,0x3, 0x2, 0xa2,0x7e,0x7e,0x34,0x0, 0x4, 0x7e,0x24,0xc, +0xd0,0x7e,0x14,0x11,0x38,0x74,0x1, 0x12,0xa2,0xb4,0x7e,0x73,0x4f,0x55,0x7a,0x73, +0x3, 0xd5,0x7a,0x73,0x3, 0xd6,0x22,0x7e,0xb3,0x3, 0xd2,0xb4,0x1, 0x37,0x7e,0xa3, +0x3, 0xd0,0x7a,0xa3,0x3, 0xd1,0x7e,0xb3,0x3, 0xd8,0x4, 0x7a,0xb3,0x3, 0xd8,0x7e, +0xb3,0x3, 0xd7,0x4, 0x7a,0xb3,0x3, 0xd7,0x12,0xa6,0x48,0xbe,0xb3,0x3, 0xd7,0x38, +0x14,0xe4,0x7a,0xb3,0x3, 0xd7,0x7c,0xba,0x4, 0x7a,0xb3,0x3, 0xd0,0x12,0xa3,0x5d, +0x28,0x3, 0x12,0xa3,0x56,0x22,0x74,0x3, 0x7a,0xb3,0x3, 0xd2,0x22,0x7e,0x73,0x3, +0xcf,0xbe,0x73,0x3, 0xd0,0x22,0x12,0xa3,0x5d,0x38,0x2, 0xe4,0x22,0x7e,0xa3,0x3, +0xd0,0x74,0x7, 0xa4,0x49,0x55,0x3, 0xdb,0x12,0xa3,0x7e,0xe4,0x33,0x22,0x7c,0x3b, +0xd2,0x2, 0x12,0xa6,0x6f,0x12,0xa6,0x52,0x1b,0x30,0x68,0x1d,0x1b,0x30,0x68,0x23, +0x1b,0x30,0x68,0x29,0x1b,0x30,0x68,0x2f,0xb, 0x32,0x78,0x73,0x12,0x35,0x38,0x7e, +0x1f,0x3, 0xb3,0x7e,0xf, 0x3, 0xaf,0x80,0x52,0x7e,0x1f,0x3, 0xbb,0x7e,0xf, 0x3, +0xb7,0x80,0x48,0x7e,0x1f,0x3, 0xc3,0x7e,0xf, 0x3, 0xbf,0x80,0x3e,0x7e,0x1f,0x3, +0xcb,0x7e,0xf, 0x3, 0xc7,0x80,0x34,0x7e,0x34,0x0, 0x8, 0xca,0x39,0x7e,0x71,0x13, +0x74,0x8, 0xac,0x7b,0x2e,0x34,0x3, 0xaf,0x6d,0x22,0x7e,0x8, 0x49,0x49,0x12,0x16, +0x35,0x1b,0xfd,0x7e,0x34,0x0, 0x1, 0x7a,0x37,0x49,0x49,0x7e,0x73,0x4f,0x98,0x7a, +0x73,0x49,0x4b,0x7e,0x1f,0x49,0x4d,0x7e,0xf, 0x49,0x49,0x7a,0x1d,0x42,0x7a,0xd, +0x3e,0x12,0x2, 0x3d,0x74,0x1, 0x7a,0xb3,0x3, 0xd2,0x12,0xd, 0xbd,0x80,0x2, 0xc2, +0x2, 0xa2,0x2, 0x22,0x7e,0xb3,0x3, 0xd2,0xb4,0x1, 0x2, 0x80,0x2, 0x81,0xb7,0x7e, +0x73,0x3, 0xcf,0xbe,0x73,0x3, 0xd1,0x28,0x74,0x7e,0x63,0x3, 0xd1,0x7e,0x70,0x7, +0xac,0x67,0x49,0x53,0x3, 0xdb,0x7c,0xab,0x7e,0x43,0x3, 0xd8,0x7e,0x50,0x2, 0xac, +0x45,0x2d,0x32,0x49,0x33,0x3, 0xdd,0x7a,0x35,0x11,0x4d,0x33,0x68,0x4f,0xd2,0x2f, +0x1b,0xa0,0x68,0x10,0x1b,0xa0,0x68,0xc, 0x1b,0xa0,0x68,0x8, 0x1b,0xa0,0x68,0x4, +0xb, 0xa2,0x78,0x39,0x12,0xa4,0xb8,0x30,0x14,0x4, 0x74,0x2, 0x80,0x2, 0x74,0x1, +0x7e,0xa3,0x3, 0xd8,0xa, 0x3a,0x19,0xb3,0x3, 0xd3,0x7e,0xb3,0x3, 0xd8,0x70,0xe, +0x7e,0x73,0x3, 0xda,0xbe,0x70,0x1, 0x28,0x5, 0x12,0xb, 0xe5,0x80,0xf, 0x7e,0xf, +0x4f,0xa1,0xb, 0x16,0xb, 0xa, 0x30,0x5e,0x60,0xef,0x1b,0xa, 0x30,0x12,0xa3,0x5d, +0x38,0x15,0x74,0x2, 0x7a,0xb3,0x3, 0xd2,0xc2,0x2a,0x12,0x1b,0xed,0x12,0x1f,0xea, +0xe5,0x13,0x70,0x3, 0x2, 0x35,0x1, 0x22,0xca,0x69,0xca,0xf8,0x7e,0xd5,0x11,0x6d, +0xcc,0x7e,0xf3,0x3, 0xd8,0x7e,0xb3,0x40,0x21,0x60,0xa, 0x7e,0x47,0x40,0x15,0x7e, +0xf7,0x40,0x17,0x80,0x8, 0x7e,0xf7,0x40,0x15,0x7e,0x47,0x40,0x17,0x20,0x2f,0x2, +0xc1,0x1a,0x7e,0x17,0x44,0x81,0x7e,0x24,0x0, 0xa, 0xa9,0xd7,0xea,0x7e,0x5f,0x1, +0x5f,0x69,0x55,0x2, 0x64,0x69,0xe5,0x0, 0xc, 0x4d,0xe5,0x7e,0xd0,0x8, 0xac,0xdf, +0x59,0xe6,0x0, 0xcb,0x69,0xe5,0x2, 0x5c,0x69,0x55,0x0, 0x4, 0x4d,0x5e,0x59,0x56, +0x0, 0xcd,0x69,0xe5,0x2, 0x5a,0x69,0x55,0x0, 0x2, 0xbd,0x5e,0x28,0x8, 0x69,0x55, +0x0, 0x2, 0x7d,0x35,0x80,0x4, 0x69,0x35,0x2, 0x5a,0x74,0x8, 0xac,0xbf,0x59,0x35, +0x0, 0xcf,0xb, 0x5a,0x50,0x12,0xa6,0x3c,0x19,0xa3,0x0, 0xd1,0x69,0x55,0x2, 0x58, +0x12,0xa6,0x3c,0x19,0xa3,0x0, 0xd2,0x6d,0xee,0x7d,0x3e,0xbe,0x34,0x0, 0x1, 0x78, +0x4, 0xb, 0x24,0x80,0x23,0x7c,0xb7,0x7e,0xb4,0x0, 0x1, 0x60,0x5, 0x3e,0xb4,0x14, +0x78,0xfb,0x7e,0xb3,0x40,0x13,0xa, 0x5b,0x5d,0x5b,0x68,0x5, 0x12,0xa6,0x1f,0x80, +0x7, 0x6d,0x55,0x12,0xa6,0x2e,0xb, 0x24,0xb, 0x34,0xbe,0x34,0x0, 0x3, 0x78,0xcb, +0x7e,0xb3,0x40,0x21,0x60,0x4, 0x7d,0x4, 0x80,0x2, 0x7d,0xe, 0x7d,0x3e,0x80,0x18, +0x7d,0x53,0x2d,0x52,0x3e,0x54,0x7e,0x5f,0x1, 0x5f,0x2d,0xb5,0xb, 0x5a,0x50,0x7d, +0xb0,0xb, 0x4, 0x12,0xa6,0x32,0xb, 0x34,0xbd,0xf3,0x38,0xe4,0x7e,0x24,0x1, 0x36, +0x7d,0x3e,0xbe,0x34,0x0, 0x1, 0x78,0x4, 0xb, 0x24,0x80,0x23,0x7c,0xb7,0x7e,0xb4, +0x0, 0x1, 0x60,0x5, 0x3e,0xb4,0x14,0x78,0xfb,0x7e,0xb3,0x40,0x14,0xa, 0x5b,0x5d, +0x5b,0x68,0x5, 0x12,0xa6,0x1f,0x80,0x7, 0x6d,0x55,0x12,0xa6,0x2e,0xb, 0x24,0xb, +0x34,0xbe,0x34,0x0, 0x3, 0x78,0xcb,0x7e,0xb3,0x40,0x21,0x60,0x2, 0x7d,0xe, 0x7d, +0x3e,0x80,0x1e,0x7d,0x52,0xb, 0x24,0x3e,0x54,0x7e,0x5f,0x1, 0x5f,0x2d,0xb5,0xb, +0x5a,0x50,0x7d,0xe0,0xb, 0x4, 0x3e,0xe4,0x7f,0x56,0x2d,0xbe,0x1b,0x5a,0x50,0xb, +0x34,0xbd,0x43,0x38,0xde,0xa9,0xc7,0xea,0xc2,0x2f,0xda,0xf8,0xda,0x69,0x22,0x7d, +0x52,0xb, 0x24,0x3e,0x54,0x7e,0x5f,0x1, 0x5f,0x2d,0xb5,0xb, 0x5a,0x50,0x7d,0xb1, +0xb, 0x14,0x3e,0xb4,0x2d,0xbd,0x7d,0xac,0x1b,0x5a,0x50,0x22,0x5e,0x54,0x0, 0x7f, +0x7c,0xab,0x7e,0x70,0x8, 0xac,0x7f,0x22,0x7e,0x70,0x7, 0xac,0x7a,0x9, 0xb3,0x3, +0xe1,0x22,0x6c,0xaa,0x7e,0xb3,0x4f,0x4c,0xa, 0x3b,0x1e,0x34,0xb, 0x34,0x7e,0x50, +0x8, 0xac,0x5a,0x19,0x72,0x3, 0xb4,0xb, 0xa0,0xbe,0xa0,0x4, 0x40,0xe6,0x22,0xe5, +0x13,0x70,0x21,0x7e,0x37,0x4f,0x52,0x4d,0x33,0x78,0xf8,0x12,0x69,0xbd,0x7e,0x34, +0x0, 0x5, 0x7a,0x37,0x4f,0x52,0xbe,0x34,0x0, 0x21,0x28,0x8, 0x7e,0x34,0x0, 0x21, +0x7a,0x37,0x4f,0x52,0x22,0x12,0xa6,0xf6,0xe5,0x13,0x70,0x5, 0x12,0x36,0x22,0x80, +0x3, 0x12,0x37,0xc9,0x2, 0xa6,0xa7,0x6c,0x77,0x7e,0x30,0x3b,0x7e,0xa0,0x3c,0x7e, +0xb3,0x4d,0x9e,0xb4,0x1, 0xf, 0xe5,0x13,0x60,0xb, 0x7e,0x23,0x4f,0x9c,0xbc,0x27, +0x78,0x3, 0x12,0xa7,0xc2,0x7e,0xb3,0x4d,0x9e,0xb4,0x1, 0x29,0xe5,0x13,0x60,0x25, +0x7e,0xb3,0x4f,0x9c,0xbc,0xb3,0x78,0x3, 0x12,0x4f,0x71,0x7e,0xb3,0x4f,0x9c,0x7a, +0xb3,0x4f,0x99,0x4, 0x7a,0xb3,0x4f,0x9c,0x7e,0x73,0x4f,0x9c,0xbc,0x7a,0x28,0x5, +0xe4,0x7a,0xb3,0x4f,0x9c,0x22,0x30,0x22,0x24,0xc2,0x22,0x7e,0x73,0x4d,0x77,0x7a, +0x73,0x4d,0x9e,0x74,0xff,0x7a,0xb3,0x4d,0x77,0x7e,0xa3,0x4d,0x9e,0x4c,0xaa,0x78, +0x5, 0x12,0x4f,0x64,0x80,0x7, 0xbe,0xa0,0x1, 0x78,0x2, 0xd2,0x1c,0x30,0x1c,0x3, +0x12,0xa7,0x89,0x7e,0xb3,0x4d,0x9e,0x14,0x68,0x35,0x1b,0xb1,0x68,0x39,0x24,0x3, +0x78,0x48,0x12,0xa7,0x81,0x38,0x7, 0x7e,0xb3,0x4f,0x8c,0xb4,0x1, 0x3, 0x2, 0x4f, +0x5d,0x7e,0xb3,0x4d,0x7f,0x30,0xe0,0x38,0x7e,0x17,0x4f,0x9a,0x7e,0x4, 0x3, 0xe8, +0x8d,0x10,0x7e,0x73,0x4d,0x80,0xa, 0x37,0xbd,0x13,0x40,0x24,0x2, 0xa7,0x89,0x12, +0xa7,0x81,0x28,0x1c,0x2, 0x4f,0xf9,0x7e,0x34,0x13,0x87,0x12,0x1d,0xf2,0x12,0x1d, +0x19,0x12,0x35,0xf0,0x12,0x1d,0xb8,0x2, 0x4f,0x64,0x74,0x1, 0x7a,0xb3,0x4d,0x9e, +0x22,0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x0, 0x22,0xe5,0x13,0xb4,0x1, 0xc, 0x7e,0xb3, +0x24,0x27,0x60,0x6, 0xe4,0x7a,0xb3,0x4d,0x9e,0x22,0xc2,0x1c,0x74,0x1, 0x7a,0xb3, +0x4d,0x9e,0x12,0x4f,0x5d,0xe4,0x7a,0xb3,0x4f,0x9c,0x7a,0xb3,0x4f,0x99,0x12,0x33, +0x91,0x5e,0x34,0x0, 0x2, 0x68,0xa, 0x7e,0xb3,0x44,0x80,0x44,0x8, 0x7a,0xb3,0x44, +0x80,0x22,0x12,0x33,0x91,0x5e,0x34,0x0, 0x1, 0x68,0x4, 0xd2,0x1b,0xc2,0x1e,0x22, +0x80,0x3, 0x12,0x37,0x84,0x30,0x16,0xfa,0x22,0xc2,0x1d,0x22,0xd2,0x2, 0x12,0x45, +0xf2,0x12,0x0, 0x1e,0x70,0xfb,0x22,0x30,0x1b,0x2a,0xc2,0x1b,0xd2,0x1d,0x12,0x33, +0x91,0x5e,0x34,0x0, 0x2, 0x74,0x1, 0x68,0x5, 0x12,0x5, 0x30,0x80,0x3, 0x12,0x2d, +0x29,0x7e,0x34,0x0, 0x1, 0x7e,0xa1,0x13,0x74,0x8, 0xa4,0x59,0x35,0x3, 0xaf,0xe5, +0x13,0x2, 0x2f,0xb7,0x30,0x1e,0x33,0xc2,0x1e,0xc2,0x1d,0x12,0x33,0x91,0x5e,0x34, +0x0, 0x2, 0x74,0x1, 0x68,0x5, 0x12,0x5, 0xbc,0x80,0x3, 0x12,0x2d,0x29,0x7e,0xb3, +0x4f,0x4d,0xb4,0x1, 0xe, 0x7e,0x34,0x0, 0x2, 0x7e,0xa1,0x13,0x74,0x8, 0xa4,0x59, +0x35,0x3, 0xaf,0xe5,0x13,0x12,0x2f,0xb7,0x80,0x7, 0x30,0x1d,0x4, 0xe5,0x13,0x70, +0x3, 0x2, 0x1c,0x24,0x22,0x30,0x1d,0x8, 0xe5,0x13,0xb4,0x1, 0x3, 0x2, 0x1c,0x24, +0x22,0x7c,0xab,0x7e,0x8, 0x0, 0x6d,0x7e,0x70,0xa, 0xac,0x7a,0x9, 0xb3,0x4c,0x47, +0x12,0xc, 0x3e,0x7e,0x8, 0x0, 0xa9,0x74,0xa, 0xa4,0x9, 0xb5,0x4c,0x47,0x12,0xc, +0x3e,0x7e,0x34,0x0, 0xd, 0x7e,0x8, 0x0, 0x6d,0x7e,0x24,0x0, 0x1, 0x2, 0xc, 0xcc, +0xca,0xd8,0xca,0x79,0x7c,0xf7,0x7c,0xeb,0xe4,0x12,0x4f,0xc9,0x6c,0xdd,0x7e,0x70, +0xb5,0xac,0x7d,0x2e,0x34,0x1, 0x0, 0x2e,0x34,0x0, 0x16,0x7a,0x35,0x29,0x12,0x7, +0x40,0x7a,0x35,0x2b,0x7e,0x35,0x29,0x12,0x8, 0x0, 0x7a,0x35,0x2d,0x7e,0x25,0x2b, +0x5e,0x50,0xf8,0x7a,0x25,0x2b,0x5e,0x70,0xf8,0x7a,0x35,0x2d,0x7c,0xbe,0x54,0x5, +0xa, 0x3b,0x4e,0x35,0x2b,0x7a,0x35,0x2b,0x7c,0xbf,0x54,0x5, 0xa, 0x3b,0x4e,0x35, +0x2d,0x7a,0x35,0x2d,0x7e,0x35,0x29,0x7e,0x25,0x2b,0x12,0x6, 0x48,0x7e,0x35,0x29, +0x7e,0x25,0x2d,0x12,0x6, 0xc5,0xb, 0xd0,0xbe,0xd0,0x3, 0x40,0xa1,0xda,0x79,0xda, +0xd8,0x22,0x7c,0xab,0x74,0x27,0xa4,0x49,0x25,0x4b,0xa9,0xb, 0x24,0x7e,0x37,0x4e, +0x45,0xad,0x32,0x7e,0x8, 0x0, 0x69,0x12,0xa9,0x1d,0x2, 0xc, 0xcc,0x6d,0x22,0x12, +0xd, 0x3e,0x7e,0x8, 0x0, 0xa5,0x6d,0x22,0x12,0xd, 0x3e,0x7e,0x34,0x0, 0xb, 0x7e, +0x8, 0x0, 0x69,0x7e,0x24,0x0, 0x2, 0x22,0x7c,0xab,0x6d,0x33,0xbe,0xa0,0x4, 0x50, +0x27,0x6c,0x55,0x80,0x16,0x7e,0x10,0x2, 0xac,0x15,0x7e,0x30,0x27,0xac,0x3a,0x2d, +0x10,0x49,0x11,0x4b,0xa9,0xb, 0x14,0x2d,0x31,0xb, 0x50,0x7e,0x30,0x27,0xac,0x3a, +0x9, 0x41,0x4b,0xa4,0xbc,0x45,0x50,0xdd,0x4d,0x33,0x78,0x2, 0xb, 0x34,0x22,0xbe, +0xb0,0x4, 0x50,0x37,0x7e,0x37,0x0, 0x85,0x5e,0x70,0xf0,0x7a,0x37,0x0, 0x85,0xa, +0x3b,0x4e,0x37,0x0, 0x85,0x7a,0x37,0x0, 0x85,0x7a,0x37,0x0, 0xc1,0x7e,0x34,0x0, +0x19,0x7e,0x8, 0x0, 0x85,0x7e,0x24,0x0, 0x1, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x19, +0x7e,0x8, 0x0, 0xc1,0x7e,0x24,0x0, 0x1, 0x2, 0x4, 0x96,0x22,0x7c,0x1b,0x7e,0xa3, +0x44,0x85,0xc2,0x2, 0xa, 0xf1,0x7e,0xd4,0x2, 0x3c,0xad,0xdf,0x7d,0x3d,0x12,0xaa, +0x22,0x6d,0x22,0x6d,0x11,0x7d,0x41,0x80,0x10,0x7d,0xed,0x2d,0xe4,0x9, 0xbe,0x31, +0x9d,0x70,0x4, 0xd2,0x2, 0x80,0xa, 0xb, 0x44,0x7e,0xe7,0x44,0x81,0xbd,0xe4,0x38, +0xe8,0x7d,0x41,0x7c,0xba,0x54,0x1, 0xb4,0x1, 0x13,0x7d,0x14,0x3e,0x14,0x2d,0x13, +0x7d,0x2, 0xb, 0xa, 0x10,0x4d,0x11,0x78,0x4, 0xd2,0x2, 0x80,0xa, 0x1e,0xa0,0xb, +0x44,0xbe,0x44,0x0, 0x4, 0x40,0xdc,0x30,0x2, 0x10,0x7e,0xb3,0x4f,0x97,0xbe,0xb0, +0x0, 0x28,0xd, 0x14,0x7a,0xb3,0x4f,0x97,0xc3,0x22,0x74,0x5, 0x7a,0xb3,0x4f,0x97, +0xd3,0x22,0x2e,0x37,0x44,0x81,0x2e,0x34,0x31,0x9d,0x22,0xca,0x79,0x7c,0x5b,0x7e, +0x40,0xff,0x7e,0xa0,0xff,0x6c,0x33,0x41,0xbf,0xbc,0x63,0x78,0x2, 0x41,0xbd,0x7e, +0x90,0x2, 0xac,0x93,0x9, 0x24,0x3c,0xc9,0xa, 0xf2,0xa, 0x5, 0x9d,0xf, 0xbe,0x4, +0x0, 0x0, 0x8, 0xc, 0xa, 0xe2,0xa, 0xf5,0x9d,0xfe,0x7d,0x7f,0x7c,0x2f,0x80,0x8, +0x6e,0x4, 0xff,0xff,0xb, 0x4, 0x7c,0x21,0x7e,0x10,0x2, 0xac,0x13,0x9, 0xb0,0x3c, +0xca,0xa, 0xb, 0xa, 0x47,0x9d,0x40,0xbe,0x44,0x0, 0x0, 0x8, 0x8, 0xa, 0xfb,0xa, +0x7, 0x9d,0xf, 0x80,0x4, 0x6d,0x0, 0x9d,0x4, 0xbe,0x20,0x1, 0x38,0xa, 0xbe,0x10, +0x1, 0x38,0x5, 0x7e,0xa0,0x1, 0x80,0x31,0xbe,0x20,0x2, 0x38,0xa, 0xbe,0x10,0x2, +0x38,0x5, 0x7e,0x40,0x2, 0x80,0x10,0x30,0x0, 0xd, 0xbe,0x20,0x3, 0x38,0x8, 0xbe, +0x10,0x3, 0x38,0x3, 0x7e,0x40,0x3, 0xbc,0x4a,0x50,0x2, 0x7c,0xa4,0xb, 0x30,0x7e, +0x3, 0x3e,0x53,0xbc,0x3, 0x28,0x2, 0x41,0x39,0x7c,0xba,0xda,0x79,0x22,0xe4,0x7a, +0xb3,0x3e,0x68,0x12,0xaa,0xea,0xe4,0x12,0x77,0xb2,0x7e,0xb3,0x24,0x26,0xb4,0x1, +0x8, 0x7e,0x73,0x3e,0x53,0x7a,0x73,0x3e,0x67,0x22,0x6c,0x33,0x80,0x9, 0xe4,0xa, +0x33,0x19,0xb3,0x3d,0x41,0xb, 0x30,0x90,0x13,0x80,0xe4,0x93,0xc4,0x23,0x54,0x1f, +0xa, 0x2b,0xb, 0x24,0xa, 0x33,0xbd,0x32,0x48,0xe4,0x12,0xac,0x2a,0x6d,0x33,0x7a, +0x37,0x3e,0x55,0x7a,0x37,0x3e,0x57,0x7a,0x37,0x3e,0x59,0x7a,0x37,0x3e,0x5d,0x7e, +0xd4,0x44,0x89,0x1e,0xd4,0x3e,0xd4,0x6d,0xcc,0x7e,0x1f,0x22,0xe0,0x7a,0x37,0x44, +0xc9,0x7d,0x3d,0x7a,0x37,0x44,0xcd,0x7e,0x34,0x23,0x34,0x7a,0x37,0x44,0xcb,0x7e, +0x73,0x40,0xf, 0x7a,0x73,0x44,0xc6,0x7e,0x73,0x40,0x10,0x7a,0x73,0x44,0xc5,0x7e, +0x37,0x3f,0xed,0x7a,0x37,0x44,0xcf,0x7e,0x37,0x3f,0xef,0x7a,0x37,0x44,0xd1,0x7e, +0x37,0x3f,0xf7,0x7a,0x37,0x44,0xd3,0x7e,0x37,0x3f,0xf9,0x7a,0x37,0x44,0xd5,0x12, +0x84,0xfa,0x1b,0x34,0x7a,0x73,0x44,0xc7,0x7e,0x73,0x4f,0xb1,0x7a,0x73,0x44,0xc8, +0x7e,0x8, 0x44,0xc5,0x7e,0x18,0x44,0xd7,0x12,0x3, 0x1d,0x7e,0x73,0x44,0xd7,0x7a, +0x73,0x3e,0x53,0x7e,0x73,0x44,0xd8,0x7a,0x73,0x3e,0x54,0x7e,0x37,0x44,0xd9,0x7a, +0x37,0x3e,0x55,0x7e,0x37,0x44,0xdb,0x7a,0x37,0x3e,0x57,0x7e,0x37,0x44,0xe1,0x7a, +0x37,0x3e,0x59,0x7e,0x37,0x44,0xe3,0x7d,0x23,0x7a,0x53,0x3e,0x5b,0xa, 0x36,0x7a, +0x73,0x3e,0x5c,0x7e,0x37,0x44,0xdd,0x7a,0x37,0x3e,0x5d,0x7e,0x37,0x44,0xdf,0x7d, +0x23,0x7a,0x53,0x3e,0x5f,0xa, 0x36,0x7a,0x73,0x3e,0x60,0x6c,0x33,0x80,0x1b,0x12, +0x26,0xf6,0x74,0x2, 0xac,0xb3,0x49,0x45,0x23,0x34,0xa, 0x38,0x7c,0x27,0x19,0x25, +0x3c,0xc9,0x7c,0x29,0x19,0x25,0x3c,0xca,0xb, 0x30,0x7e,0x23,0x3e,0x53,0xbc,0x23, +0x38,0xdd,0x6c,0x33,0x80,0x1b,0x74,0x2, 0xac,0xb3,0x7f,0x16,0x2d,0x35,0xb, 0x1a, +0x40,0xa, 0x38,0x7c,0x27,0x19,0x25,0x3d,0x5, 0x7c,0x29,0x19,0x25,0x3d,0x6, 0xb, +0x30,0x7e,0x23,0x3e,0x54,0xbc,0x23,0x38,0xdd,0x22,0xe4,0x7a,0xb3,0x3e,0x53,0x7a, +0xb3,0x3e,0x54,0x22,0x7e,0x34,0x1, 0x16,0x7e,0x8, 0x44,0x87,0x7e,0x24,0x0, 0x12, +0x12,0x3, 0xfa,0x7e,0x34,0x1, 0x16,0x7e,0x8, 0x44,0xab,0x7e,0x24,0x0, 0x12,0x12, +0x4, 0x96,0x12,0x1c,0x24,0xd2,0x2, 0x12,0x45,0xf2,0x7e,0x34,0x4, 0x68,0x22,0x3e, +0x24,0x2e,0x24,0x46,0xf1,0xb, 0x28,0x30,0x4d,0x31,0x1b,0x28,0x30,0x22,0x75,0x13, +0x2, 0x74,0x2, 0x7a,0xb3,0x4f,0x55,0x74,0x1, 0x2, 0x5, 0xbc,0x69,0x32,0x0, 0x2, +0x7d,0x13,0x5e,0x14,0x0, 0xf, 0x3e,0x14,0x3e,0x14,0xa, 0x24,0x5e,0x24,0x0, 0x3, +0x4d,0x21,0x22,0x6d,0x33,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x16,0x7e,0x34,0x1, +0x2c,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x18,0x22,0x7a,0xb3,0x3, 0xd3,0x7a,0xb3, +0x3, 0xd4,0x7a,0xb3,0x3, 0xd7,0x74,0xff,0x7a,0xb3,0x3, 0xd8,0x22,0x7d,0x36,0x3e, +0x34,0x49,0x73,0x40,0x22,0x22,0x7e,0x8, 0x44,0x87,0x7e,0x34,0x0, 0x48,0x22,0xa, +0x25,0x2d,0x21,0x7d,0x13,0x1e,0x14,0x3e,0x14,0x59,0x21,0x47,0x39,0xb, 0x35,0x22, +0x7e,0x37,0x3f,0xef,0x7e,0x14,0x0, 0x6, 0xad,0x31,0x7e,0x44,0x0, 0x4, 0x7d,0x24, +0x22,0x74,0x2, 0xac,0xbd,0x9, 0xf5,0x3c,0xc9,0x9, 0xe5,0x3c,0xca,0x7c,0xbf,0x7c, +0x7e,0x22,0x7e,0x57,0x44,0x81,0x3e,0x54,0x7e,0x1f,0x22,0xe0,0x2d,0x35,0xb, 0x1a, +0x50,0x22,0x12,0x6, 0x48,0x6d,0x33,0x7e,0x27,0x44,0xcf,0x22,0x7e,0x34,0x0, 0x2, +0x7e,0x27,0x44,0xd3,0x5e,0x40,0x9c,0x4e,0x40,0x21,0x22,0x7e,0x18,0xc, 0xd0,0x7e, +0x8, 0x44,0xe1,0x22,0x3e,0x24,0x2e,0x24,0x44,0xab,0x22,0x74,0x2, 0xac,0xb1,0x9, +0x95,0x3c,0xc9,0x9, 0x5, 0x3c,0xca,0x22,0x7e,0x73,0x40,0x10,0xa, 0x37,0x22,0x7e, +0x34,0x0, 0x17,0x7e,0x27,0x44,0xd7,0x5e,0x24,0xe0,0x3f,0x22,0x7e,0x34,0x0, 0x1, +0x7e,0x27,0x44,0xd1,0x5e,0x24,0x80,0x0, 0x22,0x7e,0x34,0x1, 0x6, 0x7e,0x27,0x44, +0xdb,0x5e,0x24,0xfc,0x0, 0x22,0x49,0x35,0x4c,0x4e,0x49,0x25,0x4c,0x4c,0x2, 0x9, +0xad,0x2e,0x34,0x4b,0xa9,0x6d,0x22,0x74,0x10,0x2, 0xb, 0x8, 0x7e,0xf1,0x46,0x74, +0xb5,0xac,0xfb,0x2e,0x74,0x1, 0x0, 0x22,0x7a,0xb3,0x3, 0xd0,0x74,0xff,0x7a,0xb3, +0x3, 0xd1,0xe4,0x22,0xe5,0x27,0xa, 0x5b,0xb, 0x54,0xf5,0x2a,0x85,0x27,0x2b,0x22, +0x7e,0x34,0x2, 0x34,0x7a,0x35,0x29,0x22,0x7e,0x34,0x0, 0x8, 0x7e,0x27,0x44,0xd5, +0x4e,0x40,0x40,0x22,0x9d,0x32,0x12,0x16,0x6c,0xbe,0x34,0x0, 0x2, 0x22,0x9, 0x73, +0x4b,0xa4,0x2, 0xd, 0x23,0x7e,0x24,0x0, 0x12,0x2, 0x4, 0x96,0x7e,0xb3,0x4e,0x19, +0xbe,0xb0,0x1, 0x22,0x7e,0xb3,0x4f,0x55,0x7e,0x70,0x2, 0x22,0xc2,0x6, 0x7c,0xb1, +0x2, 0x26,0xfa,0x7e,0xb3,0x40,0x3, 0xbe,0xb0,0x1, 0x22,0x12,0x6, 0x48,0x7e,0x34, +0x1, 0x2, 0x22,0x12,0x6, 0xc5,0x7e,0x34,0x1, 0x2, 0x22,0x12,0x6, 0x48,0x7e,0x34, +0x1, 0x1, 0x22,0x12,0x6, 0xc5,0x7e,0x34,0x1, 0x1, 0x22,0x12,0x6, 0x48,0x7e,0x34, +0x1, 0x0, 0x22,0xff, \ No newline at end of file diff --git a/drivers/input/touchscreen/focaltech_touch_n10/include/firmware/FT8716_app_sample.i b/drivers/input/touchscreen/focaltech_touch_n10/include/firmware/FT8716_app_sample.i new file mode 100644 index 0000000000000000000000000000000000000000..ce504111e7ff10400267904dca3966fdec6a807d --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/include/firmware/FT8716_app_sample.i @@ -0,0 +1,2787 @@ +0x2, 0x15,0xb8,0x2, 0xa0,0xba,0x1b,0xa, 0x30,0x22,0x22,0x2, 0x0, 0x19,0x0, 0x1, +0x1, 0x0, 0x22,0x2, 0x57,0x2c,0xeb,0xaa,0x8, 0x32,0xff,0x2, 0x54,0xe7,0xa2,0x93, +0xe4,0x33,0x22,0x2, 0x1a,0x3e,0x2, 0x3f,0x7a,0xff,0xff,0x2, 0x57,0xf1,0xca,0x3b, +0x7d,0x72,0x7d,0x63,0x7d,0x27,0x12,0x6, 0x48,0x7d,0x36,0x7d,0x27,0x12,0x6, 0xc5, +0xda,0x3b,0x22,0x2, 0x58,0x1d,0x7f,0x71,0xa9,0xd6,0xcb,0x69,0x30,0x0, 0x4, 0x7e, +0x6f,0x4f,0x9d,0x79,0x36,0x0, 0x4, 0x69,0x30,0x0, 0x6, 0x7e,0x6f,0x4f,0x9d,0x79, +0x36,0x0, 0x6, 0x69,0x30,0x0, 0x8, 0x7e,0x6f,0x4f,0x9d,0x79,0x36,0x0, 0x8, 0x7e, +0x7b,0xa0,0x7c,0x6a,0x6c,0x77,0x7e,0x6f,0x4f,0x9d,0x79,0x36,0x0, 0xe, 0x7c,0x4b, +0x6c,0x55,0xe5,0x27,0xa, 0x3b,0x4d,0x32,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0x10, +0x29,0x77,0x0, 0x2, 0xa, 0x37,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x29,0x57, +0x0, 0x4, 0x7c,0x46,0x4c,0x57,0x7e,0x2f,0x4f,0x9d,0x2e,0x54,0x0, 0xe, 0xb, 0x2a, +0x30,0x4d,0x32,0x1b,0x2a,0x30,0x29,0x77,0x0, 0x1, 0x7c,0x47,0x6c,0x55,0x29,0x77, +0x0, 0x3, 0x7c,0x64,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0xa, 0x7e,0xb, 0x70,0x7c, +0x47,0x29,0x70,0x0, 0x1, 0xa, 0x37,0x2d,0x32,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, +0xc, 0x6d,0x11,0x7e,0x1f,0x4f,0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0x30,0x12,0xa, +0x5e,0xa9,0xc6,0xcb,0x22,0x1, 0x2, 0x4, 0x8, 0x10,0x20,0x40,0x80,0xb2,0x86,0x22, +0xae,0x24,0x51,0xdb,0xfd,0xf0,0x2, 0xf, 0xeb,0x7b,0x14,0x84,0xe0,0x1f,0xd, 0xf2, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x87,0xa6, +0xca,0x3b,0x7f,0x30,0x7e,0x3b,0xb0,0xf5,0x2d,0x29,0xb3,0x0, 0x1, 0xbe,0xb1,0x2d, +0x28,0x2, 0xf5,0x2d,0x69,0x13,0x0, 0x6, 0x6d,0x0, 0x7e,0x34,0x0, 0xf2,0x74,0xff, +0x12,0x16,0x5a,0x7f,0x3, 0x12,0xa, 0x6, 0xa9,0xd6,0xcb,0x75,0x2b,0x0, 0x80,0x33, +0x75,0x2c,0x0, 0x80,0x23,0x7e,0x11,0x2b,0x74,0xb, 0xac,0x1b,0xe5,0x2c,0xa, 0x1b, +0x2d,0x1, 0x3e,0x4, 0x69,0x13,0x0, 0x6, 0x2d,0x10,0x6d,0x0, 0xb, 0xa, 0x30,0x6e, +0x34,0xff,0xff,0x1b,0xa, 0x30,0x5, 0x2c,0x29,0x73,0x0, 0x1, 0xbe,0x71,0x2c,0x38, +0xd4,0x5, 0x2b,0x7e,0x3b,0x70,0xbe,0x71,0x2b,0x38,0xc5,0x69,0x33,0x0, 0x6, 0x7e, +0xf, 0x4f,0x9d,0x79,0x30,0x0, 0x4, 0xe5,0x2d,0xa, 0x2b,0x7d,0x32,0x7c,0x67,0x6c, +0x77,0x2d,0x32,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0xc, 0x6d,0x11,0x7e,0x1f,0x4f, +0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0xd0,0x12,0xa, 0x5e,0x75,0x2b,0x0, 0xe5,0x2b, +0xbe,0xb0,0x4, 0x50,0x17,0x7e,0xa1,0x2b,0x74,0x4, 0xa4,0x7e,0x1f,0x4f,0x9d,0x69, +0x11,0x0, 0x26,0x60,0x44,0x1e,0x14,0x14,0x78,0xfb,0x80,0x3d,0xe5,0x2b,0xbe,0xb0, +0x8, 0x50,0x1b,0xe5,0x2b,0xa, 0x5b,0x1b,0x56,0x3e,0x54,0x3e,0x54,0x7e,0x1f,0x4f, +0x9d,0x69,0x11,0x0, 0x28,0x60,0x22,0x1e,0x14,0x14,0x78,0xfb,0x80,0x1b,0xe5,0x2b, +0xa, 0x5b,0x9e,0x54,0x0, 0x8, 0x3e,0x54,0x3e,0x54,0x7e,0x1f,0x4f,0x9d,0x69,0x11, +0x0, 0x2a,0x60,0x5, 0x1e,0x14,0x14,0x78,0xfb,0x5e,0x14,0x0, 0xf, 0x7e,0xa1,0x2b, +0x74,0x2, 0xa4,0x69,0x33,0x0, 0x6, 0x2d,0x35,0x6d,0x22,0x1b,0x1a,0x10,0x5, 0x2b, +0xe5,0x2b,0xbe,0xb0,0xb, 0x40,0x87,0xa9,0xc6,0xcb,0xda,0x3b,0x22,0x6d,0x33,0x7e, +0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x12,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x14,0xb, +0xa, 0x30,0x5e,0x60,0x7f,0x1b,0xa, 0x30,0xe5,0x40,0x54,0x1f,0xa, 0x2b,0x7e,0xf, +0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0xe5,0x41, +0x54,0x1, 0xa, 0x2b,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x7e,0xf, +0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0xe5,0x42, +0x54,0x3, 0xa, 0x2b,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24, +0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30, +0x7e,0x35,0x3e,0xbe,0x34,0x0, 0x2, 0x78,0x63,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, +0x14,0xb, 0xa, 0x30,0x4e,0x60,0x80,0x1b,0xa, 0x30,0xe5,0x43,0x54,0x1f,0x7c,0x4b, +0x6c,0x55,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x32,0x1b, +0xa, 0x30,0xe5,0x44,0x54,0x1, 0xa, 0x5b,0xc4,0x23,0x54,0xe0,0x7c,0xab,0xe4,0x7e, +0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x35,0x1b,0xa, 0x30,0xe5, +0x45,0x54,0x3, 0xa, 0x5b,0x3, 0x3, 0x54,0xc0,0x7c,0xab,0xe4,0x7e,0xf, 0x4f,0xa1, +0x2e,0x14,0x0, 0x12,0xb, 0xa, 0x30,0x4d,0x35,0x1b,0xa, 0x30,0x22,0x7f,0x21,0xa9, +0xd6,0xcb,0x69,0x30,0x0, 0x4, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0x4, 0x69,0x30, +0x0, 0x8, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0x6, 0x69,0x30,0x0, 0x6, 0x7e,0x7f, +0x4f,0x9d,0x79,0x37,0x0, 0x8, 0x29,0x70,0x0, 0x1, 0x7c,0x47,0x6c,0x55,0x7e,0xb, +0x70,0xa, 0x37,0x2d,0x32,0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0xc, 0x29,0x70,0x0, +0x2, 0xa, 0x37,0x1b,0x34,0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0xa, 0x69,0x30,0x0, +0xa, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0xe, 0x69,0x30,0x0, 0xc, 0x7e,0x7f,0x4f, +0x9d,0x79,0x37,0x0, 0x10,0x69,0x30,0x0, 0xe, 0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, +0x12,0x69,0x30,0x0, 0x10,0x7e,0x7f,0x4f,0x9d,0x79,0x37,0x0, 0x30,0x29,0x70,0x0, +0x3, 0x7c,0x27,0x6c,0x33,0x7e,0x1f,0x4f,0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0xa0, +0x12,0xa, 0x5e,0x7e,0x1f,0x4f,0x9d,0x69,0x11,0x0, 0x1a,0x7a,0x2b,0x30,0x69,0x11, +0x0, 0x1c,0x39,0x32,0x0, 0x1, 0x69,0x11,0x0, 0x16,0x79,0x12,0x0, 0x2, 0x69,0x11, +0x0, 0x18,0x79,0x12,0x0, 0x4, 0x69,0x11,0x0, 0x22,0x79,0x12,0x0, 0x6, 0x69,0x11, +0x0, 0x24,0x79,0x12,0x0, 0x8, 0x69,0x11,0x0, 0x1e,0x79,0x12,0x0, 0xa, 0x69,0x31, +0x0, 0x20,0x79,0x32,0x0, 0xc, 0xa9,0xc6,0xcb,0x22,0xca,0x3b,0x7a,0x25,0x51,0x7f, +0x30,0x7a,0x35,0x4f,0xa2,0xac,0x92,0xb, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31, +0x0, 0x4, 0x5e,0x34,0x10,0x0, 0x7a,0x37,0x49,0x63,0xc2,0xc, 0x12,0xc, 0x17,0xa2, +0xb, 0x92,0xac,0xa9,0xd3,0xcb,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f, +0x6f,0x79,0x30,0x0, 0x6, 0x7e,0xf, 0x4f,0x6f,0x69,0x30,0x0, 0x6, 0x4d,0x33,0x78, +0xf4,0x7e,0x35,0x4f,0x2e,0x34,0x80,0x0, 0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0x6f,0x69, +0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6d,0x33,0x80,0x20,0x7d,0x23,0x3e,0x24,0x7f, +0x3, 0x2d,0x12,0xb, 0xa, 0x20,0x7e,0xf, 0x4f,0x6f,0x1b,0xa, 0x20,0x7e,0xf, 0x4f, +0x6f,0x69,0x20,0x0, 0x8, 0x4d,0x22,0x68,0xf4,0xb, 0x34,0xbe,0x35,0x51,0x40,0xdb, +0xa9,0xc5,0xcb,0xa9,0xc3,0xcb,0x7e,0x37,0x49,0x63,0x2e,0x34,0xff,0xff,0x92,0xc, +0x12,0xc, 0x17,0xda,0x3b,0x22,0xca,0x3b,0x7a,0x25,0x51,0x7f,0x30,0x7a,0x35,0x4f, +0xa2,0xac,0x92,0xb, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x4, 0x5e,0x34, +0x10,0x0, 0x7a,0x37,0x49,0x63,0xc2,0xc, 0x12,0xc, 0x17,0xa2,0xb, 0x92,0xac,0xd2, +0xcd,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x73,0x79,0x30,0x0, 0x6, +0x7e,0xf, 0x4f,0x73,0x69,0x30,0x0, 0x6, 0x4d,0x33,0x78,0xf4,0x7e,0x35,0x4f,0x2e, +0x34,0x80,0x0, 0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0x73,0x69,0x31,0x0, 0x8, 0x4d,0x33, +0x68,0xf4,0x6d,0x33,0x80,0x20,0x7d,0x23,0x3e,0x24,0x7f,0x3, 0x2d,0x12,0xb, 0xa, +0x20,0x7e,0xf, 0x4f,0x73,0x1b,0xa, 0x20,0x7e,0xf, 0x4f,0x73,0x69,0x20,0x0, 0x8, +0x4d,0x22,0x68,0xf4,0xb, 0x34,0xbe,0x35,0x51,0x40,0xdb,0xa9,0xc5,0xcb,0xc2,0xcd, +0x7e,0x37,0x49,0x63,0x2e,0x34,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17,0xda,0x3b,0x22, +0xca,0x79,0x7c,0xab,0x6d,0x77,0x7e,0xf, 0x4f,0xa1,0x69,0x30,0x0, 0x6, 0x5e,0x34, +0x0, 0x2, 0x68,0x18,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b,0xa, +0x30,0x74,0x3, 0x7a,0xb3,0x4f,0x55,0x75,0x13,0x3, 0x80,0x3, 0xe4,0x80,0x5a,0x4c, +0xaa,0x68,0x54,0x80,0x44,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x6, 0x5e,0x34,0x0, +0x1, 0x78,0xa, 0xe4,0x7a,0xb3,0x4f,0x55,0x75,0x13,0x0, 0x80,0x3c,0x7e,0x34,0x0, +0x1, 0x12,0x53,0x12,0xb, 0x74,0xbe,0x74,0x3, 0xe8,0x28,0x1d,0x7e,0xf, 0x4f,0xa1, +0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70,0x4, 0x1b,0xa, 0x30,0x74,0x2, 0x7a, +0xb3,0x4f,0x55,0x75,0x13,0x2, 0xe4,0x80,0x10,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, +0xe, 0x5e,0x34,0x0, 0x3, 0x78,0xae,0x74,0x1, 0xda,0x79,0x22,0xca,0x79,0x7c,0xab, +0x6d,0x77,0x7e,0xf, 0x4f,0xa1,0x69,0x30,0x0, 0x6, 0x5e,0x34,0x0, 0x2, 0x68,0x18, +0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70,0x4, 0x1b,0xa, 0x30,0x74,0x2, 0x7a, +0xb3,0x4f,0x55,0x75,0x13,0x2, 0x80,0x3, 0xe4,0x80,0x5a,0x4c,0xaa,0x68,0x54,0x80, +0x44,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x6, 0x5e,0x34,0x0, 0x1, 0x78,0xa, 0xe4, +0x7a,0xb3,0x4f,0x55,0x75,0x13,0x0, 0x80,0x3c,0x7e,0x34,0x0, 0x1, 0x12,0x53,0x12, +0xb, 0x74,0xbe,0x74,0x3, 0xe8,0x28,0x1d,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0xe, +0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b,0xa, 0x30,0x74,0x3, 0x7a,0xb3,0x4f,0x55,0x75, +0x13,0x3, 0xe4,0x80,0x10,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0xe, 0x5e,0x34,0x0, +0x8, 0x68,0xae,0x74,0x1, 0xda,0x79,0x22,0xca,0x3b,0x7d,0x72,0x7d,0x63,0xa2,0xac, +0x92,0x3, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x4, 0x5e,0x34,0x10,0x0, +0x7a,0x37,0x49,0x49,0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x3, 0x92,0xac,0xa9,0xd3,0xcb, +0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x6f,0x79,0x30,0x0, 0x6, 0x7e, +0xf, 0x4f,0x6f,0x69,0x30,0x0, 0x6, 0x4d,0x33,0x78,0xf4,0x7d,0x36,0x2e,0x34,0x80, +0x0, 0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0x6f,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4, +0x1b,0x1a,0x70,0x7e,0x1f,0x4f,0x6f,0x69,0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0xa9, +0xc5,0xcb,0xa9,0xc3,0xcb,0x7e,0x37,0x49,0x49,0x2e,0x34,0xff,0xff,0x92,0xc, 0x12, +0xc, 0x17,0xda,0x3b,0x22,0xca,0x3b,0x7d,0x72,0x7d,0x63,0xa2,0xac,0x92,0x3, 0xc2, +0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x4, 0x5e,0x34,0x10,0x0, 0x7a,0x37,0x49, +0x49,0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x3, 0x92,0xac,0xd2,0xcd,0xa9,0xd5,0xcb,0x7e, +0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x73,0x79,0x30,0x0, 0x6, 0x7e,0xf, 0x4f,0x73,0x69, +0x30,0x0, 0x6, 0x4d,0x33,0x78,0xf4,0x7d,0x36,0x2e,0x34,0x80,0x0, 0x1b,0xa, 0x30, +0x7e,0x1f,0x4f,0x73,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4,0x1b,0x1a,0x70,0x7e, +0x1f,0x4f,0x73,0x69,0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0xa9,0xc5,0xcb,0xc2,0xcd, +0x7e,0x37,0x49,0x49,0x2e,0x34,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17,0xda,0x3b,0x22, +0xca,0x3b,0x7d,0x73,0xa2,0xac,0x92,0x0, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x61, +0x0, 0x4, 0x5e,0x64,0x10,0x0, 0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x0, 0x92,0xac,0xa9, +0xd3,0xcb,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x6f,0x79,0x30,0x0, +0x6, 0x7e,0x1f,0x4f,0x6f,0x69,0x11,0x0, 0x6, 0x4d,0x11,0x78,0xf4,0x1b,0x1a,0x70, +0x7e,0xf, 0x4f,0x6f,0x69,0x30,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6d,0x33,0x1b,0xa, +0x30,0x7e,0x1f,0x4f,0x6f,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4,0x69,0x71,0x0, +0x2, 0xa9,0xc5,0xcb,0xa9,0xc3,0xcb,0x2e,0x64,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17, +0x7d,0x37,0xda,0x3b,0x22,0x7e,0x8, 0x1, 0x63,0x7e,0x34,0x0, 0x18,0xe4,0x12,0x16, +0x5a,0xa9,0xd1,0xcb,0xd2,0xcc,0x7e,0x34,0x0, 0x4, 0x7e,0x8, 0x1, 0x63,0x74,0xc, +0x12,0xa, 0xb5,0xa9,0xd1,0xcb,0xc2,0xcc,0x6c,0xaa,0x7e,0x70,0x2, 0xac,0x7a,0x7e, +0x8, 0x1, 0x63,0x2d,0x13,0xb, 0xa, 0x20,0x7c,0x45,0x6c,0x55,0xb, 0xa, 0x30,0xa, +0x36,0x4d,0x32,0x1b,0xa, 0x30,0xb, 0xa0,0xbe,0xa0,0xc, 0x40,0xdd,0x22,0xff,0xff, +0xca,0x3b,0x7d,0x73,0xa2,0xac,0x92,0x0, 0xc2,0xac,0x7e,0x1f,0x4f,0xa1,0x69,0x61, +0x0, 0x4, 0x5e,0x64,0x10,0x0, 0xc2,0xc, 0x12,0xc, 0x17,0xa2,0x0, 0x92,0xac,0xd2, +0xcd,0xa9,0xd5,0xcb,0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x4f,0x73,0x79,0x30,0x0, 0x6, +0x7e,0x1f,0x4f,0x73,0x69,0x11,0x0, 0x6, 0x4d,0x11,0x78,0xf4,0x1b,0x1a,0x70,0x7e, +0xf, 0x4f,0x73,0x69,0x30,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6d,0x33,0x1b,0xa, 0x30, +0x7e,0x1f,0x4f,0x73,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4,0x69,0x71,0x0, 0x2, +0xa9,0xc5,0xcb,0xc2,0xcd,0x2e,0x64,0xff,0xff,0x92,0xc, 0x12,0xc, 0x17,0x7d,0x37, +0xda,0x3b,0x22,0xa9,0xd6,0xcb,0x69,0x30,0x0, 0x6, 0x7e,0x2f,0x4f,0x9d,0x79,0x32, +0x0, 0x4, 0x69,0x30,0x0, 0x8, 0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0x8, 0x29,0x70, +0x0, 0x2, 0x7c,0x47,0x6c,0x55,0x29,0x70,0x0, 0x3, 0xa, 0x37,0x2d,0x32,0x7e,0x2f, +0x4f,0x9d,0x79,0x32,0x0, 0xc, 0x7e,0xb, 0x70,0x7c,0x47,0x29,0x70,0x0, 0x1, 0xa, +0x37,0x2d,0x32,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0xa, 0x29,0x70,0x0, 0x4, 0xa, +0x37,0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0xe, 0x29,0xb0,0x0, 0x5, 0x54,0x1, 0x7c, +0x2b,0x6c,0x33,0x7e,0x1f,0x4f,0x9d,0x1b,0x1a,0x10,0x7e,0x34,0x0, 0xc0,0x12,0xa, +0x5e,0xa9,0xc6,0xcb,0x22,0xa9,0xd6,0xcb,0xc2,0x31,0x69,0x30,0x0, 0x4, 0x7e,0x2f, +0x4f,0x9d,0x79,0x32,0x0, 0x4, 0x69,0x30,0x0, 0x6, 0x7e,0x2f,0x4f,0x9d,0x79,0x32, +0x0, 0x6, 0x69,0x30,0x0, 0x8, 0x7e,0x2f,0x4f,0x9d,0x79,0x32,0x0, 0x8, 0x7e,0xb, +0x70,0x7c,0x47,0x6c,0x55,0x29,0x70,0x0, 0x1, 0xa, 0x37,0x2d,0x32,0x7e,0x2f,0x4f, +0x9d,0x79,0x32,0x0, 0xc, 0x29,0x70,0x0, 0x2, 0xa, 0x37,0x7e,0x2f,0x4f,0x9d,0x79, +0x32,0x0, 0xe, 0x29,0xb0,0x0, 0x3, 0x54,0x1, 0xa, 0x5b,0x7c,0xab,0xe4,0x7e,0x1f, +0x4f,0x9d,0x1b,0x1a,0x50,0x69,0x30,0x0, 0xa, 0x12,0xa, 0x5e,0xa9,0xc6,0xcb,0x22, +0xa9,0xd6,0xcb,0x69,0x20,0x0, 0x4, 0x7e,0x2f,0x4f,0x9d,0x79,0x22,0x0, 0x4, 0x69, +0x20,0x0, 0x8, 0x7e,0x2f,0x4f,0x9d,0x79,0x22,0x0, 0x8, 0x7e,0xb, 0x50,0xa, 0x55, +0x7c,0xab,0xe4,0x29,0x50,0x0, 0x1, 0xa, 0x25,0x2d,0x25,0x7e,0x2f,0x4f,0x9d,0x79, +0x22,0x0, 0xc, 0x29,0x50,0x0, 0x2, 0xa, 0x25,0x7e,0xf, 0x4f,0x9d,0x79,0x20,0x0, +0xe, 0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0xa, 0x6d,0x11,0x7e,0x1f,0x4f,0x9d,0x1b, +0x1a,0x10,0x7e,0x34,0x0, 0x40,0x12,0xa, 0x5e,0xa9,0xc6,0xcb,0x22,0xca,0x3b,0x6c, +0xaa,0x7e,0x90,0x2, 0xac,0x9a,0x7f,0x70,0x2d,0xf4,0xb, 0x7a,0x40,0x5e,0x80,0x3, +0x1b,0x7a,0x40,0x7e,0x90,0x6, 0xac,0x9a,0x7c,0xb9,0x7f,0x71,0x60,0xd, 0x1e,0xf4, +0x1e,0xe4,0x50,0x4, 0x4e,0xf4,0x80,0x0, 0x14,0x78,0xf3,0x7d,0x4f,0x5e,0x44,0x0, +0x3f,0x7d,0x74,0x7c,0xef,0x6c,0xff,0x3e,0x74,0x3e,0x74,0x7e,0xd0,0x2, 0xac,0xda, +0x7f,0x60,0x2d,0xd6,0xb, 0x6a,0xf0,0x4d,0xf7,0x1b,0x6a,0xf0,0xb, 0xa0,0xbe,0xa0, +0x4, 0x40,0xae,0xda,0x3b,0x22,0x7f,0x10,0xa9,0xd6,0xcb,0x69,0x11,0x0, 0x2, 0x7e, +0x2f,0x4f,0x9d,0x79,0x12,0x0, 0x4, 0x69,0x11,0x0, 0x4, 0x7e,0x2f,0x4f,0x9d,0x79, +0x12,0x0, 0x6, 0x69,0x11,0x0, 0x6, 0x7e,0x2f,0x4f,0x9d,0x79,0x12,0x0, 0x8, 0x7e, +0x1b,0x30,0xa, 0x3, 0x7e,0x14,0x1, 0x0, 0xad,0x10,0x29,0x71,0x0, 0x1, 0xa, 0x37, +0x2d,0x31,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0xc, 0x6d,0x11,0x7e,0x1f,0x4f,0x9d, +0x1b,0x1a,0x10,0x7e,0x34,0x0, 0x60,0x12,0xa, 0x5e,0xa9,0xc6,0xcb,0x22,0xa9,0xd7, +0xcb,0x7d,0x23,0x4e,0x50,0x1, 0x7e,0xf, 0x4f,0x9d,0xb, 0xa, 0x30,0x4d,0x32,0x1b, +0xa, 0x30,0x80,0x1e,0x7e,0xf, 0x4f,0x9d,0xb, 0xa, 0x30,0x7d,0x23,0x5e,0x24,0x0, +0x8, 0xbe,0x24,0x0, 0x8, 0x78,0xb, 0xa9,0xd7,0xcb,0x4e,0x70,0x4, 0x1b,0xa, 0x30, +0xd2,0x31,0x7e,0xf, 0x4f,0x9d,0xb, 0xa, 0x30,0x7d,0x23,0x5e,0x24,0x80,0x0, 0xbe, +0x24,0x80,0x0, 0x78,0xcf,0x4e,0x60,0x40,0x1b,0xa, 0x30,0x6d,0x11,0x7e,0x1f,0x4f, +0x9d,0x1b,0x1a,0x10,0x22,0x7e,0x24,0x0, 0x1, 0x7e,0x7f,0x4f,0x77,0x79,0x27,0x0, +0x6, 0x7e,0x7f,0x4f,0x77,0x69,0x27,0x0, 0x6, 0x4d,0x22,0x78,0xf4,0x5e,0x60,0x7f, +0x1b,0x7a,0x30,0x7e,0x1f,0x4f,0x77,0x69,0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6c, +0xaa,0x80,0x20,0x6d,0x44,0x7e,0x1f,0x4f,0x77,0x1b,0x1a,0x40,0x7e,0x1f,0x4f,0x77, +0x69,0x41,0x0, 0x8, 0x4d,0x44,0x68,0xf4,0x69,0x41,0x0, 0x2, 0x1b,0xa, 0x40,0xb, +0x15,0xb, 0xa0,0xbc,0xba,0x38,0xdc,0x22,0xca,0x79,0x7c,0xab,0x6c,0x99,0x80,0x2d, +0x7e,0xf0,0x2, 0xac,0xf9,0x7f,0x60,0x2d,0xd7,0xb, 0x6a,0xf0,0x5e,0xf4,0xfc,0x0, +0x1b,0x6a,0xf0,0x7f,0x71,0x2d,0xf7,0xb, 0x7a,0xe0,0x7e,0xf0,0x2, 0xac,0xf9,0x7f, +0x60,0x2d,0xd7,0xb, 0x6a,0xf0,0x4d,0xfe,0x1b,0x6a,0xf0,0xb, 0x90,0xbc,0xa9,0x38, +0xcf,0xda,0x79,0x22,0xb, 0x38,0x20,0x5e,0x50,0xc0,0x1b,0x38,0x20,0xb, 0xa, 0x20, +0x5e,0x40,0x7, 0x1b,0xa, 0x20,0xe5,0x2e,0xa, 0x5b,0xb, 0x38,0x20,0x4d,0x25,0x1b, +0x38,0x20,0xe5,0x2d,0xa, 0x3b,0x7d,0x23,0x7c,0x45,0x6c,0x55,0x3e,0x24,0x3e,0x24, +0x3e,0x24,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xa9,0xd6,0xcb,0x54,0x3f, +0x5e,0x70,0x1f,0x7e,0x14,0x0, 0x1, 0x7e,0x7f,0x4f,0x9d,0x79,0x17,0x0, 0x2, 0x7c, +0x2b,0x6c,0x33,0xa, 0x37,0x2d,0x31,0x7e,0xf, 0x4f,0x9d,0x79,0x30,0x0, 0x32,0x7e, +0xf, 0x4f,0x9d,0x79,0x20,0x0, 0x14,0xa9,0xc6,0xcb,0x12,0x7, 0xb5,0x2, 0xd, 0x59, +0x30,0x2a,0x31,0xa9,0xd2,0xea,0xa9,0xc2,0xea,0x6d,0x33,0x7e,0xf, 0x4f,0xa1,0x79, +0x30,0x0, 0x16,0x7e,0x34,0x1, 0x2c,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x18,0xc2, +0x2a,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x14,0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b, +0xa, 0x30,0xc2,0x29,0x22,0xa2,0xac,0x92,0x8, 0x7e,0xf, 0x4f,0xa1,0xb, 0xa, 0x30, +0x5e,0x34,0x10,0x0, 0x68,0xb, 0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x10,0x1b,0xa, +0x30,0xc2,0xac,0x7e,0xf, 0x4f,0xa1,0xb, 0x16,0xb, 0xa, 0x30,0x4e,0x60,0x10,0x1b, +0xa, 0x30,0xa2,0x8, 0x92,0xac,0x22,0xa2,0xac,0x92,0xd, 0xc2,0xac,0x7e,0xf, 0x4f, +0xa1,0x30,0xc, 0xa, 0xb, 0x16,0xb, 0xa, 0x30,0x4e,0x60,0x10,0x80,0x8, 0xb, 0x16, +0xb, 0xa, 0x30,0x5e,0x60,0xef,0x1b,0xa, 0x30,0xa2,0xd, 0x92,0xac,0x22,0xb, 0xa, +0x30,0x5e,0x34,0xfc,0x7f,0x1b,0xa, 0x30,0xa, 0x2b,0x5e,0x24,0x0, 0x7, 0x3e,0x24, +0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0xb, 0xa, 0x30,0x4d, +0x32,0x1b,0xa, 0x30,0x22,0xa9,0xd7,0xca,0x7e,0x24,0x0, 0x1, 0x7e,0xf, 0x4f,0xa5, +0x1b,0xa, 0x20,0x7e,0x24,0x9, 0x60,0x7e,0xf, 0x4f,0xa5,0x79,0x20,0x0, 0x2, 0x7e, +0xf, 0x4f,0xa5,0x79,0x30,0x0, 0x4, 0x22,0xb, 0xa, 0x20,0x5e,0x24,0x80,0x1f,0x1b, +0xa, 0x20,0x7d,0x23,0x5e,0x40,0x3, 0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e,0x24,0x3e, +0x24,0xb, 0xa, 0x30,0x2d,0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30,0x5e,0x60,0xc7, +0x1b,0xa, 0x30,0x54,0x7, 0xa, 0x3b,0x7d,0x23,0x7c,0x45,0x6c,0x55,0x3e,0x24,0x3e, +0x24,0x3e,0x24,0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xca,0x3b,0x7d,0x72, +0x7a,0xd, 0x2d,0x7d,0x63,0x7e,0xd, 0x2d,0x7d,0x27,0x12,0x3, 0xfa,0x7d,0x36,0x7e, +0xd, 0x2d,0x7d,0x27,0x12,0x4, 0x96,0xda,0x3b,0x22,0xb, 0xa, 0x30,0x5e,0x60,0x9f, +0x1b,0xa, 0x30,0x54,0x3, 0xa, 0x5b,0xc4,0x23,0x54,0xe0,0x7c,0xab,0xe4,0xb, 0xa, +0x30,0x4d,0x35,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30,0x5e,0x70,0xe7,0x1b,0xa, 0x30, +0x54,0x3, 0xa, 0x2b,0x3e,0x24,0x3e,0x24,0x3e,0x24,0xb, 0xa, 0x30,0x4d,0x32,0x1b, +0xa, 0x30,0x22,0x7c,0xa7,0xb, 0xa, 0x30,0x5e,0x60,0x40,0x60,0x3, 0x4e,0x60,0x80, +0x7c,0xba,0x54,0x3f,0x7c,0x4b,0x6c,0x55,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, +0x50,0x54,0xe0,0x1b,0xa, 0x50,0x7d,0x52,0x5e,0x54,0x0, 0x1f,0xb, 0xa, 0x20,0x4d, +0x25,0x1b,0xa, 0x20,0x79,0x30,0x0, 0x2, 0x22,0x7e,0xb3,0x1, 0x73,0xb4,0xe7,0x12, +0x7e,0xb3,0x1, 0x74,0xb4,0x16,0xb, 0x7e,0xb3,0x1, 0x70,0x54,0x1, 0xb4,0x1, 0x2, +0x80,0xfe,0x22,0xb, 0xa, 0x30,0x5e,0x60,0xf, 0x1b,0xa, 0x30,0xa, 0x5b,0xc4,0x54, +0xf0,0x7c,0xab,0xe4,0xb, 0xa, 0x30,0x4d,0x35,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30, +0x5e,0x60,0xfc,0x1b,0xa, 0x30,0x54,0x3, 0x7c,0x4b,0x6c,0x55,0xb, 0xa, 0x30,0x4d, +0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x20,0x5e,0x50,0xfc,0x1b,0xa, 0x20,0x7d,0x23, +0x5e,0x24,0x0, 0x3, 0xb, 0xa, 0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xd2,0x2a,0xd2, +0x29,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0x14,0xb, 0xa, 0x30,0x4e,0x70,0x2, 0x1b, +0xa, 0x30,0x22,0x7d,0x23,0xb, 0xa, 0x30,0x5e,0x34,0xf8,0x0, 0x1b,0xa, 0x30,0x4d, +0x32,0x1b,0xa, 0x30,0x22,0x7d,0x23,0xb, 0xa, 0x30,0x5e,0x34,0xf8,0x0, 0x1b,0xa, +0x30,0x4d,0x32,0x1b,0xa, 0x30,0x22,0xb, 0xa, 0x30,0x5e,0x70,0x3, 0x70,0x3, 0x4e, +0x70,0xc, 0x1b,0xa, 0x30,0x22,0x70,0x8f,0x0, 0xff,0xe0,0x1f,0x4, 0xa7,0x24,0x87, +0x2, 0xa9,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x46,0x54,0x53,0x38,0x37,0x31,0x36,0x50,0x30,0x30, +0x31,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30,0x30,0x31,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, +0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x0, +0x1, 0x9, 0x9, 0x12,0x1e,0x12,0x1e,0x5, 0x4, 0x1, 0xe, 0x1, 0xe, 0x0, 0xc, 0x0, +0xc, 0x1, 0xe, 0x1, 0xe, 0x1, 0x0, 0xc, 0x0, 0xd, 0x0, 0xe, 0x0, 0xf, 0x0, 0x10, +0x0, 0x11,0x0, 0x12,0x0, 0x13,0x0, 0x14,0x0, 0x15,0x0, 0x16,0x0, 0x17,0x0, 0x18, +0x0, 0x19,0x0, 0x1a,0x0, 0x1b,0x0, 0x1c,0x0, 0x1d,0x0, 0x1e,0x0, 0x1f,0x0, 0x20, +0x0, 0x21,0x0, 0x22,0x0, 0x23,0x0, 0x24,0x0, 0x25,0x0, 0x26,0x0, 0x27,0x0, 0x28, +0x0, 0x29,0x0, 0x2a,0x0, 0x2b,0x0, 0x2c,0x0, 0x2d,0x0, 0x2e,0x0, 0x2f,0x0, 0x30, +0x0, 0x31,0x0, 0x32,0x0, 0x33,0x0, 0x34,0x0, 0x35,0x0, 0x36,0x0, 0x37,0x0, 0x38, +0x0, 0x39,0x0, 0x3a,0x0, 0x3b,0x0, 0x3c,0x0, 0x3d,0x0, 0x3e,0x0, 0x3f,0x0, 0x40, +0x0, 0x41,0x0, 0x42,0x0, 0x43,0x0, 0x44,0x0, 0x45,0x0, 0x46,0x0, 0x47,0x0, 0x48, +0x0, 0x49,0x0, 0x4a,0x0, 0x4b,0x0, 0x4c,0x0, 0x4d,0x0, 0x4e,0x0, 0x4f,0x0, 0x50, +0x0, 0x51,0x0, 0x52,0x0, 0x53,0x0, 0x54,0x0, 0x55,0x0, 0x56,0x0, 0x57,0x0, 0x58, +0x0, 0x59,0x0, 0x5a,0x0, 0x5b,0x0, 0x5c,0x0, 0x5d,0x0, 0x5e,0x0, 0x5f,0x0, 0x60, +0x0, 0x61,0x0, 0x62,0x0, 0x63,0x0, 0x64,0x0, 0x65,0x0, 0x66,0x0, 0x67,0x0, 0x68, +0x0, 0x69,0x0, 0x6a,0x0, 0x6b,0x0, 0x6c,0x0, 0x6d,0x0, 0x6e,0x0, 0x6f,0x0, 0x70, +0x0, 0x71,0x0, 0x72,0x0, 0x73,0x0, 0x74,0x0, 0x75,0x0, 0x76,0x0, 0x77,0x0, 0x78, +0x0, 0x79,0x0, 0x7a,0x0, 0x7b,0x0, 0x7c,0x0, 0x7d,0x0, 0x7e,0x0, 0x7f,0x0, 0x80, +0x0, 0x81,0x0, 0x82,0x0, 0x83,0x0, 0x84,0x0, 0x85,0x0, 0x86,0x0, 0x87,0x0, 0x88, +0x0, 0x89,0x0, 0x8a,0x0, 0x8b,0x0, 0x8c,0x0, 0x8d,0x0, 0x8e,0x0, 0x8f,0x0, 0x90, +0x0, 0x91,0x0, 0x92,0x0, 0x93,0x0, 0x94,0x0, 0x95,0x0, 0x96,0x0, 0x97,0x0, 0x98, +0x0, 0x99,0x0, 0x9a,0x0, 0x9b,0x0, 0x9c,0x0, 0x9d,0x0, 0x9e,0x0, 0x9f,0x0, 0xa0, +0x0, 0xa1,0x0, 0xa2,0x0, 0xa3,0x0, 0xa4,0x0, 0xa5,0x0, 0xa6,0x0, 0xa7,0x0, 0xa8, +0x0, 0xa9,0x0, 0xaa,0x0, 0xab,0x0, 0xac,0x0, 0xad,0x0, 0xae,0x0, 0xaf,0x0, 0xb0, +0x0, 0xb1,0x0, 0xb2,0x0, 0xb3,0x0, 0xb4,0x0, 0xb5,0x0, 0xb6,0x0, 0xb7,0x0, 0xb8, +0x0, 0xb9,0x0, 0xba,0x0, 0xbb,0x0, 0xbc,0x0, 0xbd,0x0, 0xbe,0x0, 0xbf,0x0, 0xc0, +0x0, 0xc1,0x0, 0xc2,0x0, 0xc3,0x0, 0xc4,0x0, 0xc5,0x0, 0xc6,0x0, 0xc7,0x0, 0xc8, +0x0, 0xc9,0x0, 0xca,0x0, 0xcb,0x0, 0xcc,0x0, 0xcd,0x0, 0xce,0x0, 0xcf,0x0, 0xd0, +0x0, 0xd1,0x0, 0xd2,0x0, 0xd3,0x0, 0xd4,0x0, 0xd5,0x0, 0xd6,0x0, 0xd7,0x0, 0xd8, +0x0, 0xd9,0x0, 0xda,0x0, 0xdb,0x0, 0xdc,0x0, 0xdd,0x0, 0xde,0x0, 0xdf,0x0, 0xe0, +0x0, 0xe1,0x0, 0xe2,0x0, 0xe3,0x0, 0xe4,0x0, 0xe5,0x0, 0xe6,0x0, 0xe7,0x0, 0xe8, +0x0, 0xe9,0x0, 0xea,0x0, 0xeb,0x0, 0xec,0x0, 0xed,0x0, 0xee,0x0, 0xef,0x0, 0xf0, +0x0, 0xf1,0x0, 0xf2,0x0, 0xf3,0x0, 0xf4,0x0, 0xf5,0x0, 0xf6,0x0, 0xf7,0x0, 0xf8, +0x0, 0xf9,0x0, 0xfa,0x0, 0xfb,0x0, 0xfc,0x0, 0xfd,0x0, 0xfe,0x0, 0xff,0x1, 0x0, +0x1, 0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x4, 0x1, 0x5, 0x1, 0x6, 0x1, 0x7, 0x1, 0x8, +0x1, 0x9, 0x1, 0xa, 0x1, 0xb, 0x1, 0xc, 0x1, 0xd, 0x1, 0xe, 0x1, 0xf, 0x1, 0x10, +0x1, 0x11,0x1, 0x12,0x1, 0x13,0x1, 0x14,0x1, 0x15,0x1, 0x16,0x1, 0x17,0x1, 0x18, +0x1, 0x19,0x1, 0x19,0x1, 0x18,0x1, 0x17,0x1, 0x16,0x1, 0x15,0x1, 0x14,0x1, 0x13, +0x1, 0x12,0x1, 0x11,0x1, 0x10,0x1, 0xf, 0x1, 0xe, 0x1, 0xd, 0x1, 0xc, 0x1, 0xb, +0x1, 0xa, 0x1, 0x9, 0x1, 0x8, 0x1, 0x7, 0x1, 0x6, 0x1, 0x5, 0x1, 0x4, 0x1, 0x3, +0x1, 0x2, 0x1, 0x1, 0x1, 0x0, 0x0, 0xff,0x0, 0xfe,0x0, 0xfd,0x0, 0xfc,0x0, 0xfb, +0x0, 0xfa,0x0, 0xf9,0x0, 0xf8,0x0, 0xf7,0x0, 0xf6,0x0, 0xf5,0x0, 0xf4,0x0, 0xf3, +0x0, 0xf2,0x0, 0xf1,0x0, 0xf0,0x0, 0xef,0x0, 0xee,0x0, 0xed,0x0, 0xec,0x0, 0xeb, +0x0, 0xea,0x0, 0xe9,0x0, 0xe8,0x0, 0xe7,0x0, 0xe6,0x0, 0xe5,0x0, 0xe4,0x0, 0xe3, +0x0, 0xe2,0x0, 0xe1,0x0, 0xe0,0x0, 0xdf,0x0, 0xde,0x0, 0xdd,0x0, 0xdc,0x0, 0xdb, +0x0, 0xda,0x0, 0xd9,0x0, 0xd8,0x0, 0xd7,0x0, 0xd6,0x0, 0xd5,0x0, 0xd4,0x0, 0xd3, +0x0, 0xd2,0x0, 0xd1,0x0, 0xd0,0x0, 0xcf,0x0, 0xce,0x0, 0xcd,0x0, 0xcc,0x0, 0xcb, +0x0, 0xca,0x0, 0xc9,0x0, 0xc8,0x0, 0xc7,0x0, 0xc6,0x0, 0xc5,0x0, 0xc4,0x0, 0xc3, +0x0, 0xc2,0x0, 0xc1,0x0, 0xc0,0x0, 0xbf,0x0, 0xbe,0x0, 0xbd,0x0, 0xbc,0x0, 0xbb, +0x0, 0xba,0x0, 0xb9,0x0, 0xb8,0x0, 0xb7,0x0, 0xb6,0x0, 0xb5,0x0, 0xb4,0x0, 0xb3, +0x0, 0xb2,0x0, 0xb1,0x0, 0xb0,0x0, 0xaf,0x0, 0xae,0x0, 0xad,0x0, 0xac,0x0, 0xab, +0x0, 0xaa,0x0, 0xa9,0x0, 0xa8,0x0, 0xa7,0x0, 0xa6,0x0, 0xa5,0x0, 0xa4,0x0, 0xa3, +0x0, 0xa2,0x0, 0xa1,0x0, 0xa0,0x0, 0x9f,0x0, 0x9e,0x0, 0x9d,0x0, 0x9c,0x0, 0x9b, +0x0, 0x9a,0x0, 0x99,0x0, 0x98,0x0, 0x97,0x0, 0x96,0x0, 0x95,0x0, 0x94,0x0, 0x93, +0x0, 0x92,0x0, 0x91,0x0, 0x90,0x0, 0x8f,0x0, 0x8e,0x0, 0x8d,0x0, 0x8c,0x0, 0x8b, +0x0, 0x8a,0x0, 0x89,0x0, 0x88,0x0, 0x87,0x0, 0x86,0x0, 0x85,0x0, 0x84,0x0, 0x83, +0x0, 0x82,0x0, 0x81,0x0, 0x80,0x0, 0x7f,0x0, 0x7e,0x0, 0x7d,0x0, 0x7c,0x0, 0x7b, +0x0, 0x7a,0x0, 0x79,0x0, 0x78,0x0, 0x77,0x0, 0x76,0x0, 0x75,0x0, 0x74,0x0, 0x73, +0x0, 0x72,0x0, 0x71,0x0, 0x70,0x0, 0x6f,0x0, 0x6e,0x0, 0x6d,0x0, 0x6c,0x0, 0x6b, +0x0, 0x6a,0x0, 0x69,0x0, 0x68,0x0, 0x67,0x0, 0x66,0x0, 0x65,0x0, 0x64,0x0, 0x63, +0x0, 0x62,0x0, 0x61,0x0, 0x60,0x0, 0x5f,0x0, 0x5e,0x0, 0x5d,0x0, 0x5c,0x0, 0x5b, +0x0, 0x5a,0x0, 0x59,0x0, 0x58,0x0, 0x57,0x0, 0x56,0x0, 0x55,0x0, 0x54,0x0, 0x53, +0x0, 0x52,0x0, 0x51,0x0, 0x50,0x0, 0x4f,0x0, 0x4e,0x0, 0x4d,0x0, 0x4c,0x0, 0x4b, +0x0, 0x4a,0x0, 0x49,0x0, 0x48,0x0, 0x47,0x0, 0x46,0x0, 0x45,0x0, 0x44,0x0, 0x43, +0x0, 0x42,0x0, 0x41,0x0, 0x40,0x0, 0x3f,0x0, 0x3e,0x0, 0x3d,0x0, 0x3c,0x0, 0x3b, +0x0, 0x3a,0x0, 0x39,0x0, 0x38,0x0, 0x37,0x0, 0x36,0x0, 0x35,0x0, 0x34,0x0, 0x33, +0x0, 0x32,0x0, 0x31,0x0, 0x30,0x0, 0x2f,0x0, 0x2e,0x0, 0x2d,0x0, 0x2c,0x0, 0x2b, +0x0, 0x2a,0x0, 0x29,0x0, 0x28,0x0, 0x27,0x0, 0x26,0x0, 0x25,0x0, 0x24,0x0, 0x23, +0x0, 0x22,0x0, 0x21,0x0, 0x20,0x0, 0x1f,0x0, 0x1e,0x0, 0x1d,0x0, 0x1c,0x0, 0x1b, +0x0, 0x1a,0x0, 0x19,0x0, 0x18,0x0, 0x17,0x0, 0x16,0x0, 0x15,0x0, 0x14,0x0, 0x13, +0x0, 0x12,0x0, 0x11,0x0, 0x10,0x0, 0xf, 0x0, 0xe, 0x0, 0xd, 0x0, 0xc, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x18,0x19,0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, +0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, +0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x0, 0xb, 0x18,0x19,0x2, 0x5, 0x0, 0x0, 0x0, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, +0x18,0x19,0x2, 0x5, 0x1, 0x0, 0x0, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, +0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, +0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x18,0x19,0x2, 0x5, 0x2, 0x0, 0x0, 0x0, 0x5, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, +0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x0, 0x5, 0x1, 0xa, +0x1e,0x20,0x8, 0x0, 0x64,0xd, 0xac,0x0, 0xc8,0x2, 0x26,0x1, 0xf4,0x1, 0xf4,0x3, +0x20,0x3, 0x20,0x3, 0x20,0x1, 0x90,0x1, 0x90,0xa, 0x0, 0x2, 0x26,0x1, 0xa, 0x6, +0x21,0x3c,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16,0x1, 0x0, 0x1, 0x87,0x1, 0x0, 0xd, 0x1, 0xe0, +0x0, 0x1, 0x0, 0x15,0x2, 0x1, 0x4, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d,0x0, 0x0, 0x0, 0x0, 0x0, 0xff,0x0, 0xff,0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x40,0x3, 0xc0,0x4, 0x38,0x2, 0x1c, +0x3e,0x3e,0x1, 0xe0,0x1, 0xe0,0x0, 0xf0,0x0, 0xf0,0x7, 0x80,0x3, 0xc0,0x40,0x40, +0x1, 0xfe,0x1, 0xfe,0x1, 0x0, 0x1, 0x0, 0x12,0x2, 0x58,0x3, 0x20,0x0, 0xc8,0x0, +0x0, 0x7, 0xd0,0x1, 0x2c,0x0, 0x43,0x0, 0x4, 0x1, 0x5, 0x2, 0x2, 0x4, 0x4, 0x6, +0x80,0x0, 0xc8,0x13,0x88,0x10,0x3, 0x6, 0x1, 0x2c,0x2, 0x58,0x3, 0x20,0x1f,0x40, +0x28,0x1, 0x5e,0x2, 0xbc,0x0, 0x14,0x19,0x5, 0xf, 0x4, 0x4c,0x2, 0x26,0x8, 0x98, +0x0, 0x64,0x4, 0xa, 0x5, 0x0, 0x0, 0x4, 0x38,0x0, 0x0, 0x7, 0x80,0x0, 0x32,0x1, +0xf4,0x1, 0xf4,0x3, 0x20,0x0, 0xc8,0x0, 0x6c,0x0, 0x1e,0x0, 0x80,0x2, 0x1c,0x1, +0xe0,0x0, 0x64,0x7, 0xd0,0x1, 0xe0,0x2, 0x1c,0x0, 0x64,0x7, 0xd0,0x0, 0x0, 0x4, +0x38,0x0, 0x0, 0x7, 0x80,0x0, 0x64,0x0, 0xa0,0x0, 0xa0,0x9, 0xc4,0x1, 0x2c,0xc2, +0xd5,0x7c,0xb4,0x30,0xe7,0x8, 0xb2,0xd5,0x6e,0x24,0xff,0xff,0xb, 0x24,0x7c,0xb6, +0x30,0xe7,0x12,0xb2,0xd5,0x6e,0x34,0xff,0xff,0xb, 0x34,0x8d,0x32,0x6e,0x24,0xff, +0xff,0xb, 0x24,0x80,0x2, 0x8d,0x32,0x30,0xd5,0x6, 0x6e,0x34,0xff,0xff,0xb, 0x34, +0x22,0x7d,0x51,0xad,0x3, 0x7d,0x2, 0x7d,0x21,0xad,0x5, 0x2d,0x12,0xad,0x35,0x2d, +0x21,0x22,0x7d,0x2, 0xad,0x31,0xad,0x10,0x2d,0x21,0x22,0x6d,0x0, 0x74,0x10,0x4d, +0x0, 0x78,0xb, 0x4d,0x22,0x78,0x27,0x8d,0x31,0x7d,0x12,0x6d,0x22,0x22,0x7d,0x43, +0x7d,0x32,0x6d,0x22,0x2f,0x11,0x2d,0x44,0x50,0x2, 0xa5,0xf, 0xbf,0x10,0x40,0x4, +0x9f,0x10,0xb, 0x90,0x14,0x78,0xed,0x7f,0x1, 0x6d,0x22,0x7d,0x34,0x22,0x7d,0x41, +0x7d,0x13,0x8d,0x24,0x7d,0x2, 0x2f,0x0, 0x40,0x4, 0xbd,0x4, 0x40,0x4, 0x9d,0x4, +0xb, 0x14,0x14,0x78,0xf1,0x7d,0x23,0x7d,0x31,0x7d,0x10,0x6d,0x0, 0x22,0xc2,0xd5, +0x7c,0xb0,0x30,0xe7,0x8, 0xb2,0xd5,0x9f,0x22,0x9f,0x20,0x7f,0x2, 0x7c,0xb4,0x30, +0xe7,0x13,0xb2,0xd5,0x9f,0x22,0x9f,0x21,0x7f,0x12,0x12,0x14,0xed,0x9f,0x22,0x9f, +0x20,0x7f,0x2, 0x80,0x3, 0x12,0x14,0xed,0x30,0xd5,0x6, 0x9f,0x22,0x9f,0x21,0x7f, +0x12,0x22,0x6c,0xaa,0x4d,0x11,0x68,0x1a,0x1e,0x54,0x68,0xe, 0xb, 0x38,0x20,0x1b, +0x18,0x20,0xb, 0x35,0xb, 0x15,0x1b,0x54,0x78,0xf2,0x50,0x6, 0x7e,0x39,0x40,0x7a, +0x19,0x40,0x22,0x6c,0xaa,0x4d,0x11,0x68,0x1e,0x1e,0x54,0x50,0xc, 0x7e,0x1b,0x0, +0x7a,0x19,0x0, 0x68,0x12,0xb, 0x1c,0xb, 0x14,0xb, 0x1a,0x0, 0x1b,0x18,0x0, 0xb, +0x1d,0xb, 0x15,0x1b,0x54,0x78,0xf2,0x22,0x75,0x84,0x1, 0x7e,0x44,0x7f,0xff,0xe4, +0x7a,0x49,0xb0,0x1b,0x44,0x78,0xf9,0x7e,0xf8,0x4f,0xb1,0xc2,0x20,0xc2,0x21,0xc2, +0x22,0xc2,0x2c,0xc2,0x23,0xd2,0x24,0xc2,0x25,0xc2,0x26,0xc2,0x2d,0xc2,0x27,0xd2, +0x28,0xc2,0x17,0xc2,0x18,0xc2,0x19,0xc2,0x1a,0xc2,0xe, 0xc2,0xf, 0xc2,0x10,0xc2, +0x11,0xc2,0x12,0xc2,0x13,0xc2,0x14,0xc2,0x15,0xc2,0x16,0xc2,0x2e,0xc2,0x2f,0xd2, +0x29,0xc2,0x2a,0x75,0x13,0x0, 0x75,0x14,0x1, 0x7e,0x4, 0x0, 0xff,0x7e,0x14,0x18, +0xb8,0xb, 0xa, 0x40,0x5d,0x44,0x68,0x1a,0x69,0x20,0x0, 0x2, 0xb, 0xe, 0xb, 0x44, +0x80,0xa, 0x7e,0xb, 0xb0,0x7a,0x29,0xb0,0xb, 0x24,0xb, 0xc, 0x1b,0x44,0x78,0xf2, +0x80,0xdf,0x2, 0x1f,0xff,0xca,0xf8,0x7f,0x20,0x80,0xa, 0x7e,0x1b,0xf0,0x7a,0x2b, +0xf0,0xb, 0x34,0xb, 0x54,0x69,0xff,0xff,0xfc,0x7d,0xef,0x1b,0xe4,0x79,0xef,0xff, +0xfc,0x4d,0xff,0x78,0xe6,0x7f,0x10,0xda,0xf8,0x22,0x7d,0x43,0x7f,0x10,0x80,0x7, +0x1b,0x44,0x7a,0xb, 0xb0,0xb, 0x14,0x4d,0x44,0x78,0xf5,0x22,0x7d,0x23,0xbe,0x24, +0x0, 0x0, 0x48,0x3, 0x7d,0x32,0x22,0x6d,0x33,0x9d,0x32,0x22,0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2c,0xf9,0x1, 0x0, 0x1, 0x2c, +0xff,0x1, 0x0, 0x1, 0x2d,0x1, 0x5, 0x0, 0x3, 0x31,0x8c,0x0, 0x0, 0x0, 0x0, 0x6, +0x31,0x8f,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x31,0x95,0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x1, 0x4f,0xab,0x1, 0x0, 0x2, 0x4e,0x47,0x0, 0x0, 0x0, 0x1, 0x4d, +0x77,0xff,0x0, 0x8, 0x4c,0x3e,0x5, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0, 0x2, 0x0, 0xc, +0x4c,0x6e,0x3, 0x3, 0x0, 0x3, 0x0, 0x0, 0x3, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, +0x4f,0xad,0x0, 0x0, 0x1, 0x4e,0x97,0x0, 0x0, 0x1, 0x4e,0xdb,0xff,0x0, 0x1, 0x4e, +0xdc,0xff,0x0, 0x2, 0x4f,0xa9,0x0, 0x0, 0x0, 0x1, 0x4f,0x1b,0x0, 0x0, 0x1, 0x49, +0xe9,0xff,0x0, 0x1, 0x4a,0x1, 0x0, 0x0, 0x2, 0x4a,0x2, 0x0, 0x0, 0x0, 0x4, 0x4a, +0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x4a,0x76,0x0, 0x0, 0x1, 0x4f,0x8a,0x1, 0x0, +0x1, 0x4f,0x8b,0x0, 0x0, 0x1, 0x4f,0x93,0x0, 0x0, 0x2, 0x4d,0x75,0x0, 0x0, 0x0, +0x2, 0x4e,0x4c,0x0, 0x5, 0x0, 0x1, 0x4e,0x91,0xff,0x0, 0x1, 0x4e,0x92,0xff,0x0, +0x1, 0x4c,0xfa,0x64,0x0, 0x1, 0x4f,0xb0,0x0, 0x0, 0x1, 0x4f,0x4b,0x0, 0x0, 0x1, +0x4f,0x50,0x5, 0x0, 0x1, 0x4f,0x54,0x4, 0x0, 0x1, 0x4f,0x55,0x1, 0x0, 0x1, 0x4f, +0x59,0x0, 0x0, 0x1, 0x4f,0x98,0x1, 0x0, 0x1, 0x4f,0xb1,0x1, 0x0, 0x4, 0x4f,0x9d, +0x0, 0x0, 0x90,0x0, 0x0, 0x4, 0x4f,0x6f,0x0, 0x0, 0x94,0x0, 0x0, 0x4, 0x4f,0x73, +0x0, 0x0, 0x98,0x0, 0x0, 0x4, 0x4f,0x77,0x0, 0x0, 0x9c,0x0, 0x0, 0x4, 0x1, 0x5f, +0x0, 0x0, 0x80,0x0, 0x0, 0x4, 0x4f,0xa1,0x0, 0x0, 0x91,0x0, 0x0, 0x4, 0x4f,0xa5, +0x0, 0x0, 0x92,0x0, 0x0, 0x0, 0x3, 0xe8,0x0, 0x51,0x0, 0x3, 0x3, 0x20,0x0, 0x50, +0x0, 0x3, 0x2, 0x58,0x0, 0x4e,0x0, 0x4, 0x1, 0xc2,0x0, 0x4b,0x0, 0x4, 0x1, 0x40, +0x0, 0x47,0x0, 0x4, 0x0, 0xc8,0x0, 0x44,0x0, 0x4, 0x0, 0x78,0x0, 0x3e,0x0, 0x5, +0x0, 0x64,0x0, 0x3c,0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x12,0x1f,0xf8,0x7a,0xb3,0x4f,0x6e,0xe4,0x7a,0xb3,0x4d,0xeb,0x2, 0x1a,0x33, +0x12,0x1d,0x19,0x74,0x1f,0x7a,0xb3,0x44,0x7f,0x7a,0xb3,0x44,0x80,0x22,0xca,0x7b, +0xca,0x6b,0xca,0x5b,0xca,0x4b,0xca,0x2b,0xca,0x1b,0xca,0xb, 0xc0,0xd0,0xc0,0x83, +0xc0,0x82,0x12,0x1b,0xde,0x5e,0x34,0x80,0x0, 0x68,0x28,0xb, 0xa, 0x30,0x5e,0x34, +0x80,0x0, 0x68,0x1f,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x6e,0x70,0x40,0x1b,0xa, +0x30,0x7e,0xf, 0x4f,0xa1,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x80,0x12,0x1b,0xe7, +0x12,0x1f,0xf1,0x12,0x1b,0xde,0x5e,0x34,0x0, 0x2, 0x68,0x17,0xb, 0xa, 0x30,0x5e, +0x34,0x0, 0x2, 0x68,0xe, 0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x70,0x2, 0x12,0x1b,0xe7, +0x12,0x1f,0xf1,0x12,0x1b,0xde,0x5e,0x34,0x0, 0x1, 0x68,0x20,0xb, 0xa, 0x30,0x5e, +0x34,0x0, 0x1, 0x68,0x17,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x70,0x1, 0x1b,0xa, 0x30, +0x12,0x33,0xd7,0x12,0x1b,0xed,0x4e,0x70,0x1, 0x1b,0xa, 0x30,0x12,0x1b,0xde,0x5e, +0x34,0x0, 0x8, 0x68,0x17,0xb, 0xa, 0x30,0x5e,0x34,0x0, 0x8, 0x68,0xe, 0xb, 0x15, +0xb, 0xa, 0x30,0x4e,0x70,0x8, 0x1b,0xa, 0x30,0x12,0x33,0xb5,0x12,0x1b,0xde,0x5e, +0x34,0x0, 0x4, 0x68,0x17,0xb, 0xa, 0x30,0x5e,0x34,0x0, 0x4, 0x68,0xe, 0xb, 0x15, +0xb, 0xa, 0x30,0x4e,0x70,0x4, 0x1b,0xa, 0x30,0x12,0x33,0x9a,0x12,0x1b,0xde,0x5e, +0x34,0x40,0x0, 0x68,0x31,0xb, 0xa, 0x30,0x5e,0x34,0x40,0x0, 0x68,0x28,0xb, 0x15, +0xb, 0xa, 0x30,0x4e,0x60,0x40,0x1b,0xa, 0x30,0xd2,0xf, 0x7e,0xb3,0x4f,0x49,0xbe, +0xb0,0xc8,0x50,0x5, 0x4, 0x7a,0xb3,0x4f,0x49,0x7e,0xb3,0x4f,0x49,0xb4,0x1, 0x6, +0x12,0x1a,0x33,0x12,0x1c,0xa, 0x12,0x1b,0xde,0x5e,0x34,0x20,0x0, 0x68,0x19,0xb, +0xa, 0x30,0x5e,0x34,0x20,0x0, 0x68,0x10,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x20, +0x1b,0xa, 0x30,0xd2,0xf, 0x12,0x1c,0xa, 0x12,0x1b,0xde,0x5e,0x34,0x10,0x0, 0x68, +0x26,0xb, 0xa, 0x30,0x7d,0x23,0x5e,0x24,0x10,0x0, 0x68,0x1b,0x5e,0x34,0x8, 0x0, +0x2e,0x34,0xff,0xff,0x92,0x14,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x60,0x8, 0x1b,0xa, +0x30,0x12,0xa3,0x17,0x12,0xa4,0x14,0x12,0x1b,0xde,0x5e,0x34,0x0, 0x40,0x68,0x29, +0xb, 0xa, 0x30,0x5e,0x34,0x0, 0x40,0x68,0x20,0xb, 0x15,0xb, 0xa, 0x30,0x4e,0x70, +0x40,0x1b,0xa, 0x30,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0xa, 0x5e,0x34,0xf, 0xc0, +0x12,0x1f,0x16,0x1e,0x34,0x7a,0x73,0x4f,0x4c,0xd0,0x82,0xd0,0x83,0xd0,0xd0,0xda, +0xb, 0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b,0xda,0x6b,0xda,0x7b,0x32,0x7e,0xf, +0x4f,0xa1,0x69,0x30,0x0, 0x4, 0x22,0x1b,0xa, 0x30,0x12,0x1b,0xf9,0x7e,0xf, 0x4f, +0xa1,0x2e,0x14,0x0, 0x14,0xb, 0xa, 0x30,0x22,0xd2,0xe, 0xd2,0x12,0x12,0x33,0x91, +0x5e,0x34,0x0, 0x1, 0x78,0x3, 0x2, 0x33,0xab,0x22,0x30,0x2a,0x16,0xa9,0xd2,0xea, +0xa9,0xc2,0xea,0x12,0xac,0x93,0xc2,0x2a,0x12,0x1b,0xed,0x12,0x1f,0xea,0xc2,0x29, +0x2, 0x33,0xc6,0x22,0xe4,0x7a,0xb3,0x3, 0xd2,0x12,0xad,0x98,0x12,0xac,0xaa,0xe4, +0x7a,0xb3,0x3, 0xd9,0x12,0x1b,0xed,0x12,0x1f,0xea,0xc2,0x2, 0x12,0x1c,0x4f,0x12, +0xa3,0x66,0xbe,0xb0,0x1, 0x68,0x3, 0x12,0xa3,0x56,0xd2,0x2, 0x2, 0x1c,0x4f,0xa2, +0xac,0x92,0x3, 0xc2,0xac,0x7e,0xf, 0x4f,0xa1,0x30,0x2, 0xa, 0xb, 0x16,0xb, 0xa, +0x30,0x4e,0x70,0x3, 0x80,0x8, 0xb, 0x16,0xb, 0xa, 0x30,0x5e,0x70,0xfc,0x1b,0xa, +0x30,0xa2,0x3, 0x92,0xac,0x22,0xca,0x3b,0xc2,0x2, 0x12,0x1c,0x4f,0xc2,0xf, 0x30, +0xe, 0x11,0xc2,0xe, 0x12,0x3e,0x74,0x12,0x2f,0x59,0x12,0x3d,0x1f,0x12,0x4f,0x55, +0x12,0x1a,0x33,0xd2,0x2, 0x12,0x1c,0x4f,0xc2,0x1, 0x12,0xa1,0x68,0x30,0x10,0x39, +0xc2,0x10,0x7e,0x3f,0x4f,0xa1,0x69,0x33,0x0, 0x6, 0x7d,0x23,0x5e,0x24,0x0, 0x1, +0x68,0x27,0x5e,0x34,0x0, 0x2, 0x68,0x5, 0x12,0xac,0x6e,0x80,0xe, 0x75,0x13,0x1, +0x74,0x1, 0x7a,0xb3,0x4f,0x55,0x7f,0x3, 0x12,0x1f,0xe3,0x12,0x3d,0x1f,0xe5,0x13, +0x12,0x2f,0xb7,0x74,0x1f,0x7a,0xb3,0x44,0x80,0xd2,0x1, 0x12,0xa1,0x68,0xda,0x3b, +0x22,0x74,0x5, 0x7a,0xb3,0x4f,0x97,0x12,0x1c,0x76,0x7e,0xb3,0x44,0x7f,0x60,0x11, +0x80,0xa, 0x7e,0x34,0x9, 0xc4,0x12,0x1d,0x19,0x12,0x1c,0x76,0x12,0x6a,0x89,0x50, +0xf1,0x7e,0xb3,0x44,0x80,0x60,0x11,0x80,0xa, 0x7e,0x34,0x9, 0xc4,0x12,0x1d,0x19, +0x12,0x1c,0x76,0x12,0x69,0x35,0x50,0xf1,0x22,0x6d,0x22,0x7a,0x27,0x4f,0x5d,0x7a, +0x37,0x4f,0x5f,0x22,0x12,0x49,0x69,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x74,0x12,0x40, +0x9c,0x12,0x1c,0xe1,0x7e,0x34,0x9, 0xc4,0x12,0x1d,0x19,0x7e,0xb3,0x4d,0xeb,0x30, +0xe7,0x5b,0x7e,0xb3,0x4d,0xfc,0x70,0x5, 0xc2,0x2, 0x12,0x45,0xf2,0x12,0x1c,0x76, +0x30,0x12,0x8, 0xc2,0x12,0x12,0x3d,0xc, 0x12,0x1c,0x24,0x7e,0xb3,0x4d,0xfc,0x70, +0x5, 0x12,0x70,0xf4,0x80,0x6, 0x12,0x71,0xb, 0x12,0x71,0xd2,0x7e,0xb3,0x44,0x7e, +0xb4,0x1, 0x17,0x12,0x77,0x8, 0x74,0x2, 0x12,0x9d,0x1a,0x12,0xaa,0xce,0x12,0x48, +0x3, 0x12,0x9c,0x2c,0x12,0x6c,0x5, 0x12,0x21,0x6, 0x12,0x51,0xa6,0x7e,0xb3,0x4d, +0xfc,0x70,0xa, 0x7e,0xb3,0x4d,0xeb,0x54,0x7f,0x7a,0xb3,0x4d,0xeb,0x12,0x51,0x35, +0x80,0x85,0xd2,0x2c,0xd2,0x2, 0x12,0x45,0xf2,0x2, 0x1d,0xac,0xe4,0x7a,0xb3,0x4f, +0x94,0x6d,0x33,0x7a,0x37,0x4f,0x95,0x22,0x7e,0x34,0x13,0x85,0x12,0x1d,0xf2,0x12, +0x1d,0x19,0x12,0x55,0x15,0x12,0x34,0x8a,0x12,0x1f,0xf8,0x7a,0xb3,0x4f,0x6e,0x7e, +0x34,0xd, 0xac,0x2, 0x1a,0x30,0x7a,0x37,0x3f,0xed,0xe4,0x7a,0xb3,0x4f,0xae,0x7e, +0x34,0x13,0x95,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0x30,0x7a,0x37,0x3f,0xf7,0x7e,0x34, +0x13,0x97,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0x30,0x22,0x90,0x13,0x7f,0xe4,0x93,0x7a, +0xb3,0x3f,0xe9,0x12,0x1f,0xd9,0x7e,0x34,0x13,0x89,0x12,0x1d,0xf2,0x7a,0x37,0x3f, +0xeb,0x7e,0x34,0x13,0x8b,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xed,0x7e,0x34,0x13,0x8d, +0x12,0x1d,0xf2,0x12,0x1f,0xa2,0x7a,0x37,0x3f,0xef,0x7e,0x34,0x13,0x8f,0x12,0x1d, +0xf2,0x7a,0x37,0x3f,0xf1,0x7e,0x34,0x13,0x91,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xf3, +0x7e,0x34,0x13,0x93,0x12,0x1d,0xf2,0x12,0x1f,0xa2,0x7a,0x37,0x3f,0xf5,0x12,0x1d, +0xdf,0x12,0x1f,0xa2,0x7a,0x37,0x3f,0xf9,0x90,0x13,0xc9,0xe4,0x93,0x7a,0xb3,0x3f, +0xfd,0x90,0x13,0x82,0xe4,0x93,0x7a,0xb3,0x3f,0xfe,0x7e,0x34,0x13,0x83,0x12,0x1d, +0xf2,0x7a,0x37,0x3f,0xff,0x7e,0x34,0x13,0x99,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xfb, +0xe4,0x7a,0xb3,0x40,0x1, 0x7a,0xb3,0x40,0x2, 0x7a,0xb3,0x40,0x3, 0x7a,0xb3,0x40, +0x4, 0x7a,0xb3,0x40,0x5, 0x7a,0xb3,0x40,0x6, 0x7a,0xb3,0x40,0x7, 0x7a,0xb3,0x40, +0x8, 0x7a,0xb3,0x40,0x9, 0x7a,0xb3,0x40,0xa, 0x22,0x7e,0x34,0x13,0x89,0x12,0x1d, +0xf2,0x12,0x1f,0x16,0x7a,0x73,0x4d,0x79,0x7e,0x34,0x13,0x8b,0x12,0x1d,0xf2,0x12, +0x1f,0xb1,0x7a,0x73,0x4d,0x7a,0x7e,0x34,0x13,0x8f,0x12,0x1d,0xf2,0x12,0x1f,0x16, +0x7a,0x73,0x4d,0x7b,0x7e,0x34,0x13,0x91,0x12,0x1d,0xf2,0x12,0x1f,0xb1,0x7a,0x73, +0x4d,0x7c,0x7e,0x34,0x13,0x99,0x12,0x1d,0xf2,0x12,0x1f,0x16,0x7a,0x73,0x4d,0x7e, +0x7e,0x34,0x0, 0x6a,0xca,0x39,0x7e,0x34,0x13,0x9d,0x7e,0x24,0x0, 0xff,0x7e,0x8, +0x4d,0x7f,0x12,0x16,0x35,0x1b,0xfd,0x22,0x6e,0x34,0xff,0xff,0xb, 0x34,0x7a,0x37, +0x3f,0xf9,0x7e,0x37,0x3f,0xeb,0x1e,0x34,0x1e,0x34,0x1e,0x34,0x1e,0x34,0x1e,0x34, +0x22,0x7e,0x34,0x13,0x89,0x12,0x1d,0xf2,0x12,0x1f,0xd5,0x7e,0x34,0x13,0x8b,0x12, +0x1d,0xf2,0x12,0x1d,0xd6,0x12,0x1f,0x8, 0x12,0x1f,0xa9,0x7a,0x73,0x4d,0x7a,0x22, +0x7e,0xb3,0x4d,0xc9,0xb4,0x1, 0x5, 0x12,0x1f,0x21,0x80,0xf, 0x7e,0xb3,0x40,0x3, +0xb4,0x1, 0x5, 0x12,0x1f,0xbc,0x80,0x3, 0x12,0x59,0xf7,0x7e,0xb3,0x4f,0xae,0x70, +0x17,0x7e,0xb3,0x3f,0xdd,0x70,0x11,0x7e,0xb3,0x40,0x3, 0x70,0xb, 0x7e,0x34,0x13, +0x9b,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xeb,0x12,0x9d,0x9e,0x68,0x16,0x7e,0x34,0x13, +0x8f,0x12,0x1d,0xf2,0x7a,0x37,0x3f,0xf1,0x7e,0x34,0x13,0x91,0x12,0x1d,0xf2,0x7a, +0x37,0x3f,0xf3,0x7e,0x34,0x13,0x8d,0x12,0x1d,0xf2,0x12,0x1f,0xa2,0x7a,0x37,0x3f, +0xef,0x22,0x6e,0x34,0xff,0xff,0xb, 0x34,0x22,0x7a,0x73,0x4d,0x79,0x7e,0x37,0x3f, +0xed,0xe, 0x34,0xe, 0x34,0xe, 0x34,0xe, 0x34,0xe, 0x34,0x22,0x7e,0x34,0x0, 0x96, +0x12,0x1f,0xd5,0x7e,0x34,0x0, 0x78,0x12,0x1d,0xd6,0x12,0x1f,0x8, 0x12,0x1f,0xa9, +0x7a,0x73,0x4d,0x7a,0x22,0x7a,0x37,0x3f,0xeb,0x90,0x13,0x81,0xe4,0x93,0x7a,0xb3, +0x3f,0xea,0x22,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x5e,0x70,0xfb,0x1b,0xa, 0x30, +0x22,0x5e,0x70,0xfe,0x1b,0xa, 0x30,0x22,0x74,0x1, 0x7a,0xb3,0x4d,0xa0,0x22,0x12, +0x55,0x15,0x12,0x1e,0xaa,0x12,0x34,0x8a,0x12,0x3e,0x68,0x12,0x1a,0x21,0x7e,0xb3, +0x4d,0xa0,0x24,0xfd,0x68,0x9, 0xb, 0xb1,0x78,0xf4,0x12,0x20,0x24,0x80,0xef,0x12, +0x1d,0x24,0x80,0xea,0x30,0x2c,0xf, 0x7e,0xb3,0x4d,0xe7,0xb4,0x1, 0x8, 0x74,0x1, +0x7a,0xb3,0x44,0x7e,0x80,0x3, 0x12,0x4a,0x4b,0xc2,0x2c,0x7e,0xb3,0x4f,0x6e,0xb4, +0x1, 0x2, 0x80,0x2, 0x1, 0xcd,0x12,0x54,0xb0,0x12,0x69,0xbd,0x12,0x2b,0xbd,0x12, +0x1c,0xe1,0x7e,0x34,0x13,0x87,0x12,0x1d,0xf2,0x12,0x1d,0x19,0x12,0x71,0xb, 0x7e, +0xb3,0x24,0x26,0x70,0x2, 0x80,0x24,0x12,0x77,0x8, 0x7e,0xb3,0x4d,0x9d,0xb4,0x1, +0x2, 0xd2,0x86,0x12,0x7d,0x75,0x7e,0xb3,0x40,0x2, 0x70,0x6, 0x12,0x1f,0x40,0x12, +0xaa,0xce,0x12,0x6c,0x5, 0x7e,0xb3,0x24,0x26,0x70,0xb, 0x12,0x92,0x4d,0x12,0x51, +0x54,0x12,0xa8,0x55,0x80,0xa5,0x74,0x1, 0x12,0x20,0xe2,0x12,0x21,0x6, 0x12,0x81, +0xf7,0x12,0x5b,0x39,0x12,0x5f,0xd5,0x74,0x2, 0x12,0x20,0xe2,0x12,0x88,0x18,0x74, +0x3, 0x12,0x20,0xe2,0x12,0x5c,0x7, 0x74,0x4, 0x12,0x20,0xe2,0x12,0x5d,0xb8,0x12, +0x60,0xef,0x12,0x54,0x8a,0x12,0xa6,0x95,0x12,0x51,0x5d,0x1, 0x3b,0xd2,0x2, 0x12, +0x45,0xf2,0x2, 0x20,0xd5,0x12,0xa7,0xd9,0x7e,0xb3,0x4d,0x9d,0xb4,0x1, 0x2, 0xd2, +0x86,0x22,0x1b,0xb1,0x68,0x10,0x14,0x68,0x13,0x14,0x68,0x16,0x24,0x3, 0x78,0x15, +0xe4,0x7a,0xb3,0x3f,0xe7,0x22,0x12,0x0, 0xa, 0x2, 0x8f,0xc4,0x12,0x8c,0xb7,0x2, +0x62,0xb7,0x2, 0x90,0x8d,0x22,0xc2,0x23,0x7e,0xb3,0x40,0x1, 0x70,0x3, 0x12,0x7e, +0xae,0x12,0x23,0x3d,0x12,0x27,0x28,0x12,0x25,0x87,0x12,0x23,0x3d,0x12,0x27,0x79, +0x12,0x23,0x3d,0x12,0x85,0x18,0x12,0x23,0x3d,0x12,0x23,0x89,0x12,0x23,0x3d,0x2, +0x21,0x32,0xca,0x3b,0xc2,0x0, 0x7e,0xd3,0x3e,0x53,0xa, 0x3d,0x3e,0x34,0xca,0x39, +0x7e,0x18,0x3c,0xc9,0x7e,0x8, 0x44,0x87,0x12,0x16,0x35,0x1b,0xfd,0x6c,0x11,0x75, +0x27,0x0, 0x6c,0xcc,0x41,0x16,0x7e,0x44,0x3, 0xff,0x7e,0xe0,0xff,0x6c,0xff,0x80, +0x64,0x7c,0xbf,0x12,0x5b,0xf5,0x60,0x5b,0x74,0x2, 0xac,0xbf,0x9, 0x5, 0x44,0x87, +0xbe,0x0, 0xff,0x68,0x4e,0x9, 0x5, 0x44,0x88,0xa, 0x10,0x7e,0x70,0x2, 0xac,0x7c, +0x9, 0x3, 0x4e,0x9f,0xa, 0x30,0x12,0x7c,0x3, 0x8, 0x4, 0x9d,0x31,0x80,0x4, 0x6d, +0x33,0x9d,0x32,0x74,0x2, 0xac,0xbf,0x9, 0x5, 0x44,0x87,0xa, 0xf0,0x74,0x2, 0xac, +0xbc,0x9, 0x5, 0x4e,0x9e,0xa, 0x10,0x7d,0x21,0x9d,0x2f,0xbe,0x24,0x0, 0x0, 0x8, +0x4, 0x9d,0x1f,0x80,0x4, 0x6d,0x11,0x9d,0x12,0x2d,0x13,0xbd,0x41,0x28,0x4, 0x7d, +0x41,0x7c,0xef,0xb, 0xf0,0xbc,0xdf,0x38,0x98,0xbe,0xe0,0xff,0x68,0x46,0x7e,0x70, +0x2, 0xac,0x7e,0x9, 0xb3,0x44,0x87,0x9, 0x73,0x44,0x88,0x12,0x23,0x82,0x7d,0x13, +0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x44,0x87,0x12,0x80,0xaf,0xbd,0x13,0x48,0x25,0x7e, +0x70,0x2, 0xac,0x7e,0x9, 0x3, 0x44,0x87,0x7e,0xa1,0x27,0x74,0x2, 0xa4,0x19,0x5, +0x44,0xc3,0x9, 0x3, 0x44,0x88,0x19,0x5, 0x44,0xc4,0x74,0xff,0x19,0xb3,0x44,0x87, +0xb, 0x10,0x5, 0x27,0xb, 0xc0,0x7e,0x3, 0x4e,0xda,0xbc,0xc, 0x28,0x2, 0x21,0x56, +0x7c,0xc1,0x41,0xb4,0x6d,0x0, 0x7e,0xe0,0xff,0x6c,0xff,0x80,0x5a,0x7c,0xbf,0x12, +0x5b,0xf5,0x60,0x51,0x7e,0x30,0x2, 0xac,0x3f,0x9, 0xb1,0x44,0x87,0xbe,0xb0,0xff, +0x68,0x43,0x9, 0x71,0x44,0x88,0x12,0x23,0x82,0x7d,0x43,0xc2,0x0, 0xbd,0x4, 0x58, +0x2, 0xd2,0x0, 0x30,0x0, 0x2f,0x7e,0xb3,0x40,0x2, 0x60,0x14,0x7e,0x73,0x3f,0xde, +0xbe,0x70,0x2, 0x40,0xb, 0x7e,0x37,0x3e,0x59,0x12,0x6f,0xf0,0xbd,0x34,0x18,0x15, +0x7e,0x70,0x2, 0xac,0x7f,0x9, 0xb3,0x44,0x87,0xf5,0x28,0x9, 0xb3,0x44,0x88,0xf5, +0x29,0x7d,0x4, 0x7c,0xef,0xb, 0xf0,0xbc,0xdf,0x38,0xa2,0xbe,0xe0,0xff,0x68,0x22, +0x7e,0xa1,0x28,0x7e,0x31,0x27,0x74,0x2, 0xac,0x3b,0x19,0xa1,0x44,0xc3,0xe5,0x29, +0x19,0xb1,0x44,0xc4,0x7e,0xa0,0xff,0x7e,0x30,0x2, 0xac,0x3e,0x19,0xa1,0x44,0x87, +0x5, 0x27,0xb, 0xc0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbc,0x28,0x2, 0x41,0x24,0x90, +0x13,0x80,0xe4,0x93,0x7c,0xab,0x74,0x2, 0xa4,0xca,0x59,0x7e,0x18,0x44,0xc3,0x7e, +0x8, 0x44,0x87,0x12,0x16,0x35,0x1b,0xfd,0x7e,0xd1,0x27,0x12,0x3c,0xcc,0x7e,0x8, +0x4e,0x9e,0x74,0xff,0x12,0x16,0x5a,0xbe,0xd0,0x0, 0x28,0x37,0xa, 0x3d,0x3e,0x34, +0xca,0x39,0x7e,0x18,0x44,0x87,0x7e,0x8, 0x3c,0xc9,0x12,0x16,0x35,0x1b,0xfd,0xa, +0x3d,0x3e,0x34,0xca,0x39,0x7e,0x18,0x44,0x87,0x7e,0x8, 0x4e,0x9e,0x12,0x16,0x35, +0x1b,0xfd,0x6c,0xcc,0x80,0x9, 0xd2,0x6, 0x7c,0xbc,0x12,0x26,0xfa,0xb, 0xc0,0xbc, +0xdc,0x38,0xf3,0x7a,0xd3,0x4e,0xda,0x7a,0xd3,0x3e,0x53,0x90,0x13,0x7f,0xe4,0x93, +0xbe,0xb3,0x3e,0x53,0x50,0x4, 0x7a,0xb3,0x3e,0x53,0xda,0x3b,0x22,0xca,0x79,0x6c, +0xff,0x6c,0xee,0x80,0x2c,0x7c,0xbe,0x12,0x5b,0xf5,0x60,0x23,0x7e,0x34,0x0, 0x2, +0xca,0x39,0xac,0x7e,0x2e,0x34,0x3c,0xc9,0x6d,0x22,0x7e,0x30,0x2, 0xac,0x3f,0x2e, +0x14,0x3c,0xc9,0x6d,0x0, 0x12,0x16,0x35,0x1b,0xfd,0xd2,0x6, 0x12,0x27,0x71,0xb, +0xe0,0x12,0x5f,0xd8,0x38,0xcf,0x7a,0xf3,0x3e,0x53,0xda,0x79,0x22,0xe5,0x2b,0x7e, +0x71,0x2c,0x12,0x7d,0x3c,0xb, 0x1a,0x30,0x22,0x7e,0xb3,0x40,0x2, 0x60,0x2, 0xa1, +0x86,0x12,0xad,0xf3,0x78,0x2, 0xa1,0x86,0x7e,0xa3,0x3e,0x53,0xbe,0xa0,0x1, 0x78, +0x1b,0x7e,0xb3,0x3e,0x69,0x70,0x15,0x7e,0xb3,0x3c,0xc9,0x7a,0xb3,0x4e,0x9b,0x7e, +0xb3,0x3c,0xca,0x7a,0xb3,0x4e,0x9c,0xe4,0x7a,0xb3,0x4e,0x9d,0xbe,0xa0,0x0, 0x28, +0x3e,0xc2,0x0, 0x6c,0x11,0x80,0x21,0x12,0xad,0x3b,0x7e,0x73,0x4e,0x9b,0xa, 0x27, +0x1a,0x39,0x12,0xad,0xc4,0x58,0xf, 0x7e,0x73,0x4e,0x9c,0xa, 0x27,0x1a,0x30,0x12, +0xad,0xc4,0x58,0x2, 0xd2,0x0, 0xb, 0x10,0x12,0x26,0xe5,0x38,0xda,0x30,0x0, 0xc, +0x7e,0xb3,0x4e,0x9d,0xbe,0xb0,0xc8,0x50,0xb, 0x4, 0x80,0x4, 0xe4,0x80,0x1, 0xe4, +0x7a,0xb3,0x4e,0x9d,0x7e,0x73,0x3e,0x53,0xbe,0x70,0x2, 0x50,0x2, 0xa1,0x86,0x7e, +0xb3,0x3f,0xde,0xb4,0x1, 0x2, 0x80,0x2, 0xa1,0x86,0x6d,0xee,0x6c,0x11,0x80,0x18, +0x12,0xad,0x3b,0x12,0x26,0xae,0xbd,0xde,0x8, 0xc, 0x7d,0xed,0x7a,0x93,0x3e,0x5b, +0x7a,0x3, 0x3e,0x5c,0x7c,0x81,0xb, 0x10,0x12,0x26,0xe5,0x38,0xe3,0x6c,0x11,0xa1, +0x7f,0xbc,0x81,0x78,0x2, 0xa1,0x7d,0x7e,0x30,0x2, 0xac,0x31,0x9, 0xb1,0x3c,0xc9, +0xf5,0x2b,0x9, 0xb1,0x3c,0xca,0xf5,0x2c,0x7e,0xa3,0x3e,0x5b,0x7a,0xa1,0x2d,0x7e, +0xb3,0x3e,0x5c,0xf5,0x2e,0xbe,0xa1,0x2b,0x28,0x4, 0xe5,0x2b,0x80,0x2, 0xe5,0x2d, +0xf5,0x27,0xe5,0x2d,0xbe,0xb1,0x2b,0x50,0x4, 0xe5,0x2b,0x80,0x2, 0xe5,0x2d,0xf5, +0x29,0xe5,0x2e,0xbe,0xb1,0x2c,0x28,0x4, 0xe5,0x2c,0x80,0x2, 0xe5,0x2e,0xf5,0x28, +0xe5,0x2e,0xbe,0xb1,0x2c,0x50,0x5, 0x7e,0xa1,0x2c,0x80,0x3, 0x7e,0xa1,0x2e,0x7a, +0xa1,0x2a,0xe5,0x27,0x1a,0xfb,0xe5,0x29,0x1a,0x1b,0x9d,0x1f,0xb, 0x14,0x7c,0xb3, +0xf5,0x2f,0xe5,0x28,0x1a,0x1b,0x1a,0x5a,0x9d,0x51,0xb, 0x54,0xf5,0x30,0x12,0x23, +0x7d,0x7d,0xf3,0xe5,0x30,0xbe,0xb1,0x2f,0x50,0x4c,0xe5,0x28,0xbe,0xb0,0x0, 0x8, +0x2, 0x15,0x28,0x7e,0x73,0x40,0x12,0xa, 0xc7,0x1b,0xc4,0xe5,0x2a,0x1a,0x1b,0xbd, +0x1c,0x58,0x2, 0x5, 0x2a,0x7e,0x91,0x29,0x12,0x23,0x7d,0x7d,0xe3,0x80,0x1f,0x1b, +0x90,0x6d,0xdd,0x7e,0x1, 0x2a,0x80,0xa, 0x12,0x26,0xec,0x8, 0x3, 0x12,0x26,0xae, +0x1b,0x0, 0xe5,0x28,0xbc,0xb0,0x8, 0xf0,0xbd,0xde,0x58,0x2, 0x7d,0xed,0xe5,0x27, +0xbc,0xb9,0x48,0xdb,0x80,0x4a,0xe5,0x27,0xbe,0xb0,0x0, 0x8, 0x2, 0x15,0x27,0x7e, +0x73,0x40,0x11,0xa, 0xc7,0x1b,0xc4,0xe5,0x29,0x1a,0x1b,0xbd,0x1c,0x58,0x2, 0x5, +0x29,0x7e,0x1, 0x2a,0x12,0x23,0x7d,0x7d,0xe3,0x80,0x1f,0x1b,0x0, 0x6d,0xdd,0x7e, +0x91,0x29,0x80,0xa, 0x12,0x26,0xec,0x8, 0x3, 0x12,0x26,0xae,0x1b,0x90,0xe5,0x27, +0xbc,0xb9,0x8, 0xf0,0xbd,0xde,0x58,0x2, 0x7d,0xed,0xe5,0x28,0xbc,0xb0,0x48,0xdb, +0x7d,0x3f,0x3e,0x34,0x3e,0x34,0x7e,0x24,0x0, 0xa, 0x12,0x14,0x9f,0xbd,0x3e,0x58, +0xc, 0x7e,0x73,0x4e,0x9d,0xbe,0x70,0x28,0x50,0x3, 0x12,0xad,0xec,0xb, 0x10,0x12, +0x26,0xe5,0x28,0x2, 0x81,0x41,0x22,0xca,0xd8,0xca,0x79,0xc2,0x0, 0xc2,0x1, 0xc2, +0x4, 0xd2,0x2, 0xd2,0x3, 0x6c,0xdd,0x80,0x41,0x12,0xac,0xf1,0x12,0x26,0xcd,0x50, +0x4, 0xd2,0x1, 0x80,0x33,0xd2,0x0, 0xd2,0x4, 0x7e,0x73,0x40,0x12,0xa, 0x27,0x1b, +0x24,0xa, 0x3e,0xbd,0x32,0x58,0x2, 0xc2,0x2, 0x4c,0xff,0x78,0x8, 0x7c,0xbf,0x4, +0x12,0x26,0xb8,0x18,0x13,0x7e,0xb3,0x40,0x11,0x14,0xbc,0xbf,0x78,0x8, 0x7c,0xbf, +0x14,0x12,0x26,0xb8,0x18,0x2, 0xc2,0x3, 0xb, 0xd0,0x7e,0xb3,0x3e,0x53,0xbc,0xbd, +0x38,0xb7,0xa2,0x4, 0x82,0x3, 0x92,0x3, 0xa2,0x4, 0x82,0x2, 0x92,0x2, 0xc2,0x3, +0x70,0xe, 0x7e,0xb3,0x4e,0x9a,0xbe,0xb0,0x0, 0x28,0x5, 0x14,0x7a,0xb3,0x4e,0x9a, +0xa2,0x24,0x92,0x6, 0x12,0x7f,0xff,0x92,0x5, 0x30,0x1, 0x6, 0xa2,0x5, 0x92,0x1, +0x92,0x24,0x7e,0x73,0x4e,0x9a,0xbe,0x70,0x0, 0x28,0x5, 0x20,0x3, 0x2, 0xc2,0x1, +0xa2,0x3, 0x82,0x0, 0x82,0x1, 0x50,0x2, 0xc2,0x0, 0xa2,0x0, 0x82,0x1, 0x50,0x29, +0x7e,0xb3,0x4e,0x99,0xb4,0x1, 0x4, 0xc2,0x1, 0x80,0x1e,0xb4,0x2, 0x7, 0x20,0x2, +0x4, 0xc2,0x1, 0x80,0x14,0x70,0x12,0x7e,0x27,0x3e,0x59,0x7e,0x34,0x0, 0x5, 0xad, +0x32,0xbe,0x37,0x3e,0x61,0x8, 0x2, 0xc2,0x1, 0x30,0x1, 0x2, 0xc2,0x0, 0x30,0x1, +0x4, 0x74,0x2, 0x80,0x12,0x30,0x0, 0xe, 0x74,0x1, 0x7a,0xb3,0x4e,0x99,0x74,0x8, +0x7a,0xb3,0x4e,0x9a,0x80,0x5, 0xe4,0x7a,0xb3,0x4e,0x99,0x6c,0xdd,0x80,0x22,0x12, +0xac,0xf1,0x12,0x26,0xcd,0x50,0x5, 0x20,0x1, 0x2, 0x80,0xc, 0x7c,0xbf,0x7c,0x7e, +0x12,0x26,0xcd,0x40,0xa, 0x20,0x0, 0x7, 0xc2,0x6, 0x7c,0xbd,0x12,0x26,0xfa,0xb, +0xd0,0x7e,0x73,0x3e,0x53,0xbc,0x7d,0x38,0xd6,0xda,0x79,0xda,0xd8,0x22,0x7c,0xb9, +0x7c,0x70,0x12,0x23,0x82,0x7d,0xd3,0x22,0x7c,0x7e,0x12,0x23,0x82,0x7e,0xf4,0x0, +0x3, 0xad,0xf3,0x7c,0xbf,0x7c,0x7e,0x12,0x23,0x82,0xbd,0x3f,0x22,0x7c,0xa7,0x7c, +0x7b,0x90,0x14,0x28,0xe4,0x93,0xbc,0xb7,0x78,0x9, 0x7c,0xba,0x12,0x96,0xb4,0x50, +0x2, 0xd3,0x22,0xc3,0x22,0x7e,0x73,0x3e,0x53,0xbc,0x71,0x22,0x7c,0xb9,0x7c,0x70, +0x12,0x23,0x82,0xbd,0x3d,0x22,0xd2,0x6, 0x7c,0xb3,0x7c,0x7b,0xc4,0x23,0x54,0x1f, +0x7c,0xab,0x12,0x58,0xc1,0x30,0x6, 0xf, 0xa, 0x3a,0x2e,0x34,0x3d,0x41,0x7e,0x39, +0xa0,0x4c,0xba,0x7a,0x39,0xb0,0x22,0x64,0xff,0xa, 0x2a,0x2e,0x24,0x3d,0x41,0x7e, +0x29,0x70,0x5c,0x7b,0x7a,0x29,0x70,0x22,0x12,0x7f,0xa8,0x28,0x3a,0x7e,0xb3,0x3f, +0xde,0x70,0x34,0x7e,0x37,0x3e,0x55,0xbe,0x34,0x0, 0x26,0x28,0x2f,0x7e,0xb3,0x4f, +0x93,0xbe,0xb0,0x2, 0x50,0x26,0x4, 0x7a,0xb3,0x4f,0x93,0x6c,0x33,0x80,0x9, 0xc2, +0x6, 0x7c,0xb3,0x12,0x26,0xfa,0xb, 0x30,0x7e,0x23,0x3e,0x53,0xbc,0x23,0x38,0xef, +0xe4,0x7a,0xb3,0x3e,0x53,0x80,0x5, 0xe4,0x7a,0xb3,0x4f,0x93,0x2, 0x23,0x3d,0xc2, +0x6, 0x7c,0xbf,0x12,0x26,0xfa,0xb, 0xf0,0x22,0xca,0xf8,0xc2,0x0, 0xc2,0x1, 0x12, +0xad,0xf3,0x68,0x70,0x7e,0xb3,0x3e,0x53,0x70,0x5, 0x12,0x98,0xde,0x80,0x65,0x12, +0x97,0x1, 0x92,0x1, 0x12,0x98,0xfd,0x92,0x0, 0x30,0x0, 0x13,0x7e,0x34,0x14,0x55, +0x12,0x1d,0xf2,0x7a,0x37,0x4f,0x91,0x74,0x1, 0x7a,0xb3,0x4f,0x8d,0x80,0x14,0x30, +0x1, 0x19,0x7e,0x34,0x14,0x55,0x12,0x1d,0xf2,0x7a,0x37,0x4f,0x91,0x74,0x1, 0x7a, +0xb3,0x4f,0x8e,0x74,0x1, 0x7a,0xb3,0x4f,0x8c,0x80,0x3, 0x12,0x98,0xde,0x7e,0xb3, +0x4f,0x8d,0x60,0xe, 0x6c,0xff,0x80,0x3, 0x12,0x27,0x6f,0x12,0x27,0xf7,0x38,0xf8, +0x80,0x12,0x7e,0xb3,0x4f,0x8e,0x60,0xc, 0x6c,0xff,0x80,0x3, 0x12,0x27,0x6f,0x12, +0x27,0xf7,0x38,0xf8,0xda,0xf8,0x22,0x7e,0x73,0x3e,0x53,0xbc,0x7f,0x22,0xca,0x3b, +0x7e,0xf3,0x4f,0x55,0x7e,0x30,0x27,0xac,0x3f,0x9, 0xb1,0x4b,0xa2,0xf5,0x2b,0x9, +0xb1,0x4b,0xa3,0xf5,0x2c,0x7e,0x4, 0x0, 0x27,0xca,0x9, 0x2e,0x14,0x4b,0xa2,0x6d, +0x0, 0x7e,0x18,0x4e,0x1c,0x12,0x16,0x35,0x1b,0xfd,0x74,0x27,0xac,0xbf,0x9, 0xe5, +0x4b,0xa6,0x7e,0xd0,0xb5,0xac,0xde,0x2e,0x64,0x1, 0x0, 0xe4,0x12,0x4f,0xc9,0x12, +0x2a,0x16,0x5e,0x24,0x1, 0x0, 0x68,0x9, 0x5e,0x60,0xfe,0x12,0x2a,0x24,0x12,0x30, +0x19,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x1, 0x68,0x2e,0x5e,0x70,0xfe,0x7a,0x37,0x2d, +0x6, 0x7e,0xb3,0x4e,0x1c,0x12,0x30,0x1, 0x50,0xc, 0x7e,0xb3,0x4e,0x1c,0x12,0x30, +0x7a,0x12,0x2a,0x90,0x80,0x12,0x7e,0xa1,0x2b,0x7e,0x70,0x27,0xac,0x7f,0x19,0xa3, +0x4b,0xa2,0xe5,0x2b,0x7a,0xb3,0x4e,0x1c,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x2, 0x68, +0x2e,0x5e,0x70,0xfd,0x7a,0x37,0x2d,0x6, 0x7e,0xb3,0x4e,0x1d,0x12,0x31,0x14,0x50, +0xc, 0x7e,0xb3,0x4e,0x1d,0x12,0x2d,0x3a,0x12,0x2a,0x90,0x80,0x12,0x7e,0xa1,0x2c, +0x7e,0x70,0x27,0xac,0x7f,0x19,0xa3,0x4b,0xa3,0xe5,0x2c,0x7a,0xb3,0x4e,0x1d,0x12, +0x2a,0x16,0x5e,0x24,0x0, 0x4, 0x68,0x34,0x5e,0x70,0xfb,0x12,0x2a,0x1d,0x12,0x2a, +0x57,0x7e,0x30,0x2c,0xac,0x3e,0x12,0x2c,0x5b,0x74,0x1, 0x7e,0x70,0x27,0xac,0x7f, +0x12,0xad,0xce,0x12,0x2c,0x62,0x12,0x2a,0x2b,0x12,0x2d,0x1b,0x12,0x2d,0x31,0x49, +0x25,0x0, 0xdf,0x12,0x0, 0x2e,0x12,0x31,0xd, 0x12,0x50,0x44,0x12,0x2a,0x16,0x5e, +0x24,0x0, 0x8, 0x68,0xe, 0x5e,0x70,0xf7,0x7a,0x37,0x2d,0x6, 0x7e,0xb3,0x4e,0x1f, +0x12,0x30,0xc6,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x10,0x68,0xf, 0x5e,0x70,0xef,0x12, +0x2a,0x24,0x12,0x2a,0x57,0x12,0x2a,0x2b,0x12,0x2d,0x1b,0x12,0x2a,0x16,0x5e,0x24, +0x0, 0x20,0x68,0x41,0x5e,0x70,0xdf,0x7a,0x37,0x2d,0x6, 0x4e,0x60,0x2, 0x12,0x2a, +0x1d,0x12,0x2a,0x57,0x12,0x2c,0x62,0x12,0x2a,0x4b,0x74,0xa, 0xac,0xbf,0x12,0xad, +0x76,0x12,0x2a,0x4b,0x7e,0x70,0x27,0xac,0x7f,0x12,0xad,0x81,0x7c,0xbf,0x12,0xa8, +0x61,0x12,0x2d,0x31,0x49,0x25,0x0, 0xdf,0x12,0x0, 0x2e,0x12,0x2a,0x45,0x7e,0x24, +0x0, 0x10,0x12,0xc, 0xcc,0x12,0x2a,0x16,0x5e,0x24,0x0, 0x40,0x68,0xc, 0x5e,0x70, +0xbf,0x12,0x2a,0x24,0x12,0x4e,0x89,0x12,0x46,0xa, 0x12,0x2a,0x16,0x5e,0x24,0x0, +0x80,0x68,0xa, 0x5e,0x70,0x7f,0x7a,0x37,0x2d,0x6, 0x12,0x3f,0x7a,0x12,0x2a,0x16, +0x5e,0x24,0x2, 0x0, 0x68,0x3b,0x5e,0x60,0xfd,0x7a,0x37,0x2d,0x6, 0x74,0x27,0xac, +0xbf,0x49,0xe5,0x4b,0xa9,0xb, 0xe4,0x7e,0xf7,0x4e,0x45,0xad,0xef,0xbe,0x78,0x7f, +0xff,0x28,0x4, 0x7e,0x78,0x7f,0xff,0x7e,0x8, 0x0, 0x69,0x12,0x2d,0x22,0x7e,0x8, +0x0, 0xa5,0x12,0x2d,0x22,0x7e,0x8, 0x0, 0x69,0x7d,0x3f,0x12,0xa9,0x1d,0x12,0xc, +0xcc,0x12,0x2a,0x16,0x5e,0x24,0x4, 0x0, 0x68,0x7, 0x5e,0x60,0xfb,0x7a,0x37,0x2d, +0x6, 0x12,0x2a,0x16,0x5e,0x24,0x10,0x0, 0x68,0x7, 0x5e,0x60,0xef,0x7a,0x37,0x2d, +0x6, 0x12,0x2a,0x16,0x5e,0x24,0x20,0x0, 0x68,0x9, 0x5e,0x60,0xdf,0x12,0x2a,0x24, +0x12,0x50,0x4b,0xda,0x3b,0x22,0x7e,0x37,0x2d,0x6, 0x7d,0x23,0x22,0x7a,0x37,0x2d, +0x6, 0x4e,0x60,0x10,0x7a,0x37,0x2d,0x6, 0x7c,0xbf,0x22,0x7e,0x30,0x2c,0xac,0x3e, +0x2e,0x14,0x0, 0xe7,0x6d,0x0, 0x74,0xa, 0xac,0xbf,0x49,0x35,0x4c,0x4e,0x49,0x25, +0x4c,0x4c,0x12,0x9, 0xad,0x7d,0x36,0x2e,0x34,0x0, 0x6, 0x7e,0x30,0x2c,0xac,0x3e, +0x2e,0x14,0x0, 0xe7,0x6d,0x0, 0x22,0xca,0xf8,0x7c,0xfb,0x12,0x2a,0x90,0x7e,0xa3, +0x4e,0x1e,0x7e,0x70,0x27,0xac,0x7f,0x19,0xa3,0x4b,0xa4,0x6c,0xaa,0x7e,0x50,0x2, +0xac,0x5a,0x49,0x42,0x4e,0x23,0x7e,0x70,0x27,0xac,0x7f,0x2d,0x32,0x59,0x43,0x4b, +0xa9,0xb, 0xa0,0xbe,0xa0,0x10,0x40,0xe5,0x7c,0xbf,0x12,0x4a,0xe0,0xda,0xf8,0x22, +0x12,0xad,0xdc,0x68,0x42,0xe5,0x13,0x60,0x3e,0x7e,0xb3,0x4e,0x1c,0x7e,0x73,0x4e, +0x1d,0x12,0xa1,0x8f,0x7d,0x23,0x7e,0x34,0x0, 0x3, 0xad,0x32,0x7e,0x24,0x0, 0xa, +0x8d,0x32,0x6c,0xaa,0x7e,0x50,0x2, 0xac,0x5a,0x49,0x12,0x4e,0x23,0xbd,0x13,0x28, +0xf, 0x59,0x32,0x4e,0x23,0x7e,0x27,0x2d,0x6, 0x4e,0x50,0x20,0x7a,0x27,0x2d,0x6, +0xb, 0xa0,0xbe,0xa0,0x10,0x78,0xdd,0x22,0xca,0x79,0x7c,0xeb,0xbe,0xe0,0x4, 0x40, +0x2, 0x61,0xad,0x74,0x27,0xac,0xbe,0x9, 0xf5,0x4b,0xa6,0xbe,0xf0,0x3, 0x40,0x2, +0x61,0xad,0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x4c,0x3f,0x54,0x3f,0xa, 0x3b,0x74,0x2c, +0xac,0xbf,0x59,0x35,0x0, 0xdb,0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x4c,0x3e,0x54,0x1f, +0x7c,0x6b,0x6c,0x77,0x12,0x2b,0xb6,0x74,0x2c,0xac,0xbf,0x59,0x35,0x0, 0xdd,0x12, +0x2c,0x56,0x74,0x1, 0x7e,0x70,0x27,0xac,0x7e,0x12,0xad,0xce,0x7e,0x30,0x2c,0xac, +0x3f,0x12,0x2a,0x50,0x7e,0x70,0x27,0xac,0x7e,0x12,0xad,0x81,0x7e,0x30,0x2c,0xac, +0x3f,0x12,0x30,0x73,0x74,0x27,0xac,0xbe,0x9, 0x75,0x4b,0xa2,0xa, 0x37,0x12,0x2b, +0xb6,0x12,0xd, 0xd3,0x12,0x2d,0x74,0x74,0x27,0xac,0xbe,0x9, 0x75,0x4b,0xa3,0xa, +0x37,0x12,0x2b,0xb6,0x12,0xd, 0xe5,0x12,0x2d,0x74,0x74,0xa, 0xac,0xbe,0x12,0x2c, +0x71,0x7e,0x30,0x2c,0xac,0x3f,0x12,0x2a,0x50,0x74,0xa, 0xac,0xbe,0x12,0xad,0x76, +0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xef,0x6d,0x0, 0x74,0x27,0xac,0xbe,0x9, +0xb5,0x4b,0xa5,0x12,0xc, 0xaa,0xe4,0x12,0x4f,0xc9,0x7e,0x70,0xb5,0xac,0x7f,0x2e, +0x34,0x1, 0x0, 0x12,0x2c,0x56,0x7e,0x24,0x0, 0x16,0x12,0xc, 0xcc,0xda,0x79,0x22, +0xa, 0x37,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x3e,0x34,0x22,0x7e,0x24,0x4d, +0x79,0x30,0x21,0x7a,0xc2,0x21,0x7e,0x29,0x70,0x12,0x2b,0xb0,0x7a,0x37,0x3f,0xeb, +0x9, 0x72,0x0, 0x1, 0x12,0x2b,0xb0,0x7a,0x37,0x3f,0xed,0x9, 0x72,0x0, 0x2, 0x12, +0x2b,0xb0,0x7a,0x37,0x3f,0xf1,0x9, 0x72,0x0, 0x3, 0x12,0x2b,0xb0,0x7a,0x37,0x3f, +0xf3,0x9, 0x72,0x0, 0x5, 0x12,0x2b,0xb0,0x7a,0x37,0x3f,0xfb,0x9, 0x72,0x0, 0x40, +0x7a,0x73,0x40,0x1, 0x9, 0x72,0x0, 0x41,0xbe,0x73,0x40,0x3, 0x68,0x28,0x7a,0x73, +0x40,0x3, 0x74,0x1, 0x7a,0xb3,0x40,0x4, 0x7e,0xb3,0x40,0x3, 0xb4,0x1, 0xf, 0x7e, +0x73,0x40,0x1, 0x7a,0x73,0x4d,0x78,0xe4,0x7a,0xb3,0x40,0x1, 0x80,0x8, 0x7e,0x73, +0x4d,0x78,0x7a,0x73,0x40,0x1, 0x7e,0x73,0x40,0x1, 0x7a,0x73,0x4d,0xb9,0x7e,0x37, +0x3f,0xeb,0x7a,0x37,0x4d,0xe9,0x4d,0x33,0x78,0xb, 0x7e,0x34,0x13,0x89,0x12,0x1d, +0xf2,0x7a,0x37,0x4d,0xe9,0x22,0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xdb,0x6d, +0x0, 0x22,0x7e,0x30,0x2c,0xac,0x3e,0x2e,0x14,0x0, 0xdf,0x6d,0x0, 0x74,0xa, 0xac, +0xbf,0x9, 0xb5,0x4c,0x46,0x2, 0xd, 0x73,0x12,0x2d,0x12,0x7d,0x1, 0x5e,0x4, 0x0, +0x1, 0x78,0xa, 0xe4,0x7a,0xb3,0x4f,0x55,0x75,0x13,0x0, 0x80,0x31,0x5e,0x14,0x0, +0x2, 0x78,0x7, 0x74,0x1, 0x12,0x2d,0x29,0x80,0x24,0x7e,0xb3,0x4f,0x55,0xbe,0xb0, +0x1, 0x68,0x2, 0x70,0x19,0x12,0x2d,0x9, 0x68,0xb, 0x74,0x2, 0x7a,0xb3,0x4f,0x55, +0x75,0x13,0x2, 0x80,0x9, 0x74,0x3, 0x7a,0xb3,0x4f,0x55,0x75,0x13,0x3, 0x74,0x1, +0x12,0x2a,0xd8,0x7e,0xb3,0x4f,0x55,0x24,0x0, 0x68,0x2d,0x24,0xfd,0x68,0x16,0x4, +0x78,0x2a,0x12,0x2d,0x12,0x5e,0x14,0x0, 0x2, 0x68,0x2d,0x12,0x2d,0x9, 0x78,0x28, +0x74,0x1, 0x2, 0x5, 0xbc,0x12,0x2d,0x12,0x5e,0x14,0x0, 0x2, 0x68,0x1a,0x12,0x2d, +0x9, 0x68,0x15,0x74,0x1, 0x2, 0x5, 0x30,0xe4,0x2, 0x2a,0xd8,0x7e,0xf, 0x4f,0xa1, +0x12,0x1f,0xe3,0x74,0x1, 0x12,0x2d,0x29,0x22,0x69,0x31,0x0, 0xe, 0x5e,0x34,0x0, +0x8, 0x22,0x7e,0x1f,0x4f,0xa1,0x69,0x11,0x0, 0x6, 0x22,0x7e,0x24,0x0, 0x4, 0x2, +0xc, 0xcc,0x7e,0x37,0x4e,0x43,0x2, 0xc, 0x88,0x7a,0xb3,0x4f,0x55,0x75,0x13,0x1, +0x22,0x7d,0x36,0xb, 0x35,0x74,0x2c,0xac,0xbe,0x22,0xca,0x3b,0x7c,0xfb,0x6c,0xee, +0x74,0x27,0xac,0xbe,0x19,0xf5,0x4b,0xa3,0xb, 0xe0,0xbe,0xe0,0x4, 0x78,0xf1,0x7e, +0x64,0x1, 0x0, 0x6c,0xee,0x7e,0x30,0x2c,0xac,0x3e,0x12,0x2d,0x79,0xa, 0x3f,0x12, +0x2b,0xb6,0x12,0xd, 0xe5,0x12,0x2d,0x31,0x49,0x25,0x0, 0xdf,0x12,0x30,0xb9,0x40, +0xe4,0xda,0x3b,0x22,0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xdf,0x6d,0x0, 0x22, +0xca,0x3b,0x7e,0x73,0x4f,0x55,0xa, 0x27,0x12,0x4e,0x80,0x12,0xaa,0x22,0x6d,0x22, +0x7a,0x1d,0x27,0x7e,0x38,0x44,0x8d,0x7e,0x73,0x40,0x13,0x7a,0x73,0x44,0x88,0x7e, +0x73,0x40,0x14,0x7a,0x73,0x44,0x89,0x7e,0x73,0x4e,0x1d,0x7a,0x73,0x44,0x8a,0x7e, +0x73,0x4e,0x14,0x7a,0x73,0x44,0x8b,0x7e,0x73,0x4e,0x15,0x7a,0x73,0x44,0x8c,0x7e, +0x8, 0x44,0x8d,0x7e,0x34,0x0, 0x8, 0xe4,0x12,0x16,0x5a,0x7e,0x34,0x0, 0x20,0xca, +0x39,0x7e,0x18,0x4e,0x23,0x7e,0x8, 0x44,0x95,0x12,0x16,0x35,0x1b,0xfd,0x74,0x5, +0x7a,0xb3,0x4e,0x1d,0xe4,0x7a,0xb3,0x4e,0x14,0x74,0x2, 0x7a,0xb3,0x4e,0x15,0xe4, +0x7a,0xb3,0x44,0x87,0x7e,0x34,0x0, 0x2, 0x12,0x2f,0xa, 0x59,0x35,0x4e,0x23,0x12, +0x2f,0x12,0xb4,0x10,0xef,0x12,0x2f,0x1c,0x7a,0xb3,0x44,0x87,0x7e,0xa3,0x44,0x87, +0x4c,0xaa,0x78,0xd, 0x7e,0xb3,0x44,0x85,0x54,0x1, 0xb4,0x1, 0x4, 0x74,0x1, 0x80, +0x12,0xbe,0xa0,0x1, 0x78,0x14,0x7e,0xb3,0x44,0x85,0x54,0x2, 0x1e,0xb0,0xb4,0x1, +0x9, 0x74,0x4, 0x7a,0xb3,0x40,0x13,0xe4,0x80,0x34,0xbe,0xa0,0x2, 0x78,0x16,0x7e, +0xb3,0x44,0x85,0x54,0x4, 0x1e,0xb0,0x1e,0xb0,0xb4,0x1, 0x9, 0xe4,0x7a,0xb3,0x40, +0x13,0x74,0x1, 0x80,0x19,0xbe,0xa0,0x3, 0x78,0x3a,0x7e,0xb3,0x44,0x85,0x54,0x8, +0xc4,0x23,0x54,0x1f,0xb4,0x1, 0x2d,0xe4,0x7a,0xb3,0x40,0x13,0x74,0x4, 0x7a,0xb3, +0x40,0x14,0x7e,0x34,0x13,0x85,0x12,0x1d,0xf2,0x12,0x1d,0x19,0x12,0x6b,0x8f,0x12, +0x1c,0xe1,0x12,0x2f,0xa, 0x7e,0x1d,0x27,0x2d,0x35,0xb, 0x1a,0x10,0x7f,0x13,0x2d, +0x35,0x1b,0x1a,0x10,0x12,0x2f,0x12,0xb4,0x4, 0x2, 0x80,0x2, 0xc1,0xc, 0xe4,0x7a, +0xb3,0x44,0x87,0x12,0x2f,0xa, 0x7f,0x13,0x2d,0x35,0xb, 0x1a,0x10,0x7e,0x1d,0x27, +0x2d,0x35,0x1b,0x1a,0x10,0x12,0x2f,0x12,0x7e,0x73,0x44,0x87,0xbe,0x70,0x4, 0x40, +0xe2,0x7e,0x73,0x44,0x88,0x7a,0x73,0x40,0x13,0x7e,0x73,0x44,0x89,0x7a,0x73,0x40, +0x14,0x7e,0x73,0x44,0x8a,0x7a,0x73,0x4e,0x1d,0x7e,0x73,0x44,0x8b,0x7a,0x73,0x4e, +0x14,0x7e,0x73,0x44,0x8c,0x7a,0x73,0x4e,0x15,0x7e,0x34,0x0, 0x20,0xca,0x39,0x7e, +0x18,0x44,0x95,0x7e,0x8, 0x4e,0x23,0x12,0x16,0x35,0x1b,0xfd,0x12,0x2f,0x1c,0x7a, +0xb3,0x4e,0x1a,0x7a,0xb3,0x4e,0x19,0xda,0x3b,0x22,0x7e,0xa3,0x44,0x87,0x74,0x2, +0xa4,0x22,0x7e,0xb3,0x44,0x87,0x4, 0x7a,0xb3,0x44,0x87,0x22,0x7e,0xb3,0x4e,0x1d, +0x12,0x2d,0x3a,0x7e,0x37,0x2d,0x6, 0x4e,0x60,0x1, 0x7a,0x37,0x2d,0x6, 0x4e,0x70, +0x20,0x7a,0x37,0x2d,0x6, 0x12,0x27,0xfe,0xe4,0x22,0xca,0xf8,0x12,0xa2,0x4c,0x7e, +0xf0,0x1, 0x7c,0xbf,0x12,0x2a,0xd8,0xb, 0xf0,0xbe,0xf0,0x4, 0x78,0xf4,0xe5,0x13, +0x70,0x4, 0xe4,0x12,0x2a,0xd8,0xda,0xf8,0x22,0x7e,0xf, 0x4f,0xa1,0x69,0x30,0x0, +0x6, 0x5e,0x34,0x0, 0x1, 0x68,0x18,0x12,0x33,0x7b,0x5e,0x34,0x0, 0x2, 0x68,0x3, +0x12,0xac,0x6e,0x74,0x3, 0x12,0xa9,0x6f,0x74,0x1, 0x12,0x2a,0xd8,0x80,0x33,0x12, +0xa7,0xd9,0x75,0x13,0x0, 0xe4,0x7a,0xb3,0x4f,0x55,0x74,0x1, 0x12,0xa9,0x6f,0xe4, +0x12,0x2a,0xd8,0x7e,0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0xa, 0xb, 0xa, 0x30,0x4e,0x60, +0x10,0x1b,0xa, 0x30,0xe4,0x7a,0xb3,0x4f,0x4c,0x12,0x1b,0xed,0x12,0x1f,0xf1,0x12, +0x35,0x1, 0xe5,0x13,0x2, 0x2f,0xb7,0x7c,0xab,0x12,0x4f,0x8c,0x1b,0xa0,0x68,0x12, +0x1b,0xa0,0x68,0x13,0x1b,0xa0,0x68,0x14,0x2e,0xa0,0x3, 0x78,0x12,0x12,0xa2,0x87, +0x80,0xd, 0x12,0xa2,0x9c,0x80,0x8, 0x12,0xa2,0x66,0x80,0x3, 0x12,0xa2,0xe1,0x2, +0x2f,0xe2,0xe4,0x7a,0xb3,0x3, 0xda,0x6c,0xaa,0x80,0xd, 0x12,0xa6,0x48,0x2e,0xb3, +0x3, 0xda,0x7a,0xb3,0x3, 0xda,0xb, 0xa0,0x7e,0xb3,0x3, 0xcf,0xbc,0xba,0x38,0xeb, +0x22,0x7c,0x7b,0x74,0x8, 0xac,0x7b,0xbe,0x34,0x0, 0x5a,0x38,0x2, 0xc3,0x22,0xbe, +0x34,0x0, 0x1e,0x50,0x2, 0xc3,0x22,0xd3,0x22,0x7c,0x7b,0x74,0x27,0xac,0xb7,0x9, +0x95,0x4b,0xa6,0x7e,0x63,0x4e,0x14,0x74,0x2, 0xac,0xb7,0x19,0x65,0x4c,0x3e,0x7e, +0x63,0x4e,0x15,0x74,0x2, 0xac,0xb7,0x19,0x65,0x4c,0x3f,0x74,0x2, 0xac,0x7b,0x2e, +0x34,0x4c,0x3e,0x7e,0x14,0x0, 0x2d,0x12,0x15,0x72,0x7e,0x30,0x2c,0xac,0x39,0x7d, +0x31,0x2e,0x34,0x0, 0xdb,0x12,0x30,0x73,0x12,0xb, 0x44,0x7e,0x70,0xb5,0xac,0x79, +0x2e,0x34,0x1, 0x0, 0x7e,0x30,0x2c,0xac,0x39,0x12,0x2c,0x5b,0x7e,0x24,0x0, 0x2, +0x2, 0xc, 0xcc,0x2e,0x14,0x0, 0xdd,0x6d,0x0, 0x22,0xca,0x3b,0x7c,0xfb,0x6c,0xee, +0x74,0x27,0xac,0xbe,0x19,0xf5,0x4b,0xa2,0xb, 0xe0,0xbe,0xe0,0x4, 0x78,0xf1,0x7e, +0x64,0x1, 0x0, 0x6c,0xee,0x7e,0x30,0x2c,0xac,0x3e,0x12,0x30,0x73,0xa, 0x3f,0x12, +0x2b,0xb6,0x12,0xd, 0xd3,0x7d,0x36,0xb, 0x34,0x74,0x2c,0xac,0xbe,0x49,0x25,0x0, +0xdd,0x12,0x30,0xb9,0x40,0xdf,0xda,0x3b,0x22,0x12,0x0, 0x2e,0x2e,0x64,0x0, 0xb5, +0xb, 0xe0,0xbe,0xe0,0x3, 0x22,0xca,0x3b,0x7c,0xfb,0x6c,0xee,0x74,0x27,0xac,0xbe, +0x19,0xf5,0x4b,0xa5,0xb, 0xe0,0xbe,0xe0,0x4, 0x78,0xf1,0x7e,0x64,0x1, 0xa, 0x6c, +0xee,0x7e,0x30,0x2c,0xac,0x3e,0x2e,0x14,0x0, 0xef,0x6d,0x0, 0x7c,0xbf,0x12,0xc, +0xaa,0x12,0x31,0xd, 0x49,0x25,0x0, 0xef,0x12,0x6, 0x48,0x12,0x31,0xd, 0x49,0x25, +0x0, 0xef,0x12,0x6, 0xc5,0x12,0x30,0xbc,0x40,0xd7,0xda,0x3b,0x22,0x7d,0x36,0x74, +0x2c,0xac,0xbe,0x22,0x7c,0x7b,0x74,0x8, 0xac,0x7b,0xbe,0x34,0x0, 0x12,0x50,0x2, +0xc3,0x22,0xd3,0x22,0xca,0x79,0x7c,0xeb,0xbe,0xe0,0xfa,0x78,0x6, 0x7e,0xb3,0x2c, +0xff,0x41,0xc9,0xbe,0xe0,0xfc,0x78,0x4, 0x74,0x1, 0x41,0xc9,0xbe,0xe0,0x5b,0x38, +0x8, 0xa, 0x3e,0x9, 0xb3,0x4d,0xeb,0x41,0xc9,0xbe,0xe0,0x6a,0x68,0x5, 0xbe,0xe0, +0x6b,0x78,0x22,0x12,0x40,0x18,0x7e,0x37,0x2c,0xfc,0x7d,0x23,0xb, 0x24,0x7a,0x27, +0x2c,0xfc,0x2e,0x37,0x31,0x74,0x7e,0x39,0xf0,0xbe,0xe0,0x6b,0x78,0x3, 0x75,0xf, +0x6a,0x7c,0xbf,0x41,0xc9,0xbe,0xe0,0x6e,0x68,0x5, 0xbe,0xe0,0x6f,0x78,0x22,0x12, +0x3f,0xc1,0x7e,0x37,0x2c,0xfa,0x7d,0x23,0xb, 0x24,0x7a,0x27,0x2c,0xfa,0x2e,0x37, +0x2d,0x8, 0x7e,0x39,0xf0,0xbe,0xe0,0x6f,0x78,0x3, 0x75,0xf, 0x6e,0x7c,0xbf,0x41, +0xc9,0xbe,0xe0,0x6c,0x68,0x5, 0xbe,0xe0,0x6d,0x78,0x1f,0x7e,0x37,0x31,0x72,0x7d, +0x23,0xb, 0x24,0x7a,0x27,0x31,0x72,0x2e,0x37,0x2d,0x4, 0x7e,0x39,0xf0,0xbe,0xe0, +0x6d,0x78,0x3, 0x75,0xf, 0x6c,0x7c,0xbf,0x41,0xc9,0xbe,0xe0,0x89,0x68,0x5, 0xbe, +0xe0,0x8a,0x78,0x1f,0x7e,0x37,0x31,0x78,0x7d,0x23,0xb, 0x24,0x7a,0x27,0x31,0x78, +0x2e,0x37,0x31,0x76,0x7e,0x39,0xf0,0xbe,0xe0,0x8a,0x78,0x3, 0x75,0xf, 0x89,0x7c, +0xbf,0x41,0xc9,0xbe,0xe0,0x70,0x40,0xc, 0xbe,0xe0,0x7f,0x38,0x7, 0x7c,0xbe,0x12, +0x32,0xcc,0x41,0xc9,0xbe,0xe0,0x81,0x68,0x5, 0xbe,0xe0,0x82,0x78,0x26,0x7e,0x24, +0xe, 0x6, 0x7e,0xb3,0x4e,0x2, 0xa, 0x3b,0x2d,0x32,0x6d,0x22,0x2e,0x24,0x0, 0xff, +0x7e,0x1b,0xf0,0x4, 0x7a,0xb3,0x4e,0x2, 0xbe,0xe0,0x82,0x78,0x3, 0x75,0xf, 0x81, +0x7c,0xbf,0x41,0xc9,0xbe,0xe0,0x86,0x78,0x6, 0x7e,0xb3,0x2d,0x1, 0x41,0xc9,0xbe, +0xe0,0x87,0x78,0x6, 0x7e,0xb3,0x2c,0xf9,0x80,0x7f,0xbe,0xe0,0x88,0x78,0x1a,0x7e, +0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x10,0x5e,0x34,0x38,0x0, 0xa, 0x56,0x1e,0x54,0x1e, +0x54,0x1e,0x54,0x5e,0x54,0x0, 0x7, 0x80,0x60,0xbe,0xe0,0x90,0x40,0xc, 0xbe,0xe0, +0x94,0x38,0x7, 0x7c,0xbe,0x12,0x52,0x9b,0x80,0x4f,0xbe,0xe0,0x99,0x68,0x5, 0xbe, +0xe0,0x9a,0x78,0x1d,0x7e,0xa3,0x2c,0xfe,0x7c,0xba,0x4, 0x7a,0xb3,0x2c,0xfe,0xa, +0x3a,0x9, 0xf3,0x31,0x7a,0xbe,0xe0,0x9a,0x78,0x3, 0x75,0xf, 0x99,0x7c,0xbf,0x80, +0x28,0xbe,0xe0,0x9b,0x78,0x6, 0x7e,0xb3,0x2d,0x0, 0x80,0x1d,0xbe,0xe0,0xf6,0x78, +0x6, 0x7e,0xb3,0x4f,0x94,0x80,0x12,0xbe,0xe0,0xf7,0x78,0xc, 0x7e,0x57,0x4f,0x95, +0x7e,0x44,0x0, 0x64,0x8d,0x54,0x80,0x1, 0xe4,0xda,0x79,0x22,0x7c,0x6b,0x7e,0x70, +0xff,0x7c,0xb6,0x24,0x8c,0xbe,0xb0,0xa, 0x40,0x2, 0x61,0x78,0x7e,0xa0,0x3, 0xa4, +0x90,0x32,0xe4,0x73,0x2, 0x33,0x22,0x2, 0x33,0x78,0x2, 0x33,0x2, 0x2, 0x33,0x10, +0x2, 0x33,0x19,0x2, 0x33,0x2b,0x2, 0x33,0x47,0x2, 0x33,0x36,0x2, 0x33,0x4c,0x2, +0x33,0x4c,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0xe, 0x5e,0x34,0x0, 0x4, 0x80,0x68, +0x7e,0x1f,0x4f,0xa1,0x12,0x2d,0x9, 0x80,0x5f,0x12,0x33,0x91,0x5e,0x34,0x0, 0x2, +0x80,0x56,0x12,0x33,0x91,0x5e,0x34,0x0, 0x1, 0x80,0x4d,0x12,0x33,0x91,0x5e,0x34, +0x4, 0x0, 0xa, 0x36,0x80,0xb, 0x12,0x33,0x91,0x5e,0x34,0x8, 0x0, 0xa, 0x36,0x1e, +0x34,0x1e,0x34,0x1e,0x34,0x80,0x31,0x7e,0x71,0xef,0x80,0x2c,0x7e,0x73,0x4f,0x4a, +0x7c,0xb7,0x4, 0x7a,0xb3,0x4f,0x4a,0xa, 0x27,0x9, 0x72,0x1, 0x63,0x7e,0xb3,0x4e, +0xf, 0x4, 0x7a,0xb3,0x4e,0xf, 0x70,0x9, 0x7e,0xb3,0x4e,0xe, 0x4, 0x7a,0xb3,0x4e, +0xe, 0xa5,0xbe,0x7d,0x3, 0x75,0xf, 0x7c,0x7c,0xb7,0x22,0x2e,0x14,0x0, 0x14,0xb, +0xa, 0x30,0x4e,0x70,0x1, 0x1b,0xa, 0x30,0x75,0x13,0x1, 0x74,0x1, 0x7a,0xb3,0x4f, +0x55,0x7e,0x1f,0x4f,0xa1,0x69,0x31,0x0, 0x6, 0x22,0xd2,0x10,0xd2,0x12,0x12,0x33, +0x91,0x5e,0x34,0x0, 0x2, 0x68,0x3, 0x2, 0x33,0xab,0x22,0x12,0xb, 0xb0,0x20,0x29, +0x3, 0x2, 0x33,0xc6,0x22,0xd2,0x10,0xd2,0x12,0x12,0x33,0x91,0x5e,0x34,0x0, 0x2, +0x78,0x3, 0x2, 0x33,0xab,0x22,0x12,0xb, 0xe5,0x12,0xa3,0x56,0x74,0x2, 0x7a,0xb3, +0x3, 0xd3,0x7a,0xb3,0x3, 0xd4,0x22,0xd2,0xe, 0xd2,0x12,0x12,0x33,0x91,0x5e,0x34, +0x0, 0x1, 0x68,0x8, 0xe4,0x7a,0xb3,0x4f,0x49,0x2, 0x33,0xab,0x22,0x7c,0x7b,0x6c, +0xaa,0x12,0x34,0x4c,0x78,0x9, 0x7c,0xb7,0x12,0x58,0x28,0x7c,0xab,0x80,0xa, 0xb4, +0x4, 0x7, 0x7c,0xb7,0x12,0x31,0x24,0x7c,0xab,0x7c,0xba,0x22,0x30,0x90,0x19,0xc2, +0x90,0xe5,0x8, 0x70,0x9, 0x75,0x8, 0x1, 0xe5,0x91,0xf5,0xf, 0x80,0x11,0x7e,0x71, +0x91,0xe5,0xf, 0x12,0x34,0x37,0x5, 0xf, 0x30,0x91,0xb, 0xc2,0x91,0x5, 0xf, 0xe5, +0xf, 0x12,0x33,0xed,0xf5,0x91,0x22,0x7c,0x6b,0x12,0x34,0x4c,0x78,0x5, 0x7c,0xb6, +0x2, 0x53,0x51,0xb4,0x4, 0x5, 0x7c,0xb6,0x2, 0x38,0x14,0x22,0x7e,0xb3,0x4d,0xeb, +0xc4,0x54,0x7, 0x22,0xca,0x3b,0x7e,0x3f,0x4f,0xa1,0x69,0x33,0x0, 0x6, 0x5e,0x34, +0x0, 0x1, 0x68,0x10,0x7f,0x3, 0x12,0x33,0x7b,0x5e,0x34,0x0, 0x2, 0x68,0x18,0x12, +0xac,0x6e,0x80,0x13,0x75,0x13,0x0, 0xe4,0x7a,0xb3,0x4f,0x55,0x7f,0x3, 0x12,0x1b, +0xf1,0x12,0x1f,0xf1,0x12,0x35,0x1, 0xda,0x3b,0x22,0x12,0x67,0xd0,0x12,0x6f,0xf7, +0x12,0x68,0x59,0x12,0x4a,0x73,0x12,0x70,0xb3,0x12,0x1d,0xfa,0x12,0x34,0xe6,0x12, +0x34,0xa8,0x12,0x98,0xc2,0x2, 0x34,0x54,0x12,0x34,0xda,0x7e,0x8, 0x3e,0x89,0x12, +0x34,0xd5,0x7e,0x8, 0x3f,0x3d,0x12,0x34,0xd5,0x7e,0x8, 0x3e,0xe3,0x74,0xff,0x12, +0x16,0x5a,0x7e,0x8, 0x3f,0x97,0x12,0x8c,0x6d,0x7e,0x8, 0x3f,0xdd,0x7e,0x34,0x0, +0xc, 0xe4,0x2, 0x16,0x5a,0x74,0xff,0x12,0x16,0x5a,0x90,0x13,0x7f,0xe4,0x93,0x7c, +0x7b,0x74,0x9, 0xac,0x7b,0x22,0x7e,0x8, 0x3c,0xc9,0x7e,0x34,0x1, 0xa1,0xe4,0x12, +0x16,0x5a,0x90,0x13,0x80,0x12,0x34,0xde,0x7e,0x8, 0x3d,0x45,0x74,0xff,0x2, 0x16, +0x5a,0x7e,0xb3,0x4f,0x55,0x7e,0x70,0x1, 0x12,0x35,0x21,0x7e,0x70,0x1, 0x12,0x35, +0x69,0x12,0xad,0xe4,0x12,0x35,0x75,0x12,0x35,0x8e,0x5e,0x70,0xef,0x1b,0xa, 0x30, +0x22,0x12,0x35,0x29,0x7e,0xb3,0x4f,0x55,0x22,0x70,0xc, 0x12,0x35,0x84,0x12,0xd, +0x8d,0x12,0x35,0x9d,0x2, 0x4, 0x96,0x22,0x12,0x35,0x8e,0x4e,0x70,0x10,0x1b,0xa, +0x30,0x12,0xad,0xe4,0x12,0x35,0x75,0x74,0x14,0x12,0x53,0x95,0x7e,0xb3,0x4f,0x55, +0x7e,0x73,0x4c,0x6e,0x12,0x35,0x75,0x7e,0xb3,0x4f,0x55,0x7e,0x73,0x4c,0x6f,0x12, +0x35,0x21,0x7e,0x73,0x4c,0x70,0x2, 0x35,0x69,0x70,0x9, 0x12,0x35,0x84,0x12,0x35, +0x9a,0x2, 0x4, 0x96,0x22,0x70,0xc, 0x12,0x35,0x84,0x12,0xc, 0xea,0x12,0x35,0x9d, +0x2, 0x4, 0x96,0x22,0x5e,0x70,0x3, 0x7e,0x8, 0x0, 0x57,0x7c,0xb7,0x22,0x7e,0xf, +0x4f,0xa1,0x2e,0x14,0x0, 0x10,0xb, 0xa, 0x30,0x22,0x12,0xd, 0x7, 0x7e,0x37,0x0, +0x57,0x7a,0x37,0x0, 0x93,0x7e,0x34,0x0, 0x2, 0x7e,0x8, 0x0, 0x57,0x7e,0x24,0x0, +0x1, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x2, 0x7e,0x8, 0x0, 0x93,0x7e,0x24,0x0, 0x1, +0x22,0x30,0x0, 0x5, 0x43,0xc3,0x80,0x80,0x3, 0x53,0xc3,0x7f,0x30,0x0, 0x5, 0x43, +0xc2,0x80,0x80,0x3, 0x53,0xc2,0x7f,0x7e,0xf, 0x4f,0xa1,0x30,0x0, 0x8, 0x12,0x35, +0x92,0x4e,0x60,0xc4,0x80,0x6, 0x12,0x35,0x92,0x5e,0x60,0x3b,0x1b,0xa, 0x30,0x22, +0x12,0x37,0x7d,0x12,0xa7,0xdc,0x12,0x36,0x53,0x12,0x36,0x14,0xa9,0xd6,0xeb,0x74, +0x1, 0x7e,0x70,0x82,0x12,0x36,0x6f,0xa9,0xc6,0xeb,0xd2,0x0, 0x12,0x36,0x14,0xd2, +0x0, 0x2, 0x35,0xc1,0xa9,0xd0,0xce,0x30,0x0, 0x4, 0xa9,0xd5,0xc9,0x22,0xa9,0xc5, +0xc9,0x22,0x12,0x37,0xb3,0x40,0x6, 0x12,0x37,0xa8,0x12,0x0, 0x12,0x12,0x36,0x53, +0x12,0x36,0x5b,0x80,0x3, 0x12,0x36,0xf0,0x30,0x16,0xfa,0x7e,0xb3,0x4f,0x51,0xbe, +0xb0,0x0, 0x28,0x5, 0x14,0x7a,0xb3,0x4f,0x51,0xd2,0x0, 0x12,0x36,0x5b,0xd2,0x0, +0x2, 0x35,0xc1,0xc2,0x0, 0x12,0x35,0xc1,0xc2,0x0, 0x22,0xa2,0x0, 0xa9,0x92,0xcb, +0xa2,0x0, 0xa9,0x92,0xca,0xa2,0x0, 0xa9,0x91,0xcb,0x22,0xe4,0x7e,0x70,0xff,0x7c, +0x6b,0x7e,0xb3,0x4f,0x4b,0xb4,0x81,0x72,0xa5,0xbe,0x0, 0x2, 0x80,0x66,0xa5,0xbe, +0x1, 0x22,0xc2,0xaf,0xa, 0x27,0x5e,0x24,0x0, 0x2, 0x68,0x2, 0xd2,0x95,0x7a,0x71, +0xcd,0xa9,0xd0,0xce,0xa9,0xc6,0xc9,0xa9,0xd0,0xce,0xa9,0xc7,0xc9,0xa9,0xd1,0x87, +0xd2,0xaf,0x80,0x40,0xa5,0xbe,0x2, 0x1d,0xc2,0xaf,0x7a,0x71,0xcd,0x12,0x0, 0x1e, +0x70,0xf, 0xa9,0xd0,0xce,0xa9,0xc7,0xc9,0xa9,0xd0,0xce,0xa9,0xd6,0xc9,0xa9,0xd1, +0x87,0xd2,0xaf,0x80,0x1f,0xa5,0xbe,0x3, 0x21,0xc2,0xaf,0x7a,0x71,0xcd,0x12,0x0, +0x1e,0x70,0xf, 0xa9,0xd0,0xce,0xa9,0xd7,0xc9,0xa9,0xd0,0xce,0xa9,0xc6,0xc9,0xa9, +0xd1,0x87,0xd2,0xaf,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe4,0x7a,0xb3,0x4f,0x4b,0x22, +0x80,0xe, 0x12,0x37,0x7d,0x12,0x37,0xb3,0x40,0x19,0x20,0x16,0x16,0x12,0x36,0x6b, +0x12,0x0, 0x1e,0x70,0xed,0x12,0x37,0x7d,0x12,0xa1,0x31,0x74,0x2, 0x7e,0x70,0x7, +0x2, 0x36,0x6f,0x22,0xca,0xf8,0x7e,0x34,0x1a,0x15,0x7e,0x24,0x0, 0xff,0x7e,0x14, +0x49,0x49,0x74,0xc, 0x12,0x15,0x93,0x7e,0x57,0x31,0x78,0x4d,0x55,0x78,0x4b,0x12, +0x40,0x8b,0x7c,0xba,0x30,0xe0,0x20,0x7d,0x14,0xb, 0x44,0x2e,0x17,0x31,0x76,0x12, +0x40,0x79,0x19,0x41,0x49,0x49,0x7d,0x14,0xb, 0x44,0x2e,0x17,0x31,0x76,0x12,0x40, +0x79,0x19,0x41,0x49,0x49,0x80,0x2, 0xb, 0x45,0x12,0x40,0x83,0x78,0xd4,0x7d,0x43, +0x6c,0xff,0xa, 0x5f,0x9, 0x75,0x49,0x49,0x7d,0x54,0xb, 0x44,0x2e,0x57,0x31,0x76, +0x7a,0x59,0x70,0xb, 0xf0,0xbe,0xf0,0xc, 0x78,0xe8,0xda,0xf8,0x22,0x74,0x81,0x7a, +0xb3,0x4f,0x4b,0x22,0x80,0xe, 0x12,0x37,0x7d,0x12,0x37,0xb3,0x40,0x19,0x20,0x16, +0x16,0x12,0x36,0x6b,0x12,0x0, 0x1e,0x70,0xed,0x12,0x37,0x7d,0x12,0xa1,0x31,0x74, +0x2, 0x7e,0x70,0x7, 0x2, 0x36,0x6f,0x22,0x80,0x3, 0x12,0x37,0x84,0x12,0x37,0xb3, +0x50,0xf8,0x22,0x30,0xe, 0x3, 0x12,0x1c,0xa, 0x7e,0xb3,0x3, 0xd3,0x70,0x6, 0x7e, +0xb3,0x3, 0xd4,0x60,0x2, 0xd3,0x22,0xc3,0x22,0x20,0x16,0x6, 0x12,0xa7,0xd0,0x12, +0x0, 0x12,0x30,0x1d,0x3, 0x12,0x1c,0x24,0x12,0x37,0xb3,0x40,0x6, 0x12,0x37,0xa8, +0x2, 0x0, 0x12,0x22,0x7e,0xa3,0x4d,0xef,0xbe,0xa0,0x5, 0x78,0x8, 0x74,0x1, 0x7a, +0xb3,0x4d,0xef,0x80,0x18,0xbe,0xa0,0x4, 0x78,0x19,0x74,0x1, 0x7a,0xb3,0x4d,0xef, +0x7e,0x34,0x13,0x85,0x12,0x1d,0xf2,0x12,0x1a,0x30,0x12,0x1c,0xe1,0x74,0x2, 0x7a, +0xb3,0x4d,0xef,0x22,0xca,0x79,0x7c,0xf7,0x7c,0xeb,0xbe,0xe0,0xfa,0x78,0x4, 0x7a, +0xf3,0x2c,0xff,0x4c,0xee,0x78,0x7, 0x7c,0xbf,0x12,0x53,0xb1,0x81,0x1d,0xbe,0xe0, +0xf, 0x78,0xe, 0x74,0x1, 0x7a,0xb3,0x4d,0xfa,0x7a,0xb3,0x4d,0xfb,0xd2,0x20,0x81, +0x3c,0xbe,0xe0,0x2e,0x78,0xe, 0x74,0x1, 0x7a,0xb3,0x4e,0x19,0x7a,0xb3,0x4e,0x1a, +0xd2,0x20,0x81,0x3c,0xbe,0xe0,0x12,0x78,0x6, 0x7a,0xf3,0x4d,0xfd,0x81,0x3c,0xbe, +0xe0,0x11,0x78,0x34,0xbe,0xf0,0x1, 0x78,0x1f,0x7e,0xb3,0x4d,0xfc,0x60,0x2, 0x81, +0x3c,0x74,0x1, 0x7a,0xb3,0x4d,0xfc,0xe4,0x7a,0xb3,0x4d,0xfe,0x7e,0xb3,0x4d,0xeb, +0x44,0x80,0x7a,0xb3,0x4d,0xeb,0x81,0x3c,0x4c,0xff,0x68,0x2, 0x81,0x3c,0x7e,0x1f, +0x22,0xe0,0x7a,0x37,0x31,0x74,0x81,0x3c,0xbe,0xe0,0x99,0x68,0x5, 0xbe,0xe0,0x9a, +0x78,0x1d,0x7e,0xa3,0x2d,0x0, 0x7c,0xba,0x4, 0x7a,0xb3,0x2d,0x0, 0xa, 0x3a,0x19, +0xf3,0x31,0x7a,0xbe,0xe0,0x9a,0x68,0x2, 0x81,0x3c,0x75,0xf, 0x99,0x81,0x3c,0xbe, +0xe0,0x9b,0x78,0xa, 0x7a,0xf3,0x2d,0x0, 0x7a,0xf3,0x2c,0xfe,0x81,0x3c,0xbe,0xe0, +0x1, 0x78,0xe, 0x12,0x3d,0x5, 0x7a,0xf3,0x4d,0xec,0x7c,0xbf,0x12,0x3c,0xd8,0x81, +0x1d,0xbe,0xe0,0x5b,0x28,0x2, 0x61,0x1d,0xbe,0xe0,0x30,0x78,0x11,0x7e,0x73,0x4e, +0x1b,0xbc,0x7f,0x78,0x2, 0x81,0x3c,0xbe,0xf0,0x4, 0x40,0x2, 0x81,0x3c,0xbe,0xe0, +0x20,0x40,0xc, 0xbe,0xe0,0x22,0x38,0x7, 0xbe,0xf0,0x3, 0x28,0x2, 0x81,0x3c,0x7c, +0xbe,0x24,0xf9,0xbe,0xb0,0x29,0x40,0x2, 0x21,0x9d,0x7e,0xa0,0x3, 0xa4,0x90,0x39, +0x22,0x73,0x2, 0x3c,0x3c,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x3c, +0x3c,0x2, 0x3c,0x3c,0x2, 0x3c,0x3c,0x2, 0x3c,0x3c,0x2, 0x39,0x9d,0x2, 0x3c,0x3c, +0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, +0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39, +0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d, +0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, +0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x39,0x9d,0x2, 0x3c, +0x3c,0x2, 0x3c,0x3c,0x2, 0x3c,0x3c,0x2, 0x39,0x9d,0x2, 0x3c,0x3c,0xa, 0x3e,0x19, +0xf3,0x4d,0xeb,0x7c,0xbe,0x1b,0xb2,0xbe,0xb0,0x34,0x40,0x2, 0x41,0xd8,0x7e,0xa0, +0x3, 0xa4,0x90,0x39,0xb6,0x73,0x2, 0x3a,0x52,0x2, 0x3a,0xd8,0x2, 0x3a,0x52,0x2, +0x3a,0xd8,0x2, 0x3a,0x56,0x2, 0x3a,0x52,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a, +0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8, +0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, +0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0x9e,0x2, 0x3a,0xd8,0x2, 0x3a,0xab,0x2, 0x3a, +0xd8,0x2, 0x3a,0xbe,0x2, 0x3a,0x52,0x2, 0x3a,0x52,0x2, 0x3a,0x5b,0x2, 0x3a,0x5b, +0x2, 0x3a,0x5b,0x2, 0x3a,0xd8,0x2, 0x3a,0xcd,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, +0x3a,0xd8,0x2, 0x3a,0x64,0x2, 0x3a,0x64,0x2, 0x3a,0x64,0x2, 0x3a,0xd8,0x2, 0x3a, +0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, 0x3a,0x52,0x2, 0x3a,0x6d, +0x2, 0x3a,0x76,0x2, 0x3a,0x7f,0x2, 0x3a,0x88,0x2, 0x3a,0xd8,0x2, 0x3a,0xd8,0x2, +0x3a,0x91,0xd2,0x20,0x41,0xd8,0x12,0x0, 0xfd,0x80,0x7d,0x7e,0x37,0x2d,0x6, 0x4e, +0x60,0x20,0x80,0x34,0x7e,0x37,0x2d,0x6, 0x4e,0x60,0x1, 0x80,0x2b,0x7e,0x37,0x2d, +0x6, 0x4e,0x70,0x1, 0x80,0x22,0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x2, 0x80,0x19,0x7e, +0x37,0x2d,0x6, 0x4e,0x70,0x4, 0x80,0x10,0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x8, 0x80, +0x7, 0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x10,0x7a,0x37,0x2d,0x6, 0x80,0x3a,0x7e,0x73, +0x4e,0x3, 0x12,0x3c,0x3f,0x7a,0x37,0x2c,0xfa,0x80,0x2d,0x7e,0x73,0x4e,0x5, 0x12, +0x3c,0x3f,0x3e,0x34,0x7a,0x37,0x31,0x72,0x7a,0x37,0x2d,0x2, 0x80,0x1a,0x7e,0x73, +0x4e,0x7, 0x12,0x3c,0x3f,0x3e,0x34,0x7a,0x37,0x2c,0xfc,0x80,0xb, 0x7e,0x73,0x4e, +0xe, 0x12,0x3c,0x3f,0x7a,0x73,0x4f,0x4a,0xbe,0xe0,0x38,0x40,0x1c,0xbe,0xe0,0x56, +0x38,0x17,0xa, 0x3e,0x5e,0x34,0x0, 0x1, 0xbe,0x34,0x0, 0x1, 0x78,0xb, 0x7e,0x37, +0x2d,0x6, 0x4e,0x70,0x20,0x7a,0x37,0x2d,0x6, 0xbe,0xe0,0x58,0x40,0xb, 0x7e,0x37, +0x2d,0x6, 0x4e,0x60,0x2, 0x7a,0x37,0x2d,0x6, 0xbe,0xe0,0xa, 0x68,0x2, 0x81,0x1d, +0x7e,0x37,0x2d,0x6, 0x4e,0x60,0x4, 0x7a,0x37,0x2d,0x6, 0x81,0x1d,0xbe,0xe0,0x6c, +0x68,0x5, 0xbe,0xe0,0x6d,0x78,0x2a,0x7e,0x37,0x2d,0x6, 0x4e,0x70,0x80,0x7a,0x37, +0x2d,0x6, 0x7e,0x37,0x2d,0x2, 0x7d,0x23,0xb, 0x24,0x7a,0x27,0x2d,0x2, 0x2e,0x37, +0x2d,0x4, 0x7a,0x39,0xf0,0xbe,0xe0,0x6d,0x68,0x2, 0x81,0x1d,0x75,0xf, 0x6c,0x81, +0x1d,0xbe,0xe0,0x6e,0x68,0x5, 0xbe,0xe0,0x6f,0x78,0x49,0x7e,0x37,0x2d,0x6, 0x4e, +0x70,0x40,0x7a,0x37,0x2d,0x6, 0x7e,0x63,0x4e,0x3, 0x6c,0x77,0x7e,0xb3,0x4e,0x4, +0xa, 0x2b,0x2d,0x23,0x4, 0x7a,0xb3,0x4e,0x4, 0x70,0x9, 0x7e,0xb3,0x4e,0x3, 0x4, +0x7a,0xb3,0x4e,0x3, 0x7a,0x27,0x2c,0xfa,0x12,0x3f,0xc1,0x7e,0x27,0x2c,0xfa,0x7e, +0x37,0x2d,0x8, 0x2d,0x32,0x7a,0x39,0xf0,0xbe,0xe0,0x6f,0x68,0x2, 0x81,0x1d,0x75, +0xf, 0x6e,0x80,0x79,0xbe,0xe0,0x70,0x40,0xe, 0xbe,0xe0,0x7f,0x38,0x9, 0x7c,0xbe, +0x7c,0x7f,0x12,0x51,0xf, 0x80,0x66,0xbe,0xe0,0x86,0x78,0xf, 0x7c,0xbf,0x54,0x7, +0x7a,0xb3,0x2d,0x1, 0x53,0xc3,0xf8,0x42,0xc3,0x80,0x52,0xbe,0xe0,0x87,0x78,0xf, +0x7c,0xbf,0x54,0x3, 0x7a,0xb3,0x2c,0xf9,0x53,0xc2,0xfc,0x42,0xc2,0x80,0x3e,0xbe, +0xe0,0x88,0x78,0x21,0x5e,0xf0,0x7, 0x12,0x35,0x8e,0x5e,0x60,0xc7,0x1b,0xa, 0x30, +0xa, 0x3f,0x7d,0x23,0x7c,0x45,0x6c,0x55,0x12,0x3c,0x4b,0x12,0x35,0x8e,0x4d,0x32, +0x1b,0xa, 0x30,0x80,0x18,0xbe,0xe0,0xf6,0x78,0x6, 0x7a,0xf3,0x4f,0x94,0x80,0xd, +0xbe,0xe0,0xf7,0x78,0x8, 0x74,0x64,0xac,0xbf,0x7a,0x57,0x4f,0x95,0x30,0x20,0xa, +0x7e,0xb3,0x4d,0xf9,0x44,0x1, 0x7a,0xb3,0x4d,0xf9,0x7e,0x37,0x2d,0x6, 0x4d,0x33, +0x68,0xa, 0x7e,0xb3,0x4d,0xf9,0x44,0x2, 0x7a,0xb3,0x4d,0xf9,0xda,0x79,0x22,0x7c, +0x47,0x6c,0x55,0xa, 0x3f,0x2d,0x32,0x22,0xb, 0x18,0x20,0x3e,0x24,0x3e,0x24,0x3e, +0x24,0x22,0x7c,0x67,0x7c,0x7b,0xa5,0xbf,0x0, 0xd, 0xbe,0x60,0x0, 0x28,0x5, 0xe4, +0x7a,0xb3,0x3f,0xe4,0x2, 0x3c,0xb3,0xa5,0xbe,0x0, 0x1b,0x6c,0xaa,0x80,0xe, 0x7e, +0x60,0xff,0x7e,0x50,0x9, 0xac,0x5a,0x19,0x62,0x3f,0x41,0xb, 0xa0,0x90,0x13,0x7f, +0xe4,0x93,0xbc,0xba,0x38,0xe9,0x6c,0xaa,0x80,0x24,0x7e,0x30,0x9, 0xac,0x3a,0x2e, +0x14,0x3e,0x89,0x12,0x3c,0x48,0x3e,0x24,0x1b,0x18,0x20,0x7e,0x30,0x9, 0xac,0x3a, +0x2e,0x14,0x3e,0x8b,0x12,0x3c,0x48,0x3e,0x24,0x1b,0x18,0x20,0xb, 0xa0,0xbc,0x7a, +0x38,0xd8,0x22,0x12,0x3c,0xcc,0x7e,0x8, 0x49,0xeb,0xe4,0x12,0x16,0x5a,0x90,0x13, +0x7f,0x12,0x3c,0xd0,0x7e,0x8, 0x49,0xd3,0xe4,0x2, 0x16,0x5a,0x90,0x13,0x7f,0xe4, +0x93,0x7c,0x7b,0x74,0x2, 0xac,0x7b,0x22,0x24,0x52,0x68,0x6, 0x4, 0x78,0x25,0x2, +0x3d,0x5, 0x7e,0x63,0x40,0xf, 0x7e,0x73,0x40,0x10,0xac,0x76,0x3e,0x34,0x7a,0x37, +0x2c,0xfc,0x1e,0x34,0xa, 0x36,0x7a,0x73,0x4e,0x7, 0x7e,0x37,0x2c,0xfc,0x1e,0x34, +0x7a,0x73,0x4e,0x8, 0x22,0x6d,0x33,0x7a,0x37,0x2c,0xfc,0x22,0x12,0x3d,0x5, 0xd2, +0x2, 0x12,0x45,0xf2,0x12,0x2c,0x78,0xe5,0x13,0x12,0x2f,0xb7,0x2, 0x3d,0x1f,0x7e, +0x1f,0x22,0xe0,0x7a,0x37,0x31,0x74,0x7e,0x63,0x4f,0x55,0xa, 0x6, 0x12,0x3e,0x5f, +0x2e,0x24,0x31,0x9d,0x7a,0x27,0x2d,0x8, 0x6d,0x22,0x7a,0x27,0x2c,0xfa,0x7e,0x24, +0x40,0x22,0x7a,0x27,0x2d,0x4, 0x7e,0x24,0x0, 0x27,0xca,0x29,0x7e,0x70,0x27,0xac, +0x67,0x2e,0x34,0x4b,0xa2,0x6d,0x22,0x7e,0x8, 0x4e,0x1c,0x12,0x16,0x35,0x1b,0xfd, +0x7e,0x34,0x0, 0x2, 0xca,0x39,0x7e,0x63,0x4f,0x55,0xac,0x67,0x2e,0x34,0x4c,0x3e, +0x6d,0x22,0x7e,0x8, 0x4e,0x14,0x12,0x16,0x35,0x1b,0xfd,0x7e,0xa3,0x4f,0x55,0x74, +0xa, 0xa4,0x49,0x35,0x4c,0x4a,0x7a,0x37,0x4e,0x21,0x7e,0xb3,0x4f,0x55,0x12,0xa9, +0x2, 0x7e,0xb3,0x4f,0x55,0x12,0xa8,0x61,0x7e,0xb3,0x4f,0x55,0x12,0x50,0xb7,0x12, +0x3d,0xd6,0x9, 0x75,0x4c,0x6e,0x7a,0x73,0x4e,0xb, 0x12,0x3d,0xd6,0x9, 0x75,0x4c, +0x6f,0x7a,0x73,0x4e,0xc, 0x12,0x3d,0xd6,0x9, 0x75,0x4c,0x70,0x7a,0x73,0x4e,0xd, +0x7e,0x73,0x4f,0x55,0x7a,0x73,0x4e,0x1b,0x2, 0x3d,0xcb,0xe5,0x13,0x7a,0xb3,0x4d, +0xf7,0x22,0x7e,0x8, 0x0, 0x57,0x7e,0xa3,0x4f,0x55,0x74,0x3, 0xa4,0x22,0x12,0x1b, +0xed,0x12,0x1f,0xea,0x12,0xa1,0xa6,0x7e,0xb3,0x40,0x21,0x7e,0x37,0x40,0x1d,0x60, +0xe, 0x7a,0x37,0x0, 0xa1,0x7e,0x37,0x40,0x1f,0x7a,0x37,0x0, 0x65,0x80,0xc, 0x7a, +0x37,0x0, 0x65,0x7e,0x37,0x40,0x1f,0x7a,0x37,0x0, 0xa1,0x7e,0x37,0x0, 0x63,0x4e, +0x70,0x2, 0x7a,0x37,0x0, 0x63,0x7e,0x37,0x0, 0x9f,0x4e,0x70,0x2, 0x7a,0x37,0x0, +0x9f,0x12,0x3d,0xd2,0x9, 0xb5,0x4c,0x6e,0x12,0xc, 0xea,0x12,0x3d,0xd2,0x9, 0xb5, +0x4c,0x6f,0x12,0xd, 0x8d,0x12,0x3d,0xd2,0x12,0x50,0xd5,0x7e,0x37,0x0, 0x57,0x7a, +0x37,0x0, 0x93,0x6d,0x33,0x7e,0x8, 0x0, 0x53,0x7e,0x24,0x0, 0x1e,0x12,0x3, 0xfa, +0x6d,0x33,0x7e,0x8, 0x0, 0x8f,0x7e,0x24,0x0, 0x1e,0x2, 0x4, 0x96,0xa, 0xf, 0x7e, +0x14,0x2, 0x3c,0xad,0x10,0x7d,0x21,0x22,0x12,0x3d,0xde,0x12,0x3e,0x74,0x12,0x0, +0x26,0x2, 0x2f,0x3a,0xca,0x3b,0x7e,0x38,0x1, 0x63,0x12,0x7, 0xb5,0x7e,0xa3,0x1, +0x73,0xbe,0xa0,0xff,0x68,0x2a,0x7e,0x63,0x1, 0x74,0xbe,0x60,0xff,0x68,0x21,0x7e, +0x73,0x1, 0x75,0xbe,0x70,0xff,0x68,0x18,0x4c,0xaa,0x68,0x14,0x4c,0x66,0x68,0x10, +0x4c,0x77,0x68,0xc, 0x7a,0xa3,0x4d,0x9c,0x7a,0x63,0x4d,0x98,0x7a,0x73,0x4d,0x99, +0xc2,0x11,0x7e,0xb3,0x1, 0x75,0xbe,0xb0,0x3, 0x28,0xf, 0x74,0x4, 0x7a,0xb3,0x4f, +0x50,0x7a,0xb3,0x2d,0x1, 0x75,0xc3,0x84,0xd2,0x11,0xc2,0x13,0x7c,0xba,0x54,0xf0, +0xb4,0xe0,0x2, 0xd2,0x13,0x7e,0x8, 0x0, 0x87,0x69,0x33,0x0, 0x4, 0x12,0x3f,0x6f, +0x12,0x0, 0x6, 0x7e,0x8, 0x0, 0x89,0x29,0xb3,0x0, 0x6, 0x12,0x3f,0x66,0x12,0xd, +0xa5,0x7e,0x8, 0x0, 0xc3,0x69,0x33,0x0, 0x1, 0x12,0x3f,0x6f,0x12,0x0, 0x6, 0x7e, +0x8, 0x0, 0xc5,0x29,0xb3,0x0, 0x3, 0x12,0x3f,0x66,0x12,0xd, 0xa5,0x7e,0x8, 0x0, +0x8b,0x69,0x33,0x0, 0xa, 0x12,0x3f,0x6f,0x12,0x0, 0x6, 0x7e,0x8, 0x0, 0x8d,0x29, +0xb3,0x0, 0xc, 0x12,0x3f,0x66,0x12,0xd, 0xa5,0x7e,0x8, 0x0, 0xc7,0x69,0x33,0x0, +0x7, 0x12,0x3f,0x6f,0x12,0x0, 0x6, 0x7e,0x8, 0x0, 0xc9,0x29,0xb3,0x0, 0x9, 0x12, +0x3f,0x66,0x12,0xd, 0xa5,0x7e,0x34,0x0, 0x1a,0x7e,0x8, 0x0, 0x87,0x7e,0x24,0x0, +0x4, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x1a,0x7e,0x8, 0x0, 0xc3,0x7e,0x24,0x0, 0x4, +0x12,0x4, 0x96,0xda,0x3b,0x22,0x54,0xc0,0x23,0x23,0x54,0x3, 0xa, 0x3b,0x22,0x7d, +0x23,0x7c,0x45,0x6c,0x55,0xa, 0x36,0x4d,0x32,0x22,0xca,0x3b,0x7e,0x67,0x40,0x15, +0x7e,0x77,0x40,0x17,0x74,0x1, 0x12,0x4f,0xc9,0x7e,0xb3,0x40,0x21,0x7e,0x34,0x1, +0x0, 0x7e,0x8, 0x40,0x22,0x7d,0x26,0x60,0xb, 0x12,0x4, 0x96,0x12,0x3f,0xb0,0x12, +0x3, 0xfa,0x80,0x9, 0x12,0x3, 0xfa,0x12,0x3f,0xb0,0x12,0x4, 0x96,0xda,0x3b,0x22, +0x7e,0x34,0x1, 0x0, 0x7d,0x16,0x3e,0x14,0x2e,0x14,0x40,0x22,0x6d,0x0, 0x7d,0x27, +0x22,0x7e,0x37,0x44,0x81,0xbe,0x37,0x2c,0xfa,0x38,0x4c,0x7d,0x23,0x2e,0x24,0x0, +0xc, 0xbe,0x27,0x2c,0xfa,0x38,0x9, 0x2e,0x34,0x0, 0xb, 0x7a,0x37,0x2c,0xfa,0x22, +0x7e,0xa3,0x44,0x85,0x7e,0x24,0x0, 0x2, 0x7d,0x42,0x7e,0x37,0x2c,0xfa,0x9e,0x37, +0x44,0x81,0x8d,0x32,0x7c,0xb7,0x60,0x1a,0x1e,0xa0,0x14,0x78,0xfb,0x80,0x13,0x7c, +0xba,0x20,0xe0,0x13,0x7d,0x24,0x2e,0x27,0x2c,0xfa,0x7a,0x27,0x2c,0xfa,0x1e,0xa0, +0xb, 0x70,0xbe,0x70,0x4, 0x40,0xe8,0x22,0xca,0xf8,0x7e,0x34,0x1a,0x9, 0x7e,0x24, +0x0, 0xff,0x7e,0x14,0x49,0x55,0x74,0xc, 0x12,0x15,0x93,0x7e,0x57,0x2c,0xfc,0x4d, +0x55,0x78,0x3b,0x12,0x40,0x8b,0x7c,0xba,0x30,0xe0,0x10,0x12,0x40,0x71,0x19,0x41, +0x49,0x55,0x12,0x40,0x71,0x19,0x41,0x49,0x55,0x80,0x2, 0xb, 0x45,0x12,0x40,0x83, +0x78,0xe4,0x7d,0x43,0x6c,0xff,0xa, 0x5f,0x9, 0x75,0x49,0x55,0x7d,0x54,0xb, 0x44, +0x2e,0x57,0x31,0x74,0x7a,0x59,0x70,0xb, 0xf0,0xbe,0xf0,0xc, 0x78,0xe8,0xda,0xf8, +0x22,0x7d,0x14,0xb, 0x44,0x2e,0x17,0x31,0x74,0x7e,0x19,0x40,0x7c,0x35,0xb, 0x50, +0xa, 0x13,0x22,0x1e,0xa0,0xb, 0xf0,0xbe,0xf0,0x4, 0x22,0x7e,0xa3,0x44,0x85,0x7e, +0x37,0x44,0x81,0x3e,0x34,0x6c,0x55,0x7d,0x43,0x6c,0xff,0x22,0x30,0x20,0x76,0xc2, +0x20,0x12,0x37,0xe4,0xd2,0x2, 0x12,0x45,0xf2,0x7e,0x73,0x4e,0x1b,0xbe,0x73,0x4f, +0x55,0x68,0x7, 0x7a,0x73,0x4f,0x55,0x12,0x3d,0xc, 0x7e,0xb3,0x4e,0x9, 0xbe,0xb3, +0x40,0x13,0x68,0x14,0x54,0x5, 0x7a,0xb3,0x4e,0x9, 0x7e,0x73,0x4e,0x9, 0x7a,0x73, +0x40,0x13,0x12,0x70,0x9f,0x12,0xa8,0x90,0x7e,0xb3,0x4e,0xa, 0xbe,0xb3,0x40,0x14, +0x68,0x14,0x54,0x5, 0x7a,0xb3,0x4e,0xa, 0x7e,0x73,0x4e,0xa, 0x7a,0x73,0x40,0x14, +0x12,0x70,0x9f,0x12,0xa8,0x90,0x7e,0xb3,0x4d,0xf9,0x54,0xfe,0x7a,0xb3,0x4d,0xf9, +0x7e,0xb3,0x4d,0xfa,0x60,0x3, 0x12,0x41,0x33,0x7e,0xb3,0x4e,0x19,0x60,0x3, 0x12, +0x2d,0x80,0x12,0x1c,0x24,0x7e,0x37,0x2d,0x6, 0x4d,0x33,0x68,0x15,0xd2,0x2, 0x12, +0x45,0xf2,0x12,0x27,0xfe,0x7e,0xb3,0x4d,0xf9,0x54,0xfd,0x7a,0xb3,0x4d,0xf9,0x2, +0x1c,0x24,0x22,0xca,0x3b,0x6d,0x33,0x7a,0x37,0x31,0x78,0x7e,0x8, 0x2d,0xa, 0x12, +0x68,0x80,0x12,0x4f,0xc9,0x7e,0x34,0x1, 0x0, 0x12,0x7, 0x40,0x7a,0x37,0x44,0xd9, +0x7e,0x34,0x1, 0x1, 0x12,0x7, 0x40,0x7a,0x37,0x44,0xdd,0x7e,0x34,0x1, 0x2, 0x12, +0x7, 0x40,0x7a,0x37,0x44,0xdf,0x7e,0x34,0x1, 0x6, 0x12,0x7, 0x40,0x7a,0x37,0x44, +0xdb,0x7e,0x34,0x1, 0x0, 0x6d,0x22,0x12,0xae,0x1b,0x6d,0x22,0x12,0xae,0x13,0x7e, +0x24,0x7, 0x8, 0x12,0xae,0xb, 0x7e,0x24,0x7, 0x8, 0x12,0xae,0x3, 0x7e,0x24,0x6, +0x88,0x12,0xad,0xfb,0x7e,0x24,0x6, 0x88,0x12,0x6, 0xc5,0x12,0xad,0x69,0x12,0x6, +0x48,0x12,0xad,0x69,0x12,0x6, 0xc5,0x6d,0x33,0x12,0x7, 0x40,0x7a,0x37,0x44,0xcf, +0x7e,0x34,0x0, 0x1, 0x12,0x7, 0x40,0x7a,0x37,0x44,0xd1,0x7e,0x34,0x0, 0x2, 0x12, +0x7, 0x40,0x7a,0x37,0x44,0xd3,0x7e,0x34,0x0, 0x8, 0x12,0x7, 0x40,0x7a,0x37,0x44, +0xd5,0x7e,0x34,0x0, 0x17,0x12,0x7, 0x40,0x7a,0x37,0x44,0xd7,0x12,0xad,0x15,0x5e, +0x50,0xe0,0x4e,0x50,0xa, 0x12,0xad,0x12,0x5e,0x50,0xe0,0x4e,0x50,0xa, 0x12,0x6, +0xc5,0x12,0xad,0x5c,0x12,0x6, 0x48,0x12,0xad,0x5c,0x12,0x6, 0xc5,0x12,0xad,0x1c, +0x12,0x6, 0x48,0x12,0xad,0x1c,0x12,0x6, 0xc5,0x12,0xad,0xb8,0x12,0x6, 0x48,0x12, +0xad,0xb8,0x12,0x6, 0xc5,0x12,0xad,0x4f,0x12,0x6, 0x48,0x12,0xad,0x4f,0x12,0x6, +0xc5,0x12,0xac,0xc6,0xe4,0x12,0x16,0x5a,0x6d,0x66,0x80,0x34,0x12,0xac,0xbd,0x7e, +0xb3,0x40,0x21,0x70,0x14,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78, +0xfb,0x12,0x45,0xe7,0x12,0x47,0xf5,0x80,0x12,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, +0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad,0x34,0x12,0xac,0x65,0xb, 0x64, +0x12,0xad,0x48,0xbd,0x36,0x38,0xc5,0x7e,0xb3,0x40,0x13,0x54,0x1, 0xb4,0x1, 0xb, +0x7e,0x37,0x44,0x87,0x4e,0x70,0x1, 0x7a,0x37,0x44,0x87,0x12,0xac,0x34,0xca,0x39, +0x7e,0x18,0xc, 0xd0,0x7e,0x8, 0x2d,0xa, 0x12,0x16,0x35,0x1b,0xfd,0x7e,0x34,0x0, +0x1, 0x61,0x4c,0x12,0xac,0xc6,0xe4,0x12,0x16,0x5a,0x7e,0x73,0x40,0x10,0xa, 0x27, +0x7e,0x35,0x27,0xad,0x32,0x7d,0x63,0x80,0x61,0x12,0xac,0xbd,0x7e,0x73,0x40,0xd, +0xa, 0x37,0xbe,0x35,0x27,0x28,0x22,0x7e,0xb3,0x40,0x21,0x70,0xe, 0x7d,0x57,0x12, +0x45,0xde,0x60,0x3b,0x3e,0x14,0x14,0x78,0xfb,0x80,0x34,0x7d,0x57,0x12,0x45,0xde, +0x60,0x19,0x3e,0x14,0x14,0x78,0xfb,0x80,0x12,0x7e,0xb3,0x40,0x21,0x70,0x14,0x7d, +0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad, +0x34,0x80,0x12,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12, +0x45,0xe7,0x12,0x47,0xf5,0x12,0xac,0x65,0xb, 0x64,0x7e,0x25,0x27,0xb, 0x24,0x12, +0xad,0x48,0xad,0x32,0xbd,0x36,0x38,0x91,0x7e,0xb3,0x40,0x13,0x54,0x4, 0xb4,0x4, +0xb, 0x7e,0x37,0x44,0x87,0x4e,0x70,0x4, 0x7a,0x37,0x44,0x87,0x12,0xac,0x34,0xca, +0x39,0x12,0xad,0x2b,0x12,0x16,0x35,0x1b,0xfd,0x12,0xad,0xb0,0x7e,0x8, 0x2d,0xa, +0x7e,0x18,0x44,0xe1,0x12,0x50,0xdc,0x7e,0x35,0x27,0xb, 0x34,0x7a,0x35,0x27,0x7e, +0x73,0x40,0xf, 0xa, 0x37,0xbe,0x35,0x27,0x28,0x2, 0x41,0x93,0x6d,0x33,0x81,0xe, +0x12,0xac,0xc6,0xe4,0x12,0x16,0x5a,0x7e,0x65,0x27,0x80,0x61,0x12,0xac,0xbd,0x7e, +0x37,0x40,0x15,0xbd,0x36,0x28,0x22,0x7e,0xb3,0x40,0x21,0x70,0xe, 0x7d,0x57,0x12, +0x45,0xde,0x60,0x3b,0x3e,0x14,0x14,0x78,0xfb,0x80,0x34,0x7d,0x57,0x12,0x45,0xde, +0x60,0x19,0x3e,0x14,0x14,0x78,0xfb,0x80,0x12,0x7e,0xb3,0x40,0x21,0x70,0x14,0x7d, +0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad, +0x34,0x80,0x12,0x7d,0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12, +0x45,0xe7,0x12,0x47,0xf5,0x12,0xac,0x65,0x12,0xad,0x48,0x2d,0x63,0x7e,0xa3,0x40, +0x10,0x7e,0xb3,0x40,0xf, 0xa4,0xbd,0x56,0x38,0x92,0x7e,0xb3,0x40,0x14,0x54,0x1, +0xb4,0x1, 0xb, 0x7e,0x37,0x44,0xab,0x4e,0x70,0x1, 0x7a,0x37,0x44,0xab,0x12,0xac, +0x34,0xca,0x39,0x12,0xad,0x2b,0x12,0x16,0x35,0x1b,0xfd,0x12,0xad,0xb0,0x7e,0x8, +0x2d,0xa, 0x7e,0x18,0x44,0xe1,0x12,0x50,0xdc,0x7e,0x35,0x27,0xb, 0x34,0x7a,0x35, +0x27,0x12,0xad,0x48,0xbe,0x35,0x27,0x28,0x2, 0x61,0x60,0x12,0xac,0xc6,0xe4,0x12, +0x16,0x5a,0x7e,0xb3,0x40,0x14,0x54,0x4, 0xb4,0x4, 0xb, 0x7e,0x37,0x44,0xab,0x4e, +0x70,0x4, 0x7a,0x37,0x44,0xab,0x12,0xac,0x34,0xca,0x39,0x12,0xad,0x2b,0x12,0x16, +0x35,0x1b,0xfd,0x12,0xad,0xb0,0x7e,0x8, 0x2d,0xa, 0x7e,0x18,0x44,0xe1,0x12,0x50, +0xdc,0x6d,0x66,0x7d,0x26,0x3e,0x24,0x49,0x32,0x2d,0xa, 0xbe,0x34,0x2, 0x0, 0x28, +0xf, 0x7d,0x12,0x2e,0x14,0x2d,0xa, 0x9e,0x34,0x2, 0x0, 0x1b,0x18,0x30,0x80,0x6, +0x6d,0x33,0x59,0x32,0x2d,0xa, 0xb, 0x64,0xbe,0x64,0x2, 0x34,0x78,0xd5,0x7e,0x34, +0x2d,0xa, 0x7a,0x37,0x31,0x76,0xe4,0x7a,0xb3,0x4d,0xfb,0x7a,0xb3,0x4d,0xfa,0x12, +0xad,0x15,0x12,0xad,0x12,0x12,0x6, 0xc5,0x7e,0x34,0x0, 0x1, 0x7e,0x27,0x44,0xd1, +0x12,0x6, 0x48,0x7e,0x34,0x0, 0x1, 0x7e,0x27,0x44,0xd1,0x12,0x6, 0xc5,0x7e,0x34, +0x0, 0x2, 0x7e,0x27,0x44,0xd3,0x12,0x6, 0x48,0x7e,0x34,0x0, 0x2, 0x7e,0x27,0x44, +0xd3,0x12,0x6, 0xc5,0x7e,0x34,0x0, 0x8, 0x7e,0x27,0x44,0xd5,0x12,0x6, 0x48,0x7e, +0x34,0x0, 0x8, 0x7e,0x27,0x44,0xd5,0x12,0x6, 0xc5,0x7e,0x34,0x0, 0x17,0x7e,0x27, +0x44,0xd7,0x12,0x6, 0x48,0x7e,0x34,0x0, 0x17,0x7e,0x27,0x44,0xd7,0x12,0x6, 0xc5, +0x7e,0x34,0x1, 0x0, 0x7e,0x27,0x44,0xd9,0x12,0xae,0x1b,0x7e,0x27,0x44,0xd9,0x12, +0xae,0x13,0x7e,0x27,0x44,0xdd,0x12,0xae,0xb, 0x7e,0x27,0x44,0xdd,0x12,0xae,0x3, +0x7e,0x27,0x44,0xdf,0x12,0xad,0xfb,0x7e,0x27,0x44,0xdf,0x12,0x6, 0xc5,0x7e,0x34, +0x1, 0x6, 0x7e,0x27,0x44,0xdb,0x12,0x6, 0x48,0x7e,0x34,0x1, 0x6, 0x7e,0x27,0x44, +0xdb,0x12,0x6, 0xc5,0x6d,0x66,0x80,0x5e,0x12,0xac,0xbd,0x7e,0x37,0x40,0x15,0xbd, +0x36,0x28,0x22,0x7e,0xb3,0x40,0x21,0x70,0xe, 0x7d,0x57,0x12,0x45,0xde,0x60,0x3b, +0x3e,0x14,0x14,0x78,0xfb,0x80,0x34,0x7d,0x57,0x12,0x45,0xde,0x60,0x19,0x3e,0x14, +0x14,0x78,0xfb,0x80,0x12,0x7e,0xb3,0x40,0x21,0x70,0x14,0x7d,0x57,0x12,0x45,0xde, +0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0xad,0x34,0x80,0x12,0x7d, +0x57,0x12,0x45,0xde,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe7,0x12,0x47, +0xf5,0x12,0xac,0x65,0xb, 0x64,0x7e,0x37,0x40,0x17,0x2e,0x37,0x40,0x15,0xbd,0x36, +0x38,0x96,0x7e,0x34,0x1, 0x16,0x7e,0x8, 0x44,0x87,0x12,0x47,0xfc,0x7e,0x34,0x1, +0x16,0x7e,0x8, 0x44,0xab,0x12,0xad,0xd5,0x12,0x70,0xaa,0x12,0xa8,0x90,0x12,0x37, +0x14,0xda,0x3b,0x22,0x7e,0x35,0x3e,0x3e,0x34,0x49,0x23,0x40,0x22,0x7a,0x25,0x40, +0x7f,0x3, 0x2e,0x15,0x3e,0x7e,0xb, 0x70,0x19,0x72,0x1, 0x7b,0x7d,0x52,0x5e,0x54, +0x0, 0xf, 0x7e,0x14,0x0, 0x1, 0x22,0x7d,0x27,0x1e,0x24,0x1e,0x24,0x1e,0x24,0x1e, +0x24,0x22,0x80,0x6, 0x30,0xe, 0x3, 0x12,0x1c,0xa, 0x7e,0xb3,0x3, 0xd2,0xbe,0xb0, +0x1, 0x68,0xf1,0x30,0x2, 0x3, 0x2, 0xb, 0xe5,0x22,0xca,0x3b,0x7f,0x30,0x7c,0xab, +0xbe,0xa0,0x4, 0x40,0x2, 0xe1,0xf2,0x74,0x27,0xa4,0x9, 0xb5,0x4b,0xa6,0xf5,0x46, +0xe4,0x12,0x4f,0xc9,0x7e,0xe7,0x40,0x15,0x7e,0xf7,0x40,0x17,0x2d,0xfe,0x7f,0x13, +0x2d,0x3f,0x7a,0x1d,0x42,0x7e,0x8, 0x46,0xf1,0x7e,0x34,0x0, 0x48,0xe4,0x12,0x16, +0x5a,0x7e,0xb3,0x40,0x21,0x60,0x63,0x6d,0x33,0x80,0x33,0x7e,0x35,0x3e,0x3e,0x34, +0x49,0x23,0x40,0x22,0x7a,0x25,0x40,0x7f,0x3, 0x2e,0x15,0x3e,0x7e,0xb, 0x70,0x19, +0x72,0x2, 0x95,0x12,0x45,0xdc,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe9, +0x3e,0x24,0x2e,0x24,0x47,0x15,0x12,0xac,0x65,0x7e,0x35,0x3e,0xb, 0x34,0x7a,0x35, +0x3e,0xbe,0xe5,0x3e,0x38,0xc5,0x7a,0xe5,0x3e,0x80,0x18,0x12,0x45,0xc4,0x60,0x5, +0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe9,0x12,0xac,0x5f,0x7e,0x35,0x3e,0xb, 0x34, +0x7a,0x35,0x3e,0xbe,0xf5,0x3e,0x38,0xe3,0x80,0x6a,0x6d,0x33,0x80,0x15,0x12,0x45, +0xc4,0x60,0x5, 0x3e,0x14,0x14,0x78,0xfb,0x12,0x45,0xe9,0x12,0xac,0x5f,0x7e,0x35, +0x3e,0xb, 0x34,0x7a,0x35,0x3e,0xbe,0xe5,0x3e,0x38,0xe3,0x80,0x3f,0x7e,0xe5,0x3e, +0x3e,0xe4,0x49,0x3e,0x40,0x22,0x7a,0x35,0x40,0x7f,0x3, 0x2e,0x15,0x3e,0x7e,0xb, +0x50,0x19,0x53,0x2, 0x95,0x7d,0x53,0x5e,0x54,0x0, 0xf, 0x7e,0x24,0x0, 0x1, 0x60, +0x5, 0x3e,0x24,0x14,0x78,0xfb,0x12,0x1f,0x18,0x3e,0x34,0x2e,0x34,0x47,0x15,0xb, +0x38,0xe0,0x4d,0xe2,0x1b,0x38,0xe0,0x7e,0xe5,0x3e,0xb, 0xe4,0x7a,0xe5,0x3e,0xbe, +0xf5,0x3e,0x38,0xb9,0x7e,0x7d,0x42,0xb, 0x7a,0x20,0x7d,0x32,0x7a,0x73,0x1, 0x7b, +0x7f,0x27,0x2e,0x54,0x0, 0x0, 0x12,0xac,0x7c,0x7a,0x53,0x1, 0x7c,0x5e,0x34,0x3, +0xf0,0x12,0x1f,0x18,0x7a,0x73,0x1, 0x7d,0x69,0x27,0x0, 0x4, 0x7d,0x32,0x7a,0x73, +0x2, 0x95,0x7f,0x27,0xb, 0x56,0x12,0xac,0x7c,0x7a,0x53,0x2, 0x96,0x5e,0x34,0x3, +0xf0,0x12,0x1f,0x18,0x7a,0x73,0x2, 0x97,0x7e,0xb3,0x40,0x13,0x54,0x5, 0xa, 0x3b, +0x4e,0x37,0x46,0xf1,0x7a,0x37,0x46,0xf1,0x7e,0xb3,0x40,0x14,0x54,0x5, 0xa, 0x3b, +0x4e,0x37,0x47,0x15,0x7a,0x37,0x47,0x15,0x12,0xad,0x8c,0x2e,0x74,0x0, 0x16,0x7d, +0x37,0x7e,0x8, 0x46,0xf1,0x12,0x47,0xfc,0x7d,0x37,0x7e,0x8, 0x47,0x15,0x12,0xad, +0xd5,0x12,0xad,0x8c,0x2e,0x74,0x0, 0x28,0x6d,0x33,0x7a,0x35,0x3e,0x7e,0x35,0x3e, +0x9, 0x53,0x1, 0x7c,0x7c,0x25,0x6c,0x33,0x9, 0x53,0x1, 0x7b,0x12,0xac,0xcf,0x7a, +0x35,0x3e,0xbe,0x34,0x1, 0x1a,0x40,0xe5,0x7d,0x37,0x7e,0x8, 0x47,0x39,0x7e,0x24, +0x0, 0x8d,0x12,0x3, 0xfa,0x6d,0x33,0x7a,0x35,0x3e,0x7e,0x35,0x3e,0x9, 0x53,0x2, +0x96,0x7c,0x25,0x6c,0x33,0x9, 0x53,0x2, 0x95,0x12,0xac,0xcf,0x7a,0x35,0x3e,0xbe, +0x34,0x1, 0x1a,0x40,0xe5,0x7d,0x37,0x7e,0x8, 0x47,0x39,0x7e,0x24,0x0, 0x8d,0x12, +0x4, 0x96,0xda,0x3b,0x22,0x3e,0x24,0x2e,0x24,0x44,0x87,0x22,0x7e,0x24,0x0, 0x12, +0x2, 0x3, 0xfa,0xca,0xf8,0x7e,0x14,0x1a,0x6, 0x7e,0x4, 0x0, 0xff,0x69,0x30,0x0, +0x1, 0x7e,0xb, 0x50,0x7a,0x37,0x44,0x88,0x7a,0x53,0x44,0x87,0xc2,0x0, 0x6d,0xcc, +0x7e,0xb4,0xff,0xff,0x20,0x1f,0x2, 0x21,0x45,0x7e,0xd4,0x4, 0x68,0xca,0xd9,0x7e, +0x1f,0x22,0xe0,0x7e,0x8, 0x28,0x91,0x12,0x16,0x35,0x1b,0xfd,0x6d,0xaa,0x7d,0xda, +0x80,0x26,0x7d,0x2d,0x3e,0x24,0x49,0x12,0x28,0x91,0xbe,0x14,0x0, 0x0, 0x8, 0x6, +0x49,0x32,0x28,0x91,0x80,0x4, 0x6d,0x33,0x9d,0x31,0x59,0x32,0x28,0x91,0xbd,0x3c, +0x28,0x4, 0x7d,0xc3,0x7d,0xbd,0xb, 0xd4,0x7e,0x37,0x44,0x81,0xbd,0x3d,0x38,0xd2, +0x7e,0x37,0x31,0x8a,0xbd,0x3c,0x50,0x4, 0x7a,0xc7,0x31,0x8a,0x7e,0x37,0x31,0x80, +0xbd,0x3c,0x50,0x10,0xbe,0xb4,0xff,0xff,0x68,0xa, 0x7e,0x37,0x31,0x88,0xb, 0x34, +0x7a,0x37,0x31,0x88,0x7e,0x73,0x40,0x10,0xa, 0x27,0x7d,0x3b,0x8d,0x32,0x7c,0xf5, +0xbe,0xf0,0x0, 0x40,0x7, 0xbe,0xf0,0x1d,0x38,0x2, 0xd2,0x0, 0x7d,0xda,0x7d,0x3d, +0x3e,0x34,0x49,0x23,0x31,0x7a,0xbd,0x2c,0x50,0x51,0xbe,0xb4,0xff,0xff,0x68,0x4b, +0x9, 0xbd,0x31,0x8c,0xb4,0x1, 0x25,0x49,0x23,0x31,0x95,0xbd,0x2b,0x78,0x10,0x7d, +0xa3,0x2e,0xa4,0x31,0x8f,0xb, 0xa8,0x20,0xb, 0x24,0x1b,0xa8,0x20,0x80,0x32,0x4d, +0xdd,0x78,0x14,0x30,0x0, 0x25,0x80,0xf, 0x80,0x21,0x80,0xb, 0x4d,0xdd,0x78,0x7, +0x30,0x0, 0x18,0x80,0x2, 0x80,0x14,0x59,0xb3,0x31,0x95,0x7e,0x24,0x0, 0x1, 0x59, +0x23,0x31,0x8f,0x74,0x1, 0x19,0xbd,0x31,0x8c,0x80,0x6, 0x74,0x1, 0x19,0xbd,0x44, +0x87,0x49,0xa3,0x31,0x82,0x49,0x23,0x31,0x8f,0xbd,0x2a,0x28,0x4, 0x59,0x23,0x31, +0x82,0x9, 0xbd,0x44,0x87,0xb4,0x1, 0x11,0x6d,0x22,0x59,0x23,0x31,0x95,0x6d,0xaa, +0x59,0xa3,0x31,0x8f,0xe4,0x19,0xbd,0x31,0x8c,0xb, 0xd4,0xbe,0xd4,0x0, 0x3, 0x68, +0x2, 0x1, 0xae,0x80,0x1a,0x7e,0x8, 0x31,0x8c,0x7e,0x34,0x0, 0x3, 0xe4,0x12,0x16, +0x5a,0x7e,0x8, 0x31,0x8f,0x12,0x49,0x62,0x7e,0x8, 0x31,0x95,0x12,0x49,0x62,0xda, +0xf8,0x22,0x7e,0x34,0x0, 0x6, 0x2, 0x16,0x5a,0xe4,0x7a,0xb3,0x4d,0x9e,0x6d,0x33, +0x7a,0x37,0x31,0x72,0x7e,0x73,0x4d,0xf1,0x7a,0x73,0x44,0x7e,0x12,0x49,0x98,0x12, +0x3d,0xc, 0x7e,0x34,0x4, 0x68,0xca,0x39,0x7e,0x1f,0x22,0xdc,0x7e,0xf, 0x22,0xe0, +0x12,0x16,0x35,0x1b,0xfd,0x2, 0x1c,0x24,0x7e,0x8, 0x3, 0xaf,0x7e,0x34,0x0, 0x20, +0xe4,0x12,0x16,0x5a,0x7e,0x34,0x0, 0x1, 0x7a,0x37,0x3, 0xaf,0x7a,0xb3,0x3, 0xb1, +0x74,0x1, 0x7a,0xb3,0x3, 0xb2,0xe4,0x7a,0xb3,0x3, 0xb3,0x7e,0xb3,0x4f,0x4d,0xb4, +0x1, 0x3f,0x7e,0x34,0x0, 0x2, 0x12,0x4a,0x28,0x7a,0xb3,0x3, 0xbb,0x7e,0x73,0x4f, +0x4c,0x1e,0x34,0xb, 0x34,0x7a,0x73,0x3, 0xbc,0x74,0x1, 0x7a,0xb3,0x3, 0xbd,0xe4, +0x7a,0xb3,0x3, 0xbe,0x7e,0x34,0x0, 0x2, 0x12,0x4a,0x38,0x7e,0x73,0x4f,0x4c,0x1e, +0x34,0xb, 0x34,0x7a,0x73,0x3, 0xc4,0x7a,0xb3,0x3, 0xc5,0x7a,0xb3,0x3, 0xc6,0x80, +0xe, 0x7e,0x34,0x0, 0x1, 0x12,0x4a,0x28,0x7a,0xb3,0x3, 0xbb,0x12,0x4a,0x38,0x7e, +0x34,0x0, 0x1, 0x7a,0x37,0x3, 0xc7,0x74,0x1, 0x7a,0xb3,0x3, 0xc9,0x7a,0xb3,0x3, +0xca,0x74,0x2, 0x7a,0xb3,0x3, 0xcb,0x22,0x7a,0x37,0x3, 0xb7,0x74,0x1, 0x7a,0xb3, +0x3, 0xb9,0x7a,0xb3,0x3, 0xba,0xe4,0x22,0x7a,0x37,0x3, 0xbf,0x74,0x1, 0x7a,0xb3, +0x3, 0xc1,0x7a,0xb3,0x3, 0xc2,0x7a,0xb3,0x3, 0xc3,0x22,0xe4,0x7a,0xb3,0x4d,0x9e, +0x74,0x1, 0x7a,0xb3,0x4f,0x55,0x7a,0xb3,0x44,0x7e,0x12,0x56,0xc6,0x12,0x49,0x98, +0x12,0x2f,0x59,0x12,0x3d,0x1f,0x7e,0x34,0xd, 0xac,0x12,0x1d,0x19,0x12,0x8f,0xab, +0x2, 0x1a,0x33,0x7e,0x34,0x0, 0x27,0xca,0x39,0x7e,0x34,0x12,0xe2,0x7e,0x24,0x0, +0xff,0x7e,0x8, 0x4b,0xa2,0x12,0x16,0x35,0x1b,0xfd,0x7e,0x34,0x0, 0x27,0xca,0x39, +0x7e,0x34,0x13,0x9, 0x7e,0x24,0x0, 0xff,0x7e,0x8, 0x4b,0xc9,0x12,0x16,0x35,0x1b, +0xfd,0x7e,0x34,0x0, 0x27,0xca,0x39,0x7e,0x34,0x13,0x30,0x7e,0x24,0x0, 0xff,0x7e, +0x8, 0x4b,0xf0,0x12,0x16,0x35,0x1b,0xfd,0x7e,0x34,0x0, 0x27,0xca,0x39,0x7e,0x34, +0x13,0x57,0x7e,0x24,0x0, 0xff,0x7e,0x8, 0x4c,0x17,0x12,0x16,0x35,0x1b,0xfd,0x6c, +0x88,0x7c,0xb8,0x12,0x4a,0xe0,0xb, 0x80,0xbe,0x80,0x4, 0x40,0xf4,0x2, 0x49,0x98, +0x7c,0x9b,0x12,0xa9,0x38,0x7e,0x50,0xa, 0xac,0x59,0x59,0x32,0x4c,0x48,0x74,0x27, +0xac,0xb9,0x49,0x5, 0x4b,0xa7,0x59,0x2, 0x4c,0x4a,0x49,0x15,0x4b,0xa9,0xb, 0x14, +0xad,0x10,0x6d,0x0, 0x59,0x12,0x4c,0x4e,0x59,0x2, 0x4c,0x4c,0x12,0x4b,0x33,0x7c, +0xab,0x7e,0x70,0xa, 0xac,0x79,0x19,0xa3,0x4c,0x46,0x74,0x27,0xac,0xb9,0x49,0x35, +0x4b,0xa9,0xb, 0x34,0x12,0x4b,0x33,0x7c,0xab,0x7e,0x70,0xa, 0xac,0x79,0x19,0xa3, +0x4c,0x47,0x22,0xe4,0x80,0x5, 0xb, 0x34,0x1e,0x34,0x4, 0xbe,0x34,0x0, 0x10,0x38, +0xf5,0x22,0xca,0x3b,0x7c,0xeb,0xc2,0x2, 0x7e,0x70,0x27,0xac,0x7e,0x9, 0xf3,0x4b, +0xa6,0x12,0x4f,0xbf,0x4c,0xee,0x68,0x18,0xd2,0x2, 0xe4,0x19,0xb3,0x4b,0xa4,0x7c, +0xbe,0x12,0x4a,0xe0,0x12,0x4f,0x8c,0x12,0xa2,0xf9,0x12,0x2f,0xe2,0x12,0x4f,0xfc, +0xa2,0x2, 0xda,0x3b,0x22,0xca,0x79,0x7c,0xfb,0xd2,0x0, 0xc2,0x1, 0x6d,0x33,0x7a, +0x37,0x4f,0x44,0x74,0x27,0xac,0xbf,0x9, 0xe5,0x4b,0xa4,0x7c,0xbf,0x12,0x4b,0x42, +0x92,0x1, 0xd2,0x0, 0x30,0x0, 0x7, 0x7c,0xbf,0x7c,0x7f,0x12,0x4b,0xca,0x7e,0xb3, +0x4e,0x19,0x70,0xc, 0x7c,0xbf,0x12,0xa9,0xac,0x92,0x30,0x20,0x30,0x2, 0xc2,0x0, +0x30,0x1, 0x12,0x74,0x27,0xac,0xbf,0x19,0xe5,0x4b,0xa4,0x7c,0xbf,0x12,0x4a,0xe0, +0x7c,0xbf,0x12,0x4f,0xa5,0xa2,0x0, 0xda,0x79,0x22,0xca,0x3b,0x7c,0xf7,0x7c,0xeb, +0x75,0x2c,0x9, 0x7e,0x34,0x2, 0x0, 0x7a,0x35,0x2f,0x75,0x39,0x0, 0x7e,0x34,0x16, +0x7c,0x7e,0x24,0x0, 0xff,0x7e,0x14,0x44,0xb5,0x7e,0x54,0x2, 0x3c,0x12,0x15,0x95, +0x6d,0x66,0x80,0xe, 0x7e,0x34,0x7f,0xff,0x7d,0x26,0x3e,0x24,0x59,0x32,0x11,0x38, +0xb, 0x64,0x7e,0x37,0x44,0x81,0x7d,0x23,0xb, 0x26,0xbd,0x26,0x38,0xe6,0x2e,0x34, +0x0, 0x8, 0x12,0x4e,0x89,0xe4,0x12,0x16,0x5a,0x12,0x4e,0x7e,0x12,0xaa,0x22,0x6d, +0x22,0x7a,0x1d,0x31,0x7e,0x37,0x44,0x81,0x2e,0x34,0x44,0xb5,0x7a,0x1d,0x35,0x7e, +0xb3,0x4f,0x94,0xb4,0x1, 0xa, 0x7e,0x37,0x4f,0x95,0x12,0x1f,0x18,0x7a,0x35,0x2f, +0x74,0xa, 0xac,0xbe,0x49,0x25,0x4c,0x48,0x7e,0x35,0x2f,0xad,0x32,0x9, 0xb5,0x4c, +0x46,0x60,0xc, 0x1e,0x34,0x1e,0x24,0x50,0x3, 0x4e,0x60,0x80,0x14,0x78,0xf4,0x7a, +0x35,0x2f,0xe5,0x2c,0xa, 0x5b,0x1b,0x54,0xf5,0x2b,0xa1,0xcc,0xe5,0x2b,0x7e,0x34, +0x0, 0x1, 0x60,0x5, 0x3e,0x34,0x14,0x78,0xfb,0x7a,0x35,0x2d,0x7e,0x34,0x9, 0xc4, +0x12,0x1d,0x19,0xe5,0x2b,0xbe,0xb0,0x7, 0x58,0x1b,0x6d,0x66,0x80,0x12,0x7e,0x35, +0x2d,0x7c,0x67,0x12,0x3e,0x5d,0x12,0x4e,0xa2,0x4c,0x76,0x7a,0x29,0x70,0xb, 0x64, +0x12,0x4e,0x77,0x38,0xe9,0x6d,0x66,0x12,0x4f,0x7f,0x4e,0x35,0x2d,0x1b,0xa, 0x30, +0x12,0x4e,0x70,0x78,0xf2,0x12,0x4e,0x87,0x12,0x46,0xa, 0x5, 0x39,0xe5,0x39,0x54, +0x1, 0xb4,0x1, 0x8, 0x74,0x1, 0x7a,0xb3,0x4f,0x98,0x80,0xe, 0x7e,0x73,0x4f,0x4c, +0xa, 0x37,0x1e,0x34,0xb, 0x34,0x7a,0x73,0x4f,0x98,0x12,0x1c,0x24,0xd2,0x2, 0x12, +0x45,0xf2,0xe5,0x2b,0xbe,0xb0,0x7, 0x58,0x65,0x6d,0x66,0x80,0x5c,0x7d,0x26,0x3e, +0x24,0x49,0x32,0xc, 0xd0,0x7d,0x3, 0x12,0x4e,0x68,0x8, 0x7, 0x7d,0x13,0x9e,0x15, +0x2f,0x80,0x4, 0x6d,0x11,0x9d,0x10,0x12,0x4e,0x5f,0x8, 0x5, 0x9e,0x15,0x2f,0x80, +0x4, 0x6d,0x11,0x9d,0x10,0x7a,0x15,0x3c,0xbe,0x15,0x3a,0x40,0x11,0x59,0x32,0x11, +0x38,0x12,0x4e,0x7e,0x2d,0x36,0x9, 0x73,0x31,0x9d,0x19,0x76,0x44,0xb5,0x7d,0x36, +0x12,0x4e,0x98,0x50,0x12,0x7e,0x55,0x2d,0x64,0xff,0x12,0x4e,0x7e,0x7d,0x23,0x12, +0x4e,0xa2,0x5c,0x7b,0x7a,0x29,0x70,0xb, 0x64,0x12,0x4e,0x77,0x38,0x9f,0x6d,0x66, +0x7e,0x27,0x44,0x81,0x2d,0x26,0x3e,0x24,0x49,0x32,0xc, 0xd0,0x7d,0x3, 0x12,0x4e, +0x68,0x8, 0x7, 0x7d,0x13,0x9e,0x15,0x2f,0x80,0x4, 0x6d,0x11,0x9d,0x10,0x12,0x4e, +0x5f,0x8, 0x5, 0x9e,0x15,0x2f,0x80,0x4, 0x6d,0x11,0x9d,0x10,0x7a,0x15,0x3c,0xbe, +0x15,0x3a,0x40,0x18,0x59,0x32,0x11,0x38,0x7d,0x6, 0x3e,0x4, 0x7e,0x1d,0x31,0x2d, +0x30,0xb, 0x1a,0x10,0x7e,0x1d,0x35,0x2d,0x30,0x1b,0x1a,0x10,0x7e,0x37,0x44,0x81, +0x2d,0x36,0x12,0x4e,0x98,0x50,0xf, 0x7e,0x25,0x2d,0x6e,0x24,0xff,0xff,0x12,0x4f, +0x7f,0x5d,0x32,0x1b,0xa, 0x30,0x12,0x4e,0x70,0x78,0x95,0x30,0xe, 0x2, 0xc1,0x5c, +0x30,0xf, 0x2, 0xc1,0x5c,0x30,0x10,0x2, 0xc1,0x5c,0x15,0x2b,0xe5,0x2b,0xbe,0xb0, +0x1, 0x48,0x2, 0x81,0x6c,0x7e,0xb3,0x4e,0xb, 0xbe,0xb0,0x2, 0x68,0x6f,0x12,0xad, +0xdc,0x68,0x6a,0x7e,0x8, 0x11,0x38,0x74,0xa, 0xac,0xbe,0x12,0x4e,0xb2,0x6d,0x66, +0x80,0x23,0x7d,0x26,0x3e,0x24,0x49,0x32,0x11,0x38,0xbe,0x34,0x3, 0xe8,0x28,0x13, +0xbe,0x34,0x3e,0x80,0x50,0xd, 0x9, 0x76,0x44,0xb5,0x12,0x3e,0x5d,0x2d,0x26,0x19, +0x72,0x31,0x9d,0xb, 0x64,0x12,0x4e,0x77,0x38,0xd8,0x6d,0x66,0x7e,0x27,0x44,0x81, +0x2d,0x26,0x3e,0x24,0x49,0x32,0x11,0x38,0xbe,0x34,0x3, 0xe8,0x28,0x1a,0xbe,0x34, +0x3e,0x80,0x50,0x14,0x7d,0x6, 0x3e,0x4, 0x7e,0x1d,0x35,0x2d,0x30,0xb, 0x1a,0x10, +0x7e,0x1d,0x31,0x2d,0x30,0x1b,0x1a,0x10,0x12,0x4e,0x70,0x78,0xcf,0x74,0x1, 0x7a, +0xb3,0x4f,0x98,0x12,0x4e,0x87,0x12,0x46,0xa, 0x12,0x4f,0x55,0xda,0x3b,0x22,0x7a, +0x15,0x3a,0x49,0x12,0x11,0x38,0x7d,0x1, 0x9e,0x5, 0x2f,0xbe,0x4, 0x0, 0x0, 0x22, +0xb, 0x64,0xbe,0x64,0x0, 0x4, 0x22,0x7e,0x37,0x44,0x81,0xbd,0x36,0x22,0xa, 0x2f, +0x7e,0x34,0x2, 0x3c,0xad,0x32,0x22,0x7c,0xbe,0xa, 0xf, 0x7e,0x14,0x2, 0x3c,0xad, +0x10,0x2e,0x14,0x31,0x9d,0x6d,0x0, 0x22,0x3e,0x34,0x49,0x33,0xc, 0xd0,0xbe,0x35, +0x2f,0x22,0x2d,0x26,0x2e,0x24,0x31,0x9d,0x7e,0x29,0x70,0x22,0x7e,0xa1,0x2f,0x74, +0xa, 0xa4,0x49,0x35,0x4c,0x48,0x7d,0xb3,0x7f,0x70,0x7d,0x3b,0x12,0x4b,0x33,0x7c, +0x7b,0xa, 0x57,0x2e,0x54,0x0, 0xb, 0x7e,0x18,0x0, 0x1, 0x60,0x5, 0x2f,0x11,0x14, +0x78,0xfb,0x74,0x4, 0x2f,0x11,0x14,0x78,0xfb,0x7d,0x1b,0x12,0x14,0xeb,0x7f,0x61, +0xbe,0xb4,0x0, 0x10,0x68,0x6e,0x7e,0x73,0x40,0xf, 0x7a,0x73,0x46,0xf1,0x7e,0x73, +0x40,0x10,0x7a,0x73,0x46,0xf2,0x74,0xb, 0x7a,0xb3,0x46,0xf3,0x7d,0xaf,0x7a,0xa7, +0x46,0xf5,0x7a,0xa7,0x46,0xf9,0xbe,0xb4,0x0, 0x2, 0x38,0xd, 0xe4,0x7a,0xb3,0x46, +0xf3,0x7e,0xd4,0x0, 0x10,0x8d,0xdb,0x6d,0xcc,0x7e,0x8, 0x46,0xf1,0x7d,0x3d,0x12, +0x9, 0x50,0x7e,0x47,0x44,0x81,0x7e,0xa0,0x4, 0x7d,0x34,0x3e,0x34,0x7f,0x57,0x2d, +0xb3,0xb, 0x5a,0x10,0x7f,0x16,0x12,0x14,0xe2,0x7e,0xb3,0x46,0xf3,0x60,0xc, 0x1e, +0x34,0x1e,0x24,0x50,0x3, 0x4e,0x60,0x80,0x14,0x78,0xf4,0x1b,0x5a,0x30,0xb, 0x44, +0x1b,0xa0,0x78,0xd5,0x22,0xe4,0x7a,0xb3,0x4f,0x5a,0x2, 0x4f,0x5d,0x6d,0x33,0x7a, +0x37,0x4f,0x9a,0x22,0xe4,0x7a,0xb3,0x4d,0x9e,0xd2,0x16,0x12,0x4f,0x5d,0x2, 0x4f, +0x71,0x12,0x33,0x91,0x5e,0x34,0x0, 0x1, 0x68,0x4, 0xd2,0x1e,0xc2,0x1b,0x22,0x7d, +0x36,0x3e,0x34,0x7e,0xd, 0x31,0x2d,0x13,0xb, 0xa, 0x30,0x22,0xe4,0x7a,0xb3,0x3, +0xcf,0x12,0xad,0x98,0x7a,0xb3,0x3, 0xd2,0x12,0xac,0xaa,0xe4,0x7a,0xb3,0x3, 0xd9, +0x7a,0xb3,0x3, 0xda,0x22,0xca,0x3b,0x7c,0xeb,0x74,0x27,0xac,0xbe,0x9, 0xf5,0x4b, +0xa6,0x12,0x4f,0xbf,0xe5,0x13,0x12,0x2f,0xb7,0x12,0x4f,0xfc,0xda,0x3b,0x22,0x7e, +0xd0,0xb5,0xac,0xdf,0x2e,0x64,0x1, 0x0, 0x22,0x7c,0xab,0x7e,0x8, 0x0, 0x63,0x7c, +0xba,0x12,0xd, 0xf7,0x7e,0x8, 0x0, 0x9f,0x12,0xd, 0xf7,0x7e,0x34,0x0, 0x8, 0x7e, +0x8, 0x0, 0x63,0x7e,0x24,0x0, 0x1, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x8, 0x7e,0x8, +0x0, 0x9f,0x7e,0x24,0x0, 0x1, 0x2, 0x4, 0x96,0x2, 0x4f,0x64,0xe4,0x12,0x4f,0xc9, +0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14,0x0, 0xdb,0x6d,0x0, 0x74,0x1, 0x7e,0x70,0x27, +0xac,0x7e,0x9, 0x73,0x4b,0xa4,0x12,0xd, 0x23,0x7e,0x30,0x2c,0xac,0x3f,0x2e,0x14, +0x0, 0xdf,0x6d,0x0, 0x74,0xa, 0xac,0xbe,0x9, 0xb5,0x4c,0x46,0x12,0xd, 0x73,0x7d, +0x36,0xb, 0x35,0x74,0x2c,0xac,0xbf,0x49,0x25,0x0, 0xdf,0x12,0x0, 0x2e,0x7d,0x36, +0x74,0x2c,0xac,0xbf,0x49,0x25,0x0, 0xdb,0x2, 0x0, 0x2e,0x7c,0x9b,0x74,0x3, 0xac, +0xb9,0x9, 0x85,0x4c,0x6e,0xbe,0x83,0x4e,0xb, 0x68,0x8, 0x7e,0x83,0x4e,0xb, 0x19, +0x85,0x4c,0x6e,0x9, 0x85,0x4c,0x6f,0xbe,0x83,0x4e,0xc, 0x68,0x8, 0x7e,0x83,0x4e, +0xc, 0x19,0x85,0x4c,0x6f,0x9, 0x85,0x4c,0x70,0xbe,0x83,0x4e,0xd, 0x68,0x8, 0x7e, +0x83,0x4e,0xd, 0x19,0x85,0x4c,0x70,0x7e,0x8, 0x0, 0x57,0x12,0x50,0x98,0x9, 0xb5, +0x4c,0x70,0x12,0x35,0x9a,0x2, 0x4, 0x96,0x9, 0xb5,0x4c,0x6e,0x12,0xc, 0xea,0x7e, +0x8, 0x0, 0x57,0x74,0x3, 0xac,0xb9,0x9, 0xb5,0x4c,0x6f,0x12,0xd, 0x8d,0x7e,0x8, +0x0, 0x57,0x74,0x3, 0xac,0xb9,0x22,0x7c,0x9b,0x12,0x50,0xae,0x12,0x50,0x98,0x12, +0x50,0xd5,0x4c,0x99,0x78,0x9, 0x7e,0x8, 0x0, 0x57,0x74,0x1, 0x12,0xc, 0xea,0x12, +0x35,0x9d,0x2, 0x4, 0x96,0x9, 0xb5,0x4c,0x70,0x2, 0xd, 0x7, 0x6d,0x55,0x80,0x29, +0x7d,0xf5,0x3e,0xf4,0x7f,0x61,0x2d,0xdf,0xb, 0x6a,0x40,0xbe,0x44,0x0, 0x64,0x28, +0x16,0x2d,0xf1,0x7d,0xe0,0xb, 0x7a,0xd0,0xbe,0xd4,0x0, 0x64,0x50,0x2, 0x80,0x4, +0xbd,0xd4,0x28,0x3, 0x1b,0x7a,0x40,0xb, 0x54,0xbe,0x55,0x29,0x40,0xd2,0x22,0x24, +0x8a,0x78,0x21,0x7e,0xf, 0x4f,0xa1,0xa5,0xbf,0x0, 0xc, 0x2e,0x14,0x0, 0xe, 0xb, +0xa, 0x30,0x5e,0x70,0xfb,0x80,0xa, 0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70, +0x4, 0x1b,0xa, 0x30,0x22,0x12,0x3d,0xcb,0x7e,0x73,0x4f,0x4c,0x7a,0x73,0x4d,0xf2, +0x7e,0x73,0x4d,0xf1,0x7a,0x73,0x44,0x7e,0xe4,0x7a,0xb3,0x3f,0xde,0x7a,0xb3,0x3f, +0xdd,0x2, 0x51,0x54,0x7e,0x73,0x4d,0xa0,0x7a,0x73,0x4f,0x6e,0x22,0x2, 0x51,0x54, +0x7e,0x34,0x4, 0x68,0xca,0x39,0x7e,0x1f,0x22,0xe0,0x7e,0x8, 0x28,0x91,0x12,0x16, +0x35,0x1b,0xfd,0x6d,0x33,0x7d,0x13,0x3e,0x14,0x49,0x1, 0x28,0x91,0xbe,0x4, 0x0, +0x0, 0x8, 0x6, 0x49,0x21,0x28,0x91,0x80,0x4, 0x6d,0x22,0x9d,0x20,0x59,0x21,0x28, +0x91,0x49,0x1, 0x24,0x29,0xbd,0x20,0x28,0x4, 0x59,0x21,0x24,0x29,0xb, 0x34,0xbe, +0x34,0x2, 0x34,0x40,0xd0,0x22,0x7e,0x37,0x31,0x9b,0x7a,0x73,0x4d,0xff,0x7e,0xb3, +0x4d,0xfc,0xb4,0x1, 0x2, 0x80,0x2, 0x41,0x88,0x7e,0xb3,0x4d,0xeb,0x44,0x80,0x7a, +0xb3,0x4d,0xeb,0x7e,0xa7,0x31,0x9b,0xbe,0xa4,0x0, 0x5, 0x38,0x30,0x6d,0xdd,0x7a, +0xd7,0x31,0x8a,0x7a,0xd7,0x31,0x88,0x7e,0x8, 0x31,0x82,0x7e,0x34,0x0, 0x6, 0xe4, +0x12,0x16,0x5a,0x7e,0x34,0x4, 0x68,0x7d,0x1d,0xad,0x13,0x2e,0x14,0x24,0x29,0x6d, +0x0, 0xe4,0x12,0x16,0x5a,0xb, 0xd4,0xbe,0xd4,0x0, 0x2, 0x78,0xe6,0x7e,0xa7,0x31, +0x9b,0xb, 0xa4,0x7a,0xa7,0x31,0x9b,0xbe,0xa4,0x0, 0x5, 0x28,0x5, 0xd2,0x1f,0x12, +0x51,0x60,0x7e,0x73,0x4d,0xfd,0xa, 0xa7,0x3e,0xa4,0x3e,0xa4,0x2e,0xa4,0x0, 0x5, +0xbe,0xa7,0x31,0x9b,0x78,0x74,0x6d,0xdd,0x4d,0xdd,0x78,0x4, 0x6d,0xbb,0x80,0xa, +0x7d,0x3d,0x1b,0x34,0x3e,0x34,0x49,0xb3,0x24,0x29,0xbe,0xd4,0x2, 0x34,0x78,0x4, +0x6d,0xcc,0x80,0x8, 0x7d,0xcd,0x3e,0xc4,0x49,0xcc,0x24,0x2b,0x7d,0x3b,0x2d,0x3c, +0x7e,0x24,0x0, 0xa, 0x8d,0x32,0x7d,0x3d,0x3e,0x34,0x2e,0x34,0x24,0x29,0xb, 0x38, +0xa0,0x2d,0xa2,0x1b,0x38,0xa0,0xb, 0xd4,0xbe,0xd4,0x2, 0x34,0x78,0xba,0xc2,0x1f, +0xe4,0x7a,0xb3,0x4d,0xfc,0x6d,0xaa,0x7a,0xa7,0x2c,0xfc,0x7e,0x34,0x24,0x29,0x7a, +0x37,0x31,0x74,0x7a,0xa7,0x31,0x9b,0x22,0xc2,0x1f,0x7e,0xa7,0x31,0x9b,0x4d,0xaa, +0x68,0x8, 0x6d,0xaa,0x7a,0xa7,0x31,0x9b,0xd2,0x12,0x22,0x24,0x6f,0x68,0x12,0x14, +0x68,0x14,0x14,0x68,0x16,0x14,0x68,0x18,0xb, 0xb2,0x78,0x19,0x7e,0xb3,0x1, 0x76, +0x22,0x7e,0xb3,0x1, 0x77,0x22,0x7e,0xb3,0x1, 0x78,0x22,0x7e,0xb3,0x1, 0x79,0x22, +0x7e,0xb3,0x1, 0x7a,0x22,0x74,0xfe,0x22,0x24,0xab,0x68,0x10,0x24,0xef,0x68,0x1c, +0x24,0xde,0x68,0x26,0x24,0xde,0x78,0x2f,0x74,0x5, 0x80,0x2d,0x7e,0xb3,0x4f,0xab, +0xb4,0x5, 0x2a,0x12,0x53,0xe, 0x12,0x54,0x42,0x2, 0x53,0x4e,0x7e,0xb3,0x4f,0xab, +0xb4,0x5, 0x1a,0x12,0x53,0xe, 0x75,0xe9,0xff,0x22,0x7e,0xb3,0x4f,0xab,0xb4,0x5, +0xc, 0x12,0x53,0xe, 0x2, 0x53,0x31,0x74,0x1, 0x7a,0xb3,0x4f,0xab,0x22,0x7e,0x34, +0x0, 0x1, 0x7d,0x23,0x80,0x12,0x7e,0x30,0x4, 0x80,0x5, 0x74,0xfa,0x12,0x53,0x95, +0x7c,0x23,0x1b,0x30,0xa5,0xba,0x0, 0xf3,0x7d,0x32,0x1b,0x24,0x4d,0x33,0x78,0xe6, +0x22,0x2, 0x53,0x34,0x75,0xe7,0x6b,0xe4,0x7e,0x34,0x1, 0x4, 0x7e,0x24,0x0, 0xff, +0x7a,0x1b,0xb0,0x7e,0x34,0x1, 0x5, 0x7a,0x1b,0xb0,0x75,0xe9,0xff,0x22,0x2, 0x53, +0x34,0x7c,0xa7,0x7c,0x3b,0xa5,0xbb,0x0, 0x7, 0x7c,0xba,0x12,0x53,0xb1,0x80,0x25, +0xbe,0x30,0xeb,0x68,0x4, 0xa5,0xbb,0xec,0x9, 0x7c,0xb3,0x7c,0x7a,0x12,0x54,0x6, +0x80,0x13,0xbe,0x30,0x80,0x40,0xe, 0xbe,0x30,0xef,0x38,0x9, 0x7c,0xb3,0x24,0x80, +0x7c,0x7a,0x12,0x53,0xd9,0xa5,0xbb,0xfc,0x5, 0x7c,0xba,0x2, 0x52,0xc8,0x74,0x1, +0x7a,0xb3,0x4f,0xab,0x22,0x7c,0xab,0x80,0xf, 0x7e,0x70,0x2, 0x80,0x1, 0x0, 0x7c, +0x67,0x1b,0x70,0xa5,0xbe,0x0, 0xf7,0x0, 0x7c,0x6a,0x1b,0xa0,0xa5,0xbe,0x0, 0xe9, +0x22,0x7a,0xb3,0x4d,0xeb,0xc4,0x54,0x7, 0xbe,0xb0,0x4, 0x68,0x3, 0xb4,0x2, 0x4, +0x74,0x3, 0x80,0x7, 0x60,0x3, 0xb4,0x1, 0x7, 0x74,0x1, 0x7a,0xb3,0x4d,0xa0,0x22, +0x12,0x1f,0xf8,0xe4,0x7a,0xb3,0x4d,0xeb,0x22,0x7c,0x6b,0x2e,0x60,0xdd,0x68,0x25, +0x2e,0x60,0xfd,0x68,0x20,0x1b,0x61,0x68,0x1c,0x2e,0x60,0xfa,0x68,0x17,0x1b,0x60, +0x68,0x13,0x80,0x0, 0xa, 0x2b,0x19,0x72,0x4d,0x79,0xd2,0x21,0xb4,0x25,0x6, 0xd2, +0x22,0x7a,0x73,0x4d,0x77,0x22,0xbe,0xb0,0xeb,0x68,0x3, 0xb4,0xec,0x33,0x7e,0x27, +0x4e,0x47,0x4d,0x22,0x78,0xe, 0xa5,0xbf,0xaa,0xa, 0x7e,0x24,0x0, 0x1, 0x7a,0x27, +0x4e,0x47,0x15,0xf, 0x7e,0x27,0x4e,0x47,0xbe,0x24,0x0, 0x1, 0x78,0x10,0xa5,0xbf, +0x9, 0x6, 0x7e,0x34,0x0, 0x2, 0x80,0x2, 0x6d,0x33,0x7a,0x37,0x4e,0x47,0x75,0xf, +0xea,0x22,0x7e,0x14,0xf7,0xf0,0x7e,0x4, 0x0, 0xff,0x7e,0x34,0x47,0x52,0x7e,0x24, +0x55,0x50,0x79,0x30,0x0, 0x2, 0x1b,0xa, 0x20,0x7e,0x34,0x45,0x20,0x7e,0x24,0x41, +0x44,0x79,0x30,0x0, 0x6, 0x79,0x20,0x0, 0x4, 0x7e,0x34,0x99,0x33,0x7e,0x24,0x66, +0xcc,0x79,0x30,0x0, 0xa, 0x79,0x20,0x0, 0x8, 0x7e,0x34,0x41,0x47,0x7e,0x24,0x46, +0x4c,0x79,0x30,0x0, 0xe, 0x79,0x20,0x0, 0xc, 0x22,0x7e,0x73,0x3e,0x68,0x7a,0x73, +0x3e,0x69,0x7e,0x73,0x3f,0xdd,0x7a,0x73,0x3f,0xde,0xe4,0x7a,0xb3,0x3f,0xe1,0x7e, +0x73,0x4f,0x4c,0x7a,0x73,0x4d,0xa4,0x7e,0x73,0x40,0x2, 0x7a,0x73,0x49,0xe9,0x22, +0x7e,0xb3,0x4f,0xac,0x4, 0x7a,0xb3,0x4f,0xac,0x7e,0x73,0x4f,0xac,0x7a,0x73,0x4d, +0x8a,0x22,0x7e,0x37,0x4f,0x5d,0xb, 0x34,0x7a,0x37,0x4f,0x5d,0x7e,0x37,0x4f,0x5f, +0xbe,0x37,0x4f,0x5d,0x28,0x3, 0x2, 0x54,0xdd,0x22,0x2, 0x54,0xc2,0xe5,0x9a,0x60, +0x5, 0xd2,0x9c,0xa9,0xd6,0xdf,0x22,0xca,0x7b,0xca,0x6b,0xca,0x5b,0xca,0x4b,0xca, +0x2b,0xca,0x1b,0xca,0xb, 0xc0,0xd0,0xc0,0x83,0xc0,0x82,0xc2,0x8f,0x12,0x54,0xda, +0xd0,0x82,0xd0,0x83,0xd0,0xd0,0xda,0xb, 0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b, +0xda,0x6b,0xda,0x7b,0x32,0xe4,0x12,0x57,0xc3,0x12,0x57,0x12,0x12,0x55,0x9d,0x12, +0x55,0x92,0x12,0x56,0xfb,0x7e,0x34,0x0, 0x1c,0x12,0xc, 0x65,0x7e,0x34,0x9, 0xc4, +0x12,0x1d,0x19,0x12,0x56,0xe1,0x12,0x56,0xd0,0x12,0x56,0xdb,0x12,0x56,0xd5,0x12, +0x57,0x6, 0x12,0x57,0xe1,0x12,0x55,0xb3,0x12,0xa1,0x38,0x12,0x55,0x6d,0x12,0x56, +0x49,0xd2,0xaf,0x12,0x56,0x8, 0x90,0xe, 0x73,0xe4,0x93,0xca,0xb8,0x90,0xe, 0x74, +0xe4,0x93,0x7c,0x7b,0x7e,0x24,0x1, 0x33,0xda,0xb8,0x2, 0xb, 0x7b,0x2, 0x55,0x70, +0xd2,0x0, 0x12,0x36,0x14,0xa9,0xd0,0xcb,0xa9,0xc6,0xca,0x12,0x57,0x1f,0xa9,0xd3, +0x9e,0xa9,0xc3,0xb9,0xc2,0x8a,0xd2,0xaa,0x2, 0x55,0x8b,0xa9,0xd0,0x9e,0xa9,0xd7, +0x9e,0x22,0xc2,0x8d,0xc2,0x8f,0x12,0x56,0x0, 0xa9,0xc0,0x93,0x22,0x75,0xec,0xff, +0x75,0xee,0xff,0x75,0xeb,0x23,0x75,0xac,0xc0,0x12,0x57,0xd1,0xa9,0xd5,0xad,0xa9, +0xc5,0xed,0x22,0xe4,0x7a,0xb3,0x4d,0xeb,0x7e,0x8, 0x4b,0x21,0x12,0x56,0xe8,0x7e, +0x8, 0x4b,0x5f,0x7e,0x34,0x0, 0x3e,0x12,0x16,0x5a,0x7e,0x18,0x4b,0x21,0x7a,0x1f, +0x4b,0x9d,0x12,0x55,0xe5,0x2, 0x55,0xd8,0x75,0x8, 0x0, 0x75,0xf, 0x0, 0x7e,0xb3, +0x4d,0xeb,0xf5,0x91,0x22,0x2, 0x55,0xe8,0xc2,0x92,0x12,0x56,0x0, 0x90,0xe, 0x6, +0xe4,0x93,0x54,0xfe,0xf5,0x92,0xd2,0xe8,0xc2,0xc0,0xa9,0xd4,0x95,0xd2,0xad,0x22, +0x75,0x91,0x0, 0xc2,0x90,0xc2,0x91,0x22,0x6c,0x77,0xa9,0xc7,0xb3,0xa9,0xc6,0xb3, +0xd2,0xc8,0x43,0xed,0xf, 0xc2,0xea,0xb, 0x70,0xbe,0x70,0x3, 0x28,0x3, 0x7e,0x70, +0x3, 0xa, 0x57,0x3e,0x54,0x3e,0x54,0x3e,0x54,0x3e,0x54,0x2e,0x54,0x0, 0x3, 0xf5, +0xb3,0xa9,0xd1,0xb4,0xa9,0xc0,0xb4,0x12,0x56,0xf1,0x2, 0x56,0x3d,0xa9,0xc5,0xca, +0xa9,0xc7,0x94,0xe4,0x7a,0xb3,0x4f,0xb0,0x22,0xa9,0xd2,0xea,0xa9,0xc2,0xea,0x6d, +0x33,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x10,0x12,0x35,0x8e,0x4e,0x34,0xdc,0xe, +0x1b,0xa, 0x30,0x7e,0x34,0x1, 0xc2,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x1e,0x7e, +0xf, 0x4f,0xa1,0x2e,0x14,0x0, 0xe, 0xb, 0xa, 0x30,0x4e,0x70,0x10,0x1b,0xa, 0x30, +0x12,0xac,0x93,0x12,0xb, 0xe5,0x7e,0x34,0xff,0xff,0x7e,0xf, 0x4f,0xa1,0x79,0x30, +0x0, 0x2, 0x6d,0x33,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x14,0x7e,0xf, 0x4f,0xa1, +0x79,0x30,0x0, 0x4, 0x7e,0x34,0xf0,0x4f,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x4, +0xd2,0x2, 0x12,0x1c,0x4f,0x53,0xc3,0xf8,0x75,0xc3,0x85,0x53,0xc2,0xfc,0x43,0xc2, +0x81,0xd2,0xac,0x2, 0x56,0xc6,0x90,0x13,0x7e,0xe4,0x93,0x7a,0xb3,0x4f,0x4d,0x22, +0xc2,0x88,0xd2,0xa8,0x22,0xa9,0xd5,0xcd,0xd2,0x99,0x22,0xa9,0xd6,0xcd,0xd2,0x98, +0x22,0xa9,0xd0,0x99,0xa9,0xc6,0xdf,0x22,0x7e,0x34,0x0, 0x3e,0x74,0xff,0x2, 0x16, +0x5a,0xa9,0xd7,0x94,0x74,0xa5,0x7a,0xb3,0x4f,0xb0,0x22,0xa9,0xc3,0xcb,0xc2,0xcd, +0xc2,0xcc,0xa9,0xd6,0xea,0x22,0x75,0x9a,0x2f,0xa9,0xd1,0x99,0xd2,0x9c,0xa9,0xd6, +0xdf,0x22,0xa9,0xc5,0xcb,0xa9,0xd1,0xcb,0xa9,0xd2,0xca,0xa9,0xd2,0xcb,0x22,0xa9, +0xd0,0x9e,0xa9,0xd4,0x9e,0x75,0x9d,0x0, 0x75,0x9c,0x20,0x22,0xca,0xb8,0xca,0x39, +0x12,0x57,0x1f,0x12,0x55,0x8b,0x7e,0x37,0x4f,0x44,0xb, 0x34,0x7a,0x37,0x4f,0x44, +0x7e,0x37,0x4f,0x56,0xb, 0x34,0x7a,0x37,0x4f,0x56,0x7e,0xb3,0x4d,0xa0,0xb4,0x1, +0x40,0x7e,0xb3,0x4f,0x58,0x4, 0x7a,0xb3,0x4f,0x58,0x7e,0x73,0x4f,0x58,0xbe,0x70, +0xa, 0x28,0x2e,0xe4,0x7a,0xb3,0x4f,0x58,0x7e,0x73,0x4f,0x4f,0xbe,0x73,0x4f,0xac, +0x78,0x8, 0x7e,0x37,0x4f,0x46,0xb, 0x34,0x80,0xa, 0x7e,0x73,0x4f,0xac,0x7a,0x73, +0x4f,0x4f,0x6d,0x33,0x7a,0x37,0x4f,0x46,0xbe,0x34,0x0, 0xfa,0x28,0x3, 0x75,0xe9, +0xff,0x7e,0xb3,0x4f,0x48,0x60,0x5, 0x14,0x7a,0xb3,0x4f,0x48,0x7e,0xb3,0x4f,0x48, +0x70,0x2, 0xd2,0x16,0x7e,0x37,0x4f,0x9a,0xb, 0x34,0x7a,0x37,0x4f,0x9a,0x7e,0x37, +0x4f,0x52,0xbe,0x34,0x0, 0x0, 0x28,0x6, 0x1b,0x34,0x7a,0x37,0x4f,0x52,0xda,0x39, +0xda,0xb8,0x32,0xa9,0xc5,0xca,0xbe,0xb0,0x8, 0x50,0x2, 0xf5,0xcc,0x75,0xe6,0x0, +0x22,0xa9,0xc5,0xca,0x75,0xed,0x8f,0x75,0xad,0xb0,0xa9,0xc7,0x94,0xa9,0xd4,0x94, +0x22,0xc2,0x8e,0x43,0x89,0x20,0x75,0x8d,0x1, 0x75,0x8b,0x0, 0xd2,0x8e,0xd2,0xab, +0x22,0xca,0x7b,0xca,0x6b,0xca,0x5b,0xca,0x4b,0xca,0x2b,0xca,0x1b,0xca,0xb, 0xc0, +0xd0,0xc0,0x83,0xc0,0x82,0x12,0x34,0xc, 0xd0,0x82,0xd0,0x83,0xd0,0xd0,0xda,0xb, +0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b,0xda,0x6b,0xda,0x7b,0x32,0x12,0x58,0x24, +0x75,0x8, 0x0, 0x32,0xa9,0xc0,0x93,0x22,0xb4,0xfa,0x5, 0x7e,0xb3,0x2c,0xff,0x22, +0x70,0x5, 0x7e,0xb3,0x4d,0xeb,0x22,0xbe,0xb0,0x3, 0x38,0x13,0x30,0x2b,0x6, 0x7e, +0x18,0x4b,0x21,0x80,0x4, 0x7e,0x18,0x4b,0x5f,0x7a,0x1f,0x4b,0x9d,0x80,0x5, 0xbe, +0xb0,0x6e,0x38,0xe, 0xa, 0x1b,0x7e,0x1f,0x4b,0x9d,0x2d,0x31,0x1b,0x34,0x7e,0x1b, +0xb0,0x22,0xbe,0xb0,0xeb,0x68,0x3, 0xb4,0xec,0x3, 0x2, 0x58,0x98,0xbe,0xb0,0x80, +0x40,0xc, 0xbe,0xb0,0xef,0x38,0x7, 0xa, 0x3b,0x9, 0xb3,0x4c,0xf9,0x22,0xb4,0xfc, +0x5, 0x7e,0xb3,0x4d,0xa0,0x22,0xb4,0xfe,0xc, 0x7e,0xa3,0x4f,0x55,0x74,0x27,0xa4, +0x9, 0xb5,0x4b,0xa3,0x22,0x74,0xff,0x22,0xb4,0xeb,0x3, 0x75,0x10,0x0, 0xe5,0x10, +0xa, 0x3b,0x2e,0x34,0x0, 0x16,0x12,0x58,0xcb,0x7c,0xab,0x5, 0x10,0xe5,0x10,0xb4, +0x3, 0x9, 0x75,0x10,0x0, 0x6d,0x33,0x7a,0x37,0x4e,0x47,0x75,0xf, 0xeb,0x7c,0xba, +0x22,0x7c,0xb7,0x54,0x7, 0xa, 0x3b,0x2e,0x34,0x0, 0xf5,0x7a,0x71,0x82,0x7a,0x61, +0x83,0xe4,0x93,0x22,0x74,0x1, 0x7a,0xb3,0x4f,0xae,0x7e,0xb3,0x4d,0xc9,0xb4,0x1, +0x6, 0xe4,0x7a,0xb3,0x4f,0xae,0x22,0x7e,0xb4,0x13,0x81,0x7d,0x3b,0x12,0x58,0xcb, +0x7c,0x7b,0x1e,0x70,0x7a,0x73,0x3f,0xea,0x7e,0xa4,0x0, 0x96,0x7a,0xa7,0x3f,0xeb, +0x7e,0x34,0x0, 0x8c,0x7a,0x37,0x3f,0xed,0x12,0xaa,0xea,0x7e,0xa3,0x3e,0x53,0xbe, +0xa0,0x0, 0x38,0x2, 0x21,0xa7,0xbe,0xa0,0x8, 0x28,0x1f,0x7e,0x37,0x3e,0x59,0xbe, +0x34,0x1, 0x90,0x58,0x15,0x7d,0x3b,0x12,0x58,0xcb,0x1e,0xb0,0xa, 0x3b,0x7d,0x2a, +0x7e,0x14,0x0, 0x8c,0x7e,0x4, 0x0, 0x82,0x80,0x66,0xbe,0xa0,0x6, 0x28,0x1b,0x7e, +0x37,0x3e,0x59,0xbe,0x34,0x1, 0xf4,0x58,0x11,0x7d,0x3b,0x12,0x58,0xcb,0xa, 0x3b, +0x7e,0x24,0x0, 0xa0,0x7d,0x1a,0x7d,0xa, 0x80,0x46,0xbe,0xa0,0x4, 0x28,0x1f,0x7e, +0xa7,0x3e,0x59,0xbe,0xa4,0x2, 0x58,0x58,0x15,0x7d,0x3b,0x12,0x58,0xcb,0xa, 0x3b, +0x7e,0x24,0x0, 0xb4,0x7e,0x14,0x0, 0xaa,0x7e,0x4, 0x0, 0xc8,0x80,0x22,0xbe,0xa0, +0x2, 0x28,0x24,0x7e,0xa7,0x3e,0x59,0xbe,0xa4,0x3, 0x20,0x58,0x1a,0x7d,0x3b,0x12, +0x58,0xcb,0xa, 0x3b,0x7e,0x24,0x0, 0xdc,0x7e,0x14,0x0, 0xd2,0x7e,0x4, 0x0, 0xe6, +0x12,0x59,0xd8,0x80,0x7, 0x80,0x0, 0xe4,0x7a,0xb3,0x4f,0xae,0x7e,0xb3,0x4f,0xae, +0x70,0x23,0x90,0x13,0x81,0xe4,0x93,0xa, 0x3b,0x7e,0x14,0x13,0x89,0x12,0x5d,0x9f, +0x7e,0x14,0x13,0x8b,0x12,0x59,0xfd,0x7e,0x54,0x13,0x95,0x7e,0x44,0x0, 0xff,0xb, +0x2a,0x0, 0x2, 0x59,0xd8,0xd2,0x21,0x22,0x7a,0x73,0x3f,0xea,0x7a,0x27,0x3f,0xeb, +0x7a,0x17,0x3f,0xed,0x7a,0x7, 0x3f,0xf7,0x6d,0x33,0x9d,0x30,0x12,0x1f,0xe, 0x12, +0x1f,0xa9,0x7a,0x73,0x4d,0x7a,0x22,0x12,0x9d,0xa6,0x2, 0x58,0xd4,0x7e,0x4, 0x0, +0xff,0xb, 0xa, 0x10,0x22,0x7d,0x13,0x9f,0x11,0x7e,0xf4,0x14,0xa, 0x7e,0xe4,0x0, +0xff,0xb, 0x7a,0x0, 0x7e,0xf4,0x14,0x1a,0x7e,0xe4,0x0, 0xff,0xb, 0x7a,0xf0,0x7e, +0xd4,0x14,0x1c,0x7e,0xc4,0x0, 0xff,0xb, 0x6a,0xe0,0x90,0xe, 0x5a,0xe4,0x93,0x70, +0x3, 0x7d,0x31,0x22,0x90,0x14,0x7, 0xe4,0x93,0xb4,0x1, 0x6, 0x7e,0x83,0x40,0x11, +0x80,0x4, 0x7e,0x83,0x40,0x12,0x12,0x5d,0xa7,0xbe,0x14,0x0, 0x3f,0x38,0x1a,0x7e, +0x24,0x0, 0x3f,0x9d,0x21,0x7e,0x14,0x14,0x20,0x12,0x5b,0x1b,0x12,0x5b,0x2d,0x48, +0x2, 0x7f,0x10,0x9f,0x1, 0x7f,0x10,0x61,0x12,0x7d,0x54,0x9e,0x54,0x0, 0x3f,0xbd, +0x51,0x38,0x43,0x7d,0x54,0x9e,0x54,0x0, 0x1f,0xbd,0x51,0x40,0x1d,0x7d,0x34,0x9e, +0x34,0x0, 0x40,0x12,0x5b,0x13,0x90,0x14,0x1f,0x12,0x5b,0x30,0x48,0x4, 0x7f,0x10, +0x1b,0x1c,0xa, 0xb, 0x7d,0x1f,0x9d,0x10,0x80,0x16,0xbd,0x41,0x50,0x74,0x7e,0xb3, +0x44,0x86,0xbe,0xb0,0x0, 0x28,0x6b,0x7d,0x34,0xb, 0x34,0x12,0x5b,0x13,0x7d,0x1f, +0x6d,0x0, 0x2f,0x10,0x80,0x5c,0x7d,0x50,0x1b,0x54,0xbd,0x51,0x40,0x1f,0x7d,0x30, +0x9d,0x31,0x6d,0x22,0x7e,0x14,0x14,0x24,0x12,0x59,0xfd,0x12,0x14,0xe2,0x12,0x5b, +0x26,0x7d,0x1e,0x1b,0x14,0x6d,0x0, 0x9f,0x1, 0x7f,0x10,0x80,0x19,0x7d,0x31,0x9d, +0x30,0x6d,0x22,0x7e,0x14,0x14,0x26,0x12,0x59,0xfd,0x12,0x14,0xe2,0x12,0x5b,0x26, +0x7d,0x1e,0x6d,0x0, 0x2f,0x10,0x12,0x5b,0x2d,0x58,0x4, 0x7f,0x10,0x80,0x13,0x90, +0x14,0x1f,0xe4,0x93,0xa, 0xb, 0x7d,0x1f,0x9d,0x10,0x6d,0x0, 0xbf,0x10,0x8, 0x2, +0x7f,0x10,0x22,0x7d,0x21,0x9d,0x23,0x7e,0x14,0x14,0x22,0x7e,0x4, 0x0, 0xff,0xb, +0xa, 0x30,0xad,0x32,0x6d,0x22,0x7c,0x76,0x7c,0x65,0x1a,0x24,0x22,0x90,0x14,0x1e, +0xe4,0x93,0xa, 0x1b,0x6d,0x0, 0xbf,0x10,0x22,0xca,0xf8,0x12,0x5f,0xdf,0x40,0x2, +0x61,0xd9,0x7e,0xb3,0x24,0x26,0xb4,0x1, 0x2, 0x80,0x2, 0x61,0xd9,0x6c,0xff,0x61, +0xd2,0x74,0x9, 0xac,0xbf,0x49,0x35,0x3d,0x45,0x12,0x5c,0x83,0x7d,0xb3,0x74,0x9, +0xac,0xbf,0x49,0x35,0x3d,0x47,0x12,0x5a,0x5, 0x7d,0xa3,0x7e,0x34,0x14,0xc, 0x7e, +0x24,0x0, 0xff,0xb, 0x1a,0x40,0x7e,0x73,0x4d,0xbd,0x12,0x5b,0xec,0x12,0x5b,0xdc, +0x7d,0x3b,0x6d,0x22,0xbf,0x10,0x40,0x41,0x7e,0x34,0x14,0x1a,0x7e,0x24,0x0, 0xff, +0xb, 0x1a,0x50,0x7e,0x73,0x4d,0xbf,0x12,0x5b,0xe3,0x12,0x5b,0xdc,0x7d,0x3a,0x6d, +0x22,0xbf,0x10,0x40,0x24,0x7e,0x73,0x4d,0xbe,0x12,0x5b,0xec,0x12,0x5b,0xdc,0x7d, +0x3b,0x6d,0x22,0xbf,0x10,0x38,0x12,0x7e,0x73,0x4d,0xc0,0x12,0x5b,0xe3,0x12,0x5b, +0xdc,0x7d,0x3a,0x6d,0x22,0xbf,0x10,0x28,0x7, 0xc2,0x6, 0x7c,0xbf,0x12,0x26,0xfa, +0xb, 0xf0,0x12,0x27,0xf7,0x28,0x2, 0x61,0x51,0xda,0xf8,0x22,0x7c,0x36,0x7c,0x25, +0xa, 0x4, 0x22,0xa, 0x37,0x6d,0x22,0x7d,0x15,0x2, 0x14,0xe2,0xa, 0x37,0x6d,0x22, +0x7d,0x14,0x2, 0x14,0xe2,0x7c,0x7b,0xc4,0x23,0x54,0x1f,0xa, 0x2b,0x9, 0xa2,0x3d, +0x41,0x12,0x58,0xc1,0x5c,0xba,0x22,0xca,0xf8,0x7e,0xb3,0x3f,0xdd,0x70,0x17,0xe4, +0x7a,0xb3,0x3f,0xe6,0x12,0x5f,0xe7,0x28,0x1f,0x74,0x1, 0x7a,0xb3,0x3f,0xe2,0xe4, +0x7a,0xb3,0x3f,0xe5,0x80,0x12,0x74,0x1, 0x7a,0xb3,0x3f,0xe6,0x7e,0xb3,0x3f,0xde, +0x70,0x6, 0x74,0x1, 0x7a,0xb3,0x3f,0xe1,0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e, +0x89,0x7e,0x8, 0x3e,0xe3,0x12,0x16,0x35,0x1b,0xfd,0x90,0xe, 0x5a,0xe4,0x93,0xbe, +0xb0,0x0, 0x28,0x2c,0x6c,0xff,0x80,0x1f,0x74,0x9, 0xac,0xbf,0x49,0x35,0x3e,0x89, +0x12,0x5c,0x83,0x74,0x9, 0xac,0xbf,0x59,0x35,0x3e,0xe3,0x49,0x35,0x3e,0x8b,0x12, +0x5a,0x5, 0x12,0x5d,0xaf,0xb, 0xf0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xd8, +0xda,0xf8,0x22,0x7e,0x14,0x14,0x8, 0x12,0x5d,0x9f,0x7e,0x14,0x14,0xc, 0x7e,0x4, +0x0, 0xff,0xb, 0xa, 0xd0,0x7e,0x14,0x14,0xe, 0x7e,0x4, 0x0, 0xff,0xb, 0xa, 0xc0, +0x90,0xe, 0x5a,0xe4,0x93,0x70,0x1, 0x22,0x90,0x14,0x7, 0xe4,0x93,0xb4,0x1, 0x6, +0x7e,0x83,0x40,0x12,0x80,0x4, 0x7e,0x83,0x40,0x11,0x12,0x5d,0xa7,0xbe,0x34,0x0, +0x3f,0x38,0x22,0x7e,0xe4,0x0, 0x3f,0x9d,0xe3,0x7e,0x34,0x14,0x12,0x12,0x5d,0x76, +0x7c,0x76,0x7c,0x65,0x7f,0x71,0x12,0x5d,0x6e,0xbf,0x71,0x40,0x2, 0x7f,0x71,0x9f, +0x17,0x7f,0x71,0xa1,0x6b,0x7d,0x54,0x9e,0x54,0x0, 0x3f,0xbd,0x53,0x38,0x2c,0x7d, +0xe3,0x9d,0xe5,0x7e,0x34,0x14,0x14,0x12,0x5d,0x76,0x7c,0x76,0x7c,0x65,0x7f,0x71, +0x90,0x14,0x11,0xe4,0x93,0xa, 0x3b,0xbf,0x71,0x40,0x4, 0x7f,0x71,0x1b,0x7c,0xa, +0x2b,0x7d,0x3d,0x9d,0x32,0x6d,0x22,0x2f,0x71,0x80,0x50,0x7d,0x52,0x1b,0x54,0xbd, +0x53,0x40,0x17,0x7d,0xf5,0x9d,0xf3,0x6d,0xee,0x7e,0x34,0x14,0x16,0x12,0x5d,0x86, +0x1b,0x34,0x6d,0x22,0x9f,0x17,0x7f,0x71,0x80,0x11,0x7d,0xf3,0x9d,0xf2,0x6d,0xee, +0x7e,0x34,0x14,0x18,0x12,0x5d,0x86,0x6d,0x22,0x2f,0x71,0x12,0x5d,0x6e,0x6d,0x22, +0xbf,0x71,0x50,0x4, 0x7f,0x71,0x80,0x13,0x90,0x14,0x11,0xe4,0x93,0xa, 0x2b,0x7d, +0x3d,0x9d,0x32,0x6d,0x22,0xbf,0x71,0x28,0x2, 0x7f,0x71,0x7d,0x3f,0x22,0x90,0x14, +0x10,0xe4,0x93,0xa, 0x3b,0x22,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0xf0,0xad,0xfe,0x6d, +0xee,0x7d,0x3f,0x7d,0x2e,0x22,0x7e,0x24,0x0, 0xff,0xb, 0x1a,0x10,0x7f,0x17,0x12, +0x14,0xe2,0x7f,0x71,0x7c,0x76,0x7c,0x65,0xa, 0x24,0x7f,0x71,0x7d,0x3c,0x22,0x7e, +0x4, 0x0, 0xff,0xb, 0xa, 0x20,0x22,0x7e,0x90,0x40,0xac,0x89,0x1b,0x44,0x22,0x74, +0x9, 0xac,0xbf,0x59,0x35,0x3e,0xe5,0x22,0xca,0xd8,0xca,0x79,0x7e,0x34,0x14,0x1a, +0x12,0x5f,0xef,0x90,0xe, 0x5a,0xe4,0x93,0x60,0x68,0x7e,0xb3,0x44,0x86,0x60,0x62, +0x6c,0xff,0x80,0x55,0x7e,0x70,0x9, 0xac,0x7f,0x9, 0xe3,0x3e,0xe7,0x5e,0xe0,0xf, +0x49,0x23,0x3e,0xe5,0xbd,0x2d,0x40,0x3f,0x49,0xc3,0x3e,0x89,0x7d,0x3c,0x12,0x96, +0xc8,0x7c,0xdb,0x7e,0x73,0x44,0x86,0xbc,0x7d,0x28,0x20,0x7e,0x70,0x2, 0xac,0x7d, +0x2e,0x34,0x14,0x29,0x12,0x1d,0xf2,0x74,0x9, 0xac,0xbf,0x59,0x35,0x3e,0xe3,0x7e, +0x34,0x14,0x31,0x12,0x1d,0xf2,0x12,0x5d,0xaf,0x80,0xc, 0x7d,0x3d,0x1b,0x34,0x12, +0x5d,0xaf,0x7c,0xbe,0x12,0x96,0x75,0xb, 0xf0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf, +0x38,0xa2,0xda,0x79,0xda,0xd8,0x22,0xca,0x79,0x6c,0xff,0xc2,0x0, 0x7e,0xb3,0x40, +0x2, 0x60,0x6, 0x7e,0xd4,0x1, 0xc2,0x80,0x4, 0x7e,0xd4,0x3, 0xe8,0x7e,0xb3,0x40, +0x3, 0xb4,0x1, 0x4, 0x7e,0xd4,0x0, 0xf0,0x7e,0xc7,0x3e,0x59,0x6c,0xee,0xc1,0xe2, +0xc2,0x0, 0x7c,0xbe,0x12,0x7d,0x20,0x7d,0xb3,0x74,0x2, 0xac,0xbe,0x9, 0xb5,0x3c, +0xc9,0x12,0x80,0xaf,0xbd,0x3b,0x58,0x4, 0xd2,0x0, 0x80,0x37,0x74,0x2, 0xac,0xbe, +0x9, 0xb5,0x3c,0xc9,0x12,0x5e,0xf8,0x50,0x4, 0xd2,0x0, 0x80,0x26,0x7e,0x73,0x3f, +0xde,0xbe,0x73,0x3e,0x53,0x78,0x1c,0x7e,0xa7,0x4f,0xa9,0xe, 0xa4,0xbd,0xac,0x58, +0x12,0x7c,0xbe,0x7e,0x70,0x1, 0x12,0x5f,0x3, 0x7d,0x1d,0x6d,0x0, 0xbf,0x10,0x8, +0x2, 0xd2,0x0, 0x30,0x0, 0x2a,0x7c,0xbe,0x12,0x5b,0xf5,0x60,0x23,0x7e,0xa4,0x0, +0x9, 0xca,0xa9,0x7e,0x70,0x9, 0xac,0x7e,0x2e,0x34,0x3d,0x45,0x6d,0x22,0x7e,0x30, +0x9, 0xac,0x3f,0x2e,0x14,0x3e,0x89,0x6d,0x0, 0x12,0x16,0x35,0x1b,0xfd,0xb, 0xf0, +0xb, 0xe0,0x12,0x5f,0xd8,0x28,0x2, 0xc1,0x60,0x7a,0x73,0x3e,0x68,0x7a,0xf3,0x3f, +0xdd,0x7a,0xc7,0x4f,0xa9,0xda,0x79,0x22,0x7c,0xab,0x12,0x5f,0xcd,0x78,0x2, 0xd3, +0x22,0xc3,0x22,0x7c,0x67,0x7c,0x7b,0x7e,0x50,0x2, 0xac,0x57,0x9, 0xa2,0x3c,0xc9, +0x9, 0x72,0x3c,0xca,0x12,0x5f,0xcd,0x78,0x3, 0x9f,0x11,0x22,0x7c,0xba,0x2, 0x5f, +0x21,0x7c,0x16,0x7c,0x7, 0x7c,0x9b,0x7e,0xb3,0x40,0x11,0xf5,0x2a,0x7e,0xb3,0x40, +0x12,0xf5,0x2b,0x9f,0x77,0xa, 0x31,0xa, 0x19,0x9d,0x13,0x7c,0x83,0x80,0x7d,0x7a, +0x81,0x28,0xbe,0x80,0x0, 0x58,0xc, 0x1a,0x58,0x1a,0x19,0x9d,0x15,0xa, 0x59,0x2d, +0x51,0xf5,0x28,0xe5,0x2a,0xbc,0xb8,0x18,0xc, 0x1a,0x59,0x1a,0x18,0x9d,0x15,0xa, +0x59,0x9d,0x51,0xf5,0x28,0xa, 0x11,0xa, 0x50,0x9d,0x51,0xf5,0x27,0x80,0x3d,0x85, +0x27,0x29,0xe5,0x27,0xbe,0xb0,0x0, 0x58,0xe, 0xe5,0x27,0x1a,0x5b,0x1a,0x10,0x9d, +0x15,0xa, 0x50,0x2d,0x51,0xf5,0x29,0xe5,0x2b,0xbe,0xb1,0x27,0x18,0xe, 0x1a,0x30, +0xe5,0x27,0x1a,0x1b,0x9d,0x13,0xa, 0x50,0x9d,0x51,0xf5,0x29,0xe5,0x28,0x7e,0x71, +0x29,0x12,0x23,0x82,0x1a,0x26,0x1a,0x24,0x2f,0x71,0x5, 0x27,0xa, 0x21,0xa, 0x30, +0x2d,0x32,0xe5,0x27,0x1a,0x1b,0xbd,0x13,0x8, 0xb5,0xb, 0x80,0xa, 0x11,0xa, 0x59, +0x2d,0x51,0x1a,0x18,0xbd,0x15,0x18,0x2, 0xe1,0x3f,0x7f,0x17,0x22,0x90,0x14,0x28, +0xe4,0x93,0xbc,0xba,0x22,0x2, 0x5e,0x37,0x7e,0x73,0x3e,0x53,0xbc,0x7e,0x22,0x7e, +0x73,0x40,0x3, 0x2e,0x70,0xff,0x22,0x7e,0x73,0x3f,0xde,0xbe,0x70,0x0, 0x22,0x7e, +0x24,0x0, 0xff,0xb, 0x1a,0xd0,0x22,0xca,0x79,0x7c,0xfb,0x7f,0x51,0x7f,0x40,0x74, +0x9, 0xac,0xbf,0x9, 0xb5,0x3e,0xe8,0xf5,0x37,0x74,0x9, 0xac,0xbf,0x9, 0xb5,0x3e, +0xe9,0xc4,0x54,0xf0,0xf5,0x38,0x74,0x9, 0xac,0xbf,0x9, 0xe5,0x3e,0xe7,0x7e,0x73, +0x3f,0xe9,0xbc,0x7e,0x28,0x58,0x7e,0xb3,0x3f,0xe4,0x70,0x28,0x75,0x39,0xf, 0x7e, +0x8, 0x0, 0x37,0xa, 0x3e,0x2e,0x34,0x4b,0xd, 0x6d,0x22,0x74,0x1, 0x12,0x60,0xa8, +0x75,0x39,0x20,0x7e,0x8, 0x0, 0x38,0xa, 0x3e,0x2e,0x34,0x4b,0x17,0x74,0x10,0x12, +0x60,0xa8,0x80,0xe, 0xa, 0x3e,0x9, 0xb3,0x4b,0xd, 0xf5,0x37,0x9, 0xb3,0x4b,0x17, +0xf5,0x38,0x74,0x7, 0xac,0xbe,0x9, 0xb5,0x3f,0x97,0xb4,0x1, 0x11,0xe4,0xa, 0x3e, +0x19,0xb3,0x4b,0xd, 0x19,0xb3,0x4b,0x17,0x75,0x37,0x0, 0x75,0x38,0x0, 0x7e,0xb3, +0x3f,0xfd,0xb4,0xff,0x16,0x85,0x36,0x37,0x75,0x37,0x0, 0x74,0x9, 0xac,0xbf,0x9, +0xb5,0x3e,0xe7,0xbe,0xb0,0xff,0x68,0x3, 0x75,0x37,0x1, 0xe5,0x37,0x7a,0x4b,0xb0, +0xe5,0x38,0x7a,0x5b,0xb0,0xda,0x79,0x22,0x7c,0x9b,0x7e,0x1b,0xa0,0x4c,0xaa,0x78, +0x7, 0x7e,0xb, 0xb0,0x7a,0x1b,0xb0,0x22,0xa, 0xda,0x7e,0xb, 0x80,0xa, 0xe8,0x7d, +0xfe,0x9d,0xfd,0xbe,0xf4,0x0, 0x0, 0x8, 0x4, 0x9d,0xed,0x80,0x4, 0x6d,0xee,0x9d, +0xef,0xe5,0x39,0xa, 0xfb,0xbd,0xef,0x8, 0xf, 0xbc,0x8a,0x7c,0xba,0x28,0x4, 0x2c, +0xb9,0x80,0x2, 0x9c,0xb9,0x7a,0x1b,0xb0,0x7e,0x1b,0x70,0x7a,0xb, 0x70,0x22,0xca, +0x3b,0x75,0x29,0x0, 0x75,0x2a,0x0, 0x75,0x2b,0x0, 0x75,0x2c,0x0, 0x75,0x2e,0x0, +0x75,0x2f,0x3, 0x7e,0x38,0x4b,0x21,0x7e,0x18,0x3f,0x97,0x7a,0x1d,0x32,0xe4,0x39, +0xb3,0x0, 0x1, 0x7e,0xb3,0x3f,0xe6,0x70,0xe, 0x7e,0xb3,0x3f,0xe2,0x70,0x8, 0x7e, +0xb3,0x3f,0xe3,0x70,0x2, 0x41,0x85,0x30,0x2b,0x6, 0x7e,0x38,0x4b,0x5f,0x80,0x4, +0x7e,0x38,0x4b,0x21,0x7f,0x3, 0x12,0x56,0xe8,0x75,0x27,0x0, 0x41,0x3e,0x7e,0xa1, +0x27,0x74,0x9, 0xa4,0x49,0xc5,0x3e,0xe3,0x49,0x45,0x3e,0xe5,0x7a,0x45,0x30,0x9, +0xb5,0x3e,0xe7,0xf5,0x2d,0x90,0x13,0x7f,0xe4,0x93,0xbe,0xb1,0x2d,0x38,0x2, 0x41, +0x3c,0x7e,0xa1,0x2d,0x5e,0xa0,0xf, 0x74,0x7, 0xa4,0x7e,0x1d,0x32,0x2d,0x35,0x7e, +0x1b,0xb0,0xf5,0x2f,0xbe,0xb0,0x3, 0x78,0x2, 0x41,0x3c,0xe5,0x2f,0xb4,0x1, 0x30, +0x75,0x28,0x0, 0x80,0x21,0x7e,0x71,0x28,0x74,0x9, 0xac,0x7b,0x9, 0xb3,0x4a,0xb7, +0x54,0xf, 0xbe,0xb1,0x2d,0x78,0xd, 0x49,0xc3,0x4a,0xb3,0x49,0xd3,0x4a,0xb5,0x7a, +0xd5,0x30,0x80,0xc, 0x5, 0x28,0x90,0x13,0x7f,0xe4,0x93,0xbe,0xb1,0x28,0x38,0xd5, +0x85,0x29,0x36,0x7e,0x8, 0x0, 0x2b,0x7e,0x18,0x0, 0x2c,0xe5,0x27,0x12,0x5f,0xf7, +0x5e,0xc4,0xf, 0xff,0x7e,0xd5,0x30,0x5e,0xd4,0xf, 0xff,0x7a,0xd5,0x30,0x7e,0x91, +0x27,0x74,0x9, 0xac,0x9b,0x9, 0x74,0x3e,0xe7,0xa, 0x57,0xc4,0x54,0xf0,0x7c,0xab, +0xe4,0x7d,0xd5,0x2e,0xd5,0x30,0x7a,0xd5,0x30,0xbe,0x70,0xff,0x68,0x1a,0xe5,0x2f, +0xbe,0xb0,0x1, 0x68,0x2, 0x5, 0x29,0x5, 0x2e,0xe5,0x2f,0xa, 0x5b,0x3, 0x3, 0x54, +0xc0,0x7c,0xab,0xe4,0x2d,0xc5,0x80,0x4, 0x2e,0xc4,0xc0,0x0, 0x7e,0x71,0x2a,0x74, +0x6, 0xac,0x7b,0x7f,0x3, 0x2d,0x13,0x79,0xc0,0x0, 0x2, 0x7e,0x25,0x30,0x7f,0x3, +0x2d,0x13,0x79,0x20,0x0, 0x4, 0xe5,0x2b,0x7f,0x3, 0x2d,0x13,0x39,0xb0,0x0, 0x6, +0xe5,0x2c,0x2d,0x37,0x7d,0x26,0x39,0xb1,0x0, 0x7, 0x5, 0x2a,0x5, 0x27,0x7e,0x73, +0x3f,0xe9,0xbe,0x71,0x27,0x28,0x2, 0x21,0x3e,0xe5,0x29,0x39,0xb3,0x0, 0x1, 0x7e, +0x73,0x3f,0xdf,0x7a,0x3b,0x70,0xe5,0x2e,0xbe,0xb0,0x0, 0x38,0x6, 0x7e,0xb3,0x3f, +0xe3,0x60,0x7, 0xb2,0x2b,0xc2,0x86,0x12,0x67,0xbe,0x7e,0xb3,0x3f,0xe2,0x60,0x6, +0x7e,0xd, 0x32,0x12,0x8c,0x6d,0xe4,0x7a,0xb3,0x3f,0xe6,0x7a,0xb3,0x3f,0xe2,0x7a, +0xb3,0x3f,0xe3,0x80,0x2, 0xd2,0x86,0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e,0xe3, +0x7e,0x8, 0x4a,0xb3,0x12,0x16,0x35,0x1b,0xfd,0xe5,0x2e,0x70,0xc, 0x12,0x34,0xda, +0x7e,0x8, 0x4a,0xb3,0x74,0xff,0x12,0x16,0x5a,0xda,0x3b,0x22,0x90,0x13,0x7f,0xe4, +0x93,0x7c,0xab,0x74,0x9, 0xa4,0x22,0xca,0x79,0x7e,0xf3,0x3f,0xdd,0x7e,0xe3,0x3f, +0xde,0x7c,0xbf,0x7c,0x7e,0x12,0x3c,0x52,0x7c,0xbf,0x12,0x63,0x4e,0x4c,0xee,0x78, +0x17,0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e,0x89,0x7e,0x8, 0x3f,0x3d,0x12,0x16, +0x35,0x1b,0xfd,0x12,0x62,0xfe,0x80,0xe, 0x7e,0xb3,0x3f,0xe4,0x70,0x8, 0x12,0x62, +0xfe,0x7c,0xbf,0x12,0x64,0xa0,0x7c,0xbf,0x12,0x92,0x5c,0xda,0x79,0x22,0x7e,0xa3, +0x3f,0xdd,0x6c,0x77,0x80,0x43,0x7e,0x90,0x9, 0xac,0x97,0x9, 0x64,0x3f,0x41,0x7e, +0x50,0x7, 0xac,0x56,0x9, 0xb2,0x3f,0x97,0x70,0x2d,0x7e,0x30,0x1, 0x7e,0x50,0x9, +0xac,0x56,0x19,0x32,0x49,0x72,0x49,0x14,0x3e,0x89,0x59,0x12,0x49,0x73,0x49,0x14, +0x3e,0x8b,0x59,0x12,0x49,0x75,0xe4,0x19,0xb2,0x49,0x77,0x19,0xb2,0x49,0x6f,0x19, +0xb2,0x49,0x70,0x19,0xb2,0x49,0x71,0xb, 0x70,0xbc,0xa7,0x38,0xb9,0x22,0xca,0x79, +0x7c,0xeb,0x90,0x13,0x7f,0xe4,0x93,0x7c,0xfb,0x7e,0x70,0x9, 0xac,0x7f,0x7e,0x8, +0x44,0x87,0x74,0xff,0x12,0x16,0x5a,0xe4,0x6c,0x77,0x7c,0x6e,0x12,0x63,0xd0,0x7c, +0x7e,0x7c,0x6f,0x12,0x63,0xd0,0x7c,0x1b,0x6c,0x0, 0x80,0x3a,0x6c,0x99,0x80,0x17, +0x74,0x9, 0xac,0xb9,0x9, 0xa5,0x44,0x8b,0x7e,0x30,0x9, 0xac,0x30,0x9, 0x81,0x3e, +0x8d,0xbc,0x8a,0x68,0x6, 0xb, 0x90,0xbc,0x19,0x38,0xe5,0xbc,0x19,0x78,0x15,0x7e, +0x70,0x9, 0xac,0x70,0x12,0x67,0xb6,0xac,0x31,0x2e,0x14,0x44,0x87,0x74,0x9, 0x12, +0x15,0x72,0xb, 0x10,0xb, 0x0, 0xbc,0xf0,0x38,0xc2,0x74,0x9, 0xac,0xbf,0xca,0x59, +0x7e,0x18,0x44,0x87,0x7e,0x8, 0x3f,0x3d,0x12,0x16,0x35,0x1b,0xfd,0xda,0x79,0x22, +0x7e,0x8, 0x44,0x87,0xca,0x69,0xca,0xf8,0x7f,0x70,0x7c,0x86,0x7c,0xf7,0x7c,0xab, +0x6c,0x99,0x81,0x92,0x7c,0x3f,0x81,0x8a,0x7e,0x10,0x9, 0xac,0x19,0x9, 0x20,0x3f, +0x41,0x7e,0x10,0x9, 0xac,0x13,0x9, 0xb0,0x3e,0x8d,0xbc,0xb2,0x68,0x2, 0x81,0x88, +0xbe,0x20,0xff,0x78,0x2, 0x81,0x88,0x7e,0xd0,0x7, 0xac,0xd2,0x9, 0xb6,0x3f,0x97, +0x70,0xa, 0x7d,0x30,0x2e,0x34,0x3e,0x89,0x6d,0x22,0x80,0xb, 0x7e,0x70,0x9, 0xac, +0x79,0x2e,0x34,0x3f,0x3d,0x6d,0x22,0x29,0x11,0x0, 0x4, 0x7e,0xd0,0x9, 0xac,0xda, +0x7f,0x67,0x2d,0xd6,0x39,0x16,0x0, 0x4, 0xb, 0x1a,0x0, 0x7e,0xd0,0x9, 0xac,0xda, +0x7f,0x67,0x2d,0xd6,0x1b,0x6a,0x0, 0x69,0x1, 0x0, 0x2, 0x7e,0xd0,0x9, 0xac,0xda, +0x7f,0x67,0x2d,0xd6,0x79,0x6, 0x0, 0x2, 0x7e,0x10,0x9, 0xac,0x13,0x9, 0x10,0x3e, +0x8e,0x7e,0xd0,0x9, 0xac,0xda,0x7f,0x67,0x2d,0xd6,0x39,0x16,0x0, 0x5, 0x7e,0x10, +0x9, 0xac,0x13,0x9, 0x10,0x3e,0x8f,0x7e,0xd0,0x9, 0xac,0xda,0x7f,0x67,0x2d,0xd6, +0x39,0x16,0x0, 0x6, 0xb, 0xa0,0x80,0x8, 0xb, 0x30,0xbc,0x83,0x28,0x2, 0x61,0xe8, +0xb, 0x90,0x12,0x67,0xae,0x28,0x2, 0x61,0xe4,0x7c,0xba,0xda,0xf8,0xda,0x69,0x22, +0xca,0x3b,0x7c,0xfb,0x6c,0xee,0xa1,0x42,0x6c,0xdd,0x80,0x16,0x74,0x9, 0xac,0xbd, +0x9, 0x65,0x3f,0x41,0x74,0x9, 0xac,0xbe,0x9, 0x75,0x3e,0x8d,0xbc,0x67,0x68,0xb, +0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbd,0x38,0xe1,0x90,0x13,0x7f,0xe4,0x93, +0xbc,0xbd,0x28,0x74,0x7e,0x50,0x9, 0xac,0x5d,0x9, 0xc2,0x3f,0x41,0x49,0x42,0x3f, +0x3f,0x74,0x9, 0xac,0xbe,0x49,0xa5,0x3e,0x8b,0x7d,0x3a,0x9d,0x34,0xbe,0x34,0x0, +0x0, 0x8, 0x4, 0x9d,0xa4,0x80,0x4, 0x6d,0xaa,0x9d,0xa3,0x49,0x42,0x3f,0x3d,0x49, +0xb5,0x3e,0x89,0x7d,0x3b,0x9d,0x34,0xbe,0x34,0x0, 0x0, 0x8, 0x4, 0x9d,0xb4,0x80, +0x4, 0x6d,0xbb,0x9d,0xb3,0x2d,0xba,0x74,0x7, 0xac,0xbc,0x9, 0xb5,0x3f,0x97,0xb4, +0x1, 0xe, 0x6d,0xaa,0x74,0x2, 0xac,0xbc,0x59,0xa5,0x49,0xd3,0x59,0xa5,0x49,0xeb, +0x7d,0x3b,0x7c,0xbd,0x7c,0x5e,0x7c,0x4c,0x12,0x66,0x9e,0x7c,0xbd,0x12,0x65,0x4b, +0xb, 0xe0,0xbc,0xfe,0x28,0x2, 0x81,0xa8,0xda,0x3b,0x22,0x2, 0x65,0x4e,0xca,0x3b, +0x7c,0xd4,0x7c,0xe5,0x7c,0xfb,0x7d,0xf3,0x7e,0x17,0x3f,0xfb,0xbd,0x13,0x38,0x6, +0x7e,0xd4,0x1, 0x0, 0x80,0x17,0x6d,0x22,0x7c,0x56,0x7c,0x67,0x6c,0x77,0x12,0x14, +0xeb,0x7d,0xd3,0xbe,0xd4,0x0, 0x10,0x50,0x4, 0x7e,0xd4,0x0, 0x10,0x74,0x2, 0xac, +0xbd,0x49,0x45,0x49,0xeb,0xbd,0x4f,0x28,0x6, 0x49,0xd5,0x49,0xd3,0x80,0x4, 0x59, +0xd5,0x49,0xd3,0x59,0xf5,0x49,0xeb,0xbe,0xd4,0x1, 0x0, 0x28,0x4, 0x7e,0xd4,0x1, +0x0, 0x7e,0xb3,0x40,0x2, 0x60,0xb, 0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x2, 0x40,0x2, +0x1e,0xd4,0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x5, 0x28,0x2, 0x1e,0xd4,0xbe,0xd4,0x0, +0x20,0x50,0x11,0x7e,0x70,0x9, 0xac,0x7d,0x9, 0xb3,0x49,0x77,0xb4,0x1, 0x5, 0xe4, +0x19,0xb3,0x49,0x77,0xbe,0xd4,0x0, 0x40,0x28,0xc, 0x7e,0xa0,0x1, 0x7e,0x70,0x9, +0xac,0x7d,0x19,0xa3,0x49,0x77,0x7c,0xbe,0x7c,0x7d,0x12,0x92,0xb3,0x7d,0x13,0x7e, +0xb3,0x40,0x2, 0x60,0x2, 0x1e,0xd4,0x7e,0x70,0x9, 0xac,0x7f,0x49,0x3, 0x3f,0x3d, +0x7e,0xd0,0x9, 0xac,0xde,0x49,0x26,0x3e,0x89,0x7d,0xe2,0x9d,0xe0,0xbe,0xe4,0x0, +0x0, 0x8, 0x6, 0x7d,0xf2,0x9d,0xf0,0x80,0x4, 0x6d,0xff,0x9d,0xfe,0x12,0x66,0x8f, +0xbd,0x20,0x28,0xf, 0x7d,0xe3,0x2e,0xe4,0x3f,0x3d,0x7d,0xc0,0x2d,0xcf,0x1b,0xe8, +0xc0,0x80,0xf, 0x74,0x9, 0xac,0xbf,0x7d,0xe5,0x2e,0xe4,0x3f,0x3d,0x9d,0xf, 0x1b, +0xe8,0x0, 0x7e,0x50,0x9, 0xac,0x5f,0x49,0x32,0x3f,0x3f,0x7e,0xd0,0x9, 0xac,0xde, +0x49,0xe6,0x3e,0x8b,0x7d,0xe, 0x9d,0x3, 0xbe,0x4, 0x0, 0x0, 0x8, 0x6, 0x7d,0xfe, +0x9d,0xf3,0x80,0x4, 0x6d,0xff,0x9d,0xf0,0x12,0x66,0x8f,0xbd,0xe3,0x28,0xf, 0x7d, +0xe2,0x2e,0xe4,0x3f,0x3f,0x7d,0x23,0x2d,0x2f,0x1b,0xe8,0x20,0x80,0xe, 0x7e,0x50, +0x9, 0xac,0x5f,0x2e,0x24,0x3f,0x3f,0x9d,0x3f,0x1b,0x28,0x30,0xda,0x3b,0x22,0x7d, +0x5d,0xad,0x5f,0x7c,0xba,0x7c,0xa9,0xa, 0x48,0x7d,0xf5,0x5d,0xf1,0x22,0xca,0x3b, +0x7c,0xab,0x7d,0x3, 0x7e,0x20,0x10,0x7d,0x30,0x7e,0x90,0x9, 0xac,0x95,0x9, 0x34, +0x3e,0x8f,0xbe,0x30,0x10,0x28,0x2, 0x7c,0x23,0xbe,0x20,0x20,0x28,0x3, 0x7e,0x20, +0x20,0x49,0xe4,0x3e,0x89,0xbe,0xe4,0x6, 0x50,0x40,0x20,0x7e,0x33,0x40,0x11,0x12, +0x67,0x9a,0xbd,0xef,0x38,0x15,0x49,0xe4,0x3e,0x8b,0xbe,0xe4,0x6, 0x50,0x40,0xb, +0x7e,0x33,0x40,0x12,0x12,0x67,0x9a,0xbd,0xef,0x28,0x3, 0x7e,0x20,0x8, 0x7e,0xf0, +0x10,0xac,0xf2,0xbd,0x70,0x40,0x5d,0x7e,0xf0,0x9, 0xac,0xf4,0x9, 0xb7,0x49,0x77, +0x70,0x52,0x7e,0xd0,0x8, 0xac,0xd2,0xbd,0x60,0x50,0x3c,0x9, 0xb7,0x49,0x70,0x70, +0x1f,0x9, 0xb7,0x49,0x71,0xbe,0xb0,0x0, 0x28,0xc, 0x7d,0x37,0x2e,0x34,0x49,0x71, +0x14,0x7a,0x39,0xb0,0x80,0x6, 0x74,0x1, 0x19,0xb7,0x49,0x70,0x6d,0x33,0x80,0x34, +0x9, 0xb7,0x49,0x71,0xbe,0xb0,0x14,0x50,0x2b,0x7d,0x37,0x2e,0x34,0x49,0x71,0x4, +0x7a,0x39,0xb0,0x6d,0x33,0x80,0x1d,0xe4,0x19,0xb7,0x49,0x71,0x19,0xb7,0x49,0x70, +0x6d,0x33,0x80,0x10,0x6c,0x33,0x7e,0xf0,0x9, 0xac,0xf4,0x19,0x37,0x49,0x71,0xe4, +0x19,0xb7,0x49,0x70,0x7e,0x30,0x8, 0xac,0x23,0xbd,0x10,0x40,0x2a,0x7e,0x70,0x9, +0xac,0x7a,0x49,0x33,0x3f,0x3d,0x59,0x34,0x3e,0x89,0x74,0x9, 0xa4,0x49,0x35,0x3f, +0x3f,0x74,0x9, 0xac,0xb5,0x59,0x35,0x3e,0x8b,0x7e,0xa0,0x1, 0x7e,0x70,0x9, 0xac, +0x74,0x19,0xa3,0x49,0x6f,0x6d,0x33,0xda,0x3b,0x22,0x7e,0xf0,0x40,0xac,0xf3,0x7d, +0xf7,0x9e,0xf4,0x0, 0x65,0x3e,0xf4,0x3e,0xf4,0x3e,0xf4,0x3e,0xf4,0x22,0x90,0x13, +0x7f,0xe4,0x93,0xbc,0xb9,0x22,0x2e,0x34,0x3e,0x89,0x7e,0x30,0x9, 0x22,0x7e,0xb3, +0x4b,0xa1,0x4, 0x7a,0xb3,0x4b,0xa1,0x7e,0x73,0x4b,0xa1,0x7a,0x73,0x4d,0x88,0x22, +0xe4,0x7a,0xb3,0x4d,0xeb,0x90,0xe, 0x73,0x93,0x7a,0xb3,0x4d,0xed,0x90,0xe, 0x74, +0xe4,0x93,0x7a,0xb3,0x4d,0xee,0x90,0x13,0x7f,0xe4,0x93,0x7a,0xb3,0x4d,0xf0,0xe4, +0x7a,0xb3,0x4d,0xf1,0x74,0x1, 0x7a,0xb3,0x4d,0xf6,0x12,0x3d,0xcb,0xe4,0x7a,0xb3, +0x4d,0xf9,0x7e,0x73,0x4c,0x71,0x7a,0x73,0x4e,0xb, 0x7e,0x73,0x4c,0x72,0x7a,0x73, +0x4e,0xc, 0x7e,0x73,0x4c,0x73,0x7a,0x73,0x4e,0xd, 0x7e,0x73,0x4c,0x40,0x7a,0x73, +0x4e,0x14,0x7e,0x73,0x4c,0x41,0x7a,0x73,0x4e,0x15,0x90,0xe, 0x77,0x93,0x7a,0xb3, +0x4e,0x9, 0x90,0xe, 0x78,0xe4,0x93,0x7a,0xb3,0x4e,0xa, 0x74,0x1, 0x7a,0xb3,0x4e, +0x1b,0x7e,0x34,0x14,0x60,0x12,0x1d,0xf2,0x7a,0x37,0x4e,0x45,0x74,0x2, 0x7a,0xb3, +0x4d,0xf4,0x74,0x17,0x7a,0xb3,0x4e,0x18,0x22,0x7e,0x18,0x15,0xa0,0x7a,0x1f,0x22, +0xdc,0x7e,0x18,0x4, 0x0, 0x7a,0x1f,0x22,0xe0,0x7e,0xf, 0x22,0xdc,0x12,0x68,0x80, +0x7e,0xf, 0x22,0xe0,0x7e,0x34,0x4, 0x68,0x12,0x16,0x5a,0x7a,0xb3,0x24,0x26,0x22, +0x7e,0x34,0x4, 0x68,0xe4,0x2, 0x16,0x5a,0xca,0x3b,0xf5,0x2f,0x7f,0x31,0x7a,0xd, +0x2b,0x7e,0x18,0xc, 0xd0,0x7a,0x1d,0x32,0x12,0x1c,0x24,0x7e,0xd, 0x2b,0x12,0x68, +0x80,0x30,0x1, 0xc, 0x7e,0x18,0x11,0x38,0x7a,0x1d,0x36,0x7f,0x3, 0x12,0x68,0x80, +0xe4,0x68,0x3, 0x12,0x1c,0x24,0xd2,0x2, 0x12,0x45,0xf2,0x30,0x1, 0x29,0x6d,0x33, +0x80,0x1d,0x12,0x69,0x23,0x7e,0xd, 0x36,0x2d,0x12,0xb, 0xa, 0x50,0x7d,0x23,0x3e, +0x24,0x7f,0x3, 0x2d,0x12,0xb, 0xa, 0x20,0x2d,0x25,0x1b,0xa, 0x20,0xb, 0x34,0x7a, +0x35,0x30,0x12,0x69,0x2b,0x38,0xdb,0x6d,0x33,0x80,0x1f,0x12,0x69,0x23,0x7e,0xd, +0x32,0x2d,0x12,0xb, 0xa, 0x20,0x3e,0x34,0x7e,0xd, 0x2b,0x2d,0x13,0xb, 0xa, 0x30, +0x2d,0x32,0x1b,0xa, 0x30,0x7e,0x35,0x30,0xb, 0x34,0x7a,0x35,0x30,0x12,0x69,0x2b, +0x38,0xd9,0x7e,0xd, 0x2b,0x12,0x4e,0xac,0x30,0x1, 0x5, 0x7f,0x3, 0x12,0x4e,0xac, +0xda,0x3b,0x22,0x7e,0x35,0x30,0x7d,0x23,0x3e,0x24,0x22,0x7e,0x37,0x44,0x81,0xb, +0x36,0xbe,0x35,0x30,0x22,0xca,0xf8,0xc2,0x0, 0x7e,0xf3,0x4f,0x55,0x20,0xe, 0x6, +0x20,0xf, 0x3, 0x30,0x10,0x3, 0xc3,0x80,0x71,0x7e,0x24,0x0, 0x1, 0x7c,0xbf,0x60, +0x5, 0x3e,0x24,0x14,0x78,0xfb,0x7e,0x73,0x44,0x80,0x6c,0x66,0x5c,0x75,0x4d,0x33, +0x68,0x57,0x7c,0xbf,0x12,0x6b,0x73,0x50,0x2, 0xd2,0x0, 0xd2,0x2, 0x12,0x45,0xf2, +0xe4,0x7c,0x7f,0x12,0x71,0xda,0xa2,0x0, 0x92,0x1, 0x7e,0xf, 0x22,0xdc,0x7e,0x18, +0x1a,0x8, 0x7c,0xbf,0x12,0x68,0x88,0x20,0xe, 0x6, 0x20,0xf, 0x3, 0x30,0x10,0x3, +0xc3,0x80,0x27,0x12,0x1c,0x24,0x12,0x6a,0x82,0x60,0x5, 0x3e,0x34,0x14,0x78,0xfb, +0x6e,0x70,0xff,0x5e,0x73,0x44,0x80,0x7a,0x73,0x44,0x80,0x12,0x4f,0x55,0x12,0x69, +0xbd,0x7c,0xbf,0x12,0x6a,0xf9,0xd3,0x80,0x1, 0xd3,0xda,0xf8,0x22,0x7e,0x73,0x4d, +0x83,0x7e,0xb3,0x4d,0x9e,0x70,0x3a,0xe5,0x13,0x70,0x1d,0x7e,0x63,0x4d,0x81,0xbe, +0x60,0x14,0x28,0x5, 0x7e,0x60,0x14,0x80,0x7, 0xa5,0xbe,0x0, 0x3, 0x7e,0x60,0x1, +0xa, 0x26,0x7e,0x34,0x0, 0x64,0x80,0x74,0xe5,0x13,0xb4,0x3, 0x2, 0x80,0x44,0x12, +0x6a,0x7b,0xb4,0x1, 0x6, 0x7e,0x34,0x1, 0xf4,0x80,0x61,0x7e,0x34,0x3, 0xe8,0x80, +0x5b,0xe5,0x13,0x70,0xe, 0x7e,0x63,0x4d,0x82,0xbe,0x60,0x7f,0x28,0x53,0x7e,0x60, +0x7f,0x80,0x4e,0x7e,0x63,0x4f,0x99,0xbe,0x60,0x3b,0x40,0x12,0x12,0x6a,0x7b,0xb4, +0x1, 0x6, 0x7e,0x34,0x1, 0xf4,0x80,0x26,0x7e,0x34,0x3, 0xe8,0x80,0x20,0xe5,0x13, +0xb4,0x3, 0x8, 0x7e,0x73,0x4d,0xb8,0xa, 0x37,0x80,0x15,0x30,0x1b,0x18,0x12,0x6a, +0x7b,0xb4,0x1, 0x6, 0x7e,0x34,0x1, 0xf4,0x80,0x4, 0x7e,0x34,0x3, 0xe8,0x8d,0x32, +0x1b,0x34,0x7c,0x67,0x80,0xb, 0xa, 0x27,0x7e,0x34,0x3, 0xe8,0x12,0x14,0x9f,0x7c, +0x67,0x7e,0x73,0x4d,0xa5,0xac,0x67,0x7e,0x24,0x0, 0x18,0x12,0x14,0x9f,0x7a,0x73, +0x4f,0x48,0xc2,0x16,0x6d,0x33,0x7a,0x37,0x4f,0x44,0x22,0x7e,0xb3,0x4f,0x4d,0xa, +0x27,0x22,0x7e,0x34,0x0, 0x1, 0x7c,0xbf,0x22,0xca,0xf8,0x7e,0xf3,0x4f,0x55,0x20, +0xe, 0x6, 0x20,0xf, 0x3, 0x30,0x10,0x3, 0xc3,0x80,0x5b,0x12,0x6a,0x82,0x60,0x5, +0x3e,0x34,0x14,0x78,0xfb,0x7e,0x53,0x44,0x7f,0x6c,0x44,0x5c,0x57,0x4d,0x22,0x68, +0x44,0x7e,0xb3,0x4e,0x19,0x70,0x8, 0x4e,0x73,0x44,0x80,0x7a,0x73,0x44,0x80,0xd2, +0x2, 0x12,0x45,0xf2,0x7c,0xbf,0x12,0x4b,0x75,0x40,0x3, 0xc3,0x80,0x28,0x20,0xe, +0x6, 0x20,0xf, 0x3, 0x30,0x10,0x3, 0xc3,0x80,0x1c,0x12,0x6a,0x82,0x60,0x5, 0x3e, +0x34,0x14,0x78,0xfb,0x6e,0x70,0xff,0x5e,0x73,0x44,0x7f,0x7a,0x73,0x44,0x7f,0x12, +0x69,0xbd,0xd3,0x80,0x1, 0xd3,0xda,0xf8,0x22,0xc2,0x1, 0x12,0x6b,0x73,0x50,0x2, +0xd2,0x1, 0x7e,0x37,0x44,0x81,0x6c,0xaa,0x90,0xe, 0x77,0xe4,0x93,0x20,0xe0,0x4, +0x4c,0xaa,0x68,0x57,0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x5, 0xbe,0xa0,0x1, 0x68,0x4b, +0x90,0xe, 0x78,0xe4,0x93,0x20,0xe0,0x5, 0xbe,0xa0,0x2, 0x68,0x3e,0x1e,0xb0,0x1e, +0xb0,0x20,0xe0,0x5, 0xbe,0xa0,0x3, 0x68,0x32,0x30,0x1, 0x1c,0xa, 0x2a,0x2d,0x23, +0x3e,0x24,0x49,0x12,0x15,0xa0,0xbe,0x14,0xb, 0xb8,0x40,0x1c,0x49,0x22,0x1a,0x8, +0xbe,0x24,0xb, 0xb8,0x50,0x15,0x80,0x10,0xa, 0x2a,0x2d,0x23,0x3e,0x24,0x49,0x22, +0x15,0xa0,0xbe,0x24,0xb, 0xb8,0x50,0x3, 0x2, 0x6b,0x8f,0xb, 0xa0,0xbe,0xa0,0x4, +0x40,0x96,0x22,0x7c,0xab,0xd2,0x2, 0x7e,0xb3,0x4f,0x4d,0x70,0x4, 0xc2,0x2, 0x80, +0xb, 0x4c,0xaa,0x68,0x5, 0xbe,0xa0,0x3, 0x78,0x2, 0xc2,0x2, 0xa2,0x2, 0x22,0x74, +0x1f,0x7a,0xb3,0x44,0x7f,0x22,0x7e,0x37,0x44,0x81,0x6c,0xaa,0x90,0xe, 0x77,0xe4, +0x93,0x20,0xe0,0x4, 0x4c,0xaa,0x68,0x25,0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x5, 0xbe, +0xa0,0x1, 0x68,0x19,0x90,0xe, 0x78,0xe4,0x93,0x20,0xe0,0x5, 0xbe,0xa0,0x2, 0x68, +0xc, 0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x9, 0xbe,0xa0,0x3, 0x78,0x4, 0xb, 0x34,0x80, +0x22,0x7d,0x23,0x3e,0x24,0x49,0x42,0x8, 0x68,0x12,0x6b,0xfb,0x2d,0x24,0x1b,0xa, +0x20,0x7d,0x23,0x3e,0x24,0x12,0x6b,0xfb,0xbe,0x24,0xf, 0xa0,0x50,0x3, 0x12,0x6b, +0x8f,0xb, 0x34,0xb, 0xa0,0xbe,0xa0,0x4, 0x40,0xa2,0x22,0x7e,0xf, 0x22,0xdc,0x2d, +0x12,0xb, 0xa, 0x20,0x22,0xca,0xf8,0x12,0x6e,0x85,0x12,0x6c,0x8a,0x12,0x6c,0x78, +0x40,0x5, 0xe4,0x7a,0xb3,0x3e,0x82,0x7e,0xb3,0x3e,0x82,0x60,0xb, 0xe4,0x7a,0xb3, +0x4f,0x84,0x74,0x1f,0x7a,0xb3,0x44,0x80,0x12,0x6c,0x78,0x40,0x6, 0x12,0x76,0xad, +0x12,0xac,0x2a,0x7e,0xb3,0x3e,0x85,0x60,0x6, 0x74,0x2, 0x7a,0xb3,0x4f,0x8b,0x7e, +0xf3,0x4f,0x8b,0xbe,0xf0,0x0, 0x28,0x23,0xe5,0x13,0xb4,0x1, 0x14,0x7e,0xb3,0x4d, +0x9e,0xb4,0x1, 0xd, 0x7e,0xb3,0x4f,0x99,0xbe,0xb0,0x3c,0x68,0x4, 0x70,0xc, 0x80, +0x0, 0x7c,0xbf,0x14,0x7a,0xb3,0x4f,0x8b,0x12,0x6b,0x96,0x7e,0xb3,0x3e,0x88,0x60, +0x4, 0xe4,0x12,0x73,0xab,0xda,0xf8,0x22,0xe5,0x13,0x70,0xc, 0x7e,0x73,0x4f,0x54, +0xbe,0x73,0x4f,0x5a,0x40,0x2, 0xc3,0x22,0xd3,0x22,0x12,0x93,0xb2,0x12,0x94,0x82, +0x12,0x6d,0xc9,0x2, 0x6c,0x96,0x7e,0xb3,0x3e,0x82,0xb4,0x1, 0x18,0x12,0x6d,0xbf, +0xbe,0x73,0x4f,0x84,0x28,0xc, 0xe4,0x7a,0xb3,0x3e,0x82,0x7e,0xb3,0x4f,0x84,0x4, +0x80,0x4, 0xe4,0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x84,0x7e,0xb3,0x3e,0x82,0x70,0x53, +0x12,0x6d,0xb8,0x78,0x15,0x7e,0xb3,0x3e,0x83,0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x86, +0x4, 0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x86,0x80,0x18,0xbe,0xa0,0x1, 0x78,0x13,0x7e, +0xb3,0x3e,0x84,0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x87,0x4, 0x80,0x1, 0xe4,0x7a,0xb3, +0x4f,0x87,0x7e,0x73,0x4f,0x86,0xbe,0x70,0x3, 0x50,0x9, 0x7e,0x73,0x4f,0x87,0xbe, +0x70,0x3, 0x40,0xf, 0x74,0x1, 0x7a,0xb3,0x3e,0x82,0xe4,0x7a,0xb3,0x4f,0x86,0x7a, +0xb3,0x4f,0x87,0x7e,0xb3,0x3e,0x85,0xb4,0x1, 0x18,0x12,0x6d,0xbf,0xbe,0x73,0x4f, +0x85,0x28,0xc, 0xe4,0x7a,0xb3,0x3e,0x85,0x7e,0xb3,0x4f,0x85,0x4, 0x80,0x4, 0xe4, +0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x85,0x7e,0xb3,0x3e,0x85,0x70,0x53,0x12,0x6d,0xb8, +0x78,0x15,0x7e,0xb3,0x3e,0x86,0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x88,0x4, 0x80,0x1, +0xe4,0x7a,0xb3,0x4f,0x88,0x80,0x18,0xbe,0xa0,0x1, 0x78,0x13,0x7e,0xb3,0x3e,0x87, +0xb4,0x1, 0x7, 0x7e,0xb3,0x4f,0x89,0x4, 0x80,0x1, 0xe4,0x7a,0xb3,0x4f,0x89,0x7e, +0x73,0x4f,0x88,0xbe,0x70,0x3, 0x50,0x9, 0x7e,0x73,0x4f,0x89,0xbe,0x70,0x3, 0x40, +0xf, 0x74,0x1, 0x7a,0xb3,0x3e,0x85,0xe4,0x7a,0xb3,0x4f,0x88,0x7a,0xb3,0x4f,0x89, +0x7e,0xb3,0x3e,0x88,0xb4,0x1, 0x1a,0x7e,0x73,0x3e,0x72,0xbe,0x73,0x4f,0x8a,0x28, +0xc, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x4f,0x8a,0x4, 0x80,0x6, 0x74,0x1, 0x80, +0x2, 0x74,0x1, 0x7a,0xb3,0x4f,0x8a,0x22,0x7e,0xa3,0x24,0x27,0x4c,0xaa,0x22,0xe4, +0x7a,0xb3,0x3e,0x88,0x7e,0x73,0x3e,0x73,0x22,0x7e,0x47,0x3e,0x5d,0x7e,0x7, 0x3f, +0xef,0x7e,0x34,0x0, 0x6, 0xad,0x30,0x7e,0x14,0x0, 0x4, 0x12,0x6e,0x7d,0x8, 0x5, +0x7e,0xa0,0x4, 0x80,0x1d,0x7d,0x30,0x3e,0x34,0x12,0x6e,0x7b,0x8, 0x5, 0x7e,0xa0, +0x3, 0x80,0xf, 0x7d,0x30,0x12,0x6e,0x7b,0x8, 0x5, 0x7e,0xa0,0x2, 0x80,0x3, 0x7e, +0xa0,0x1, 0x7e,0xb3,0x3e,0x7f,0x60,0x3, 0x7e,0xa0,0x4, 0xa, 0x2a,0x7e,0x14,0x14, +0x37,0x7e,0x4, 0x0, 0xff,0xb, 0xa, 0x30,0xad,0x32,0x12,0x70,0xe6,0x7e,0xb3,0x3e, +0x53,0xbe,0xb0,0x0, 0x28,0x28,0x7e,0xb3,0x3e,0x74,0x70,0x22,0x7e,0x37,0x3e,0x70, +0xbe,0x34,0x0, 0x2, 0x48,0x9, 0x12,0x6f,0xf0,0x7a,0x37,0x3e,0x70,0x80,0xf, 0x7e, +0x63,0x3e,0x72,0x7e,0x70,0x2, 0xac,0x67,0x7c,0xb7,0x7a,0xb3,0x3e,0x72,0x7e,0xb3, +0x4d,0x9e,0xb4,0x1, 0xe, 0x7e,0x27,0x3e,0x70,0x7e,0x34,0x0, 0x5, 0xad,0x32,0x7a, +0x37,0x3e,0x70,0x7e,0xb3,0x4e,0x49,0xbe,0xb0,0x0, 0x28,0xe, 0x7e,0x34,0x0, 0x1, +0x7a,0x37,0x3e,0x70,0x74,0x1, 0x7a,0xb3,0x3e,0x72,0x22,0x3e,0x34,0x7d,0x21,0x12, +0x14,0x9f,0xbd,0x34,0x22,0x12,0x99,0x43,0x12,0x6e,0xb5,0x12,0x9c,0x5c,0x2, 0x6e, +0x91,0x7e,0x27,0x44,0x81,0x1e,0x24,0x1e,0x24,0xe4,0x7a,0xb3,0x3e,0x7f,0x7e,0x37, +0x3e,0x55,0xbd,0x32,0x38,0x8, 0x7e,0x37,0x3e,0x57,0xbd,0x32,0x28,0x6, 0x74,0x1, +0x7a,0xb3,0x3e,0x7f,0x22,0xe4,0x7a,0xb3,0x3e,0x75,0x7a,0xb3,0x3e,0x78,0x7a,0xb3, +0x3e,0x76,0x7a,0xb3,0x3e,0x77,0x7a,0xb3,0x3e,0x79,0x7a,0xb3,0x3e,0x7a,0x7e,0x73, +0x3e,0x54,0xbe,0x70,0x0, 0x28,0x35,0x12,0xac,0xe0,0x12,0x14,0x9f,0xbe,0x37,0x3e, +0x5d,0x8, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x75,0x7e,0x7, 0x3f,0xf5,0x7d,0x30,0x12, +0x6f,0xe4,0x8, 0x3, 0x12,0x6f,0xdd,0x7d,0x30,0x3e,0x34,0x3e,0x34,0x7d,0x21,0x12, +0x6f,0xe8,0x8, 0x8, 0xd2,0x2d,0x6d,0x33,0x7a,0x37,0x4d,0x75,0x7e,0x37,0x3e,0x63, +0xbe,0x34,0x1, 0xf4,0x8, 0x2d,0x30,0x23,0x2a,0x30,0x2d,0x1b,0x12,0x6f,0xdd,0x7e, +0x37,0x4d,0x75,0xb, 0x34,0x7a,0x37,0x4d,0x75,0xbe,0x34,0x0, 0x5, 0x28,0x8, 0xc2, +0x2d,0x6d,0x33,0x7a,0x37,0x4d,0x75,0x12,0x76,0xbd,0xbe,0x34,0x0, 0x64,0x28,0x3, +0x12,0x6f,0xdd,0x7e,0xa3,0x3e,0x54,0xbe,0xa0,0x0, 0x28,0x49,0x12,0xac,0xe0,0x12, +0x14,0x9f,0xbe,0x37,0x3e,0x5d,0x8, 0x1a,0x7e,0x73,0x24,0x27,0xa5,0xbf,0x0, 0x8, +0x74,0x1, 0x7a,0xb3,0x3e,0x76,0x80,0xa, 0xa5,0xbf,0x1, 0x6, 0x74,0x1, 0x7a,0xb3, +0x3e,0x77,0x7e,0x37,0x3f,0xf5,0x12,0x6f,0xe4,0x8, 0x1a,0x7e,0x73,0x24,0x27,0xa5, +0xbf,0x0, 0x8, 0x74,0x1, 0x7a,0xb3,0x3e,0x79,0x80,0xa, 0xa5,0xbf,0x1, 0x6, 0x74, +0x1, 0x7a,0xb3,0x3e,0x7a,0x7e,0xb3,0x3e,0x75,0xbe,0xb0,0x1, 0x68,0x10,0x7e,0xb3, +0x3e,0x76,0xbe,0xb0,0x1, 0x68,0x7, 0x7e,0xb3,0x3e,0x77,0xb4,0x1, 0x29,0xbe,0xa0, +0x0, 0x28,0x24,0xbe,0xa0,0x3, 0x50,0x1f,0x7e,0xb3,0x3e,0x53,0xb4,0x1, 0x18,0x90, +0x14,0x28,0xe4,0x93,0xbe,0xb3,0x3c,0xc9,0x68,0xd, 0xe4,0x7a,0xb3,0x3e,0x75,0x7a, +0xb3,0x3e,0x76,0x7a,0xb3,0x3e,0x77,0xe4,0x7a,0xb3,0x3e,0x7b,0x22,0x74,0x1, 0x7a, +0xb3,0x3e,0x78,0x22,0xad,0x31,0x7d,0x24,0x12,0x14,0x9f,0xbe,0x37,0x3e,0x63,0x22, +0x7e,0x24,0x0, 0x2, 0x2, 0x14,0x9f,0x7e,0x34,0x4, 0x71,0xca,0x39,0x7e,0x34,0xe, +0x71,0x7e,0x24,0x0, 0xff,0x7e,0x8, 0x40,0xd, 0x12,0x16,0x35,0x1b,0xfd,0x7e,0x37, +0x40,0x17,0x2e,0x37,0x40,0x15,0x7a,0x37,0x44,0x81,0x90,0xe, 0x77,0xe4,0x93,0xca, +0xb8,0x90,0xe, 0x78,0xe4,0x93,0x7c,0x7b,0xda,0xb8,0x12,0x70,0x4a,0x90,0x14,0x7, +0xe4,0x93,0x70,0x6, 0x7e,0x63,0x40,0x10,0x80,0x4, 0x7e,0x63,0x40,0xf, 0x7e,0x70, +0x40,0xac,0x67,0x1b,0x34,0x7a,0x37,0x44,0x83,0x22,0x7c,0x6b,0x7c,0x56,0x5e,0x50, +0x4, 0x1e,0x50,0xa, 0x45,0x7c,0xb6,0x54,0x1, 0xa, 0x5b,0x2d,0x54,0x7c,0xab,0x7c, +0x67,0x5e,0x60,0x4, 0x1e,0x60,0xa, 0x26,0x7c,0xb7,0x54,0x1, 0xa, 0x3b,0x2d,0x32, +0x7c,0xb7,0xa, 0x4b,0x3e,0x44,0x3e,0x44,0xa, 0x5a,0x2d,0x54,0x7c,0xab,0x7a,0xa3, +0x44,0x85,0xe4,0x7a,0xb3,0x44,0x86,0x7e,0x70,0x4, 0x7c,0xba,0x30,0xe0,0x9, 0x7e, +0xb3,0x44,0x86,0x4, 0x7a,0xb3,0x44,0x86,0x1e,0xa0,0x1b,0x70,0x78,0xec,0x22,0x7e, +0xb3,0x40,0x13,0x7e,0x73,0x40,0x14,0x12,0x70,0x4a,0x7e,0xb3,0x40,0x13,0x7e,0x73, +0x40,0x14,0x22,0x7e,0x34,0x14,0x33,0x12,0x1d,0xf2,0x7a,0x37,0x3e,0x6c,0x7e,0x34, +0x14,0x35,0x12,0x1d,0xf2,0x7a,0x37,0x3e,0x6e,0x7e,0x34,0x14,0x37,0x12,0x1d,0xf2, +0x12,0x70,0xe6,0x90,0x14,0x3a,0xe4,0x93,0x7a,0xb3,0x3e,0x73,0xe4,0x7a,0xb3,0x3e, +0x7c,0x7a,0xb3,0x3e,0x7d,0x22,0x7a,0x37,0x3e,0x70,0x90,0x14,0x39,0xe4,0x93,0x7a, +0xb3,0x3e,0x72,0x22,0xca,0xf8,0x6c,0xff,0x12,0x71,0xb, 0xb, 0xf0,0x7e,0x73,0x3, +0xda,0xbc,0x7f,0x38,0xf3,0x12,0x71,0xd2,0xda,0xf8,0x22,0xca,0xd8,0xca,0x79,0xd2, +0x0, 0x12,0x37,0xb3,0x50,0xfb,0x7e,0xe3,0x3, 0xd9,0x7a,0xe3,0x24,0x27,0x7e,0xd3, +0x3, 0xda,0xa, 0x3e,0x9, 0xb3,0x3, 0xd3,0x60,0x31,0xa, 0x3b,0x1b,0x34,0x7c,0xa7, +0x7a,0xa3,0x4e,0x16,0xb4,0x1, 0x4, 0x74,0x1, 0x80,0x1, 0xe4,0x7a,0xb3,0x24,0x26, +0xe4,0xa, 0x3e,0x19,0xb3,0x3, 0xd3,0x9, 0xf3,0x3, 0xd5,0x7c,0xbe,0x7c,0x7f,0x12, +0x71,0xda,0x7e,0xb3,0x3, 0xd9,0x4, 0x7a,0xb3,0x3, 0xd9,0x7e,0x73,0x3, 0xda,0xbe, +0x73,0x3, 0xd9,0x38,0x6, 0x12,0x1c,0x76,0x12,0xa7,0xe7,0x7e,0xb3,0x24,0x26,0xbe, +0xb0,0x1, 0x68,0x7, 0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x38,0x74,0xa, 0xac,0xbf,0x49, +0x35,0x4c,0x48,0x7e,0xf, 0x22,0xd8,0x12,0x4e,0xb6,0x7c,0xbe,0x7c,0x7f,0x12,0x77, +0x51,0x92,0x0, 0x7e,0xb3,0x4f,0x4d,0x70,0xc, 0xbe,0xe0,0x1, 0x40,0x7, 0xe4,0x7a, +0xb3,0x24,0x26,0xc2,0x0, 0x30,0x0, 0xb, 0x12,0x72,0x78,0x7a,0xe3,0x4e,0x17,0x7a, +0xf3,0x4f,0x59,0x7e,0xb3,0x4f,0x6e,0xb4,0x1, 0x3, 0x12,0x72,0xb, 0x7c,0xbd,0x14, +0xbc,0xbe,0x78,0x3, 0x12,0xb, 0xe5,0x12,0x76,0x9e,0x12,0x6c,0x78,0xda,0x79,0xda, +0xd8,0x22,0x7e,0xb3,0x4e,0x17,0x7e,0x73,0x4f,0x59,0x14,0x68,0x1d,0x4, 0x78,0x1a, +0x7e,0x8, 0xc, 0xd0,0x7a,0xf, 0x22,0xd8,0x7e,0x8, 0x15,0xa0,0x7a,0xf, 0x22,0xdc, +0xa5,0xbf,0x3, 0x16,0x7e,0x18,0x1e,0x70,0x80,0xc, 0x7e,0x18,0x11,0x38,0x7a,0x1f, +0x22,0xd8,0x7e,0x18,0x1a,0x8, 0x7a,0x1f,0x22,0xdc,0x22,0x6d,0x22,0x7d,0x32,0x7d, +0x52,0x3e,0x54,0x7e,0xf, 0x22,0xd8,0x12,0x72,0x6c,0x28,0x2, 0xb, 0x34,0xb, 0x24, +0xbe,0x24,0x0, 0x14,0x78,0xe9,0xbe,0x34,0x0, 0x5, 0x38,0x6, 0xe4,0x7a,0xb3,0x4e, +0x97,0x22,0x7e,0x24,0x0, 0x14,0x80,0xd, 0x7d,0x52,0x3e,0x54,0x12,0x72,0x6c,0x28, +0x2, 0xb, 0x34,0xb, 0x24,0x7e,0x57,0x44,0x81,0xbd,0x52,0x38,0xeb,0xbe,0x34,0x0, +0xb4,0x28,0x7, 0x7e,0xb3,0x4e,0x97,0x4, 0x80,0x1, 0xe4,0x7a,0xb3,0x4e,0x97,0x7e, +0x73,0x4e,0x97,0xbe,0x70,0x4, 0x40,0x3, 0x75,0xe9,0xff,0x22,0x2d,0x51,0x7d,0x40, +0xb, 0x2a,0x50,0xbe,0x54,0x3e,0x80,0x22,0xca,0xf8,0x7e,0xb3,0x44,0x7e,0x70,0xd, +0x7e,0xf, 0x22,0xe0,0x7e,0x1f,0x22,0xd8,0x12,0x73,0xc, 0x80,0x14,0x7e,0x1f,0x22, +0xdc,0x7a,0x1d,0x27,0x7e,0xf, 0x22,0xe0,0x7e,0x1f,0x22,0xd8,0x74,0x1, 0x12,0x73, +0x20,0x7e,0x37,0x44,0x81,0x90,0xe, 0x59,0xe4,0x93,0x70,0x13,0x6c,0xff,0x6d,0x22, +0x7d,0x53,0x12,0x72,0xf9,0x1b,0xa, 0x20,0x12,0x72,0xf1,0x78,0xf1,0x80,0x2f,0x6c, +0xff,0x7e,0xb3,0x44,0x7e,0xb4,0x1, 0x14,0x7d,0x53,0x3e,0x54,0x7e,0xf, 0x22,0xdc, +0x2d,0x15,0xb, 0xa, 0x40,0x12,0x73,0x2, 0x9d,0x24,0x80,0x7, 0x7d,0x53,0x3e,0x54, +0x12,0x73,0x2, 0x12,0x72,0xfb,0x1b,0xa, 0x20,0x12,0x72,0xf1,0x78,0xd3,0xda,0xf8, +0x22,0xb, 0x34,0xb, 0xf0,0xbe,0xf0,0x4, 0x22,0x3e,0x54,0x7e,0xf, 0x22,0xe0,0x2d, +0x15,0x22,0x7e,0xf, 0x22,0xd8,0x2d,0x15,0xb, 0xa, 0x20,0x22,0x12,0x73,0x7b,0x7a, +0x37,0x44,0x8b,0x12,0x73,0x74,0x7e,0x34,0x0, 0x20,0x12,0x73,0x50,0x2, 0x8, 0xe5, +0x7c,0xab,0x7f,0x61,0x7f,0x70,0x12,0x73,0xa2,0xe4,0x12,0x16,0x5a,0x7e,0xb3,0x40, +0x10,0x7a,0xb3,0x44,0x88,0x7e,0xb3,0x40,0xf, 0x7a,0xb3,0x44,0x87,0xe4,0x12,0x73, +0x9b,0x12,0x73,0x69,0x7a,0xa3,0x44,0x8a,0x6d,0x33,0x12,0x73,0x50,0x2, 0x8, 0xe5, +0x7a,0x37,0x44,0x91,0x7e,0x8, 0x44,0x87,0x22,0x12,0x73,0x7b,0x12,0x73,0x69,0x7e, +0x34,0x0, 0x10,0x12,0x73,0x50,0x2, 0x8, 0xe5,0x7a,0x37,0x44,0x8b,0x7e,0x1d,0x27, +0x7a,0x37,0x44,0x8d,0x7d,0x3f,0x7a,0x37,0x44,0x8f,0x22,0x7f,0x61,0x7f,0x70,0x7e, +0x8, 0x44,0x87,0x7e,0x34,0x0, 0xc, 0xe4,0x12,0x16,0x5a,0x7e,0x73,0x40,0x10,0x7a, +0x73,0x44,0x88,0x7e,0x73,0x40,0xf, 0x7a,0x73,0x44,0x87,0x7a,0xb3,0x44,0x89,0x7d, +0x3d,0x22,0x7e,0x8, 0x44,0x87,0x7e,0x34,0x0, 0xc, 0x22,0xca,0x3b,0x7c,0xcb,0x12, +0x73,0xa2,0xe4,0x12,0x16,0x5a,0x7e,0x8, 0x44,0x93,0x7e,0x34,0x0, 0x5, 0x12,0x16, +0x5a,0x7e,0xe3,0x40,0xf, 0x7e,0xd3,0x40,0x10,0x7e,0xb7,0x44,0x81,0x7e,0x97,0x3e, +0x70,0x7d,0xa9,0x3e,0xa4,0x3e,0xa4,0x4c,0xcc,0x78,0x6c,0x7a,0xd3,0x44,0x88,0x7a, +0xe3,0x44,0x87,0x7e,0x84,0x8, 0x68,0x7a,0x87,0x44,0x8b,0x7e,0x1f,0x22,0xdc,0x7d, +0x83,0x7a,0x87,0x44,0x8d,0x7e,0x1f,0x22,0xdc,0x7d,0x83,0x7a,0x87,0x44,0x8f,0x7d, +0x39,0x7c,0xb7,0xf5,0x27,0x7e,0x8, 0x44,0x87,0x7e,0x18,0x44,0x93,0x7d,0x59,0x12, +0x0, 0x46,0x6c,0xff,0x7d,0x3b,0x3e,0x34,0x49,0x83,0x8, 0x68,0xbd,0xa8,0x58,0x10, +0x7e,0xf, 0x22,0xdc,0x2d,0x13,0xb, 0xa, 0x20,0x2d,0x2a,0x1b,0xa, 0x20,0x80,0x10, +0x6d,0x22,0x9d,0x2a,0xbd,0x28,0x8, 0x8, 0x12,0x74,0x96,0x9d,0x3a,0x1b,0xa, 0x30, +0x12,0x74,0x8e,0x78,0xcf,0x80,0x44,0xbe,0xc0,0x1, 0x78,0x3f,0x6c,0xff,0x80,0x24, +0x6c,0x77,0x80,0x1a,0x7c,0xbf,0xac,0xbd,0xa, 0x87,0x2d,0x85,0x3e,0x84,0x7e,0xf, +0x22,0xdc,0x2d,0x18,0xb, 0xa, 0x80,0x2d,0x89,0x1b,0xa, 0x80,0xb, 0x70,0xbc,0xd7, +0x38,0xe2,0xb, 0xf0,0xbc,0xef,0x38,0xd8,0x6c,0xff,0x7d,0x3b,0x3e,0x34,0x12,0x74, +0x96,0x2d,0x3a,0x1b,0xa, 0x30,0x12,0x74,0x8e,0x78,0xef,0xda,0x3b,0x22,0xb, 0xb4, +0xb, 0xf0,0xbe,0xf0,0x4, 0x22,0x7e,0xf, 0x22,0xdc,0x2d,0x13,0xb, 0xa, 0x30,0x22, +0xca,0x3b,0x7c,0x45,0x7c,0x57,0x7c,0x7b,0x75,0x44,0x0, 0x7e,0xe0,0xff,0xc2,0x5, +0x7e,0xf4,0x7f,0xff,0xbc,0x67,0x28,0x4, 0x7c,0xd7,0x80,0x2, 0x7c,0xd6,0xbc,0x67, +0x50,0x4, 0x7c,0xa7,0x80,0x2, 0x7c,0xa6,0xbc,0x45,0x28,0x4, 0x7c,0xc5,0x80,0x2, +0x7c,0xc4,0xbc,0x45,0x50,0x4, 0x7c,0xb5,0x80,0x2, 0x7c,0xb4,0xf5,0x45,0x7a,0xd1, +0x46,0x7a,0xc1,0x47,0x7a,0xa1,0x48,0x85,0x45,0x49,0xd2,0x5, 0xbe,0x51,0x47,0x78, +0xa, 0xe5,0x46,0xbc,0xb7,0x50,0xc, 0xc2,0x5, 0x80,0x8, 0xe5,0x46,0xbc,0xb6,0x50, +0x2, 0xc2,0x5, 0x30,0x5, 0x2, 0xc1,0x17,0x7c,0xda,0xc1,0x17,0x12,0x73,0xa2,0x74, +0xff,0x12,0x16,0x5a,0x30,0x5, 0x79,0xa, 0x2c,0xb, 0x24,0xe5,0x49,0xa, 0x3b,0xbd, +0x23,0x18,0x3, 0x12,0x76,0x83,0xa, 0xd, 0xb, 0x4, 0xe5,0x48,0xa, 0x1b,0xbd,0x1, +0x18,0xc, 0xa, 0x5d,0xb, 0x54,0x7a,0xb3,0x44,0x8b,0x7a,0xc3,0x44,0x8c,0xbd,0x1, +0x18,0xb, 0xbd,0x23,0x18,0x7, 0xa, 0x3d,0xb, 0x34,0x12,0x76,0x76,0x7e,0xe4,0x80, +0x1, 0x6c,0xff,0x12,0x76,0x69,0x68,0xe, 0x12,0x76,0x4c,0x68,0x9, 0x12,0x76,0x90, +0x8, 0x4, 0x7d,0xe3,0x7c,0xef,0xb, 0xf0,0xbe,0xf0,0x3, 0x78,0xe6,0x12,0x76,0x5c, +0x78,0x7, 0x12,0x76,0x54,0x78,0x2, 0xc1,0x25,0xe5,0x49,0xbe,0xb1,0x47,0x78,0x7, +0x12,0x76,0x54,0x78,0x2, 0xc1,0x25,0xbe,0xe0,0xff,0x78,0x2, 0xc1,0x17,0x80,0x71, +0xa, 0x2c,0xb, 0x24,0xe5,0x49,0xa, 0x3b,0xbd,0x23,0x18,0x3, 0x12,0x76,0x83,0xa, +0xd, 0x1b,0x4, 0xe5,0x46,0xa, 0x1b,0xbd,0x1, 0x48,0xc, 0xa, 0x5d,0x1b,0x54,0x7a, +0xb3,0x44,0x8b,0x7a,0xc3,0x44,0x8c,0xbd,0x1, 0x48,0xb, 0xbd,0x23,0x18,0x7, 0xa, +0x3d,0x1b,0x34,0x12,0x76,0x76,0x7e,0xe4,0x80,0x1, 0x6c,0xff,0x12,0x76,0x69,0x68, +0xe, 0x12,0x76,0x4c,0x68,0x9, 0x12,0x76,0x90,0x8, 0x4, 0x7d,0xe3,0x7c,0xef,0xb, +0xf0,0xbe,0xf0,0x3, 0x78,0xe6,0x12,0x76,0x5c,0x78,0x5, 0x12,0x76,0x44,0x68,0x35, +0xe5,0x49,0xbe,0xb1,0x47,0x78,0x5, 0x12,0x76,0x44,0x68,0x29,0xbe,0xe0,0xff,0x68, +0x16,0x7e,0x71,0x44,0x74,0x2, 0xac,0x7b,0x59,0xe3,0x4c,0xda,0x9, 0xd4,0x44,0x87, +0x7c,0xca,0x5, 0x44,0x7e,0xe0,0xff,0xe5,0x45,0xa, 0x2b,0xb, 0x24,0xa, 0x3c,0xbd, +0x32,0x68,0x2, 0xa1,0xc, 0x6c,0xff,0x80,0x10,0x74,0x2, 0xac,0xbf,0x49,0xe5,0x4c, +0xda,0xbd,0xef,0x58,0x2, 0x7d,0xfe,0xb, 0xf0,0xe5,0x44,0xbc,0xbf,0x38,0xea,0x7d, +0x3f,0xda,0x3b,0x22,0x9, 0xb4,0x44,0x87,0xbe,0xb1,0x46,0x22,0x9, 0x72,0x44,0x88, +0xbe,0x70,0xff,0x22,0x9, 0xb4,0x44,0x87,0xbe,0xb1,0x48,0x22,0x7e,0x90,0x4, 0xac, +0x9e,0x9, 0xa4,0x44,0x88,0xbe,0xa1,0x49,0x22,0x7e,0x50,0x4, 0xac,0x5f,0x9, 0xb2, +0x44,0x87,0xbe,0xb0,0xff,0x22,0x7a,0x73,0x44,0x8f,0xa, 0x3c,0xb, 0x34,0x7a,0x73, +0x44,0x90,0x22,0x7a,0xd3,0x44,0x87,0xa, 0x1c,0xb, 0x14,0x7a,0x33,0x44,0x88,0x22, +0x12,0x23,0x82,0x74,0x4, 0xac,0xbf,0x59,0x35,0x44,0x89,0xbd,0x3e,0x22,0x7e,0xb3, +0x4f,0x5a,0xbe,0xb0,0xc8,0x50,0x5, 0x4, 0x7a,0xb3,0x4f,0x5a,0x22,0x7e,0x18,0x8, +0x68,0x7a,0x1d,0x27,0x7e,0x1f,0x22,0xdc,0x7f,0x1, 0x2, 0x73,0x59,0x6d,0x22,0x7d, +0x32,0x80,0x12,0x7d,0x52,0x12,0x72,0xf9,0xb, 0xa, 0x10,0xbe,0x14,0xff,0xb0,0x58, +0x2, 0xb, 0x34,0xb, 0x24,0x7e,0x17,0x44,0x81,0xbd,0x12,0x38,0xe6,0x22,0x7e,0x8, +0x8, 0x68,0x7e,0x1f,0x22,0xe0,0x12,0x73,0xc, 0x7e,0x37,0x44,0x81,0x7e,0x50,0x4, +0x7d,0x3, 0x3e,0x4, 0x7e,0x2f,0x22,0xe0,0x2d,0x50,0xb, 0x2a,0x10,0x59,0x10,0x8, +0x68,0xb, 0x34,0x1b,0x50,0x78,0xe9,0x22,0x12,0x77,0x47,0x12,0x76,0xde,0x12,0x77, +0x1b,0x2, 0x77,0x14,0x74,0x1, 0x7a,0xb3,0x4f,0xb1,0x22,0xca,0x3b,0x7e,0xf3,0x40, +0x10,0x7e,0xe3,0x40,0x11,0x7e,0xd3,0x40,0x12,0x6c,0xcc,0x80,0x13,0x7c,0x3c,0xac, +0x3f,0x3e,0x14,0x2e,0x14,0x4, 0x0, 0x6d,0x0, 0x7c,0xbd,0x12,0x95,0x4f,0xb, 0xc0, +0xbc,0xec,0x38,0xe9,0xda,0x3b,0x22,0xe4,0x7a,0xb3,0x3e,0x80,0x7a,0xb3,0x3e,0x81, +0x22,0x7c,0x67,0x7c,0x7b,0xd2,0x1, 0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x51,0x7c,0xb6, +0x12,0x6b,0x73,0x50,0x4a,0x7e,0xa3,0x4d,0xf4,0xbe,0xa0,0x2, 0x40,0x37,0x7e,0xb3, +0x4d,0xfc,0x70,0x2d,0x7e,0x63,0x4f,0xad,0xa, 0x26,0x2e,0x24,0x0, 0xe, 0x7a,0x51, +0x82,0x7a,0x41,0x83,0xe4,0x93,0x24,0xff,0x92,0x1, 0x7c,0xb6,0x4, 0x7a,0xb3,0x4f, +0xad,0x7e,0x63,0x4f,0xad,0xbe,0x60,0x4, 0x40,0x15,0xe4,0x7a,0xb3,0x4f,0xad,0x80, +0xe, 0xd2,0x1, 0x80,0xa, 0xbc,0xa7,0x78,0x4, 0xd2,0x1, 0x80,0x2, 0xc2,0x1, 0xa2, +0x1, 0x22,0xca,0x79,0x7c,0xeb,0x75,0x2f,0x0, 0x6c,0x11,0x12,0xad,0x2, 0x7a,0x57, +0x3e,0x61,0x12,0xad,0x2, 0x7a,0x57,0x3e,0x63,0xe4,0x7a,0xb3,0x3e,0x65,0x7a,0xb3, +0x3e,0x66,0x7e,0xf4,0x0, 0x1, 0x7e,0xa0,0xff,0xbe,0xe0,0x1, 0x78,0x8, 0x7e,0xb3, +0x4e,0xdb,0xf5,0x30,0x80,0x6, 0x7e,0xb3,0x4e,0xdc,0xf5,0x30,0x6c,0x33,0x90,0xe, +0x77,0xe4,0x93,0x20,0xe0,0x7, 0x4c,0x33,0x78,0x3, 0x2, 0x78,0xa0,0x1e,0xb0,0x1e, +0xb0,0x20,0xe0,0x7, 0xbe,0x30,0x1, 0x78,0x2, 0x1, 0xa0,0x90,0xe, 0x78,0xe4,0x93, +0x20,0xe0,0x7, 0xbe,0x30,0x2, 0x78,0x2, 0x1, 0xa0,0x1e,0xb0,0x1e,0xb0,0x20,0xe0, +0x5, 0xbe,0x30,0x3, 0x68,0x7a,0xe5,0x30,0xb4,0xff,0x6, 0x7e,0x47,0x3f,0xf3,0x80, +0x1f,0xe5,0x30,0xbc,0xb3,0x7e,0x27,0x3f,0xf3,0x78,0x6, 0x7e,0x34,0x0, 0x3, 0x80, +0x4, 0x7e,0x34,0x0, 0x5, 0xad,0x32,0x7e,0x24,0x0, 0x4, 0x12,0x14,0x9f,0x7d,0x43, +0xa, 0xe3,0x2e,0xe7,0x44,0x81,0x3e,0xe4,0x7e,0x1f,0x22,0xe0,0x2d,0x3e,0xb, 0x1a, +0xe0,0xbd,0x4e,0x18,0x8, 0xbd,0xfe,0x58,0x4, 0x7c,0xa3,0x7d,0xfe,0x7e,0x37,0x3f, +0xf5,0xbd,0x3e,0x48,0xb, 0x7c,0x1, 0x2e,0x0, 0x2b,0x7c,0xb3,0xa5,0xf6,0xb, 0x10, +0x7e,0x37,0x3e,0x61,0xbd,0x3e,0x58,0x8, 0x7a,0xe7,0x3e,0x61,0x7a,0x33,0x3e,0x65, +0x7e,0x37,0x3e,0x63,0xbd,0x3e,0x8, 0x8, 0x7a,0xe7,0x3e,0x63,0x7a,0x33,0x3e,0x66, +0xb, 0x30,0xa5,0xbb,0x4, 0x2, 0x80,0x3, 0x2, 0x77,0xee,0xbe,0xa0,0x4, 0x50,0x6, +0x75,0x2f,0x1, 0x7a,0xa1,0x27,0xbe,0xe0,0x1, 0x78,0x6, 0x7a,0xa3,0x4e,0xdb,0x80, +0x4, 0x7a,0xa3,0x4e,0xdc,0xe5,0x2f,0xa, 0x5b,0x7e,0x3, 0x3e,0x53,0xa, 0x70,0x2d, +0x75,0x90,0x13,0x80,0xe4,0x93,0xbc,0xbf,0x50,0x2, 0x7c,0xfb,0x7c,0x30,0x80,0x2a, +0x12,0x26,0xf6,0x90,0x14,0x28,0xe4,0x93,0x7c,0xb, 0x74,0x2, 0xac,0xb3,0x19,0x5, +0x3c,0xc9,0x7c,0x3, 0x9e,0x3, 0x3e,0x53,0x2e,0x0, 0x27,0xa5,0xe6,0x7c,0xab,0x7e, +0x70,0x2, 0xac,0x73,0x19,0xa3,0x3c,0xca,0xb, 0x30,0xbc,0xf3,0x38,0xd2,0x7a,0xf3, +0x3e,0x53,0xa, 0x21,0x7e,0xa3,0x3e,0x54,0xa, 0x3a,0x2d,0x32,0x7c,0x27,0x90,0x13, +0x80,0xe4,0x93,0xbc,0xb2,0x50,0x2, 0x7c,0x2b,0x7c,0x3a,0x80,0x20,0x90,0x14,0x28, +0xe4,0x93,0x12,0x79,0x58,0x19,0xa0,0x3d,0x5, 0x7c,0x13,0x9e,0x13,0x3e,0x54,0x2e, +0x10,0x2b,0xa5,0xe7,0x12,0x79,0x58,0x19,0xa0,0x3d,0x6, 0xb, 0x30,0xbc,0x23,0x38, +0xdc,0x7a,0x23,0x3e,0x54,0xda,0x79,0x22,0x7c,0xab,0x7e,0x10,0x2, 0xac,0x13,0x22, +0x7c,0xa7,0x7e,0x73,0x40,0x10,0xac,0x7b,0xa, 0x2a,0x2d,0x32,0x22,0xca,0x3b,0x7c, +0xf5,0x7c,0xe6,0x7c,0xd7,0x7c,0xcb,0x75,0x35,0x0, 0x75,0x36,0x0, 0x75,0x37,0x0, +0x75,0x38,0x0, 0x75,0x39,0x0, 0x75,0x3a,0x0, 0x75,0x3d,0x0, 0x7e,0x37,0x3f,0xff, +0x7a,0x35,0x3e,0x6c,0xaa,0x12,0x7b,0xf7,0xe4,0x19,0xb3,0x3d,0x4b,0x7e,0x13,0x40, +0xf, 0x7e,0xb3,0x40,0x10,0xf5,0x34,0x12,0x7d,0x4a,0xf5,0x33,0x12,0x7d,0x14,0x7a, +0x35,0x3e,0x7e,0x37,0x3f,0xff,0xbe,0x35,0x3e,0x8, 0x3, 0x7a,0x35,0x3e,0xe5,0x32, +0x7c,0x71,0x7c,0x6c,0x7e,0x8, 0x0, 0x37,0x12,0x7c,0xc, 0xf5,0x35,0xe5,0x33,0x7e, +0x71,0x34,0x7c,0x6d,0x7e,0x8, 0x0, 0x38,0x12,0x7c,0xc, 0xf5,0x36,0xe5,0x37,0x7e, +0x71,0x38,0x12,0x7d,0x3c,0x7a,0x37,0x44,0x8d,0x7e,0x34,0x23,0x34,0x7a,0x37,0x44, +0x8f,0xe5,0x37,0x7a,0xb3,0x44,0x87,0xe5,0x38,0x7a,0xb3,0x44,0x88,0xe5,0x35,0x7a, +0xb3,0x44,0x89,0xe5,0x36,0x7a,0xb3,0x44,0x8a,0x7e,0x73,0x3f,0xea,0x7a,0x73,0x44, +0x8b,0xe4,0x7a,0xb3,0x44,0x8c,0x7e,0x8, 0x44,0x87,0x12,0x8, 0x73,0x7e,0x37,0x23, +0x34,0x7d,0x23,0x6d,0x33,0x7e,0xb7,0x23,0x36,0x6d,0xaa,0x2f,0x51,0x7e,0x37,0x23, +0x38,0x6d,0x22,0x7d,0x3, 0x6d,0x11,0x7e,0x37,0x23,0x3a,0x2f,0x10,0x7a,0x1d,0x2c, +0x7e,0x37,0x23,0x3c,0x7d,0x23,0x6d,0x33,0x7e,0x97,0x23,0x3e,0x6d,0x88,0x2f,0x41, +0x7f,0x65,0xe5,0x35,0xa, 0x4b,0xe5,0x37,0xa, 0x5b,0x2d,0x54,0xf5,0x39,0xe5,0x36, +0xa, 0x4b,0xe5,0x38,0xa, 0x5b,0x2d,0x54,0xf5,0x3a,0x85,0x37,0x30,0x61,0x39,0x85, +0x38,0x31,0x61,0x2e,0xe5,0x30,0x7e,0x71,0x31,0x12,0x7d,0x32,0x9d,0x32,0x7a,0x35, +0x3b,0xbe,0x34,0x0, 0x0, 0x18,0x2, 0x61,0x2c,0x7e,0x35,0x3e,0xbe,0x35,0x3b,0x18, +0x2, 0x5, 0x3d,0xe5,0x32,0xa, 0x1b,0xe5,0x30,0x12,0x7c,0x1, 0x8, 0x4, 0x9d,0x31, +0x80,0x4, 0x6d,0x33,0x9d,0x32,0xbe,0x34,0x0, 0x1, 0x18,0x19,0xe5,0x33,0xa, 0x1b, +0xe5,0x31,0x12,0x7c,0x1, 0x8, 0x4, 0x9d,0x31,0x80,0x4, 0x6d,0x33,0x9d,0x32,0xbe, +0x34,0x0, 0x1, 0x8, 0x67,0xbe,0xc0,0x3, 0x40,0x9, 0xbe,0xd0,0x3, 0x40,0x4, 0xd2, +0x0, 0x80,0x2, 0xc2,0x0, 0xe5,0x30,0x7e,0x71,0x31,0x7c,0x6e,0x12,0xaa,0x2b,0x7c, +0x9b,0xbe,0x90,0x2, 0x68,0x5, 0xbe,0x90,0x3, 0x78,0x8, 0x7e,0x35,0x3b,0xe, 0x34, +0x7a,0x35,0x3b,0xbe,0x90,0x2, 0x68,0xa, 0xbe,0x90,0x1, 0x68,0x5, 0xbe,0x90,0x3, +0x78,0x2a,0x7e,0xf5,0x3b,0x12,0x7b,0xd7,0xe5,0x30,0x12,0x7b,0xde,0x7f,0x1, 0x7e, +0x1d,0x2c,0x9f,0x10,0x7a,0x1d,0x2c,0x12,0x7b,0xd7,0xe5,0x31,0x12,0x7b,0xde,0x9f, +0x41,0x12,0x7b,0xd7,0x9f,0x51,0x1a,0x26,0x1a,0x24,0x9f,0x61,0x5, 0x31,0xe5,0x3a, +0xbe,0xb1,0x31,0x28,0x2, 0x41,0x74,0x5, 0x30,0xe5,0x39,0xbe,0xb1,0x30,0x28,0x2, +0x41,0x6f,0xbe,0x58,0x0, 0x0, 0x78,0x2, 0xb, 0x5c,0xbe,0x68,0x0, 0x0, 0x78,0x2, +0xb, 0x6c,0x74,0x6, 0x7e,0x1d,0x2c,0x2f,0x11,0x14,0x78,0xfb,0x7a,0x1d,0x2c,0x7f, +0x5, 0x12,0x7b,0xe5,0x7e,0xd0,0x9, 0xac,0xdf,0x59,0x36,0x3d,0x45,0x74,0x6, 0x2f, +0x44,0x14,0x78,0xfb,0x7f,0x14,0x7f,0x6, 0x12,0x7b,0xe5,0x59,0x36,0x3d,0x47,0x7e, +0xb3,0x3f,0xfe,0x60,0xd, 0x1e,0xd4,0x1e,0xc4,0x50,0x4, 0x4e,0xd4,0x80,0x0, 0x14, +0x78,0xf3,0xbe,0x68,0x0, 0x7f,0x28,0x4, 0x7e,0x68,0x0, 0x7f,0x7d,0x3d,0x7c,0xa7, +0x12,0x7b,0xf7,0x7e,0xa1,0x3d,0x12,0x7b,0xed,0x74,0x9, 0xac,0xbf,0x9, 0x75,0x3d, +0x4b,0xbe,0x70,0x2d,0x28,0x6, 0x7e,0xa0,0x2d,0x12,0x7b,0xed,0x7e,0xa1,0x32,0x7e, +0x70,0x9, 0xac,0x7f,0x19,0xa3,0x3d,0x4c,0x7e,0xa1,0x33,0x7e,0x70,0x9, 0xac,0x7f, +0x19,0xa3,0x3d,0x4d,0xda,0x3b,0x22,0x7d,0x3f,0x1a,0x26,0x1a,0x24,0x22,0xa, 0x1b, +0x6d,0x0, 0x2, 0x14,0xd1,0x12,0x14,0xed,0x2e,0x18,0x0, 0x20,0x22,0x7e,0x70,0x9, +0xac,0x7f,0x19,0xa3,0x3d,0x4b,0x22,0x7e,0x70,0x9, 0xac,0x7f,0x19,0xa3,0x3d,0x4a, +0x22,0xa, 0x3b,0x7d,0x23,0x9d,0x21,0xbe,0x24,0x0, 0x0, 0x22,0xca,0xf8,0x7c,0xf6, +0x7c,0x87,0x7c,0x9b,0xa, 0x2f,0x7d,0x32,0x3e,0x34,0xb, 0x34,0x7c,0xb7,0xbc,0xf9, +0x38,0x14,0xa, 0xf8,0x1b,0xf4,0xa, 0x3f,0x9d,0xf3,0xa, 0x39,0xbd,0x3f,0x18,0x6, +0x7c,0xab,0xa, 0x39,0x80,0x1d,0xbc,0xf9,0x28,0xd, 0xa, 0x39,0xa, 0x5f,0x2d,0x53, +0xb, 0x54,0x7c,0xab,0xe4,0x80,0x10,0xa, 0x3f,0xa, 0x58,0x2d,0x53,0xa, 0x39,0x9d, +0x53,0x7c,0xab,0x9d,0x32,0x7c,0xb7,0x7a,0xb, 0xb0,0x7c,0xba,0xda,0xf8,0x22,0xca, +0x3b,0x6c,0xff,0x6c,0xee,0xa1,0x8, 0x12,0x7d,0x4a,0xf5,0x33,0x75,0x2b,0x3, 0x75, +0x2c,0x3, 0x12,0x7d,0x14,0x7d,0xe3,0x7e,0xf7,0x3f,0xff,0xbd,0xfe,0x8, 0x2, 0x7d, +0xef,0x7e,0x73,0x40,0xf, 0x7a,0x71,0x27,0x7e,0xb3,0x40,0x10,0xf5,0x28,0xe5,0x32, +0x7e,0x61,0x2b,0x7e,0x8, 0x0, 0x2d,0x12,0x7c,0xc, 0xf5,0x29,0xe5,0x33,0x7e,0x71, +0x28,0x7e,0x61,0x2c,0x7e,0x8, 0x0, 0x2e,0x12,0x7c,0xc, 0x7c,0xab,0x7a,0xa1,0x2a, +0xe5,0x29,0xa, 0x4b,0xe5,0x2d,0xa, 0xfb,0x2d,0xf4,0x7d,0x3f,0x7c,0xb7,0xf5,0x2f, +0xa, 0x4a,0xe5,0x2e,0xa, 0x5b,0x2d,0x54,0xf5,0x30,0x75,0x31,0x0, 0x7e,0xd1,0x2d, +0x80,0x26,0x7e,0xc1,0x2e,0x80,0x19,0x7c,0xbd,0x7c,0x7c,0x12,0x7d,0x32,0x7d,0xd3, +0x9d,0xd2,0xbe,0xd4,0x0, 0x0, 0x8, 0x6, 0xbd,0xed,0x18,0x2, 0x5, 0x31,0xb, 0xc0, +0xe5,0x30,0xbc,0xbc,0x38,0xe1,0xb, 0xd0,0xe5,0x2f,0xbc,0xbd,0x38,0xd4,0xbe,0xf1, +0x31,0x50,0x3, 0x7e,0xf1,0x31,0xb, 0xe0,0x12,0x5f,0xd8,0x28,0x2, 0x81,0x67,0x7c, +0xbf,0xda,0x3b,0x22,0x7c,0xbe,0x12,0x7d,0x20,0x7e,0x24,0x0, 0x3, 0x2, 0x14,0x9f, +0x7c,0xab,0x7e,0x70,0x2, 0xac,0x7a,0x9, 0xb3,0x3c,0xc9,0x9, 0x73,0x3c,0xca,0x2, +0x23,0x82,0x12,0x23,0x82,0x7e,0x53,0x3f,0xea,0xa, 0x25,0x22,0x12,0x79,0x60,0x7d, +0x13,0x3e,0x14,0x7e,0x1f,0x22,0xe0,0x2d,0x31,0x22,0x7e,0x70,0x2, 0xac,0x7e,0x9, +0xb3,0x3c,0xc9,0xf5,0x32,0x9, 0xb3,0x3c,0xca,0x22,0x7e,0x37,0x3e,0x59,0xbe,0x34, +0x1, 0x5e,0x58,0xa, 0x12,0x7f,0xb0,0x50,0x5, 0x12,0x7c,0x5f,0x80,0x2, 0x74,0xff, +0x7a,0xb3,0x3, 0xfe,0x22,0x7e,0xb3,0x40,0x1, 0x70,0x6, 0xe4,0x7a,0xb3,0x40,0x2, +0x22,0x7e,0xb3,0x40,0x2, 0x70,0x1b,0x12,0x5f,0xe7,0x28,0x6, 0x7e,0x34,0x0, 0xf, +0x80,0xc, 0x7e,0x37,0x4e,0x4c,0xbe,0x34,0x0, 0x5, 0x28,0x6, 0x1b,0x34,0x7a,0x37, +0x4e,0x4c,0xe4,0x7a,0xb3,0x3e,0x68,0x74,0x1, 0x12,0x9d,0x1a,0x12,0xaa,0xea,0x74, +0x1, 0x12,0x77,0xb2,0x12,0x7e,0xae,0x12,0x23,0x3d,0x12,0x7d,0x5a,0xc2,0x0, 0x12, +0x7d,0xd2,0x7e,0xb3,0x24,0x26,0xb4,0x1, 0x8, 0x7e,0x73,0x3e,0x53,0x7a,0x73,0x3e, +0x67,0x22,0xca,0xf8,0xc2,0x4, 0xc2,0x5, 0xc2,0x6, 0x7e,0xb3,0x3e,0x53,0x70,0x3, +0x12,0x7f,0xb8,0x7e,0x34,0x2, 0xbc,0x12,0x7e,0xb9,0x7a,0xb3,0x4e,0x49,0x7e,0x37, +0x4e,0x4c,0x12,0x7f,0xf, 0x92,0x1, 0x7e,0xb3,0x40,0x2, 0x70,0x62,0x7e,0xa3,0x4e, +0x49,0xbe,0xa0,0x0, 0x38,0x2, 0xc1,0xa4,0xbe,0xa0,0x4, 0x28,0x2, 0xc1,0xa4,0xd2, +0x2, 0x20,0x2, 0x2, 0xc1,0xa4,0xbe,0xa0,0x4, 0x78,0x5, 0x7e,0xf0,0x2, 0x80,0x17, +0xbe,0xa0,0x3, 0x78,0x5, 0x7e,0xf0,0x3, 0x80,0xd, 0xbe,0xa0,0x2, 0x78,0x5, 0x7e, +0xf0,0x5, 0x80,0x3, 0x7e,0xf0,0x8, 0x7c,0xbf,0x12,0x9c,0x66,0x92,0x3, 0x12,0x7f, +0xd7,0x92,0x4, 0xd2,0x5, 0x30,0x3, 0x9, 0x30,0x4, 0x6, 0x30,0x5, 0x3, 0x12,0x7e, +0xa7,0x30,0x1, 0x50,0x30,0x4, 0x4d,0x30,0x5, 0x4a,0x12,0x7e,0xa7,0x80,0x45,0x7e, +0x73,0x4e,0x49,0xbe,0x70,0x0, 0x28,0x7, 0x12,0x7e,0xa7,0x6d,0x33,0x80,0x12,0x7e, +0xb3,0x3e,0x53,0x70,0x12,0x74,0x1, 0x7a,0xb3,0x40,0x2, 0x7e,0x37,0x4e,0x95,0xb, +0x34,0x7a,0x37,0x4e,0x95,0x80,0x2, 0xd2,0x6, 0x20,0x6, 0xd, 0x7e,0x37,0x4e,0x95, +0xbe,0x34,0xe, 0x10,0x50,0x3, 0x30,0x0, 0xb, 0xe4,0x7a,0xb3,0x40,0x2, 0x6d,0x33, +0x7a,0x37,0x4e,0x95,0xda,0xf8,0x22,0x74,0x2, 0x7a,0xb3,0x40,0x2, 0x22,0x7e,0xb3, +0x4f,0x6e,0xb4,0x1, 0x3, 0x2, 0x9a,0x5b,0x22,0x7d,0x23,0x12,0x7f,0xa8,0x28,0x4b, +0x7e,0x37,0x3e,0x59,0xbd,0x32,0x8, 0x4, 0xd2,0x1a,0xe4,0x22,0x30,0x1a,0x2, 0xe4, +0x22,0x12,0x7f,0x80,0x50,0x32,0x7e,0x27,0x3f,0xed,0x7d,0x32,0x3e,0x34,0xbe,0x37, +0x3e,0x59,0x48,0x3, 0x74,0x1, 0x22,0x7d,0x32,0x3e,0x34,0x3e,0x34,0xbe,0x37,0x3e, +0x59,0x48,0x3, 0x74,0x2, 0x22,0x7e,0x34,0x0, 0x6, 0xad,0x32,0xbe,0x37,0x3e,0x59, +0x48,0x3, 0x74,0x3, 0x22,0x74,0x4, 0x22,0x74,0xff,0x22,0xc2,0x1a,0xe4,0x22,0x7c, +0x3b,0x7d,0x43,0xc2,0x7, 0x7e,0x23,0x4e,0x91,0xa, 0x22,0x7e,0x23,0x3e,0x5b,0x12, +0x7f,0x74,0x18,0x37,0x7e,0x23,0x4e,0x92,0xa, 0x22,0x7e,0x23,0x3e,0x5c,0x12,0x7f, +0x74,0x18,0x28,0x12,0x7f,0x80,0x50,0x23,0xbe,0x30,0x0, 0x28,0x1e,0x7e,0x57,0x4e, +0x93,0xb, 0x54,0x7a,0x57,0x4e,0x93,0x7e,0x37,0x4e,0x93,0xbd,0x34,0x40,0x12,0x6d, +0x33,0x7a,0x37,0x4e,0x93,0xd2,0x7, 0x80,0x8, 0x80,0x0, 0x6d,0x33,0x7a,0x37,0x4e, +0x93,0x7e,0x73,0x3e,0x5b,0x7a,0x73,0x4e,0x91,0x7e,0x73,0x3e,0x5c,0x7a,0x73,0x4e, +0x92,0xa2,0x7, 0x22,0xa, 0x32,0x9d,0x32,0x12,0x16,0x6c,0xbe,0x34,0x0, 0x1, 0x22, +0x7e,0xb3,0x3e,0x5b,0x7e,0x73,0x3e,0x5c,0x7c,0xab,0x4c,0x77,0x68,0x18,0x7e,0xb3, +0x40,0x12,0x14,0xbc,0xb7,0x68,0xf, 0x4c,0xaa,0x68,0xb, 0x7e,0xb3,0x40,0x11,0x14, +0xbc,0xba,0x68,0x2, 0xd3,0x22,0xc3,0x22,0x7e,0x73,0x3e,0x53,0xbe,0x70,0x0, 0x22, +0x7e,0x73,0x3e,0x53,0xbe,0x70,0x3, 0x22,0xe4,0x7a,0xb3,0x4e,0x4e,0x7a,0xb3,0x4e, +0x4b,0x7e,0x8, 0x4e,0x72,0x7e,0x34,0x0, 0x1f,0x12,0x16,0x5a,0x7e,0x8, 0x4e,0x4f, +0x7e,0x34,0x0, 0x23,0x2, 0x16,0x5a,0xca,0xf8,0xd2,0x7, 0x6c,0xff,0x80,0x13,0x7c, +0xbf,0x7e,0x70,0x1, 0x12,0x5f,0x3, 0xbe,0x18,0x2, 0xee,0x58,0x3, 0xc3,0x80,0xc, +0xb, 0xf0,0x7e,0x33,0x3e,0x53,0xbc,0x3f,0x38,0xe5,0xa2,0x7, 0xda,0xf8,0x22,0x6d, +0x22,0x6c,0x33,0x7e,0x44,0x7f,0xff,0x7c,0xb3,0x3e,0xb0,0x24,0x27,0xa, 0xfb,0x1b, +0xf8,0x40,0x90,0xe, 0x77,0xe4,0x93,0x20,0xe0,0x4, 0x4c,0x33,0x68,0x39,0x1e,0xb0, +0x1e,0xb0,0x20,0xe0,0x5, 0xbe,0x30,0x1, 0x68,0x2d,0x90,0xe, 0x78,0xe4,0x93,0x20, +0xe0,0x5, 0xbe,0x30,0x2, 0x68,0x20,0x1e,0xb0,0x1e,0xb0,0x20,0xe0,0x5, 0xbe,0x30, +0x3, 0x68,0x14,0xa, 0xe3,0x2e,0xe7,0x44,0x81,0x3e,0xe4,0x7e,0x6f,0x22,0xe0,0x2d, +0xde,0xb, 0x6a,0x0, 0x1b,0xf8,0x0, 0xb, 0x30,0xa5,0xbb,0x4, 0xa6,0x7d,0x34,0x6c, +0x33,0x7c,0xb3,0x3e,0xb0,0x24,0x27,0xa, 0xb, 0xb, 0x8, 0x0, 0xbe,0x4, 0x7f,0xff, +0x68,0x8, 0xbd,0x3, 0x58,0x2, 0x7d,0x30,0x2d,0x20,0xb, 0x30,0xa5,0xbb,0x4, 0xe1, +0xbe,0x34,0x0, 0x0, 0x58,0x4, 0x7e,0x34,0x0, 0x1, 0x20,0x6, 0x5, 0x7e,0xa0,0x4, +0x80,0x3, 0x7e,0xa0,0x3, 0xa, 0x1a,0xad,0x13,0xbe,0x17,0x3e,0x61,0x8, 0xe, 0x7e, +0x27,0x3e,0x61,0xbe,0x24,0x3, 0xe8,0x8, 0x4, 0xd2,0x23,0xc3,0x22,0xd3,0x22,0x7e, +0x37,0x3f,0xeb,0x7e,0x53,0x40,0x11,0xbc,0x5b,0x38,0x4, 0x7e,0x37,0x3f,0xf1,0x22, +0x7f,0x20,0xb, 0x2a,0x10,0xb, 0x1a,0x0, 0x1b,0x2a,0x0, 0x1b,0x1a,0x10,0x22,0xca, +0x3b,0x6c,0xff,0x6c,0xee,0x7e,0xb3,0x40,0x11,0xf5,0x2b,0x7e,0xd3,0x40,0x12,0xe4, +0x7a,0xb3,0x3, 0xff,0x7e,0xb3,0x24,0x26,0xb4,0x1, 0x2, 0x80,0x2, 0x21,0xf4,0x6c, +0xcc,0x21,0xe2,0x7e,0x70,0x2, 0xac,0x7c,0x12,0x81,0xfa,0x75,0x27,0x3, 0x75,0x28, +0x3, 0xe5,0x29,0x12,0x5e,0xf8,0x50,0xf, 0x75,0x27,0x0, 0x75,0x28,0x0, 0x7c,0xbc, +0x7c,0x7e,0x12,0x87,0x28,0x21,0xde,0xe5,0x29,0x7e,0x71,0x2a,0x12,0x23,0x82,0xbe, +0x37,0x3f,0xed,0x58,0x2, 0x21,0xe0,0x7e,0x73,0x3e,0x53,0xbe,0x70,0x5, 0x28,0x6, +0x75,0x27,0x2, 0x75,0x28,0x2, 0xe5,0x29,0xbe,0xb0,0x1, 0x68,0x9, 0xe5,0x2b,0x24, +0xfe,0xbe,0xb1,0x29,0x78,0x3, 0x75,0x27,0x2, 0xe5,0x2a,0xbe,0xb0,0x1, 0x68,0x9, +0x7c,0xbd,0x24,0xfe,0xbe,0xb1,0x2a,0x78,0x3, 0x75,0x28,0x2, 0xe5,0x29,0x60,0x8, +0xe5,0x2b,0x14,0xbe,0xb1,0x29,0x78,0x3, 0x75,0x27,0x2, 0xe5,0x2a,0x60,0x8, 0x7c, +0xbd,0x14,0xbe,0xb1,0x2a,0x78,0x3, 0x75,0x28,0x2, 0xc2,0x0, 0xe5,0x29,0x7e,0x71, +0x2a,0x7c,0x6c,0x12,0xaa,0x2b,0xbe,0xb0,0xff,0x68,0x6, 0x75,0x27,0x2, 0x75,0x28, +0x2, 0x7c,0xbc,0x7e,0x8, 0x0, 0x27,0x7e,0x18,0x0, 0x28,0x12,0x87,0xc1,0x7e,0xb3, +0x40,0x2, 0x60,0x6, 0x75,0x27,0x4, 0x75,0x28,0x4, 0xe5,0x27,0x7e,0x71,0x28,0x7c, +0x6c,0x7c,0x5e,0x12,0x79,0x6d,0x7e,0x70,0x9, 0xac,0x7e,0x9, 0x53,0x3d,0x4b,0xbc, +0x5f,0x28,0x2, 0x7c,0xf5,0x90,0x14,0x7, 0xe4,0x93,0xb4,0x1, 0x11,0x7d,0x13,0x2e, +0x14,0x3d,0x45,0x6d,0x0, 0x2e,0x34,0x3d,0x47,0x6d,0x22,0x12,0x80,0xc0,0xb, 0xe0, +0xb, 0xc0,0x7e,0x73,0x3e,0x53,0xbc,0x7c,0x28,0x2, 0x1, 0xf3,0x7a,0xe3,0x3e,0x53, +0x7a,0xf3,0x3, 0xff,0xda,0x3b,0x22,0x2, 0x80,0xcf,0x9, 0xb3,0x3c,0xc9,0xf5,0x29, +0x9, 0xb3,0x3c,0xca,0xf5,0x2a,0x22,0xca,0x3b,0x7c,0xfb,0xc2,0x2, 0xc2,0x3, 0xc2, +0x4, 0x7e,0x94,0x0, 0x51,0x7e,0xe3,0x3e,0x53,0xe4,0x7a,0xb3,0x4c,0xba,0x7a,0xb3, +0x4c,0xbb,0x7a,0xb3,0x4c,0x7c,0x7e,0x8, 0x4c,0xbc,0x12,0x84,0xfa,0xe4,0x12,0x16, +0x5a,0x12,0x84,0xfa,0x3e,0x34,0x7e,0x8, 0x4c,0x7d,0xe4,0x12,0x16,0x5a,0xbe,0xe0, +0x2, 0x50,0x2, 0x81,0xe1,0x6c,0xdd,0x81,0xdb,0x74,0x2, 0x7c,0x7d,0xac,0x7b,0x12, +0x81,0xfa,0x90,0x14,0x28,0xe4,0x93,0xbe,0xb1,0x29,0x78,0x2, 0x81,0xd9,0x4c,0xdd, +0x68,0x8, 0xa, 0x8d,0x9, 0xb8,0x4c,0xbc,0x70,0xa, 0xa, 0x3d,0xb, 0x34,0xa, 0x8d, +0x19,0x78,0x4c,0xbc,0xa, 0x5d,0xb, 0x54,0xf5,0x27,0x81,0xd2,0x7e,0xa1,0x27,0x74, +0x2, 0x7c,0x7a,0xac,0x7b,0x9, 0xb3,0x3c,0xc9,0xf5,0x2b,0x9, 0xb3,0x3c,0xca,0xf5, +0x2c,0x90,0x14,0x28,0xe4,0x93,0xbe,0xb1,0x2b,0x78,0x2, 0x81,0xd0,0xe5,0x2b,0xa, +0x2b,0xe5,0x29,0x12,0x85,0x1, 0x8, 0x6, 0x7d,0x50,0x9d,0x52,0x80,0x4, 0x6d,0x55, +0x9d,0x53,0xf5,0x2d,0xe5,0x2c,0xa, 0x2b,0xe5,0x2a,0x12,0x85,0x1, 0x8, 0x6, 0x7d, +0x80,0x9d,0x82,0x80,0x4, 0x6d,0x88,0x9d,0x83,0x7d,0x38,0x7c,0xc7,0xe5,0x2d,0xbe, +0xb0,0x6, 0x40,0x2, 0x81,0xd0,0xbe,0xc0,0x6, 0x40,0x2, 0x81,0xd0,0xe5,0x29,0x7e, +0x71,0x2a,0x12,0x23,0x82,0x7a,0x35,0x2f,0x12,0x23,0x7d,0x7d,0x83,0x7e,0x25,0x2f, +0xbd,0x28,0x8, 0x4, 0x7d,0x38,0x80,0x3, 0x7e,0x35,0x2f,0x7a,0x35,0x31,0xbd,0x28, +0x58,0x4, 0x7d,0x38,0x80,0x3, 0x7e,0x35,0x2f,0x7a,0x35,0x33,0x75,0x2e,0x0, 0xe5, +0x2d,0xbe,0xb0,0x1, 0x38,0x21,0xbe,0xc0,0x1, 0x38,0x1c,0x7c,0xbf,0x30,0xe0,0x17, +0x7e,0xb3,0x4c,0x7c,0x4, 0x7a,0xb3,0x4c,0x7c,0x75,0x2e,0x1, 0x7e,0xb3,0x4c,0xba, +0x4, 0x7a,0xb3,0x4c,0xba,0x81,0x74,0xe5,0x2d,0xbe,0xb0,0x1, 0x38,0x7, 0xbe,0xc0, +0x1, 0x38,0x2, 0x81,0x74,0xe5,0x2d,0xbe,0xb0,0x6, 0x40,0x2, 0x81,0x74,0xbe,0xc0, +0x6, 0x40,0x2, 0x81,0x74,0x7c,0xbf,0x20,0xe1,0x2, 0x81,0x74,0xc2,0x3, 0xe5,0x2d, +0xbe,0xb0,0x2, 0x28,0x5, 0xbe,0xc0,0x2, 0x38,0x2, 0xd2,0x3, 0x12,0x85,0xc, 0x12, +0x74,0xa0,0x7d,0x13,0x1a,0x2, 0x1a,0x0, 0x7a,0xd, 0x3b,0x7d,0x38,0x2e,0x35,0x2f, +0x12,0x6f,0xf0,0x7a,0x35,0x35,0xc2,0x2, 0xbe,0x8, 0x7f,0xff,0x78,0x5, 0x9f,0x11, +0x7a,0x1d,0x3b,0x7e,0x35,0x35,0x7a,0x35,0x44,0x12,0x85,0xc, 0x7e,0xd, 0x3b,0x12, +0x85,0xf1,0x92,0x4, 0x12,0xa0,0x41,0x92,0x1, 0x7e,0x35,0x33,0x12,0x84,0xe7,0x20, +0x1, 0x1a,0xe5,0x2d,0xbe,0xb0,0x4, 0x38,0x13,0xbe,0xc0,0x4, 0x38,0xe, 0xa, 0x2c, +0xe5,0x2d,0xa, 0x3b,0x12,0x84,0xf3,0x18,0x3, 0x12,0x84,0xe4,0x85,0x2a,0x44,0x85, +0x2b,0x45,0x85,0x2c,0x46,0x7e,0x8, 0x0, 0x3f,0x7e,0x18,0x0, 0x41,0xe5,0x29,0x12, +0x87,0x6c,0xe5,0x2d,0xa, 0x4b,0xbe,0x45,0x41,0x8, 0x7, 0xa, 0x3c,0xbe,0x35,0x41, +0x18,0x8, 0x12,0x84,0xef,0x18,0x3, 0x7e,0x95,0x3f,0x7e,0x5, 0x41,0xbe,0x4, 0x0, +0x3, 0x78,0x5, 0x7e,0x35,0x33,0x80,0x14,0xbe,0x4, 0x0, 0x4, 0x78,0x5, 0x7e,0x35, +0x35,0x80,0x9, 0xbe,0x4, 0x0, 0x5, 0x78,0x6, 0x7e,0x35,0x31,0x12,0x84,0xe7,0x7e, +0xb3,0x4d,0xc9,0xb4,0x1, 0x4, 0x7e,0x94,0x0, 0x3c,0x7e,0xb3,0x40,0x2, 0x60,0x18, +0x12,0x84,0xe4,0xe5,0x2d,0xbe,0xb0,0x2, 0x38,0xe, 0xbe,0xc0,0x2, 0x38,0x9, 0x12, +0x84,0xef,0x18,0x4, 0x7e,0x94,0x0, 0x32,0x7d,0x19,0x1a,0x2, 0x1a,0x0, 0x7e,0x1d, +0x37,0x12,0x14,0xd1,0x7e,0x8, 0x0, 0x64,0x12,0x15,0x3e,0x7f,0x1, 0x7e,0x1d,0x3b, +0xbf,0x10,0x8, 0x2, 0xd2,0x2, 0x30,0x4, 0x5, 0x20,0x3, 0x2, 0xc2,0x2, 0x30,0x2, +0x3, 0x75,0x2e,0x2, 0xe5,0x2e,0xbe,0xb0,0x0, 0x28,0x55,0xe5,0x27,0xa, 0x4b,0x9, +0x14,0x4c,0xbc,0xa5,0xb9,0x0, 0xc, 0xa, 0x3d,0x9, 0xa3,0x4c,0xbc,0x19,0xa4,0x4c, +0xbc,0x80,0x3d,0xa, 0x3d,0x9, 0x53,0x4c,0xbc,0x7a,0x51,0x43,0xbc,0x51,0x28,0x3, +0x7a,0x11,0x43,0x75,0x28,0x0, 0x80,0x23,0x9, 0x64,0x4c,0xbc,0xe5,0x28,0xa, 0xb, +0x9, 0x30,0x4c,0xbc,0xbc,0x36,0x68,0xa, 0xa, 0x3d,0x9, 0x63,0x4c,0xbc,0xbc,0x36, +0x78,0x7, 0x7e,0xa1,0x43,0x19,0xa0,0x4c,0xbc,0x5, 0x28,0xbe,0xe1,0x28,0x38,0xd8, +0x5, 0x27,0xbe,0xe1,0x27,0x28,0x2, 0x41,0x7c,0xb, 0xd0,0xbc,0xed,0x28,0x2, 0x41, +0x49,0xda,0x3b,0x22,0x7e,0x35,0x31,0x1a,0x26,0x1a,0x24,0x7a,0x1d,0x37,0x22,0xa, +0x2c,0x7d,0x34,0x2d,0x32,0xbe,0x34,0x0, 0x6, 0x22,0x90,0x13,0x80,0x93,0xa, 0x3b, +0x22,0xa, 0xb, 0x7d,0x30,0x9d,0x32,0xbe,0x34,0x0, 0x0, 0x22,0xe5,0x29,0x7e,0x71, +0x2a,0x7e,0x61,0x2b,0x7e,0x51,0x2c,0x22,0xca,0xd8,0xca,0x79,0xc2,0x0, 0x7e,0xe0, +0x3, 0xe4,0x7a,0xb3,0x4c,0xb9,0x7e,0xd3,0x3f,0xde,0x12,0x9f,0x8, 0x7e,0xf3,0x3e, +0x53,0xbe,0xf0,0x1, 0x38,0x2, 0xa1,0xe2,0x7c,0xbe,0x12,0x82,0x7, 0x4c,0xdd,0x78, +0x4, 0xc2,0x0, 0x80,0x5f,0xbe,0xd0,0x1, 0x28,0xd, 0x7e,0x73,0x4c,0xfa,0xbe,0x70, +0x6, 0x28,0x4, 0xc2,0x0, 0x80,0x4d,0xc2,0x0, 0x7e,0x53,0x3e,0x53,0xbc,0x5d,0x78, +0x11,0x12,0x87,0x8, 0x50,0x5, 0x7e,0xe0,0x3, 0x80,0x3, 0x7e,0xe0,0x1, 0xd2,0x0, +0x80,0x32,0x7e,0x43,0x4c,0xba,0xa, 0x34,0xa, 0x25,0x7d,0x12,0x9d,0x13,0xb, 0x14, +0xa, 0x3d,0xbd,0x31,0x78,0x7, 0x7e,0xe0,0x1, 0xd2,0x0, 0x80,0x17,0x7e,0x73,0x4c, +0x7c,0xa, 0x37,0x9d,0x23,0xb, 0x24,0x7e,0x73,0x4c,0xfb,0xbd,0x32,0x78,0x5, 0x7e, +0xe0,0x41,0xd2,0x0, 0x30,0x0, 0x5, 0x7c,0xbe,0x12,0x82,0x7, 0x7e,0x8, 0x4c,0xbc, +0x12,0x9d,0xb3,0x7a,0xb3,0x4c,0xb9,0x7e,0xa3,0x4c,0xb9,0x7a,0xa3,0x3e,0x53,0x74, +0x2, 0xa4,0xca,0x59,0x7e,0x18,0x4c,0x7d,0x7e,0x8, 0x3c,0xc9,0x12,0x16,0x35,0x1b, +0xfd,0x7e,0x73,0x3e,0x53,0x7a,0x73,0x4c,0xfb,0x12,0x9e,0x7f,0x7a,0xb3,0x4c,0xfa, +0x80,0xa, 0x74,0x64,0x7a,0xb3,0x4c,0xfa,0x7a,0xf3,0x4c,0xfb,0xda,0x79,0xda,0xd8, +0x22,0xca,0x79,0x7f,0x60,0x7c,0xf5,0x7c,0xe6,0x12,0x86,0x58,0x7d,0xb3,0x7c,0xbe, +0x7c,0x7f,0x12,0x86,0x58,0x2d,0x3b,0x12,0x6f,0xf0,0x7d,0xa3,0x7e,0x25,0x44,0x7d, +0x12,0x9d,0x1a,0xbe,0x14,0x0, 0x0, 0x8, 0x6, 0x7d,0x32,0x9d,0x3a,0x80,0x4, 0x6d, +0x33,0x9d,0x31,0x7d,0x12,0x1a,0x2, 0x1a,0x0, 0x9f,0x6, 0xbe,0x14,0x0, 0x0, 0x8, +0x6, 0x7d,0xd, 0x9d,0x20,0x80,0x4, 0x6d,0x22,0x9d,0x21,0x7e,0x14,0x0, 0x3, 0xad, +0x13,0xbd,0x12,0x58,0xf, 0xbe,0x24,0x0, 0x64,0x8, 0x9, 0xbe,0x34,0x0, 0x46,0x8, +0x3, 0xd3,0x80,0x1, 0xc3,0xda,0x79,0x22,0xca,0x79,0x7c,0x8b,0x7e,0xb3,0x40,0x11, +0xf5,0x49,0x7e,0x93,0x40,0x12,0x7e,0x4, 0x80,0x1, 0x7c,0xf7,0x1a,0x18,0x1b,0x14, +0x7c,0xe3,0xc1,0xf7,0x7a,0xe1,0x47,0xbe,0xe0,0x0, 0x58,0xc, 0x1a,0x5e,0x1a,0x18, +0x9d,0x15,0x1a,0x58,0x2d,0x51,0xf5,0x47,0xe5,0x49,0xbc,0xbe,0x18,0xc, 0x1a,0x58, +0x1a,0x1e,0x9d,0x15,0x1a,0x58,0x9d,0x51,0xf5,0x47,0x1a,0x5f,0x1b,0x54,0xf5,0x46, +0x80,0x47,0x85,0x46,0x48,0xe5,0x46,0xbe,0xb0,0x0, 0x58,0xe, 0xe5,0x46,0x1a,0x5b, +0x1a,0x1f,0x9d,0x15,0x1a,0x5f,0x2d,0x51,0xf5,0x48,0xbe,0x91,0x46,0x18,0xe, 0x1a, +0x3f,0xe5,0x46,0x1a,0x1b,0x9d,0x13,0x1a,0x5f,0x9d,0x51,0xf5,0x48,0xbe,0x81,0x47, +0x78,0x5, 0xbe,0xf1,0x48,0x68,0x10,0xe5,0x47,0x7e,0x71,0x48,0x12,0x23,0x82,0x7d, +0xf3,0xbd,0xf0,0x8, 0x2, 0x7d,0xf, 0x5, 0x46,0x1a,0xef,0xb, 0xe4,0xe5,0x46,0x1a, +0x1b,0xbd,0x1e,0x8, 0xad,0xb, 0xe0,0x1a,0x58,0xb, 0x54,0x1a,0x1e,0xbd,0x15,0x18, +0x2, 0xc1,0x74,0x7d,0x30,0xda,0x79,0x22,0x6c,0xaa,0x80,0x12,0x7e,0x70,0x9, 0xac, +0x7a,0x9, 0xb3,0x3d,0x4b,0xbe,0xb0,0x10,0x28,0x2, 0xd3,0x22,0xb, 0xa0,0x7e,0xb3, +0x3e,0x69,0xbc,0xba,0x38,0xe6,0xc3,0x22,0x7c,0x57,0x12,0x3c,0xd1,0x9, 0x63,0x3c, +0xca,0x90,0x14,0x7, 0xe4,0x93,0x70,0x6, 0x7e,0xa3,0x40,0x10,0x80,0x4, 0x7e,0xa3, +0x40,0xf, 0x7e,0x70,0x40,0xac,0x67,0x2e,0x34,0x0, 0x20,0x7e,0x90,0x9, 0xac,0x95, +0x59,0x34,0x3d,0x45,0x7e,0x70,0x40,0xac,0x7a,0x2e,0x34,0x0, 0x20,0x59,0x34,0x3d, +0x47,0x74,0xff,0x19,0xb4,0x3d,0x4b,0x19,0xb4,0x3d,0x4a,0x22,0x7c,0x9b,0x7f,0x71, +0x7f,0x60,0x7e,0x34,0x19,0xd6,0x7e,0x24,0x0, 0xff,0x7e,0x14,0x44,0x87,0x74,0x30, +0x12,0x15,0x93,0x7e,0x58,0x44,0x87,0x7c,0xb9,0x7e,0x71,0x44,0x12,0x23,0x82,0x7d, +0x3, 0xe5,0x45,0x7e,0x71,0x46,0x12,0x23,0x82,0x2d,0x30,0xe, 0x34,0x7f,0x5, 0x7e, +0x50,0x8, 0xb, 0xa, 0x50,0xbd,0x53,0x58,0xf, 0x69,0x30,0x0, 0x2, 0x1b,0x6a,0x30, +0x69,0x30,0x0, 0x4, 0x1b,0x7a,0x30,0x22,0x2e,0x14,0x0, 0x6, 0x1b,0x50,0x78,0xe2, +0x22,0x7c,0xab,0x7e,0xb3,0x3e,0x69,0x7e,0x93,0x3e,0x53,0x60,0x4a,0xb4,0x1, 0x5, +0xbe,0x90,0x2, 0x68,0x42,0x74,0x9, 0xa4,0x9, 0xa5,0x3d,0x4b,0xbe,0x90,0x1, 0x78, +0x24,0xbe,0xa0,0x19,0x28,0x7, 0x74,0x6, 0x7a,0xb, 0xb0,0x80,0x27,0xbe,0xa0,0x14, +0x28,0x7, 0x74,0x5, 0x7a,0xb, 0xb0,0x80,0x1b,0xbe,0xa0,0xa, 0x28,0x19,0x74,0x4, +0x7a,0xb, 0xb0,0x80,0xf, 0xbe,0x90,0x2, 0x78,0xd, 0xbe,0xa0,0x14,0x28,0x8, 0x74, +0x4, 0x7a,0xb, 0xb0,0x7a,0x1b,0xb0,0x22,0xca,0x3b,0xc2,0x0, 0x7e,0x8, 0x44,0xad, +0x7e,0x34,0x0, 0xa, 0xe4,0x12,0x16,0x5a,0x7e,0x18,0x3f,0x97,0x7a,0x1d,0x27,0x6c, +0xdd,0x80,0x19,0x7e,0xa0,0xff,0x12,0x8b,0xd1,0x74,0xff,0xa, 0x3d,0x19,0xb3,0x44, +0x9b,0xe4,0x19,0xb3,0x44,0x87,0x19,0xb3,0x44,0x91,0xb, 0xd0,0x90,0x13,0x7f,0xe4, +0x93,0xbc,0xbd,0x38,0xde,0x7e,0xa3,0x3f,0xdd,0x4c,0xaa,0x78,0x33,0x7e,0xb3,0x4f, +0x1b,0x70,0x2, 0x61,0x66,0x6c,0xdd,0x80,0x1c,0x7e,0x44,0x7f,0xff,0x7e,0x30,0x7, +0xac,0x3d,0x7e,0x1d,0x27,0x2d,0x31,0x79,0x41,0x0, 0x2, 0x7e,0x30,0x7, 0xac,0x3d, +0x12,0x8b,0xc7,0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbd,0x38,0xdb,0x61,0x66, +0x7e,0xb3,0x4f,0x1b,0x70,0x47,0xbe,0xa0,0x0, 0x28,0x42,0x6c,0xdd,0x80,0x34,0x74, +0x9, 0xac,0xbd,0x49,0x35,0x3e,0x89,0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30,0x0, 0x2, +0x74,0x9, 0xac,0xbd,0x49,0x35,0x3e,0x8b,0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30,0x0, +0x4, 0x74,0x1, 0xa, 0x3d,0x19,0xb3,0x44,0x87,0x74,0x9, 0xac,0xbd,0x19,0xd5,0x3e, +0x8d,0xb, 0xd0,0x7e,0x73,0x3f,0xdd,0xbc,0x7d,0x38,0xc4,0x61,0x66,0x6c,0xdd,0x80, +0x19,0x7e,0x34,0x7f,0xff,0x12,0x8b,0xbf,0x59,0x32,0x22,0xe4,0x59,0x32,0x22,0xe6, +0x59,0x32,0x23,0xc, 0x59,0x32,0x23,0xe, 0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0xbc, +0xbd,0x38,0xde,0x7e,0x73,0x4f,0x1b,0xbe,0x73,0x3f,0xdd,0x28,0x9, 0xbe,0x70,0x2, +0x40,0x4, 0xd2,0x0, 0x80,0x2, 0xc2,0x0, 0x6c,0xdd,0x21,0xdd,0x6c,0xff,0x21,0xd0, +0x74,0x7, 0xac,0xbf,0x7e,0x7d,0x27,0x2d,0xf5,0x69,0x7, 0x0, 0x2, 0xbe,0x4, 0x7f, +0xff,0x78,0x2, 0x21,0xce,0xa, 0x1f,0x9, 0xb1,0x44,0x91,0x60,0x2, 0x21,0xce,0x30, +0x0, 0x6c,0x74,0x2, 0xac,0xbf,0x49,0x45,0x4f,0x30,0xbe,0x44,0x7f,0xff,0x68,0x5e, +0x49,0x45,0x4f,0x30,0x69,0x27,0x0, 0x2, 0x7d,0x32,0x9d,0x34,0x2d,0x32,0x49,0x45, +0x4f,0x1c,0x69,0x57,0x0, 0x4, 0x7d,0x25,0x9d,0x24,0x2d,0x25,0xbe,0x34,0x0, 0x0, +0x58,0x2, 0x6d,0x33,0xbe,0x24,0x0, 0x0, 0x58,0x2, 0x6d,0x22,0x7e,0xa3,0x40,0x11, +0x12,0x8b,0xdb,0xbd,0x43,0x18,0x6, 0x7d,0x35,0x9e,0x34,0x0, 0x21,0x7e,0xa3,0x40, +0x12,0x12,0x8b,0xdb,0xbd,0x42,0x18,0x6, 0x7d,0x25,0x9e,0x24,0x0, 0x21,0x74,0x2, +0xac,0xbd,0x3e,0x54,0x59,0x35,0x22,0xe4,0x59,0x25,0x22,0xe6,0x80,0x12,0x74,0x2, +0xac,0xbd,0x3e,0x54,0x59,0x5, 0x22,0xe4,0x69,0x7, 0x0, 0x4, 0x59,0x5, 0x22,0xe6, +0xa, 0xd, 0x19,0xf0,0x44,0x9b,0x74,0x1, 0x19,0xb1,0x44,0x91,0x80,0xd, 0xb, 0xf0, +0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x28,0x2, 0x21,0x20,0xb, 0xd0,0x7e,0x73,0x4f, +0x1b,0xbc,0x7d,0x28,0x2, 0x21,0x1c,0x6c,0xdd,0x80,0x1f,0x74,0x7, 0xac,0xbd,0x7e, +0x1d,0x27,0x2d,0x35,0x69,0x41,0x0, 0x2, 0x74,0x2, 0xac,0xbd,0x59,0x45,0x4f,0x30, +0x69,0x31,0x0, 0x4, 0x59,0x35,0x4f,0x1c,0xb, 0xd0,0x90,0x13,0x7f,0xe4,0x93,0x7c, +0xab,0xbc,0xad,0x38,0xd6,0x6c,0xdd,0x80,0x2b,0xa, 0x3d,0x9, 0xb3,0x44,0x9b,0xb4, +0xff,0x20,0x6c,0xff,0x80,0x18,0xa, 0x4f,0x9, 0xb4,0x44,0x91,0x70,0xe, 0xa, 0x3d, +0x19,0xf3,0x44,0x9b,0x74,0x1, 0x19,0xb4,0x44,0x91,0x80,0x6, 0xb, 0xf0,0xbc,0xaf, +0x38,0xe4,0xb, 0xd0,0xbc,0xad,0x38,0xd1,0x6c,0xdd,0x80,0x1a,0x7e,0x70,0x9, 0xac, +0x7d,0x49,0x13,0x3e,0x89,0x12,0x8b,0xbf,0x59,0x12,0x23,0xc, 0x49,0x33,0x3e,0x8b, +0x59,0x32,0x23,0xe, 0xb, 0xd0,0x7e,0x73,0x3f,0xdd,0xbc,0x7d,0x38,0xde,0x7e,0x34, +0x22,0xe4,0x7a,0x37,0x44,0xa7,0x7e,0x34,0x23,0xc, 0x7a,0x37,0x44,0xa9,0x7e,0x34, +0x23,0x34,0x7a,0x37,0x44,0xab,0x7e,0x73,0x4f,0x1b,0x7a,0x73,0x44,0xa5,0x7e,0x73, +0x3f,0xdd,0x7a,0x73,0x44,0xa6,0x7e,0x8, 0x44,0xa5,0x12,0x1, 0x20,0x6c,0xdd,0x61, +0x2c,0x7e,0xa0,0xff,0x6c,0xff,0x80,0x19,0x7e,0x70,0x2, 0xac,0x7f,0x49,0x23,0x23, +0x34,0xa, 0x3d,0xbd,0x32,0x78,0x8, 0xa, 0x3f,0x9, 0xa3,0x44,0x9b,0x80,0xb, 0xb, +0xf0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xde,0xbe,0xa0,0xff,0x68,0x5b,0x12, +0x8b,0xd1,0x74,0x1, 0xa, 0x4a,0x19,0xb4,0x44,0x87,0x7e,0x70,0x7, 0xac,0x7a,0x7e, +0xd, 0x27,0x2d,0x13,0x69,0x30,0x0, 0x4, 0xbe,0x37,0x44,0x83,0x38,0x1e,0x7e,0x70, +0x9, 0xac,0x7d,0x49,0x33,0x3e,0x8b,0xbe,0x37,0x44,0x83,0x28,0xf, 0xe4,0xa, 0x4a, +0x19,0xb4,0x44,0x87,0x74,0x1, 0xa, 0x4d,0x19,0xb4,0x44,0xad,0x7e,0x70,0x9, 0xac, +0x7d,0x49,0x33,0x3e,0x89,0x79,0x30,0x0, 0x2, 0x7e,0x70,0x9, 0xac,0x7d,0x49,0x43, +0x3e,0x8b,0x7e,0x30,0x7, 0xac,0x3a,0x12,0x8b,0xc7,0xb, 0xd0,0x7e,0xb3,0x3f,0xdd, +0xbc,0xbd,0x28,0x2, 0x41,0xa1,0x6c,0xdd,0x80,0x23,0xa, 0x3d,0x9, 0xb3,0x44,0x87, +0xbe,0xb0,0x1, 0x68,0x16,0x7e,0x34,0x7f,0xff,0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30, +0x0, 0x2, 0x12,0x8b,0xb7,0x2d,0x15,0x79,0x30,0x0, 0x4, 0xb, 0xd0,0x90,0x13,0x7f, +0xe4,0x93,0xbc,0xbd,0x38,0xd4,0x6c,0xee,0x7e,0xc3,0x3f,0xdd,0x6c,0xdd,0x80,0x2a, +0xa, 0x3d,0x9, 0xb3,0x44,0xad,0x70,0x20,0x7e,0x34,0x0, 0x9, 0xca,0x39,0xac,0x7d, +0x2e,0x34,0x3e,0x89,0x6d,0x22,0x7e,0x30,0x9, 0xac,0x3e,0x2e,0x14,0x3e,0x89,0x6d, +0x0, 0x12,0x16,0x35,0x1b,0xfd,0xb, 0xe0,0xb, 0xd0,0xbc,0xcd,0x38,0xd2,0x7a,0xe3, +0x3f,0xdd,0x7e,0x73,0x3f,0xdd,0x7a,0x73,0x4f,0x1b,0x7e,0xd, 0x27,0x7e,0x18,0x44, +0x87,0x12,0x8b,0xe5,0xda,0x3b,0x22,0x74,0x7, 0xac,0xbd,0x7e,0xd, 0x27,0x22,0x7e, +0x50,0x2, 0xac,0x5d,0x3e,0x24,0x22,0x7e,0x1d,0x27,0x2d,0x31,0x79,0x41,0x0, 0x4, +0x22,0x7e,0x70,0x9, 0xac,0x7d,0x19,0xa3,0x3e,0x8d,0x22,0x74,0x40,0xa4,0x7d,0x45, +0x9e,0x44,0x0, 0x20,0x22,0xca,0x79,0x7e,0xa3,0x3f,0xdd,0x6c,0x99,0x80,0x6e,0xa, +0xf9,0x2d,0xf3,0x7d,0xe2,0x7e,0x7b,0xb0,0xb4,0x1, 0x2b,0x12,0x8c,0x65,0x2d,0xf7, +0x29,0xb7,0x0, 0x1, 0xb4,0x1, 0x6, 0x74,0x3, 0x39,0xb7,0x0, 0x1, 0x12,0x8c,0x65, +0x2d,0xf7,0x29,0x87,0x0, 0x1, 0xbe,0x80,0x3, 0x78,0x3, 0xe4,0x80,0x2e,0x4c,0x88, +0x78,0x2d,0x74,0x2, 0x80,0x26,0x12,0x8c,0x65,0x2d,0xf7,0x29,0xb7,0x0, 0x1, 0xbe, +0xb0,0x2, 0x68,0x2, 0x70,0x14,0x74,0x1, 0x7a,0x7b,0xb0,0x7c,0x8a,0xb, 0xa0,0x7e, +0xf0,0x9, 0xac,0xf8,0x19,0x97,0x3e,0x8d,0x80,0x5, 0x74,0x3, 0x7a,0x7b,0xb0,0x12, +0x8c,0x65,0x2d,0xf7,0x7e,0x7b,0xb0,0x39,0xb7,0x0, 0x1, 0xb, 0x90,0x12,0x67,0xae, +0x38,0x8d,0xda,0x79,0x22,0x7e,0xf0,0x7, 0xac,0xf9,0x7f,0x70,0x22,0xca,0xf8,0x6c, +0xaa,0x80,0x38,0x7e,0xf0,0x3, 0x7e,0x90,0x7, 0xac,0x9a,0x7f,0x10,0x2d,0x34,0x7a, +0x1b,0xf0,0x74,0x3, 0x7f,0x10,0x2d,0x34,0x39,0xb1,0x0, 0x1, 0x7e,0x34,0x7f,0xff, +0x7f,0x70,0x2d,0xf4,0x79,0x37,0x0, 0x2, 0x7f,0x70,0x2d,0xf4,0x79,0x37,0x0, 0x4, +0xe4,0x7f,0x10,0x2d,0x34,0x39,0xb1,0x0, 0x6, 0xb, 0xa0,0x90,0x13,0x7f,0xe4,0x93, +0xbc,0xba,0x38,0xbf,0xda,0xf8,0x22,0xca,0xd8,0xca,0x79,0x6d,0xee,0x7d,0xfe,0x7e, +0x73,0x3f,0xdd,0x7c,0xd7,0x7e,0xa3,0x4d,0x9e,0x4c,0xaa,0x78,0x1b,0x7e,0xb3,0x4a, +0x76,0xb4,0x1, 0x14,0x4c,0x77,0x68,0x10,0x7e,0xb3,0x3f,0xde,0x70,0x2, 0xe1,0x41, +0xbe,0xb3,0x3f,0xdd,0x78,0x2, 0xe1,0x41,0x7a,0xa3,0x4a,0x76,0xc2,0x26,0x7e,0x68, +0x3e,0x89,0x4c,0xdd,0x68,0x6, 0x7e,0xb3,0x3f,0xde,0x70,0x2b,0x6c,0xff,0x80,0x1e, +0x74,0x2, 0xac,0xbf,0x59,0xe5,0x4a,0x62,0x7e,0xa0,0xff,0x7e,0x70,0x9, 0xac,0x7f, +0x19,0xa3,0x4a,0xc, 0x74,0x1, 0xa, 0x3f,0x19,0xb3,0x4a,0x77,0xb, 0xf0,0x90,0x13, +0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xd9,0xc2,0x25,0x7e,0xb3,0x49,0xe9,0x60,0x6, 0x7e, +0xb3,0x40,0x2, 0x60,0x7, 0x12,0x8f,0xf1,0x50,0x2, 0xd2,0x25,0x12,0x8f,0x6f,0x6c, +0xff,0xc1,0xda,0x74,0x9, 0xac,0xbf,0x9, 0xe5,0x3e,0x8d,0x5e,0xe0,0xf, 0x12,0x8f, +0x46,0x38,0x2, 0xc1,0xd8,0x74,0x7, 0xac,0xbe,0x9, 0xb5,0x3f,0x97,0xbe,0xb0,0x1, +0x78,0x2, 0xc1,0xbb,0x6c,0x11,0xc1,0xae,0x7e,0x70,0x9, 0xac,0x71,0x9, 0x3, 0x4a, +0xc, 0x7a,0x1, 0x27,0xbc,0xe, 0x68,0x2, 0xc1,0xac,0x49,0x23,0x4a,0xa, 0x74,0x9, +0xac,0xbf,0x7f,0x56,0x2d,0xb5,0x69,0xe5,0x0, 0x2, 0x7d,0x5e,0x9d,0x52,0xbe,0x54, +0x0, 0x0, 0x8, 0x4, 0x9d,0xe2,0x80,0x4, 0x6d,0xee,0x9d,0xe5,0x74,0x9, 0xac,0xb1, +0x49,0x25,0x4a,0x8, 0x74,0x9, 0xac,0xbf,0x7f,0x56,0x2d,0xb5,0xb, 0x5a,0x50,0x7d, +0x35,0x12,0x85,0x5, 0x8, 0x6, 0x9d,0x52,0x7d,0x45,0x80,0x4, 0x6d,0x44,0x9d,0x43, +0x2d,0x4e,0x12,0x8f,0x4e,0x49,0xf5,0x4a,0x62,0x59,0x45,0x4a,0x62,0xe5,0x27,0xa, +0xeb,0x9, 0xbe,0x4a,0x77,0xbe,0xb0,0x0, 0x28,0x10,0x2e,0xe4,0x4a,0x77,0x14,0x7a, +0xe9,0xb0,0xbe,0x44,0x1, 0x40,0x50,0x2, 0xc1,0xd8,0xbe,0xf4,0x0, 0x32,0x28,0x8, +0xbe,0x44,0x0, 0x32,0x28,0x2, 0xd2,0x26,0xbe,0xf4,0x0, 0x1e,0x28,0xa, 0x7d,0x5f, +0x2e,0x54,0x1, 0x40,0xbd,0x54,0x40,0x3a,0xbe,0xf4,0x0, 0x1e,0x28,0x15,0xbe,0x44, +0x0, 0x1e,0x28,0xf, 0x12,0x8f,0x5f,0x50,0x2, 0xc1,0xd8,0xbe,0xf4,0x0, 0x3c,0x28, +0x2, 0xc1,0xd8,0x7d,0x5f,0x2e,0x54,0x0, 0x1e,0xbd,0x54,0x50,0x15,0xbe,0xf4,0x0, +0x1e,0x28,0xf, 0x12,0x8f,0x5f,0x50,0x2, 0xc1,0xd8,0xbe,0xf4,0x0, 0x3c,0x28,0x2, +0xc1,0xd8,0x30,0x25,0x2, 0xc1,0xd8,0xbe,0x44,0x0, 0xb4,0x28,0x56,0x7e,0x70,0x7, +0xac,0x7e,0x9, 0xb3,0x3f,0x97,0x70,0x4, 0x74,0x3, 0x80,0x2, 0x74,0x1, 0x19,0xb3, +0x3f,0x97,0x7e,0x0, 0x3, 0x7e,0xa1,0x27,0x74,0x7, 0xa4,0x19,0x5, 0x3f,0x98,0xbe, +0xd0,0x0, 0x28,0x2f,0x1b,0xd0,0x7e,0x70,0x9, 0xac,0x7f,0x2e,0x34,0x3e,0x89,0x7e, +0x14,0x44,0x87,0x74,0x9, 0x12,0x15,0x72,0x7e,0x70,0x9, 0xac,0x7d,0x12,0x67,0xb6, +0xac,0x3f,0x12,0x8f,0x56,0x7e,0x34,0x44,0x87,0x7e,0x30,0x9, 0xac,0x3d,0x12,0x8f, +0x56,0x1b,0xf0,0x12,0x8f,0x4e,0x59,0x45,0x4a,0x62,0x80,0x2c,0xb, 0x10,0x90,0x13, +0x7f,0xe4,0x93,0xbc,0xb1,0x28,0x2, 0xa1,0x68,0x80,0x1d,0x6d,0xee,0x74,0x2, 0xac, +0xbe,0x59,0xe5,0x4a,0x62,0x7e,0x0, 0xff,0x74,0x9, 0xac,0xbe,0x19,0x5, 0x4a,0xc, +0x74,0x1, 0xa, 0xee,0x19,0xbe,0x4a,0x77,0xb, 0xf0,0xbc,0xdf,0x28,0x2, 0xa1,0x43, +0x12,0x62,0xac,0xca,0x59,0x7e,0x18,0x3e,0x89,0x7e,0x8, 0x4a,0x8, 0x12,0x16,0x35, +0x1b,0xfd,0x6c,0xff,0x80,0x39,0x7e,0x70,0x9, 0xac,0x7f,0x9, 0xe3,0x4a,0xc, 0x12, +0x8f,0x46,0x28,0x29,0x7e,0x50,0x7, 0xac,0x5e,0x9, 0xb2,0x3f,0x97,0xbe,0xb0,0x1, +0x68,0x3, 0xb4,0x3, 0x18,0x6d,0x22,0x74,0x2, 0xac,0xbe,0x59,0x25,0x4a,0x62,0x74, +0xff,0x19,0xb3,0x4a,0xc, 0x74,0x1, 0xa, 0x3e,0x19,0xb3,0x4a,0x77,0xb, 0xf0,0x90, +0x13,0x7f,0xe4,0x93,0xbc,0xbf,0x38,0xbe,0x7a,0xd3,0x3f,0xdd,0xe4,0x7a,0xb3,0x49, +0xea,0xda,0x79,0xda,0xd8,0x22,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xbe,0x22,0x7e,0x1, +0x27,0x74,0x2, 0xac,0xb0,0x22,0x2e,0x14,0x3e,0x89,0x74,0x9, 0x2, 0x15,0x72,0x74, +0x9, 0xac,0xbf,0x7f,0x16,0x2d,0x35,0x29,0x1, 0x0, 0x6, 0xbe,0x0, 0x14,0x22,0x7e, +0x73,0x3f,0xde,0xbe,0x73,0x3f,0xdd,0x78,0x17,0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x1, +0x40,0xe, 0x7e,0x37,0x49,0xe7,0xbe,0x34,0x0, 0x14,0x38,0xe, 0xb, 0x34,0x80,0x6, +0x7e,0x37,0x49,0xe7,0x1e,0x34,0x7a,0x37,0x49,0xe7,0x7e,0xb3,0x3f,0xdd,0x70,0x6, +0x6d,0x33,0x7a,0x37,0x49,0xe7,0x7e,0x37,0x49,0xe7,0x22,0x7e,0x8, 0x49,0x65,0x7e, +0x34,0x0, 0xa, 0x74,0x8, 0x12,0x16,0x5a,0x7e,0x8, 0x49,0xc9,0x7e,0x34,0x0, 0xa, +0xe4,0x2, 0x16,0x5a,0x7e,0xa3,0x3f,0xde,0xbe,0xa0,0x0, 0x38,0x23,0xbe,0xa3,0x3f, +0xdd,0x50,0x18,0x7e,0xb3,0x3f,0xe7,0xbe,0xb3,0x4a,0x0, 0x28,0x13,0x7e,0xb3,0x4a, +0x0, 0x4, 0x7a,0xb3,0x4a,0x0, 0x7a,0xa3,0x3f,0xdd,0x22,0xe4,0x7a,0xb3,0x4a,0x0, +0x22,0x7e,0x73,0x3f,0xde,0xbe,0x73,0x3f,0xdd,0x78,0x7d,0x7e,0xb3,0x3f,0xdd,0xb4, +0x1, 0x76,0x7e,0xb3,0x4a,0x1, 0xbe,0xb0,0x2, 0x38,0x13,0x4, 0x7a,0xb3,0x4a,0x1, +0x7e,0x37,0x3e,0x89,0x7a,0x37,0x4a,0x4, 0x7e,0x37,0x3e,0x8b,0x80,0x69,0x7e,0x37, +0x4a,0x2, 0xbe,0x34,0x6, 0xa4,0x50,0x4e,0x7e,0x27,0x3e,0x89,0x7d,0x12,0x9e,0x17, +0x4a,0x4, 0xbe,0x14,0x0, 0x0, 0x8, 0x8, 0x7d,0x32,0x9e,0x37,0x4a,0x4, 0x80,0x4, +0x6d,0x33,0x9d,0x31,0x2e,0x37,0x4a,0x2, 0x7a,0x37,0x4a,0x2, 0x7e,0x37,0x3e,0x8b, +0x7d,0x3, 0x9e,0x7, 0x4a,0x6, 0xbe,0x4, 0x0, 0x0, 0x8, 0x8, 0x7d,0x13,0x9e,0x17, +0x4a,0x6, 0x80,0x4, 0x6d,0x11,0x9d,0x10,0x2e,0x17,0x4a,0x2, 0x7a,0x17,0x4a,0x2, +0x7a,0x27,0x4a,0x4, 0x80,0x11,0xd3,0x22,0xe4,0x7a,0xb3,0x4a,0x1, 0x6d,0x33,0x7a, +0x37,0x4a,0x2, 0x7a,0x37,0x4a,0x4, 0x7a,0x37,0x4a,0x6, 0xc3,0x22,0xca,0x79,0x7e, +0xb3,0x3f,0xdd,0x7e,0x18,0x3f,0x97,0x70,0x11,0x12,0x8f,0xab,0x7e,0x8, 0x4a,0xa9, +0x7e,0x34,0x0, 0xa, 0xe4,0x12,0x16,0x5a,0x41,0x40,0x6c,0xaa,0x41,0x35,0x7e,0xf0, +0x9, 0xac,0xfa,0x9, 0x37,0x3e,0xe7,0xc2,0x0, 0xc2,0x1, 0x49,0xe7,0x3e,0xe3,0x4d, +0xee,0x68,0x11,0x7e,0xd4,0x14,0xc, 0x7e,0xc4,0x0, 0xff,0xb, 0x6a,0xf0,0x1b,0xf4, +0xbd,0xef,0x78,0x2, 0xd2,0x0, 0x49,0xf7,0x3e,0xe5,0x4d,0xff,0x68,0x11,0x7e,0xd4, +0x14,0x1a,0x7e,0xc4,0x0, 0xff,0xb, 0x6a,0x0, 0x1b,0x4, 0xbd,0xf0,0x78,0x2, 0xd2, +0x1, 0xbe,0x30,0xff,0x78,0x2, 0x41,0x33,0x7e,0x10,0x7, 0xac,0x13,0x7f,0x61,0x2d, +0xd0,0x7e,0x6b,0xb0,0xb4,0x2, 0x2, 0x80,0x2, 0x41,0x6, 0x7e,0x10,0x4, 0xac,0x13, +0x49,0xd0,0x4a,0x81,0x7d,0xce,0x9d,0xcd,0xbe,0xc4,0x0, 0x0, 0x8, 0x6, 0x7d,0x4e, +0x9d,0x4d,0x80,0x4, 0x6d,0x44,0x9d,0x4c,0x49,0xb0,0x4a,0x83,0x7d,0xcf,0x9d,0xcb, +0xbe,0xc4,0x0, 0x0, 0x8, 0x6, 0x7d,0xf, 0x9d,0xb, 0x80,0x4, 0x6d,0x0, 0x9d,0xc, +0x7e,0x23,0x3f,0xdd,0xbe,0x20,0x8, 0x40,0x8, 0x74,0xf, 0xa, 0xca,0x19,0xbc,0x49, +0x65,0xa, 0xca,0x9, 0xbc,0x4a,0xa9,0x70,0xe, 0x7d,0xc0,0x2d,0xc4,0xbe,0xc4,0x0, +0x4, 0x50,0x4, 0x6d,0x0, 0x7d,0x40,0xa, 0xca,0x9, 0x2c,0x49,0x65,0xa, 0xc2,0xbd, +0xc4,0x28,0x56,0xbd,0xc0,0x28,0x52,0x20,0x0, 0x9, 0x7e,0xf0,0x9, 0xac,0xfa,0x59, +0xd7,0x3e,0xe3,0x20,0x1, 0x12,0x7e,0xf0,0x4, 0xac,0xf3,0x49,0xd7,0x4a,0x83,0x7e, +0xf0,0x9, 0xac,0xfa,0x59,0xd7,0x3e,0xe5,0xa, 0xda,0x2e,0xd4,0x49,0xc9,0x7e,0xd9, +0xb0,0x4, 0x7a,0xd9,0xb0,0xa, 0xda,0x9, 0xbd,0x49,0xc9,0xbe,0xb0,0x32,0x50,0x2, +0x41,0x33,0xa, 0xda,0x9, 0xbd,0x49,0x65,0xbe,0xb0,0x8, 0x50,0x76,0xa, 0xda,0x2e, +0xd4,0x49,0x65,0x4, 0x7a,0xd9,0xb0,0x80,0x6a,0x74,0x1, 0xa, 0xda,0x19,0xbd,0x4a, +0xa9,0x12,0x92,0x43,0x7e,0xf0,0x4, 0xac,0xf3,0x59,0xf7,0x4a,0x83,0xbe,0x20,0x8, +0x40,0xa, 0x74,0x3, 0xa, 0xda,0x19,0xbd,0x49,0x65,0x80,0x11,0xbe,0x20,0x1, 0x28, +0xc, 0xa, 0xda,0x2e,0xd4,0x49,0x65,0x7c,0xb2,0x14,0x7a,0xd9,0xb0,0xe4,0xa, 0xda, +0x19,0xbd,0x49,0xc9,0x80,0x2d,0x7e,0xf0,0x7, 0xac,0xf3,0x7f,0x61,0x2d,0xd7,0x7e, +0x6b,0xb0,0x70,0x9, 0x12,0x92,0x43,0x59,0xf7,0x4a,0x83,0x80,0x16,0x7e,0xf0,0x7, +0xac,0xf3,0x7f,0x71,0x2d,0xf7,0x7e,0x7b,0xb0,0xb4,0x1, 0x7, 0xe4,0xa, 0xfa,0x19, +0xbf,0x4a,0xa9,0xb, 0xa0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xba,0x28,0x2, 0x1, 0xae, +0xda,0x79,0x22,0x7e,0xf0,0x4, 0xac,0xf3,0x59,0xe7,0x4a,0x81,0x22,0x7e,0xb3,0x49, +0xea,0xbe,0xb0,0xfa,0x50,0x5, 0x4, 0x7a,0xb3,0x49,0xea,0x22,0x6c,0xaa,0x80,0x49, +0x7e,0x50,0x9, 0xac,0x5a,0x49,0x32,0x3f,0x3d,0x12,0x1f,0x18,0x59,0x32,0x3e,0x89, +0x7e,0x50,0x9, 0xac,0x5a,0x49,0x32,0x3f,0x3f,0x12,0x1f,0x18,0x59,0x32,0x3e,0x8b, +0x7e,0x90,0x9, 0xac,0x9a,0x9, 0xb4,0x3f,0x41,0x19,0xb4,0x3e,0x8d,0x7e,0x90,0x9, +0xac,0x9a,0x9, 0xb4,0x3f,0x42,0x19,0xb4,0x3e,0x8e,0x7e,0x90,0x9, 0xac,0x9a,0x9, +0xb4,0x3f,0x43,0x19,0xb4,0x3e,0x8f,0xb, 0xa0,0x90,0x13,0x7f,0xe4,0x93,0xbc,0xba, +0x38,0xae,0x22,0x7c,0x17,0x7c,0xab,0x7e,0x14,0xff,0xfc,0x7e,0x3, 0x3f,0xdd,0x7e, +0x90,0x9, 0xac,0x91,0x9, 0xb4,0x49,0x72,0xb4,0x1, 0x49,0xa5,0xb8,0x1, 0xc, 0xbe, +0x14,0xff,0x0, 0x28,0x10,0x7e,0x14,0xff,0x0, 0x80,0xa, 0xbe,0x14,0xff,0xe0,0x28, +0x4, 0x7e,0x14,0xff,0xe0,0x49,0x34,0x49,0x73,0x7e,0x50,0x9, 0xac,0x5a,0x49,0x22, +0x3e,0x89,0x12,0x93,0x9c,0x8, 0x3, 0x12,0x93,0xa6,0x7e,0x70,0x9, 0xac,0x71,0x49, +0x33,0x49,0x75,0x7e,0x50,0x9, 0xac,0x5a,0x49,0x22,0x3e,0x8b,0x12,0x93,0x9c,0x8, +0x3, 0x12,0x93,0xa6,0x7e,0x70,0x9, 0xac,0x71,0x49,0x23,0x49,0x73,0x7e,0x70,0x9, +0xac,0x7a,0x49,0x33,0x3e,0x89,0x12,0x93,0x92,0x18,0x16,0x74,0x9, 0xac,0x1b,0x49, +0x20,0x49,0x75,0x7e,0x70,0x9, 0xac,0x7a,0x49,0x33,0x3e,0x8b,0x12,0x93,0x92,0x8, +0x4, 0x7e,0x14,0xff,0xfc,0x7e,0x50,0x9, 0xac,0x5a,0x49,0x2, 0x3e,0x89,0xbe,0x4, +0x6, 0x50,0x40,0x37,0x7e,0x63,0x40,0x11,0x7e,0x70,0x40,0xac,0x67,0x9e,0x34,0x0, +0x65,0x12,0x2b,0xb4,0xbd,0x3, 0x38,0x23,0x49,0x32,0x3e,0x8b,0xbe,0x34,0x6, 0x50, +0x40,0x19,0x7e,0x3, 0x40,0x12,0x7e,0x10,0x40,0xac,0x1, 0x9e,0x4, 0x0, 0x65,0x3e, +0x4, 0x3e,0x4, 0x3e,0x4, 0x3e,0x4, 0xbd,0x30,0x28,0x4, 0x7e,0x14,0xff,0xff,0x7d, +0x31,0x22,0x9d,0x32,0x12,0x16,0x6c,0xbe,0x34,0x4, 0x0, 0x22,0x9d,0x32,0x12,0x16, +0x6c,0xbe,0x34,0x1, 0x0, 0x22,0x6c,0x0, 0x7e,0x70,0x9, 0xac,0x71,0x19,0x3, 0x49, +0x72,0x22,0x74,0x1, 0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x3e,0x74,0xb4,0x1, 0x5, 0xe4, +0x7a,0xb3,0x3e,0x88,0x12,0x5f,0xe7,0x28,0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3, +0x24,0x26,0x70,0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x4f,0x8c,0xb4,0x1, 0x5, +0xe4,0x7a,0xb3,0x3e,0x88,0x12,0x94,0x17,0x7e,0xb3,0x4d,0xc9,0x70,0xa, 0x12,0x7f, +0xa8,0x28,0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x7e,0xb3,0x4d,0x9e,0xb4,0x1, 0x17,0x7e, +0x73,0x4f,0x99,0xbe,0x70,0x3c,0x50,0xe, 0xbe,0x70,0x0, 0x28,0x9, 0xe5,0x13,0x60, +0x5, 0xe4,0x7a,0xb3,0x3e,0x88,0x22,0xc2,0x0, 0x12,0x5f,0xdf,0x50,0x30,0x6c,0x66, +0x80,0x1b,0x74,0x2, 0xac,0xb6,0x9, 0x55,0x3c,0xc9,0x9, 0x45,0x3c,0xca,0x7c,0xb5, +0x7c,0x74,0x12,0x7f,0x88,0x50,0x4, 0xd2,0x0, 0x80,0xa, 0xb, 0x60,0x7e,0x73,0x3e, +0x53,0xbc,0x76,0x38,0xdd,0x20,0x0, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x88,0x7e,0xb3, +0x40,0x4, 0xb4,0x1, 0x27,0x7e,0xb3,0x4f,0xaf,0x4, 0x7a,0xb3,0x4f,0xaf,0x7e,0x73, +0x4f,0xaf,0xbe,0x70,0x50,0x50,0xe, 0x7e,0x34,0x14,0x37,0x12,0x1d,0xf2,0x3e,0x34, +0x7a,0x37,0x3e,0x70,0x22,0xe4,0x7a,0xb3,0x40,0x4, 0x80,0x0, 0xe4,0x7a,0xb3,0x4f, +0xaf,0x22,0xd2,0x0, 0xe4,0x7a,0xb3,0x3e,0x82,0x7a,0xb3,0x3e,0x85,0x7e,0xb3,0x3e, +0x75,0xb4,0x1, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x82,0x12,0x6d,0xb8,0x78,0x14,0xe4, +0x7a,0xb3,0x3e,0x83,0x7e,0xb3,0x3e,0x76,0xb4,0x1, 0x1f,0x74,0x1, 0x7a,0xb3,0x3e, +0x83,0x80,0x17,0xbe,0xa0,0x1, 0x78,0x12,0xe4,0x7a,0xb3,0x3e,0x84,0x7e,0xb3,0x3e, +0x77,0xb4,0x1, 0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x84,0x7e,0xb3,0x3e,0x78,0xb4,0x1, +0x6, 0x74,0x1, 0x7a,0xb3,0x3e,0x85,0x4c,0xaa,0x78,0x14,0xe4,0x7a,0xb3,0x3e,0x86, +0x7e,0xb3,0x3e,0x79,0xb4,0x1, 0x1f,0x74,0x1, 0x7a,0xb3,0x3e,0x86,0x80,0x17,0xbe, +0xa0,0x1, 0x78,0x12,0xe4,0x7a,0xb3,0x3e,0x87,0x7e,0xb3,0x3e,0x7a,0xb4,0x1, 0x6, +0x74,0x1, 0x7a,0xb3,0x3e,0x87,0x7e,0xb3,0x3e,0x7e,0x70,0xb, 0xe4,0x7a,0xb3,0x3e, +0x82,0x7a,0xb3,0x3e,0x85,0xc2,0x0, 0x7e,0xb3,0x24,0x26,0x70,0xb, 0xe4,0x7a,0xb3, +0x3e,0x82,0x7a,0xb3,0x3e,0x85,0xc2,0x0, 0x7e,0xb3,0x3e,0x80,0xb4,0x1, 0xb, 0xe4, +0x7a,0xb3,0x3e,0x82,0x7a,0xb3,0x3e,0x85,0xc2,0x0, 0x20,0x0, 0x11,0xe4,0x7a,0xb3, +0x3e,0x83,0x7a,0xb3,0x3e,0x84,0x7a,0xb3,0x3e,0x86,0x7a,0xb3,0x3e,0x87,0x22,0xca, +0xd8,0xca,0x79,0x7c,0xfb,0x7f,0x70,0xc2,0x0, 0x6c,0xdd,0x9f,0x55,0x6d,0x11,0x7d, +0xc1,0x7d,0x91,0x7d,0xd1,0x7e,0x4, 0x7f,0xff,0x6c,0xee,0x80,0x21,0x12,0x96,0x62, +0xb, 0x1a,0x30,0x12,0x16,0x6c,0x7d,0x93,0xbd,0xc9,0x58,0x2, 0x7d,0xc9,0xbd,0x9, +0x8, 0x2, 0x7d,0x9, 0x7d,0x39,0x1a,0x26,0x1a,0x24,0x2f,0x51,0xb, 0xe0,0xbc,0xfe, +0x38,0xdb,0xbe,0xc4,0x0, 0x1e,0x58,0xa, 0x7e,0xb3,0x3e,0x69,0x70,0x4, 0x6d,0x33, +0xc1,0x5d,0xbe,0xc4,0x4, 0xb0,0x8, 0x2, 0xd2,0x0, 0xbe,0xc4,0x4, 0xb0,0x8, 0x11, +0x7e,0xc4,0x0, 0xa0,0x7e,0xb3,0x4d,0xc9,0xb4,0x1, 0x38,0x7e,0xc4,0x2, 0x58,0x80, +0x32,0xbe,0xc4,0x3, 0x20,0x8, 0x11,0x7e,0xc4,0x0, 0x96,0x7e,0xb3,0x4d,0xc9,0xb4, +0x1, 0x21,0x7e,0xc4,0x2, 0x26,0x80,0x1b,0xbe,0xc4,0x0, 0x0, 0x8, 0x11,0x7e,0xc4, +0x0, 0x8c,0x7e,0xb3,0x4d,0xc9,0xb4,0x1, 0xa, 0x7e,0xc4,0x1, 0xc2,0x80,0x4, 0x6d, +0x33,0x80,0x6a,0xbd,0xc, 0x8, 0x5, 0x30,0x0, 0x2, 0x7d,0xc0,0xa, 0x1f,0x12,0x96, +0x6b,0x9f,0x55,0x6c,0xee,0x80,0x1d,0x12,0x96,0x62,0xb, 0x1a,0xd0,0x7d,0x3d,0x12, +0x16,0x6c,0x7d,0x93,0xbd,0x19,0x8, 0xa, 0x7d,0x3d,0x1a,0x26,0x1a,0x24,0x2f,0x51, +0xb, 0xd0,0xb, 0xe0,0xbc,0xfe,0x38,0xdf,0x6d,0x11,0xbe,0xd0,0x0, 0x28,0x5, 0xa, +0x1d,0x12,0x96,0x6b,0xbd,0x1c,0x8, 0x4, 0x7d,0x1c,0x80,0xa, 0x6d,0x0, 0x9d,0xc, +0xbd,0x1, 0x8, 0x2, 0x7d,0x10,0x6c,0xee,0x80,0xd, 0x12,0x96,0x62,0xb, 0x1a,0xd0, +0x9d,0xd1,0x1b,0x1a,0xd0,0xb, 0xe0,0xbc,0xfe,0x38,0xef,0x7d,0x31,0xda,0x79,0xda, +0xd8,0x22,0x74,0x2, 0xac,0xbe,0x7f,0x17,0x2d,0x35,0x22,0x6d,0x0, 0x7f,0x15,0x12, +0x15,0x3e,0x7d,0x13,0x22,0x7c,0xab,0x7e,0x8, 0x3f,0x97,0x90,0x13,0x7f,0xe4,0x93, +0xbc,0xba,0x28,0x2f,0x7e,0x70,0x7, 0xac,0x7a,0x7f,0x70,0x2d,0xf3,0x7e,0x7b,0xb0, +0xbe,0xb0,0x2, 0x68,0x3, 0xb4,0x1, 0xe, 0x74,0x1, 0x7a,0x7b,0xb0,0x74,0x3, 0x2d, +0x13,0x39,0xb0,0x0, 0x1, 0x22,0x74,0x3, 0x7a,0x7b,0xb0,0x2d,0x31,0x7d,0x20,0x39, +0xb1,0x0, 0x1, 0x22,0x7e,0xa3,0x44,0x85,0x60,0x5, 0x1e,0xa0,0x14,0x78,0xfb,0x7c, +0xba,0x30,0xe0,0x2, 0xd3,0x22,0xc3,0x22,0x7d,0x43,0x6c,0xaa,0x6c,0x77,0x7e,0x63, +0x44,0x85,0x7c,0xb7,0x60,0x5, 0x1e,0x60,0x14,0x78,0xfb,0x7c,0xb6,0x30,0xe0,0xf, +0x7e,0x50,0x40,0xac,0x57,0x2e,0x24,0x0, 0x20,0xbd,0x24,0x68,0x9, 0xb, 0xa0,0xb, +0x70,0xbe,0x70,0x4, 0x40,0xd8,0xa5,0xbf,0x4, 0x4, 0x7e,0xa3,0x44,0x86,0x7c,0xba, +0x22,0xca,0x3b,0x7e,0xe3,0x40,0xf, 0x7e,0xd3,0x40,0x10,0xc2,0x2, 0x7e,0x34,0x14, +0x51,0x12,0x5f,0xef,0x7e,0x17,0x3e,0x59,0xbd,0x1d,0x58,0x4, 0x7d,0xd1,0xe, 0xd4, +0x6c,0xcc,0x2, 0x98,0x97,0x7e,0x30,0x2, 0xac,0x3c,0x9, 0xb1,0x3c,0xc9,0xf5,0x27, +0x9, 0x71,0x3c,0xca,0x7a,0x71,0x28,0x12,0x23,0x82,0x7d,0xc3,0xbd,0xdc,0x8, 0x3, +0x2, 0x98,0x95,0xbe,0xe1,0x27,0x38,0x3, 0x2, 0x98,0x95,0xbe,0xd1,0x28,0x38,0x3, +0x2, 0x98,0x95,0x7d,0x1c,0xe, 0x14,0x7d,0xec,0xe, 0xe4,0xe, 0xe4,0x2d,0xe1,0x6d, +0xff,0x12,0xad,0xa4,0x85,0x28,0x2c,0x80,0x2d,0x6c,0x99,0x7e,0xf1,0x27,0x80,0x1b, +0x7c,0xbf,0x7e,0x71,0x2c,0x12,0x98,0xaa,0x18,0x9, 0xbd,0xc0,0x48,0x5, 0x12,0x98, +0xba,0x80,0x6, 0xe5,0x2b,0xbc,0xbf,0x58,0x7, 0x1b,0xf0,0xbe,0xf0,0x0, 0x58,0xe0, +0x4c,0x99,0x68,0x9, 0x15,0x2c,0xe5,0x2c,0xbe,0xb0,0x0, 0x58,0xcc,0xa, 0x3e,0x1b, +0x34,0xe5,0x27,0xa, 0x1b,0xbd,0x13,0x58,0x3d,0x85,0x28,0x2c,0x80,0x31,0x6c,0x99, +0xe5,0x27,0xa, 0x1b,0xb, 0x14,0x7c,0x83,0x80,0x1b,0x7c,0xb8,0x7e,0x71,0x2c,0x12, +0x98,0xaa,0x18,0x9, 0xbd,0xc0,0x48,0x5, 0x12,0x98,0xb2,0x80,0x6, 0xe5,0x2a,0xbc, +0xb8,0x28,0x6, 0xb, 0x80,0xbc,0xe8,0x38,0xe1,0x4c,0x99,0x68,0x9, 0x15,0x2c,0xe5, +0x2c,0xbe,0xb0,0x0, 0x58,0xc8,0x12,0xad,0xa4,0xa, 0x3d,0x1b,0x34,0xe5,0x28,0xa, +0x1b,0xbd,0x13,0x48,0x3, 0x2, 0x98,0x7a,0xe5,0x28,0xa, 0x5b,0xb, 0x54,0xf5,0x29, +0x80,0x2a,0x6c,0x99,0x7e,0xf1,0x27,0x80,0x18,0x7c,0xbf,0x12,0x98,0xa7,0x18,0x9, +0xbd,0xc0,0x48,0x5, 0x12,0x98,0xba,0x80,0x6, 0xe5,0x2b,0xbc,0xbf,0x58,0x7, 0x1b, +0xf0,0xbe,0xf0,0x0, 0x58,0xe3,0x4c,0x99,0x68,0x7, 0x5, 0x29,0xbe,0xd1,0x29,0x38, +0xd1,0xa, 0x3e,0x1b,0x34,0xe5,0x27,0xa, 0x1b,0xbd,0x13,0x58,0x3d,0xe5,0x28,0xa, +0x5b,0xb, 0x54,0xf5,0x29,0x80,0x2e,0x6c,0x99,0xe5,0x27,0xa, 0x1b,0xb, 0x14,0x7c, +0x83,0x80,0x18,0x7c,0xb8,0x12,0x98,0xa7,0x18,0x9, 0xbd,0xc0,0x48,0x5, 0x12,0x98, +0xb2,0x80,0x6, 0xe5,0x2a,0xbc,0xb8,0x28,0x6, 0xb, 0x80,0xbc,0xe8,0x38,0xe4,0x4c, +0x99,0x68,0x7, 0x5, 0x29,0xbe,0xd1,0x29,0x38,0xcd,0x90,0x14,0x50,0xe4,0x93,0xa, +0x1b,0xbd,0x1f,0x38,0x10,0xd2,0x2, 0xe5,0x27,0x7a,0xb3,0x4f,0x8f,0xe5,0x28,0x7a, +0xb3,0x4f,0x90,0x80,0xd, 0xb, 0xc0,0x7e,0x73,0x3e,0x53,0xbc,0x7c,0x28,0x3, 0x2, +0x97,0x25,0xa2,0x2, 0xda,0x3b,0x22,0x7e,0x71,0x29,0x12,0x23,0x82,0x7d,0x3, 0xbd, +0xe0,0x22,0xb, 0xf4,0xb, 0x90,0x7a,0x81,0x2a,0x22,0xb, 0xf4,0xb, 0x90,0x7a,0xf1, +0x2b,0x22,0x6d,0x33,0x7a,0x37,0x4f,0x91,0xe4,0x7a,0xb3,0x4f,0x8f,0x7a,0xb3,0x4f, +0x90,0x7a,0xb3,0x4f,0x8c,0x7a,0xb3,0x4f,0x8d,0x7a,0xb3,0x4f,0x8e,0x22,0x7e,0x37, +0x4f,0x91,0xbe,0x34,0x0, 0x0, 0x28,0x7, 0x1b,0x34,0x7a,0x37,0x4f,0x91,0x22,0xe4, +0x7a,0xb3,0x4f,0x8d,0x7a,0xb3,0x4f,0x8e,0x7a,0xb3,0x4f,0x8c,0x22,0x7e,0x63,0x40, +0x10,0x7e,0x73,0x40,0xf, 0xac,0x76,0x7d,0x13,0x1e,0x14,0x7e,0x27,0x3e,0x57,0x2e, +0x27,0x3e,0x55,0xbd,0x21,0x38,0x16,0x1e,0x34,0x1e,0x34,0x7d,0x23,0x2e,0x24,0x0, +0x14,0xbe,0x27,0x3e,0x55,0x40,0x6, 0xbe,0x37,0x3e,0x57,0x50,0x2, 0xd3,0x22,0xc3, +0x22,0x7e,0x37,0x3e,0x57,0x2e,0x37,0x3e,0x55,0xbe,0x37,0x3e,0x6e,0x28,0x2, 0xd3, +0x22,0xc3,0x22,0xe4,0x7a,0xb3,0x3e,0x74,0x75,0x27,0x0, 0x75,0x28,0x0, 0x7e,0xb3, +0x40,0xf, 0xf5,0x29,0x7e,0xb3,0x40,0x10,0xf5,0x2a,0x7e,0x8, 0x0, 0x27,0x7e,0x37, +0x3f,0xed,0x12,0x99,0x88,0xe4,0x33,0x7a,0xb3,0x3e,0x74,0xe4,0x7a,0xb3,0x3e,0x7d, +0x12,0x99,0x31,0x33,0x7a,0xb3,0x3e,0x7d,0x74,0x1, 0x7a,0xb3,0x3e,0x7e,0x12,0x99, +0xc5,0xe4,0x33,0x7a,0xb3,0x3e,0x7e,0x22,0xca,0xd8,0xca,0x79,0x7d,0x43,0x7f,0x70, +0x12,0x7f,0xa8,0x28,0x2a,0x6c,0xff,0x80,0x21,0x12,0x9a,0x4e,0x7c,0xbe,0x7c,0x7d, +0x12,0x23,0x82,0x7d,0xd3,0x7f,0x7, 0x7c,0x7d,0x12,0x9c,0x37,0x50,0x7, 0xbd,0x4d, +0x58,0x6, 0xd3,0x80,0xb, 0xd3,0x80,0x8, 0xb, 0xf0,0x12,0x27,0xf7,0x38,0xda,0xc3, +0xda,0x79,0xda,0xd8,0x22,0xd2,0x0, 0x6c,0x99,0x80,0x31,0x74,0x2, 0xac,0xb9,0x9, +0x5, 0x4d,0x39,0x9, 0x15,0x4d,0x3a,0x12,0x9a,0x42,0x49,0x25,0x4c,0xfc,0x7d,0xf3, +0x9d,0xf2,0xbe,0xf4,0x0, 0x0, 0x8, 0x4, 0x7d,0x1f,0x80,0x4, 0x6d,0x11,0x9d,0x1f, +0xbe,0x17,0x3e,0x6c,0x28,0x4, 0xc2,0x0, 0x80,0xa, 0xb, 0x90,0x7e,0x83,0x4d,0x38, +0xbc,0x89,0x38,0xc7,0x20,0x0, 0x2d,0x6c,0x99,0x80,0x1d,0x74,0x2, 0xac,0xb9,0x9, +0x5, 0x3c,0xc9,0x9, 0x15,0x3c,0xca,0x12,0x9a,0x42,0x59,0x35,0x4c,0xfc,0x19,0x5, +0x4d,0x39,0x19,0x15,0x4d,0x3a,0xb, 0x90,0x7e,0x73,0x3e,0x53,0xbc,0x79,0x38,0xdb, +0x7a,0x73,0x4d,0x38,0x7e,0xb3,0x3e,0x53,0x70,0x5, 0xe4,0x7a,0xb3,0x4d,0x38,0xa2, +0x0, 0x22,0x7c,0xb0,0x7c,0x71,0x12,0x23,0x82,0x74,0x2, 0xac,0xb9,0x22,0x74,0x2, +0xac,0xbf,0x9, 0xe5,0x3c,0xc9,0x9, 0xd5,0x3c,0xca,0x22,0xca,0x3b,0x30,0x11,0x2, +0x61,0xbd,0x7e,0xb3,0x3e,0x53,0xf5,0x27,0x6c,0xff,0x61,0x1d,0x12,0x9a,0x4e,0x7e, +0x73,0x40,0xf, 0xbc,0x7e,0x78,0x2, 0x61,0x1b,0x12,0x9b,0xde,0x7d,0xc3,0x12,0x9b, +0xfe,0x4c,0xee,0x78,0x2, 0x6d,0xee,0x12,0x9b,0xc8,0x78,0x2, 0x6d,0xff,0x4c,0xdd, +0x78,0x2, 0x6d,0x0, 0x12,0x9b,0xc0,0x78,0x2, 0x6d,0x11,0xbe,0xe4,0x0, 0x46,0x8, +0x2, 0xb, 0xc0,0xbe,0xf4,0x0, 0x46,0x8, 0x2, 0xb, 0xc0,0xbe,0x4, 0x0, 0x46,0x8, +0x2, 0xb, 0xc0,0xbe,0x14,0x0, 0x46,0x8, 0x2, 0xb, 0xc0,0xbe,0xc0,0x2, 0x40,0x4, +0xd2,0x0, 0x80,0x2e,0x4c,0xee,0x68,0x16,0x7e,0xb3,0x40,0x11,0x14,0xbc,0xbe,0x68, +0xd, 0x4c,0xdd,0x68,0x9, 0x7e,0xb3,0x40,0x12,0x14,0xbc,0xbd,0x78,0x14,0xbe,0xc4, +0x1, 0x36,0x8, 0xe, 0xbe,0xc0,0x0, 0x28,0x9, 0x7e,0xb3,0x4f,0x6e,0xb4,0x1, 0x2, +0xd2,0x0, 0x20,0x0, 0x26,0x7d,0xd3,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x4, 0x7d,0x5d, +0x80,0xb, 0x7e,0xb3,0x4f,0x6e,0xb4,0x1, 0xb, 0x7d,0x5d,0xe, 0x54,0xe, 0x54,0xe, +0x54,0x12,0x9b,0xd0,0xc2,0x6, 0x7c,0xbf,0x12,0x26,0xfa,0xb, 0xf0,0xe5,0x27,0xbc, +0xbf,0x28,0x2, 0x41,0x6c,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x2, 0x80,0x2, 0x61,0xbd, +0x7e,0xb3,0x3e,0x54,0xf5,0x27,0x6c,0xff,0x80,0x7b,0x74,0x2, 0xac,0xbf,0x9, 0xe5, +0x3d,0x5, 0x9, 0xd5,0x3d,0x6, 0x7e,0x73,0x40,0xf, 0xbc,0x7e,0x68,0x65,0x12,0x9b, +0xde,0x12,0x9b,0xfe,0x4c,0xee,0x78,0x2, 0x6d,0xee,0x12,0x9b,0xc8,0x78,0x2, 0x6d, +0xff,0x4c,0xdd,0x78,0x2, 0x6d,0x0, 0x12,0x9b,0xc0,0x78,0x2, 0x6d,0x11,0xbe,0xe4, +0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0xf4,0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0x4, +0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0x14,0xff,0xba,0x58,0x2, 0xb, 0xc0,0xbe,0xc0, +0x2, 0x40,0x2, 0xd2,0x0, 0x20,0x0, 0x1b,0x12,0x16,0x6c,0x7d,0xd3,0x7d,0x5d,0xe, +0x54,0xe, 0x54,0x6e,0x54,0xff,0xff,0xb, 0x54,0x12,0x9b,0xd0,0xc2,0x6, 0x7c,0xbf, +0x12,0x26,0xfa,0xb, 0xf0,0xe5,0x27,0xbc,0xbf,0x28,0x2, 0x61,0x3a,0xda,0x3b,0x22, +0x7e,0xb3,0x40,0x10,0x14,0xbc,0xbd,0x22,0x7e,0xb3,0x40,0xf, 0x14,0xbc,0xbe,0x22, +0x7d,0xb4,0x3e,0xb4,0x7e,0x1f,0x22,0xe0,0x2d,0x3b,0x1b,0x1a,0x50,0x22,0x6c,0xcc, +0xc2,0x0, 0x7e,0x33,0x40,0x10,0x7c,0x9e,0xac,0x93,0xa, 0x5d,0x2d,0x45,0x7d,0x24, +0x3e,0x24,0x7e,0x5f,0x22,0xe0,0x7f,0x75,0x2d,0xf2,0xb, 0x7a,0x30,0x22,0xa, 0x53, +0x7d,0x14,0x9d,0x15,0x3e,0x14,0x2d,0x1b,0x7d,0xa, 0xb, 0xa, 0xe0,0x2d,0x54,0x3e, +0x54,0x7f,0x5, 0x2d,0x15,0xb, 0xa, 0xf0,0x7d,0x54,0x1b,0x54,0x3e,0x54,0x7f,0x5, +0x2d,0x15,0xb, 0xa, 0x0, 0x2d,0xb2,0x69,0x15,0x0, 0x2, 0x22,0x7e,0xb3,0x4f,0x6e, +0xb4,0x3, 0x3, 0x2, 0x9a,0x5b,0x22,0x7c,0x67,0x7e,0xb, 0x70,0xbc,0x7b,0x38,0x1a, +0x29,0x70,0x0, 0x2, 0xbc,0x7b,0x28,0x12,0x29,0x70,0x0, 0x1, 0xbc,0x76,0x38,0xa, +0x29,0x70,0x0, 0x3, 0xbc,0x76,0x28,0x2, 0xd3,0x22,0xc3,0x22,0xe4,0x7a,0xb3,0x3e, +0x7c,0x7a,0xb3,0x3e,0x7c,0x22,0x7c,0x5b,0x7e,0x73,0x4e,0x4e,0xa5,0xbf,0x0, 0xe, +0x7e,0x63,0x3e,0x5b,0xa, 0x17,0x19,0x61,0x4e,0x72,0x74,0x1, 0x80,0x20,0x7e,0xb3, +0x3e,0x5b,0x7e,0x8, 0x4e,0x72,0x12,0x9d,0x3, 0x40,0x17,0x7e,0x43,0x3e,0x5b,0x7e, +0x73,0x4e,0x4e,0xa, 0x37,0x19,0x43,0x4e,0x72,0x7e,0xb3,0x4e,0x4e,0x4, 0x7a,0xb3, +0x4e,0x4e,0x7e,0x73,0x4e,0x4b,0xa5,0xbf,0x0, 0xe, 0x7e,0x63,0x3e,0x5c,0xa, 0x17, +0x19,0x61,0x4e,0x4f,0x74,0x1, 0x80,0x20,0x7e,0xb3,0x3e,0x5c,0x7e,0x8, 0x4e,0x4f, +0x12,0x9d,0x3, 0x40,0x17,0x7e,0x43,0x3e,0x5c,0x7e,0x73,0x4e,0x4b,0xa, 0x37,0x19, +0x43,0x4e,0x4f,0x7e,0xb3,0x4e,0x4b,0x4, 0x7a,0xb3,0x4e,0x4b,0x7e,0xa3,0x4e,0x4e, +0xbc,0xa5,0x50,0x18,0x7e,0x73,0x4e,0x4b,0xbc,0x75,0x50,0x10,0x74,0x3, 0xac,0x5b, +0xe, 0x24,0xa, 0x17,0xa, 0x3a,0x2d,0x31,0xbd,0x32,0x48,0x5, 0x12,0x7f,0xb8,0xd3, +0x22,0xc3,0x22,0x6c,0x66,0x80,0xd, 0x7e,0xb, 0xa0,0xbc,0xab,0x78,0x2, 0xd3,0x22, +0xb, 0x14,0xb, 0x60,0xbc,0x76,0x38,0xef,0xc3,0x22,0x7c,0xab,0xbe,0xa0,0x1, 0x78, +0x41,0x12,0x1f,0xd9,0x7e,0x34,0x0, 0x78,0x7a,0x37,0x3f,0xeb,0x7e,0x34,0x0, 0x6e, +0x7a,0x37,0x3f,0xed,0x7e,0x34,0xff,0x88,0x7a,0x37,0x3f,0xef,0x7e,0x34,0x1, 0x2c, +0x7a,0x37,0x3f,0xf7,0x7e,0x34,0xfe,0xd4,0x7a,0x37,0x3f,0xf9,0x12,0x9d,0x9e,0x68, +0x4c,0x7e,0x34,0x2, 0x58,0x7a,0x37,0x3f,0xf1,0x7e,0x34,0x2, 0x26,0x7a,0x37,0x3f, +0xf3,0x22,0xbe,0xa0,0x2, 0x78,0x36,0x7e,0xb3,0x4f,0x6e,0xb4,0x3, 0x18,0x74,0x5c, +0x7a,0xb3,0x3f,0xea,0x7e,0x34,0x0, 0x5c,0x7a,0x37,0x3f,0xeb,0x7a,0x37,0x3f,0xed, +0x7e,0x34,0xff,0xa4,0x80,0x13,0x12,0x1f,0xd9,0x7e,0x34,0x1, 0x2c,0x7a,0x37,0x3f, +0xeb,0x7a,0x37,0x3f,0xed,0x7e,0x34,0xfe,0xd4,0x7a,0x37,0x3f,0xef,0x22,0x7e,0xb3, +0x4d,0x7d,0xbe,0xb0,0xaa,0x22,0x7e,0x8, 0x4f,0xae,0x7e,0x34,0x0, 0x1, 0x74,0xff, +0x2, 0x16,0x5a,0xca,0x79,0x7f,0x70,0x7e,0x3, 0x40,0x10,0x7e,0x93,0x3e,0x53,0x7e, +0x6f,0x22,0xe0,0x6c,0x11,0x6c,0x88,0x6c,0xff,0x80,0xd, 0xa, 0x1f,0x12,0x9e,0x77, +0xbc,0x78,0x40,0x2, 0x7c,0x87,0xb, 0xf0,0xbc,0x9f,0x38,0xef,0x7e,0xf0,0x1, 0xc1, +0x64,0x75,0x29,0x0, 0x6d,0xbb,0x6d,0x99,0x7d,0xa9,0x6c,0xee,0x80,0x3a,0x7e,0x30, +0x2, 0xac,0x3e,0x9, 0xb1,0x3c,0xc9,0xf5,0x27,0x9, 0xb1,0x3c,0xca,0xf5,0x28,0xa, +0x1e,0x12,0x9e,0x77,0xbc,0x7f,0x78,0x1e,0x5, 0x29,0xe5,0x27,0xa, 0x1b,0x2d,0xa1, +0xe5,0x28,0xa, 0x1b,0x2d,0x91,0xe5,0x27,0x7e,0x71,0x28,0x12,0x23,0x82,0x7d,0x83, +0xbd,0xb8,0x58,0x2, 0x7d,0xb8,0xb, 0xe0,0xbc,0x9e,0x38,0xc2,0xe5,0x29,0xbe,0xb0, +0x0, 0x28,0x2f,0xe5,0x29,0xa, 0x8b,0x7d,0x3a,0x8d,0x38,0x7d,0xa3,0x8d,0x98,0x12, +0x9e,0x6f,0x19,0xa1,0x4c,0x7d,0x7d,0x39,0x12,0x9e,0x6f,0x19,0xa1,0x4c,0x7e,0xa, +0x30,0xad,0x3a,0x7d,0x13,0x2d,0x19,0x3e,0x14,0x7f,0x16,0x2d,0x31,0x1b,0x1a,0xb0, +0xb, 0x10,0xb, 0xf0,0xbc,0x8f,0x40,0x2, 0xa1,0xe1,0x7c,0xb1,0xda,0x79,0x22,0x7c, +0xa7,0x7e,0x30,0x2, 0xac,0x31,0x22,0x7f,0x17,0x2d,0x31,0x7e,0x1b,0x70,0x22,0xca, +0x3b,0x7e,0xa0,0x64,0x6c,0x77,0x80,0x6c,0xa, 0x27,0xb, 0x24,0x7c,0x65,0x80,0x5a, +0x7e,0xf0,0x2, 0xac,0xf6,0x9, 0xb7,0x3c,0xc9,0xa, 0xb, 0x7e,0xd0,0x2, 0xac,0xd7, +0x9, 0xb6,0x3c,0xc9,0xa, 0x2b,0x7d,0x12,0x9d,0x10,0xbe,0x14,0x0, 0x0, 0x8, 0x4, +0x9d,0x20,0x80,0x4, 0x6d,0x22,0x9d,0x21,0x9, 0x47,0x3c,0xca,0xa, 0x44,0x9, 0x46, +0x3c,0xca,0xa, 0x14,0x7d,0x1, 0x9d,0x4, 0xbe,0x4, 0x0, 0x0, 0x8, 0x4, 0x9d,0x14, +0x80,0x4, 0x6d,0x11,0x9d,0x10,0x7c,0x43,0xbc,0x45,0x50,0x4, 0x7c,0x35,0x80,0x2, +0x7c,0x34,0xbc,0xa3,0x28,0x2, 0x7c,0xa3,0xb, 0x60,0x7e,0x23,0x3e,0x53,0xbc,0x26, +0x38,0x9e,0xb, 0x70,0x7e,0xb3,0x3e,0x53,0xbc,0xb7,0x38,0x8c,0xbe,0xa0,0x64,0x78, +0x2, 0x6c,0xaa,0x7c,0xba,0xda,0x3b,0x22,0xca,0x3b,0x75,0x29,0xff,0x6c,0xff,0x7e, +0xc0,0xff,0x6c,0xee,0x6c,0x99,0x6c,0x88,0x7e,0xf4,0x7f,0xff,0x6c,0xdd,0x80,0x69, +0x7e,0x70,0x2, 0xac,0x7d,0x9, 0xb3,0x3c,0xc9,0xf5,0x27,0x9, 0x73,0x3c,0xca,0x7a, +0x71,0x28,0x12,0x23,0x82,0x7d,0x3, 0xbd,0xf, 0x58,0x2, 0x7d,0xf0,0xe5,0x27,0xbe, +0xb1,0x29,0x50,0x3, 0x85,0x27,0x29,0xe5,0x27,0xbc,0xbf,0x28,0x3, 0x7e,0xf1,0x27, +0xe5,0x28,0xbc,0xbc,0x50,0x3, 0x7e,0xc1,0x28,0xe5,0x28,0xbc,0xbe,0x28,0x3, 0x7e, +0xe1,0x28,0xe5,0x29,0xa, 0x5b,0xa, 0x1f,0x9d,0x15,0xbe,0x14,0x0, 0x7, 0x18,0xc, +0xa, 0x5c,0xa, 0x1e,0x9d,0x15,0xbe,0x14,0x0, 0x7, 0x8, 0xb, 0x7e,0x14,0x1, 0xf4, +0x7a,0x17,0x4c,0xf8,0x2, 0xa0,0x3e,0xb, 0xd0,0x7e,0x73,0x3e,0x53,0xbc,0x7d,0x38, +0x8f,0x7d,0x3f,0x3e,0x34,0x12,0x7d,0x19,0x7d,0x3, 0x7c,0xdc,0x80,0x1c,0x7e,0xc1, +0x29,0x80,0x11,0x7c,0xbc,0x7c,0x7d,0x12,0x23,0x82,0xbd,0x30,0x8, 0x2, 0xb, 0x90, +0xb, 0x80,0xb, 0xc0,0xbc,0xfc,0x50,0xeb,0xb, 0xd0,0xbc,0xed,0x50,0xe0,0x7e,0x73, +0x3f,0xde,0xbe,0x70,0x3, 0x40,0x12,0x7e,0x17,0x4c,0xf8,0xbe,0x14,0x3, 0xe8,0x50, +0x2d,0xb, 0x14,0x7a,0x17,0x4c,0xf8,0x80,0x25,0xbe,0x70,0x1, 0x38,0x20,0x7e,0x17, +0x4c,0xf8,0xbe,0x14,0x0, 0x2, 0x28,0x6, 0x1b,0x15,0x7a,0x17,0x4c,0xf8,0x7e,0x17, +0x4c,0x7a,0xbe,0x14,0x1, 0xf4,0x50,0x6, 0xb, 0x14,0x7a,0x17,0x4c,0x7a,0x7e,0x73, +0x3e,0x53,0xbe,0x70,0x1, 0x40,0x37,0x7e,0x30,0x2, 0xac,0x38,0x74,0x3, 0xac,0xb9, +0xbd,0x51,0x8, 0x14,0x6d,0x11,0x7a,0x17,0x4c,0xf8,0x7e,0x17,0x4c,0x7a,0xbe,0x14, +0x1, 0xf4,0x50,0x1a,0xb, 0x14,0x80,0x12,0x7e,0x17,0x4c,0xf8,0xbe,0x14,0x3, 0xe8, +0x50,0x6, 0xb, 0x15,0x7a,0x17,0x4c,0xf8,0x6d,0x11,0x7a,0x17,0x4c,0x7a,0xda,0x3b, +0x22,0xd2,0x5, 0x12,0x7f,0xb0,0x50,0x2, 0xc3,0x22,0x7e,0x8, 0x44,0x87,0x7e,0x34, +0x0, 0x3c,0xe4,0x12,0x16,0x5a,0x6c,0xaa,0x80,0x17,0x7e,0x90,0x2, 0xac,0x9a,0x9, +0xb4,0x3c,0xc9,0x19,0xb4,0x44,0x87,0x9, 0xb4,0x3c,0xca,0x19,0xb4,0x44,0x88,0xb, +0xa0,0x7e,0x73,0x3e,0x53,0xbc,0x7a,0x38,0xe1,0x6c,0xaa,0x80,0x36,0xa, 0x2a,0xb, +0x24,0x7c,0x65,0x80,0x28,0x7e,0x50,0x2, 0xac,0x56,0x9, 0x12,0x44,0x87,0x7e,0x30, +0x2, 0xac,0x3a,0x9, 0xb1,0x44,0x87,0xbc,0xb1,0x78,0x2, 0xc2,0x5, 0x9, 0x52,0x44, +0x88,0x9, 0xb1,0x44,0x88,0xbc,0xb5,0x78,0x2, 0xc2,0x5, 0xb, 0x60,0xbc,0x76,0x38, +0xd4,0xb, 0xa0,0xbc,0x7a,0x38,0xc6,0xa2,0x5, 0x22,0xca,0x7b,0xca,0x6b,0xca,0x5b, +0xca,0x4b,0xca,0x2b,0xca,0x1b,0xca,0xb, 0xc0,0xd0,0xc0,0x83,0xc0,0x82,0xa9,0x31, +0xcd,0xc, 0xa9,0x31,0xe5,0x8, 0x12,0xa1,0x31,0xc2,0x95,0xa9,0xc1,0xcd,0xa9,0x30, +0xcd,0x7, 0xa9,0x30,0xe5,0x3, 0xa9,0xc0,0xcd,0xa9,0x32,0xcd,0x7, 0xa9,0x32,0xe5, +0x3, 0xa9,0xc2,0xcd,0xa9,0x35,0xcd,0xe, 0xa9,0x35,0xe5,0xa, 0xa9,0xc5,0xcd,0xe4, +0x7e,0x70,0x3, 0x12,0x35,0x75,0xa9,0x36,0xcd,0x7, 0xa9,0x36,0xe5,0x3, 0xa9,0xc6, +0xcd,0xa9,0x37,0xcd,0x7, 0xa9,0x37,0xe5,0x3, 0xa9,0xc7,0xcd,0xd0,0x82,0xd0,0x83, +0xd0,0xd0,0xda,0xb, 0xda,0x1b,0xda,0x2b,0xda,0x4b,0xda,0x5b,0xda,0x6b,0xda,0x7b, +0x32,0xa9,0xd5,0xea,0xa9,0xc5,0xea,0x22,0x75,0xb7,0x0, 0x75,0xb8,0x0, 0x75,0xf7, +0x0, 0x75,0xf8,0x0, 0xa9,0xd0,0xb7,0xd2,0xb8,0xa9,0xd5,0xb7,0xd2,0xbd,0xa9,0xd0, +0xf7,0xd2,0xf8,0xa9,0xd4,0xb7,0xc2,0xbc,0xa9,0xc2,0xb7,0xc2,0xba,0xa9,0xc1,0xb7, +0xc2,0xb9,0xa9,0xc3,0xb7,0xc2,0xbb,0x22,0xa2,0xac,0x92,0x2, 0xc2,0xac,0x7e,0xf, +0x4f,0xa1,0x30,0x1, 0xa, 0xb, 0x16,0xb, 0xa, 0x30,0x4e,0x70,0xc, 0x80,0x8, 0xb, +0x16,0xb, 0xa, 0x30,0x5e,0x70,0xf3,0x1b,0xa, 0x30,0xa2,0x2, 0x92,0xac,0x22,0xa, +0x7, 0xa, 0x1b,0x2d,0x10,0x3e,0x14,0x3e,0x14,0x3e,0x14,0x3e,0x14,0x6d,0x0, 0x7e, +0x18,0xbb,0x80,0x2, 0x15,0x3e,0x7e,0x8, 0x0, 0x53,0x7e,0x34,0x0, 0x3c,0xe4,0x12, +0x16,0x5a,0x7e,0x34,0x1, 0x5, 0x7a,0x37,0x0, 0x53,0x7e,0x34,0x20,0x0, 0x7a,0x37, +0x0, 0x55,0x6d,0x33,0x7a,0x37,0x0, 0x57,0x7e,0x34,0x1, 0xe0,0x7a,0x37,0x0, 0x59, +0x7e,0x34,0x28,0x30,0x7a,0x37,0x0, 0x5b,0x7e,0x34,0x18,0x1e,0x7a,0x37,0x0, 0x5d, +0x7e,0x34,0x66,0x6, 0x7a,0x37,0x0, 0x5f,0x7e,0x34,0x73,0x0, 0x7a,0x37,0x0, 0x61, +0x7e,0x34,0x14,0x2, 0x7a,0x37,0x0, 0x63,0x6d,0x33,0x7a,0x37,0x0, 0x67,0x7a,0x37, +0x0, 0x69,0x7a,0x37,0x0, 0x6b,0x7a,0x37,0x0, 0x6d,0x7a,0x37,0x0, 0x7f,0x7e,0x34, +0x38,0x1, 0x7a,0x37,0x0, 0x81,0x7e,0x34,0x4, 0x1, 0x7a,0x37,0x0, 0x83,0x7e,0x34, +0x6, 0x3, 0x7a,0x37,0x0, 0x85,0x6d,0x33,0x7a,0x37,0x0, 0x87,0x7a,0x37,0x0, 0x89, +0x7a,0x37,0x0, 0x8b,0x7a,0x37,0x0, 0x8d,0x7e,0x34,0x0, 0x3c,0xca,0x39,0x7e,0x18, +0x0, 0x53,0x7e,0x8, 0x0, 0x8f,0x12,0x16,0x35,0x1b,0xfd,0x22,0x6c,0xaa,0x7e,0x30, +0x2c,0xac,0x3a,0x12,0x2c,0x5b,0x7e,0x34,0x0, 0x2c,0xe4,0x12,0x16,0x5a,0xb, 0xa0, +0xbe,0xa0,0x3, 0x40,0xe9,0x22,0x7e,0x34,0x0, 0x2, 0x7e,0x24,0xc, 0xd0,0x7e,0x14, +0x11,0x38,0x7e,0x57,0x3, 0xbf,0x12,0xa2,0xb4,0x74,0x2, 0x2, 0xa2,0x7e,0x7a,0xb3, +0x3, 0xd5,0x7a,0xb3,0x3, 0xd6,0x22,0x6d,0x33,0x7e,0x24,0xc, 0xd0,0x7e,0x14,0x11, +0x38,0x7e,0x57,0x3, 0xaf,0x12,0xa2,0xb4,0xe4,0x2, 0xa2,0x7e,0x7e,0x34,0x0, 0x1, +0x7e,0x24,0xc, 0xd0,0x7e,0x14,0x11,0x38,0x7e,0x57,0x3, 0xb7,0x12,0xa2,0xb4,0x74, +0x1, 0x2, 0xa2,0x7e,0x7c,0x1b,0x7d,0x43,0x7e,0xa3,0x3, 0xcf,0xbe,0xa0,0x5, 0x50, +0x1e,0x7e,0x70,0x7, 0xac,0x7a,0x59,0x43,0x3, 0xdb,0x59,0x23,0x3, 0xdd,0x59,0x13, +0x3, 0xdf,0x19,0x13,0x3, 0xe1,0x7c,0xba,0x4, 0x7a,0xb3,0x3, 0xcf,0xc3,0x22,0xd3, +0x22,0x7e,0x34,0x0, 0x3, 0x7e,0x24,0xc, 0xd0,0x7e,0x14,0x11,0x38,0x7e,0x57,0x3, +0xc7,0x12,0xa2,0xb4,0x74,0x3, 0x2, 0xa2,0x7e,0x7e,0x34,0x0, 0x4, 0x7e,0x24,0xc, +0xd0,0x7e,0x14,0x11,0x38,0x74,0x1, 0x12,0xa2,0xb4,0x7e,0x73,0x4f,0x55,0x7a,0x73, +0x3, 0xd5,0x7a,0x73,0x3, 0xd6,0x22,0x7e,0xb3,0x3, 0xd2,0xb4,0x1, 0x37,0x7e,0xa3, +0x3, 0xd0,0x7a,0xa3,0x3, 0xd1,0x7e,0xb3,0x3, 0xd8,0x4, 0x7a,0xb3,0x3, 0xd8,0x7e, +0xb3,0x3, 0xd7,0x4, 0x7a,0xb3,0x3, 0xd7,0x12,0xa6,0x48,0xbe,0xb3,0x3, 0xd7,0x38, +0x14,0xe4,0x7a,0xb3,0x3, 0xd7,0x7c,0xba,0x4, 0x7a,0xb3,0x3, 0xd0,0x12,0xa3,0x5d, +0x28,0x3, 0x12,0xa3,0x56,0x22,0x74,0x3, 0x7a,0xb3,0x3, 0xd2,0x22,0x7e,0x73,0x3, +0xcf,0xbe,0x73,0x3, 0xd0,0x22,0x12,0xa3,0x5d,0x38,0x2, 0xe4,0x22,0x7e,0xa3,0x3, +0xd0,0x74,0x7, 0xa4,0x49,0x55,0x3, 0xdb,0x12,0xa3,0x7e,0xe4,0x33,0x22,0x7c,0x3b, +0xd2,0x2, 0x12,0xa6,0x6f,0x12,0xa6,0x52,0x1b,0x30,0x68,0x1d,0x1b,0x30,0x68,0x23, +0x1b,0x30,0x68,0x29,0x1b,0x30,0x68,0x2f,0xb, 0x32,0x78,0x73,0x12,0x35,0x38,0x7e, +0x1f,0x3, 0xb3,0x7e,0xf, 0x3, 0xaf,0x80,0x52,0x7e,0x1f,0x3, 0xbb,0x7e,0xf, 0x3, +0xb7,0x80,0x48,0x7e,0x1f,0x3, 0xc3,0x7e,0xf, 0x3, 0xbf,0x80,0x3e,0x7e,0x1f,0x3, +0xcb,0x7e,0xf, 0x3, 0xc7,0x80,0x34,0x7e,0x34,0x0, 0x8, 0xca,0x39,0x7e,0x71,0x13, +0x74,0x8, 0xac,0x7b,0x2e,0x34,0x3, 0xaf,0x6d,0x22,0x7e,0x8, 0x49,0x49,0x12,0x16, +0x35,0x1b,0xfd,0x7e,0x34,0x0, 0x1, 0x7a,0x37,0x49,0x49,0x7e,0x73,0x4f,0x98,0x7a, +0x73,0x49,0x4b,0x7e,0x1f,0x49,0x4d,0x7e,0xf, 0x49,0x49,0x7a,0x1d,0x42,0x7a,0xd, +0x3e,0x12,0x2, 0x3d,0x74,0x1, 0x7a,0xb3,0x3, 0xd2,0x12,0xd, 0xbd,0x80,0x2, 0xc2, +0x2, 0xa2,0x2, 0x22,0x7e,0xb3,0x3, 0xd2,0xb4,0x1, 0x2, 0x80,0x2, 0x81,0xb7,0x7e, +0x73,0x3, 0xcf,0xbe,0x73,0x3, 0xd1,0x28,0x74,0x7e,0x63,0x3, 0xd1,0x7e,0x70,0x7, +0xac,0x67,0x49,0x53,0x3, 0xdb,0x7c,0xab,0x7e,0x43,0x3, 0xd8,0x7e,0x50,0x2, 0xac, +0x45,0x2d,0x32,0x49,0x33,0x3, 0xdd,0x7a,0x35,0x11,0x4d,0x33,0x68,0x4f,0xd2,0x2f, +0x1b,0xa0,0x68,0x10,0x1b,0xa0,0x68,0xc, 0x1b,0xa0,0x68,0x8, 0x1b,0xa0,0x68,0x4, +0xb, 0xa2,0x78,0x39,0x12,0xa4,0xb8,0x30,0x14,0x4, 0x74,0x2, 0x80,0x2, 0x74,0x1, +0x7e,0xa3,0x3, 0xd8,0xa, 0x3a,0x19,0xb3,0x3, 0xd3,0x7e,0xb3,0x3, 0xd8,0x70,0xe, +0x7e,0x73,0x3, 0xda,0xbe,0x70,0x1, 0x28,0x5, 0x12,0xb, 0xe5,0x80,0xf, 0x7e,0xf, +0x4f,0xa1,0xb, 0x16,0xb, 0xa, 0x30,0x5e,0x60,0xef,0x1b,0xa, 0x30,0x12,0xa3,0x5d, +0x38,0x15,0x74,0x2, 0x7a,0xb3,0x3, 0xd2,0xc2,0x2a,0x12,0x1b,0xed,0x12,0x1f,0xea, +0xe5,0x13,0x70,0x3, 0x2, 0x35,0x1, 0x22,0xca,0x69,0xca,0xf8,0x7e,0xd5,0x11,0x6d, +0xcc,0x7e,0xf3,0x3, 0xd8,0x7e,0xb3,0x40,0x21,0x60,0xa, 0x7e,0x47,0x40,0x15,0x7e, +0xf7,0x40,0x17,0x80,0x8, 0x7e,0xf7,0x40,0x15,0x7e,0x47,0x40,0x17,0x20,0x2f,0x2, +0xc1,0x1a,0x7e,0x17,0x44,0x81,0x7e,0x24,0x0, 0xa, 0xa9,0xd7,0xea,0x7e,0x5f,0x1, +0x5f,0x69,0x55,0x2, 0x64,0x69,0xe5,0x0, 0xc, 0x4d,0xe5,0x7e,0xd0,0x8, 0xac,0xdf, +0x59,0xe6,0x0, 0xcb,0x69,0xe5,0x2, 0x5c,0x69,0x55,0x0, 0x4, 0x4d,0x5e,0x59,0x56, +0x0, 0xcd,0x69,0xe5,0x2, 0x5a,0x69,0x55,0x0, 0x2, 0xbd,0x5e,0x28,0x8, 0x69,0x55, +0x0, 0x2, 0x7d,0x35,0x80,0x4, 0x69,0x35,0x2, 0x5a,0x74,0x8, 0xac,0xbf,0x59,0x35, +0x0, 0xcf,0xb, 0x5a,0x50,0x12,0xa6,0x3c,0x19,0xa3,0x0, 0xd1,0x69,0x55,0x2, 0x58, +0x12,0xa6,0x3c,0x19,0xa3,0x0, 0xd2,0x6d,0xee,0x7d,0x3e,0xbe,0x34,0x0, 0x1, 0x78, +0x4, 0xb, 0x24,0x80,0x23,0x7c,0xb7,0x7e,0xb4,0x0, 0x1, 0x60,0x5, 0x3e,0xb4,0x14, +0x78,0xfb,0x7e,0xb3,0x40,0x13,0xa, 0x5b,0x5d,0x5b,0x68,0x5, 0x12,0xa6,0x1f,0x80, +0x7, 0x6d,0x55,0x12,0xa6,0x2e,0xb, 0x24,0xb, 0x34,0xbe,0x34,0x0, 0x3, 0x78,0xcb, +0x7e,0xb3,0x40,0x21,0x60,0x4, 0x7d,0x4, 0x80,0x2, 0x7d,0xe, 0x7d,0x3e,0x80,0x18, +0x7d,0x53,0x2d,0x52,0x3e,0x54,0x7e,0x5f,0x1, 0x5f,0x2d,0xb5,0xb, 0x5a,0x50,0x7d, +0xb0,0xb, 0x4, 0x12,0xa6,0x32,0xb, 0x34,0xbd,0xf3,0x38,0xe4,0x7e,0x24,0x1, 0x36, +0x7d,0x3e,0xbe,0x34,0x0, 0x1, 0x78,0x4, 0xb, 0x24,0x80,0x23,0x7c,0xb7,0x7e,0xb4, +0x0, 0x1, 0x60,0x5, 0x3e,0xb4,0x14,0x78,0xfb,0x7e,0xb3,0x40,0x14,0xa, 0x5b,0x5d, +0x5b,0x68,0x5, 0x12,0xa6,0x1f,0x80,0x7, 0x6d,0x55,0x12,0xa6,0x2e,0xb, 0x24,0xb, +0x34,0xbe,0x34,0x0, 0x3, 0x78,0xcb,0x7e,0xb3,0x40,0x21,0x60,0x2, 0x7d,0xe, 0x7d, +0x3e,0x80,0x1e,0x7d,0x52,0xb, 0x24,0x3e,0x54,0x7e,0x5f,0x1, 0x5f,0x2d,0xb5,0xb, +0x5a,0x50,0x7d,0xe0,0xb, 0x4, 0x3e,0xe4,0x7f,0x56,0x2d,0xbe,0x1b,0x5a,0x50,0xb, +0x34,0xbd,0x43,0x38,0xde,0xa9,0xc7,0xea,0xc2,0x2f,0xda,0xf8,0xda,0x69,0x22,0x7d, +0x52,0xb, 0x24,0x3e,0x54,0x7e,0x5f,0x1, 0x5f,0x2d,0xb5,0xb, 0x5a,0x50,0x7d,0xb1, +0xb, 0x14,0x3e,0xb4,0x2d,0xbd,0x7d,0xac,0x1b,0x5a,0x50,0x22,0x5e,0x54,0x0, 0x7f, +0x7c,0xab,0x7e,0x70,0x8, 0xac,0x7f,0x22,0x7e,0x70,0x7, 0xac,0x7a,0x9, 0xb3,0x3, +0xe1,0x22,0x6c,0xaa,0x7e,0xb3,0x4f,0x4c,0xa, 0x3b,0x1e,0x34,0xb, 0x34,0x7e,0x50, +0x8, 0xac,0x5a,0x19,0x72,0x3, 0xb4,0xb, 0xa0,0xbe,0xa0,0x4, 0x40,0xe6,0x22,0xe5, +0x13,0x70,0x21,0x7e,0x37,0x4f,0x52,0x4d,0x33,0x78,0xf8,0x12,0x69,0xbd,0x7e,0x34, +0x0, 0x5, 0x7a,0x37,0x4f,0x52,0xbe,0x34,0x0, 0x21,0x28,0x8, 0x7e,0x34,0x0, 0x21, +0x7a,0x37,0x4f,0x52,0x22,0x12,0xa6,0xf6,0xe5,0x13,0x70,0x5, 0x12,0x36,0x22,0x80, +0x3, 0x12,0x37,0xc9,0x2, 0xa6,0xa7,0x6c,0x77,0x7e,0x30,0x3b,0x7e,0xa0,0x3c,0x7e, +0xb3,0x4d,0x9e,0xb4,0x1, 0xf, 0xe5,0x13,0x60,0xb, 0x7e,0x23,0x4f,0x9c,0xbc,0x27, +0x78,0x3, 0x12,0xa7,0xc2,0x7e,0xb3,0x4d,0x9e,0xb4,0x1, 0x29,0xe5,0x13,0x60,0x25, +0x7e,0xb3,0x4f,0x9c,0xbc,0xb3,0x78,0x3, 0x12,0x4f,0x71,0x7e,0xb3,0x4f,0x9c,0x7a, +0xb3,0x4f,0x99,0x4, 0x7a,0xb3,0x4f,0x9c,0x7e,0x73,0x4f,0x9c,0xbc,0x7a,0x28,0x5, +0xe4,0x7a,0xb3,0x4f,0x9c,0x22,0x30,0x22,0x24,0xc2,0x22,0x7e,0x73,0x4d,0x77,0x7a, +0x73,0x4d,0x9e,0x74,0xff,0x7a,0xb3,0x4d,0x77,0x7e,0xa3,0x4d,0x9e,0x4c,0xaa,0x78, +0x5, 0x12,0x4f,0x64,0x80,0x7, 0xbe,0xa0,0x1, 0x78,0x2, 0xd2,0x1c,0x30,0x1c,0x3, +0x12,0xa7,0x89,0x7e,0xb3,0x4d,0x9e,0x14,0x68,0x35,0x1b,0xb1,0x68,0x39,0x24,0x3, +0x78,0x48,0x12,0xa7,0x81,0x38,0x7, 0x7e,0xb3,0x4f,0x8c,0xb4,0x1, 0x3, 0x2, 0x4f, +0x5d,0x7e,0xb3,0x4d,0x7f,0x30,0xe0,0x38,0x7e,0x17,0x4f,0x9a,0x7e,0x4, 0x3, 0xe8, +0x8d,0x10,0x7e,0x73,0x4d,0x80,0xa, 0x37,0xbd,0x13,0x40,0x24,0x2, 0xa7,0x89,0x12, +0xa7,0x81,0x28,0x1c,0x2, 0x4f,0xf9,0x7e,0x34,0x13,0x87,0x12,0x1d,0xf2,0x12,0x1d, +0x19,0x12,0x35,0xf0,0x12,0x1d,0xb8,0x2, 0x4f,0x64,0x74,0x1, 0x7a,0xb3,0x4d,0x9e, +0x22,0x7e,0x73,0x3f,0xdd,0xbe,0x70,0x0, 0x22,0xe5,0x13,0xb4,0x1, 0xc, 0x7e,0xb3, +0x24,0x27,0x60,0x6, 0xe4,0x7a,0xb3,0x4d,0x9e,0x22,0xc2,0x1c,0x74,0x1, 0x7a,0xb3, +0x4d,0x9e,0x12,0x4f,0x5d,0xe4,0x7a,0xb3,0x4f,0x9c,0x7a,0xb3,0x4f,0x99,0x12,0x33, +0x91,0x5e,0x34,0x0, 0x2, 0x68,0xa, 0x7e,0xb3,0x44,0x80,0x44,0x8, 0x7a,0xb3,0x44, +0x80,0x22,0x12,0x33,0x91,0x5e,0x34,0x0, 0x1, 0x68,0x4, 0xd2,0x1b,0xc2,0x1e,0x22, +0x80,0x3, 0x12,0x37,0x84,0x30,0x16,0xfa,0x22,0xc2,0x1d,0x22,0xd2,0x2, 0x12,0x45, +0xf2,0x12,0x0, 0x1e,0x70,0xfb,0x22,0x30,0x1b,0x2a,0xc2,0x1b,0xd2,0x1d,0x12,0x33, +0x91,0x5e,0x34,0x0, 0x2, 0x74,0x1, 0x68,0x5, 0x12,0x5, 0x30,0x80,0x3, 0x12,0x2d, +0x29,0x7e,0x34,0x0, 0x1, 0x7e,0xa1,0x13,0x74,0x8, 0xa4,0x59,0x35,0x3, 0xaf,0xe5, +0x13,0x2, 0x2f,0xb7,0x30,0x1e,0x33,0xc2,0x1e,0xc2,0x1d,0x12,0x33,0x91,0x5e,0x34, +0x0, 0x2, 0x74,0x1, 0x68,0x5, 0x12,0x5, 0xbc,0x80,0x3, 0x12,0x2d,0x29,0x7e,0xb3, +0x4f,0x4d,0xb4,0x1, 0xe, 0x7e,0x34,0x0, 0x2, 0x7e,0xa1,0x13,0x74,0x8, 0xa4,0x59, +0x35,0x3, 0xaf,0xe5,0x13,0x12,0x2f,0xb7,0x80,0x7, 0x30,0x1d,0x4, 0xe5,0x13,0x70, +0x3, 0x2, 0x1c,0x24,0x22,0x30,0x1d,0x8, 0xe5,0x13,0xb4,0x1, 0x3, 0x2, 0x1c,0x24, +0x22,0x7c,0xab,0x7e,0x8, 0x0, 0x6d,0x7e,0x70,0xa, 0xac,0x7a,0x9, 0xb3,0x4c,0x47, +0x12,0xc, 0x3e,0x7e,0x8, 0x0, 0xa9,0x74,0xa, 0xa4,0x9, 0xb5,0x4c,0x47,0x12,0xc, +0x3e,0x7e,0x34,0x0, 0xd, 0x7e,0x8, 0x0, 0x6d,0x7e,0x24,0x0, 0x1, 0x2, 0xc, 0xcc, +0xca,0xd8,0xca,0x79,0x7c,0xf7,0x7c,0xeb,0xe4,0x12,0x4f,0xc9,0x6c,0xdd,0x7e,0x70, +0xb5,0xac,0x7d,0x2e,0x34,0x1, 0x0, 0x2e,0x34,0x0, 0x16,0x7a,0x35,0x29,0x12,0x7, +0x40,0x7a,0x35,0x2b,0x7e,0x35,0x29,0x12,0x8, 0x0, 0x7a,0x35,0x2d,0x7e,0x25,0x2b, +0x5e,0x50,0xf8,0x7a,0x25,0x2b,0x5e,0x70,0xf8,0x7a,0x35,0x2d,0x7c,0xbe,0x54,0x5, +0xa, 0x3b,0x4e,0x35,0x2b,0x7a,0x35,0x2b,0x7c,0xbf,0x54,0x5, 0xa, 0x3b,0x4e,0x35, +0x2d,0x7a,0x35,0x2d,0x7e,0x35,0x29,0x7e,0x25,0x2b,0x12,0x6, 0x48,0x7e,0x35,0x29, +0x7e,0x25,0x2d,0x12,0x6, 0xc5,0xb, 0xd0,0xbe,0xd0,0x3, 0x40,0xa1,0xda,0x79,0xda, +0xd8,0x22,0x7c,0xab,0x74,0x27,0xa4,0x49,0x25,0x4b,0xa9,0xb, 0x24,0x7e,0x37,0x4e, +0x45,0xad,0x32,0x7e,0x8, 0x0, 0x69,0x12,0xa9,0x1d,0x2, 0xc, 0xcc,0x6d,0x22,0x12, +0xd, 0x3e,0x7e,0x8, 0x0, 0xa5,0x6d,0x22,0x12,0xd, 0x3e,0x7e,0x34,0x0, 0xb, 0x7e, +0x8, 0x0, 0x69,0x7e,0x24,0x0, 0x2, 0x22,0x7c,0xab,0x6d,0x33,0xbe,0xa0,0x4, 0x50, +0x27,0x6c,0x55,0x80,0x16,0x7e,0x10,0x2, 0xac,0x15,0x7e,0x30,0x27,0xac,0x3a,0x2d, +0x10,0x49,0x11,0x4b,0xa9,0xb, 0x14,0x2d,0x31,0xb, 0x50,0x7e,0x30,0x27,0xac,0x3a, +0x9, 0x41,0x4b,0xa4,0xbc,0x45,0x50,0xdd,0x4d,0x33,0x78,0x2, 0xb, 0x34,0x22,0xbe, +0xb0,0x4, 0x50,0x37,0x7e,0x37,0x0, 0x85,0x5e,0x70,0xf0,0x7a,0x37,0x0, 0x85,0xa, +0x3b,0x4e,0x37,0x0, 0x85,0x7a,0x37,0x0, 0x85,0x7a,0x37,0x0, 0xc1,0x7e,0x34,0x0, +0x19,0x7e,0x8, 0x0, 0x85,0x7e,0x24,0x0, 0x1, 0x12,0x3, 0xfa,0x7e,0x34,0x0, 0x19, +0x7e,0x8, 0x0, 0xc1,0x7e,0x24,0x0, 0x1, 0x2, 0x4, 0x96,0x22,0x7c,0x1b,0x7e,0xa3, +0x44,0x85,0xc2,0x2, 0xa, 0xf1,0x7e,0xd4,0x2, 0x3c,0xad,0xdf,0x7d,0x3d,0x12,0xaa, +0x22,0x6d,0x22,0x6d,0x11,0x7d,0x41,0x80,0x10,0x7d,0xed,0x2d,0xe4,0x9, 0xbe,0x31, +0x9d,0x70,0x4, 0xd2,0x2, 0x80,0xa, 0xb, 0x44,0x7e,0xe7,0x44,0x81,0xbd,0xe4,0x38, +0xe8,0x7d,0x41,0x7c,0xba,0x54,0x1, 0xb4,0x1, 0x13,0x7d,0x14,0x3e,0x14,0x2d,0x13, +0x7d,0x2, 0xb, 0xa, 0x10,0x4d,0x11,0x78,0x4, 0xd2,0x2, 0x80,0xa, 0x1e,0xa0,0xb, +0x44,0xbe,0x44,0x0, 0x4, 0x40,0xdc,0x30,0x2, 0x10,0x7e,0xb3,0x4f,0x97,0xbe,0xb0, +0x0, 0x28,0xd, 0x14,0x7a,0xb3,0x4f,0x97,0xc3,0x22,0x74,0x5, 0x7a,0xb3,0x4f,0x97, +0xd3,0x22,0x2e,0x37,0x44,0x81,0x2e,0x34,0x31,0x9d,0x22,0xca,0x79,0x7c,0x5b,0x7e, +0x40,0xff,0x7e,0xa0,0xff,0x6c,0x33,0x41,0xbf,0xbc,0x63,0x78,0x2, 0x41,0xbd,0x7e, +0x90,0x2, 0xac,0x93,0x9, 0x24,0x3c,0xc9,0xa, 0xf2,0xa, 0x5, 0x9d,0xf, 0xbe,0x4, +0x0, 0x0, 0x8, 0xc, 0xa, 0xe2,0xa, 0xf5,0x9d,0xfe,0x7d,0x7f,0x7c,0x2f,0x80,0x8, +0x6e,0x4, 0xff,0xff,0xb, 0x4, 0x7c,0x21,0x7e,0x10,0x2, 0xac,0x13,0x9, 0xb0,0x3c, +0xca,0xa, 0xb, 0xa, 0x47,0x9d,0x40,0xbe,0x44,0x0, 0x0, 0x8, 0x8, 0xa, 0xfb,0xa, +0x7, 0x9d,0xf, 0x80,0x4, 0x6d,0x0, 0x9d,0x4, 0xbe,0x20,0x1, 0x38,0xa, 0xbe,0x10, +0x1, 0x38,0x5, 0x7e,0xa0,0x1, 0x80,0x31,0xbe,0x20,0x2, 0x38,0xa, 0xbe,0x10,0x2, +0x38,0x5, 0x7e,0x40,0x2, 0x80,0x10,0x30,0x0, 0xd, 0xbe,0x20,0x3, 0x38,0x8, 0xbe, +0x10,0x3, 0x38,0x3, 0x7e,0x40,0x3, 0xbc,0x4a,0x50,0x2, 0x7c,0xa4,0xb, 0x30,0x7e, +0x3, 0x3e,0x53,0xbc,0x3, 0x28,0x2, 0x41,0x39,0x7c,0xba,0xda,0x79,0x22,0xe4,0x7a, +0xb3,0x3e,0x68,0x12,0xaa,0xea,0xe4,0x12,0x77,0xb2,0x7e,0xb3,0x24,0x26,0xb4,0x1, +0x8, 0x7e,0x73,0x3e,0x53,0x7a,0x73,0x3e,0x67,0x22,0x6c,0x33,0x80,0x9, 0xe4,0xa, +0x33,0x19,0xb3,0x3d,0x41,0xb, 0x30,0x90,0x13,0x80,0xe4,0x93,0xc4,0x23,0x54,0x1f, +0xa, 0x2b,0xb, 0x24,0xa, 0x33,0xbd,0x32,0x48,0xe4,0x12,0xac,0x2a,0x6d,0x33,0x7a, +0x37,0x3e,0x55,0x7a,0x37,0x3e,0x57,0x7a,0x37,0x3e,0x59,0x7a,0x37,0x3e,0x5d,0x7e, +0xd4,0x44,0x89,0x1e,0xd4,0x3e,0xd4,0x6d,0xcc,0x7e,0x1f,0x22,0xe0,0x7a,0x37,0x44, +0xc9,0x7d,0x3d,0x7a,0x37,0x44,0xcd,0x7e,0x34,0x23,0x34,0x7a,0x37,0x44,0xcb,0x7e, +0x73,0x40,0xf, 0x7a,0x73,0x44,0xc6,0x7e,0x73,0x40,0x10,0x7a,0x73,0x44,0xc5,0x7e, +0x37,0x3f,0xed,0x7a,0x37,0x44,0xcf,0x7e,0x37,0x3f,0xef,0x7a,0x37,0x44,0xd1,0x7e, +0x37,0x3f,0xf7,0x7a,0x37,0x44,0xd3,0x7e,0x37,0x3f,0xf9,0x7a,0x37,0x44,0xd5,0x12, +0x84,0xfa,0x1b,0x34,0x7a,0x73,0x44,0xc7,0x7e,0x73,0x4f,0xb1,0x7a,0x73,0x44,0xc8, +0x7e,0x8, 0x44,0xc5,0x7e,0x18,0x44,0xd7,0x12,0x3, 0x1d,0x7e,0x73,0x44,0xd7,0x7a, +0x73,0x3e,0x53,0x7e,0x73,0x44,0xd8,0x7a,0x73,0x3e,0x54,0x7e,0x37,0x44,0xd9,0x7a, +0x37,0x3e,0x55,0x7e,0x37,0x44,0xdb,0x7a,0x37,0x3e,0x57,0x7e,0x37,0x44,0xe1,0x7a, +0x37,0x3e,0x59,0x7e,0x37,0x44,0xe3,0x7d,0x23,0x7a,0x53,0x3e,0x5b,0xa, 0x36,0x7a, +0x73,0x3e,0x5c,0x7e,0x37,0x44,0xdd,0x7a,0x37,0x3e,0x5d,0x7e,0x37,0x44,0xdf,0x7d, +0x23,0x7a,0x53,0x3e,0x5f,0xa, 0x36,0x7a,0x73,0x3e,0x60,0x6c,0x33,0x80,0x1b,0x12, +0x26,0xf6,0x74,0x2, 0xac,0xb3,0x49,0x45,0x23,0x34,0xa, 0x38,0x7c,0x27,0x19,0x25, +0x3c,0xc9,0x7c,0x29,0x19,0x25,0x3c,0xca,0xb, 0x30,0x7e,0x23,0x3e,0x53,0xbc,0x23, +0x38,0xdd,0x6c,0x33,0x80,0x1b,0x74,0x2, 0xac,0xb3,0x7f,0x16,0x2d,0x35,0xb, 0x1a, +0x40,0xa, 0x38,0x7c,0x27,0x19,0x25,0x3d,0x5, 0x7c,0x29,0x19,0x25,0x3d,0x6, 0xb, +0x30,0x7e,0x23,0x3e,0x54,0xbc,0x23,0x38,0xdd,0x22,0xe4,0x7a,0xb3,0x3e,0x53,0x7a, +0xb3,0x3e,0x54,0x22,0x7e,0x34,0x1, 0x16,0x7e,0x8, 0x44,0x87,0x7e,0x24,0x0, 0x12, +0x12,0x3, 0xfa,0x7e,0x34,0x1, 0x16,0x7e,0x8, 0x44,0xab,0x7e,0x24,0x0, 0x12,0x12, +0x4, 0x96,0x12,0x1c,0x24,0xd2,0x2, 0x12,0x45,0xf2,0x7e,0x34,0x4, 0x68,0x22,0x3e, +0x24,0x2e,0x24,0x46,0xf1,0xb, 0x28,0x30,0x4d,0x31,0x1b,0x28,0x30,0x22,0x75,0x13, +0x2, 0x74,0x2, 0x7a,0xb3,0x4f,0x55,0x74,0x1, 0x2, 0x5, 0xbc,0x69,0x32,0x0, 0x2, +0x7d,0x13,0x5e,0x14,0x0, 0xf, 0x3e,0x14,0x3e,0x14,0xa, 0x24,0x5e,0x24,0x0, 0x3, +0x4d,0x21,0x22,0x6d,0x33,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x16,0x7e,0x34,0x1, +0x2c,0x7e,0xf, 0x4f,0xa1,0x79,0x30,0x0, 0x18,0x22,0x7a,0xb3,0x3, 0xd3,0x7a,0xb3, +0x3, 0xd4,0x7a,0xb3,0x3, 0xd7,0x74,0xff,0x7a,0xb3,0x3, 0xd8,0x22,0x7d,0x36,0x3e, +0x34,0x49,0x73,0x40,0x22,0x22,0x7e,0x8, 0x44,0x87,0x7e,0x34,0x0, 0x48,0x22,0xa, +0x25,0x2d,0x21,0x7d,0x13,0x1e,0x14,0x3e,0x14,0x59,0x21,0x47,0x39,0xb, 0x35,0x22, +0x7e,0x37,0x3f,0xef,0x7e,0x14,0x0, 0x6, 0xad,0x31,0x7e,0x44,0x0, 0x4, 0x7d,0x24, +0x22,0x74,0x2, 0xac,0xbd,0x9, 0xf5,0x3c,0xc9,0x9, 0xe5,0x3c,0xca,0x7c,0xbf,0x7c, +0x7e,0x22,0x7e,0x57,0x44,0x81,0x3e,0x54,0x7e,0x1f,0x22,0xe0,0x2d,0x35,0xb, 0x1a, +0x50,0x22,0x12,0x6, 0x48,0x6d,0x33,0x7e,0x27,0x44,0xcf,0x22,0x7e,0x34,0x0, 0x2, +0x7e,0x27,0x44,0xd3,0x5e,0x40,0x9c,0x4e,0x40,0x21,0x22,0x7e,0x18,0xc, 0xd0,0x7e, +0x8, 0x44,0xe1,0x22,0x3e,0x24,0x2e,0x24,0x44,0xab,0x22,0x74,0x2, 0xac,0xb1,0x9, +0x95,0x3c,0xc9,0x9, 0x5, 0x3c,0xca,0x22,0x7e,0x73,0x40,0x10,0xa, 0x37,0x22,0x7e, +0x34,0x0, 0x17,0x7e,0x27,0x44,0xd7,0x5e,0x24,0xe0,0x3f,0x22,0x7e,0x34,0x0, 0x1, +0x7e,0x27,0x44,0xd1,0x5e,0x24,0x80,0x0, 0x22,0x7e,0x34,0x1, 0x6, 0x7e,0x27,0x44, +0xdb,0x5e,0x24,0xfc,0x0, 0x22,0x49,0x35,0x4c,0x4e,0x49,0x25,0x4c,0x4c,0x2, 0x9, +0xad,0x2e,0x34,0x4b,0xa9,0x6d,0x22,0x74,0x10,0x2, 0xb, 0x8, 0x7e,0xf1,0x46,0x74, +0xb5,0xac,0xfb,0x2e,0x74,0x1, 0x0, 0x22,0x7a,0xb3,0x3, 0xd0,0x74,0xff,0x7a,0xb3, +0x3, 0xd1,0xe4,0x22,0xe5,0x27,0xa, 0x5b,0xb, 0x54,0xf5,0x2a,0x85,0x27,0x2b,0x22, +0x7e,0x34,0x2, 0x34,0x7a,0x35,0x29,0x22,0x7e,0x34,0x0, 0x8, 0x7e,0x27,0x44,0xd5, +0x4e,0x40,0x40,0x22,0x9d,0x32,0x12,0x16,0x6c,0xbe,0x34,0x0, 0x2, 0x22,0x9, 0x73, +0x4b,0xa4,0x2, 0xd, 0x23,0x7e,0x24,0x0, 0x12,0x2, 0x4, 0x96,0x7e,0xb3,0x4e,0x19, +0xbe,0xb0,0x1, 0x22,0x7e,0xb3,0x4f,0x55,0x7e,0x70,0x2, 0x22,0xc2,0x6, 0x7c,0xb1, +0x2, 0x26,0xfa,0x7e,0xb3,0x40,0x3, 0xbe,0xb0,0x1, 0x22,0x12,0x6, 0x48,0x7e,0x34, +0x1, 0x2, 0x22,0x12,0x6, 0xc5,0x7e,0x34,0x1, 0x2, 0x22,0x12,0x6, 0x48,0x7e,0x34, +0x1, 0x1, 0x22,0x12,0x6, 0xc5,0x7e,0x34,0x1, 0x1, 0x22,0x12,0x6, 0x48,0x7e,0x34, +0x1, 0x0, 0x22,0xff, diff --git a/drivers/input/touchscreen/focaltech_touch_n10/include/pramboot/FT8716_Pramboot_V0.5_20160723.i b/drivers/input/touchscreen/focaltech_touch_n10/include/pramboot/FT8716_Pramboot_V0.5_20160723.i new file mode 100644 index 0000000000000000000000000000000000000000..16d74c167782a580ee3b7af20c49294623ca0e1d --- /dev/null +++ b/drivers/input/touchscreen/focaltech_touch_n10/include/pramboot/FT8716_Pramboot_V0.5_20160723.i @@ -0,0 +1,246 @@ +0x2, 0x3, 0x83,0xca,0x39,0x12,0xf, 0x3c,0xda,0x39,0x32,0x2, 0x0, 0x3, 0x6d,0x22, +0x80,0x13,0x75,0xb5,0x0, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0xe5,0xb5,0x7a,0xb, +0xb0,0xb, 0x14,0xb, 0x24,0xbd,0x32,0x38,0xe9,0x22,0xff,0x2, 0xd, 0xf, 0xe5,0x33, +0xb4,0xc, 0xf, 0xc2,0x86,0xc2,0x87,0x7e,0x34,0x0, 0x64,0x12,0xe, 0x86,0xd2,0x86, +0xd2,0x87,0x22,0x2, 0x0, 0xf9,0xca,0x3b,0x7a,0xd, 0x10,0x7f,0x31,0xe5,0x24,0xb4, +0x80,0x2, 0x80,0x3, 0x2, 0x0, 0xdc,0x7f,0x13,0x5e,0x34,0x0, 0x7f,0x7d,0x23,0x7e, +0x34,0x0, 0x80,0x9d,0x32,0x7a,0x35,0x16,0x7e,0x35,0x14,0xbe,0x35,0x16,0x38,0x2, +0x80,0x5d,0x7e,0x35,0x16,0x7a,0x35,0x18,0x7f,0x13,0x7e,0xd, 0x10,0x12,0xa, 0xe6, +0x7e,0x35,0x14,0x9e,0x35,0x16,0x7a,0x35,0x14,0x7e,0x35,0x16,0x6d,0x22,0x2f,0x31, +0x7e,0x1d,0x10,0x2e,0x35,0x16,0x7a,0x1d,0x10,0x80,0x27,0x7e,0x34,0x0, 0x80,0x7a, +0x35,0x18,0x7f,0x13,0x7e,0xd, 0x10,0x12,0xa, 0xe6,0x7e,0x35,0x14,0x9e,0x34,0x0, +0x80,0x7a,0x35,0x14,0x7e,0x1d,0x10,0x2e,0x34,0x0, 0x80,0x7a,0x1d,0x10,0x2e,0x38, +0x0, 0x80,0x7e,0x35,0x14,0xbe,0x34,0x0, 0x80,0x50,0xd0,0x4d,0x33,0x68,0x26,0x7a, +0x35,0x18,0x7f,0x13,0x7e,0xd, 0x10,0x12,0xa, 0xe6,0x80,0x19,0x74,0x2, 0x12,0xa, +0x89,0x5e,0x70,0xf4,0x12,0xc, 0x86,0x7e,0x35,0x14,0x7a,0x35,0x18,0x7f,0x13,0x7e, +0xd, 0x10,0x12,0x8, 0xe, 0xd3,0xda,0x3b,0x22,0xa9,0xc0,0x93,0x75,0x39,0x0, 0x32, +0xf, 0x60,0xf0,0x9f,0x4c,0xf1,0xb3,0xe, 0xce,0xb9,0x31,0x46,0xff,0x0, 0xff,0x0, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0x7c,0x6b,0xc2,0x2, 0xe5,0x22,0x14,0x78,0x3, 0x2, 0x2, 0xda,0x1b,0xb1,0x78,0x3, +0x2, 0x2, 0x3d,0x1b,0xb1,0x78,0x3, 0x2, 0x2, 0x89,0x1b,0xb1,0x78,0x3, 0x2, 0x2, +0x9a,0x1b,0xb1,0x78,0x3, 0x2, 0x2, 0xc1,0x24,0xf9,0x78,0x3, 0x2, 0x2, 0xd6,0x24, +0xaf,0x78,0x3, 0x2, 0x3, 0x3b,0x24,0xfd,0x68,0x3a,0x14,0x78,0x3, 0x2, 0x2, 0xdd, +0x14,0x78,0x3, 0x2, 0x2, 0xda,0x1b,0xb2,0x78,0x3, 0x2, 0x2, 0xda,0x24,0xda,0x68, +0x26,0x24,0xe6,0x68,0x1f,0x24,0xeb,0x68,0x3b,0x24,0xf3,0x78,0x3, 0x2, 0x2, 0xda, +0x24,0xe4,0x78,0x3, 0x2, 0x3, 0x46,0x14,0x78,0x3, 0x2, 0x2, 0xda,0x24,0x94,0x68, +0x3, 0x2, 0x3, 0x82,0x2, 0x3, 0x42,0xbe,0x60,0x4, 0x50,0xc, 0x75,0x3f,0x0, 0x7c, +0x16,0x2e,0x10,0x25,0x7c,0xb7,0xa5,0xf7,0xa5,0xbe,0x0, 0x2, 0x80,0x3, 0x2, 0x3, +0x82,0xd2,0x2, 0x22,0x7c,0xb6,0x24,0x0, 0x78,0x3, 0x2, 0x3, 0x82,0x1b,0xb1,0x68, +0x1e,0x14,0x68,0x1e,0x14,0x68,0x1e,0x14,0x68,0x1e,0xb, 0xb2,0x78,0x33,0x30,0x1, +0x7, 0x7e,0x8, 0x0, 0x44,0x2, 0x2, 0x5a,0x7e,0x8, 0x1, 0x50,0x2, 0x2, 0x5a,0x2, +0x2, 0xfb,0x2, 0x3, 0x2, 0x2, 0x3, 0x1a,0xa, 0x27,0x7e,0xd, 0x3a,0xb, 0x16,0xb, +0xa, 0x30,0x2d,0x32,0x1b,0xa, 0x30,0x6d,0x33,0x7e,0xd, 0x3a,0x79,0x30,0x0, 0x6, +0x22,0x7c,0xb7,0x62,0x3f,0x7e,0x2d,0x3a,0x2e,0x54,0x0, 0x6, 0xb, 0x2a,0x20,0x7d, +0x12,0xb, 0x14,0x1b,0x2a,0x10,0x7e,0xd, 0x3a,0x2d,0x12,0x39,0x70,0x0, 0x8, 0x7e, +0xd, 0x3a,0x69,0x50,0x0, 0x4, 0x69,0x20,0x0, 0x6, 0xbd,0x25,0x50,0x3, 0x2, 0x3, +0x82,0xb2,0x1, 0x7a,0xd, 0x34,0x7e,0x34,0x0, 0x2, 0x2, 0x3, 0x7f,0x7c,0xb6,0x1b, +0xb1,0x68,0x1d,0x14,0x68,0x1d,0xb, 0xb1,0x68,0x3, 0x2, 0x3, 0x82,0x30,0x1, 0x6, +0x7e,0x8, 0x0, 0x44,0x80,0x4, 0x7e,0x8, 0x1, 0x50,0x7a,0xd, 0x3a,0x2, 0x2, 0xf3, +0x2, 0x2, 0xfb,0xa, 0x57,0x6d,0x44,0x7e,0xd, 0x3a,0x69,0x30,0x0, 0x2, 0xb, 0xa, +0x20,0x2f,0x12,0x79,0x30,0x0, 0x2, 0x1b,0xa, 0x20,0x7e,0x1d,0x3a,0x7a,0x1d,0x34, +0xd2,0x2, 0x7e,0x34,0x0, 0x1, 0x2, 0x3, 0x7f,0xbe,0x60,0x1, 0x68,0x9, 0xa5,0xbe, +0x2, 0x5, 0x7a,0x71,0x3e,0xd2,0x3, 0xd2,0x2, 0x22,0x75,0xe6,0x0, 0xe4,0x7e,0x34, +0x1, 0x4, 0x7e,0x24,0x0, 0xff,0x7a,0x1b,0xb0,0x7e,0x34,0x1, 0x5, 0x7a,0x1b,0xb0, +0x7e,0x34,0x1, 0x8, 0x7a,0x1b,0xb0,0x7e,0x34,0x1, 0x9, 0x7a,0x1b,0xb0,0xd2,0x4, +0x22,0xa5,0xbe,0x1, 0x4, 0x7a,0x71,0x38,0x22,0xa5,0xbe,0x2, 0x2, 0x80,0x3, 0x2, +0x3, 0x82,0x7a,0x71,0x23,0x22,0x7a,0x71,0x33,0x22,0xd2,0x2, 0x22,0x7c,0xb6,0x1b, +0xb1,0x68,0x18,0x14,0x68,0x1c,0x14,0x68,0x31,0x14,0x68,0x3a,0xb, 0xb2,0x68,0x3, +0x2, 0x3, 0x82,0xa, 0x37,0x7d,0x3, 0x6d,0x11,0x80,0x59,0xa, 0x57,0x7c,0xab,0xe4, +0x80,0x2, 0xa, 0x57,0x6d,0x44,0x7e,0xd, 0x3a,0x69,0x30,0x0, 0x2, 0xb, 0xa, 0x20, +0x2f,0x12,0x79,0x30,0x0, 0x2, 0x1b,0xa, 0x20,0x22,0x7c,0x67,0x6c,0x77,0x7e,0xd, +0x3a,0x79,0x30,0x0, 0x4, 0x22,0xa, 0x27,0x7e,0xd, 0x3a,0xb, 0x16,0xb, 0xa, 0x30, +0x2d,0x32,0x1b,0xa, 0x30,0x7e,0x34,0x0, 0x3, 0x80,0x44,0x7e,0x34,0x0, 0x4, 0x7a, +0x35,0x2f,0x75,0x3f,0x0, 0x22,0x1b,0x61,0x68,0x15,0xb, 0x60,0x78,0x34,0x7c,0x27, +0x6c,0x33,0x6d,0x0, 0x7e,0x1d,0x3a,0x79,0x11,0x0, 0x2, 0x1b,0x1a,0x0, 0x22,0xa, +0x57,0x6d,0x44,0x7e,0xd, 0x3a,0x69,0x30,0x0, 0x2, 0xb, 0xa, 0x20,0x2f,0x12,0x79, +0x30,0x0, 0x2, 0x1b,0xa, 0x20,0xe4,0x7a,0xb3,0x2, 0xe4,0x7e,0x34,0x0, 0x5, 0x7a, +0x35,0x2f,0x22,0x75,0x84,0x1, 0x7e,0x44,0x1f,0xff,0xe4,0x7a,0x49,0xb0,0x1b,0x44, +0x78,0xf9,0x7e,0xf8,0x2, 0xe8,0xd2,0x7, 0xc2,0x8, 0x75,0x3f,0x0, 0x75,0x40,0x87, +0x75,0x41,0xa6,0x75,0x42,0x0, 0x75,0x43,0x0, 0xd2,0x0, 0xc2,0x2, 0xc2,0x3, 0xc2, +0x4, 0x75,0x22,0x0, 0x75,0x23,0x0, 0x75,0x24,0x80,0x75,0x2f,0x0, 0x75,0x30,0x0, +0x75,0x31,0x0, 0x75,0x32,0x0, 0x75,0x33,0x0, 0x75,0x38,0xb, 0x75,0x39,0x0, 0x75, +0x3e,0x1, 0x7e,0x4, 0x0, 0xff,0x7e,0x14,0xf, 0x50,0xb, 0xa, 0x40,0x5d,0x44,0x68, +0x1a,0x69,0x20,0x0, 0x2, 0xb, 0xe, 0xb, 0x44,0x80,0xa, 0x7e,0xb, 0xb0,0x7a,0x29, +0xb0,0xb, 0x24,0xb, 0xc, 0x1b,0x44,0x78,0xf2,0x80,0xdf,0x2, 0x4, 0x20,0xff,0xff, +0x56,0x30,0x2e,0x35,0x4a,0x75,0x6c,0x20,0x32,0x33,0x20,0x32,0x30,0x31,0x36,0x0, +0x46,0x54,0x53,0x38,0x37,0x31,0x36,0x5f,0x70,0x72,0x61,0x6d,0x62,0x6f,0x6f,0x74, +0x12,0xe, 0x63,0x2, 0x5, 0xbc,0x7e,0x35,0x2f,0x1b,0x34,0x68,0x60,0x1b,0x35,0x78, +0x3, 0x2, 0x4, 0xbc,0x1b,0x34,0x78,0x3, 0x2, 0x4, 0xe6,0x1b,0x34,0x78,0x3, 0x2, +0x5, 0x96,0x2e,0x34,0x0, 0x3, 0x68,0x3, 0x2, 0x5, 0xa8,0x6d,0x33,0x7a,0x35,0x2f, +0x7a,0x35,0x31,0x30,0x7, 0x5, 0x12,0x0, 0x2e,0xc2,0x7, 0x7e,0xd, 0x34,0x69,0x30, +0x0, 0x4, 0x7a,0x35,0x14,0x69,0x30,0x0, 0x2, 0xb, 0xa, 0x20,0x2e,0x14,0x0, 0x8, +0x12,0x0, 0x46,0xd2,0x7, 0x7e,0x2d,0x34,0x69,0x12,0x0, 0x4, 0x69,0x32,0x0, 0x2, +0xb, 0x2a,0x20,0x12,0xb, 0xe2,0x2e,0x34,0x10,0x0, 0x2, 0x5, 0x91,0x6d,0x33,0x7a, +0x35,0x2f,0x7e,0x34,0x1, 0x0, 0x7a,0x35,0x15,0x7e,0xd, 0x34,0x69,0x30,0x0, 0x2, +0xb, 0xa, 0x20,0x2e,0x14,0x0, 0x8, 0x12,0xe, 0xf2,0x20,0x0, 0x3, 0x2, 0x5, 0xa8, +0x7e,0x1d,0x34,0x29,0xb1,0x0, 0x8, 0xf5,0x91,0x2, 0x5, 0xa8,0x6d,0x33,0x7a,0x35, +0x2f,0x7a,0x35,0x31,0x7e,0x18,0x0, 0x3f,0x7a,0x1d,0xe, 0x7e,0xd, 0x34,0x69,0x30, +0x0, 0x2, 0xb, 0xa, 0x20,0x69,0x10,0x0, 0x4, 0x12,0x7, 0x62,0x12,0x0, 0x2e,0x7e, +0x34,0xf0,0x55,0x2, 0x5, 0x91,0x7e,0x18,0x10,0x0, 0x7a,0x1d,0x8, 0xd2,0x5, 0x6d, +0x33,0x7a,0x35,0x2f,0x7a,0x35,0x31,0xe5,0x38,0xb4,0xa, 0x17,0xe5,0x24,0xb4,0x80, +0xc, 0xe4,0x12,0xc, 0xd1,0x74,0x1, 0x12,0xc, 0xd1,0x2, 0x5, 0x7f,0x12,0x8, 0xa4, +0x2, 0x5, 0x7f,0xe5,0x38,0xb4,0xb, 0x27,0xe5,0x24,0xb4,0x80,0x11,0x7e,0xf0,0x1, +0x7c,0xbf,0x12,0x5, 0xc3,0xb, 0xf0,0xbe,0xf0,0x11,0x78,0xf4,0x80,0x51,0x7e,0xf0, +0x4, 0x7c,0xbf,0x12,0x5, 0xc3,0xb, 0xf0,0xbe,0xf0,0x40,0x78,0xf4,0x80,0x40,0xe5, +0x38,0xa, 0x3b,0x9e,0x34,0x0, 0x80,0x7c,0xe7,0xe5,0x24,0xb4,0x80,0x10,0xa, 0x3e, +0x6d,0x22,0x74,0xc, 0x2f,0x11,0x14,0x78,0xfb,0x7a,0x1d,0x8, 0x80,0xe, 0xa, 0x3e, +0x6d,0x22,0x74,0xa, 0x2f,0x11,0x14,0x78,0xfb,0x7a,0x1d,0x8, 0x6c,0xdd,0x80,0x9, +0x7c,0xbe,0x12,0x5, 0xc3,0xb, 0xe0,0xb, 0xd0,0xe5,0x23,0xbc,0xbd,0x38,0xf1,0x7e, +0x1d,0x8, 0x12,0xe, 0xd, 0x92,0x5, 0x12,0x0, 0x2e,0x30,0x5, 0x1b,0x7e,0x34,0xf0, +0xaa,0x7a,0x35,0x31,0x80,0x12,0x6d,0x33,0x7a,0x35,0x2f,0x7a,0x35,0x31,0x7e,0xd, +0x34,0x69,0x30,0x0, 0x2, 0x12,0x6, 0x98,0x30,0x4, 0x11,0x7e,0x34,0x13,0x88,0x12, +0xe, 0x86,0x7e,0x34,0x13,0x88,0x12,0xe, 0x86,0x75,0xe9,0xff,0x30,0x8, 0x3, 0x2, +0x4, 0x26,0x22,0xca,0xf8,0x7c,0xfb,0xe5,0x24,0xb4,0x80,0x4a,0xd2,0x6, 0x12,0xe, +0xdf,0x74,0x20,0xca,0xb8,0xa, 0x3f,0x6d,0x22,0x74,0xc, 0x2f,0x11,0x14,0x78,0xfb, +0xda,0xb8,0x12,0xd, 0xb3,0xa9,0xd2,0xb4,0x12,0xf, 0x32,0x12,0xe, 0xca,0x50,0x9, +0x7e,0x35,0x42,0xbe,0x34,0x1, 0xf4,0x28,0xf2,0x7e,0x35,0x42,0xbe,0x34,0x1, 0xf4, +0x38,0x6, 0x12,0xf, 0x4d,0x2, 0x6, 0x95,0xc2,0x86,0x7e,0x34,0x13,0x88,0x12,0xe, +0x86,0xd2,0x86,0x2, 0x6, 0x95,0x74,0x1, 0x12,0xa, 0x21,0x74,0x1, 0x6d,0x33,0x12, +0xc, 0x86,0xe4,0x12,0xa, 0x89,0x5e,0x34,0x80,0x0, 0x7c,0x4f,0x6c,0x55,0x3e,0x24, +0x4d,0x32,0x12,0xc, 0x86,0x74,0x4, 0x6d,0x33,0x12,0xc, 0x86,0x7e,0x34,0x0, 0x50, +0x12,0xc, 0x86,0x7e,0x34,0x0, 0x19,0x12,0xe, 0x86,0x74,0x4, 0x7e,0x34,0x0, 0x51, +0x12,0xc, 0x86,0x7e,0x34,0xa2,0x1c,0x12,0xe, 0x86,0x74,0x4, 0x7e,0x34,0x0, 0x11, +0x12,0xc, 0x86,0x7e,0x34,0x0, 0x19,0x12,0xe, 0x86,0x74,0x4, 0x7e,0x34,0x0, 0x10, +0x12,0xc, 0x86,0x7e,0x34,0x0, 0x19,0x12,0xe, 0x86,0x74,0x4, 0x6d,0x33,0x12,0xc, +0x86,0x7e,0x34,0x0, 0x5, 0x12,0xe, 0x86,0xe4,0x12,0xa, 0x21,0x74,0x4, 0x7e,0x34, +0xff,0xf7,0x12,0xc, 0x86,0xda,0xf8,0x22,0xca,0xf8,0xe4,0x7a,0xb3,0x2, 0xe4,0xe5, +0x24,0xbe,0xb0,0x80,0x68,0x9, 0x74,0x1, 0x7a,0xb3,0x2, 0xe4,0x2, 0x7, 0x5f,0xbe, +0x34,0xff,0xff,0x68,0x6, 0xbe,0x34,0x0, 0x12,0x50,0x4, 0x7e,0x34,0x0, 0x12,0x7d, +0x13,0x6d,0x0, 0x74,0xc, 0x2f,0x0, 0x14,0x78,0xfb,0x7a,0xd, 0xc, 0x7c,0xb7,0x12, +0x5, 0xc3,0x7e,0x1d,0xc, 0x12,0xe, 0xd, 0xe4,0x33,0x7c,0xfb,0xbe,0xf0,0x1, 0x78, +0xa, 0x7e,0xb3,0x2, 0xe4,0x44,0x2, 0x7a,0xb3,0x2, 0xe4,0x6c,0xaa,0xa, 0x3a,0x19, +0xa3,0x2, 0xdc,0xb, 0xa0,0xbe,0xa0,0x8, 0x78,0xf3,0x7e,0x34,0x0, 0x8, 0x7a,0x35, +0x14,0x7e,0x1d,0xc, 0x7e,0x8, 0x2, 0xdc,0x12,0x0, 0x46,0x6c,0xaa,0xe4,0xa, 0x4a, +0x19,0xb4,0x2, 0xdc,0xb, 0xa0,0xbe,0xa0,0x8, 0x78,0xf3,0x7e,0x34,0x0, 0x8, 0x7a, +0x35,0x15,0x7e,0x1d,0xc, 0x7e,0x8, 0x2, 0xdc,0x12,0xe, 0xf2,0x7e,0xf0,0x1, 0x6c, +0xaa,0xa, 0x3a,0x9, 0xb3,0x2, 0xdc,0xbc,0xba,0x68,0x4, 0x6c,0xff,0x80,0x7, 0xb, +0xa0,0xbe,0xa0,0x8, 0x40,0xeb,0xbe,0xf0,0x1, 0x78,0xa, 0x7e,0xb3,0x2, 0xe4,0x44, +0x4, 0x7a,0xb3,0x2, 0xe4,0x7e,0xb3,0x2, 0xe4,0x44,0x1, 0x7a,0xb3,0x2, 0xe4,0xda, +0xf8,0x22,0xca,0x3b,0x7a,0x15,0xc, 0x7f,0x31,0x75,0x12,0x0, 0x7e,0x35,0xc, 0xbe, +0x34,0x0, 0x0, 0x38,0x4f,0x7e,0x34,0xff,0xff,0x7a,0x35,0xc, 0x75,0x12,0x1, 0x80, +0x43,0x7e,0x34,0x0, 0x80,0x7a,0x35,0x15,0x7f,0x13,0x7e,0x8, 0x2, 0x5c,0x12,0xe, +0xf2,0x7e,0x35,0xc, 0x9e,0x34,0x0, 0x80,0x7a,0x35,0xc, 0x2e,0x38,0x0, 0x80,0x6d, +0x33,0x7a,0x35,0x13,0x7e,0x35,0x13,0x9, 0x63,0x2, 0x5c,0x7e,0xd, 0xe, 0x7e,0xb, +0x70,0x6c,0x76,0x7a,0xb, 0x70,0x7e,0x35,0x13,0xb, 0x34,0x7a,0x35,0x13,0xbe,0x34, +0x0, 0x80,0x78,0xe0,0x7e,0x35,0xc, 0xbe,0x34,0x0, 0x80,0x38,0xb4,0xe5,0x12,0x60, +0x5, 0xb, 0x34,0x7a,0x35,0xc, 0x7e,0x35,0xc, 0x7a,0x35,0x15,0x7f,0x13,0x7e,0x8, +0x2, 0x5c,0x12,0xe, 0xf2,0x6d,0x33,0x80,0x17,0x7e,0x35,0x13,0x9, 0x63,0x2, 0x5c, +0x7e,0xd, 0xe, 0x7e,0xb, 0x70,0x6c,0x76,0x7a,0xb, 0x70,0x7e,0x35,0x13,0xb, 0x34, +0x7a,0x35,0x13,0x7e,0x35,0xc, 0xbe,0x35,0x13,0x38,0xde,0xda,0x3b,0x22,0xca,0x3b, +0x7f,0x30,0x7c,0xb6,0xf5,0x1a,0x7c,0xb7,0xf5,0x1b,0x74,0x1, 0x7e,0x35,0x18,0x1e, +0x34,0x1b,0x34,0x4e,0x60,0x80,0x12,0xc, 0x86,0x12,0xa, 0x21,0xa9,0xc2,0xb4,0xa9, +0xc6,0xb3,0x75,0xb5,0x2, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x75,0xb5,0x0, 0xa9, +0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x85,0x1a,0xb5,0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3, +0x85,0x1b,0xb5,0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x6d,0x33,0x80,0x2a,0x7f,0x13, +0x2e,0x35,0x1c,0x7e,0x1b,0xb0,0xf5,0xb5,0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x7e, +0x35,0x1c,0x5e,0x34,0x0, 0x1, 0xbe,0x34,0x0, 0x1, 0x78,0x7, 0x7e,0x34,0x0, 0x78, +0x12,0xe, 0x86,0x7e,0x35,0x1c,0xb, 0x34,0x7a,0x35,0x1c,0x7e,0x35,0x18,0xbe,0x35, +0x1c,0x38,0xcb,0xa9,0xd2,0xb4,0x7e,0x34,0x0, 0x5, 0x12,0xe, 0x86,0xe4,0x12,0xa, +0x21,0xda,0x3b,0x22,0xe5,0x24,0xb4,0x80,0x16,0xd2,0x6, 0x12,0xe, 0xdf,0xa9,0xc2, +0xb4,0x74,0x60,0x12,0xf, 0x27,0xa9,0xd2,0xb4,0x12,0xe, 0xca,0x40,0xfb,0x22,0x74, +0x1, 0x12,0xa, 0x21,0xe4,0x6d,0x33,0x12,0xc, 0x86,0x74,0x1, 0x6d,0x33,0x12,0xc, +0x86,0x74,0x4, 0x6d,0x33,0x12,0xc, 0x86,0x7e,0x34,0x0, 0x54,0x12,0xc, 0x86,0x7e, +0x34,0x0, 0x19,0x12,0xe, 0x86,0x74,0x4, 0x7e,0x34,0x0, 0x55,0x12,0xc, 0x86,0x7e, +0x34,0xa2,0x1c,0x12,0xe, 0x86,0x74,0x4, 0x7e,0x34,0x0, 0x15,0x12,0xc, 0x86,0x7e, +0x34,0x0, 0xa0,0x12,0xe, 0x86,0x74,0x4, 0x7e,0x34,0x0, 0x14,0x12,0xc, 0x86,0x7e, +0x34,0x0, 0x19,0x12,0xe, 0x86,0x74,0x4, 0x7e,0x34,0x0, 0x4, 0x12,0xc, 0x86,0x7e, +0x34,0x0, 0x5, 0x12,0xe, 0x86,0xe4,0x12,0xa, 0x21,0x74,0x4, 0x7e,0x34,0xff,0xf7, +0x2, 0xc, 0x86,0x7c,0x7b,0x7e,0xa0,0xef,0xe5,0x22,0x24,0xfd,0x68,0x3c,0x1b,0xb1, +0x68,0x26,0x24,0x9f,0x68,0x41,0x1b,0xb2,0x68,0x42,0x24,0x9e,0x68,0x39,0x24,0xe3, +0x68,0x52,0x24,0x59,0x78,0x52,0xa5,0xbf,0x0, 0x5, 0x7e,0xa1,0x40,0x80,0x49,0xa5, +0xbf,0x1, 0x45,0x7e,0xa1,0x41,0x80,0x40,0xa5,0xbf,0x0, 0x5, 0x7e,0xa1,0x24,0x80, +0x37,0xa5,0xbf,0x1, 0x33,0x7e,0xa1,0x3e,0x80,0x2e,0xa, 0x17,0x7e,0x1d,0x3a,0x2d, +0x31,0x29,0xa1,0x0, 0x8, 0x80,0x21,0x7e,0xa1,0x3f,0x80,0x1c,0xa5,0xbf,0x0, 0x9, +0x7e,0x35,0x31,0xa, 0x56,0x7c,0xab,0x80,0xf, 0xa5,0xbf,0x1, 0xb, 0x7e,0x55,0x31, +0x7c,0xab,0x80,0x4, 0x7e,0xa3,0x2, 0xe4,0x7c,0xba,0x22,0xca,0x79,0x6c,0xee,0x7e, +0xf0,0x70,0x75,0x91,0x0, 0xc2,0x90,0xc2,0x91,0x30,0x8, 0x31,0x7e,0x34,0x0, 0x2, +0x7a,0x35,0x15,0x9f,0x11,0x7e,0x8, 0x0, 0xc, 0x12,0xe, 0xf2,0xe5,0xc, 0xbe,0xb0, +0xff,0x68,0x1a,0xe5,0xc, 0x60,0x16,0xe5,0xd, 0xa, 0x2b,0xe5,0xc, 0xa, 0x3b,0x2d, +0x32,0xbe,0x34,0x0, 0xff,0x78,0x6, 0x7e,0xf1,0xc, 0x7e,0xe0,0x1, 0x4c,0xee,0x78, +0x1c,0xa9,0xd1,0xcb,0xd2,0xcc,0x12,0xc, 0x35,0x7c,0xfb,0xc2,0xcc,0xa9,0xc1,0xcb, +0xbe,0xf0,0x2, 0x40,0x5, 0xbe,0xf0,0xfd,0x28,0x3, 0x7e,0xf0,0x70,0x7c,0xbf,0x54, +0xfe,0xf5,0x92,0xd2,0xe8,0xc2,0xc0,0xa9,0xd5,0xb7,0xd2,0xbd,0xd2,0xad,0xda,0x79, +0x22,0xca,0x79,0xbe,0xb0,0x0, 0x28,0x2e,0x74,0x6, 0x12,0xa, 0x89,0x7d,0x73,0x6c, +0xff,0x7e,0xf0,0xa5,0x7d,0x37,0x12,0xc, 0x86,0x6c,0xff,0x7e,0xf0,0xf, 0x7d,0x37, +0x12,0xc, 0x86,0x6c,0xff,0x7e,0xf0,0x6a,0x7d,0x37,0x12,0xc, 0x86,0x7e,0x34,0x0, +0x5, 0x12,0xe, 0x86,0x80,0x30,0x74,0x1, 0x7e,0x34,0xdf,0xff,0x12,0xc, 0x86,0x74, +0x6, 0x12,0xa, 0x89,0x7d,0x73,0x6c,0xff,0x7d,0x37,0x12,0xc, 0x86,0x7d,0x37,0x12, +0xc, 0x86,0x7d,0x37,0x12,0xc, 0x86,0x74,0x2, 0x12,0xa, 0x89,0x7d,0x73,0x4e,0xf0, +0x1, 0x7d,0x37,0x12,0xc, 0x86,0xda,0x79,0x22,0xa9,0xc2,0xb4,0xa9,0xc6,0xb3,0x75, +0xb5,0x5, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x75,0xb5,0x0, 0xa9,0x36,0xb3,0xfc, +0xa9,0xc6,0xb3,0x75,0xb5,0x0, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0xf5,0xb5,0xa9, +0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x75,0xb5,0x0, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3, +0x75,0xb5,0x0, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x7e,0x71,0xb5,0x75,0xb5,0x0, +0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x7e,0xa1,0xb5,0xa9,0xd2,0xb4,0x7c,0x47,0x6c, +0x55,0xa, 0x3a,0x4d,0x32,0x22,0x7f,0x70,0xd2,0x6, 0x12,0xe, 0xdf,0x74,0x2, 0x12, +0xd, 0xb3,0x6d,0x33,0x80,0x12,0x7f,0x7, 0x2d,0x13,0x7e,0xb, 0xb0,0xf5,0xb5,0xa9, +0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0xb, 0x34,0x7e,0x25,0x18,0xbd,0x23,0x38,0xe7,0xa9, +0xd2,0xb4,0x12,0xf, 0x32,0x12,0xe, 0xca,0x50,0x9, 0x7e,0x35,0x42,0xbe,0x34,0x1, +0xf4,0x28,0xf2,0x7e,0x35,0x42,0xbe,0x34,0x1, 0xf4,0x38,0x3, 0x2, 0xf, 0x4d,0xc2, +0x86,0x7e,0x34,0x13,0x88,0x12,0xe, 0x86,0xd2,0x86,0x22,0xa9,0xd1,0xcb,0xd2,0xcc, +0x7e,0x34,0x0, 0x4, 0x7e,0x8, 0x2, 0x5c,0x74,0xc, 0x12,0xb, 0x8f,0xa9,0xd1,0xcb, +0xc2,0xcc,0x6c,0xaa,0x7e,0x70,0x2, 0xac,0x7a,0x7e,0x8, 0x2, 0x5c,0x2d,0x13,0xb, +0xa, 0x30,0x7d,0x23,0x7c,0x45,0x6c,0x55,0xa, 0x36,0x4d,0x32,0x1b,0xa, 0x30,0xb, +0xa0,0xbe,0xa0,0xc, 0x78,0xde,0x7e,0x37,0x2, 0x6c,0x7d,0x23,0xa, 0x54,0x7c,0xa7, +0xb4,0xe7,0xb, 0xbe,0xa0,0x16,0x78,0x6, 0x75,0x40,0xe7,0x75,0x41,0xa6,0x22,0x7e, +0x24,0x0, 0x1, 0x7e,0x7f,0x2, 0xe5,0x79,0x27,0x0, 0x6, 0x7e,0x7f,0x2, 0xe5,0x69, +0x27,0x0, 0x6, 0x4d,0x22,0x78,0xf4,0x5e,0x60,0x7f,0x1b,0x7a,0x30,0x7e,0x1f,0x2, +0xe5,0x69,0x31,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6c,0xaa,0x80,0x20,0x6d,0x44,0x7e, +0x1f,0x2, 0xe5,0x1b,0x1a,0x40,0x7e,0x1f,0x2, 0xe5,0x69,0x41,0x0, 0x8, 0x4d,0x44, +0x68,0xf4,0x69,0x41,0x0, 0x2, 0x1b,0xa, 0x40,0xb, 0x15,0xb, 0xa0,0xbc,0xba,0x38, +0xdc,0x22,0x6d,0x0, 0x74,0x10,0x4d,0x0, 0x78,0xb, 0x4d,0x22,0x78,0x27,0x8d,0x31, +0x7d,0x12,0x6d,0x22,0x22,0x7d,0x43,0x7d,0x32,0x6d,0x22,0x2f,0x11,0x2d,0x44,0x50, +0x2, 0xa5,0xf, 0xbf,0x10,0x40,0x4, 0x9f,0x10,0xb, 0x90,0x14,0x78,0xed,0x7f,0x1, +0x6d,0x22,0x7d,0x34,0x22,0x7d,0x41,0x7d,0x13,0x8d,0x24,0x7d,0x2, 0x2f,0x0, 0x40, +0x4, 0xbd,0x4, 0x40,0x4, 0x9d,0x4, 0xb, 0x14,0x14,0x78,0xf1,0x7d,0x23,0x7d,0x31, +0x7d,0x10,0x6d,0x0, 0x22,0x7e,0x34,0x0, 0x2, 0x7e,0xf, 0x2, 0xe5,0x79,0x30,0x0, +0x4, 0x7e,0x34,0x0, 0x1, 0x7e,0xf, 0x2, 0xe5,0x79,0x30,0x0, 0x6, 0x7e,0xf, 0x2, +0xe5,0x69,0x30,0x0, 0x6, 0x4d,0x33,0x78,0xf4,0x7e,0x34,0x0, 0x4, 0x1b,0xa, 0x30, +0x7e,0xf, 0x2, 0xe5,0x69,0x30,0x0, 0x8, 0x4d,0x33,0x68,0xf4,0x6d,0x33,0x1b,0xa, +0x30,0x7e,0x1f,0x2, 0xe5,0x69,0x11,0x0, 0x8, 0x4d,0x11,0x68,0xf4,0x69,0x51,0x0, +0x2, 0x5e,0x54,0x0, 0xfe,0x22,0x7d,0x23,0xa, 0x36,0x7c,0xa5,0xa9,0xc2,0xb4,0xa9, +0xc6,0xb3,0x75,0xb5,0x1, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x75,0xb5,0x0, 0xa9, +0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x75,0xb5,0x0, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3, +0xf5,0xb5,0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0x7a,0x71,0xb5,0xa9,0x36,0xb3,0xfc, +0xa9,0xc6,0xb3,0x7a,0xa1,0xb5,0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0xa9,0xd2,0xb4, +0x22,0x7c,0xab,0xd2,0x6, 0x12,0xe, 0xdf,0x74,0xd8,0xa, 0x3a,0x7d,0x23,0x6d,0x33, +0x12,0xd, 0xb3,0xa9,0xd2,0xb4,0x12,0xf, 0x32,0x12,0xe, 0xca,0x50,0x9, 0x7e,0x35, +0x42,0xbe,0x34,0x5, 0xdc,0x28,0xf2,0x7e,0x35,0x42,0xbe,0x34,0x5, 0xdc,0x38,0x3, +0x2, 0xf, 0x4d,0xc2,0x86,0x7e,0x34,0x13,0x88,0x12,0xe, 0x86,0xd2,0x86,0x22,0xca, +0x2b,0xca,0x1b,0xca,0xb, 0xd2,0x0, 0x30,0x90,0x1c,0xc2,0x90,0x7e,0x71,0x91,0xe5, +0x39,0x70,0x3, 0x7a,0x71,0x22,0xe5,0x39,0x12,0x1, 0x20,0x5, 0x39,0x30,0x2, 0x6, +0xe4,0x12,0x9, 0x33,0xf5,0x91,0x30,0x91,0xb, 0xc2,0x91,0x5, 0x39,0xe5,0x39,0x12, +0x9, 0x33,0xf5,0x91,0xda,0xb, 0xda,0x1b,0xda,0x2b,0x32,0xd2,0x6, 0x12,0xe, 0xdf, +0xa9,0xc2,0xb4,0x74,0x9f,0x12,0xf, 0x27,0x12,0xf, 0xe, 0xa9,0xd2,0xb4,0x60,0x3, +0xb4,0xff,0x1a,0x75,0x24,0x81,0xa9,0xd5,0xca,0xa9,0xd0,0xca,0x75,0xed,0x9f,0x75, +0xad,0x20,0xa9,0xd1,0xea,0xa9,0xc1,0xea,0x74,0x1, 0x2, 0xd, 0xe0,0x2, 0xd, 0x80, +0xd2,0x6, 0x12,0xe, 0xdf,0xa9,0xc2,0xb4,0x74,0x5, 0x12,0xf, 0x27,0x12,0xf, 0xe, +0x7c,0xab,0xa9,0xd2,0xb4,0xd2,0x6, 0x12,0xe, 0xdf,0x5e,0xa0,0xe3,0xa9,0xc2,0xb4, +0x74,0x1, 0x12,0xf, 0x27,0x7c,0xba,0x12,0xf, 0x27,0xa9,0xd2,0xb4,0x12,0xe, 0xca, +0x40,0xfb,0x22,0x7c,0xab,0x7d,0x12,0x7c,0xb3,0xf5,0x1c,0x7c,0x36,0x7c,0x25,0xa, +0x4, 0x7c,0xb3,0xf5,0x1b,0x7c,0xb7,0xf5,0x1a,0xa9,0xc2,0xb4,0x7c,0xba,0x12,0xf, +0x27,0xe5,0x1c,0x12,0xf, 0x27,0xe5,0x1b,0x12,0xf, 0x27,0xe5,0x1a,0x2, 0xf, 0x27, +0xca,0xf8,0x7c,0xfb,0xe5,0x24,0xb4,0x81,0x21,0x74,0x2, 0x12,0xa, 0x89,0x4c,0xff, +0x78,0x8, 0xa9,0xc0,0xca,0x5e,0x70,0xdf,0x80,0x6, 0xa9,0xd0,0xca,0x4e,0x70,0x20, +0x74,0x2, 0x12,0xc, 0x86,0x74,0x2, 0x12,0xa, 0x89,0xda,0xf8,0x22,0xd2,0x6, 0x7e, +0x14,0x0, 0x8, 0x7a,0x15,0x15,0x7e,0x8, 0x2, 0xdc,0x12,0xe, 0xf2,0x6c,0xaa,0xa, +0x3a,0x9, 0xb3,0x2, 0xdc,0xbe,0xb0,0xff,0x68,0x4, 0xc2,0x6, 0x80,0x7, 0xb, 0xa0, +0xbe,0xa0,0x8, 0x40,0xea,0xa2,0x6, 0x22,0x7d,0x52,0xf5,0x19,0x7c,0xb6,0x7c,0xa5, +0xa, 0x44,0xf5,0x18,0x7f,0x21,0xf5,0x17,0xa9,0xc2,0xb4,0x74,0xb, 0x12,0xf, 0x27, +0xe5,0x19,0x12,0xf, 0x27,0xe5,0x18,0x12,0xf, 0x27,0xe5,0x17,0x12,0xf, 0x27,0xe4, +0x2, 0xf, 0x27,0x12,0xe, 0xa9,0x12,0xb, 0x3b,0xa9,0xa6,0x94,0xb3,0x92,0x8, 0x30, +0x8, 0x6, 0x12,0xf, 0x1b,0x12,0xd, 0x4b,0x12,0x9, 0xab,0x12,0xf, 0x0, 0xd2,0xaf, +0x30,0x3, 0xfd,0x2, 0xf, 0x45,0x80,0x18,0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0xe5,0x3e,0x70,0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x7d,0x23,0x1b,0x34,0x4d,0x22,0x78,0xe0,0x22,0xd2,0xcf,0x85,0x3e,0xcc,0x75,0xec, +0xff,0x75,0xee,0xff,0x75,0xeb,0x3, 0x75,0xac,0xc0,0xa9,0xc5,0xca,0x75,0xed,0xf, +0x75,0xad,0xb0,0xa9,0xd7,0x94,0xa9,0xd4,0x94,0x22,0xa9,0xc2,0xb4,0x74,0x5, 0x12, +0xf, 0x27,0x12,0xf, 0xe, 0xa9,0xd2,0xb4,0x30,0xe0,0x2, 0xd3,0x22,0xc3,0x22,0xa9, +0xc2,0xb4,0x30,0x6, 0x4, 0x74,0x6, 0x80,0x2, 0x74,0x4, 0x12,0xf, 0x27,0xa9,0xd2, +0xb4,0x22,0x12,0xe, 0x38,0x7e,0x35,0x15,0x12,0x0, 0xe, 0xa9,0xd2,0xb4,0xd3,0x22, +0xc2,0x8c,0x43,0x89,0x2, 0x75,0x8c,0x1, 0x75,0x8a,0x0, 0xd2,0xa9,0x22,0x75,0xb5, +0x0, 0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3,0xe5,0xb5,0x22,0xd2,0xc8,0x75,0xb3,0x13, +0xa9,0xd1,0xb4,0xa9,0xc0,0xb4,0x22,0xf5,0xb5,0xa9,0x36,0xb3,0xfc,0xa9,0xc6,0xb3, +0xd3,0x22,0xc2,0x8c,0x6d,0x33,0x7a,0x35,0x42,0xd2,0x8c,0x22,0x7e,0x35,0x42,0xb, +0x34,0x7a,0x35,0x42,0x22,0x85,0x3e,0xcc,0xe5,0x3e,0x2, 0xd, 0xe0,0x2, 0xf, 0x3c, +0x0, 0x1, 0x2, 0xe4,0x0, 0x0, 0x4, 0x2, 0xe5,0x0, 0x0, 0x9c,0x0, 0x0, 0x0, 0xff, diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..9e5b04742b376a16c2f391532f20bce962173ec0 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Kconfig @@ -0,0 +1,117 @@ +# +# Himax Touchscreen driver configuration +# + +config TOUCHSCREEN_HIMAX_COMMON + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + This enables support for HIMAX CHIPSET over I2C based touchscreens. + +choice + prompt "HIMAX touch IC types" + depends on TOUCHSCREEN_HIMAX_COMMON + default TOUCHSCREEN_HIMAX_INCELL + +config TOUCHSCREEN_HIMAX_ONCELL + bool "HIMAX chipset on-cell function" + depends on TOUCHSCREEN_HIMAX_COMMON + help + This enables support for HIMAX CHIPSET of on-cell function. + +config TOUCHSCREEN_HIMAX_INCELL + bool "HIMAX chipset in-cell function" + depends on TOUCHSCREEN_HIMAX_COMMON + help + This enables support for HIMAX CHIPSET of in-cell function. + +endchoice + +# ***************** On-cell Start ***************** +config TOUCHSCREEN_HIMAX_IC_HX852xH + tristate "HIMAX chipset HX852xH function" + depends on TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX CHIPSET of HX852xH. + +config TOUCHSCREEN_HIMAX_IC_HX852xG + tristate "HIMAX chipset HX852xG function" + depends on TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX CHIPSET of HX852xG. + +# ***************** On-cell End ******************* +# ***************** In-cell Start ***************** +config TOUCHSCREEN_HIMAX_IC_HX83192 + tristate "HIMAX chipset HX83192 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83192. + +config TOUCHSCREEN_HIMAX_IC_HX83191 + tristate "HIMAX chipset HX83191 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83191. + +config TOUCHSCREEN_HIMAX_IC_HX83113 + tristate "HIMAX chipset HX83113 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83113. + +config TOUCHSCREEN_HIMAX_IC_HX83112 + tristate "HIMAX chipset HX83112 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83112. + +config TOUCHSCREEN_HIMAX_IC_HX83111 + tristate "HIMAX chipset HX83111 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83111. + +config TOUCHSCREEN_HIMAX_IC_HX83106 + tristate "HIMAX chipset HX83106 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83106. + +config TOUCHSCREEN_HIMAX_IC_HX83103 + tristate "HIMAX chipset HX83103 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83103. + +config TOUCHSCREEN_HIMAX_IC_HX83102 + tristate "HIMAX chipset HX83102 function" + depends on TOUCHSCREEN_HIMAX_INCELL + help + This enables support for HIMAX CHIPSET of HX83102. + +# ***************** In-cell End ******************* + +config TOUCHSCREEN_HIMAX_DEBUG + bool "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_INCELL || TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX debug function. +config TOUCHSCREEN_HIMAX_INSPECT + bool "HIMAX inspect function" + depends on TOUCHSCREEN_HIMAX_INCELL || TOUCHSCREEN_HIMAX_ONCELL + help + This enables support for HIMAX debug function. + +config TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE + bool "HIMAX embedded firmware function" + depends on TOUCHSCREEN_HIMAX_INCELL || TOUCHSCREEN_HIMAX_ONCELL + help + This enables built-in FW inside kernel as binary array + +config HMX_DB + bool "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_COMMON + help + This enables support for HIMAX driver test over Dragon Board. + diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48ab92a3619bb4615ec6e17085fdee9d81d73069 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Makefile @@ -0,0 +1,166 @@ +# Makefile for the Himax touchscreen drivers. + +ifneq ($(filter y, $(CONFIG_KALLSYMS_ALL)),) + ccflags-y += -D__KERNEL_KALLSYMS_ALL_ENABLED__ +endif + +ifneq ($(filter y, $(CONFIG_DRM)),) + ccflags-y += -DHX_CONFIG_DRM +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)),) + himax_mmi-objs += himax_debug.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_INSPECT)),) + himax_mmi-objs += himax_inspection.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_INCELL)),) + himax_mmi-objs += himax_ic_incell_core.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_ONCELL)),) + himax_mmi-objs += himax_ic_oncell_core.o +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xG)),) + ccflags-y += -D__HIMAX_HX852xG_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX852xG.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX852xG.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX852xH)),) + ccflags-y += -D__HIMAX_HX852xH_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX852xH.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX852xH.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83102)),) + ccflags-y += -D__HIMAX_HX83102_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83102.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83102.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83103)),) + ccflags-y += -D__HIMAX_HX83103_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83103.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83103.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83106)),) + ccflags-y += -D__HIMAX_HX83106_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83106.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83106.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83111)),) + ccflags-y += -D__HIMAX_HX83111_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83111.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83111.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112)),) + ccflags-y += -D__HIMAX_HX83112_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83112.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83112.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83113)),) + ccflags-y += -D__HIMAX_HX83113_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83113.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83113.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83192)),) + ccflags-y += -D__HIMAX_HX83192_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83192.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83192.o + endif +endif + +ifneq ($(filter y m, $(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83191)),) + ccflags-y += -D__HIMAX_HX83191_MOD__ + ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-m += himax_ic_HX83191.o + endif + ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + obj-y += himax_ic_HX83191.o + endif +endif + +ifneq ($(filter m, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + ccflags-y += -D__HIMAX_MOD__ + himax_mmi-objs += himax_common.o + himax_mmi-objs += himax_platform.o +ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE)),) + himax_mmi-objs += Himax_firmware.o +endif + obj-m += himax_mmi.o +endif +ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_COMMON)),) + himax_mmi-objs += himax_common.o + himax_mmi-objs += himax_platform.o +ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE)),) + himax_mmi-objs += Himax_firmware.o +endif + obj-y += himax_mmi.o +endif + +ifneq ($(filter y, $(CONFIG_TOUCHSCREEN_HIMAX_EMBEDDED_FIRMWARE)),) +ccflags-y += -D__EMBEDDED_FW__ + +ld_array_start_str = _binary_$(srctree)/$(src)_Himax_firmware_bin_start +ld_array_start_sym = $(subst -,_,$(subst .,_,$(subst /,_,$(ld_array_start_str)))) +obj_array_start_sym = _binary___Himax_firmware_bin_start + +ld_array_size_str = _binary_$(srctree)/$(src)_Himax_firmware_bin_size +ld_array_size_sym = $(subst -,_,$(subst .,_,$(subst /,_,$(ld_array_size_str)))) +obj_array_size_sym = _binary___Himax_firmware_bin_size + +ld_array_end_str = _binary_$(srctree)/$(src)_Himax_firmware_bin_end +ld_array_end_sym = $(subst -,_,$(subst .,_,$(subst /,_,$(ld_array_end_str)))) +obj_array_end_sym = _binary___Himax_firmware_bin_end + +$(src)/Himax_firmware.o: $(src)/Himax_firmware.bin FORCE + $(LD) $(LDFLAGS) -r -b binary $(srctree)/$(src)/Himax_firmware.bin -o $(objtree)/$(obj)/Himax_firmware.o + $(OBJCOPY) --redefine-sym $(ld_array_start_sym)=$(obj_array_start_sym) $(objtree)/$(obj)/Himax_firmware.o + $(OBJCOPY) --redefine-sym $(ld_array_size_sym)=$(obj_array_size_sym) $(objtree)/$(obj)/Himax_firmware.o + $(OBJCOPY) --redefine-sym $(ld_array_end_sym)=$(obj_array_end_sym) $(objtree)/$(obj)/Himax_firmware.o + +endif diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c new file mode 100644 index 0000000000000000000000000000000000000000..81bbbbb62ee8e39e781c71f32fa44a91f08d7eb0 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -0,0 +1,3430 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for common functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +/*#include "himax_common.h"*/ +/*#include "himax_ic_core.h"*/ +#include "himax_inspection.h" +#include "himax_modular_table.h" + +#if defined(__HIMAX_MOD__) +int (*hx_msm_drm_register_client)(struct notifier_block *nb); +int (*hx_msm_drm_unregister_client)(struct notifier_block *nb); +#endif + +#if defined(HX_SMART_WAKEUP) +#define GEST_SUP_NUM 26 +/* Setting cust key define (DF = double finger) */ +/* {Double Tap, Up, Down, Left, Right, C, Z, M, + * O, S, V, W, e, m, @, (reserve), + * Finger gesture, ^, >, <, f(R), f(L), Up(DF), Down(DF), + * Left(DF), Right(DF)} + */ +uint8_t gest_event[GEST_SUP_NUM] = { + 0x80, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x81, 0x1D, 0x2D, 0x3D, 0x1F, 0x2F, 0x51, 0x52, + 0x53, 0x54}; + +/*gest_event mapping to gest_key_def*/ +uint16_t gest_key_def[GEST_SUP_NUM] = { + HX_KEY_DOUBLE_CLICK, HX_KEY_UP, HX_KEY_DOWN, HX_KEY_LEFT, + HX_KEY_RIGHT, HX_KEY_C, HX_KEY_Z, HX_KEY_M, + HX_KEY_O, HX_KEY_S, HX_KEY_V, HX_KEY_W, + HX_KEY_E, HX_KEY_LC_M, HX_KEY_AT, HX_KEY_RESERVE, + HX_KEY_FINGER_GEST, HX_KEY_V_DOWN, HX_KEY_V_LEFT, HX_KEY_V_RIGHT, + HX_KEY_F_RIGHT, HX_KEY_F_LEFT, HX_KEY_DF_UP, HX_KEY_DF_DOWN, + HX_KEY_DF_LEFT, HX_KEY_DF_RIGHT}; + +uint8_t *wake_event_buffer; +#endif + +#if !defined(HX_USE_KSYM) +struct himax_chip_entry himax_ksym_lookup; +EXPORT_SYMBOL(himax_ksym_lookup); +#endif + +#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F +#define TS_WAKE_LOCK_TIMEOUT (5000) +#define FRAME_COUNT 5 + +#if defined(HX_TP_PROC_GUEST_INFO) +struct hx_guest_info *g_guest_info_data; +EXPORT_SYMBOL(g_guest_info_data); + +char *g_guest_info_item[] = { + "projectID", + "CGColor", + "BarCode", + "Reserve1", + "Reserve2", + "Reserve3", + "Reserve4", + "Reserve5", + "VCOM", + "Vcom-3Gar", + NULL +}; +#endif + +uint32_t g_hx_chip_inited; + +#if defined(__EMBEDDED_FW__) +struct firmware g_embedded_fw = { + .data = _binary___Himax_firmware_bin_start, +}; +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +bool g_boot_upgrade_flag; +const struct firmware *hxfw; +int g_i_FW_VER; +int g_i_CFG_VER; +int g_i_CID_MAJ; /*GUEST ID*/ +int g_i_CID_MIN; /*VER for GUEST*/ +#if defined(HX_ZERO_FLASH) +int g_f_0f_updat; +#endif +#endif + +struct himax_ts_data *private_ts; +EXPORT_SYMBOL(private_ts); + +struct himax_ic_data *ic_data; +EXPORT_SYMBOL(ic_data); + +struct himax_report_data *hx_touch_data; +EXPORT_SYMBOL(hx_touch_data); + +struct himax_core_fp g_core_fp; +EXPORT_SYMBOL(g_core_fp); + +struct himax_debug *debug_data; +EXPORT_SYMBOL(debug_data); + +struct proc_dir_entry *himax_touch_proc_dir; +EXPORT_SYMBOL(himax_touch_proc_dir); + +int g_mmi_refcnt; +EXPORT_SYMBOL(g_mmi_refcnt); + +#define HIMAX_PROC_TOUCH_FOLDER "android_touch" +/*ts_work about start*/ +struct himax_target_report_data *g_target_report_data; +EXPORT_SYMBOL(g_target_report_data); + +static void himax_report_all_leave_event(struct himax_ts_data *ts); +/*ts_work about end*/ + +struct filename* (*kp_getname_kernel)(const char *filename); +void (*kp_putname_kernel)(struct filename *name); +struct file* (*kp_file_open_name)(struct filename *name, + int flags, umode_t mode); + +unsigned long FW_VER_MAJ_FLASH_ADDR; +EXPORT_SYMBOL(FW_VER_MAJ_FLASH_ADDR); + +unsigned long FW_VER_MIN_FLASH_ADDR; +EXPORT_SYMBOL(FW_VER_MIN_FLASH_ADDR); + +unsigned long CFG_VER_MAJ_FLASH_ADDR; +EXPORT_SYMBOL(CFG_VER_MAJ_FLASH_ADDR); + +unsigned long CFG_VER_MIN_FLASH_ADDR; +EXPORT_SYMBOL(CFG_VER_MIN_FLASH_ADDR); + +unsigned long CID_VER_MAJ_FLASH_ADDR; +EXPORT_SYMBOL(CID_VER_MAJ_FLASH_ADDR); + +unsigned long CID_VER_MIN_FLASH_ADDR; +EXPORT_SYMBOL(CID_VER_MIN_FLASH_ADDR); +/*unsigned long PANEL_VERSION_ADDR;*/ +uint32_t CFG_TABLE_FLASH_ADDR; +EXPORT_SYMBOL(CFG_TABLE_FLASH_ADDR); + +unsigned char IC_CHECKSUM; +EXPORT_SYMBOL(IC_CHECKSUM); + +#if defined(HX_EXCP_RECOVERY) +u8 HX_EXCP_RESET_ACTIVATE; +EXPORT_SYMBOL(HX_EXCP_RESET_ACTIVATE); + +int hx_EB_event_flag; +EXPORT_SYMBOL(hx_EB_event_flag); + +int hx_EC_event_flag; +EXPORT_SYMBOL(hx_EC_event_flag); + +int hx_ED_event_flag; +EXPORT_SYMBOL(hx_ED_event_flag); + +int g_zero_event_count; + +#endif + +static bool chip_test_r_flag; +u8 HX_HW_RESET_ACTIVATE; + +static uint8_t AA_press; +static uint8_t EN_NoiseFilter; +static uint8_t Last_EN_NoiseFilter; + +static int p_point_num = 0xFFFF; +static int probe_fail_flag; +#if defined(HX_USB_DETECT_GLOBAL) +bool USB_detect_flag; +#endif + +#if defined(HX_GESTURE_TRACK) +static int gest_pt_cnt; +static int gest_pt_x[GEST_PT_MAX_NUM]; +static int gest_pt_y[GEST_PT_MAX_NUM]; +static int gest_start_x, gest_start_y, gest_end_x, gest_end_y; +static int gest_width, gest_height, gest_mid_x, gest_mid_y; +static int hx_gesture_coor[16]; +#endif + +int g_ts_dbg; +EXPORT_SYMBOL(g_ts_dbg); + +/* File node for Selftest, SMWP and HSEN - Start*/ +#define HIMAX_PROC_SELF_TEST_FILE "self_test" +struct proc_dir_entry *himax_proc_self_test_file; + +uint8_t HX_PROC_SEND_FLAG; +EXPORT_SYMBOL(HX_PROC_SEND_FLAG); + +#if defined(HX_SMART_WAKEUP) +#define HIMAX_PROC_SMWP_FILE "SMWP" +struct proc_dir_entry *himax_proc_SMWP_file; +#define HIMAX_PROC_GESTURE_FILE "GESTURE" +struct proc_dir_entry *himax_proc_GESTURE_file; +uint8_t HX_SMWP_EN; +#if defined(HX_ULTRA_LOW_POWER) +#define HIMAX_PROC_PSENSOR_FILE "Psensor" +struct proc_dir_entry *himax_proc_psensor_file; +#endif +#endif + +#if defined(HX_HIGH_SENSE) +#define HIMAX_PROC_HSEN_FILE "HSEN" +struct proc_dir_entry *himax_proc_HSEN_file; +#endif + +#define HIMAX_PROC_VENDOR_FILE "vendor" +struct proc_dir_entry *himax_proc_vendor_file; + +#if defined(HX_PALM_REPORT) +static int himax_palm_detect(uint8_t *buf) +{ + struct himax_ts_data *ts = private_ts; + int32_t loop_i; + int base = 0; + int x = 0, y = 0, w = 0; + + loop_i = 0; + base = loop_i * 4; + x = buf[base] << 8 | buf[base + 1]; + y = (buf[base + 2] << 8 | buf[base + 3]); + w = buf[(ts->nFinger_support * 4) + loop_i]; + I(" %s HX_PALM_REPORT_loopi=%d,base=%x,X=%x,Y=%x,W=%x\n", + __func__, loop_i, base, x, y, w); + if ((!atomic_read(&ts->suspend_mode)) + && (x == 0xFA5A) + && (y == 0xFA5A) + && (w == 0x00)) + return PALM_REPORT; + else + return NOT_REPORT; +} +#endif + +static ssize_t himax_self_test(struct seq_file *s, void *v) +{ + int val = 0x00; + size_t ret = 0; + + I("%s: enter, %d\n", __func__, __LINE__); + + if (private_ts->suspended == 1) { + E("%s: please do self test in normal active mode\n", __func__); + return HX_INIT_FAIL; + } + + himax_int_enable(0);/* disable irq */ + + private_ts->in_self_test = 1; + + val = g_core_fp.fp_chip_self_test(s, v); +/* + *#if defined(HX_EXCP_RECOVERY) + * HX_EXCP_RESET_ACTIVATE = 1; + *#endif + * himax_int_enable(1); //enable irq + */ + + private_ts->in_self_test = 0; + +#if defined(HX_EXCP_RECOVERY) + HX_EXCP_RESET_ACTIVATE = 1; +#endif + himax_int_enable(1); + + return ret; +} + +static void *himax_self_test_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) + return NULL; + + + return (void *)((unsigned long) *pos + 1); +} + +static void *himax_self_test_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} + +static void himax_self_test_seq_stop(struct seq_file *s, void *v) +{ +} + +static int himax_self_test_seq_read(struct seq_file *s, void *v) +{ + size_t ret = 0; + + if (chip_test_r_flag) { +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + if (g_rslt_data) + seq_printf(s, "%s", g_rslt_data); + else +#endif + seq_puts(s, "No chip test data.\n"); + } else { + himax_self_test(s, v); + } + + return ret; +} + +static const struct seq_operations himax_self_test_seq_ops = { + .start = himax_self_test_seq_start, + .next = himax_self_test_seq_next, + .stop = himax_self_test_seq_stop, + .show = himax_self_test_seq_read, +}; + +static int himax_self_test_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_self_test_seq_ops); +}; + +static ssize_t himax_self_test_write(struct file *filp, const char __user *buff, + size_t len, loff_t *data) +{ + char buf[80]; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == 'r') { + chip_test_r_flag = true; + I("%s: Start to read chip test data.\n", __func__); + } else { + chip_test_r_flag = false; + I("%s: Back to do self test.\n", __func__); + } + + return len; +} + +static const struct file_operations himax_proc_self_test_ops = { + .owner = THIS_MODULE, + .open = himax_self_test_proc_open, + .read = seq_read, + .write = himax_self_test_write, + .release = seq_release, +}; + +#if defined(HX_HIGH_SENSE) +static ssize_t himax_HSEN_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t count = 0; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + count = snprintf(temp_buf, PAGE_SIZE, "%d\n", + ts->HSEN_enable); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + } + + return count; +} + +static ssize_t himax_HSEN_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->HSEN_enable = 0; + else if (buf[0] == '1') + ts->HSEN_enable = 1; + else + return -EINVAL; + + g_core_fp.fp_set_HSEN_enable(ts->HSEN_enable, ts->suspended); + I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); + return len; +} + +static const struct file_operations himax_proc_HSEN_ops = { + .owner = THIS_MODULE, + .read = himax_HSEN_read, + .write = himax_HSEN_write, +}; +#endif + +#if defined(HX_SMART_WAKEUP) +static ssize_t himax_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + count = snprintf(temp_buf, PAGE_SIZE, "%d\n", + ts->SMWP_enable); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + } + + return count; +} + +static ssize_t himax_SMWP_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') + ts->SMWP_enable = 0; + else if (buf[0] == '1') + ts->SMWP_enable = 1; + else + return -EINVAL; + + g_core_fp.fp_set_SMWP_enable(ts->SMWP_enable, ts->suspended); + HX_SMWP_EN = ts->SMWP_enable; + I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); + return len; +} + +static const struct file_operations himax_proc_SMWP_ops = { + .owner = THIS_MODULE, + .read = himax_SMWP_read, + .write = himax_SMWP_write, +}; + +static ssize_t himax_GESTURE_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + size_t ret = 0; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + for (i = 0; i < GEST_SUP_NUM; i++) + ret += snprintf(temp_buf + ret, len - ret, + "ges_en[%d]=%d\n", + i, ts->gesture_cust_en[i]); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + ret = 0; + } + + return ret; +} + +static ssize_t himax_GESTURE_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i = 0; + int j = 0; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + I("himax_GESTURE_store= %s, len = %d\n", buf, (int)len); + + for (i = 0; i < len; i++) { + if (buf[i] == '0' && j < GEST_SUP_NUM) { + ts->gesture_cust_en[j] = 0; + I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]); + j++; + } else if (buf[i] == '1' && j < GEST_SUP_NUM) { + ts->gesture_cust_en[j] = 1; + I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]); + j++; + } else + I("Not 0/1 or >=GEST_SUP_NUM : buf[%d] = %c\n", + i, buf[i]); + } + + return len; +} + +static const struct file_operations himax_proc_Gesture_ops = { + .owner = THIS_MODULE, + .read = himax_GESTURE_read, + .write = himax_GESTURE_write, +}; + +#if defined(HX_ULTRA_LOW_POWER) +static ssize_t himax_psensor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + if (temp_buf != NULL) { + count = snprintf(temp_buf, PAGE_SIZE, + "p-sensor flag = %d\n", + ts->psensor_flag); + + if (copy_to_user(buf, temp_buf, len)) + I("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + E("%s, Failed to allocate memory\n", __func__); + } + } else { + HX_PROC_SEND_FLAG = 0; + } + + return count; +} + +static ssize_t himax_psensor_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0' && ts->SMWP_enable == 1) { + ts->psensor_flag = false; + g_core_fp.fp_black_gest_ctrl(false); + } else if (buf[0] == '1' && ts->SMWP_enable == 1) { + ts->psensor_flag = true; + g_core_fp.fp_black_gest_ctrl(true); + } else if (ts->SMWP_enable == 0) { + I("%s: SMWP is disable, not supprot to ctrl p-sensor.\n", + __func__); + } else + return -EINVAL; + + I("%s: psensor_flag = %d.\n", __func__, ts->psensor_flag); + return len; +} + +static const struct file_operations himax_proc_psensor_ops = { + .owner = THIS_MODULE, + .read = himax_psensor_read, + .write = himax_psensor_write, +}; +#endif +#endif + +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *temp_buf = NULL; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL); + ret += snprintf(temp_buf + ret, len - ret, + "IC = %s\n", private_ts->chip_name); + + ret += snprintf(temp_buf + ret, len - ret, + "FW_VER = 0x%2.2X\n", ic_data->vendor_fw_ver); + + if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) { + ret += snprintf(temp_buf + ret, len - ret, + "CONFIG_VER = 0x%2.2X\n", + ic_data->vendor_config_ver); + } else { + ret += snprintf(temp_buf + ret, len - ret, + "TOUCH_VER = 0x%2.2X\n", + ic_data->vendor_touch_cfg_ver); + ret += snprintf(temp_buf + ret, len - ret, + "DISPLAY_VER = 0x%2.2X\n", + ic_data->vendor_display_cfg_ver); + } + + if (ic_data->vendor_cid_maj_ver < 0 + && ic_data->vendor_cid_min_ver < 0) { + ret += snprintf(temp_buf + ret, len - ret, + "CID_VER = NULL\n"); + } else { + ret += snprintf(temp_buf + ret, len - ret, + "CID_VER = 0x%2.2X\n", + (ic_data->vendor_cid_maj_ver << 8 | + ic_data->vendor_cid_min_ver)); + } + + if (ic_data->vendor_panel_ver < 0) { + ret += snprintf(temp_buf + ret, len - ret, + "PANEL_VER = NULL\n"); + } else { + ret += snprintf(temp_buf + ret, len - ret, + "PANEL_VER = 0x%2.2X\n", + ic_data->vendor_panel_ver); + } + if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) { + ret += snprintf(temp_buf + ret, len - ret, + "Cusomer = %s\n", + ic_data->vendor_cus_info); + ret += snprintf(temp_buf + ret, len - ret, + "Project = %s\n", + ic_data->vendor_proj_info); + } + ret += snprintf(temp_buf + ret, len - ret, "\n"); + ret += snprintf(temp_buf + ret, len - ret, + "Himax Touch Driver Version:\n"); + ret += snprintf(temp_buf + ret, len - ret, "%s\n", + HIMAX_DRIVER_VER); + + if (copy_to_user(buf, temp_buf, len)) + I("%s,here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + HX_PROC_SEND_FLAG = 0; + } + + return ret; +} +static const struct file_operations himax_proc_vendor_ops = { + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; + +int himax_common_proc_init(void) +{ + himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL); + + if (himax_touch_proc_dir == NULL) { + E(" %s: himax_touch_proc_dir file create failed!\n", __func__); + return -ENOMEM; + } +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + if (fp_himax_self_test_init != NULL) + fp_himax_self_test_init(); +#endif + + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, 0444, + himax_touch_proc_dir, &himax_proc_self_test_ops); + if (himax_proc_self_test_file == NULL) { + E(" %s: proc self_test file create failed!\n", __func__); + goto fail_1; + } + +#if defined(HX_HIGH_SENSE) + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, 0666, + himax_touch_proc_dir, &himax_proc_HSEN_ops); + + if (himax_proc_HSEN_file == NULL) { + E(" %s: proc HSEN file create failed!\n", __func__); + goto fail_2; + } + +#endif +#if defined(HX_SMART_WAKEUP) + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, 0666, + himax_touch_proc_dir, &himax_proc_SMWP_ops); + + if (himax_proc_SMWP_file == NULL) { + E(" %s: proc SMWP file create failed!\n", __func__); + goto fail_3; + } + + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, 0666, + himax_touch_proc_dir, &himax_proc_Gesture_ops); + + if (himax_proc_GESTURE_file == NULL) { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_4; + } +#if defined(HX_ULTRA_LOW_POWER) + himax_proc_psensor_file = proc_create(HIMAX_PROC_PSENSOR_FILE, 0666, + himax_touch_proc_dir, &himax_proc_psensor_ops); + + if (himax_proc_psensor_file == NULL) { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_5; + } +#endif +#endif + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, 0444, + himax_touch_proc_dir, &himax_proc_vendor_ops); + if (himax_proc_vendor_file == NULL) { + E(" %s: proc vendor file create failed!\n", __func__); + goto fail_6; + } + + return 0; + + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +fail_6: +#if defined(HX_SMART_WAKEUP) +#if defined(HX_ULTRA_LOW_POWER) + remove_proc_entry(HIMAX_PROC_PSENSOR_FILE, himax_touch_proc_dir); +fail_5: +#endif + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); +fail_4: + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +fail_3: +#endif +#if defined(HX_HIGH_SENSE) + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +fail_2: +#endif + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +fail_1: + return -ENOMEM; +} + +void himax_common_proc_deinit(void) +{ + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +#if defined(HX_SMART_WAKEUP) +#if defined(HX_ULTRA_LOW_POWER) + remove_proc_entry(HIMAX_PROC_PSENSOR_FILE, himax_touch_proc_dir); +#endif + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +#endif +#if defined(HX_HIGH_SENSE) + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +#endif + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); + + remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); +} + +/* File node for SMWP and HSEN - End*/ + +void himax_parse_assign_cmd(uint32_t addr, uint8_t *cmd, int len) +{ + /*I("%s: Entering!\n", __func__);*/ + + switch (len) { + case 1: + cmd[0] = addr; + /*I("%s: cmd[0] = 0x%02X\n", __func__, cmd[0]);*/ + break; + + case 2: + cmd[0] = addr % 0x100; + cmd[1] = (addr >> 8) % 0x100; + /*I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X\n",*/ + /* __func__, cmd[0], cmd[1]);*/ + break; + + case 4: + cmd[0] = addr % 0x100; + cmd[1] = (addr >> 8) % 0x100; + cmd[2] = (addr >> 16) % 0x100; + cmd[3] = addr / 0x1000000; + /* I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X,*/ + /*cmd[2] = 0x%02X,cmd[3] = 0x%02X\n", */ + /* __func__, cmd[0], cmd[1], cmd[2], cmd[3]);*/ + break; + + default: + E("%s: input length fault,len = %d!\n", __func__, len); + } +} +EXPORT_SYMBOL(himax_parse_assign_cmd); + +int himax_input_register(struct himax_ts_data *ts) +{ + int ret = 0; +#if defined(HX_SMART_WAKEUP) + int i = 0; +#endif + ret = himax_dev_set(ts); + + if (ret < 0) { + I("%s, input device register fail!\n", __func__); + ret = INPUT_REGISTER_FAIL; + goto input_device_fail; + } + + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + set_bit(KEY_BACK, ts->input_dev->keybit); + set_bit(KEY_HOME, ts->input_dev->keybit); + set_bit(KEY_MENU, ts->input_dev->keybit); + set_bit(KEY_SEARCH, ts->input_dev->keybit); + +#if defined(HX_SMART_WAKEUP) + for (i = 0; i < GEST_SUP_NUM; i++) + set_bit(gest_key_def[i], ts->input_dev->keybit); +#elif defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) || defined(HX_PALM_REPORT) + set_bit(KEY_POWER, ts->input_dev->keybit); +#endif + set_bit(BTN_TOUCH, ts->input_dev->keybit); + set_bit(KEY_APPSELECT, ts->input_dev->keybit); + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); +#if defined(HX_PROTOCOL_A) + /*ts->input_dev->mtsize = ts->nFinger_support;*/ + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 1, 10, 0, 0); +#else + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); +#if defined(HX_PROTOCOL_B_3PA) + input_mt_init_slots(ts->input_dev, ts->nFinger_support, + INPUT_MT_DIRECT); +#else + input_mt_init_slots(ts->input_dev, ts->nFinger_support); +#endif +#endif + I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, + ts->pdata->abs_x_max, + ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, + ts->pdata->abs_y_min, ts->pdata->abs_y_max, + ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, + ts->pdata->abs_pressure_min, + ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); +#if !defined(HX_PROTOCOL_A) + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, + ts->pdata->abs_pressure_min, + ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, + ts->pdata->abs_width_min, + ts->pdata->abs_width_max, + ts->pdata->abs_pressure_fuzz, 0); +#endif +/* input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0,*/ +/* ((ts->pdata->abs_pressure_max << 16)*/ +/* | ts->pdata->abs_width_max),*/ +/* 0, 0);*/ +/* input_set_abs_params(ts->input_dev, ABS_MT_POSITION,*/ +/* 0, (BIT(31)*/ +/* | (ts->pdata->abs_x_max << 16)*/ +/* | ts->pdata->abs_y_max),*/ +/* 0, 0);*/ + + if (himax_input_register_device(ts->input_dev) == 0) { + ret = NO_ERR; + } else { + E("%s: input register fail\n", __func__); + ret = INPUT_REGISTER_FAIL; + goto input_device_fail; + } + + if (!ic_data->HX_PEN_FUNC) + goto skip_pen_operation; + + set_bit(EV_SYN, ts->hx_pen_dev->evbit); + set_bit(EV_ABS, ts->hx_pen_dev->evbit); + set_bit(EV_KEY, ts->hx_pen_dev->evbit); + set_bit(BTN_TOUCH, ts->hx_pen_dev->keybit); + set_bit(INPUT_PROP_DIRECT, ts->hx_pen_dev->propbit); + + set_bit(BTN_TOOL_PEN, ts->hx_pen_dev->keybit); + set_bit(BTN_TOOL_RUBBER, ts->hx_pen_dev->keybit); + + input_set_abs_params(ts->hx_pen_dev, ABS_PRESSURE, 0, 4095, 0, 0); + input_set_abs_params(ts->hx_pen_dev, ABS_DISTANCE, 0, 1, 0, 0); + input_set_abs_params(ts->hx_pen_dev, ABS_TILT_X, -60, 60, 0, 0); + input_set_abs_params(ts->hx_pen_dev, ABS_TILT_Y, -60, 60, 0, 0); + /*input_set_capability(ts->hx_pen_dev, EV_SW, SW_PEN_INSERT);*/ + input_set_capability(ts->hx_pen_dev, EV_KEY, BTN_TOUCH); + input_set_capability(ts->hx_pen_dev, EV_KEY, BTN_STYLUS); + input_set_capability(ts->hx_pen_dev, EV_KEY, BTN_STYLUS2); + + input_set_abs_params(ts->hx_pen_dev, ABS_X, ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->hx_pen_dev, ABS_Y, ts->pdata->abs_y_min, + ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + + if (himax_input_register_device(ts->hx_pen_dev) == 0) { + ret = NO_ERR; + } else { + E("%s: input register pen fail\n", __func__); + ret = INPUT_REGISTER_FAIL; + goto input_device_fail; + } + +skip_pen_operation: + + I("%s, input device registered.\n", __func__); + +input_device_fail: + return ret; +} +EXPORT_SYMBOL(himax_input_register); + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +static int himax_auto_update_check(void) +{ + int32_t ret; + + I("%s: Entering!\n", __func__); + if (g_core_fp.fp_fw_ver_bin() == 0) { + if (((ic_data->vendor_fw_ver < g_i_FW_VER) + || (ic_data->vendor_config_ver < g_i_CFG_VER))) { + I("%s: Need update\n", __func__); + ret = 0; + } else { + I("%s: Need not update!\n", __func__); + ret = 1; + } + } else { + E("%s: FW bin fail!\n", __func__); + ret = 1; + } + + return ret; +} + +static int i_get_FW(void) +{ + int ret = -1; + int result = NO_ERR; + + I("%s: file name = %s\n", __func__, BOOT_UPGRADE_FWNAME); + ret = request_firmware(&hxfw, BOOT_UPGRADE_FWNAME, private_ts->dev); + if (ret < 0) { +#if defined(__EMBEDDED_FW__) + hxfw = &g_embedded_fw; + I("%s: Not find FW in userspace, use embedded FW(size:%zu)", + __func__, g_embedded_fw.size); + result = HX_EMBEDDED_FW; +#else + E("%s,%d: error code = %d\n", __func__, __LINE__, ret); + return OPEN_FILE_FAIL; +#endif + } + + return result; +} + +static int i_update_FW(void) +{ +#if !defined(HX_ZERO_FLASH) + int upgrade_times = 0; + int8_t ret = 0; +#endif + int8_t result = 0; + + himax_int_enable(0); + +#if defined(HX_ZERO_FLASH) + + g_core_fp.fp_firmware_update_0f(hxfw); + + g_core_fp.fp_reload_disable(0); + + g_core_fp.fp_power_on_init(); + + g_core_fp.fp_read_FW_ver(); + + g_core_fp.fp_touch_information(); + + g_core_fp.fp_calc_touch_data_size(); + + result = 1;/*upgrade success*/ + +#else +update_retry: + + if (hxfw->size == FW_SIZE_32k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_60k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_64k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_124k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k( + (unsigned char *)hxfw->data, hxfw->size, false); + else if (hxfw->size == FW_SIZE_128k) + ret = g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k( + (unsigned char *)hxfw->data, hxfw->size, false); + + if (ret == 0) { + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", + __func__, upgrade_times); + + if (upgrade_times < 3) + goto update_retry; + else + result = -1; + + + } else { + g_core_fp.fp_power_on_init(); + g_core_fp.fp_read_FW_ver(); + g_core_fp.fp_touch_information(); + g_core_fp.fp_calc_touch_data_size(); + result = 1;/*upgrade success*/ + I("%s: TP upgrade OK\n", __func__); + } +#endif + + himax_int_enable(1); + + return result; +} +#endif +/* + *static int himax_loadSensorConfig(struct himax_i2c_platform_data *pdata) + *{ + * I("%s: initialization complete\n", __func__); + * return NO_ERR; + *} + */ +#if defined(HX_EXCP_RECOVERY) +static void himax_excp_hw_reset(void) +{ +#if defined(HX_ZERO_FLASH) + int result = 0; +#endif + if (g_ts_dbg != 0) + I("%s: Entering\n", __func__); + + I("%s: START EXCEPTION Reset\n", __func__); + + if (private_ts->in_self_test == 1) { + I("%s: In self test, not TP EXCEPTION Reset\n", __func__); + return; + } + + /*g_core_fp.fp_excp_ic_reset();*/ +#if defined(HX_ZERO_FLASH) + I("%s: It will update fw after exception event in zero flash mode!\n", + __func__); + result = g_core_fp.fp_0f_operation_dirly(); + if (result) { + E("%s: Something is wrong! Skip Update with zero flash!\n", + __func__); + goto ESCAPE_0F_UPDATE; + } + g_core_fp.fp_reload_disable(0); + g_core_fp.fp_sense_on(0x00); + himax_report_all_leave_event(private_ts); + himax_int_enable(1); +ESCAPE_0F_UPDATE: +#else + g_core_fp.fp_excp_ic_reset(); +#endif + I("%s: END EXCEPTION Reset\n", __func__); +} +#endif + +#if defined(HX_SMART_WAKEUP) +#if defined(HX_GESTURE_TRACK) +static void gest_pt_log_coordinate(int rx, int tx) +{ + /*driver report x y with range 0 - 255 , we scale it up to x/y pixel*/ + gest_pt_x[gest_pt_cnt] = rx * (ic_data->HX_X_RES) / 255; + gest_pt_y[gest_pt_cnt] = tx * (ic_data->HX_Y_RES) / 255; +} +#endif +static int himax_wake_event_parse(struct himax_ts_data *ts, int ts_status) +{ + uint8_t *buf = wake_event_buffer; +#if defined(HX_GESTURE_TRACK) + int tmp_max_x = 0x00; + int tmp_min_x = 0xFFFF; + int tmp_max_y = 0x00; + int tmp_min_y = 0xFFFF; + int gest_len; +#endif + int i = 0, check_FC = 0, ret; + int j = 0, gesture_pos = 0, gesture_flag = 0; + + if (g_ts_dbg != 0) + I("%s: Entering!, ts_status=%d\n", __func__, ts_status); + + if (buf == NULL) { + ret = -ENOMEM; + goto END; + } + + memcpy(buf, hx_touch_data->hx_event_buf, hx_touch_data->event_size); + + for (i = 0; i < GEST_PTLG_ID_LEN; i++) { + for (j = 0; j < GEST_SUP_NUM; j++) { + if (buf[i] == gest_event[j]) { + gesture_flag = buf[i]; + gesture_pos = j; + break; + } + } + I("0x%2.2X ", buf[i]); + if (buf[i] == gesture_flag) { + check_FC++; + } else { + I("ID START at %x , value = 0x%2X skip the event\n", + i, buf[i]); + break; + } + } + + I("Himax gesture_flag= %x\n", gesture_flag); + I("Himax check_FC is %d\n", check_FC); + + if (check_FC != GEST_PTLG_ID_LEN) { + ret = 0; + goto END; + } + + if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 + || buf[GEST_PTLG_ID_LEN + 1] != GEST_PTLG_HDR_ID2) { + ret = 0; + goto END; + } + +#if defined(HX_GESTURE_TRACK) + + if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 + && buf[GEST_PTLG_ID_LEN + 1] == GEST_PTLG_HDR_ID2) { + gest_len = buf[GEST_PTLG_ID_LEN + 2]; + I("gest_len = %d\n", gest_len); + i = 0; + gest_pt_cnt = 0; + I("gest doornidate start\n %s", __func__); + + while (i < (gest_len + 1) / 2) { + gest_pt_log_coordinate( + buf[GEST_PTLG_ID_LEN + 4 + i * 2], + buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1]); + i++; + I("gest_pt_x[%d]=%d,gest_pt_y[%d]=%d\n", + gest_pt_cnt, + gest_pt_x[gest_pt_cnt], + gest_pt_cnt, + gest_pt_y[gest_pt_cnt]); + gest_pt_cnt += 1; + } + + if (gest_pt_cnt) { + for (i = 0; i < gest_pt_cnt; i++) { + if (tmp_max_x < gest_pt_x[i]) + tmp_max_x = gest_pt_x[i]; + if (tmp_min_x > gest_pt_x[i]) + tmp_min_x = gest_pt_x[i]; + if (tmp_max_y < gest_pt_y[i]) + tmp_max_y = gest_pt_y[i]; + if (tmp_min_y > gest_pt_y[i]) + tmp_min_y = gest_pt_y[i]; + } + + I("gest_point x_min=%d,x_max=%d,y_min=%d,y_max=%d\n", + tmp_min_x, tmp_max_x, tmp_min_y, tmp_max_y); + + gest_start_x = gest_pt_x[0]; + hx_gesture_coor[0] = gest_start_x; + gest_start_y = gest_pt_y[0]; + hx_gesture_coor[1] = gest_start_y; + gest_end_x = gest_pt_x[gest_pt_cnt - 1]; + hx_gesture_coor[2] = gest_end_x; + gest_end_y = gest_pt_y[gest_pt_cnt - 1]; + hx_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + hx_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + hx_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x) / 2; + hx_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y) / 2; + hx_gesture_coor[7] = gest_mid_y; + /*gest_up_x*/ + hx_gesture_coor[8] = gest_mid_x; + /*gest_up_y*/ + hx_gesture_coor[9] = gest_mid_y - gest_height / 2; + /*gest_down_x*/ + hx_gesture_coor[10] = gest_mid_x; + /*gest_down_y*/ + hx_gesture_coor[11] = gest_mid_y + gest_height / 2; + /*gest_left_x*/ + hx_gesture_coor[12] = gest_mid_x - gest_width / 2; + /*gest_left_y*/ + hx_gesture_coor[13] = gest_mid_y; + /*gest_right_x*/ + hx_gesture_coor[14] = gest_mid_x + gest_width / 2; + /*gest_right_y*/ + hx_gesture_coor[15] = gest_mid_y; + } + } + +#endif + + if (!ts->gesture_cust_en[gesture_pos]) { + I("%s NOT report key [%d] = %d\n", __func__, + gesture_pos, gest_key_def[gesture_pos]); + g_target_report_data->SMWP_event_chk = 0; + ret = 0; + } else { + g_target_report_data->SMWP_event_chk = + gest_key_def[gesture_pos]; + ret = gesture_pos; + } +END: + return ret; +} + +static void himax_wake_event_report(void) +{ + int KEY_EVENT = g_target_report_data->SMWP_event_chk; + + if (g_ts_dbg != 0) + I("%s: Entering!\n", __func__); + + if (KEY_EVENT) { + I("%s SMART WAKEUP KEY event %d press\n", __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + I("%s SMART WAKEUP KEY event %d release\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); +#if defined(HX_GESTURE_TRACK) + I("gest_start_x=%d,start_y=%d,end_x=%d,end_y=%d\n", + gest_start_x, + gest_start_y, + gest_end_x, + gest_end_y); + I("gest_width=%d,height=%d,mid_x=%d,mid_y=%d\n", + gest_width, + gest_height, + gest_mid_x, + gest_mid_y); + I("gest_up_x=%d,up_y=%d,down_x=%d,down_y=%d\n", + hx_gesture_coor[8], + hx_gesture_coor[9], + hx_gesture_coor[10], + hx_gesture_coor[11]); + I("gest_left_x=%d,left_y=%d,right_x=%d,right_y=%d\n", + hx_gesture_coor[12], + hx_gesture_coor[13], + hx_gesture_coor[14], + hx_gesture_coor[15]); +#endif + g_target_report_data->SMWP_event_chk = 0; + } +} + +#endif + +int himax_report_data_init(void) +{ + if (hx_touch_data->hx_coord_buf != NULL) { + kfree(hx_touch_data->hx_coord_buf); + hx_touch_data->hx_coord_buf = NULL; + } + + if (hx_touch_data->hx_rawdata_buf != NULL) { + kfree(hx_touch_data->hx_rawdata_buf); + hx_touch_data->hx_rawdata_buf = NULL; + } + +#if defined(HX_SMART_WAKEUP) + hx_touch_data->event_size = g_core_fp.fp_get_touch_data_size(); + + if (hx_touch_data->hx_event_buf != NULL) { + kfree(hx_touch_data->hx_event_buf); + hx_touch_data->hx_event_buf = NULL; + } + + if (wake_event_buffer != NULL) { + kfree(wake_event_buffer); + wake_event_buffer = NULL; + } + +#endif + + if (g_target_report_data != NULL) { + if (ic_data->HX_PEN_FUNC) { + kfree(g_target_report_data->p_on); + g_target_report_data->p_on = NULL; + kfree(g_target_report_data->p_tilt_y); + g_target_report_data->p_tilt_y = NULL; + kfree(g_target_report_data->p_btn2); + g_target_report_data->p_btn2 = NULL; + kfree(g_target_report_data->p_btn); + g_target_report_data->p_btn = NULL; + kfree(g_target_report_data->p_tilt_x); + g_target_report_data->p_tilt_x = NULL; + kfree(g_target_report_data->p_hover); + g_target_report_data->p_hover = NULL; + kfree(g_target_report_data->pen_id); + g_target_report_data->pen_id = NULL; + kfree(g_target_report_data->p_w); + g_target_report_data->p_w = NULL; + kfree(g_target_report_data->p_y); + g_target_report_data->p_y = NULL; + kfree(g_target_report_data->p_x); + g_target_report_data->p_x = NULL; + } + + kfree(g_target_report_data->finger_id); + g_target_report_data->finger_id = NULL; + kfree(g_target_report_data->w); + g_target_report_data->w = NULL; + kfree(g_target_report_data->y); + g_target_report_data->y = NULL; + kfree(g_target_report_data->x); + g_target_report_data->x = NULL; + kfree(g_target_report_data); + g_target_report_data = NULL; + } + + hx_touch_data->touch_all_size = g_core_fp.fp_get_touch_data_size(); + hx_touch_data->raw_cnt_max = ic_data->HX_MAX_PT / 4; + hx_touch_data->raw_cnt_rmd = ic_data->HX_MAX_PT % 4; + /* more than 4 fingers */ + if (hx_touch_data->raw_cnt_rmd != 0x00) { + hx_touch_data->rawdata_size = + g_core_fp.fp_cal_data_len( + hx_touch_data->raw_cnt_rmd, + ic_data->HX_MAX_PT, + hx_touch_data->raw_cnt_max); + + hx_touch_data->touch_info_size = (ic_data->HX_MAX_PT + + hx_touch_data->raw_cnt_max + 2) * 4; + } else { /* less than 4 fingers */ + hx_touch_data->rawdata_size = + g_core_fp.fp_cal_data_len( + hx_touch_data->raw_cnt_rmd, + ic_data->HX_MAX_PT, + hx_touch_data->raw_cnt_max); + + hx_touch_data->touch_info_size = (ic_data->HX_MAX_PT + + hx_touch_data->raw_cnt_max + 1) * 4; + } + + if (ic_data->HX_PEN_FUNC) { + hx_touch_data->touch_info_size += PEN_INFO_SZ; + hx_touch_data->rawdata_size -= PEN_INFO_SZ; + } + + if ((ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + + ic_data->HX_RX_NUM) + % hx_touch_data->rawdata_size == 0) + hx_touch_data->rawdata_frame_size = + (ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + + ic_data->HX_RX_NUM) + / hx_touch_data->rawdata_size; + else + hx_touch_data->rawdata_frame_size = + (ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + + ic_data->HX_RX_NUM) + / hx_touch_data->rawdata_size + + 1; + + I("%s:rawdata_fsz = %d,HX_MAX_PT:%d,hx_raw_cnt_max:%d\n", + __func__, + hx_touch_data->rawdata_frame_size, + ic_data->HX_MAX_PT, + hx_touch_data->raw_cnt_max); + I("%s:hx_raw_cnt_rmd:%d,g_hx_rawdata_size:%d,touch_info_size:%d\n", + __func__, + hx_touch_data->raw_cnt_rmd, + hx_touch_data->rawdata_size, + hx_touch_data->touch_info_size); + + hx_touch_data->hx_coord_buf = kzalloc(sizeof(uint8_t) + * (hx_touch_data->touch_info_size), + GFP_KERNEL); + + if (hx_touch_data->hx_coord_buf == NULL) + goto mem_alloc_fail_coord_buf; + +#if defined(HX_SMART_WAKEUP) + wake_event_buffer = kcalloc(hx_touch_data->event_size, + sizeof(uint8_t), GFP_KERNEL); + if (wake_event_buffer == NULL) + goto mem_alloc_fail_smwp; + + hx_touch_data->hx_event_buf = kzalloc(sizeof(uint8_t) + * (hx_touch_data->event_size), GFP_KERNEL); + if (hx_touch_data->hx_event_buf == NULL) + goto mem_alloc_fail_event_buf; +#endif + + hx_touch_data->hx_rawdata_buf = kzalloc(sizeof(uint8_t) + * (hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size), + GFP_KERNEL); + if (hx_touch_data->hx_rawdata_buf == NULL) + goto mem_alloc_fail_rawdata_buf; + + if (g_target_report_data == NULL) { + g_target_report_data = + kzalloc(sizeof(struct himax_target_report_data), + GFP_KERNEL); + if (g_target_report_data == NULL) + goto mem_alloc_fail_report_data; +/* + *#if defined(HX_SMART_WAKEUP) + * g_target_report_data->SMWP_event_chk = 0; + *#endif + * I("%s: SMWP_event_chk = %d\n", __func__, + * g_target_report_data->SMWP_event_chk); + */ + g_target_report_data->x = kzalloc(sizeof(int) + * (ic_data->HX_MAX_PT), GFP_KERNEL); + if (g_target_report_data->x == NULL) + goto mem_alloc_fail_report_data_x; + + g_target_report_data->y = kzalloc(sizeof(int) + * (ic_data->HX_MAX_PT), GFP_KERNEL); + if (g_target_report_data->y == NULL) + goto mem_alloc_fail_report_data_y; + + g_target_report_data->w = kzalloc(sizeof(int) + * (ic_data->HX_MAX_PT), GFP_KERNEL); + if (g_target_report_data->w == NULL) + goto mem_alloc_fail_report_data_w; + + g_target_report_data->finger_id = kzalloc(sizeof(int) + * (ic_data->HX_MAX_PT), GFP_KERNEL); + if (g_target_report_data->finger_id == NULL) + goto mem_alloc_fail_report_data_fid; + + if (!ic_data->HX_PEN_FUNC) + goto skip_pen_operation; + + g_target_report_data->p_x = kzalloc(sizeof(int)*2, GFP_KERNEL); + if (g_target_report_data->p_x == NULL) + goto mem_alloc_fail_report_data_px; + + g_target_report_data->p_y = kzalloc(sizeof(int)*2, GFP_KERNEL); + if (g_target_report_data->p_y == NULL) + goto mem_alloc_fail_report_data_py; + + g_target_report_data->p_w = kzalloc(sizeof(int)*2, GFP_KERNEL); + if (g_target_report_data->p_w == NULL) + goto mem_alloc_fail_report_data_pw; + + g_target_report_data->pen_id = kzalloc(sizeof(int)*2, + GFP_KERNEL); + if (g_target_report_data->pen_id == NULL) + goto mem_alloc_fail_report_data_pid; + + g_target_report_data->p_hover = kzalloc(sizeof(int)*2, + GFP_KERNEL); + if (g_target_report_data->p_hover == NULL) + goto mem_alloc_fail_report_data_ph; + + g_target_report_data->p_tilt_x = kzalloc(sizeof(int)*2, + GFP_KERNEL); + if (g_target_report_data->p_tilt_x == NULL) + goto mem_alloc_fail_report_data_ptx; + + g_target_report_data->p_btn = kzalloc(sizeof(int)*2, + GFP_KERNEL); + if (g_target_report_data->p_btn == NULL) + goto mem_alloc_fail_report_data_pb; + + g_target_report_data->p_btn2 = kzalloc(sizeof(int)*2, + GFP_KERNEL); + if (g_target_report_data->p_btn2 == NULL) + goto mem_alloc_fail_report_data_pb2; + + g_target_report_data->p_tilt_y = kzalloc(sizeof(int)*2, + GFP_KERNEL); + if (g_target_report_data->p_tilt_y == NULL) + goto mem_alloc_fail_report_data_pty; + + g_target_report_data->p_on = kzalloc(sizeof(int)*2, GFP_KERNEL); + if (g_target_report_data->p_on == NULL) + goto mem_alloc_fail_report_data_pon; + } + +skip_pen_operation: + + return NO_ERR; + +mem_alloc_fail_report_data_pon: + kfree(g_target_report_data->p_tilt_y); + g_target_report_data->p_tilt_y = NULL; +mem_alloc_fail_report_data_pty: + kfree(g_target_report_data->p_btn2); + g_target_report_data->p_btn2 = NULL; +mem_alloc_fail_report_data_pb2: + kfree(g_target_report_data->p_btn); + g_target_report_data->p_btn = NULL; +mem_alloc_fail_report_data_pb: + kfree(g_target_report_data->p_tilt_x); + g_target_report_data->p_tilt_x = NULL; +mem_alloc_fail_report_data_ptx: + kfree(g_target_report_data->p_hover); + g_target_report_data->p_hover = NULL; +mem_alloc_fail_report_data_ph: + kfree(g_target_report_data->pen_id); + g_target_report_data->pen_id = NULL; +mem_alloc_fail_report_data_pid: + kfree(g_target_report_data->p_w); + g_target_report_data->p_w = NULL; +mem_alloc_fail_report_data_pw: + kfree(g_target_report_data->p_y); + g_target_report_data->p_y = NULL; +mem_alloc_fail_report_data_py: + kfree(g_target_report_data->p_x); + g_target_report_data->p_x = NULL; +mem_alloc_fail_report_data_px: + + kfree(g_target_report_data->finger_id); + g_target_report_data->finger_id = NULL; +mem_alloc_fail_report_data_fid: + kfree(g_target_report_data->w); + g_target_report_data->w = NULL; +mem_alloc_fail_report_data_w: + kfree(g_target_report_data->y); + g_target_report_data->y = NULL; +mem_alloc_fail_report_data_y: + kfree(g_target_report_data->x); + g_target_report_data->x = NULL; +mem_alloc_fail_report_data_x: + kfree(g_target_report_data); + g_target_report_data = NULL; +mem_alloc_fail_report_data: + kfree(hx_touch_data->hx_rawdata_buf); + hx_touch_data->hx_rawdata_buf = NULL; +mem_alloc_fail_rawdata_buf: +#if defined(HX_SMART_WAKEUP) + kfree(hx_touch_data->hx_event_buf); + hx_touch_data->hx_event_buf = NULL; +mem_alloc_fail_event_buf: + kfree(wake_event_buffer); + wake_event_buffer = NULL; +mem_alloc_fail_smwp: +#endif + kfree(hx_touch_data->hx_coord_buf); + hx_touch_data->hx_coord_buf = NULL; +mem_alloc_fail_coord_buf: + + E("%s: Failed to allocate memory\n", __func__); + return MEM_ALLOC_FAIL; +} +EXPORT_SYMBOL(himax_report_data_init); + +void himax_report_data_deinit(void) +{ + if (ic_data->HX_PEN_FUNC) { + kfree(g_target_report_data->p_on); + g_target_report_data->p_on = NULL; + kfree(g_target_report_data->p_tilt_y); + g_target_report_data->p_tilt_y = NULL; + kfree(g_target_report_data->p_btn2); + g_target_report_data->p_btn2 = NULL; + kfree(g_target_report_data->p_btn); + g_target_report_data->p_btn = NULL; + kfree(g_target_report_data->p_tilt_x); + g_target_report_data->p_tilt_x = NULL; + kfree(g_target_report_data->p_hover); + g_target_report_data->p_hover = NULL; + kfree(g_target_report_data->pen_id); + g_target_report_data->pen_id = NULL; + kfree(g_target_report_data->p_w); + g_target_report_data->p_w = NULL; + kfree(g_target_report_data->p_y); + g_target_report_data->p_y = NULL; + kfree(g_target_report_data->p_x); + g_target_report_data->p_x = NULL; + } + + kfree(g_target_report_data->finger_id); + g_target_report_data->finger_id = NULL; + kfree(g_target_report_data->w); + g_target_report_data->w = NULL; + kfree(g_target_report_data->y); + g_target_report_data->y = NULL; + kfree(g_target_report_data->x); + g_target_report_data->x = NULL; + kfree(g_target_report_data); + g_target_report_data = NULL; + +#if defined(HX_SMART_WAKEUP) + kfree(wake_event_buffer); + wake_event_buffer = NULL; + kfree(hx_touch_data->hx_event_buf); + hx_touch_data->hx_event_buf = NULL; +#endif + kfree(hx_touch_data->hx_rawdata_buf); + hx_touch_data->hx_rawdata_buf = NULL; + kfree(hx_touch_data->hx_coord_buf); + hx_touch_data->hx_coord_buf = NULL; +} + +/*start ts_work*/ +#if defined(HX_USB_DETECT_GLOBAL) +void himax_cable_detect_func(bool force_renew) +{ + struct himax_ts_data *ts; + + /*u32 connect_status = 0;*/ + uint8_t connect_status = 0; + + connect_status = USB_detect_flag;/* upmu_is_chr_det(); */ + ts = private_ts; + + /* I("Touch: cable status=%d, cable_config=%p, usb_connected=%d\n",*/ + /* connect_status, ts->cable_config, ts->usb_connected); */ + if (ts->cable_config) { + if ((connect_status != ts->usb_connected) || force_renew) { + if (connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + g_core_fp.fp_usb_detect_set(ts->cable_config); + I("%s: Cable status change: 0x%2.2X\n", __func__, + ts->usb_connected); + } + + /*else*/ + /* I("%s: Cable status is the same as*/ + /* previous one, ignore.\n", __func__);*/ + } +} +#endif + +static int himax_ts_work_status(struct himax_ts_data *ts) +{ + /* 1: normal, 2:SMWP */ + int result = HX_REPORT_COORD; + + hx_touch_data->diag_cmd = ts->diag_cmd; + if (hx_touch_data->diag_cmd) + result = HX_REPORT_COORD_RAWDATA; + +#if defined(HX_SMART_WAKEUP) + if (atomic_read(&ts->suspend_mode) + && (ts->SMWP_enable) + && (!hx_touch_data->diag_cmd)) + result = HX_REPORT_SMWP_EVENT; +#endif + /* I("Now Status is %d\n", result); */ + return result; +} + +static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf, + int ts_path, int ts_status) +{ + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + switch (ts_path) { + /*normal*/ + case HX_REPORT_COORD: + if ((HX_HW_RESET_ACTIVATE) +#if defined(HX_EXCP_RECOVERY) + || (HX_EXCP_RESET_ACTIVATE) +#endif + ) { + if (!g_core_fp.fp_read_event_stack(buf, 128)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + } else { + if (!g_core_fp.fp_read_event_stack(buf, + hx_touch_data->touch_info_size)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + } + break; +#if defined(HX_SMART_WAKEUP) + + /*SMWP*/ + case HX_REPORT_SMWP_EVENT: + __pm_wakeup_event(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + msleep(20); + g_core_fp.fp_burst_enable(0); + + if (!g_core_fp.fp_read_event_stack(buf, + hx_touch_data->event_size)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + break; +#endif + case HX_REPORT_COORD_RAWDATA: + if (!g_core_fp.fp_read_event_stack(buf, 128)) { + E("%s: can't read data from chip!\n", __func__); + ts_status = HX_TS_GET_DATA_FAIL; + } + break; + default: + break; + } + + return ts_status; +} + +/* start error_control*/ +static int himax_checksum_cal(struct himax_ts_data *ts, uint8_t *buf, + int ts_path, int ts_status) +{ + uint16_t check_sum_cal = 0; + int32_t i = 0; + int length = 0; + int zero_cnt = 0; + int raw_data_sel = 0; + int ret_val = ts_status; + + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + /* Normal */ + switch (ts_path) { + case HX_REPORT_COORD: + length = hx_touch_data->touch_info_size; + break; +#if defined(HX_SMART_WAKEUP) +/* SMWP */ + case HX_REPORT_SMWP_EVENT: + length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN); + break; +#endif + case HX_REPORT_COORD_RAWDATA: + length = hx_touch_data->touch_info_size; + break; + default: + I("%s, Neither Normal Nor SMWP error!\n", __func__); + ret_val = HX_PATH_FAIL; + goto END_FUNCTION; + } + + for (i = 0; i < length; i++) { + check_sum_cal += buf[i]; + if (buf[i] == 0x00) + zero_cnt++; + } + + if (check_sum_cal % 0x100 != 0) { + I("point data_checksum not match check_sum_cal: 0x%02X", + check_sum_cal); + ret_val = HX_CHKSUM_FAIL; + } else if (zero_cnt == length) { + if (ts->use_irq) + I("[HIMAX TP MSG] All Zero event\n"); + + ret_val = HX_CHKSUM_FAIL; + } else { + raw_data_sel = buf[HX_TOUCH_INFO_POINT_CNT]>>4 & 0x0F; + /*I("%s:raw_out_sel=%x , hx_touch_data->diag_cmd=%x.\n",*/ + /* __func__, raw_data_sel,*/ + /* hx_touch_data->diag_cmd);*/ + /*raw data out not match skip it*/ + if ((raw_data_sel != 0x0F) + && (raw_data_sel != hx_touch_data->diag_cmd)) { + /*I("%s:raw data out not match.\n", __func__);*/ + if (!hx_touch_data->diag_cmd) { + /*Need to clear event stack here*/ + g_core_fp.fp_read_event_stack(buf, + (128-hx_touch_data->touch_info_size)); + /*I("%s: size =%d, buf[0]=%x ,buf[1]=%x,*/ + /* buf[2]=%x, buf[3]=%x.\n",*/ + /* __func__,*/ + /* (128-hx_touch_data->touch_info_size),*/ + /* buf[0], buf[1], buf[2], buf[3]);*/ + /*I("%s:also clear event stack.\n", __func__);*/ + } + ret_val = HX_READY_SERVE; + } + } + +END_FUNCTION: + if (g_ts_dbg != 0) + I("%s: END, ret_val=%d!\n", __func__, ret_val); + return ret_val; +} + +#if defined(HX_EXCP_RECOVERY) +#if defined(HX_ZERO_FLASH) +void hx_update_dirly_0f(void) +{ + I("It will update fw after exception event in zero flash mode!\n"); + g_core_fp.fp_0f_operation_dirly(); +} +#endif +static int himax_ts_event_check(struct himax_ts_data *ts, + uint8_t *buf, int ts_path, int ts_status) +{ + uint32_t hx_EB_event = 0; + uint32_t hx_EC_event = 0; + uint32_t hx_ED_event = 0; + uint32_t hx_excp_event = 0; + uint32_t hx_zero_event = 0; + int shaking_ret = 0; + + uint32_t loop_i = 0; + uint32_t length = 0; + int ret_val = ts_status; + + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + /* Normal */ + switch (ts_path) { + case HX_REPORT_COORD: + length = hx_touch_data->touch_info_size; + break; +#if defined(HX_SMART_WAKEUP) +/* SMWP */ + case HX_REPORT_SMWP_EVENT: + length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN); + break; +#endif + case HX_REPORT_COORD_RAWDATA: + length = hx_touch_data->touch_info_size; + break; + default: + I("%s, Neither Normal Nor SMWP error!\n", __func__); + ret_val = HX_PATH_FAIL; + goto END_FUNCTION; + } + + if (g_ts_dbg != 0) + I("Now Path=%d, Now status=%d, length=%d\n", + ts_path, ts_status, length); + + if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) { + if (ic_data->HX_PEN_FUNC) + length -= PEN_INFO_SZ; + for (loop_i = 0; loop_i < length; loop_i++) { + /* case 1 EXCEEPTION recovery flow */ + if (buf[loop_i] == 0xEB) { + hx_EB_event++; + } else if (buf[loop_i] == 0xEC) { + hx_EC_event++; + } else if (buf[loop_i] == 0xED) { + hx_ED_event++; + + /* case 2 EXCEPTION recovery flow-Disable */ + } else if (buf[loop_i] == 0x00) { + hx_zero_event++; + } else { + g_zero_event_count = 0; + break; + } + } + } + + if (hx_EB_event == length) { + hx_excp_event = length; + hx_EB_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEB.\n"); + } else if (hx_EC_event == length) { + hx_excp_event = length; + hx_EC_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xEC.\n"); + } else if (hx_ED_event == length) { + hx_excp_event = length; + hx_ED_event_flag++; + I("[HIMAX TP MSG]: EXCEPTION event checked - ALL 0xED.\n"); + } +/*#if defined(HX_ZERO_FLASH) + * //This is for previous version(a, b) because HW pull TSIX + * low continuely after watchdog timeout reset + * else if (hx_zero_event == length) { + * //check zero flash status + * if (g_core_fp.fp_0f_esd_check() < 0) { + * g_zero_event_count = 6; + * I("[HIMAX TP MSG]: ESD event checked + - ALL Zero in ZF.\n"); + * } else { + * I("[HIMAX TP MSG]: Status check pass in ZF.\n"); + * } + * } + *#endif + */ + + if ((hx_excp_event == length || hx_zero_event == length) + && (HX_HW_RESET_ACTIVATE == 0) + && (HX_EXCP_RESET_ACTIVATE == 0) + && (hx_touch_data->diag_cmd == 0) + && (ts->in_self_test == 0)) { + shaking_ret = g_core_fp.fp_ic_excp_recovery( + hx_excp_event, hx_zero_event, length); + + if (shaking_ret == HX_EXCP_EVENT) { + g_core_fp.fp_read_FW_status(); + himax_excp_hw_reset(); + ret_val = HX_EXCP_EVENT; + } else if (shaking_ret == HX_ZERO_EVENT_COUNT) { + g_core_fp.fp_read_FW_status(); + ret_val = HX_ZERO_EVENT_COUNT; + } else { + I("I2C running. Nothing to be done!\n"); + ret_val = HX_IC_RUNNING; + } + + /* drop 1st interrupts after chip reset */ + } else if (HX_EXCP_RESET_ACTIVATE) { + HX_EXCP_RESET_ACTIVATE = 0; + I("%s: Skip by HX_EXCP_RESET_ACTIVATE.\n", __func__); + ret_val = HX_EXCP_REC_OK; + } + +END_FUNCTION: + if (g_ts_dbg != 0) + I("%s: END, ret_val=%d!\n", __func__, ret_val); + + return ret_val; +} +#endif + +static int himax_err_ctrl(struct himax_ts_data *ts, + uint8_t *buf, int ts_path, int ts_status) +{ +#if defined(HX_RST_PIN_FUNC) + if (HX_HW_RESET_ACTIVATE) { + /* drop 1st interrupts after chip reset */ + HX_HW_RESET_ACTIVATE = 0; + I("[HX_HW_RESET_ACTIVATE]%s:Back from reset,ready to serve.\n", + __func__); + ts_status = HX_RST_OK; + goto END_FUNCTION; + } +#endif + + ts_status = himax_checksum_cal(ts, buf, ts_path, ts_status); + if (ts_status == HX_CHKSUM_FAIL) { + goto CHK_FAIL; + } else { +#if defined(HX_EXCP_RECOVERY) + /* continuous N times record, not total N times. */ + g_zero_event_count = 0; +#endif + goto END_FUNCTION; + } + +CHK_FAIL: +#if defined(HX_EXCP_RECOVERY) + ts_status = himax_ts_event_check(ts, buf, ts_path, ts_status); +#endif + +END_FUNCTION: + if (g_ts_dbg != 0) + I("%s: END, ts_status=%d!\n", __func__, ts_status); + return ts_status; +} +/* end error_control*/ + +/* start distribute_data*/ +static int himax_distribute_touch_data(uint8_t *buf, + int ts_path, int ts_status) +{ + uint8_t hx_state_info_pos = hx_touch_data->touch_info_size - 3; + + if (ic_data->HX_PEN_FUNC) + hx_state_info_pos -= PEN_INFO_SZ; + + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + if (ts_path == HX_REPORT_COORD) { + memcpy(hx_touch_data->hx_coord_buf, &buf[0], + hx_touch_data->touch_info_size); + + if (buf[hx_state_info_pos] != 0xFF + && buf[hx_state_info_pos + 1] != 0xFF) + memcpy(hx_touch_data->hx_state_info, + &buf[hx_state_info_pos], 2); + else + memset(hx_touch_data->hx_state_info, 0x00, + sizeof(hx_touch_data->hx_state_info)); + + if ((HX_HW_RESET_ACTIVATE) +#if defined(HX_EXCP_RECOVERY) + || (HX_EXCP_RESET_ACTIVATE) +#endif + ) { + memcpy(hx_touch_data->hx_rawdata_buf, + &buf[hx_touch_data->touch_info_size], + hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size); + } + } else if (ts_path == HX_REPORT_COORD_RAWDATA) { + memcpy(hx_touch_data->hx_coord_buf, &buf[0], + hx_touch_data->touch_info_size); + + if (buf[hx_state_info_pos] != 0xFF + && buf[hx_state_info_pos + 1] != 0xFF) + memcpy(hx_touch_data->hx_state_info, + &buf[hx_state_info_pos], 2); + else + memset(hx_touch_data->hx_state_info, 0x00, + sizeof(hx_touch_data->hx_state_info)); + + memcpy(hx_touch_data->hx_rawdata_buf, + &buf[hx_touch_data->touch_info_size], + hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size); +#if defined(HX_SMART_WAKEUP) + } else if (ts_path == HX_REPORT_SMWP_EVENT) { + memcpy(hx_touch_data->hx_event_buf, buf, + hx_touch_data->event_size); +#endif + } else { + E("%s, Fail Path!\n", __func__); + ts_status = HX_PATH_FAIL; + } + + if (g_ts_dbg != 0) + I("%s: End, ts_status=%d!\n", __func__, ts_status); + return ts_status; +} +/* end assign_data*/ + +/* start parse_report_data*/ +int himax_parse_report_points(struct himax_ts_data *ts, + int ts_path, int ts_status) +{ + int x = 0, y = 0, w = 0; + + uint8_t p_hover = 0, p_btn = 0, p_btn2 = 0; + int8_t p_tilt_x = 0, p_tilt_y = 0; + int p_x = 0, p_y = 0, p_w = 0; + static uint8_t p_p_on; + + int base = 0; + int32_t loop_i = 0; + + if (g_ts_dbg != 0) + I("%s: start!\n", __func__); + + base = hx_touch_data->touch_info_size; + + if (!ic_data->HX_PEN_FUNC) + goto skip_pen_operation; + + p_p_on = 0; + base -= PEN_INFO_SZ; + + p_x = hx_touch_data->hx_coord_buf[base] << 8 + | hx_touch_data->hx_coord_buf[base + 1]; + p_y = (hx_touch_data->hx_coord_buf[base + 2] << 8 + | hx_touch_data->hx_coord_buf[base + 3]); + p_w = (hx_touch_data->hx_coord_buf[base + 4] << 8 + | hx_touch_data->hx_coord_buf[base + 5]); + p_tilt_x = (int8_t)hx_touch_data->hx_coord_buf[base + 6]; + p_hover = hx_touch_data->hx_coord_buf[base + 7]; + p_btn = hx_touch_data->hx_coord_buf[base + 8]; + p_btn2 = hx_touch_data->hx_coord_buf[base + 9]; + p_tilt_y = (int8_t)hx_touch_data->hx_coord_buf[base + 10]; + + if (g_ts_dbg != 0) { + D("%s: p_x=%d, p_y=%d, p_w=%d,p_tilt_x=%d, p_hover=%d\n", + __func__, p_x, p_y, p_w, p_tilt_x, p_hover); + D("%s: p_btn=%d, p_btn2=%d, p_tilt_y=%d\n", + __func__, p_btn, p_btn2, p_tilt_y); + } + + if (p_x >= 0 + && p_x <= ts->pdata->abs_x_max + && p_y >= 0 + && p_y <= ts->pdata->abs_y_max) { + g_target_report_data->p_x[0] = p_x; + g_target_report_data->p_y[0] = p_y; + g_target_report_data->p_w[0] = p_w; + g_target_report_data->p_hover[0] = p_hover; + g_target_report_data->pen_id[0] = 1; + g_target_report_data->p_btn[0] = p_btn; + g_target_report_data->p_btn2[0] = p_btn2; + g_target_report_data->p_tilt_x[0] = p_tilt_x; + g_target_report_data->p_tilt_y[0] = p_tilt_y; + g_target_report_data->p_on[0] = 1; + ts->hx_point_num++; + } else {/* report coordinates */ + g_target_report_data->p_x[0] = 0; + g_target_report_data->p_y[0] = 0; + g_target_report_data->p_w[0] = 0; + g_target_report_data->p_hover[0] = 0; + g_target_report_data->pen_id[0] = 0; + g_target_report_data->p_btn[0] = 0; + g_target_report_data->p_btn2[0] = 0; + g_target_report_data->p_tilt_x[0] = 0; + g_target_report_data->p_tilt_y[0] = 0; + g_target_report_data->p_on[0] = 0; + } + + if (g_ts_dbg != 0) { + if (p_p_on != g_target_report_data->p_on[0]) { + I("p_on[0] = %d, hx_point_num=%d\n", + g_target_report_data->p_on[0], + ts->hx_point_num); + p_p_on = g_target_report_data->p_on[0]; + } + } +skip_pen_operation: + + ts->old_finger = ts->pre_finger_mask; + if (ts->hx_point_num == 0) { + if (g_ts_dbg != 0) + I("%s: hx_point_num = 0!\n", __func__); + return ts_status; + } + ts->pre_finger_mask = 0; + hx_touch_data->finger_num = + hx_touch_data->hx_coord_buf[base - 4] & 0x0F; + hx_touch_data->finger_on = 1; + AA_press = 1; + + g_target_report_data->finger_num = hx_touch_data->finger_num; + g_target_report_data->finger_on = hx_touch_data->finger_on; + g_target_report_data->ig_count = + hx_touch_data->hx_coord_buf[base - 5]; + + if (g_ts_dbg != 0) + I("%s:finger_num = 0x%2X, finger_on = %d\n", __func__, + g_target_report_data->finger_num, + g_target_report_data->finger_on); + + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + base = loop_i * 4; + x = hx_touch_data->hx_coord_buf[base] << 8 + | hx_touch_data->hx_coord_buf[base + 1]; + y = (hx_touch_data->hx_coord_buf[base + 2] << 8 + | hx_touch_data->hx_coord_buf[base + 3]); + w = hx_touch_data->hx_coord_buf[(ts->nFinger_support * 4) + + loop_i]; + + if (g_ts_dbg != 0) + D("%s: now parsing[%d]:x=%d, y=%d, w=%d\n", __func__, + loop_i, x, y, w); + + if (x >= 0 + && x <= ts->pdata->abs_x_max + && y >= 0 + && y <= ts->pdata->abs_y_max) { + hx_touch_data->finger_num--; + + g_target_report_data->x[loop_i] = x; + g_target_report_data->y[loop_i] = y; + g_target_report_data->w[loop_i] = w; + g_target_report_data->finger_id[loop_i] = 1; + + /*I("%s: g_target_report_data->x[loop_i]=%d,*/ + /*g_target_report_data->y[loop_i]=%d,*/ + /*g_target_report_data->w[loop_i]=%d",*/ + /*__func__, g_target_report_data->x[loop_i],*/ + /*g_target_report_data->y[loop_i],*/ + /*g_target_report_data->w[loop_i]); */ + + + if (!ts->first_pressed) { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); + } + + ts->pre_finger_data[loop_i][0] = x; + ts->pre_finger_data[loop_i][1] = y; + + ts->pre_finger_mask = ts->pre_finger_mask + + (1 << loop_i); + } else {/* report coordinates */ + g_target_report_data->x[loop_i] = x; + g_target_report_data->y[loop_i] = y; + g_target_report_data->w[loop_i] = w; + g_target_report_data->finger_id[loop_i] = 0; + + if (loop_i == 0 && ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + } + } + + if (g_ts_dbg != 0) { + for (loop_i = 0; loop_i < 10; loop_i++) + D("DBG X=%d Y=%d ID=%d\n", + g_target_report_data->x[loop_i], + g_target_report_data->y[loop_i], + g_target_report_data->finger_id[loop_i]); + + D("DBG finger number %d\n", g_target_report_data->finger_num); + } + + if (g_ts_dbg != 0) + I("%s: end!\n", __func__); + return ts_status; +} + +static int himax_parse_report_data(struct himax_ts_data *ts, + int ts_path, int ts_status) +{ + + if (g_ts_dbg != 0) + I("%s: start now_status=%d!\n", __func__, ts_status); + + + EN_NoiseFilter = + (hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3); + /* I("EN_NoiseFilter=%d\n", EN_NoiseFilter); */ + EN_NoiseFilter = EN_NoiseFilter & 0x01; + /* I("EN_NoiseFilter2=%d\n", EN_NoiseFilter); */ + p_point_num = ts->hx_point_num; + + if (hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + ts->hx_point_num = 0; + else + ts->hx_point_num = + hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] + & 0x0f; + + switch (ts_path) { + case HX_REPORT_COORD: + ts_status = himax_parse_report_points(ts, ts_path, ts_status); + break; + case HX_REPORT_COORD_RAWDATA: + /* touch monitor rawdata */ + if (debug_data != NULL) { + if (debug_data->fp_set_diag_cmd(ic_data, hx_touch_data)) + I("%s:raw data_checksum not match\n", __func__); + } else { + E("%s,There is no init set_diag_cmd\n", __func__); + } + ts_status = himax_parse_report_points(ts, ts_path, ts_status); + break; +#if defined(HX_SMART_WAKEUP) + case HX_REPORT_SMWP_EVENT: + himax_wake_event_parse(ts, ts_status); + break; +#endif + default: + E("%s:Fail Path!\n", __func__); + ts_status = HX_PATH_FAIL; + break; + } + if (g_ts_dbg != 0) + I("%s: end now_status=%d!\n", __func__, ts_status); + return ts_status; +} + +/* end parse_report_data*/ + +static void himax_report_all_leave_event(struct himax_ts_data *ts) +{ + int loop_i = 0; + + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { +#if !defined(HX_PROTOCOL_A) + input_mt_slot(ts->input_dev, loop_i); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); +#endif + } + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); +} + +/* start report_point*/ +static void himax_finger_report(struct himax_ts_data *ts) +{ + int i = 0; + bool valid = false; + + + if (g_ts_dbg != 0) { + I("%s:start hx_touch_data->finger_num=%d\n", + __func__, hx_touch_data->finger_num); + } + for (i = 0; i < ts->nFinger_support; i++) { + if (g_target_report_data->x[i] >= 0 + && g_target_report_data->x[i] <= ts->pdata->abs_x_max + && g_target_report_data->y[i] >= 0 + && g_target_report_data->y[i] <= ts->pdata->abs_y_max) + valid = true; + else + valid = false; + if (g_ts_dbg != 0) + I("valid=%d\n", valid); + if (valid) { + if (g_ts_dbg != 0) { + I("report_data->x[i]=%d,y[i]=%d,w[i]=%d", + g_target_report_data->x[i], + g_target_report_data->y[i], + g_target_report_data->w[i]); + } +#if !defined(HX_PROTOCOL_A) + input_mt_slot(ts->input_dev, i); +#else + input_report_key(ts->input_dev, BTN_TOUCH, 1); +#endif + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + g_target_report_data->w[i]); +#if !defined(HX_PROTOCOL_A) + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + g_target_report_data->w[i]); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + g_target_report_data->w[i]); +#else + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, + i + 1); +#endif + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + g_target_report_data->x[i]); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + g_target_report_data->y[i]); +#if !defined(HX_PROTOCOL_A) + ts->last_slot = i; + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 1); +#else + input_mt_sync(ts->input_dev); +#endif + } else { +#if !defined(HX_PROTOCOL_A) + input_mt_slot(ts->input_dev, i); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0); + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 0); +#endif + } + } +#if !defined(HX_PROTOCOL_A) + input_report_key(ts->input_dev, BTN_TOUCH, 1); +#endif + input_sync(ts->input_dev); + + if (!ic_data->HX_PEN_FUNC) + goto skip_pen_operation; + + valid = false; + + if (g_target_report_data->p_x[0] >= 0 + && g_target_report_data->p_x[0] <= ts->pdata->abs_x_max + && g_target_report_data->p_y[0] >= 0 + && g_target_report_data->p_y[0] <= ts->pdata->abs_y_max + && (g_target_report_data->p_on[0] == 1)) + valid = true; + else + valid = false; + + if (g_ts_dbg != 0) + I("pen valid=%d\n", valid); + + if (valid) {/*Pen down*/ + if (g_ts_dbg != 0) + I("p_x[i]=%d, p_y[i]=%d, p_w[i]=%d\n", + g_target_report_data->p_x[0], + g_target_report_data->p_y[0], + g_target_report_data->p_w[0]); + + input_report_abs(ts->hx_pen_dev, ABS_X, + g_target_report_data->p_x[0]); + input_report_abs(ts->hx_pen_dev, ABS_Y, + g_target_report_data->p_y[0]); + + if (g_target_report_data->p_btn[0] != + g_target_report_data->pre_p_btn) { + if (g_ts_dbg != 0) + I("BTN_STYLUS:%d\n", + g_target_report_data->p_btn[0]); + + input_report_key(ts->hx_pen_dev, BTN_STYLUS, + g_target_report_data->p_btn[0]); + + g_target_report_data->pre_p_btn = + g_target_report_data->p_btn[0]; + } else { + if (g_ts_dbg != 0) + I("BTN_STYLUS status no change, value=%d!\n", + g_target_report_data->p_btn[0]); + } + + if (g_target_report_data->p_btn2[0] + != g_target_report_data->pre_p_btn2) { + if (g_ts_dbg != 0) + I("BTN_STYLUS2:%d\n", + g_target_report_data->p_btn2[0]); + + input_report_key(ts->hx_pen_dev, BTN_STYLUS2, + g_target_report_data->p_btn2[0]); + + g_target_report_data->pre_p_btn2 = + g_target_report_data->p_btn2[0]; + } else { + if (g_ts_dbg != 0) + I("BTN_STYLUS2 status no change, value=%d!\n", + g_target_report_data->p_btn2[0]); + } + input_report_abs(ts->hx_pen_dev, ABS_TILT_X, + g_target_report_data->p_tilt_x[0]); + + input_report_abs(ts->hx_pen_dev, ABS_TILT_Y, + g_target_report_data->p_tilt_y[0]); + + input_report_key(ts->hx_pen_dev, BTN_TOOL_PEN, 1); + + if (g_target_report_data->p_hover[0] == 0) { + input_report_key(ts->hx_pen_dev, BTN_TOUCH, 1); + input_report_abs(ts->hx_pen_dev, ABS_DISTANCE, 0); + input_report_abs(ts->hx_pen_dev, ABS_PRESSURE, + g_target_report_data->p_w[0]); + } else { + input_report_key(ts->hx_pen_dev, BTN_TOUCH, 0); + input_report_abs(ts->hx_pen_dev, ABS_DISTANCE, 1); + input_report_abs(ts->hx_pen_dev, ABS_PRESSURE, 0); + } + } else {/*Pen up*/ + g_target_report_data->pre_p_btn = 0; + g_target_report_data->pre_p_btn2 = 0; + input_report_key(ts->hx_pen_dev, BTN_STYLUS, 0); + input_report_key(ts->hx_pen_dev, BTN_STYLUS2, 0); + input_report_key(ts->hx_pen_dev, BTN_TOUCH, 0); + input_report_abs(ts->hx_pen_dev, ABS_PRESSURE, 0); + input_sync(ts->hx_pen_dev); + + input_report_abs(ts->hx_pen_dev, ABS_DISTANCE, 0); + input_report_key(ts->hx_pen_dev, BTN_TOOL_RUBBER, 0); + input_report_key(ts->hx_pen_dev, BTN_TOOL_PEN, 0); + input_report_abs(ts->hx_pen_dev, ABS_PRESSURE, 0); + } + input_sync(ts->hx_pen_dev); + +skip_pen_operation: + + if (g_ts_dbg != 0) + I("%s:end\n", __func__); +} + +static void himax_finger_leave(struct himax_ts_data *ts) +{ +#if !defined(HX_PROTOCOL_A) + int32_t loop_i = 0; +#endif + + if (g_ts_dbg != 0) + I("%s: start!\n", __func__); +#if defined(HX_PALM_REPORT) + if (himax_palm_detect(hx_touch_data->hx_coord_buf) == PALM_REPORT) { + I(" %s HX_PALM_REPORT KEY power event press\n", __func__); + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + msleep(100); + + I(" %s HX_PALM_REPORT KEY power event release\n", __func__); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + return; + } +#endif + + hx_touch_data->finger_on = 0; + g_target_report_data->finger_on = 0; + g_target_report_data->finger_num = 0; + AA_press = 0; + +#if defined(HX_PROTOCOL_A) + input_mt_sync(ts->input_dev); +#endif +#if !defined(HX_PROTOCOL_A) + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + input_mt_slot(ts->input_dev, loop_i); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } +#endif + if (ts->pre_finger_mask > 0) + ts->pre_finger_mask = 0; + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + + /*if (ts->debug_log_level & BIT(1))*/ + /* himax_log_touch_event(x, y, w, loop_i, EN_NoiseFilter,*/ + /* HX_FINGER_LEAVE); */ + + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); + + if (ic_data->HX_PEN_FUNC) { + input_report_key(ts->hx_pen_dev, BTN_STYLUS, 0); + input_report_key(ts->hx_pen_dev, BTN_TOUCH, 0); + input_report_abs(ts->hx_pen_dev, ABS_PRESSURE, 0); + input_sync(ts->hx_pen_dev); + + input_report_abs(ts->hx_pen_dev, ABS_DISTANCE, 0); + input_report_abs(ts->hx_pen_dev, ABS_TILT_X, 0); + input_report_abs(ts->hx_pen_dev, ABS_TILT_Y, 0); + input_report_key(ts->hx_pen_dev, BTN_TOOL_RUBBER, 0); + input_report_key(ts->hx_pen_dev, BTN_TOOL_PEN, 0); + input_sync(ts->hx_pen_dev); + } + + if (g_ts_dbg != 0) + I("%s: end!\n", __func__); + + +} + +static void himax_report_points(struct himax_ts_data *ts) +{ + if (g_ts_dbg != 0) + I("%s: start!\n", __func__); + + if (ts->hx_point_num != 0) + himax_finger_report(ts); + else + himax_finger_leave(ts); + + Last_EN_NoiseFilter = EN_NoiseFilter; + + if (g_ts_dbg != 0) + I("%s: end!\n", __func__); +} +/* end report_points*/ + +int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status) +{ + if (g_ts_dbg != 0) + I("%s: Entering, ts_status=%d!\n", __func__, ts_status); + + if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) { + /* Touch Point information */ + himax_report_points(ts); + +#if defined(HX_SMART_WAKEUP) + } else if (ts_path == HX_REPORT_SMWP_EVENT) { + himax_wake_event_report(); +#endif + } else { + E("%s:Fail Path!\n", __func__); + ts_status = HX_PATH_FAIL; + } + + if (g_ts_dbg != 0) + I("%s: END, ts_status=%d!\n", __func__, ts_status); + return ts_status; +} +/* end report_data */ + +static int himax_ts_operation(struct himax_ts_data *ts, + int ts_path, int ts_status) +{ + uint8_t hw_reset_check[2]; + + memset(ts->xfer_buff, 0x00, 128 * sizeof(uint8_t)); + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + + ts_status = himax_touch_get(ts, ts->xfer_buff, ts_path, ts_status); + if (ts_status == HX_TS_GET_DATA_FAIL) + goto END_FUNCTION; + + ts_status = himax_distribute_touch_data(ts->xfer_buff, + ts_path, ts_status); + ts_status = himax_err_ctrl(ts, ts->xfer_buff, ts_path, ts_status); + if (ts_status == HX_REPORT_DATA || ts_status == HX_TS_NORMAL_END) + ts_status = himax_parse_report_data(ts, ts_path, ts_status); + else + goto END_FUNCTION; + + + ts_status = himax_report_data(ts, ts_path, ts_status); + + +END_FUNCTION: + return ts_status; +} + +void himax_ts_work(struct himax_ts_data *ts) +{ + + int ts_status = HX_TS_NORMAL_END; + int ts_path = 0; + + if (debug_data != NULL) { + if (debug_data->is_checking_irq) { + if (g_ts_dbg != 0) + I("Now checking IRQ, skip it!\n"); + return; + } + debug_data->fp_ts_dbg_func(ts, HX_FINGER_ON); + } + if (ts->notouch_frame > 0) { + if (g_ts_dbg != 0) + I("Skipit=%d\n", ts->notouch_frame--); + else + ts->notouch_frame--; + return; + } + +#if defined(HX_USB_DETECT_GLOBAL) + himax_cable_detect_func(false); +#endif + + ts_path = himax_ts_work_status(ts); + switch (ts_path) { + case HX_REPORT_COORD: + ts_status = himax_ts_operation(ts, ts_path, ts_status); + break; + case HX_REPORT_SMWP_EVENT: + ts_status = himax_ts_operation(ts, ts_path, ts_status); + break; + case HX_REPORT_COORD_RAWDATA: + ts_status = himax_ts_operation(ts, ts_path, ts_status); + break; + default: + E("%s:Path Fault! value=%d\n", __func__, ts_path); + goto END_FUNCTION; + } + + if (ts_status == HX_TS_GET_DATA_FAIL) + goto GET_TOUCH_FAIL; + else + goto END_FUNCTION; + +GET_TOUCH_FAIL: + I("%s: Now reset the Touch chip.\n", __func__); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, true); +#else + g_core_fp.fp_system_reset(); +#endif +#if defined(HX_ZERO_FLASH) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); +#endif +END_FUNCTION: + if (debug_data != NULL) + debug_data->fp_ts_dbg_func(ts, HX_FINGER_LEAVE); + +} +/*end ts_work*/ +enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) +{ + struct himax_ts_data *ts; + + + ts = container_of(timer, struct himax_ts_data, timer); + queue_work(ts->himax_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +static void himax_boot_upgrade(struct work_struct *work) +{ + int fw_sts = -1; + + fw_sts = i_get_FW(); + if (fw_sts < NO_ERR) + return; + + g_core_fp.fp_bin_desc_get((unsigned char *)hxfw->data, HX1K); + + if (g_boot_upgrade_flag == true) { + I("%s: Forced upgrade\n", __func__); + goto UPDATE_FW; + } + + if (himax_auto_update_check() != 0) + goto SKIP_UPDATE_FW; + +UPDATE_FW: + if (i_update_FW() <= 0) + E("%s: Update FW fail\n", __func__); + else + I("%s: Update FW success\n", __func__); + +SKIP_UPDATE_FW: + if (fw_sts == NO_ERR) + release_firmware(hxfw); + hxfw = NULL; + +} +#endif + +#if !defined(HX_ZERO_FLASH) +static int hx_chk_flash_sts(void) +{ + int rslt = 0; + + I("%s: Entering\n", __func__); + + rslt = (!g_core_fp.fp_calculateChecksum(false, FW_SIZE_64k)); + /*avoid the FW is full of zero*/ + rslt |= g_core_fp.fp_flash_lastdata_check(FW_SIZE_64k); + + return rslt; +} +#endif + +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) +static void himax_fb_register(struct work_struct *work) +{ + int ret = 0; + + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, + work_att.work); + + I("%s in\n", __func__); +#if defined(HX_CONFIG_FB) + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); +#elif defined(HX_CONFIG_DRM) + ts->fb_notif.notifier_call = drm_notifier_callback; + if (active_panel) { + ret = drm_panel_notifier_register(active_panel, + &ts->fb_notif); + if (ret) + E("Failed to register fb notifier client"); + } + else { + E("active_panel error\n"); + } +#endif + if (ret) + E("Unable to register fb_notifier: %d\n", ret); +} +#endif + +#if defined(HX_CONTAINER_SPEED_UP) +static void himax_resume_work_func(struct work_struct *work) +{ + himax_chip_common_resume(private_ts); +} + +#endif + +static void himax_AlgOnoff_write(int alg_enable) +{ + + uint8_t tmp_addr[DATA_LEN_4] = {0x8C,0x74,0x00,0x10}; + uint8_t tmp_dataclr[DATA_LEN_4] = {0x00,0x00,0x00,0x00}; + uint8_t tmp_password[DATA_LEN_4] = {0x5A,0xA5,0x5A,0xA5}; + + + if (alg_enable){ + I("%s: alg_enable = %d.\n", __func__, alg_enable); + g_core_fp.fp_register_write(tmp_addr, 4, tmp_password, 0); + }else{ + I("%s: alg_enable = %d.\n", __func__, alg_enable); + g_core_fp.fp_register_write(tmp_addr, 4, tmp_dataclr, 0); + } +} +int himax_chip_common_init(void) +{ + + int i = 0, ret = 0, idx = 0; + int err = PROBE_FAIL; + struct himax_ts_data *ts = private_ts; + struct himax_i2c_platform_data *pdata; + struct himax_chip_entry *entry; + + I("Prepare kernel fp\n"); + kp_getname_kernel = (void *)kallsyms_lookup_name("getname_kernel"); + if (!kp_getname_kernel) { + E("prepare kp_getname_kernel failed!\n"); + /*goto err_xfer_buff_fail;*/ + } + kp_putname_kernel = (void *)kallsyms_lookup_name("putname"); + if (!kp_putname_kernel) { + E("prepare kp_putname_kernel failed!\n"); + /*goto err_xfer_buff_fail;*/ + } + kp_file_open_name = (void *)kallsyms_lookup_name("file_open_name"); + if (!kp_file_open_name) { + E("prepare kp_file_open_name failed!\n"); + goto err_xfer_buff_fail; + } + + /* Set pinctrl in active state */ + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) + E("Failed to set pin in active state %d", ret); + } + +#if defined(__EMBEDDED_FW__) + g_embedded_fw.size = (size_t)_binary___Himax_firmware_bin_end - + (size_t)_binary___Himax_firmware_bin_start; +#endif + + ts->xfer_buff = devm_kzalloc(ts->dev, 128 * sizeof(uint8_t), + GFP_KERNEL); + if (ts->xfer_buff == NULL) { + err = -ENOMEM; + goto err_xfer_buff_fail; + } + + I("PDATA START\n"); + pdata = kzalloc(sizeof(struct himax_i2c_platform_data), GFP_KERNEL); + + if (pdata == NULL) { /*Allocate Platform data space*/ + err = -ENOMEM; + goto err_dt_platform_data_fail; + } + + I("ic_data START\n"); + ic_data = kzalloc(sizeof(struct himax_ic_data), GFP_KERNEL); + if (ic_data == NULL) { /*Allocate IC data space*/ + err = -ENOMEM; + goto err_dt_ic_data_fail; + } + + /* allocate report data */ + hx_touch_data = kzalloc(sizeof(struct himax_report_data), GFP_KERNEL); + if (hx_touch_data == NULL) { + err = -ENOMEM; + goto err_alloc_touch_data_failed; + } + + ts->pdata = pdata; + + if (himax_parse_dt(ts, pdata) < 0) { + I(" pdata is NULL for DT\n"); + goto err_alloc_dt_pdata_failed; + } + + if (pdata->virtual_key) + ts->button = pdata->virtual_key; + +#if defined(HX_RST_PIN_FUNC) + ts->rst_gpio = pdata->gpio_reset; +#endif + + himax_gpio_power_config(pdata); + +#if !defined(CONFIG_OF) + if (pdata->power) { + ret = pdata->power(1); + + if (ret < 0) { + E("%s: power on failed\n", __func__); + goto err_power_failed; + } + } +#endif + +#if defined(CONFIG_OF) + ts->power = pdata->power; +#endif + + g_hx_chip_inited = 0; + idx = himax_get_ksym_idx(); + if (idx >= 0) { + if (isEmpty(idx) != 0) { + I("%s: no chip registered, please insmod ic.ko!\n", + __func__); + goto error_ic_detect_failed; + } + entry = get_chip_entry_by_index(idx); + + for (i = 0; i < entry->hx_ic_dt_num; i++) { + if (entry->core_chip_dt[i].fp_chip_detect != NULL) { + if (entry->core_chip_dt[i].fp_chip_detect()) { + I("%s: chip found! list_num=%d\n", + __func__, i); + goto found_hx_chip; + } else { + I("%s:num=%d,chip NOT found! go Next\n", + __func__, i); + continue; + } + } + } + } else { + I("%s: No available chip exist!\n", __func__); + goto error_ic_detect_failed; + } + + if (i == entry->hx_ic_dt_num) { + E("%s: chip detect failed!\n", __func__); + goto error_ic_detect_failed; + } + private_ts->notouch_frame = 0; + private_ts->ic_notouch_frame = 0; +found_hx_chip: + if (g_core_fp.fp_chip_init != NULL) { + g_core_fp.fp_chip_init(); + } else { + E("%s: function point of chip_init is NULL!\n", __func__); + goto error_ic_detect_failed; + } + +#if defined(HX_ZERO_FLASH) + g_boot_upgrade_flag = 1; +#else + if (hx_chk_flash_sts() == 1) { + E("%s: check flash fail, please upgrade FW\n", __func__); + #if defined(HX_BOOT_UPGRADE) + g_boot_upgrade_flag = 1; + #endif + } +#endif + +#if defined(HX_ZERO_FLASH) || defined(HX_BOOT_UPGRADE) + if (!g_boot_upgrade_flag) { +#endif + g_core_fp.fp_power_on_init(); + g_core_fp.fp_read_FW_ver(); +#if defined(HX_ZERO_FLASH) || defined(HX_BOOT_UPGRADE) + } +#endif + g_core_fp.fp_touch_information(); + g_core_fp.fp_calc_touch_data_size(); + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + ts->himax_boot_upgrade_wq = + create_singlethread_workqueue("HX_boot_upgrade"); + if (!ts->himax_boot_upgrade_wq) { + E("allocate himax_boot_upgrade_wq failed\n"); + err = -ENOMEM; + goto err_boot_upgrade_wq_failed; + } + INIT_DELAYED_WORK(&ts->work_boot_upgrade, himax_boot_upgrade); + queue_delayed_work(ts->himax_boot_upgrade_wq, &ts->work_boot_upgrade, + msecs_to_jiffies(2000)); +#endif + +#if defined(HX_CONTAINER_SPEED_UP) + ts->ts_int_workqueue = + create_singlethread_workqueue("himax_ts_resume_wq"); + if (!ts->ts_int_workqueue) { + E("%s: create ts_resume workqueue failed\n", __func__); + goto err_create_ts_resume_wq_failed; + } + INIT_DELAYED_WORK(&ts->ts_int_work, himax_resume_work_func); +#endif + + /*Himax Power On and Load Config*/ +/* if (himax_loadSensorConfig(pdata)) { + * E("%s: Load Sesnsor configuration failed, unload driver.\n", + * __func__); + * goto err_detect_failed; + * } + */ + himax_AlgOnoff_write(1); +#if defined(CONFIG_OF) + ts->pdata->abs_pressure_min = 0; + ts->pdata->abs_pressure_max = 200; + ts->pdata->abs_width_min = 0; + ts->pdata->abs_width_max = 200; + pdata->cable_config[0] = 0xF0; + pdata->cable_config[1] = 0x00; +#endif + + ts->suspended = false; + +#if defined(HX_USB_DETECT_GLOBAL) + ts->usb_connected = 0x00; + ts->cable_config = pdata->cable_config; +#endif + +#if defined(HX_PROTOCOL_A) + ts->protocol_type = PROTOCOL_TYPE_A; +#else + ts->protocol_type = PROTOCOL_TYPE_B; +#endif + I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + + ret = himax_input_register(ts); + if (ret) { + E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } + + spin_lock_init(&ts->irq_lock); + ts->initialized = true; + +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) + ts->himax_att_wq = create_singlethread_workqueue("HMX_ATT_request"); + + if (!ts->himax_att_wq) { + E(" allocate himax_att_wq failed\n"); + err = -ENOMEM; + goto err_get_intr_bit_failed; + } + I("register fb \n"); + INIT_DELAYED_WORK(&ts->work_att, himax_fb_register); + queue_delayed_work(ts->himax_att_wq, &ts->work_att, + msecs_to_jiffies(15000)); +#endif + +#if defined(HX_SMART_WAKEUP) + ts->SMWP_enable = 0; + wakeup_source_init(&ts->ts_SMWP_wake_lock, HIMAX_common_NAME); +#endif +#if defined(HX_HIGH_SENSE) + ts->HSEN_enable = 0; +#endif + + if (himax_common_proc_init()) { + E(" %s: himax_common proc_init failed!\n", __func__); + goto err_creat_proc_file_failed; + } + + himax_ts_register_interrupt(); + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + if (himax_debug_init()) + E(" %s: debug initial failed!\n", __func__); +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + if (g_boot_upgrade_flag) + himax_int_enable(0); +#endif + g_hx_chip_inited = true; + return 0; + +err_creat_proc_file_failed: +#if defined(HX_SMART_WAKEUP) + wakeup_source_trash(&ts->ts_SMWP_wake_lock); +#endif +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); +err_get_intr_bit_failed: +#endif +err_input_register_device_failed: + input_free_device(ts->input_dev); +/*err_detect_failed:*/ + +#if defined(HX_CONTAINER_SPEED_UP) + cancel_delayed_work_sync(&ts->ts_int_work); + destroy_workqueue(ts->ts_int_workqueue); +err_create_ts_resume_wq_failed: +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + cancel_delayed_work_sync(&ts->work_boot_upgrade); + destroy_workqueue(ts->himax_boot_upgrade_wq); +err_boot_upgrade_wq_failed: +#endif + +error_ic_detect_failed: + himax_gpio_power_deconfig(pdata); +#if !defined(CONFIG_OF) +err_power_failed: +#endif +err_alloc_dt_pdata_failed: + kfree(hx_touch_data); + hx_touch_data = NULL; +err_alloc_touch_data_failed: + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + err = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (err) + E("failed to select relase pinctrl state %d\n", + err); + } + } + kfree(ic_data); + ic_data = NULL; +err_dt_ic_data_fail: + kfree(pdata); + pdata = NULL; +err_dt_platform_data_fail: + devm_kfree(ts->dev, ts->xfer_buff); + ts->xfer_buff = NULL; +err_xfer_buff_fail: + probe_fail_flag = 1; + return err; +} + +void himax_chip_common_deinit(void) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + himax_ts_unregister_interrupt(); + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + himax_inspect_data_clear(); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_debug_remove(); +#endif + + himax_common_proc_deinit(); + himax_report_data_deinit(); + +#if defined(HX_SMART_WAKEUP) + wakeup_source_trash(&ts->ts_SMWP_wake_lock); +#endif +#if defined(HX_CONFIG_FB) + if (fb_unregister_client(&ts->fb_notif)) + E("Error occurred while unregistering fb_notifier.\n"); + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); +#elif defined(HX_CONFIG_DRM) +#if defined(__HIMAX_MOD__) + hx_msm_drm_unregister_client = + (void *)kallsyms_lookup_name("msm_drm_unregister_client"); + if (hx_msm_drm_unregister_client != NULL) { + if (hx_msm_drm_unregister_client(&ts->fb_notif)) + E("Error occurred while unregistering drm_notifier.\n"); + } else + E("hx_msm_drm_unregister_client is NULL\n"); +#else + if (active_panel) { + ret = drm_panel_notifier_unregister(active_panel, + &ts->fb_notif); + if (ret < 0) + E("Failed to unregister fb notifier client"); + } +#endif + cancel_delayed_work_sync(&ts->work_att); + destroy_workqueue(ts->himax_att_wq); +#endif + input_free_device(ts->input_dev); +#if defined(HX_CONTAINER_SPEED_UP) + cancel_delayed_work_sync(&ts->ts_int_work); + destroy_workqueue(ts->ts_int_workqueue); +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + cancel_delayed_work_sync(&ts->work_boot_upgrade); + destroy_workqueue(ts->himax_boot_upgrade_wq); +#endif + himax_gpio_power_deconfig(ts->pdata); + if (himax_mcu_cmd_struct_free) + himax_mcu_cmd_struct_free(); + + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (ret) + E("failed to select relase pinctrl state %d\n", + ret); + } + } + + kfree(hx_touch_data); + hx_touch_data = NULL; + kfree(ic_data); + ic_data = NULL; + kfree(ts->pdata->virtual_key); + ts->pdata->virtual_key = NULL; + devm_kfree(ts->dev, ts->xfer_buff); + ts->xfer_buff = NULL; + kfree(ts->pdata); + ts->pdata = NULL; + kfree(ts); + ts = NULL; + probe_fail_flag = 0; + + I("%s: Common section deinited!\n", __func__); +} + +int himax_chip_common_suspend(struct himax_ts_data *ts) +{ + int ret; + + if (ts->suspended) { + I("%s: Already suspended. Skipped.\n", __func__); + goto END; + } else { + ts->suspended = true; + I("%s: enter\n", __func__); + } + + if (debug_data != NULL && debug_data->flash_dump_going == true) { + I("[himax] %s: Flash dump is going, reject suspend\n", + __func__); + goto END; + } + +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) +#if !defined(HX_RESUME_SEND_CMD) + g_core_fp.fp_resend_cmd_func(ts->suspended); +#endif +#endif +#if defined(HX_SMART_WAKEUP) + + if (ts->SMWP_enable) { +#if defined(HX_CODE_OVERLAY) + if (ts->in_self_test == 0) + g_core_fp.fp_0f_overlay(2, 0); +#endif + if (g_core_fp._ap_notify_fw_sus != NULL) + g_core_fp._ap_notify_fw_sus(1); + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + I("[himax] %s: SMART_WAKEUP enable, reject suspend\n", + __func__); + goto END; + } + +#endif + himax_int_enable(0); + if (g_core_fp.fp_suspend_ic_action != NULL) + g_core_fp.fp_suspend_ic_action(); + + if (!ts->use_irq) { + int32_t cancel_state; + + cancel_state = cancel_work_sync(&ts->work); + if (cancel_state) + himax_int_enable(1); + } + + /*ts->first_pressed = 0;*/ + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_suspend); + if (ret < 0) + E("Failed to get idle pinctrl state %d\n", ret); + } + + if (ts->pdata) + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + +END: + if (ts->in_self_test == 1) + ts->suspend_resume_done = 1; + + I("%s: END\n", __func__); + + return 0; +} + +int himax_chip_common_resume(struct himax_ts_data *ts) +{ +#if defined(HX_RESUME_SET_FW) + int result = 0; +#endif + int ret; + + I("%s: enter\n", __func__); + + if (ts->suspended == false) { + I("%s: It had entered resume, skip this step\n", __func__); + goto END; + } else { + ts->suspended = false; + } + +#if defined(HX_EXCP_RECOVERY) + /* continuous N times record, not total N times. */ + g_zero_event_count = 0; +#endif + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) { + E("Cannot get default pinctrl state %d\n", ret); + return ret; + } + } + atomic_set(&ts->suspend_mode, 0); + ts->diag_cmd = 0; + + if (ts->pdata) + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(1); +#if defined(HX_RST_PIN_FUNC) && defined(HX_RESUME_HW_RESET) + if (g_core_fp.fp_ic_reset != NULL) + g_core_fp.fp_ic_reset(false, false); +#endif + +#if defined(HX_RESUME_SET_FW) +#if defined(HX_SMART_WAKEUP) && !defined(HX_SWU_RESUME_SET_FW) + if (!ts->SMWP_enable) { +#endif + I("It will update fw after resume in zero flash mode!\n"); + if (g_core_fp.fp_0f_operation_dirly != NULL) { + result = g_core_fp.fp_0f_operation_dirly(); + if (result) { + E("Something wrong! Skip Update zero flash!\n"); + goto ESCAPE_0F_UPDATE; + } + } + if (g_core_fp.fp_reload_disable != NULL) + g_core_fp.fp_reload_disable(0); + if (g_core_fp.fp_sense_on != NULL) + g_core_fp.fp_sense_on(0x00); +#if defined(HX_SMART_WAKEUP) && !defined(HX_SWU_RESUME_SET_FW) + } +#endif +#endif +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) + if (g_core_fp.fp_resend_cmd_func != NULL) + g_core_fp.fp_resend_cmd_func(ts->suspended); + +#if defined(HX_CODE_OVERLAY)\ + && defined(HX_SMART_WAKEUP) + if (ts->SMWP_enable && ts->in_self_test == 0) + g_core_fp.fp_0f_overlay(3, 0); +#endif + if (g_core_fp._ap_notify_fw_sus != NULL) + g_core_fp._ap_notify_fw_sus(0); +#endif + himax_report_all_leave_event(ts); + + if (g_core_fp.fp_resume_ic_action != NULL) + g_core_fp.fp_resume_ic_action(); + himax_AlgOnoff_write(1); + himax_int_enable(1); +#if defined(HX_ZERO_FLASH) && defined(HX_RESUME_SET_FW) +ESCAPE_0F_UPDATE: +#endif +END: + if (ts->in_self_test == 1) + ts->suspend_resume_done = 1; + + I("%s: END\n", __func__); + return 0; +} + diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h new file mode 100644 index 0000000000000000000000000000000000000000..afa1bfd8efd6ad4c6c51a0555f183f6d2eb5e029 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -0,0 +1,604 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for common functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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 HIMAX_COMMON_H +#define HIMAX_COMMON_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "himax_platform.h" +#include +#include + +#if defined(CONFIG_OF) + #include +#endif + +#define HIMAX_DRIVER_VER "2.0.0.70_ALG_01" + +#define FLASH_DUMP_FILE "/sdcard/HX_Flash_Dump.bin" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define HX_TP_PROC_2T2R +/*if enable, selftest works in driver*/ +/*#define HX_TP_SELF_TEST_DRIVER*/ +#endif +/*===========Himax Option function=============*/ +#define HX_RST_PIN_FUNC +#define HX_EXCP_RECOVERY + +/*#define HX_NEW_EVENT_STACK_FORMAT*/ +#define HX_BOOT_UPGRADE +/*#define HX_SMART_WAKEUP*/ +/*#define HX_GESTURE_TRACK*/ +#define HX_RESUME_SEND_CMD /*Need to enable on TDDI chipset*/ +/*#define HX_HIGH_SENSE*/ +/*#define HX_PALM_REPORT*/ +/*#define HX_USB_DETECT_GLOBAL*/ + +/* for MTK special platform.If turning on, + * it will report to system by using specific format. + */ +/*#define HX_PROTOCOL_A*/ +#define HX_PROTOCOL_B_3PA + +/*#define HX_ZERO_FLASH*/ + +/*system suspend-chipset power off, + *oncell chipset need to enable the definition + */ +/*#define HX_RESUME_HW_RESET*/ + +/*for Himax auto-motive chipset + */ +/*#define HX_PON_PIN_SUPPORT*/ + +/*=============================================*/ + +/* Enable it if driver go into suspend/resume twice */ +/*#undef HX_CONFIG_FB*/ + +/* Enable it if driver go into suspend/resume twice */ +/*#undef HX_CONFIG_DRM*/ + +#if defined(HX_CONFIG_FB) +#include +#include +#elif defined(HX_CONFIG_DRM) +#include +#endif + +#if defined(__HIMAX_MOD__) +#define HX_USE_KSYM +#if !defined(HX_USE_KSYM) || !defined(__KERNEL_KALLSYMS_ALL_ENABLED__) + #error Modulized driver must enable HX_USE_KSYM and CONFIG_KALLSYM_ALL +#endif +#endif + +#if defined(HX_ZERO_FLASH) +/*zero flash case, you need to setup the fix_touch_info of module*/ +/*Please set the size according to IC*/ +#define DSRAM_SIZE HX_32K_SZ +#define HX_RESUME_SET_FW +/*#define HX_CODE_OVERLAY*/ +/*Independent threads run the notification chain notification function resume*/ +/*#define HX_CONTAINER_SPEED_UP*/ +#else +#define HX_TP_PROC_GUEST_INFO +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +/* FW Auto upgrade case, you need to setup the fix_touch_info of module + */ +#define HX_FIX_TOUCH_INFO +#define BOOT_UPGRADE_FWNAME "Himax_firmware.bin" +#if defined(HX_ZERO_FLASH) +#define MPAP_FWNAME "Himax_mpfw.bin" +#endif +#endif + +#if defined(HX_SMART_WAKEUP) +/*This feature need P-sensor driver notified, and FW need to support*/ +/*#define HX_ULTRA_LOW_POWER*/ +#endif + +#if defined(HX_SMART_WAKEUP) && defined(HX_RESUME_SET_FW) +/* decide whether reload FW after Smart Wake Up */ +#define HX_SWU_RESUME_SET_FW +#endif + +#if defined(HX_CONTAINER_SPEED_UP) +/*Resume queue delay work time after LCM RST (unit:ms) + */ +#define DELAY_TIME 40 +#endif + +#if defined(HX_RST_PIN_FUNC) +/* origin is 20/50 */ +#define RST_LOW_PERIOD_S 5000 +#define RST_LOW_PERIOD_E 5100 +#if defined(HX_ZERO_FLASH) +#define RST_HIGH_PERIOD_S 5000 +#define RST_HIGH_PERIOD_E 5100 +#else +#define RST_HIGH_PERIOD_S 50000 +#define RST_HIGH_PERIOD_E 50100 +#endif +#endif + +#if defined(HX_CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(HX_CONFIG_DRM) +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#endif + +#define HX_MAX_WRITE_SZ (64 * 1024 + 4) + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_85XX_A_SERIES_PWON "HX85xxA" +#define HX_85XX_B_SERIES_PWON "HX85xxB" +#define HX_85XX_C_SERIES_PWON "HX85xxC" +#define HX_85XX_D_SERIES_PWON "HX85xxD" +#define HX_85XX_E_SERIES_PWON "HX85xxE" +#define HX_85XX_ES_SERIES_PWON "HX85xxES" +#define HX_85XX_F_SERIES_PWON "HX85xxF" +#define HX_85XX_G_SERIES_PWON "HX85xxG" +#define HX_85XX_H_SERIES_PWON "HX85xxH" +#define HX_83100A_SERIES_PWON "HX83100A" +#define HX_83102A_SERIES_PWON "HX83102A" +#define HX_83102B_SERIES_PWON "HX83102B" +#define HX_83102D_SERIES_PWON "HX83102D" +#define HX_83102E_SERIES_PWON "HX83102E" +#define HX_83103A_SERIES_PWON "HX83103A" +#define HX_83106A_SERIES_PWON "HX83106A" +#define HX_83110A_SERIES_PWON "HX83110A" +#define HX_83110B_SERIES_PWON "HX83110B" +#define HX_83111B_SERIES_PWON "HX83111B" +#define HX_83112A_SERIES_PWON "HX83112A" +#define HX_83112B_SERIES_PWON "HX83112B" +#define HX_83113A_SERIES_PWON "HX83113A" +#define HX_83112D_SERIES_PWON "HX83112D" +#define HX_83112E_SERIES_PWON "HX83112E" +#define HX_83112F_SERIES_PWON "HX83112F" +#define HX_83191A_SERIES_PWON "HX83191A" +#define HX_83192A_SERIES_PWON "HX83192A" + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +#define SHIFTBITS 5 + +#define FW_SIZE_32k 32768 +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 + +#define NO_ERR 0 +#define READY_TO_SERVE 1 +#define WORK_OUT 2 +#define HX_EMBEDDED_FW 3 +#define I2C_FAIL -1 +#define HX_INIT_FAIL -1 +#define MEM_ALLOC_FAIL -2 +#define CHECKSUM_FAIL -3 +#define GESTURE_DETECT_FAIL -4 +#define INPUT_REGISTER_FAIL -5 +#define FW_NOT_READY -6 +#define LENGTH_FAIL -7 +#define OPEN_FILE_FAIL -8 +#define PROBE_FAIL -9 +#define ERR_WORK_OUT -10 +#define ERR_STS_WRONG -11 +#define ERR_TEST_FAIL -12 +#define HW_CRC_FAIL 1 + +#define HX_FINGER_ON 1 +#define HX_FINGER_LEAVE 2 + +#if defined(HX_PALM_REPORT) +#define PALM_REPORT 1 +#define NOT_REPORT -1 +#endif + +#define PEN_INFO_SZ 12 + +#if defined(__EMBEDDED_FW__) +extern const uint8_t _binary___Himax_firmware_bin_start[]; +extern const uint8_t _binary___Himax_firmware_bin_end[]; +extern struct firmware g_embedded_fw; +#endif + +enum HX_TS_PATH { + HX_REPORT_COORD = 1, + HX_REPORT_SMWP_EVENT, + HX_REPORT_COORD_RAWDATA, +}; + +enum HX_TS_STATUS { + HX_TS_GET_DATA_FAIL = -4, + HX_EXCP_EVENT, + HX_CHKSUM_FAIL, + HX_PATH_FAIL, + HX_TS_NORMAL_END = 0, + HX_EXCP_REC_OK, + HX_READY_SERVE, + HX_REPORT_DATA, + HX_EXCP_WARNING, + HX_IC_RUNNING, + HX_ZERO_EVENT_COUNT, + HX_RST_OK, +}; + +enum cell_type { + CHIP_IS_ON_CELL, + CHIP_IS_IN_CELL +}; + +#if defined(HX_SMART_WAKEUP) +#define HX_KEY_DOUBLE_CLICK KEY_POWER +#define HX_KEY_UP KEY_UP +#define HX_KEY_DOWN KEY_DOWN +#define HX_KEY_LEFT KEY_LEFT +#define HX_KEY_RIGHT KEY_RIGHT +#define HX_KEY_C KEY_C +#define HX_KEY_Z KEY_Z +#define HX_KEY_M KEY_M +#define HX_KEY_O KEY_O +#define HX_KEY_S KEY_S +#define HX_KEY_V KEY_V +#define HX_KEY_W KEY_W +#define HX_KEY_E KEY_E +#define HX_KEY_LC_M 263 +#define HX_KEY_AT 264 +#define HX_KEY_RESERVE 265 +#define HX_KEY_FINGER_GEST 266 +#define HX_KEY_V_DOWN 267 +#define HX_KEY_V_LEFT 268 +#define HX_KEY_V_RIGHT 269 +#define HX_KEY_F_RIGHT 270 +#define HX_KEY_F_LEFT 271 +#define HX_KEY_DF_UP 272 +#define HX_KEY_DF_DOWN 273 +#define HX_KEY_DF_LEFT 274 +#define HX_KEY_DF_RIGHT 275 +#endif + +#if defined(HX_FIX_TOUCH_INFO) +enum fix_touch_info { + FIX_HX_RX_NUM = 36, + FIX_HX_TX_NUM = 16, + FIX_HX_BT_NUM = 0, + FIX_HX_MAX_PT = 10, + FIX_HX_XY_REVERSE = false, + FIX_HX_INT_IS_EDGE = true, + FIX_HX_PEN_FUNC = false, +#if defined(HX_TP_PROC_2T2R) + FIX_HX_RX_NUM_2 = 36, + FIX_HX_TX_NUM_2 = 16, +#endif +}; +#endif + +#if defined(HX_ZERO_FLASH) + #define HX_SPI_OPERATION + #define HX_0F_DEBUG +#endif +struct himax_ic_data { + int vendor_fw_ver; + int vendor_config_ver; + int vendor_touch_cfg_ver; + int vendor_display_cfg_ver; + int vendor_cid_maj_ver; + int vendor_cid_min_ver; + int vendor_panel_ver; + int vendor_sensor_id; + int ic_adc_num; + uint8_t vendor_cus_info[12]; + uint8_t vendor_proj_info[12]; + uint8_t vendor_ic_id[13]; + int HX_RX_NUM; + int HX_TX_NUM; + int HX_BT_NUM; + int HX_X_RES; + int HX_Y_RES; + int HX_MAX_PT; + bool HX_XY_REVERSE; + bool HX_INT_IS_EDGE; + bool HX_PEN_FUNC; +#if defined(HX_TP_PROC_2T2R) + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif +}; + +struct himax_virtual_key { + int index; + int keycode; + int x_range_min; + int x_range_max; + int y_range_min; + int y_range_max; +}; + +struct himax_target_report_data { + int *x; + int *y; + int *w; + int *finger_id; + int finger_on; + int finger_num; +#if defined(HX_SMART_WAKEUP) + int SMWP_event_chk; +#endif + + int32_t *p_x; + int32_t *p_y; + int32_t *p_w; + int32_t *pen_id; + uint32_t *p_hover; + int32_t *p_tilt_x; + uint32_t *p_btn; + uint32_t *p_btn2; + int32_t *p_tilt_y; + uint32_t *p_on; + int pre_p_btn; + int pre_p_btn2; + + int ig_count; + +}; + +struct himax_report_data { + int touch_all_size; + int raw_cnt_max; + int raw_cnt_rmd; + int touch_info_size; + uint8_t finger_num; + uint8_t finger_on; + uint8_t *hx_coord_buf; + uint8_t hx_state_info[2]; +#if defined(HX_SMART_WAKEUP) + int event_size; + uint8_t *hx_event_buf; +#endif + + int rawdata_size; + uint8_t diag_cmd; + uint8_t *hx_rawdata_buf; + uint8_t rawdata_frame_size; +}; + +struct himax_ts_data { + bool initialized; + bool suspended; + int notouch_frame; + int ic_notouch_frame; + atomic_t suspend_mode; + uint8_t x_channel; + uint8_t y_channel; + uint8_t useScreenRes; + uint8_t diag_cmd; + char chip_name[30]; + uint8_t chip_cell_type; + + uint8_t protocol_type; + uint8_t first_pressed; + uint8_t coord_data_size; + uint8_t area_data_size; + uint8_t coordInfoSize; + uint8_t raw_data_frame_size; + uint8_t raw_data_nframes; + uint8_t nFinger_support; + uint8_t irq_enabled; + uint8_t diag_self[50]; + + uint16_t finger_pressed; + uint16_t last_slot; + uint16_t pre_finger_mask; + uint16_t old_finger; + int hx_point_num; + + + uint32_t debug_log_level; + uint32_t widthFactor; + uint32_t heightFactor; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + + int rst_gpio; + int use_irq; + int (*power)(int on); + int pre_finger_data[10][2]; + + struct device *dev; + struct workqueue_struct *himax_wq; + struct work_struct work; + struct input_dev *input_dev; + + struct input_dev *hx_pen_dev; + + struct hrtimer timer; + struct i2c_client *client; + struct himax_i2c_platform_data *pdata; + struct himax_virtual_key *button; + struct mutex rw_lock; + atomic_t irq_state; + spinlock_t irq_lock; + +/******* SPI-start *******/ + struct spi_device *spi; + int hx_irq; + uint8_t *xfer_buff; +/******* SPI-end *******/ + + int in_self_test; + int suspend_resume_done; + int bus_speed; + +#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM) + struct notifier_block fb_notif; + struct workqueue_struct *himax_att_wq; + struct delayed_work work_att; +#endif + + struct workqueue_struct *flash_wq; + struct work_struct flash_work; + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + struct workqueue_struct *himax_boot_upgrade_wq; + struct delayed_work work_boot_upgrade; +#endif + +#if defined(HX_CONTAINER_SPEED_UP) + struct workqueue_struct *ts_int_workqueue; + struct delayed_work ts_int_work; +#endif + + struct workqueue_struct *himax_diag_wq; + struct delayed_work himax_diag_delay_wrok; + +#if defined(HX_SMART_WAKEUP) + uint8_t SMWP_enable; + uint8_t gesture_cust_en[26]; + struct wakeup_source ts_SMWP_wake_lock; +#if defined(HX_ULTRA_LOW_POWER) + bool psensor_flag; +#endif +#endif + +#if defined(HX_HIGH_SENSE) + uint8_t HSEN_enable; +#endif + +#if defined(HX_USB_DETECT_GLOBAL) + uint8_t usb_connected; + uint8_t *cable_config; +#endif + +#if defined(HX_TP_PROC_GUEST_INFO) + struct workqueue_struct *guest_info_wq; + struct work_struct guest_info_work; +#endif + + /* pinctrl data */ + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; + +}; + +struct himax_debug { + bool flash_dump_going; + bool is_checking_irq; + void (*fp_ts_dbg_func)(struct himax_ts_data *ts, int start); + int (*fp_set_diag_cmd)(struct himax_ic_data *ic_data, + struct himax_report_data *hx_touch_data); +}; + +enum input_protocol_type { + PROTOCOL_TYPE_A = 0x00, + PROTOCOL_TYPE_B = 0x01, +}; + +#if defined(HX_HIGH_SENSE) + void himax_set_HSEN_func(uint8_t HSEN_enable); +#endif + +#if defined(HX_SMART_WAKEUP) +void himax_set_SMWP_func(uint8_t SMWP_enable); + +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +extern uint8_t *wake_event_buffer; +#endif + +extern int g_mmi_refcnt; +extern int *g_inspt_crtra_flag; +extern uint32_t g_hx_chip_inited; +/*void himax_HW_reset(uint8_t loadconfig,uint8_t int_off);*/ + +int himax_chip_common_suspend(struct himax_ts_data *ts); +int himax_chip_common_resume(struct himax_ts_data *ts); + +extern struct filename* (*kp_getname_kernel)(const char *filename); +extern void (*kp_putname_kernel)(struct filename *name); +extern struct file * (*kp_file_open_name)(struct filename *name, + int flags, umode_t mode); + +struct himax_core_fp; +extern struct himax_core_fp g_core_fp; +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; +extern struct device *g_device; +extern struct drm_panel *active_panel; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + int himax_debug_init(void); + int himax_debug_remove(void); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT) + extern char *g_rslt_data; + extern void (*fp_himax_self_test_init)(void); +#endif + +extern int HX_TOUCH_INFO_POINT_CNT; + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata); +int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status); + +int himax_report_data_init(void); + +int himax_dev_set(struct himax_ts_data *ts); +int himax_input_register_device(struct input_dev *input_dev); + +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..a439fa2e9417096e480a9234e455bb3a8d0e033a --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.c @@ -0,0 +1,3139 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for debug nodes + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +#include "himax_debug.h" +#include "himax_ic_core.h" + +#if defined(HX_TP_PROC_2T2R) + bool Is_2T2R; + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif + +uint8_t g_diag_arr_num; + +int g_max_mutual; +int g_min_mutual = 0xFFFF; +int g_max_self; +int g_min_self = 0xFFFF; + +/* moved from debug.h */ + +uint8_t byte_length; +uint8_t reg_cmd[4]; +uint8_t cfg_flag; + +struct proc_dir_entry *himax_proc_stack_file; +struct proc_dir_entry *himax_proc_delta_file; +struct proc_dir_entry *himax_proc_dc_file; +struct proc_dir_entry *himax_proc_baseline_file; +bool dsram_flag; + +#if defined(HX_TP_PROC_2T2R) +uint32_t *diag_mutual_2; +#endif +int32_t *diag_mutual; +int32_t *diag_mutual_new; +int32_t *diag_mutual_old; +uint8_t diag_max_cnt; +uint8_t hx_state_info[2]; +uint8_t diag_coor[128]; +int32_t *diag_self; +int32_t *diag_self_new; +int32_t *diag_self_old; + +struct proc_dir_entry *himax_proc_debug_file; +bool fw_update_complete; +bool fw_update_going; +int handshaking_result; +unsigned char debug_level_cmd; +uint8_t cmd_set[8]; +uint8_t mutual_set_flag; + +struct proc_dir_entry *himax_proc_flash_dump_file; +int Flash_Size = 131072; +uint8_t *flash_buffer; +uint8_t g_flash_cmd; +uint8_t g_flash_progress; +bool g_flash_dump_rst; /*Fail = 0, Pass = 1*/ + +uint32_t **raw_data_array; +uint8_t X_NUM; +uint8_t Y_NUM; +uint8_t sel_type = 0x0D; + +/* Moved from debug.h End */ +char buf_tmp[BUF_SIZE] = {0}; +uint8_t *reg_read_data; + +struct proc_dir_entry *himax_proc_pen_pos_file; + +struct timespec timeStart, timeEnd, timeDelta; +int g_switch_mode; +/* + * Segment : Himax PROC Debug Function + */ + +static ssize_t himax_pen_ops_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int i = 0; + ssize_t ret = 0; + + if (!HX_PROC_SEND_FLAG) { + for (i = 0; i < private_ts->nFinger_support; i++) { + if (g_target_report_data->x[i] >= 0 + && g_target_report_data->x[i] + <= private_ts->pdata->abs_x_max + && g_target_report_data->y[i] >= 0 + && g_target_report_data->y[i] + <= private_ts->pdata->abs_y_max + && private_ts->hx_point_num != 0) { + ret += snprintf(buf_tmp + ret, len - ret, + "%d,%d,", g_target_report_data->x[i], + g_target_report_data->y[i]); + } else { + ret += snprintf(buf_tmp + ret, len - ret, + "65535,65535,"); + } + } + if (g_target_report_data->p_x[0] >= 0 + && g_target_report_data->p_x[0] <= private_ts->pdata->abs_x_max + && g_target_report_data->p_y[0] >= 0 + && g_target_report_data->p_y[0] <= private_ts->pdata->abs_y_max + && (g_target_report_data->p_on[0] == 1)) { + ret += snprintf(buf_tmp + ret, len - ret, "%d,%d,", + g_target_report_data->p_x[0], + g_target_report_data->p_y[0]); + } else { + ret += snprintf(buf_tmp + ret, len - ret, + "65535,65535,"); + } + + ret += snprintf(buf_tmp + ret, len - ret, + "%d,", g_target_report_data->p_w[0]); + + ret += snprintf(buf_tmp + ret, len - ret, + "%u,", g_target_report_data->p_hover[0]); + + if (g_target_report_data->p_btn[0] != 0xff) { + ret += snprintf(buf_tmp + ret, len - ret, + "%u,", g_target_report_data->p_btn[0]); + } else { + ret += snprintf(buf_tmp + ret, len - ret, "0,"); + } + if (g_target_report_data->p_btn2[0] != 0xff) { + ret += snprintf(buf_tmp + ret, len - ret, + "%u,", g_target_report_data->p_btn2[0]); + } else { + ret += snprintf(buf_tmp + ret, len - ret, "0,"); + } + + if (g_target_report_data->p_tilt_x[0] != 0xff) { + ret += snprintf(buf_tmp + ret, len - ret, + "%d,", + g_target_report_data->p_tilt_x[0]); + } else { + ret += snprintf(buf_tmp + ret, len - ret, "0,"); + } + if (g_target_report_data->p_tilt_y[0] != 0xff) { + ret += snprintf(buf_tmp + ret, len - ret, + "%d\n", + g_target_report_data->p_tilt_y[0]); + } else { + ret += snprintf(buf_tmp + ret, len - ret, "0\n"); + } + + if (copy_to_user(buf, buf_tmp, (len > BUF_SIZE)?BUF_SIZE:len)) + I("%s,here:%d\n", __func__, __LINE__); + + HX_PROC_SEND_FLAG = 1; + } else { + HX_PROC_SEND_FLAG = 0; + } + + return ret; +} + +static const struct file_operations himax_proc_pen_pos_ops = { + .owner = THIS_MODULE, + .read = himax_pen_ops_read, +}; + +static ssize_t himax_crc_test_read(char *buf, size_t len) +{ + ssize_t ret = 0; + uint8_t result = 0; + uint32_t size = 0; + + g_core_fp.fp_sense_off(true); + msleep(20); + if (g_core_fp._diff_overlay_flash() == 1) + size = FW_SIZE_128k; + else + size = FW_SIZE_64k; + result = g_core_fp.fp_calculateChecksum(false, size); + g_core_fp.fp_sense_on(0x01); + + if (result) + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "CRC test is Pass!\n"); + else + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "CRC test is Fail!\n"); + + return ret; +} + +#if 0 +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + + if (!HX_PROC_SEND_FLAG) { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "IC = %s\n", private_ts->chip_name); + + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "FW_VER = 0x%2.2X\n", ic_data->vendor_fw_ver); + + if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "CONFIG_VER = 0x%2.2X\n", + ic_data->vendor_config_ver); + } else { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "TOUCH_VER = 0x%2.2X\n", + ic_data->vendor_touch_cfg_ver); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "DISPLAY_VER = 0x%2.2X\n", + ic_data->vendor_display_cfg_ver); + } + + if (ic_data->vendor_cid_maj_ver < 0 + && ic_data->vendor_cid_min_ver < 0) { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "CID_VER = NULL\n"); + } else { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "CID_VER = 0x%2.2X\n", + (ic_data->vendor_cid_maj_ver << 8 | + ic_data->vendor_cid_min_ver)); + } + + if (ic_data->vendor_panel_ver < 0) { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "PANEL_VER = NULL\n"); + } else { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "PANEL_VER = 0x%2.2X\n", + ic_data->vendor_panel_ver); + } + if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "Cusomer = %s\n", + ic_data->vendor_cus_info); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "Project = %s\n", + ic_data->vendor_proj_info); + } + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n"); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "Himax Touch Driver Version:\n"); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%s\n", + HIMAX_DRIVER_VER); + HX_PROC_SEND_FLAG = 1; + + if (copy_to_user(buf, buf_tmp, (len > BUF_SIZE)?BUF_SIZE:len)) + I("%s,here:%d\n", __func__, __LINE__); + + } else { + HX_PROC_SEND_FLAG = 0; + } + + return ret; +} + +static const struct file_operations himax_proc_vendor_ops = { + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; +#endif + +static ssize_t himax_attn_read(char *buf, size_t len) +{ + ssize_t ret = 0; + struct himax_ts_data *ts_data; + + ts_data = private_ts; + + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "attn = %x\n", + himax_int_gpio_read(ts_data->pdata->gpio_irq)); + + return ret; +} + +static int test_irq_pin(void) +{ + struct himax_ts_data *ts = private_ts; + int result = NO_ERR; + int irq_sts = -1; + uint8_t tmp_addr[DATA_LEN_4] = {0}; + uint8_t tmp_data[DATA_LEN_4] = {0}; + uint8_t tmp_read[DATA_LEN_4] = {0}; + + g_core_fp.fp_sense_off(true); + + I("check IRQ LOW\n"); + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028060, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000002, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, 0); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028064, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, 0); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028068, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000000, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, 0); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + irq_sts = himax_int_gpio_read(ts->pdata->gpio_irq); + if (irq_sts == 0) { + I("[LOW]Now IRQ is LOW!\n"); + result += NO_ERR; + } else { + I("[LOW]Now IRQ is High!\n"); + result += 1; + } + + I("check IRQ High\n"); + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028060, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000002, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028064, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x90028068, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, false); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + + usleep_range(20000, 20001); + irq_sts = himax_int_gpio_read(ts->pdata->gpio_irq); + if (irq_sts == 0) { + I("[High]Now IRQ is LOW!\n"); + result += 1; + } else { + I("[High]Now IRQ is High!\n"); + result += NO_ERR; + } + debug_data->is_checking_irq = false; + + g_core_fp.fp_sense_on(0x00); + + return result; +} +static ssize_t himax_int_en_read(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + int check_rslt = -1; + + + if (debug_data->is_checking_irq) { + check_rslt = test_irq_pin(); + if (check_rslt == NO_ERR) { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "IRQ check OK!\n"); + } else { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "IRQ check Fail!\n"); + } + } else { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d\n", + ts->irq_enabled); + } + return ret; +} + +static ssize_t himax_int_en_write(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + + if (buf[0] == '0') { + himax_int_enable(0); + } else if (buf[0] == '1') { + himax_int_enable(1); + } else if (buf[0] == '2') { + himax_int_enable(0); + free_irq(ts->hx_irq, ts); + ts->irq_enabled = 0; + } else if (buf[0] == '3') { + ret = himax_int_en_set(); + + if (ret == 0) { + ts->irq_enabled = 1; + atomic_set(&ts->irq_state, 1); + } + } else if (buf[0] == 't' + && buf[1] == 'e' + && buf[2] == 's' + && buf[3] == 't') { + debug_data->is_checking_irq = true; + I("Checking IRQ start!\n"); + } else + return -EINVAL; + + return len; +} + +static ssize_t himax_layout_read(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ", + ts->pdata->abs_x_min); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ", + ts->pdata->abs_x_max); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ", + ts->pdata->abs_y_min); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%d ", + ts->pdata->abs_y_max); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n"); + + return ret; +} + +static ssize_t himax_layout_write(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[5] = {0}; + int i = 0, j = 0, k = 0, ret; + unsigned long value; + int layout[4] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + for (i = 0; i < 20; i++) { + if (buf[i] == ',' || buf[i] == '\n') { + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + + if (i - j <= 5) { + memcpy(buf_tmp, buf + j, i - j); + } else { + I("buffer size is over 5 char\n"); + return len; + } + + j = i + 1; + + if (k < 4) { + ret = kstrtoul(buf_tmp, 10, &value); + layout[k++] = value; + } + } + } + + if (k == 4) { + ts->pdata->abs_x_min = layout[0]; + ts->pdata->abs_x_max = (layout[1] - 1); + ts->pdata->abs_y_min = layout[2]; + ts->pdata->abs_y_max = (layout[3] - 1); + I("%d, %d, %d, %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + input_unregister_device(ts->input_dev); + himax_input_register(ts); + } else { + I("ERR@%d, %d, %d, %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + } + + return len; +} + +static ssize_t himax_debug_level_read(char *buf, size_t len) +{ + struct himax_ts_data *ts_data; + size_t ret = 0; + + ts_data = private_ts; + + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "%u\n", + ts_data->debug_log_level); + + if (copy_to_user(buf, buf_tmp, (len > BUF_SIZE)?BUF_SIZE:len)) + I("%s,here:%d\n", __func__, __LINE__); + + return ret; +} + +static ssize_t himax_debug_level_write(char *buf, size_t len) +{ + struct himax_ts_data *ts; + int i; + + ts = private_ts; + + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + + ts->debug_log_level = 0; + + for (i = 0; i < len; i++) { + if (buf[i] >= '0' && buf[i] <= '9') + ts->debug_log_level |= (buf[i] - '0'); + else if (buf[i] >= 'A' && buf[i] <= 'F') + ts->debug_log_level |= (buf[i] - 'A' + 10); + else if (buf[i] >= 'a' && buf[i] <= 'f') + ts->debug_log_level |= (buf[i] - 'a' + 10); + + if (i != len - 1) + ts->debug_log_level <<= 4; + } + I("Now debug level value=%d\n", ts->debug_log_level); + + if (ts->debug_log_level & BIT(4)) { + I("Turn on/Enable Debug Mode for Inspection!\n"); + goto END_FUNC; + } + + if (ts->debug_log_level & BIT(3)) { + if (ts->pdata->screenWidth > 0 + && ts->pdata->screenHeight > 0 + && (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 + && (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { + ts->widthFactor = + (ts->pdata->screenWidth << SHIFTBITS) + / (ts->pdata->abs_x_max + - ts->pdata->abs_x_min); + ts->heightFactor = + (ts->pdata->screenHeight << SHIFTBITS) + / (ts->pdata->abs_y_max + - ts->pdata->abs_y_min); + + if (ts->widthFactor > 0 && ts->heightFactor > 0) { + ts->useScreenRes = 1; + } else { + ts->heightFactor = 0; + ts->widthFactor = 0; + ts->useScreenRes = 0; + } + } else { + I("Enable finger debug with raw position mode!\n"); + } + } else { + ts->useScreenRes = 0; + ts->widthFactor = 0; + ts->heightFactor = 0; + } +END_FUNC: + return len; +} + +static ssize_t himax_proc_register_read(char *buf, size_t len) +{ + int ret = 0; + uint16_t loop_i; + + memset(reg_read_data, 0x00, 128 * sizeof(uint8_t)); + + I("himax_register_show: %02X,%02X,%02X,%02X\n", + reg_cmd[3], reg_cmd[2], + reg_cmd[1], reg_cmd[0]); + g_core_fp.fp_register_read(reg_cmd, 128, + reg_read_data, cfg_flag); + + ret += snprintf(buf_tmp + ret, len - ret, + "command: %02X,%02X,%02X,%02X\n", + reg_cmd[3], reg_cmd[2], + reg_cmd[1], reg_cmd[0]); + + for (loop_i = 0; loop_i < 128; loop_i++) { + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "0x%2.2X ", + reg_read_data[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, "\n"); + + } + + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, "\n"); + + return ret; +} + +static ssize_t himax_proc_register_write(char *buf, size_t len) +{ + char buff_tmp[16] = {0}; + uint8_t length = 0; + unsigned long result = 0; + uint8_t loop_i = 0; + uint16_t base = 2; + char *data_str = NULL; + uint8_t w_data[20] = {0}; + uint8_t x_pos[20] = {0}; + uint8_t count = 0; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + memset(reg_cmd, 0x0, sizeof(reg_cmd)); + + I("himax %s\n", buf); + + if ((buf[0] == 'r' || buf[0] == 'w') + && buf[1] == ':' + && buf[2] == 'x') { + length = strlen(buf); + + /* I("%s: length = %d.\n", __func__,length); */ + for (loop_i = 0; loop_i < length; loop_i++) { + /* find postion of 'x' */ + if (buf[loop_i] == 'x') { + x_pos[count] = loop_i; + count++; + } + } + + data_str = strrchr(buf, 'x'); + I("%s: %s.\n", __func__, data_str); + length = strlen(data_str + 1); + + switch (buf[0]) { + case 'r': + if (buf[3] == 'F' && buf[4] == 'E' && length == 4) { + length = length - base; + cfg_flag = 1; + memcpy(buff_tmp, data_str + base + 1, length); + } else { + cfg_flag = 0; + memcpy(buff_tmp, data_str + 1, length); + } + byte_length = length / 2; + if (!kstrtoul(buff_tmp, 16, &result)) { + for (loop_i = 0; loop_i < byte_length; loop_i++) + reg_cmd[loop_i] = + (uint8_t)(result >> loop_i * 8); + } + + if (strcmp(HX_85XX_H_SERIES_PWON, + private_ts->chip_name) == 0 && cfg_flag == 0) + cfg_flag = 2; + break; + case 'w': + if (buf[3] == 'F' && buf[4] == 'E') { + cfg_flag = 1; + memcpy(buff_tmp, buf + base + 3, length); + } else { + cfg_flag = 0; + memcpy(buff_tmp, buf + 3, length); + } + + if (count < 3) { + byte_length = length / 2; + + if (!kstrtoul(buff_tmp, 16, &result)) { + /* command */ + for (loop_i = 0; loop_i < byte_length; + loop_i++) { + reg_cmd[loop_i] = + (uint8_t)(result >> loop_i * 8); + } + } + + if (!kstrtoul(data_str + 1, 16, &result)) { + /* data */ + for (loop_i = 0; loop_i < byte_length; + loop_i++) { + w_data[loop_i] = + (uint8_t)(result >> loop_i * 8); + } + } + + g_core_fp.fp_register_write(reg_cmd, + byte_length, w_data, cfg_flag); + } else { + for (loop_i = 0; loop_i < count; loop_i++) { + /* parsing addr after 'x' */ + memset(buff_tmp, 0x0, sizeof(buff_tmp)); + if (cfg_flag != 0 && loop_i != 0) + byte_length = 2; + else + byte_length = x_pos[1] - + x_pos[0] - 2;/* original */ + + memcpy(buff_tmp, + buf + x_pos[loop_i] + 1, + byte_length); + + /* I("%s: buff_tmp = %s\n",*/ + /* __func__, buff_tmp);*/ + if (!kstrtoul(buff_tmp, 16, &result)) { + if (loop_i == 0) + reg_cmd[loop_i] = + (uint8_t)(result); + /* I("%s: + * reg_cmd + * = %X\n", __func__, + * reg_cmd[0]); + */ + else + w_data[loop_i - 1] = + (uint8_t)(result); + /* I("%s: w_data[%d] = + * %2X\n", __func__, + * loop_i - 1, + * w_data[loop_i - 1]); + */ + } + } + + byte_length = count - 1; + if (strcmp(HX_85XX_H_SERIES_PWON, + private_ts->chip_name) == 0 && cfg_flag == 0) + cfg_flag = 2; + g_core_fp.fp_register_write(reg_cmd, + byte_length, &w_data[0], cfg_flag); + + } + break; + }; + } + return len; +} + +int32_t *getMutualBuffer(void) +{ + return diag_mutual; +} +int32_t *getMutualNewBuffer(void) +{ + return diag_mutual_new; +} +int32_t *getMutualOldBuffer(void) +{ + return diag_mutual_old; +} +int32_t *getSelfBuffer(void) +{ + return diag_self; +} +int32_t *getSelfNewBuffer(void) +{ + return diag_self_new; +} +int32_t *getSelfOldBuffer(void) +{ + return diag_self_old; +} +void setMutualBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_mutual = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); +} +void setMutualNewBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_mutual_new = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); +} +void setMutualOldBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_mutual_old = kzalloc(x_num * y_num * sizeof(int32_t), GFP_KERNEL); +} +void setSelfBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_self = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); +} +void setSelfNewBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_self_new = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); +} +void setSelfOldBuffer(uint8_t x_num, uint8_t y_num) +{ + diag_self_old = kzalloc((x_num + y_num) * sizeof(int32_t), GFP_KERNEL); +} + +#if defined(HX_TP_PROC_2T2R) +int32_t *getMutualBuffer_2(void) +{ + return diag_mutual_2; +} +void setMutualBuffer_2(uint8_t x_num_2, uint8_t y_num_2) +{ + diag_mutual_2 = + kzalloc(x_num_2 * y_num_2 * sizeof(int32_t), GFP_KERNEL); +} +#endif + +int himax_set_diag_cmd(struct himax_ic_data *ic_data, + struct himax_report_data *hx_touch_data) +{ + struct himax_ts_data *ts = private_ts; + int32_t *mutual_data; + int32_t *self_data; + int mul_num; + int self_num; + /* int RawDataLen = 0; */ + hx_touch_data->diag_cmd = ts->diag_cmd; + + if (hx_touch_data->diag_cmd >= 1 && hx_touch_data->diag_cmd <= 7) { + /* Check event stack CRC */ + if (!g_core_fp.fp_diag_check_sum(hx_touch_data)) + goto bypass_checksum_failed_packet; + +#if defined(HX_TP_PROC_2T2R) + if (Is_2T2R && (hx_touch_data->diag_cmd >= 4 && + hx_touch_data->diag_cmd <= 6)) { + mutual_data = getMutualBuffer_2(); + self_data = getSelfBuffer(); + /* initiallize the block number of mutual and self */ + mul_num = ic_data->HX_RX_NUM_2 * ic_data->HX_TX_NUM_2; + self_num = ic_data->HX_RX_NUM_2 + ic_data->HX_TX_NUM_2; + } else +#endif + { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + /* initiallize the block number of mutual and self */ + mul_num = ic_data->HX_RX_NUM * ic_data->HX_TX_NUM; + self_num = ic_data->HX_RX_NUM + ic_data->HX_TX_NUM; + } + g_core_fp.fp_diag_parse_raw_data(hx_touch_data, mul_num, + self_num, hx_touch_data->diag_cmd, mutual_data, + self_data); + } else if (hx_touch_data->diag_cmd == 8) { + memset(diag_coor, 0x00, sizeof(diag_coor)); + memcpy(&(diag_coor[0]), &hx_touch_data->hx_coord_buf[0], + hx_touch_data->touch_info_size); + } + + /* assign state info data */ + memcpy(&(hx_state_info[0]), &hx_touch_data->hx_state_info[0], 2); + return NO_ERR; +bypass_checksum_failed_packet: + return 1; +} + +/* #if defined(HX_DEBUG_LEVEL) */ +void himax_log_touch_data(int start) +{ + int loop_i = 0; + int print_size = 0; + uint8_t *buf = NULL; + + if (start == 1) + return; /* report data when end of ts_work*/ + + if (hx_touch_data->diag_cmd > 0) { + print_size = hx_touch_data->touch_all_size; + buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); + if (buf == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return; + } + + memcpy(buf, hx_touch_data->hx_coord_buf, + hx_touch_data->touch_info_size); + memcpy(&buf[hx_touch_data->touch_info_size], + hx_touch_data->hx_rawdata_buf, + print_size - hx_touch_data->touch_info_size); + } +#if defined(HX_SMART_WAKEUP) + else if (private_ts->SMWP_enable > 0 && private_ts->suspended) { + print_size = hx_touch_data->event_size; + buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); + if (buf == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return; + } + + memcpy(buf, hx_touch_data->hx_event_buf, print_size); + } +#endif + else if (hx_touch_data->diag_cmd == 0) { + print_size = hx_touch_data->touch_info_size; + buf = kcalloc(print_size, sizeof(uint8_t), GFP_KERNEL); + if (buf == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return; + } + + memcpy(buf, hx_touch_data->hx_coord_buf, print_size); + } else { + E("%s:cmd fault\n", __func__); + return; + } + + for (loop_i = 0; loop_i < print_size; loop_i += 8) { + if ((loop_i + 7) >= print_size) { + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + loop_i, + buf[loop_i], + loop_i + 1, + buf[loop_i + 1]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X\n", + loop_i + 2, + buf[loop_i + 2], + loop_i + 3, + buf[loop_i + 3]); + break; + } + + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + loop_i, buf[loop_i], loop_i + 1, buf[loop_i + 1]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + loop_i + 2, buf[loop_i + 2], loop_i + 3, buf[loop_i + 3]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + loop_i + 4, buf[loop_i + 4], loop_i + 5, buf[loop_i + 5]); + I("P %2d = 0x%2.2X P %2d = 0x%2.2X ", + loop_i + 6, buf[loop_i + 6], loop_i + 7, buf[loop_i + 7]); + I("\n"); + } + kfree(buf); +} + +#define PRT_LOG "Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, Int_Delay_Cnt:%d\n" +void himax_log_touch_event(struct himax_ts_data *ts, int start) +{ + int loop_i = 0; + + if (start == 1) + return; /*report data when end of ts_work*/ + + if (g_target_report_data->finger_on > 0 && + g_target_report_data->finger_num > 0) { + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + if (g_target_report_data->x[loop_i] >= 0 + && g_target_report_data->x[loop_i] + <= ts->pdata->abs_x_max + && g_target_report_data->y[loop_i] >= 0 + && g_target_report_data->y[loop_i] + <= ts->pdata->abs_y_max) { + I(PRT_LOG, + loop_i + 1, + g_target_report_data->x[loop_i], + g_target_report_data->y[loop_i], + g_target_report_data->w[loop_i], + g_target_report_data->w[loop_i], + loop_i + 1, + g_target_report_data->ig_count); + } + } + } else if (g_target_report_data->finger_on == 0 + && g_target_report_data->finger_num == 0) { + I("All Finger leave\n"); + } else { + I("%s : wrong input!\n", __func__); + } +} +void himax_log_touch_int_devation(int touched) +{ + if (touched == HX_FINGER_ON) { + getnstimeofday(&timeStart); + /* I(" Irq start time = %ld.%06ld s\n", + * timeStart.tv_sec, timeStart.tv_nsec/1000); + */ + } else if (touched == HX_FINGER_LEAVE) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec = + (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) - + (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + /* I("Irq finish time = %ld.%06ld s\n", + * timeEnd.tv_sec, timeEnd.tv_nsec/1000); + */ + I("Touch latency = %ld us\n", timeDelta.tv_nsec / 1000); + I("bus_speed = %d kHz\n", private_ts->bus_speed); + if (g_target_report_data->finger_on == 0 + && g_target_report_data->finger_num == 0) + I("All Finger leave\n"); + } else { + I("%s : wrong input!\n", __func__); + } +} + +#define RAW_DOWN_STATUS "status: Raw:F:%02d Down, X:%d, Y:%d, W:%d\n" +#define RAW_UP_STATUS "status: Raw:F:%02d Up, X:%d, Y:%d\n" + +void himax_log_touch_event_detail(struct himax_ts_data *ts, int start) +{ + int loop_i = 0; + + if (start == HX_FINGER_LEAVE) { + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + if (((ts->old_finger >> loop_i & 1) == 0) + && ((ts->pre_finger_mask >> loop_i & 1) == 1)) { + if (g_target_report_data->x[loop_i] >= 0 + && g_target_report_data->x[loop_i] + <= ts->pdata->abs_x_max + && g_target_report_data->y[loop_i] >= 0 + && g_target_report_data->y[loop_i] + <= ts->pdata->abs_y_max) { + I(RAW_DOWN_STATUS, loop_i + 1, + g_target_report_data->x[loop_i], + g_target_report_data->y[loop_i], + g_target_report_data->w[loop_i]); + } + } else if ((((ts->old_finger >> loop_i & 1) == 1) + && ((ts->pre_finger_mask >> loop_i & 1) == 0))) { + I(RAW_UP_STATUS, loop_i + 1, + ts->pre_finger_data[loop_i][0], + ts->pre_finger_data[loop_i][1]); + } else { + /* I("dbg hx_point_num=%d, old_finger=0x%02X," + * " pre_finger_mask=0x%02X\n", + * ts->hx_point_num, ts->old_finger, + * ts->pre_finger_mask); + */ + } + } + } +} + +void himax_ts_dbg_func(struct himax_ts_data *ts, int start) +{ + if (ts->debug_log_level & BIT(0)) { + /* I("debug level 1\n"); */ + himax_log_touch_data(start); + } + if (ts->debug_log_level & BIT(1)) { + /* I("debug level 2\n"); */ + himax_log_touch_event(ts, start); + } + if (ts->debug_log_level & BIT(2)) { + /* I("debug level 4\n"); */ + himax_log_touch_int_devation(start); + } + if (ts->debug_log_level & BIT(3)) { + /* I("debug level 8\n"); */ + himax_log_touch_event_detail(ts, start); + } +} + +static int himax_change_mode(uint8_t str_pw, uint8_t end_pw) +{ + uint8_t data[4] = {0}; + int count = 0; + + /*sense off*/ + g_core_fp.fp_sense_off(true); + /*mode change*/ + data[1] = str_pw; data[0] = str_pw; + if (g_core_fp.fp_assign_sorting_mode != NULL) + g_core_fp.fp_assign_sorting_mode(data); + + /*sense on*/ + g_core_fp.fp_sense_on(1); + /*wait mode change*/ + do { + if (g_core_fp.fp_check_sorting_mode != NULL) + g_core_fp.fp_check_sorting_mode(data); + if ((data[0] == end_pw) && (data[1] == end_pw)) + return 0; + + I("Now retry %d times!\n", count); + count++; + msleep(50); + } while (count < 50); + + return ERR_WORK_OUT; +} + +#define PRT_OK_LOG "%s: change mode 0x%4X. str_pw = %2X, end_pw = %2X\n" +#define PRT_FAIL_LOG "%s: change mode failed. str_pw = %2X, end_pw = %2X\n" +static ssize_t himax_diag_cmd_write(char *buf, size_t len) +{ + struct himax_ts_data *ts = private_ts; + char *dbg_map_str = "mode:"; + char *str_ptr = NULL; + int str_len = 0; + int rst = 0; + uint8_t str_pw = 0; + uint8_t end_pw = 0; + + switch (len) { + case 1:/*raw out select - diag,X*/ + if (!kstrtoint(buf, 16, &rst)) { + ts->diag_cmd = rst; + I("%s: dsram_flag = %d\n", __func__, dsram_flag); + if (dsram_flag) { + /*Cancal work queue and return to stack*/ + process_type = 0; + dsram_flag = false; + cancel_delayed_work(&ts->himax_diag_delay_wrok); + himax_int_enable(1); + g_core_fp.fp_return_event_stack(); + } + g_core_fp.fp_diag_register_set(ts->diag_cmd, 0, false); + I("%s: Set raw out select 0x%X.\n", + __func__, ts->diag_cmd); + } + if (!ts->diag_cmd) { + if (mode_flag) /*back to normal mode*/ + himax_change_mode(0x00, 0x99); + } + break; + case 2:/*data processing + rawout select - diag,XY*/ + if (!kstrtoint(buf, 16, &rst)) { + process_type = (rst >> 4) & 0xF; + ts->diag_cmd = rst & 0xF; + } + if (ts->diag_cmd == 0) + break; + else if (process_type > 0 && process_type <= 3) { + if (!dsram_flag) { + /*Start wrok queue*/ + himax_int_enable(0); + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, false); + + queue_delayed_work(ts->himax_diag_wq, + &ts->himax_diag_delay_wrok, 2 * HZ / 100); + dsram_flag = true; + + I("%s: Start get raw data in DSRAM\n", + __func__); + } else { + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, false); + } + } + break; + case 4:/*data processing + rawout select - diag,XXYY*/ + /*ex:XXYY=010A=dsram rawdata*/ + I("%s, now case 4\n", __func__); + if (!kstrtoint(buf, 16, &rst)) { + process_type = (rst >> 8) & 0xFF; + ts->diag_cmd = rst & 0xFF; + I("%s:process_type=0x%02X, diag_cmd=0x%02X\n", + __func__, process_type, ts->diag_cmd); + } + if (process_type <= 0 || ts->diag_cmd <= 0) + break; + else if (process_type > 0 && process_type <= 3) { + if (!dsram_flag) { + /*Start wrok queue*/ + himax_int_enable(0); + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, true); + + queue_delayed_work(ts->himax_diag_wq, + &ts->himax_diag_delay_wrok, 2 * HZ / 100); + dsram_flag = true; + + I("%s: Start get raw data in DSRAM\n", + __func__); + } else { + g_core_fp.fp_diag_register_set(ts->diag_cmd, + process_type, true); + } + } + break; + case 9:/*change mode - mode:XXYY(start PW,end PW)*/ + str_ptr = strnstr(buf, dbg_map_str, len); + if (str_ptr) { + str_len = strlen(dbg_map_str); + if (!kstrtoint(buf + str_len, 16, &rst)) { + str_pw = (rst >> 8) & 0xFF; + end_pw = rst & 0xFF; + if (!himax_change_mode(str_pw, end_pw)) { + mode_flag = 1; + I(PRT_OK_LOG, __func__, + rst, str_pw, end_pw); + } else + I(PRT_FAIL_LOG, __func__, + str_pw, end_pw); + } + } else { + I("%s: Can't find string [%s].\n", + __func__, dbg_map_str); + } + break; + default: + I("%s: Length is not correct.\n", __func__); + } + return len; +} + +static ssize_t himax_diag_arrange_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + g_diag_arr_num = buf[0] - '0'; + I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num); + return len; +} + +void himax_get_mutual_edge(void) +{ + int i = 0; + + for (i = 0; i < (ic_data->HX_RX_NUM * ic_data->HX_TX_NUM); i++) { + if (diag_mutual[i] > g_max_mutual) + g_max_mutual = diag_mutual[i]; + + if (diag_mutual[i] < g_min_mutual) + g_min_mutual = diag_mutual[i]; + } +} + +void himax_get_self_edge(void) +{ + int i = 0; + + for (i = 0; i < (ic_data->HX_RX_NUM + ic_data->HX_TX_NUM); i++) { + if (diag_self[i] > g_max_self) + g_max_self = diag_self[i]; + + if (diag_self[i] < g_min_self) + g_min_self = diag_self[i]; + } +} + +static void print_state_info(struct seq_file *s) +{ + /* seq_printf(s, "State_info_2bytes:%3d, %3d\n", + * _state_info[0],hx_state_info[1]); + */ + +#if defined(HX_NEW_EVENT_STACK_FORMAT) + seq_printf(s, "ReCal = %d\t", hx_state_info[0] & 0x03); + seq_printf(s, "Base Line = %d\t", hx_state_info[0] >> 2 & 0x01); + seq_printf(s, "Palm = %d\t", hx_state_info[0] >> 3 & 0x01); + seq_printf(s, "Idle mode = %d\t", hx_state_info[0] >> 4 & 0x01); + seq_printf(s, "Water = %d\n", hx_state_info[0] >> 5 & 0x01); + seq_printf(s, "TX Hop = %d\t", hx_state_info[0] >> 6 & 0x01); + seq_printf(s, "AC mode = %d\t", hx_state_info[0] >> 7 & 0x01); + seq_printf(s, "Glove = %d\t", hx_state_info[1] & 0x01); + seq_printf(s, "Stylus = %d\t", hx_state_info[1] >> 1 & 0x01); + seq_printf(s, "Hovering = %d\t", hx_state_info[1] >> 2 & 0x01); + seq_printf(s, "Proximity = %d\t", hx_state_info[1] >> 3 & 0x01); + seq_printf(s, "KEY = %d\n", hx_state_info[1] >> 4 & 0x0F); +#else + seq_printf(s, "ReCal = %d\t", hx_state_info[0] & 0x01); + seq_printf(s, "Palm = %d\t", hx_state_info[0] >> 1 & 0x01); + seq_printf(s, "AC mode = %d\t", hx_state_info[0] >> 2 & 0x01); + seq_printf(s, "Water = %d\n", hx_state_info[0] >> 3 & 0x01); + seq_printf(s, "Glove = %d\t", hx_state_info[0] >> 4 & 0x01); + seq_printf(s, "TX Hop = %d\t", hx_state_info[0] >> 5 & 0x01); + seq_printf(s, "Base Line = %d\t", hx_state_info[0] >> 6 & 0x01); + seq_printf(s, "OSR Hop = %d\t", hx_state_info[1] >> 3 & 0x01); + seq_printf(s, "KEY = %d\n", hx_state_info[1] >> 4 & 0x0F); +#endif +} + +static void himax_diag_arrange_print(struct seq_file *s, int i, int j, + int transpose) +{ + if (transpose) + seq_printf(s, "%6d", diag_mutual[j + i * ic_data->HX_RX_NUM]); + else + seq_printf(s, "%6d", diag_mutual[i + j * ic_data->HX_RX_NUM]); +} + +/* ready to print second step which is column*/ +static void himax_diag_arrange_inloop(struct seq_file *s, int in_init, + int out_init, bool transpose, int j) +{ + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int i; + int in_max = 0; + + if (transpose) + in_max = y_channel; + else + in_max = x_channel; + + if (in_init > 0) { /* bit0 = 1 */ + for (i = in_init - 1; i >= 0; i--) + himax_diag_arrange_print(s, i, j, transpose); + + if (transpose) { + if (out_init > 0) + seq_printf(s, " %5d\n", diag_self[j]); + else + seq_printf(s, " %5d\n", + diag_self[x_channel - j - 1]); + } + } else { /* bit0 = 0 */ + for (i = 0; i < in_max; i++) + himax_diag_arrange_print(s, i, j, transpose); + + if (transpose) { + if (out_init > 0) + seq_printf(s, " %5d\n", + diag_self[x_channel - j - 1]); + else + seq_printf(s, " %5d\n", diag_self[j]); + } + } +} + +/* print first step which is row */ +static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, + int out_init, int in_init) +{ + int j; + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int out_max = 0; + int self_cnt = 0; + + if (transpose) + out_max = x_channel; + else + out_max = y_channel; + + if (out_init > 0) { /* bit1 = 1 */ + self_cnt = 1; + + for (j = out_init - 1; j >= 0; j--) { + seq_printf(s, "%3c%02d%c", '[', j + 1, ']'); + himax_diag_arrange_inloop(s, in_init, out_init, + transpose, j); + + if (!transpose) { + seq_printf(s, " %5d\n", + diag_self[y_channel + x_channel - self_cnt]); + self_cnt++; + } + } + } else { /* bit1 = 0 */ + /* self_cnt = x_channel; */ + for (j = 0; j < out_max; j++) { + seq_printf(s, "%3c%02d%c", '[', j + 1, ']'); + himax_diag_arrange_inloop(s, in_init, out_init, + transpose, j); + + if (!transpose) { + seq_printf(s, " %5d\n", + diag_self[j + x_channel]); + } + } + } +} + +/* determin the output format of diag */ +static void himax_diag_arrange(struct seq_file *s) +{ + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int bit2, bit1, bit0; + int i; + /* rotate bit */ + bit2 = g_diag_arr_num >> 2; + /* reverse Y */ + bit1 = g_diag_arr_num >> 1 & 0x1; + /* reverse X */ + bit0 = g_diag_arr_num & 0x1; + + if (g_diag_arr_num < 4) { + for (i = 0 ; i <= x_channel; i++) + seq_printf(s, "%3c%02d%c", '[', i, ']'); + + seq_puts(s, "\n"); + himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, + bit0 * x_channel); + seq_printf(s, "%6c", ' '); + + if (bit0 == 1) { + for (i = x_channel - 1; i >= 0; i--) + seq_printf(s, "%6d", diag_self[i]); + } else { + for (i = 0; i < x_channel; i++) + seq_printf(s, "%6d", diag_self[i]); + } + } else { + for (i = 0 ; i <= y_channel; i++) + seq_printf(s, "%3c%02d%c", '[', i, ']'); + + seq_puts(s, "\n"); + himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, + bit0 * y_channel); + seq_printf(s, "%6c", ' '); + + if (bit1 == 1) { + for (i = x_channel + y_channel - 1; i >= x_channel; + i--) + seq_printf(s, "%6d", diag_self[i]); + } else { + for (i = x_channel; i < x_channel + y_channel; i++) + seq_printf(s, "%6d", diag_self[i]); + } + } +} + +static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) + return NULL; + + return (void *)((unsigned long) *pos + 1); +} + +static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} + +static void himax_diag_seq_stop(struct seq_file *s, void *v) +{ + kfree(v); +} + +/* DSRAM thread */ +bool himax_ts_diag_func(void) +{ + int retry = 3; + int i = 0, j = 0; + unsigned int index = 0; + int x_channel = ic_data->HX_RX_NUM; + int y_channel = ic_data->HX_TX_NUM; + int total_size = (y_channel * x_channel + y_channel + x_channel) * 2; + uint8_t *info_data = NULL; + int32_t *mutual_data = NULL; + int32_t *mutual_data_new = NULL; + int32_t *mutual_data_old = NULL; + int32_t *self_data = NULL; + int32_t *self_data_new = NULL; + int32_t *self_data_old = NULL; + int32_t new_data; + /* 1:common dsram,2:100 frame Max,3:N-(N-1)frame */ + int dsram_type = process_type; + + info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); + if (info_data == NULL) { + E("%s: Failed to allocate memory\n", __func__); + return false; + } + + memset(info_data, 0, total_size * sizeof(uint8_t)); + + I("%s: process type=%d!\n", __func__, process_type); + + g_core_fp.fp_burst_enable(1); + + if (dsram_type <= 2) { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + } else if (dsram_type == 3) { + mutual_data = getMutualBuffer(); + mutual_data_new = getMutualNewBuffer(); + mutual_data_old = getMutualOldBuffer(); + self_data = getSelfBuffer(); + self_data_new = getSelfNewBuffer(); + self_data_old = getSelfOldBuffer(); + } + + do { + if (g_core_fp.fp_get_DSRAM_data(info_data, dsram_flag)) + break; + } while (retry-- > 0); + + if (retry <= 0) { + E("%s: Get DSRAM data failed\n", __func__); + kfree(info_data); + return false; + } + + index = 0; + + for (i = 0; i < y_channel; i++) { /*mutual data*/ + for (j = 0; j < x_channel; j++) { + new_data = (((int8_t)info_data[index + 1] << 8) | + info_data[index]); + + if (dsram_type <= 1) { + mutual_data[i * x_channel + j] = new_data; + } else if (dsram_type == 2) { /* Keep max data */ + if (mutual_data[i * x_channel + j] < new_data) + mutual_data[i * x_channel + j] = + new_data; + } else if (dsram_type == 3) { + /* Cal data for [N]-[N-1] frame */ + mutual_data_new[i * x_channel + j] = new_data; + mutual_data[i * x_channel + j] = + mutual_data_new[i * x_channel + j] + - mutual_data_old[i * x_channel + j]; + } + index += 2; + } + } + + for (i = 0; i < x_channel + y_channel; i++) { /*self data*/ + new_data = (((int8_t)info_data[index + 1] << 8) | + info_data[index]); + if (dsram_type <= 1) { + self_data[i] = new_data; + } else if (dsram_type == 2) { /* Keep max data */ + if (self_data[i] < new_data) + self_data[i] = new_data; + } else if (dsram_type == 3) { /* Cal data for [N]-[N-1] frame */ + self_data_new[i] = new_data; + self_data[i] = self_data_new[i] - self_data_old[i]; + } + index += 2; + } + + kfree(info_data); + + if (dsram_type == 3) { + memcpy(mutual_data_old, mutual_data_new, + x_channel * y_channel * sizeof(int32_t)); + /* copy N data to N-1 array */ + memcpy(self_data_old, self_data_new, + (x_channel + y_channel) * sizeof(int32_t)); + /* copy N data to N-1 array */ + } + + diag_max_cnt++; + + if (dsram_type >= 1 && dsram_type <= 3) { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1 / 10 * HZ); + } + return true; +} + +static int himax_diag_print(struct seq_file *s, void *v) +{ + int x_num = ic_data->HX_RX_NUM; + int y_num = ic_data->HX_TX_NUM; + size_t ret = 0; + uint16_t mutual_num, self_num, width; + + mutual_num = x_num * y_num; + self_num = x_num + y_num; + /* don't add KEY_COUNT */ + width = x_num; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_num, y_num); + + /* start to show out the raw data in adb shell */ + himax_diag_arrange(s); + seq_puts(s, "\n"); + seq_puts(s, "ChannelEnd"); + seq_puts(s, "\n"); + + /* print Mutual/Slef Maximum and Minimum */ + himax_get_mutual_edge(); + himax_get_self_edge(); + seq_printf(s, "Mutual Max:%3d, Min:%3d\n", g_max_mutual, + g_min_mutual); + seq_printf(s, "Self Max:%3d, Min:%3d\n", g_max_self, + g_min_self); + /* recovery status after print*/ + g_max_mutual = 0; + g_min_mutual = 0xFFFF; + g_max_self = 0; + g_min_self = 0xFFFF; + + /*pring state info*/ + print_state_info(s); + + if (s->count >= s->size) + overflow++; + + return ret; +} + +static int himax_diag_stack_read(struct seq_file *s, void *v) +{ + struct himax_ts_data *ts = private_ts; + + if (ts->diag_cmd) + himax_diag_print(s, v); + else + seq_puts(s, "Please set raw out select 'echo diag,X > debug'\n\n"); + + return 0; +} + +static const struct seq_operations himax_diag_stack_ops = { + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_stack_read, +}; + +static int himax_diag_stack_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_stack_ops); +}; + +static const struct file_operations himax_proc_stack_ops = { + .owner = THIS_MODULE, + .open = himax_diag_stack_open, + .read = seq_read, + .release = seq_release, +}; + +static int himax_sram_read(struct seq_file *s, void *v, uint8_t rs) +{ + struct himax_ts_data *ts = private_ts; + int d_type = 0; + + d_type = (!ts->diag_cmd)?rs:ts->diag_cmd; + + if (!overflow) { + if (!process_type) { + himax_int_enable(0); + g_core_fp.fp_diag_register_set(d_type, 0, false); + + if (!himax_ts_diag_func()) + seq_puts(s, "Get sram data failed."); + else + himax_diag_print(s, v); + + ts->diag_cmd = 0; + g_core_fp.fp_diag_register_set(0, 0, false); + himax_int_enable(1); + } + } + + if ((process_type <= 3 + && ts->diag_cmd + && dsram_flag) + || overflow) { + himax_diag_print(s, v); + overflow = 0; + } + + return 0; +} + +static int himax_diag_delta_read(struct seq_file *s, void *v) +{ + return himax_sram_read(s, v, 0x09); +} + +static const struct seq_operations himax_diag_delta_ops = { + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_delta_read, +}; + +static int himax_diag_delta_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_delta_ops); +}; + +static const struct file_operations himax_proc_delta_ops = { + .owner = THIS_MODULE, + .open = himax_diag_delta_open, + .read = seq_read, + .release = seq_release, +}; + +static int himax_diag_dc_read(struct seq_file *s, void *v) +{ + return himax_sram_read(s, v, 0x0A); +} + +static const struct seq_operations himax_diag_dc_ops = { + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_dc_read, +}; +static int himax_diag_dc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_dc_ops); +}; + +static const struct file_operations himax_proc_dc_ops = { + .owner = THIS_MODULE, + .open = himax_diag_dc_open, + .read = seq_read, + .release = seq_release, +}; + +static int himax_diag_baseline_read(struct seq_file *s, void *v) +{ + return himax_sram_read(s, v, 0x0B); +} + +static const struct seq_operations himax_diag_baseline_ops = { + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_baseline_read, +}; +static int himax_diag_baseline_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_baseline_ops); +}; + +static const struct file_operations himax_proc_baseline_ops = { + .owner = THIS_MODULE, + .open = himax_diag_baseline_open, + .read = seq_read, + .release = seq_release, +}; +#if defined(HX_RST_PIN_FUNC) +static void test_rst_pin(void) +{ + //struct himax_ts_data *ts = private_ts; + int rst_sts1 = -1; + int rst_sts2 = -1; + int cnt = 0; + uint8_t tmp_addr[DATA_LEN_4] = {0}; + uint8_t tmp_data[DATA_LEN_4] = {0}; + uint8_t tmp_read[DATA_LEN_4] = {0}; + + himax_int_enable(0); + g_core_fp.fp_sense_off(true); + + + usleep_range(20000, 20001); + himax_parse_assign_cmd(0x900000F0, tmp_addr, DATA_LEN_4); + himax_parse_assign_cmd(0x00000001, tmp_data, DATA_LEN_4); + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, tmp_data, 0); + usleep_range(20000, 20001); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + I("trigger Reset Pin\n"); + g_core_fp.fp_ic_reset(false, false); + + usleep_range(20000, 20001); + do { + himax_parse_assign_cmd(0x900000A8, tmp_addr, DATA_LEN_4); + g_core_fp.fp_register_read(tmp_addr, + DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + rst_sts1 = tmp_read[0]; + cnt++; + if (rst_sts1 == 0x05) + break; + if (rst_sts1 == 0x00) + cnt += 5; + if (cnt > 20) + goto END_FUNC; + } while (rst_sts1 == 0x04); + + himax_parse_assign_cmd(0x900000F0, tmp_addr, DATA_LEN_4); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_read, false); + I("R%02X%02X%02X%02XH = 0x%02X%02X%02X%02X\n", + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_read[3], tmp_read[2], tmp_read[1], tmp_read[0]); + rst_sts2 = tmp_read[0]; + +END_FUNC: + if (rst_sts1 == 0x05 && rst_sts2 == 0x00) + I("%s: TP Reset test OK!\n", __func__); + else if (rst_sts1 == 0xFF || rst_sts2 == 0x01) + I("%s: TP Reset test Fail!\n", __func__); + else + I("%s, Unknown Fail state1=0x%02X, state2=0x%02X!\n", + __func__, rst_sts1, rst_sts2); + + g_core_fp.fp_sense_on(0x00); + himax_int_enable(1); +} +#endif +static ssize_t himax_reset_write(char *buf, size_t len) +{ + if (len >= 12) { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + +#if defined(HX_RST_PIN_FUNC) + if (buf[0] == '1') + g_core_fp.fp_ic_reset(false, false); + else if (buf[0] == '2') + g_core_fp.fp_ic_reset(false, true); + /* else if (buf[0] == '5') */ + /* ESD_HW_REST(); */ + else if (buf[0] == 't' + && buf[1] == 'e' + && buf[2] == 's' + && buf[3] == 't') + test_rst_pin(); +#endif +#if defined(HX_ZERO_FLASH) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); +#endif + return len; +} + +static ssize_t himax_proc_FW_debug_read(char *buf, size_t len) +{ + ssize_t ret = 0; + uint8_t i = 0; + uint8_t addr[4] = {0}; + uint8_t data[4] = {0}; + + len = (size_t)(sizeof(dbg_reg_ary)/sizeof(uint32_t)); + + for (i = 0; i < len; i++) { + himax_parse_assign_cmd(dbg_reg_ary[i], addr, 4); + g_core_fp.fp_register_read(addr, DATA_LEN_4, data, 0); + + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + dbg_reg_ary[i], data[0], data[1], data[2], data[3]); + I("reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + dbg_reg_ary[i], data[0], data[1], data[2], data[3]); + } + + return ret; +} + +static ssize_t himax_proc_DD_debug_read(char *buf, size_t len) +{ + ssize_t ret = 0; + uint8_t tmp_data[64] = {0}; + uint8_t loop_i = 0; + + if (mutual_set_flag == 1) { + if (g_core_fp.fp_read_DD_status(cmd_set, tmp_data) == + NO_ERR) { + for (loop_i = 0; loop_i < cmd_set[0]; + loop_i++) { + if ((loop_i % 8) == 0) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "0x%02X : ", loop_i); + + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, "0x%02X ", + tmp_data[loop_i]); + + if ((loop_i % 8) == 7) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, "\n"); + } + } else { + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Get DD status falied!\n"); + } + } + + ret += snprintf(buf_tmp + ret, len - ret, "\n"); + + return ret; +} + +#define STR_TO_UL_ERR "String to ul is fail in cnt = %d, buf_tmp2 = %s\n" + +static ssize_t himax_proc_DD_debug_write(char *buf, size_t len) +{ + uint8_t i = 0; + uint8_t cnt = 2; + unsigned long result = 0; + char buf_tmp2[4]; + + if (len >= 20) { + I("%s: no command exceeds 20 chars.\n", __func__); + return -EFAULT; + } + + memset(buf_tmp2, 0x0, sizeof(buf_tmp2)); + + if (buf[2] == 'x' && buf[6] == 'x' && buf[10] == 'x') { + mutual_set_flag = 1; + + for (i = 3; i < 12; i = i + 4) { + memcpy(buf_tmp2, buf + i, 2); + + if (!kstrtoul(buf_tmp2, 16, &result)) + cmd_set[cnt] = (uint8_t)result; + else + I(STR_TO_UL_ERR, cnt, buf_tmp2); + + cnt--; + } + + I("cmd_set[2] = %02X, cmd_set[1] = %02X, cmd_set[0] = %02X\n", + cmd_set[2], cmd_set[1], cmd_set[0]); + } else { + mutual_set_flag = 0; + } + + return len; +} + +void setFlashBuffer(void) +{ + flash_buffer = kcalloc(Flash_Size, sizeof(uint8_t), GFP_KERNEL); +} + +void flash_dump_prog_set(uint8_t prog) +{ + g_flash_progress = prog; + if (prog == ONGOING) + debug_data->flash_dump_going = ONGOING; + else + debug_data->flash_dump_going = START; +} + +static int himax_proc_flash_read(struct seq_file *s, void *v) +{ + ssize_t ret = 0; + int i; + uint8_t flash_progress = g_flash_progress; + uint8_t flash_cmd = g_flash_cmd; + bool flash_rst = g_flash_dump_rst; + + I("flash_progress = %d\n", flash_progress); + + if (!flash_rst) { + seq_puts(s, "FlashStart:Fail\n"); + seq_puts(s, "FlashEnd\n"); + return ret; + } + + if (flash_progress == START) + seq_puts(s, "Flash dump - Start\n"); + else if (flash_progress == ONGOING) + seq_puts(s, "Flash dump - On-going\n"); + else if (flash_progress == FINISHED) + seq_puts(s, "Flash dump - Finished\n"); + + /*print flash dump data*/ + if (flash_cmd == 1 && flash_progress == FINISHED) { + seq_puts(s, "Start to print flash dump data\n"); + for (i = 0; i < Flash_Size; i++) { + seq_printf(s, "0x%02X,", flash_buffer[i]); + if (i % 16 == 15) + seq_puts(s, "\n"); + } + } + + seq_puts(s, "FlashEnd\n"); + + return ret; +} + +static ssize_t himax_proc_flash_write(struct file *filp, + const char __user *buff, size_t len, loff_t *data) +{ + char buf[80] = {0}; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + I("%s: buf = %s\n", __func__, buf); + + if (g_flash_progress == ONGOING) { + E("%s: process is busy , return!\n", __func__); + return len; + } + + if ((buf[1] == '_') && (buf[2] == '3') && (buf[3] == '2')) + Flash_Size = FW_SIZE_32k; + else if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') + Flash_Size = FW_SIZE_60k; + else if (buf[3] == '4') + Flash_Size = FW_SIZE_64k; + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') + Flash_Size = FW_SIZE_124k; + else if (buf[3] == '8') + Flash_Size = FW_SIZE_128k; + } + + /*1 : print flash to window, 2 : dump to sdcard*/ + if (buf[0] == '1') { + /* 1_32,1_60,1_64,1_24,1_28 for flash size: + * 32k,60k,64k,124k,128k + */ + g_flash_cmd = 1; + flash_dump_prog_set(START); + g_flash_dump_rst = true; + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } else if (buf[0] == '2') { + /* 2_32,2_60,2_64,2_24,2_28 for flash size: + * 32k,60k,64k,124k,128k + */ + g_flash_cmd = 2; + flash_dump_prog_set(START); + g_flash_dump_rst = true; + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + + return len; +} + +static void *himax_flash_dump_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) + return NULL; + + return (void *)((unsigned long) *pos + 1); +} + +static void *himax_flash_dump_seq_next(struct seq_file *s, void *v, + loff_t *pos) +{ + return NULL; +} + +static void himax_flash_dump_seq_stop(struct seq_file *s, void *v) +{ +} + +static const struct seq_operations himax_flash_dump_seq_ops = { + .start = himax_flash_dump_seq_start, + .next = himax_flash_dump_seq_next, + .stop = himax_flash_dump_seq_stop, + .show = himax_proc_flash_read, +}; +static int himax_flash_dump_proc_open(struct inode *inode, + struct file *file) +{ + return seq_open(file, &himax_flash_dump_seq_ops); +}; + +static const struct file_operations himax_proc_flash_ops = { + .owner = THIS_MODULE, + .open = himax_flash_dump_proc_open, + .read = seq_read, + .write = himax_proc_flash_write, +}; + +void himax_ts_flash_func(void) +{ + uint8_t flash_command = g_flash_cmd; + + himax_int_enable(0); + flash_dump_prog_set(ONGOING); + + /*msleep(100);*/ + I("%s: flash_command = %d enter.\n", __func__, flash_command); + + if (flash_command == 1 || flash_command == 2) { + g_core_fp.fp_flash_dump_func(flash_command, Flash_Size, + flash_buffer); + g_flash_dump_rst = true; + } + + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); + +/* if (flash_command == 2) { + * struct file *fn; + * struct filename *vts_name; + * + * vts_name = kp_getname_kernel(FLASH_DUMP_FILE); + * fn = kp_file_open_name(vts_name, O_CREAT | O_WRONLY, 0); + * + * if (!IS_ERR(fn)) { + * I("%s create file and ready to write\n", __func__); + * fn->f_op->write(fn, flash_buffer, + * Flash_Size * sizeof(uint8_t), &fn->f_pos); + * filp_close(fn, NULL); + * } else { + * E("%s Open file failed!\n", __func__); + * g_flash_dump_rst = false; + * } + * } + */ + himax_int_enable(1); + flash_dump_prog_set(FINISHED); +} + +static ssize_t himax_sense_on_off_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (buf[0] == '0') { + g_core_fp.fp_sense_off(true); + I("Sense off\n"); + } else if (buf[0] == '1') { + if (buf[1] == 's') { + g_core_fp.fp_sense_on(0x00); + I("Sense on re-map on, run sram\n"); + } else { + g_core_fp.fp_sense_on(0x01); + I("Sense on re-map off, run flash\n"); + } + } else { + I("Do nothing\n"); + } + + return len; +} + +#if defined(HX_EXCP_RECOVERY) +static ssize_t himax_excp_cnt_read(char *buf, size_t len) +{ + size_t ret = 0; + + I("%s: enter, %d\n", __func__, __LINE__); + + ret += snprintf(buf_tmp + ret, len - ret, + "EB_cnt = %d, EC_cnt = %d, ED_cnt = %d\n", + hx_EB_event_flag, + hx_EC_event_flag, + hx_ED_event_flag); + + return ret; +} + +static ssize_t himax_excp_cnt_write(char *buf, size_t len) +{ + int i = 0; + + if (len >= 12) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + I("Clear EXCEPTION Flag\n"); + + if (buf[i] == '0') { + hx_EB_event_flag = 0; + hx_EC_event_flag = 0; + hx_ED_event_flag = 0; + } + + return len; +} + +#endif + +#if defined(HX_TP_PROC_GUEST_INFO) +static int printMat(char *temp_buf, size_t len, int max_size, + uint8_t *guest_str, int loc) +{ + int ret = loc; + int i; + + for (i = 0; i < max_size; i++) { + if ((i % 16) == 0 && i > 0) + ret += snprintf(temp_buf + ret, len - ret, "\n"); + + ret += snprintf(temp_buf + ret, len - ret, "0x%02X\t", + guest_str[i]); + } + return ret; +} + +static int printUnit(char *temp_buf, size_t len, int max_size, + char *info_item, uint8_t *guest_str, int loc) +{ + int ret = loc; + + ret += snprintf(temp_buf + ret, len - ret, "%s:\n", info_item); + ret = printMat(temp_buf, len, max_size, guest_str, ret); + ret += snprintf(temp_buf + ret, len - ret, "\n"); + return ret; +} + +static ssize_t himax_proc_guest_info_read(char *buf, size_t len) +{ + int ret = 0; + int j = 0; + int max_size = 128; + struct hx_guest_info *info = g_guest_info_data; + + I("guest info progress\n"); + + if (g_core_fp.guest_info_get_status()) { + ret += snprintf(buf_tmp + ret, len - ret, "Not Ready\n"); + goto END_FUNCTION; + } else { + if (info->g_guest_info_type == 1) { + for (j = 0; j < 3; j++) { + ret = printUnit(buf_tmp, len, max_size, + g_guest_info_item[j], + info->g_guest_str[j], ret); + I("str[%d] %s\n", j, + info->g_guest_str[j]); + } + ret = printUnit(buf_tmp, len, max_size, + g_guest_info_item[8], + info->g_guest_str[8], + ret); + + I("str[8] %s\n", + info->g_guest_str[8]); + + ret = printUnit(buf_tmp, len, max_size, + g_guest_info_item[9], + info->g_guest_str[9], + ret); + + I("str[9] %s\n", info->g_guest_str[9]); + } else if (info->g_guest_info_type == 0) { + for (j = 0; j < 10; j++) { + if (j == 3) + j = 8; + + ret += snprintf(buf_tmp + ret, + len - ret, "%s:\n", + g_guest_info_item[j]); + + if (info->g_guest_data_type[j] == 0) { + ret += snprintf(buf_tmp + ret, + len - ret, "%s", + info->g_guest_str_in_format[j]); + } else { + ret = printMat(buf_tmp, len, + info->g_guest_data_len[j], + info->g_guest_str_in_format[j], + ret); + } + ret += snprintf(buf_tmp + ret, len - ret, "\n"); + } + } + } + +END_FUNCTION: + return ret; +} + +static ssize_t himax_proc_guest_info_write(char *buf, size_t len) +{ + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + I("%s: buf = %s\n", __func__, buf); + if (buf[0] == 'r') { + I("%s,Test to get", __func__); + queue_work(private_ts->guest_info_wq, + &private_ts->guest_info_work); + } + return len; +} + +#endif + +static ssize_t himax_debug_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + int i = 0; + + if (!HX_PROC_SEND_FLAG) { + I("%s, Enter\n", __func__); + + memset(buf_tmp, 0, sizeof(buf_tmp)); + if (dbg_cmd_flag) { + if (dbg_func_ptr_r[dbg_cmd_flag]) + ret += dbg_func_ptr_r[dbg_cmd_flag](buf, len); + else + goto END_FUNC_R; + } + + if (debug_level_cmd == 't') { + if (!fw_update_going) { + if (fw_update_complete) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "FW Update Complete "); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "FW Update Fail "); + } else { + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "FW Update Ongoing "); + } + } else if (debug_level_cmd == 'h') { + if (handshaking_result == 0) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Handshaking Result = %d (MCU Running)\n", + handshaking_result); + else if (handshaking_result == 1) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Handshaking Result = %d (MCU Stop)\n", + handshaking_result); + else if (handshaking_result == 2) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Handshaking Result = %d (I2C Error)\n", + handshaking_result); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Handshaking Result = error\n"); + + } else if (debug_level_cmd == 'v') { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "FW_VER = 0x%2.2X\n", ic_data->vendor_fw_ver); + + if (private_ts->chip_cell_type == CHIP_IS_ON_CELL) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "CONFIG_VER = 0x%2.2X\n", + ic_data->vendor_config_ver); + else { + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "TOUCH_VER = 0x%2.2X\n", + ic_data->vendor_touch_cfg_ver); + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "DISPLAY_VER = 0x%2.2X\n", + ic_data->vendor_display_cfg_ver); + } + if (ic_data->vendor_cid_maj_ver < 0 + && ic_data->vendor_cid_min_ver < 0) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "CID_VER = NULL\n"); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "CID_VER = 0x%2.2X\n", + (ic_data->vendor_cid_maj_ver << 8 | + ic_data->vendor_cid_min_ver)); + + if (ic_data->vendor_panel_ver < 0) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "PANEL_VER = NULL\n"); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "PANEL_VER = 0x%2.2X\n", + ic_data->vendor_panel_ver); + if (private_ts->chip_cell_type == CHIP_IS_IN_CELL) { + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Cusomer = %s\n", + ic_data->vendor_cus_info); + + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Project = %s\n", + ic_data->vendor_proj_info); + } + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, "\n"); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "Himax Touch Driver Version:\n"); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "%s\n", HIMAX_DRIVER_VER); + } else if (debug_level_cmd == 'd') { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "Himax Touch IC Information :\n"); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "%s\n", private_ts->chip_name); + + switch (IC_CHECKSUM) { + case HX_TP_BIN_CHECKSUM_SW: + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "IC Checksum : SW\n"); + break; + + case HX_TP_BIN_CHECKSUM_HW: + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "IC Checksum : HW\n"); + break; + + case HX_TP_BIN_CHECKSUM_CRC: + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "IC Checksum : CRC\n"); + break; + + default: + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "IC Checksum error.\n"); + } + + if (ic_data->HX_INT_IS_EDGE) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Driver register Interrupt : EDGE TIRGGER\n"); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Driver register Interrupt : LEVEL TRIGGER\n"); + + if (private_ts->protocol_type == PROTOCOL_TYPE_A) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Protocol : TYPE_A\n"); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Protocol : TYPE_B\n"); + + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "RX Num : %d\n", ic_data->HX_RX_NUM); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "TX Num : %d\n", ic_data->HX_TX_NUM); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "BT Num : %d\n", ic_data->HX_BT_NUM); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "X Resolution : %d\n", ic_data->HX_X_RES); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "Y Resolution : %d\n", ic_data->HX_Y_RES); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "Max Point : %d\n", ic_data->HX_MAX_PT); + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "XY reverse : %d\n", ic_data->HX_XY_REVERSE); +#if defined(HX_TP_PROC_2T2R) + if (Is_2T2R) { + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "2T2R panel\n"); + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "RX Num_2 : %d\n", HX_RX_NUM_2); + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "TX Num_2 : %d\n", HX_TX_NUM_2); + } +#endif + } else if (debug_level_cmd == 'i') { + if (g_core_fp.fp_read_i2c_status()) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "I2C communication is bad.\n"); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "I2C communication is good.\n"); + } else if (debug_level_cmd == 'n') { + /* Edgd = 1, Level = 0 */ + if (g_core_fp.fp_read_ic_trigger_type() == 1) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "IC Interrupt type is edge trigger.\n"); + else if (g_core_fp.fp_read_ic_trigger_type() == 0) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "IC Interrupt type is level trigger.\n"); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Unkown IC trigger type.\n"); + + if (ic_data->HX_INT_IS_EDGE) + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Driver register Interrupt : EDGE TIRGGER\n"); + else + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "Driver register Interrupt : LEVEL TRIGGER\n"); + } else if (debug_level_cmd == 'l') { + ret += snprintf(buf_tmp + ret, sizeof(buf_tmp) - ret, + "LotID : "); + for (i = 0; i < 13; i++) { + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, + "%02X", ic_data->vendor_ic_id[i]); + } + ret += snprintf(buf_tmp + ret, + sizeof(buf_tmp) - ret, "\n"); + } + +END_FUNC_R: + if (copy_to_user(buf, buf_tmp, (len > BUF_SIZE)?BUF_SIZE:len)) + I("%s,here:%d\n", __func__, __LINE__); + + HX_PROC_SEND_FLAG = 1; + } else { + HX_PROC_SEND_FLAG = 0; + } + + return ret; +} + +static ssize_t himax_debug_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char fileName[128]; + char buf[80] = "\0"; + int result = 0; +#if !defined(HX_ZERO_FLASH) + int fw_type = 0; + const struct firmware *fw = NULL; +#endif + + char *str_ptr = NULL; + int str_len = 0; + int i = 0; + + if (len >= 80) { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + str_len = len; + buf[str_len - 1] = 0;/*remove \n*/ + + while (dbg_cmd_str[i]) { + str_ptr = strnstr(buf, dbg_cmd_str[i], len); + if (str_ptr) { + str_len = strlen(dbg_cmd_str[i]); + dbg_cmd_flag = i + 1; + debug_level_cmd = 0; + I("Cmd is correct :%s, dbg_cmd = %d\n", + str_ptr, dbg_cmd_flag); + break; + } + i++; + } + if (!str_ptr) { + I("Cmd is not correct\n"); + dbg_cmd_flag = 0; + } + + if (buf[str_len] == ',') { + dbg_cmd_par = buf + str_len + 1; + if (dbg_func_ptr_w[dbg_cmd_flag]) + /* 2 => '/n' + ','*/ + dbg_func_ptr_w[dbg_cmd_flag](dbg_cmd_par, + len - str_len - 2); + + I("string of paremeter is %s, dbg_cmd_par = %s\n", + buf + str_len + 1, dbg_cmd_par); + } else { + I("No paremeter of this cmd\n"); + } + + if (dbg_cmd_flag) + return len; + + if (buf[0] == 'v') { /* firmware version */ + debug_level_cmd = buf[0]; + g_core_fp.fp_read_FW_ver(); +#if 0 + himax_int_enable(0); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#endif + debug_level_cmd = buf[0]; + g_core_fp.fp_read_FW_ver(); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(true, false); +#else + g_core_fp.fp_system_reset(); +#endif +#if defined(HX_ZERO_FLASH) + if (g_core_fp.fp_0f_reload_to_active) + g_core_fp.fp_0f_reload_to_active(); +#endif + himax_int_enable(1); + /* himax_check_chip_version(); */ +#endif + return len; + } else if (buf[0] == 'd') { /* ic information */ + debug_level_cmd = buf[0]; + return len; + } else if (buf[0] == 't') { + if (buf[1] == 's' + && buf[2] == 'd' + && buf[3] == 'b' + && buf[4] == 'g') { + if (buf[5] == '1') { + I("Open Ts Debug!\n"); + g_ts_dbg = 1; + } else if (buf[5] == '0') { + I("Close Ts Debug!\n"); + g_ts_dbg = 0; + } else { + E("Parameter fault for ts debug\n"); + } + goto ENDFUCTION; + } + himax_int_enable(0); + debug_level_cmd = buf[0]; + fw_update_complete = false; + fw_update_going = true; + memset(fileName, 0, 128); + /* parse the file name */ + snprintf(fileName, len - 2, "%s", &buf[2]); + +#if defined(HX_ZERO_FLASH) + I("NOW Running Zero flash update!\n"); + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + result = g_core_fp.fp_0f_op_file_dirly(fileName); + if (result) { + fw_update_complete = false; + I("Zero flash update fail!\n"); + goto ENDFUCTION; + } else { + fw_update_complete = true; + I("Zero flash update complete!\n"); + } + goto firmware_upgrade_done; +#else + I("NOW Running common flow update!\n"); + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + result = request_firmware(&fw, fileName, private_ts->dev); + + if (result < 0) { + I("fail to request_firmware fwpath: %s (ret:%d)\n", + fileName, result); + return result; + } + + I("%s: FW image: %02X, %02X, %02X, %02X\n", __func__, + fw->data[0], fw->data[1], + fw->data[2], fw->data[3]); + fw_type = (fw->size) / 1024; + /* start to upgrade */ + himax_int_enable(0); + I("Now FW size is : %dk\n", fw_type); + + switch (fw_type) { + case 32: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 60: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 64: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 124: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + case 128: + if (g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k( + (unsigned char *)fw->data, fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); + fw_update_complete = false; + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); + fw_update_complete = true; + } + break; + + default: + E("%s: Flash command fail: %d\n", __func__, __LINE__); + fw_update_complete = false; + break; + } + release_firmware(fw); + goto firmware_upgrade_done; +#endif + } else if (buf[0] == 'i' && buf[1] == '2' && buf[2] == 'c') { + /* i2c communication */ + debug_level_cmd = 'i'; + return len; + } else if (buf[0] == 'i' && buf[1] == 'n' && buf[2] == 't') { + /* INT trigger */ + debug_level_cmd = 'n'; + return len; + } else if (buf[0] == 'l' && buf[1] == 'o' && buf[2] == 't') { + debug_level_cmd = buf[0]; + g_core_fp.fp_sense_off(true); + g_core_fp.fp_ic_id_read(); + g_core_fp.fp_sense_on(0x01); + return len; + } + /* others,do nothing */ + debug_level_cmd = 0; + return len; + +firmware_upgrade_done: + fw_update_going = false; + g_core_fp.fp_reload_disable(0); + g_core_fp.fp_power_on_init(); + g_core_fp.fp_read_FW_ver(); + g_core_fp.fp_touch_information(); + g_core_fp.fp_calc_touch_data_size(); + + himax_int_enable(1); + /* todo himax_chip->tp_firmware_upgrade_proceed = 0; + * todo himax_chip->suspend_state = 0; + * todo enable_irq(himax_chip->irq); + */ +ENDFUCTION: + return len; +} + +static const struct file_operations himax_proc_debug_ops = { + .owner = THIS_MODULE, + .read = himax_debug_read, + .write = himax_debug_write, +}; + +static void himax_himax_data_init(void) +{ + debug_data->fp_ts_dbg_func = himax_ts_dbg_func; + debug_data->fp_set_diag_cmd = himax_set_diag_cmd; + debug_data->flash_dump_going = false; + debug_data->is_checking_irq = false; +} + +static void himax_ts_flash_work_func(struct work_struct *work) +{ + himax_ts_flash_func(); +} +#if defined(HX_TP_PROC_GUEST_INFO) +static void himax_ts_guest_info_work_func(struct work_struct *work) +{ + g_core_fp.read_guest_info(); +} +#endif + +static void himax_ts_diag_work_func(struct work_struct *work) +{ + himax_ts_diag_func(); +} + +void dbg_func_ptr_init(void) +{ + /*debug function ptr init*/ + dbg_func_ptr_r[1] = himax_crc_test_read; + dbg_func_ptr_r[2] = himax_proc_FW_debug_read; + dbg_func_ptr_r[3] = himax_attn_read; + dbg_func_ptr_r[4] = himax_layout_read; + dbg_func_ptr_w[4] = himax_layout_write; + dbg_func_ptr_r[5] = himax_proc_DD_debug_read; + dbg_func_ptr_w[5] = himax_proc_DD_debug_write; +#if defined(HX_EXCP_RECOVERY) + dbg_func_ptr_r[6] = himax_excp_cnt_read; + dbg_func_ptr_w[6] = himax_excp_cnt_write; +#endif + dbg_func_ptr_w[7] = himax_sense_on_off_write; + dbg_func_ptr_r[8] = himax_debug_level_read; + dbg_func_ptr_w[8] = himax_debug_level_write; +#if defined(HX_TP_PROC_GUEST_INFO) + dbg_func_ptr_r[9] = himax_proc_guest_info_read; + dbg_func_ptr_w[9] = himax_proc_guest_info_write; +#endif + dbg_func_ptr_r[10] = himax_int_en_read; + dbg_func_ptr_w[10] = himax_int_en_write; + dbg_func_ptr_w[11] = himax_proc_register_write; + dbg_func_ptr_r[11] = himax_proc_register_read; + dbg_func_ptr_w[12] = himax_reset_write; + dbg_func_ptr_w[13] = himax_diag_arrange_write; + dbg_func_ptr_w[14] = himax_diag_cmd_write; +} + +int himax_touch_proc_init(void) +{ + himax_proc_diag_dir = proc_mkdir(HIMAX_PROC_DIAG_FOLDER, + himax_touch_proc_dir); + + if (himax_proc_diag_dir == NULL) { + E(" %s: himax_proc_diag_dir file create failed!\n", __func__); + return -ENOMEM; + } + + himax_proc_stack_file = proc_create(HIMAX_PROC_STACK_FILE, 0444, + himax_proc_diag_dir, &himax_proc_stack_ops); + if (himax_proc_stack_file == NULL) { + E(" %s: proc stack file create failed!\n", __func__); + goto fail_2_1; + } + + himax_proc_delta_file = proc_create(HIMAX_PROC_DELTA_FILE, 0444, + himax_proc_diag_dir, &himax_proc_delta_ops); + if (himax_proc_delta_file == NULL) { + E(" %s: proc delta file create failed!\n", __func__); + goto fail_2_2; + } + + himax_proc_dc_file = proc_create(HIMAX_PROC_DC_FILE, 0444, + himax_proc_diag_dir, &himax_proc_dc_ops); + if (himax_proc_dc_file == NULL) { + E(" %s: proc dc file create failed!\n", __func__); + goto fail_2_3; + } + + himax_proc_baseline_file = proc_create(HIMAX_PROC_BASELINE_FILE, 0444, + himax_proc_diag_dir, &himax_proc_baseline_ops); + if (himax_proc_baseline_file == NULL) { + E(" %s: proc baseline file create failed!\n", __func__); + goto fail_2_4; + } + + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, + 0644, himax_touch_proc_dir, + &himax_proc_debug_ops); + if (himax_proc_debug_file == NULL) { + E(" %s: proc debug file create failed!\n", __func__); + goto fail_3; + } + dbg_func_ptr_init(); + + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, + 0644, himax_touch_proc_dir, + &himax_proc_flash_ops); + if (himax_proc_flash_dump_file == NULL) { + E(" %s: proc flash dump file create failed!\n", __func__); + goto fail_4; + } + + if (!ic_data->HX_PEN_FUNC) + goto skip_pen_operation; + + himax_proc_pen_pos_file = proc_create(HIMAX_PROC_PEN_POS_FILE, + 0644, + himax_touch_proc_dir, &himax_proc_pen_pos_ops); + if (himax_proc_pen_pos_file == NULL) { + E(" %s: proc CRC test file create failed!\n", __func__); + goto fail_5; + } +skip_pen_operation: + + return 0; + + /* remove_proc_entry(HIMAX_PROC_PEN_POS_FILE, himax_touch_proc_dir); */ +fail_5: remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +fail_4: remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +fail_3: remove_proc_entry(HIMAX_PROC_BASELINE_FILE, himax_proc_diag_dir); +fail_2_4: remove_proc_entry(HIMAX_PROC_DC_FILE, himax_proc_diag_dir); +fail_2_3: remove_proc_entry(HIMAX_PROC_DELTA_FILE, himax_proc_diag_dir); +fail_2_2: remove_proc_entry(HIMAX_PROC_STACK_FILE, himax_proc_diag_dir); +fail_2_1: + return -ENOMEM; +} + +void himax_touch_proc_deinit(void) +{ + if (ic_data->HX_PEN_FUNC) + remove_proc_entry(HIMAX_PROC_PEN_POS_FILE, + himax_touch_proc_dir); + + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_BASELINE_FILE, himax_proc_diag_dir); + remove_proc_entry(HIMAX_PROC_DC_FILE, himax_proc_diag_dir); + remove_proc_entry(HIMAX_PROC_DELTA_FILE, himax_proc_diag_dir); + remove_proc_entry(HIMAX_PROC_STACK_FILE, himax_proc_diag_dir); +} + +int himax_debug_init(void) +{ + struct himax_ts_data *ts = private_ts; + + I("%s:Enter\n", __func__); + + if (ts == NULL) { + E("%s: ts struct is NULL\n", __func__); + return -EPROBE_DEFER; + } + + reg_read_data = kzalloc(128 * sizeof(uint8_t), GFP_KERNEL); + if (reg_read_data == NULL) { + E("%s: reg_read_data allocate failed\n", __func__); + goto err_alloc_reg_read_data_fail; + } + + debug_data = kzalloc(sizeof(struct himax_debug), GFP_KERNEL); + if (debug_data == NULL) { /*Allocate debug data space*/ + E("%s: debug_data allocate failed\n", __func__); + goto err_alloc_debug_data_fail; + } + + himax_himax_data_init(); + + ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); + + if (!ts->flash_wq) { + E("%s: create flash workqueue failed\n", __func__); + goto err_create_flash_dump_wq_failed; + } + + INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); + + g_flash_progress = START; + setFlashBuffer(); + if (flash_buffer == NULL) { + E("%s: flash buffer allocate fail failed\n", __func__); + goto err_flash_buf_alloc_failed; + } + +#if defined(HX_TP_PROC_GUEST_INFO) + + if (g_guest_info_data == NULL) { + g_guest_info_data = kzalloc(sizeof(struct hx_guest_info), + GFP_KERNEL); + if (g_guest_info_data == NULL) { + E("%s: flash buffer allocate fail failed\n", __func__); + goto err_guest_info_alloc_failed; + } + g_guest_info_data->g_guest_info_ongoing = 0; + g_guest_info_data->g_guest_info_type = 0; + } + + ts->guest_info_wq = + create_singlethread_workqueue("himax_guest_info_wq"); + if (!ts->guest_info_wq) { + E("%s: create guest info workqueue failed\n", __func__); + goto err_create_guest_info_wq_failed; + } + INIT_WORK(&ts->guest_info_work, himax_ts_guest_info_work_func); +#endif + + ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); + + if (!ts->himax_diag_wq) { + E("%s: create diag workqueue failed\n", __func__); + goto err_create_diag_wq_failed; + } + + INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func); + + setSelfBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getSelfBuffer() == NULL) { + E("%s: self buffer allocate failed\n", __func__); + goto err_self_buf_alloc_failed; + } + + setSelfNewBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getSelfNewBuffer() == NULL) { + E("%s: self new buffer allocate failed\n", __func__); + goto err_self_new_alloc_failed; + } + + setSelfOldBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getSelfOldBuffer() == NULL) { + E("%s: self old buffer allocate failed\n", __func__); + goto err_self_old_alloc_failed; + } + + setMutualBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getMutualBuffer() == NULL) { + E("%s: mutual buffer allocate failed\n", __func__); + goto err_mut_buf_alloc_failed; + } + + setMutualNewBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getMutualNewBuffer() == NULL) { + E("%s: mutual new buffer allocate failed\n", __func__); + goto err_mut_new_alloc_failed; + } + + setMutualOldBuffer(ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + if (getMutualOldBuffer() == NULL) { + E("%s: mutual old buffer allocate failed\n", __func__); + goto err_mut_old_alloc_failed; + } + +#if defined(HX_TP_PROC_2T2R) + + if (Is_2T2R) { + setMutualBuffer_2(ic_data->HX_RX_NUM_2, ic_data->HX_TX_NUM_2); + + if (getMutualBuffer_2() == NULL) { + E("%s: mutual buffer 2 allocate failed\n", __func__); + goto err_mut_buf2_alloc_failed; + } + } +#endif + + if (himax_touch_proc_init()) + goto err_proc_init_failed; + + return 0; + +err_proc_init_failed: +#if defined(HX_TP_PROC_2T2R) + kfree(diag_mutual_2); + diag_mutual_2 = NULL; +err_mut_buf2_alloc_failed: +#endif + kfree(diag_mutual_old); + diag_mutual_old = NULL; +err_mut_old_alloc_failed: + kfree(diag_mutual_new); + diag_mutual_new = NULL; +err_mut_new_alloc_failed: + kfree(diag_mutual); + diag_mutual = NULL; +err_mut_buf_alloc_failed: + kfree(diag_self_old); + diag_self_old = NULL; +err_self_old_alloc_failed: + kfree(diag_self_new); + diag_self_new = NULL; +err_self_new_alloc_failed: + kfree(diag_self); + diag_self = NULL; +err_self_buf_alloc_failed: + cancel_delayed_work_sync(&ts->himax_diag_delay_wrok); + destroy_workqueue(ts->himax_diag_wq); +err_create_diag_wq_failed: + +#if defined(HX_TP_PROC_GUEST_INFO) + destroy_workqueue(ts->guest_info_wq); +err_create_guest_info_wq_failed: + if (g_guest_info_data != NULL) { + kfree(g_guest_info_data); + g_guest_info_data = NULL; + } +err_guest_info_alloc_failed: +#endif + kfree(flash_buffer); + flash_buffer = NULL; +err_flash_buf_alloc_failed: + destroy_workqueue(ts->flash_wq); +err_create_flash_dump_wq_failed: + kfree(debug_data); + debug_data = NULL; +err_alloc_debug_data_fail: + kfree(reg_read_data); + reg_read_data = NULL; +err_alloc_reg_read_data_fail: + + return -ENOMEM; +} +EXPORT_SYMBOL(himax_debug_init); + +int himax_debug_remove(void) +{ + struct himax_ts_data *ts = private_ts; + + himax_touch_proc_deinit(); + + cancel_delayed_work_sync(&ts->himax_diag_delay_wrok); +#if defined(HX_TP_PROC_GUEST_INFO) + destroy_workqueue(ts->guest_info_wq); + if (g_guest_info_data != NULL) + kfree(g_guest_info_data); +#endif + destroy_workqueue(ts->himax_diag_wq); + destroy_workqueue(ts->flash_wq); + + if (debug_data != NULL) + kfree(debug_data); + if (reg_read_data != NULL) + kfree(reg_read_data); + + return 0; +} +EXPORT_SYMBOL(himax_debug_remove); + diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..1de7db339323e0e5c7dcd344783181f9c2f90099 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for debug nodes + * + * Copyright (C) 2019 Himax Corporation. + * + * 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 H_HIMAX_DEBUG +#define H_HIMAX_DEBUG + +#include "himax_platform.h" +#include "himax_common.h" + + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +extern int hx_EB_event_flag; +extern int hx_EC_event_flag; +extern int hx_ED_event_flag; +#endif + +#define HIMAX_PROC_PEN_POS_FILE "pen_pos" + +int himax_touch_proc_init(void); +void himax_touch_proc_deinit(void); +extern int himax_int_en_set(void); + +extern uint8_t byte_length; +extern uint8_t register_command[4]; +extern uint8_t cfg_flag; + +#define HIMAX_PROC_DIAG_FOLDER "diag" +struct proc_dir_entry *himax_proc_diag_dir; +#define HIMAX_PROC_STACK_FILE "stack" +extern struct proc_dir_entry *himax_proc_stack_file; +#define HIMAX_PROC_DELTA_FILE "delta_s" +extern struct proc_dir_entry *himax_proc_delta_file; +#define HIMAX_PROC_DC_FILE "dc_s" +extern struct proc_dir_entry *himax_proc_dc_file; +#define HIMAX_PROC_BASELINE_FILE "baseline_s" +extern struct proc_dir_entry *himax_proc_baseline_file; + +#if defined(HX_TP_PROC_2T2R) +extern uint32_t *diag_mutual_2; + +int32_t *getMutualBuffer_2(void); +void setMutualBuffer_2(uint8_t x_num, uint8_t y_num); +#endif +extern int32_t *diag_mutual; +extern int32_t *diag_mutual_new; +extern int32_t *diag_mutual_old; +extern uint8_t diag_max_cnt; +extern uint8_t hx_state_info[2]; +extern uint8_t diag_coor[128]; +extern int32_t *diag_self; +extern int32_t *diag_self_new; +extern int32_t *diag_self_old; +int32_t *getMutualBuffer(void); +int32_t *getMutualNewBuffer(void); +int32_t *getMutualOldBuffer(void); +int32_t *getSelfBuffer(void); +int32_t *getSelfNewBuffer(void); +int32_t *getSelfOldBuffer(void); +void setMutualBuffer(uint8_t x_num, uint8_t y_num); +void setMutualNewBuffer(uint8_t x_num, uint8_t y_num); +void setMutualOldBuffer(uint8_t x_num, uint8_t y_num); +uint8_t process_type; +uint8_t mode_flag; +uint8_t overflow; + +#define HIMAX_PROC_DEBUG_FILE "debug" +extern struct proc_dir_entry *himax_proc_debug_file; +extern bool fw_update_complete; +extern int handshaking_result; +extern unsigned char debug_level_cmd; +extern uint8_t cmd_set[8]; +extern uint8_t mutual_set_flag; + +#define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" +extern struct proc_dir_entry *himax_proc_flash_dump_file; +extern int Flash_Size; +extern uint8_t *flash_buffer; +extern uint8_t g_flash_cmd; +extern uint8_t g_flash_progress; +extern bool g_flash_dump_rst; /*Fail = 0, Pass = 1*/ +void setFlashBuffer(void); + +enum flash_dump_prog { + START, + ONGOING, + FINISHED, +}; + +extern uint32_t **raw_data_array; +extern uint8_t X_NUM4; +extern uint8_t Y_NUM; +extern uint8_t sel_type; + +/* Moved from debug.c */ +extern struct himax_debug *debug_data; +extern unsigned char IC_CHECKSUM; +extern int i2c_error_count; +extern struct proc_dir_entry *himax_touch_proc_dir; + +#if defined(HX_TP_PROC_GUEST_INFO) +extern struct hx_guest_info *g_guest_info_data; +extern char *g_guest_info_item[]; +#endif + +extern int himax_input_register(struct himax_ts_data *ts); +#if defined(HX_TP_PROC_2T2R) +extern bool Is_2T2R; +#endif + +#if defined(HX_RST_PIN_FUNC) +extern void himax_ic_reset(uint8_t loadconfig, uint8_t int_off); +#endif + +extern uint8_t HX_PROC_SEND_FLAG; +extern struct himax_target_report_data *g_target_report_data; +extern struct himax_report_data *hx_touch_data; +extern int g_ts_dbg; + +/* Moved from debug.c end */ +#define BUF_SIZE 1024 +#define CMD_NUM 15 +char *dbg_cmd_str[] = { + "crc_test", + "fw_debug", + "attn", + "layout", + "dd_debug", + "excp_cnt", + "senseonoff", + "debug_level", + "guest_info", + "int_en", + "register", + "reset", + "diag_arr", + "diag", + NULL +}; + +int dbg_cmd_flag; +char *dbg_cmd_par; +ssize_t (*dbg_func_ptr_r[CMD_NUM])(char *buf, size_t len); +ssize_t (*dbg_func_ptr_w[CMD_NUM])(char *buf, size_t len); +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.c b/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.c new file mode 100644 index 0000000000000000000000000000000000000000..971a4c16cab6077880d7799b6ba032f3afe581b2 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.c @@ -0,0 +1,592 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for HX83112 chipset + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +#include "himax_ic_HX83112.h" +#include "himax_modular.h" + +static void hx83112_chip_init(void) +{ + (*kp_private_ts)->chip_cell_type = CHIP_IS_IN_CELL; + I("%s:IC cell type = %d\n", __func__, + (*kp_private_ts)->chip_cell_type); + (*kp_IC_CHECKSUM) = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + (*kp_FW_VER_MAJ_FLASH_ADDR) = 49157; /*0x00C005*/ + (*kp_FW_VER_MIN_FLASH_ADDR) = 49158; /*0x00C006*/ + (*kp_CFG_VER_MAJ_FLASH_ADDR) = 49408; /*0x00C100*/ + (*kp_CFG_VER_MIN_FLASH_ADDR) = 49409; /*0x00C101*/ + (*kp_CID_VER_MAJ_FLASH_ADDR) = 49154; /*0x00C002*/ + (*kp_CID_VER_MIN_FLASH_ADDR) = 49155; /*0x00C003*/ + (*kp_CFG_TABLE_FLASH_ADDR) = 0x10000; +} + +static bool hx83112_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + if (cnt == 0 + || (tmp_data[0] != 0xA5 + && tmp_data[0] != 0x00 + && tmp_data[0] != 0x87)) + kp_g_core_fp->fp_register_write( + (*kp_pfw_op)->addr_ctrl_fw_isr, + DATA_LEN_4, + (*kp_pfw_op)->data_fw_stop, + 0); + + /*msleep(20);*/ + usleep_range(10000, 10001); + /* check fw status */ + kp_g_core_fp->fp_register_read( + (*kp_pic_op)->addr_cs_central_state, + ADDR_LEN_4, tmp_data, 0); + + if (tmp_data[0] != 0x05) { + I("%s: Do not need wait FW, Status = 0x%02X!\n", + __func__, tmp_data[0]); + break; + } + + kp_g_core_fp->fp_register_read((*kp_pfw_op)->addr_ctrl_fw_isr, + 4, tmp_data, false); + I("%s: cnt = %d, data[0] = 0x%02X!\n", __func__, + cnt, tmp_data[0]); + } while (tmp_data[0] != 0x87 && (++cnt < 10) && check_en == true); + + cnt = 0; + + do { + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = (*kp_pic_op)->data_i2c_psw_lb[0]; + + ret = kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_lb[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /** + * I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = (*kp_pic_op)->data_i2c_psw_ub[0]; + + ret = kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_ub[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /** + * Check enter_save_mode + */ + kp_g_core_fp->fp_register_read( + (*kp_pic_op)->addr_cs_central_state, + ADDR_LEN_4, + tmp_data, + 0); + I("%s: Check enter_save_mode data[0]=%X\n", __func__, + tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + /** + * Reset TCON + */ + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_tcon_on_rst, + DATA_LEN_4, + (*kp_pic_op)->data_rst, + 0); + usleep_range(1000, 1001); + tmp_data[3] = (*kp_pic_op)->data_rst[3]; + tmp_data[2] = (*kp_pic_op)->data_rst[2]; + tmp_data[1] = (*kp_pic_op)->data_rst[1]; + tmp_data[0] = (*kp_pic_op)->data_rst[0] | 0x01; + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_tcon_on_rst, + DATA_LEN_4, + tmp_data, + 0); + /** + * Reset ADC + */ + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_adc_on_rst, + DATA_LEN_4, + (*kp_pic_op)->data_rst, + 0); + usleep_range(1000, 1001); + tmp_data[3] = (*kp_pic_op)->data_rst[3]; + tmp_data[2] = (*kp_pic_op)->data_rst[2]; + tmp_data[1] = (*kp_pic_op)->data_rst[1]; + tmp_data[0] = (*kp_pic_op)->data_rst[0] | 0x01; + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_adc_on_rst, + DATA_LEN_4, + tmp_data, + 0); + goto SUCCEED; + } else { + /*msleep(10);*/ +#if defined(HX_RST_PIN_FUNC) + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_g_core_fp->fp_system_reset(); +#endif + } + } while (cnt++ < 5); + + return false; +SUCCEED: + return true; +} + +static bool hx83112ab_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + if (cnt == 0 + || (tmp_data[0] != 0xA5 + && tmp_data[0] != 0x00 + && tmp_data[0] != 0x87)) + kp_g_core_fp->fp_register_write( + (*kp_pfw_op)->addr_ctrl_fw_isr, + DATA_LEN_4, + (*kp_pfw_op)->data_fw_stop, + 0); + + /*msleep(20);*/ + usleep_range(10000, 10001); + /* check fw status */ + kp_g_core_fp->fp_register_read( + (*kp_pic_op)->addr_cs_central_state, + ADDR_LEN_4, tmp_data, 0); + + if (tmp_data[0] != 0x05) { + I("%s: Do not need wait FW, Status = 0x%02X!\n", + __func__, tmp_data[0]); + break; + } + + kp_g_core_fp->fp_register_read((*kp_pfw_op)->addr_ctrl_fw_isr, + 4, tmp_data, false); + I("%s: cnt = %d, data[0] = 0x%02X!\n", __func__, + cnt, tmp_data[0]); + } while (tmp_data[0] != 0x87 && (++cnt < 10) && check_en == true); + + cnt = 0; + + do { + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = (*kp_pic_op)->data_i2c_psw_lb[0]; + + ret = kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_lb[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /** + * I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = (*kp_pic_op)->data_i2c_psw_ub[0]; + + ret = kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_ub[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x00 + */ + tmp_data[0] = 0x00; + + ret = kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_lb[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = (*kp_pic_op)->data_i2c_psw_lb[0]; + + ret = kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_lb[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /** + * I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = (*kp_pic_op)->data_i2c_psw_ub[0]; + + ret = kp_himax_bus_write((*kp_pic_op)->adr_i2c_psw_ub[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + /** + * Check enter_save_mode + */ + kp_g_core_fp->fp_register_read( + (*kp_pic_op)->addr_cs_central_state, + ADDR_LEN_4, + tmp_data, + 0); + I("%s: Check enter_save_mode data[0]=%X\n", __func__, + tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + /** + * Reset TCON + */ + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_tcon_on_rst, + DATA_LEN_4, + (*kp_pic_op)->data_rst, + 0); + usleep_range(1000, 1001); + tmp_data[3] = (*kp_pic_op)->data_rst[3]; + tmp_data[2] = (*kp_pic_op)->data_rst[2]; + tmp_data[1] = (*kp_pic_op)->data_rst[1]; + tmp_data[0] = (*kp_pic_op)->data_rst[0] | 0x01; + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_tcon_on_rst, + DATA_LEN_4, + tmp_data, + 0); + /** + * Reset ADC + */ + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_adc_on_rst, + DATA_LEN_4, + (*kp_pic_op)->data_rst, + 0); + usleep_range(1000, 1001); + tmp_data[3] = (*kp_pic_op)->data_rst[3]; + tmp_data[2] = (*kp_pic_op)->data_rst[2]; + tmp_data[1] = (*kp_pic_op)->data_rst[1]; + tmp_data[0] = (*kp_pic_op)->data_rst[0] | 0x01; + kp_g_core_fp->fp_register_write( + (*kp_pic_op)->addr_adc_on_rst, + DATA_LEN_4, + tmp_data, + 0); + goto SUCCEED; + } else { + /*msleep(10);*/ +#if defined(HX_RST_PIN_FUNC) + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_g_core_fp->fp_system_reset(); +#endif + } + } while (cnt++ < 5); + + return false; +SUCCEED: + return true; +} + +#if defined(HX_ZERO_FLASH) +static void himax_hx83112f_reload_to_active(void) +{ + uint8_t addr[DATA_LEN_4] = {0}; + uint8_t data[DATA_LEN_4] = {0}; + uint8_t retry_cnt = 0; + + addr[3] = 0x90; + addr[2] = 0x00; + addr[1] = 0x00; + addr[0] = 0x48; + + do { + data[3] = 0x00; + data[2] = 0x00; + data[1] = 0x00; + data[0] = 0xEC; + kp_g_core_fp->fp_register_write(addr, DATA_LEN_4, data, 0); + usleep_range(1000, 1100); + kp_g_core_fp->fp_register_read(addr, DATA_LEN_4, data, 0); + I("%s: data[1]=%d, data[0]=%d, retry_cnt=%d\n", __func__, + data[1], data[0], retry_cnt); + retry_cnt++; + } while ((data[1] != 0x01 + || data[0] != 0xEC) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +static void himax_hx83112f_resume_ic_action(void) +{ +#if !defined(HX_RESUME_HW_RESET) + himax_hx83112f_reload_to_active(); +#endif +} + +static void himax_hx83112f_sense_on(uint8_t FlashMode) +{ + uint8_t tmp_data[DATA_LEN_4]; + int retry = 0; + int ret = 0; + + I("Enter %s\n", __func__); + (*kp_private_ts)->notouch_frame = (*kp_private_ts)->ic_notouch_frame; + kp_g_core_fp->fp_interface_on(); + kp_g_core_fp->fp_register_write((*kp_pfw_op)->addr_ctrl_fw_isr, + sizeof((*kp_pfw_op)->data_clear), (*kp_pfw_op)->data_clear, 0); + /*msleep(20);*/ + usleep_range(10000, 10001); + if (!FlashMode) { +#if defined(HX_RST_PIN_FUNC) + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_g_core_fp->fp_system_reset(); +#endif + } else { + do { + kp_g_core_fp->fp_register_read( + (*kp_pfw_op)->addr_flag_reset_event, + DATA_LEN_4, tmp_data, 0); + I("%s:Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + } while ((tmp_data[1] != 0x01 + || tmp_data[0] != 0x00) + && retry++ < 5); + + if (retry >= 5) { + E("%s: Fail:\n", __func__); +#if defined(HX_RST_PIN_FUNC) + kp_g_core_fp->fp_ic_reset(false, false); +#else + kp_g_core_fp->fp_system_reset(); +#endif + } else { + I("%s:OK and Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + /* reset code*/ + tmp_data[0] = 0x00; + + ret = kp_himax_bus_write( + (*kp_pic_op)->adr_i2c_psw_lb[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) + E("%s: i2c access fail!\n", __func__); + + ret = kp_himax_bus_write( + (*kp_pic_op)->adr_i2c_psw_ub[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) + E("%s: i2c access fail!\n", __func__); + } + } + himax_hx83112f_reload_to_active(); +} + +#endif + +static void hx83112_func_re_init(void) +{ + kp_g_core_fp->fp_sense_off = hx83112_sense_off; + kp_g_core_fp->fp_chip_init = hx83112_chip_init; +} + +static void hx83112_reg_re_init(void) +{ + (*kp_private_ts)->ic_notouch_frame = hx83112_notouch_frame; +} + +static void hx83112f_reg_re_init(void) +{ + kp_himax_parse_assign_cmd(hx83112f_fw_addr_raw_out_sel, + (*kp_pfw_op)->addr_raw_out_sel, + sizeof((*kp_pfw_op)->addr_raw_out_sel)); + (*kp_private_ts)->ic_notouch_frame = hx83112f_notouch_frame; +} + +static void hx83112f_func_re_init(void) +{ +#if defined(HX_ZERO_FLASH) + kp_g_core_fp->fp_resume_ic_action = himax_hx83112f_resume_ic_action; + kp_g_core_fp->fp_sense_on = himax_hx83112f_sense_on; + kp_g_core_fp->fp_0f_reload_to_active = himax_hx83112f_reload_to_active; +#endif +} + +static void hx83112ab_func_re_init(void) +{ + kp_g_core_fp->fp_sense_off = hx83112ab_sense_off; +} + +static bool hx83112_chip_detect(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + bool ret_data = false; + int ret = 0; + int i = 0; + + if (himax_ic_setup_external_symbols()) + return false; + + ret = kp_himax_mcu_in_cmd_struct_init(); + if (ret < 0) { + ret_data = false; + E("%s:cmd_struct_init Fail:\n", __func__); + return ret_data; + } + + kp_himax_mcu_in_cmd_init(); + + hx83112_reg_re_init(); + hx83112_func_re_init(); + + ret = kp_himax_bus_read((*kp_pic_op)->addr_conti[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + if (kp_g_core_fp->fp_sense_off(false) == false) { + ret_data = false; + E("%s:fp_sense_off Fail:\n", __func__); + return ret_data; + } + for (i = 0; i < 5; i++) { + ret = kp_g_core_fp->fp_register_read( + (*kp_pfw_op)->addr_icid_addr, + DATA_LEN_4, + tmp_data, + false); + + if (ret != 0) { + ret_data = false; + E("%s:fp_register_read Fail:\n", __func__); + return ret_data; + } + I("%s:Read driver IC ID = %X, %X, %X\n", __func__, + tmp_data[3], tmp_data[2], tmp_data[1]); + + if ((tmp_data[3] == 0x83) + && (tmp_data[2] == 0x11) + && ((tmp_data[1] == 0x2a) + || (tmp_data[1] == 0x2b) + || (tmp_data[1] == 0x2e) + || (tmp_data[1] == 0x2f))) { + if (tmp_data[1] == 0x2a) { + strlcpy((*kp_private_ts)->chip_name, + HX_83112A_SERIES_PWON, 30); + (*kp_ic_data)->ic_adc_num = + hx83112a_data_adc_num; + hx83112ab_func_re_init(); + } else if (tmp_data[1] == 0x2b) { + strlcpy((*kp_private_ts)->chip_name, + HX_83112B_SERIES_PWON, 30); + (*kp_ic_data)->ic_adc_num = + hx83112b_data_adc_num; + hx83112ab_func_re_init(); + } else if (tmp_data[1] == 0x2e) { + strlcpy((*kp_private_ts)->chip_name, + HX_83112E_SERIES_PWON, 30); + (*kp_ic_data)->ic_adc_num = + hx83112e_data_adc_num; + hx83112ab_func_re_init(); + } else if (tmp_data[1] == 0x2f) { + strlcpy((*kp_private_ts)->chip_name, + HX_83112F_SERIES_PWON, 30); + (*kp_ic_data)->ic_adc_num = + hx83112f_data_adc_num; + hx83112f_reg_re_init(); + hx83112f_func_re_init(); + } + + I("%s:IC name = %s\n", __func__, + (*kp_private_ts)->chip_name); + + I("Himax IC package %x%x%x in\n", tmp_data[3], + tmp_data[2], tmp_data[1]); + ret_data = true; + goto FINAL; + } else { + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + E("Could NOT find Himax Chipset\n"); + E("Please check 1.VCCD,VCCA,VSP,VSN\n"); + E("2. LCM_RST,TP_RST\n"); + E("3. Power On Sequence\n"); + } + } +FINAL: + + return ret_data; +} + +DECLARE(HX_MOD_KSYM_HX83112); + +static int himax_hx83112_probe(void) +{ + I("%s:Enter\n", __func__); + himax_add_chip_dt(hx83112_chip_detect); + return 0; +} + +static int himax_hx83112_remove(void) +{ + free_chip_dt_table(); + return 0; +} + +static int __init himax_hx83112_init(void) +{ + int ret = 0; + + I("%s\n", __func__); + ret = himax_hx83112_probe(); + return 0; +} + +static void __exit himax_hx83112_exit(void) +{ + himax_hx83112_remove(); +} + +module_init(himax_hx83112_init); +module_exit(himax_hx83112_exit); + +MODULE_DESCRIPTION("HIMAX HX83112 touch driver"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.h b/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.h new file mode 100644 index 0000000000000000000000000000000000000000..7ab7f8ebb9bd28b766f8634cfa91a85efba76e2b --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for HX83112 chipset + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +#include "himax_platform.h" +#include "himax_common.h" +#include "himax_ic_core.h" +#include + +#define hx83112a_data_adc_num 216 +#define hx83112b_data_adc_num 216 +#define hx83112d_data_adc_num 64 +#define hx83112e_data_adc_num 64 +#define hx83112f_data_adc_num 48 +#define hx83112_notouch_frame 0 + +#define hx83112f_fw_addr_raw_out_sel 0x100072ec +#define hx83112f_notouch_frame 0 diff --git a/drivers/input/touchscreen/hxchipset/himax_ic_core.h b/drivers/input/touchscreen/hxchipset/himax_ic_core.h new file mode 100644 index 0000000000000000000000000000000000000000..b600b997a464030343b23f613990fced3b435cc9 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic_core.h @@ -0,0 +1,1005 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for ic core functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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 __HIMAX_IC_CORE_H__ +#define __HIMAX_IC_CORE_H__ + +#include "himax_platform.h" +#include "himax_common.h" +#include + +#define DATA_LEN_8 8 +#define DATA_LEN_4 4 +#define ADDR_LEN_4 4 +#define FLASH_RW_MAX_LEN 256 +#define FLASH_WRITE_BURST_SZ 8 +#define PROGRAM_SZ 48 +#define MAX_I2C_TRANS_SZ 128 +#define HIMAX_REG_RETRY_TIMES 5 +#define FW_BIN_16K_SZ 0x4000 +#define HIMAX_TOUCH_DATA_SIZE 128 +#define MASK_BIT_0 0x01 +#define MASK_BIT_1 0x02 +#define MASK_BIT_2 0x04 + +#define FW_SECTOR_PER_BLOCK 8 +#define FW_PAGE_PER_SECTOR 64 +#define FW_PAGE_SZ 128 +#define HX256B 0x100 +#define HX1K 0x400 +#define HX4K 0x1000 +#define HX_32K_SZ 0x8000 +#define HX_40K_SZ 0xA000 +#define HX_48K_SZ 0xC000 +#define HX64K 0x10000 +#define HX124K 0x1f000 +#define HX4000K 0x1000000 + +#define HX_NORMAL_MODE 1 +#define HX_SORTING_MODE 2 +#define HX_CHANGE_MODE_FAIL (-1) +#define HX_RW_REG_FAIL (-1) +#define HX_DRIVER_MAX_IC_NUM 12 + +#if defined(__HIMAX_HX852xG_MOD__) +#define HX_MOD_KSYM_HX852xG HX_MOD_KSYM_HX852xG +#endif + +#if defined(__HIMAX_HX852xH_MOD__) +#define HX_MOD_KSYM_HX852xH HX_MOD_KSYM_HX852xH +#endif + +#if defined(__HIMAX_HX83102_MOD__) +#define HX_MOD_KSYM_HX83102 HX_MOD_KSYM_HX83102 +#endif + +#if defined(__HIMAX_HX83103_MOD__) +#define HX_MOD_KSYM_HX83103 HX_MOD_KSYM_HX83103 +#endif + +#if defined(__HIMAX_HX83106_MOD__) +#define HX_MOD_KSYM_HX83106 HX_MOD_KSYM_HX83106 +#endif + +#if defined(__HIMAX_HX83111_MOD__) +#define HX_MOD_KSYM_HX83111 HX_MOD_KSYM_HX83111 +#endif + +#if defined(__HIMAX_HX83112_MOD__) +#define HX_MOD_KSYM_HX83112 HX_MOD_KSYM_HX83112 +#endif + +#if defined(__HIMAX_HX83191_MOD__) +#define HX_MOD_KSYM_HX83191 HX_MOD_KSYM_HX83191 +#endif + +#if defined(__HIMAX_HX83192_MOD__) +#define HX_MOD_KSYM_HX83192 HX_MOD_KSYM_HX83192 +#endif + +#if defined(__HIMAX_HX83113_MOD__) +#define HX_MOD_KSYM_HX83113 HX_MOD_KSYM_HX83113 +#endif + +/* CORE_INIT */ +/* CORE_IC */ +/* CORE_FW */ +/* CORE_FLASH */ +/* CORE_SRAM */ +/* CORE_DRIVER */ + +#define HX_0F_DEBUG + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) + +#if defined(HX_TP_PROC_GUEST_INFO) +extern struct hx_guest_info *g_guest_info_data; +#endif + +void himax_mcu_in_cmd_struct_free(void); + +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_ONCELL) +void himax_mcu_on_cmd_struct_free(void); +#endif + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +extern int g_i_FW_VER; +extern int g_i_CFG_VER; +extern int g_i_CID_MAJ; +extern int g_i_CID_MIN; +extern const struct firmware *hxfw; +#if defined(HX_ZERO_FLASH) +extern int g_f_0f_updat; +#endif +#endif + +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +extern unsigned long CID_VER_MAJ_FLASH_ADDR; +extern unsigned long CID_VER_MIN_FLASH_ADDR; +extern uint32_t CFG_TABLE_FLASH_ADDR; + +extern unsigned char IC_CHECKSUM; +#if defined(HX_EXCP_RECOVERY) +extern int g_zero_event_count; +#endif + +#if defined(HX_RST_PIN_FUNC) +extern u8 HX_HW_RESET_ACTIVATE; +void himax_rst_gpio_set(int pinnum, uint8_t value); +#endif + +#if defined(HX_USB_DETECT_GLOBAL) +void himax_cable_detect_func(bool force_renew); +#endif + +int himax_report_data_init(void); +extern int i2c_error_count; + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +#endif + +/* CORE_INIT */ +int himax_mcu_in_cmd_struct_init(void); +void himax_mcu_in_cmd_init(void); + +int himax_mcu_on_cmd_struct_init(void); +void himax_mcu_on_cmd_init(void); +void himax_parse_assign_cmd(uint32_t addr, uint8_t *cmd, int len); + +extern void (*himax_mcu_cmd_struct_free)(void); +/* CORE_INIT */ + +#if defined(HX_TP_PROC_GUEST_INFO) +#define HX_GUEST_INFO_FLASH_SADDR 0x20000 +#define HX_GUEST_INFO_MCF_SADDR 0x23000 +#define HX_GUEST_INFO_SIZE 10 +#define HX_GUEST_INFO_LEN_SIZE 4 +#define HX_GUEST_INFO_ID_SIZE 4 + +struct hx_guest_info { + int g_guest_info_ongoing; /* 0 stop, 1 ongoing */ + uint8_t g_guest_str[10][128]; + uint8_t g_guest_str_in_format[10][128]; + uint8_t g_guest_data_type[10]; + int g_guest_data_len[10]; + int g_guest_info_type; +}; +#endif + +/* CORE_IC */ + #define ic_adr_ahb_addr_byte_0 0x00 + #define ic_adr_ahb_rdata_byte_0 0x08 + #define ic_adr_ahb_access_direction 0x0c + #define ic_adr_conti 0x13 + #define ic_adr_incr4 0x0D + #define ic_adr_i2c_psw_lb 0x31 + #define ic_adr_i2c_psw_ub 0x32 + #define ic_cmd_ahb_access_direction_read 0x00 + #define ic_cmd_conti 0x31 + #define ic_cmd_incr4 0x10 + #define ic_cmd_i2c_psw_lb 0x27 + #define ic_cmd_i2c_psw_ub 0x95 + #define ic_adr_tcon_on_rst 0x80020020 + #define ic_addr_adc_on_rst 0x80020094 + #define ic_adr_psl 0x900000A0 + #define ic_adr_cs_central_state 0x900000A8 + #define ic_cmd_rst 0x00000000 + #define ic_adr_osc_en 0x900880A8 + #define ic_adr_osc_pw 0x900880E0 + + #define on_ic_adr_ahb_addr_byte_0 0x00 + #define on_ic_adr_ahb_rdata_byte_0 0x08 + #define on_ic_adr_ahb_access_direction 0x0c + #define on_ic_adr_conti 0x13 + #define on_ic_adr_incr4 0x0D + #define on_ic_cmd_ahb_access_direction_read 0x00 + #define on_ic_cmd_conti 0x31 + #define on_ic_cmd_incr4 0x10 + #define on_ic_adr_mcu_ctrl 0x82 + #define on_ic_cmd_mcu_on 0x25 + #define on_ic_cmd_mcu_off 0xDA + #define on_ic_adr_sleep_ctrl 0x99 + #define on_ic_cmd_sleep_in 0x80 + #define on_ic_adr_tcon_ctrl 0x80020000 + #define on_ic_cmd_tcon_on 0x00000000 + #define on_ic_adr_wdg_ctrl 0x9000800C + #define on_ic_cmd_wdg_psw 0x0000AC53 + #define on_ic_adr_wdg_cnt_ctrl 0x90008010 + #define on_ic_cmd_wdg_cnt_clr 0x000035CA +/* CORE_IC */ + +/* CORE_FW */ + #define fw_addr_system_reset 0x90000018 + #define fw_addr_ctrl_fw 0x9000005c + #define fw_addr_flag_reset_event 0x900000e4 + #define fw_addr_hsen_enable 0x10007F14 + #define fw_addr_smwp_enable 0x10007F10 + #define fw_usb_detect_addr 0x10007F38 + #define fw_addr_program_reload_from 0x00000000 + #define fw_addr_program_reload_to 0x08000000 + #define fw_addr_program_reload_page_write 0x0000fb00 + #define fw_addr_raw_out_sel 0x800204b4 + #define fw_addr_reload_status 0x80050000 + #define fw_addr_reload_crc32_result 0x80050018 + #define fw_addr_reload_addr_from 0x80050020 + #define fw_addr_reload_addr_cmd_beat 0x80050028 + #define fw_data_system_reset 0x00000055 + #define fw_data_safe_mode_release_pw_active 0x00000053 + #define fw_data_safe_mode_release_pw_reset 0x00000000 + #define fw_data_clear 0x00000000 + #define fw_data_fw_stop 0x000000A5 + #define fw_data_program_reload_start 0x0A3C3000 + #define fw_data_program_reload_compare 0x04663000 + #define fw_data_program_reload_break 0x15E75678 + #define fw_addr_selftest_addr_en 0x10007F18 + #define fw_addr_selftest_result_addr 0x10007f24 + #define fw_data_selftest_request 0x00006AA6 + #define fw_addr_criteria_addr 0x10007f1c + #define fw_data_criteria_aa_top 0x64 + #define fw_data_criteria_aa_bot 0x00 + #define fw_data_criteria_key_top 0x64 + #define fw_data_criteria_key_bot 0x00 + #define fw_data_criteria_avg_top 0x64 + #define fw_data_criteria_avg_bot 0x00 + #define fw_addr_set_frame_addr 0x10007294 + #define fw_data_set_frame 0x0000000A + #define fw_data_selftest_ack_hb 0xa6 + #define fw_data_selftest_ack_lb 0x6a + #define fw_data_selftest_pass 0xaa + #define fw_data_normal_cmd 0x00 + #define fw_data_normal_status 0x99 + #define fw_data_sorting_cmd 0xaa + #define fw_data_sorting_status 0xcc + #define fw_data_idle_dis_pwd 0x17 + #define fw_data_idle_en_pwd 0x1f + #define fw_addr_sorting_mode_en 0x10007f04 + #define fw_addr_fw_mode_status 0x10007088 + #define fw_addr_icid_addr 0x900000d0 + #define fw_addr_fw_ver_addr 0x10007004 + #define fw_addr_fw_cfg_addr 0x10007084 + #define fw_addr_fw_vendor_addr 0x10007000 + #define fw_addr_cus_info 0x10007008 + #define fw_addr_proj_info 0x10007014 + #define fw_addr_fw_state_addr 0x900000f8 + #define fw_addr_fw_dbg_msg_addr 0x10007f40 + #define fw_addr_chk_fw_status 0x900000a8 + #define fw_addr_chk_dd_status 0x900000E8 + #define fw_addr_dd_handshak_addr 0x900000fc + #define fw_addr_dd_data_addr 0x10007f80 + #define fw_addr_clr_fw_record_dd_sts 0x10007FCC + #define fw_addr_ap_notify_fw_sus 0x10007FD0 + #define fw_data_ap_notify_fw_sus_en 0xA55AA55A + #define fw_data_ap_notify_fw_sus_dis 0x00000000 + #define fw_data_dd_request 0xaa + #define fw_data_dd_ack 0xbb + #define fw_data_rawdata_ready_hb 0xa3 + #define fw_data_rawdata_ready_lb 0x3a + #define fw_addr_ahb_addr 0x11 + #define fw_data_ahb_dis 0x00 + #define fw_data_ahb_en 0x01 + #define fw_addr_event_addr 0x30 + #define fw_func_handshaking_pwd 0xA55AA55A + #define fw_func_handshaking_end 0x77887788 + #define fw_addr_ulpm_33 0x33 + #define fw_addr_ulpm_34 0x34 + #define fw_data_ulpm_11 0x11 + #define fw_data_ulpm_22 0x22 + #define fw_data_ulpm_33 0x33 + #define fw_data_ulpm_aa 0xAA + + #define on_fw_addr_smwp_enable 0xA2 + #define on_fw_usb_detect_addr 0xA4 + #define on_fw_addr_program_reload_from 0x00000000 + #define on_fw_addr_raw_out_sel 0x98 + #define on_fw_addr_flash_checksum 0x80000044 + #define on_fw_data_flash_checksum 0x00000491 + #define on_fw_addr_crc_value 0x80000050 + #define on_fw_data_safe_mode_release_pw_active 0x00000053 + #define on_fw_data_safe_mode_release_pw_reset 0x00000000 + #define on_fw_addr_criteria_addr 0x9A + #define on_fw_data_selftest_pass 0xaa + #define on_fw_addr_reK_crtl 0x8000000C + #define on_fw_data_reK_en 0x02 + #define on_fw_data_reK_dis 0xFD + #define on_fw_data_rst_init 0xF0 + #define on_fw_data_dc_set 0x02 + #define on_fw_data_bank_set 0x03 + #define on_fw_addr_selftest_addr_en 0x98 + #define on_fw_addr_selftest_result_addr 0x9B + #define on_fw_data_selftest_request 0x06 + #define on_fw_data_thx_avg_mul_dc_lsb 0x22 + #define on_fw_data_thx_avg_mul_dc_msb 0x0B + #define on_fw_data_thx_mul_dc_up_low_bud 0x64 + #define on_fw_data_thx_avg_slf_dc_lsb 0x14 + #define on_fw_data_thx_avg_slf_dc_msb 0x05 + #define on_fw_data_thx_slf_dc_up_low_bud 0x64 + #define on_fw_data_thx_slf_bank_up 0x40 + #define on_fw_data_thx_slf_bank_low 0x00 + #define on_fw_data_idle_dis_pwd 0x40 + #define on_fw_data_idle_en_pwd 0x00 + #define on_fw_addr_fw_mode_status 0x99 + #define on_fw_addr_icid_addr 0x900000d0 + #define on_fw_addr_fw_ver_start 0x90 + #define on_fw_data_rawdata_ready_hb 0xa3 + #define on_fw_data_rawdata_ready_lb 0x3a + #define on_fw_addr_ahb_addr 0x11 + #define on_fw_data_ahb_dis 0x00 + #define on_fw_data_ahb_en 0x01 + #define on_fw_addr_event_addr 0x30 +/* CORE_FW */ + +/* CORE_FLASH */ + #define flash_addr_ctrl_base 0x80000000 + #define flash_addr_spi200_trans_fmt (flash_addr_ctrl_base + 0x10) + #define flash_addr_spi200_trans_ctrl (flash_addr_ctrl_base + 0x20) + #define flash_addr_spi200_cmd (flash_addr_ctrl_base + 0x24) + #define flash_addr_spi200_addr (flash_addr_ctrl_base + 0x28) + #define flash_addr_spi200_data (flash_addr_ctrl_base + 0x2c) + #define flash_addr_spi200_fifo_rst (flash_addr_ctrl_base + 0x30) + #define flash_addr_spi200_rst_status (flash_addr_ctrl_base + 0x34) + #define flash_addr_spi200_flash_speed (flash_addr_ctrl_base + 0x40) + #define flash_addr_spi200_bt_num (flash_addr_ctrl_base + 0xe8) + #define flash_data_spi200_txfifo_rst 0x00000004 + #define flash_data_spi200_rxfifo_rst 0x00000002 + #define flash_data_spi200_trans_fmt 0x00020780 + #define flash_data_spi200_trans_ctrl_1 0x42000003 + #define flash_data_spi200_trans_ctrl_2 0x47000000 + #define flash_data_spi200_trans_ctrl_3 0x67000000 + #define flash_data_spi200_trans_ctrl_4 0x610ff000 + #define flash_data_spi200_trans_ctrl_5 0x694002ff + #define flash_data_spi200_trans_ctrl_6 0x42000000 + #define flash_data_spi200_trans_ctrl_7 0x6940020f + #define flash_data_spi200_cmd_1 0x00000005 + #define flash_data_spi200_cmd_2 0x00000006 + #define flash_data_spi200_cmd_3 0x000000C7 + #define flash_data_spi200_cmd_4 0x000000D8 + #define flash_data_spi200_cmd_5 0x00000020 + #define flash_data_spi200_cmd_6 0x00000002 + #define flash_data_spi200_cmd_7 0x0000003b + #define flash_data_spi200_cmd_8 0x00000003 + #define flash_data_spi200_addr 0x00000000 + + #define on_flash_addr_ctrl_base 0x80000000 + #define on_flash_addr_ctrl_auto 0x80000004 + #define on_flash_data_main_erase 0x0000A50D + #define on_flash_data_auto 0xA5 + #define on_flash_data_main_read 0x03 + #define on_flash_data_page_write 0x05 + #define on_flash_data_spp_read 0x10 + #define on_flash_data_sfr_read 0x14 + #define on_flash_addr_ahb_ctrl 0x80000020 + #define on_flash_data_ahb_squit 0x00000001 + #define on_flash_addr_unlock_0 0x00000000 + #define on_flash_addr_unlock_4 0x00000004 + #define on_flash_addr_unlock_8 0x00000008 + #define on_flash_addr_unlock_c 0x0000000C + #define on_flash_data_cmd0 0x28178EA0 + #define on_flash_data_cmd1 0x0A0E03FF + #define on_flash_data_cmd2 0x8C203D0C + #define on_flash_data_cmd3 0x00300263 + #define on_flash_data_lock 0x03400000 +/* CORE_FLASH */ + +/* CORE_SRAM */ + #define sram_adr_mkey 0x100070E8 + #define sram_adr_rawdata_addr 0x10000000 + #define sram_adr_rawdata_end 0x00000000 + #define sram_passwrd_start 0x5AA5 + #define sram_passwrd_end 0xA55A + + #define on_sram_adr_rawdata_addr 0x080002E0 + #define on_sram_adr_rawdata_end 0x00000000 + #define on_sram_cmd_conti 0x44332211 + #define on_sram_cmd_fin 0x00000000 + #define on_sram_passwrd_start 0x5AA5 + #define on_sram_passwrd_end 0xA55A +/* CORE_SRAM */ + +/* CORE_DRIVER */ + #define driver_addr_fw_define_flash_reload 0x10007f00 + #define driver_addr_fw_define_2nd_flash_reload 0x100072c0 + #define driver_data_fw_define_flash_reload_dis 0x0000a55a + #define driver_data_fw_define_flash_reload_en 0x00000000 + #define driver_addr_fw_define_int_is_edge 0x10007088 + #define driver_addr_fw_define_rxnum_txnum_maxpt 0x100070f4 + #define driver_data_fw_define_rxnum_txnum_maxpt_sorting 0x00000008 + #define driver_data_fw_define_rxnum_txnum_maxpt_normal 0x00000014 + #define driver_addr_fw_define_xy_res_enable 0x100070f8 + #define driver_addr_fw_define_x_y_res 0x100070fc + #define driver_data_df_rx 36 + #define driver_data_df_tx 18 + #define driver_data_df_pt 10 + #define on_driver_addr_fw_define_int_is_edge 0x10007088 + #define on_driver_data_df_rx 28 + #define on_driver_data_df_tx 14 + #define on_driver_data_df_pt 10 +#if !defined(HX_NEW_EVENT_STACK_FORMAT) + #define on_driver_addr_fw_rx_tx_maxpt_num 0x0800001C + #define on_driver_addr_fw_xy_rev_int_edge 0x0800000C + #define on_driver_addr_fw_define_x_y_res 0x08000030 +#else + #define on_driver_addr_fw_rx_tx_maxpt_num 0x08000004 + #define on_driver_addr_fw_maxpt_bt_num 0x0800000C + #define on_driver_addr_fw_xy_rev_int_edge 0x08000110 + #define on_driver_addr_fw_define_x_y_res 0x08000010 +#endif + +/* CORE_DRIVER */ + +#if defined(HX_ZERO_FLASH) + #define zf_data_dis_flash_reload 0x00009AA9 + #define zf_addr_system_reset 0x90000018 + #define zf_data_system_reset 0x00000055 + #define zf_data_sram_start_addr 0x08000000 + #define zf_data_cfg_info 0x10007000 + #define zf_data_fw_cfg_1 0x10007084 + #define zf_data_fw_cfg_2 0x10007264 + #define zf_data_fw_cfg_3 0x10007300 + #define zf_data_adc_cfg_1 0x10006A00 + #define zf_data_adc_cfg_2 0x10007B28 + #define zf_data_adc_cfg_3 0x10007AF0 + #define zf_data_map_table 0x10007500 +/* #define zf_data_mode_switch 0x10007294*/ + #define zf_addr_sts_chk 0x900000A8 + #define zf_data_activ_sts 0x05 + #define zf_addr_activ_relod 0x90000048 + #define zf_data_activ_in 0xEC + +#if defined(HX_CODE_OVERLAY) + #define ovl_section_num 3 + #define ovl_gesture_request 0x11 + #define ovl_gesture_reply 0x22 + #define ovl_border_request 0x55 + #define ovl_border_reply 0x66 + #define ovl_sorting_request 0x99 + #define ovl_sorting_reply 0xAA + #define ovl_fault 0xFF +#endif + +struct zf_info { + uint8_t sram_addr[4]; + int write_size; + uint32_t fw_addr; + uint32_t cfg_addr; +}; +#endif +/* New Version 1K*/ +enum bin_desc_map_table { + TP_CONFIG_TABLE = 0x00000A00, + FW_CID = 0x10000000, + FW_VER = 0x10000100, + CFG_VER = 0x10000600, +}; + +/*Old Version 1K + *enum bin_desc_map_table { + *TP_CONFIG_TABLE = 0x0000000A, + *FW_CID = 0x10000000, + *FW_VER = 0x10000001, + *CFG_VER = 0x10000005, + *}; + **/ + +extern uint32_t dbg_reg_ary[4]; + +struct ic_operation { + uint8_t addr_ahb_addr_byte_0[1]; + uint8_t addr_ahb_rdata_byte_0[1]; + uint8_t addr_ahb_access_direction[1]; + uint8_t addr_conti[1]; + uint8_t addr_incr4[1]; + uint8_t adr_i2c_psw_lb[1]; + uint8_t adr_i2c_psw_ub[1]; + uint8_t data_ahb_access_direction_read[1]; + uint8_t data_conti[1]; + uint8_t data_incr4[1]; + uint8_t data_i2c_psw_lb[1]; + uint8_t data_i2c_psw_ub[1]; + uint8_t addr_tcon_on_rst[4]; + uint8_t addr_adc_on_rst[4]; + uint8_t addr_psl[4]; + uint8_t addr_cs_central_state[4]; + uint8_t data_rst[4]; + uint8_t adr_osc_en[4]; + uint8_t adr_osc_pw[4]; +}; + +struct fw_operation { + uint8_t addr_system_reset[4]; + uint8_t addr_ctrl_fw_isr[4]; + uint8_t addr_flag_reset_event[4]; + uint8_t addr_hsen_enable[4]; + uint8_t addr_smwp_enable[4]; + uint8_t addr_program_reload_from[4]; + uint8_t addr_program_reload_to[4]; + uint8_t addr_program_reload_page_write[4]; + uint8_t addr_raw_out_sel[4]; + uint8_t addr_reload_status[4]; + uint8_t addr_reload_crc32_result[4]; + uint8_t addr_reload_addr_from[4]; + uint8_t addr_reload_addr_cmd_beat[4]; + uint8_t addr_selftest_addr_en[4]; + uint8_t addr_criteria_addr[4]; + uint8_t addr_set_frame_addr[4]; + uint8_t addr_selftest_result_addr[4]; + uint8_t addr_sorting_mode_en[4]; + uint8_t addr_fw_mode_status[4]; + uint8_t addr_icid_addr[4]; + uint8_t addr_fw_ver_addr[4]; + uint8_t addr_fw_cfg_addr[4]; + uint8_t addr_fw_vendor_addr[4]; + uint8_t addr_cus_info[4]; + uint8_t addr_proj_info[4]; + uint8_t addr_fw_state_addr[4]; + uint8_t addr_fw_dbg_msg_addr[4]; + uint8_t addr_chk_fw_status[4]; + uint8_t addr_dd_handshak_addr[4]; + uint8_t addr_dd_data_addr[4]; + uint8_t addr_clr_fw_record_dd_sts[4]; + uint8_t addr_ap_notify_fw_sus[4]; + uint8_t data_ap_notify_fw_sus_en[4]; + uint8_t data_ap_notify_fw_sus_dis[4]; + uint8_t data_system_reset[4]; + uint8_t data_safe_mode_release_pw_active[4]; + uint8_t data_safe_mode_release_pw_reset[4]; + uint8_t data_clear[4]; + uint8_t data_fw_stop[4]; + uint8_t data_program_reload_start[4]; + uint8_t data_program_reload_compare[4]; + uint8_t data_program_reload_break[4]; + uint8_t data_selftest_request[4]; + uint8_t data_criteria_aa_top[1]; + uint8_t data_criteria_aa_bot[1]; + uint8_t data_criteria_key_top[1]; + uint8_t data_criteria_key_bot[1]; + uint8_t data_criteria_avg_top[1]; + uint8_t data_criteria_avg_bot[1]; + uint8_t data_set_frame[4]; + uint8_t data_selftest_ack_hb[1]; + uint8_t data_selftest_ack_lb[1]; + uint8_t data_selftest_pass[1]; + uint8_t data_normal_cmd[1]; + uint8_t data_normal_status[1]; + uint8_t data_sorting_cmd[1]; + uint8_t data_sorting_status[1]; + uint8_t data_dd_request[1]; + uint8_t data_dd_ack[1]; + uint8_t data_idle_dis_pwd[1]; + uint8_t data_idle_en_pwd[1]; + uint8_t data_rawdata_ready_hb[1]; + uint8_t data_rawdata_ready_lb[1]; + uint8_t addr_ahb_addr[1]; + uint8_t data_ahb_dis[1]; + uint8_t data_ahb_en[1]; + uint8_t addr_event_addr[1]; + uint8_t addr_usb_detect[4]; + uint8_t addr_ulpm_33[1]; + uint8_t addr_ulpm_34[1]; + uint8_t data_ulpm_11[1]; + uint8_t data_ulpm_22[1]; + uint8_t data_ulpm_33[1]; + uint8_t data_ulpm_aa[1]; +}; + +struct flash_operation { + uint8_t addr_spi200_trans_fmt[4]; + uint8_t addr_spi200_trans_ctrl[4]; + uint8_t addr_spi200_fifo_rst[4]; + uint8_t addr_spi200_rst_status[4]; + uint8_t addr_spi200_flash_speed[4]; + uint8_t addr_spi200_cmd[4]; + uint8_t addr_spi200_addr[4]; + uint8_t addr_spi200_data[4]; + uint8_t addr_spi200_bt_num[4]; + + uint8_t data_spi200_txfifo_rst[4]; + uint8_t data_spi200_rxfifo_rst[4]; + uint8_t data_spi200_trans_fmt[4]; + uint8_t data_spi200_trans_ctrl_1[4]; + uint8_t data_spi200_trans_ctrl_2[4]; + uint8_t data_spi200_trans_ctrl_3[4]; + uint8_t data_spi200_trans_ctrl_4[4]; + uint8_t data_spi200_trans_ctrl_5[4]; + uint8_t data_spi200_trans_ctrl_6[4]; + uint8_t data_spi200_trans_ctrl_7[4]; + uint8_t data_spi200_cmd_1[4]; + uint8_t data_spi200_cmd_2[4]; + uint8_t data_spi200_cmd_3[4]; + uint8_t data_spi200_cmd_4[4]; + uint8_t data_spi200_cmd_5[4]; + uint8_t data_spi200_cmd_6[4]; + uint8_t data_spi200_cmd_7[4]; + uint8_t data_spi200_cmd_8[4]; + uint8_t data_spi200_addr[4]; +}; + +struct sram_operation { + uint8_t addr_mkey[4]; + uint8_t addr_rawdata_addr[4]; + uint8_t addr_rawdata_end[4]; + uint8_t passwrd_start[2]; + uint8_t passwrd_end[2]; +}; + +struct driver_operation { + uint8_t addr_fw_define_flash_reload[4]; + uint8_t addr_fw_define_2nd_flash_reload[4]; + uint8_t addr_fw_define_int_is_edge[4]; + uint8_t addr_fw_define_rxnum_txnum_maxpt[4]; + uint8_t addr_fw_define_xy_res_enable[4]; + uint8_t addr_fw_define_x_y_res[4]; + uint8_t data_df_rx[1]; + uint8_t data_df_tx[1]; + uint8_t data_df_pt[1]; + uint8_t data_fw_define_flash_reload_dis[4]; + uint8_t data_fw_define_flash_reload_en[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_sorting[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_normal[4]; +}; + +struct zf_operation { + uint8_t data_dis_flash_reload[4]; + uint8_t addr_system_reset[4]; + uint8_t data_system_reset[4]; + uint8_t data_sram_start_addr[4]; + uint8_t data_sram_clean[4]; + uint8_t data_cfg_info[4]; + uint8_t data_fw_cfg_1[4]; + uint8_t data_fw_cfg_2[4]; + uint8_t data_fw_cfg_3[4]; + uint8_t data_adc_cfg_1[4]; + uint8_t data_adc_cfg_2[4]; + uint8_t data_adc_cfg_3[4]; + uint8_t data_map_table[4]; +/* uint8_t data_mode_switch[4];*/ + uint8_t addr_sts_chk[4]; + uint8_t data_activ_sts[1]; + uint8_t addr_activ_relod[4]; + uint8_t data_activ_in[1]; +}; + +struct himax_core_command_operation { + struct ic_operation *ic_op; + struct fw_operation *fw_op; + struct flash_operation *flash_op; + struct sram_operation *sram_op; + struct driver_operation *driver_op; + struct zf_operation *zf_op; +}; + +struct on_ic_operation { + uint8_t addr_ahb_addr_byte_0[1]; + uint8_t addr_ahb_rdata_byte_0[1]; + uint8_t addr_ahb_access_direction[1]; + uint8_t addr_conti[1]; + uint8_t addr_incr4[1]; + uint8_t adr_mcu_ctrl[1]; + uint8_t data_ahb_access_direction_read[1]; + uint8_t data_conti[1]; + uint8_t data_incr4[1]; + uint8_t cmd_mcu_on[1]; + uint8_t cmd_mcu_off[1]; + uint8_t adr_sleep_ctrl[1]; + uint8_t cmd_sleep_in[1]; + uint8_t adr_tcon_ctrl[4]; + uint8_t cmd_tcon_on[4]; + uint8_t adr_wdg_ctrl[4]; + uint8_t cmd_wdg_psw[4]; + uint8_t adr_wdg_cnt_ctrl[4]; + uint8_t cmd_wdg_cnt_clr[4]; +}; + +struct on_fw_operation { + uint8_t addr_smwp_enable[1]; + uint8_t addr_program_reload_from[4]; + uint8_t addr_raw_out_sel[1]; + uint8_t addr_flash_checksum[4]; + uint8_t data_flash_checksum[4]; + uint8_t addr_crc_value[4]; + uint8_t addr_reload_status[4]; + uint8_t addr_reload_crc32_result[4]; + uint8_t addr_reload_addr_from[4]; + uint8_t addr_reload_addr_cmd_beat[4]; + uint8_t addr_set_frame_addr[4]; + uint8_t addr_fw_mode_status[1]; + uint8_t addr_icid_addr[4]; + uint8_t addr_fw_ver_start[1]; + uint8_t data_safe_mode_release_pw_active[4]; + uint8_t data_safe_mode_release_pw_reset[4]; + uint8_t data_clear[4]; + uint8_t addr_criteria_addr[1]; + uint8_t data_selftest_pass[1]; + uint8_t addr_reK_crtl[4]; + uint8_t data_reK_en[1]; + uint8_t data_reK_dis[1]; + uint8_t data_rst_init[1]; + uint8_t data_dc_set[1]; + uint8_t data_bank_set[1]; + uint8_t addr_selftest_addr_en[1]; + uint8_t addr_selftest_result_addr[1]; + uint8_t data_selftest_request[1]; + uint8_t data_thx_avg_mul_dc_lsb[1]; + uint8_t data_thx_avg_mul_dc_msb[1]; + uint8_t data_thx_mul_dc_up_low_bud[1]; + uint8_t data_thx_avg_slf_dc_lsb[1]; + uint8_t data_thx_avg_slf_dc_msb[1]; + uint8_t data_thx_slf_dc_up_low_bud[1]; + uint8_t data_thx_slf_bank_up[1]; + uint8_t data_thx_slf_bank_low[1]; + uint8_t data_idle_dis_pwd[1]; + uint8_t data_idle_en_pwd[1]; + uint8_t data_rawdata_ready_hb[1]; + uint8_t data_rawdata_ready_lb[1]; + uint8_t addr_ahb_addr[1]; + uint8_t data_ahb_dis[1]; + uint8_t data_ahb_en[1]; + uint8_t addr_event_addr[1]; + uint8_t addr_usb_detect[1]; +}; + +struct on_flash_operation { + uint8_t addr_ctrl_base[4]; + uint8_t addr_ctrl_auto[4]; + uint8_t data_main_erase[4]; + uint8_t data_auto[1]; + uint8_t data_main_read[1]; + uint8_t data_page_write[1]; + uint8_t data_sfr_read[1]; + uint8_t data_spp_read[1]; + uint8_t addr_ahb_ctrl[4]; + uint8_t data_ahb_squit[4]; + + uint8_t addr_unlock_0[4]; + uint8_t addr_unlock_4[4]; + uint8_t addr_unlock_8[4]; + uint8_t addr_unlock_c[4]; + uint8_t data_cmd0[4]; + uint8_t data_cmd1[4]; + uint8_t data_cmd2[4]; + uint8_t data_cmd3[4]; + uint8_t data_lock[4]; +}; + +struct on_sram_operation { + uint8_t addr_rawdata_addr[4]; + uint8_t addr_rawdata_end[4]; + uint8_t data_conti[4]; + uint8_t data_fin[4]; + uint8_t passwrd_start[2]; + uint8_t passwrd_end[2]; +}; + +struct on_driver_operation { + uint8_t addr_fw_define_int_is_edge[4]; + uint8_t addr_fw_rx_tx_maxpt_num[4]; +#if defined(HX_NEW_EVENT_STACK_FORMAT) + uint8_t addr_fw_maxpt_bt_num[4]; +#endif + uint8_t addr_fw_xy_rev_int_edge[4]; + uint8_t addr_fw_define_x_y_res[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_sorting[4]; + uint8_t data_fw_define_rxnum_txnum_maxpt_normal[4]; + uint8_t data_df_rx[1]; + uint8_t data_df_tx[1]; + uint8_t data_df_pt[1]; +}; + +struct himax_on_core_command_operation { + struct on_ic_operation *ic_op; + struct on_fw_operation *fw_op; + struct on_flash_operation *flash_op; + struct on_sram_operation *sram_op; + struct on_driver_operation *driver_op; +}; + +struct himax_chip_detect { + bool (*fp_chip_detect)(void); +}; + +struct himax_chip_entry { + struct himax_chip_detect *core_chip_dt; + uint32_t hx_ic_dt_num; +}; + +struct himax_core_fp { +/* CORE_IC */ + void (*fp_burst_enable)(uint8_t auto_add_4_byte); + int (*fp_register_read)(uint8_t *read_addr, uint32_t read_length, + uint8_t *read_data, uint8_t cfg_flag); + /*int (*fp_flash_write_burst)(uint8_t *reg_byte, uint8_t *write_data);*/ + /*void (*fp_flash_write_burst_lenth)(uint8_t *reg_byte, + * uint8_t *write_data, uint32_t length); + */ + int (*fp_register_write)(uint8_t *write_addr, uint32_t write_length, + uint8_t *write_data, uint8_t cfg_flag); + void (*fp_interface_on)(void); + void (*fp_sense_on)(uint8_t FlashMode); + void (*fp_tcon_on)(void); + bool (*fp_watch_dog_off)(void); + bool (*fp_sense_off)(bool check_en); + void (*fp_sleep_in)(void); + bool (*fp_wait_wip)(int Timing); + void (*fp_init_psl)(void); + void (*fp_resume_ic_action)(void); + void (*fp_suspend_ic_action)(void); + void (*fp_power_on_init)(void); + bool (*fp_dd_clk_set)(bool enable); + void (*fp_dd_reg_en)(bool enable); + bool (*fp_dd_reg_write)(uint8_t addr, uint8_t pa_num, int len, + uint8_t *data, uint8_t bank); + bool (*fp_dd_reg_read)(uint8_t addr, uint8_t pa_num, int len, + uint8_t *data, uint8_t bank); + bool (*fp_ic_id_read)(void); + bool (*fp_slave_tcon_reset)(void); + bool (*fp_slave_adc_reset_slave)(void); + bool (*fp_slave_wdt_off_slave)(void); +/* CORE_IC */ + +/* CORE_FW */ + void (*fp_parse_raw_data)(struct himax_report_data *hx_touch_data, + int mul_num, + int self_num, + uint8_t diag_cmd, + int16_t *mutual_data, + int16_t *self_data); + void (*fp_system_reset)(void); + int (*fp_Calculate_CRC_with_AP)(unsigned char *FW_content, + int CRC_from_FW, + int len); + uint32_t (*fp_check_CRC)(uint8_t *start_addr, int reload_length); + void (*fp_set_reload_cmd)(uint8_t *write_data, + int idx, + uint32_t cmd_from, + uint32_t cmd_to, + uint32_t cmd_beat); + bool (*fp_program_reload)(void); + void (*fp_set_SMWP_enable)(uint8_t SMWP_enable, bool suspended); + void (*fp_set_HSEN_enable)(uint8_t HSEN_enable, bool suspended); + void (*fp_diag_register_set)(uint8_t diag_command, + uint8_t storage_type, bool is_dirly); + void (*_clr_fw_reord_dd_sts)(void); + void (*_ap_notify_fw_sus)(int suspend); +#if defined(HX_TP_SELF_TEST_DRIVER) + void (*fp_control_reK)(bool enable); +#endif + int (*fp_chip_self_test)(struct seq_file *s, void *v); + void (*fp_idle_mode)(int disable); + void (*fp_reload_disable)(int disable); + bool (*fp_check_chip_version)(void); + int (*fp_read_ic_trigger_type)(void); + int (*fp_read_i2c_status)(void); + void (*fp_read_FW_ver)(void); + bool (*fp_read_event_stack)(uint8_t *buf, uint8_t length); + void (*fp_return_event_stack)(void); + bool (*fp_calculateChecksum)(bool change_iref, uint32_t size); + void (*fp_read_FW_status)(void); + void (*fp_irq_switch)(int switch_on); + int (*fp_assign_sorting_mode)(uint8_t *tmp_data); + int (*fp_check_sorting_mode)(uint8_t *tmp_data); + int (*fp_get_max_dc)(void); + uint8_t (*fp_read_DD_status)(uint8_t *cmd_set, uint8_t *tmp_data); + int (*fp_ulpm_in)(void); + int (*fp_black_gest_ctrl)(bool enable); + int (*_diff_overlay_bin)(void); +/* CORE_FW */ + +/* CORE_FLASH */ + void (*fp_chip_erase)(void); + bool (*fp_block_erase)(int start_addr, int length); + bool (*fp_sector_erase)(int start_addr); + void (*fp_flash_programming)(uint8_t *FW_content, int FW_Size); + void (*fp_flash_page_write)(uint8_t *write_addr, int length, + uint8_t *write_data); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_32k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_60k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_64k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_124k)(unsigned char *fw, + int len, bool change_iref); + int (*fp_fts_ctpm_fw_upgrade_with_sys_fs_128k)(unsigned char *fw, + int len, bool change_iref); + void (*fp_flash_dump_func)(uint8_t local_flash_command, + int Flash_Size, uint8_t *flash_buffer); + bool (*fp_flash_lastdata_check)(uint32_t size); + bool (*fp_bin_desc_get)(unsigned char *fw, uint32_t max_sz); + bool (*fp_ahb_squit)(void); + void (*fp_flash_read)(uint8_t *r_data, int start_addr, int length); + bool (*fp_sfr_rw)(uint8_t *addr, int length, + uint8_t *data, uint8_t rw_ctrl); + bool (*fp_lock_flash)(void); + bool (*fp_unlock_flash)(void); + void (*fp_init_auto_func)(void); + int (*_diff_overlay_flash)(void); +/* CORE_FLASH */ + +/* CORE_SRAM */ + void (*fp_sram_write)(uint8_t *FW_content); + bool (*fp_sram_verify)(uint8_t *FW_File, int FW_Size); + bool (*fp_get_DSRAM_data)(uint8_t *info_data, bool DSRAM_Flag); +/* CORE_SRAM */ + +/* CORE_DRIVER */ + void (*fp_chip_init)(void); +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + int (*fp_fw_ver_bin)(void); +#endif + void (*fp_pin_reset)(void); + void (*fp_touch_information)(void); + void (*fp_calc_touch_data_size)(void); + void (*fp_reload_config)(void); + int (*fp_get_touch_data_size)(void); + void (*fp_usb_detect_set)(uint8_t *cable_config); + int (*fp_hand_shaking)(void); + int (*fp_determin_diag_rawdata)(int diag_command); + int (*fp_determin_diag_storage)(int diag_command); + int (*fp_cal_data_len)(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); + bool (*fp_diag_check_sum)(struct himax_report_data *hx_touch_data); + void (*fp_diag_parse_raw_data)(struct himax_report_data *hx_touch_data, + int mul_num, + int self_num, + uint8_t diag_cmd, + int32_t *mutual_data, + int32_t *self_data); + void (*fp_ic_reset)(uint8_t loadconfig, uint8_t int_off); + int (*fp_ic_excp_recovery)(uint32_t hx_excp_event, + uint32_t hx_zero_event, uint32_t length); + void (*fp_excp_ic_reset)(void); + void (*fp_resend_cmd_func)(bool suspended); +#if defined(HX_TP_PROC_GUEST_INFO) + int (*guest_info_get_status)(void); + int (*read_guest_info)(void); + int (*read_mcf_data)(void); +#endif +/* CORE_DRIVER */ +#if defined(HX_ZERO_FLASH) + void (*fp_clean_sram_0f)(uint8_t *addr, int write_len, int type); + void (*fp_write_sram_0f)(const struct firmware *fw_entry, + uint8_t *addr, + int start_index, + uint32_t write_len); + int (*fp_write_sram_0f_crc)(const struct firmware *fw_entry, + uint8_t *addr, + int start_index, + uint32_t write_len); + void (*fp_firmware_update_0f)(const struct firmware *fw_entry); + int (*fp_0f_operation_dirly)(void); + int (*fp_0f_op_file_dirly)(char *file_name); + void (*fp_0f_operation)(struct work_struct *work); + int (*fp_0f_excp_check)(void); + void (*fp_0f_reload_to_active)(void); +#if defined(HX_0F_DEBUG) + void (*fp_read_sram_0f)(const struct firmware *fw_entry, + uint8_t *addr, + int start_index, + int read_len); + void (*fp_read_all_sram)(uint8_t *addr, int read_len); + void (*fp_firmware_read_0f)(const struct firmware *fw_entry, int type); + void (*fp_0f_operation_check)(int type); +#endif +#if defined(HX_CODE_OVERLAY) + int (*fp_0f_overlay)(int ovl_type, int mode); +#endif +#endif +}; + +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c b/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c new file mode 100644 index 0000000000000000000000000000000000000000..e5810c41c599b5d275f2a90a6f6dc34e4f9f3831 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic_incell_core.c @@ -0,0 +1,4881 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for incell ic core functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +#include "himax_ic_core.h" + +struct himax_core_command_operation *g_core_cmd_op; +struct ic_operation *pic_op; +EXPORT_SYMBOL(pic_op); + +struct fw_operation *pfw_op; +EXPORT_SYMBOL(pfw_op); + +struct flash_operation *pflash_op; +EXPORT_SYMBOL(pflash_op); + +struct sram_operation *psram_op; +struct driver_operation *pdriver_op; +EXPORT_SYMBOL(pdriver_op); + +#if defined(HX_ZERO_FLASH) +struct zf_operation *pzf_op; +EXPORT_SYMBOL(pzf_op); +#if defined(HX_CODE_OVERLAY) +uint8_t *ovl_idx; +EXPORT_SYMBOL(ovl_idx); +#endif +#endif + +#define Arr4_to_Arr4(A, B) {\ + A[3] = B[3];\ + A[2] = B[2];\ + A[1] = B[1];\ + A[0] = B[0];\ + } + +int HX_TOUCH_INFO_POINT_CNT; + +void (*himax_mcu_cmd_struct_free)(void); +static uint8_t *g_internal_buffer; +uint32_t dbg_reg_ary[4] = {fw_addr_fw_dbg_msg_addr, fw_addr_chk_fw_status, + fw_addr_chk_dd_status, fw_addr_flag_reset_event}; + +u8 panel_mcf_data[512] = {0}; +static int hx_read_mcf_data(void); +/* CORE_IC */ +/* IC side start*/ +static void himax_mcu_burst_enable(uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[DATA_LEN_4]; + int ret; + + /*I("%s,Entering\n", __func__);*/ + tmp_data[0] = pic_op->data_conti[0]; + + ret = himax_bus_write(pic_op->addr_conti[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + tmp_data[0] = (pic_op->data_incr4[0] | auto_add_4_byte); + + ret = himax_bus_write(pic_op->addr_incr4[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } +} + +static int himax_mcu_register_read(uint8_t *read_addr, uint32_t read_length, + uint8_t *read_data, uint8_t cfg_flag) +{ + uint8_t tmp_data[DATA_LEN_4]; + int i = 0; + int address = 0; + int ret = 0; + + /*I("%s,Entering\n",__func__);*/ + + if (cfg_flag == false) { + if (read_length > FLASH_RW_MAX_LEN) { + E("%s: read len over %d!\n", __func__, + FLASH_RW_MAX_LEN); + return LENGTH_FAIL; + } + + if (read_length > DATA_LEN_4) + g_core_fp.fp_burst_enable(1); + else + g_core_fp.fp_burst_enable(0); + + address = (read_addr[3] << 24) + + (read_addr[2] << 16) + + (read_addr[1] << 8) + + read_addr[0]; + i = address; + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], + tmp_data, DATA_LEN_4, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + + tmp_data[0] = pic_op->data_ahb_access_direction_read[0]; + + ret = himax_bus_write(pic_op->addr_ahb_access_direction[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + + ret = himax_bus_read(pic_op->addr_ahb_rdata_byte_0[0], + read_data, + read_length, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + + if (read_length > DATA_LEN_4) + g_core_fp.fp_burst_enable(0); + + } else { + ret = himax_bus_read(read_addr[0], read_data, read_length, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + } + return NO_ERR; +} + +static int himax_mcu_flash_write_burst_lenth(uint8_t *reg_byte, + uint8_t *write_data, uint32_t length) +{ + uint8_t *data_byte; + int ret = 0; + + if (!g_internal_buffer) { + E("%s: internal buffer not initialized!\n", __func__); + return MEM_ALLOC_FAIL; + } + data_byte = g_internal_buffer; + + /* assign addr 4bytes */ + memcpy(data_byte, reg_byte, ADDR_LEN_4); + /* assign data n bytes */ + memcpy(data_byte + ADDR_LEN_4, write_data, length); + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], data_byte, + length + ADDR_LEN_4, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: xfer fail!\n", __func__); + return I2C_FAIL; + } + + return NO_ERR; +} + +static int himax_mcu_register_write(uint8_t *write_addr, uint32_t write_length, + uint8_t *write_data, uint8_t cfg_flag) +{ + int address; + uint8_t tmp_addr[4]; + uint8_t *tmp_data; + int total_read_times = 0; + uint32_t max_bus_size = MAX_I2C_TRANS_SZ; + uint32_t total_size_temp = 0; + unsigned int i = 0; + int ret = 0; + + /*I("%s,Entering\n", __func__);*/ + if (cfg_flag == 0) { + total_size_temp = write_length; +#if defined(HX_ZERO_FLASH) + max_bus_size = (write_length > HX_MAX_WRITE_SZ - 4) + ? (HX_MAX_WRITE_SZ - 4) + : write_length; +#endif + + tmp_addr[3] = write_addr[3]; + tmp_addr[2] = write_addr[2]; + tmp_addr[1] = write_addr[1]; + tmp_addr[0] = write_addr[0]; + + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + if (write_length > DATA_LEN_4) + g_core_fp.fp_burst_enable(1); + else + g_core_fp.fp_burst_enable(0); + + for (i = 0; i < (total_read_times); i++) { + /* I("[log]write %d time start!\n", i); + * I("[log]addr[3]=0x%02X, addr[2]=0x%02X, + addr[1]=0x%02X, addr[0]=0x%02X!\n", + tmp_addr[3], tmp_addr[2], + tmp_addr[1], tmp_addr[0]); + * I("%s, write addr = 0x%02X%02X%02X%02X\n", + __func__, tmp_addr[3], tmp_addr[2], + tmp_addr[1], tmp_addr[0]); + */ + + if (total_size_temp >= max_bus_size) { + tmp_data = write_data+(i * max_bus_size); + + ret = himax_mcu_flash_write_burst_lenth( + tmp_addr, + tmp_data, + max_bus_size); + if (ret < 0) { + I("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + total_size_temp = total_size_temp + - max_bus_size; + } else { + tmp_data = write_data+(i * max_bus_size); + /* I("last total_size_temp=%d\n", + * total_size_temp % max_bus_size); + */ + ret = himax_mcu_flash_write_burst_lenth( + tmp_addr, + tmp_data, + total_size_temp); + if (ret < 0) { + I("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + } + + /*I("[log]write %d time end!\n", i);*/ + address = ((i+1) * max_bus_size); + tmp_addr[0] = write_addr[0] + + (uint8_t) ((address) & 0x00FF); + + if (tmp_addr[0] < write_addr[0]) + tmp_addr[1] = write_addr[1] + + (uint8_t) ((address>>8) & 0x00FF) + + 1; + else + tmp_addr[1] = write_addr[1] + + (uint8_t) ((address>>8) & 0x00FF); + + udelay(100); + } + } else if (cfg_flag == 1) { + ret = himax_bus_write(write_addr[0], write_data, write_length, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return I2C_FAIL; + } + } else + E("%s: cfg_flag = %d, value is wrong!\n", __func__, cfg_flag); + + return NO_ERR; +} + +static int himax_write_read_reg(uint8_t *tmp_addr, uint8_t *tmp_data, + uint8_t hb, uint8_t lb) +{ + int cnt = 0; + uint8_t r_data[ADDR_LEN_4] = {0}; + + do { + if (r_data[1] != lb || r_data[0] != hb) + g_core_fp.fp_register_write(tmp_addr, DATA_LEN_4, + tmp_data, 0); + usleep_range(10000, 11000); + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, r_data, 0); + /* I("%s:Now r_data[0]=0x%02X,[1]=0x%02X, + * [2]=0x%02X,[3]=0x%02X\n", + * __func__, r_data[0], + * r_data[1], r_data[2], r_data[3]); + */ + } while ((r_data[1] != hb || r_data[0] != lb) && cnt++ < 100); + + if (cnt >= 100) { + g_core_fp.fp_read_FW_status(); + return HX_RW_REG_FAIL; + } + + return NO_ERR; +} + +static void himax_mcu_interface_on(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_data2[DATA_LEN_4]; + int cnt = 0; + int ret = 0; + + /* Read a dummy register to wake up I2C.*/ + ret = himax_bus_read(pic_op->addr_ahb_rdata_byte_0[0], tmp_data, + DATA_LEN_4, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) {/* to knock I2C*/ + E("%s: i2c access fail!\n", __func__); + return; + } + + do { + tmp_data[0] = pic_op->data_conti[0]; + + ret = himax_bus_write(pic_op->addr_conti[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + tmp_data[0] = pic_op->data_incr4[0]; + + ret = himax_bus_write(pic_op->addr_incr4[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + /*Check cmd*/ + himax_bus_read(pic_op->addr_conti[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + himax_bus_read(pic_op->addr_incr4[0], tmp_data2, 1, + HIMAX_I2C_RETRY_TIMES); + + if (tmp_data[0] == pic_op->data_conti[0] + && tmp_data2[0] == pic_op->data_incr4[0]) + break; + + usleep_range(1000, 1100); + } while (++cnt < 10); + + if (cnt > 0) + I("%s:Polling burst mode: %d times\n", __func__, cnt); +} + +#define WIP_PRT_LOG "%s: retry:%d, bf[0]=%d, bf[1]=%d,bf[2]=%d, bf[3]=%d\n" +static bool himax_mcu_wait_wip(int Timing) +{ + uint8_t tmp_data[DATA_LEN_4]; + int retry_cnt = 0; + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + DATA_LEN_4, pflash_op->data_spi200_trans_fmt, 0); + tmp_data[0] = 0x01; + + do { + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + DATA_LEN_4, + pflash_op->data_spi200_trans_ctrl_1, + 0); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + DATA_LEN_4, pflash_op->data_spi200_cmd_1, 0); + tmp_data[0] = tmp_data[1] = tmp_data[2] = tmp_data[3] = 0xFF; + g_core_fp.fp_register_read(pflash_op->addr_spi200_data, 4, + tmp_data, 0); + + if ((tmp_data[0] & 0x01) == 0x00) + return true; + + retry_cnt++; + + if (tmp_data[0] != 0x00 + || tmp_data[1] != 0x00 + || tmp_data[2] != 0x00 + || tmp_data[3] != 0x00) + I(WIP_PRT_LOG, + __func__, retry_cnt, tmp_data[0], + tmp_data[1], tmp_data[2], tmp_data[3]); + + if (retry_cnt > 100) { + E("%s: Wait wip error!\n", __func__); + return false; + } + + msleep(Timing); + } while ((tmp_data[0] & 0x01) == 0x01); + + return true; +} + +static void himax_mcu_sense_on(uint8_t FlashMode) +{ + uint8_t tmp_data[DATA_LEN_4]; + int retry = 0; + int ret = 0; + + I("Enter %s\n", __func__); + private_ts->notouch_frame = private_ts->ic_notouch_frame; + g_core_fp.fp_interface_on(); + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + sizeof(pfw_op->data_clear), pfw_op->data_clear, 0); + /*msleep(20);*/ + usleep_range(10000, 11000); + if (!FlashMode) { +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } else { + do { + g_core_fp.fp_register_read( + pfw_op->addr_flag_reset_event, + DATA_LEN_4, + tmp_data, + 0); + I("%s:Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + } while ((tmp_data[1] != 0x01 + || tmp_data[0] != 0x00) + && retry++ < 5); + + if (retry >= 5) { + E("%s: Fail:\n", __func__); +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } else { + I("%s:OK and Read status from IC = %X,%X\n", + __func__, tmp_data[0], tmp_data[1]); + /* reset code*/ + tmp_data[0] = 0x00; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) + E("%s: i2c access fail!\n", __func__); + + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) + E("%s: i2c access fail!\n", __func__); + } + } +} + +static bool himax_mcu_sense_off(bool check_en) +{ + uint8_t cnt = 0; + uint8_t tmp_data[DATA_LEN_4]; + int ret = 0; + + do { + tmp_data[0] = pic_op->data_i2c_psw_lb[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + tmp_data[0] = pic_op->data_i2c_psw_ub[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + g_core_fp.fp_register_read(pic_op->addr_cs_central_state, + ADDR_LEN_4, tmp_data, 0); + I("%s: Check enter_save_mode data[0]=%X\n", __func__, + tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + g_core_fp.fp_register_write(pic_op->addr_tcon_on_rst, + DATA_LEN_4, pic_op->data_rst, 0); + usleep_range(1000, 1100); + tmp_data[3] = pic_op->data_rst[3]; + tmp_data[2] = pic_op->data_rst[2]; + tmp_data[1] = pic_op->data_rst[1]; + tmp_data[0] = pic_op->data_rst[0] | 0x01; + g_core_fp.fp_register_write(pic_op->addr_tcon_on_rst, + DATA_LEN_4, tmp_data, 0); + + g_core_fp.fp_register_write(pic_op->addr_adc_on_rst, + DATA_LEN_4, pic_op->data_rst, 0); + usleep_range(1000, 1100); + tmp_data[3] = pic_op->data_rst[3]; + tmp_data[2] = pic_op->data_rst[2]; + tmp_data[1] = pic_op->data_rst[1]; + tmp_data[0] = pic_op->data_rst[0] | 0x01; + g_core_fp.fp_register_write(pic_op->addr_adc_on_rst, + DATA_LEN_4, tmp_data, 0); + goto TRUE_END; + } else { + /*msleep(10);*/ +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + } + } while (cnt++ < 15); + + return false; +TRUE_END: + return true; +} + +/*power saving level*/ +static void himax_mcu_init_psl(void) +{ + g_core_fp.fp_register_write(pic_op->addr_psl, + sizeof(pic_op->data_rst), + pic_op->data_rst, 0); + I("%s: power saving level reset OK!\n", __func__); +} + +static void himax_mcu_resume_ic_action(void) +{ + /* Nothing to do */ +} + +static void himax_mcu_suspend_ic_action(void) +{ + /* Nothing to do */ +} + +static void himax_mcu_power_on_init(void) +{ + uint8_t data[4] = {0}; + uint8_t retry = 0; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + sizeof(pfw_op->data_clear), pfw_op->data_clear, 0); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + /*FW reload done initial*/ + g_core_fp.fp_register_write(pdriver_op->addr_fw_define_2nd_flash_reload, + DATA_LEN_4, data, 0); + + g_core_fp.fp_sense_on(0x00); + + I("%s: waiting for FW reload done", __func__); + + while (retry++ < 30) { + g_core_fp.fp_register_read( + pdriver_op->addr_fw_define_2nd_flash_reload, + DATA_LEN_4, data, 0); + + /* use all 4 bytes to compare */ + if ((data[3] == 0x00 && data[2] == 0x00 && + data[1] == 0x72 && data[0] == 0xC0)) { + I("%s: FW finish reload done\n", __func__); + break; + } + I("%s: wait reload done %d times\n", __func__, retry); + g_core_fp.fp_read_FW_status(); + usleep_range(10000, 11000); + } + +#if 0 + g_core_fp.fp_read_FW_ver(); + g_core_fp.fp_touch_information(); + g_core_fp.fp_calc_touch_data_size(); + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + sizeof(pfw_op->data_clear), + pfw_op->data_clear, 0); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + /* g_core_fp.fp_sense_on(0x00); */ +#endif +} + +static bool himax_mcu_dd_clk_set(bool enable) +{ + uint8_t data[4] = {0}; + + data[0] = (enable)?1:0; + return (g_core_fp.fp_register_write(pic_op->adr_osc_en, + sizeof(pic_op->adr_osc_en), data, 0) == NO_ERR); +} + +static void himax_mcu_dd_reg_en(bool enable) +{ + uint8_t data[4] = {0}; + + g_core_fp.fp_dd_reg_read(0xCB, 8, 1, data, 0); + + if (data[0] != 0x44) { /*need DD Touch PW*/ + data[0] = 0xA5; data[1] = 0x00; + data[2] = 0x00; data[3] = 0x00; + g_core_fp.fp_register_write(pic_op->adr_osc_pw, + DATA_LEN_4, data, 0); + data[0] = 0x00; data[1] = 0x55; + data[2] = 0xAA; data[3] = 0x00; + g_core_fp.fp_dd_reg_write(0xEB, 0, 4, data, 0); + } + + data[0] = 0x00; data[1] = 0x83; + data[2] = 0x11; data[3] = 0x2A; + g_core_fp.fp_dd_reg_write(0xB9, 0, 4, data, 0); +} + +static bool himax_mcu_dd_reg_write(uint8_t addr, uint8_t pa_num, + int len, uint8_t *data, uint8_t bank) +{ + /*Calculate total write length*/ + uint32_t data_len = (((len + pa_num - 1) / 4 - pa_num / 4) + 1) * 4; + uint8_t w_data[32]; //w_data[data_len]; + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + bool *chk_data; + uint32_t chk_idx = 0; + int i = 0; + + chk_data = kcalloc(data_len, sizeof(bool), GFP_KERNEL); + if (chk_data == NULL) { + E("%s Allocate chk buf failed\n", __func__); + return false; + } + + memset(w_data, 0, data_len * sizeof(uint8_t)); + + /*put input data*/ + chk_idx = pa_num % 4; + for (i = 0; i < len; i++) { + w_data[chk_idx] = data[i]; + chk_data[chk_idx++] = true; + } + + /*get original data*/ + chk_idx = (pa_num / 4) * 4; + for (i = 0; i < data_len; i++) { + if (!chk_data[i]) { + g_core_fp.fp_dd_reg_read(addr, + (uint8_t)(chk_idx + i), + 1, + tmp_data, + bank); + + w_data[i] = tmp_data[0]; + chk_data[i] = true; + } + D("%s w_data[%d] = %2X\n", __func__, i, w_data[i]); + } + + tmp_addr[3] = 0x30; + tmp_addr[2] = addr >> 4; + tmp_addr[1] = (addr << 4) | (bank * 4); + tmp_addr[0] = chk_idx; + D("%s Addr = %02X%02X%02X%02X.\n", __func__, + tmp_addr[3], tmp_addr[2], + tmp_addr[1], tmp_addr[0]); + kfree(chk_data); + + return (g_core_fp.fp_register_write(tmp_addr, data_len, w_data, 0) + == NO_ERR); +} + +static bool himax_mcu_dd_reg_read(uint8_t addr, uint8_t pa_num, int len, + uint8_t *data, uint8_t bank) +{ + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + int i = 0; + + for (i = 0; i < len; i++) { + tmp_addr[3] = 0x30; + tmp_addr[2] = addr >> 4; + tmp_addr[1] = (addr << 4) | (bank * 4); + tmp_addr[0] = pa_num + i; + + if (g_core_fp.fp_register_read(tmp_addr, + DATA_LEN_4, tmp_data, 0)) + goto READ_FAIL; + + data[i] = tmp_data[0]; + + D("%s Addr = %02X%02X%02X%02X.data = %2X\n", __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0], + data[i]); + } + return true; + +READ_FAIL: + E("%s Read DD reg Failed.\n", __func__); + return false; +} + +static bool himax_mcu_ic_id_read(void) +{ + int i = 0; + uint8_t data[4] = {0}; + + g_core_fp.fp_dd_clk_set(true); + g_core_fp.fp_dd_reg_en(true); + + for (i = 0; i < 13; i++) { + data[0] = 0x28 + i; + g_core_fp.fp_dd_reg_write(0xBB, 2, 1, data, 0); + data[0] = 0x80; + g_core_fp.fp_dd_reg_write(0xBB, 4, 1, data, 0); + data[0] = 0x00; + g_core_fp.fp_dd_reg_write(0xBB, 4, 1, data, 0); + g_core_fp.fp_dd_reg_read(0xBB, 5, 1, data, 0); + ic_data->vendor_ic_id[i] = data[0]; + I("ic_data->vendor_ic_id[%d] = %02X\n", i, + ic_data->vendor_ic_id[i]); + } + + g_core_fp.fp_dd_clk_set(false); + + return true; +} + +/* IC side end*/ +/* CORE_IC */ + +/* CORE_FW */ +/* FW side start*/ +static void diag_mcu_parse_raw_data(struct himax_report_data *hx_touch_data, + int mul_num, int self_num, uint8_t diag_cmd, + int32_t *mutual_data, int32_t *self_data) +{ + int RawDataLen_word; + int index = 0; + int temp1, temp2, i; + + if (hx_touch_data->hx_rawdata_buf[0] + == pfw_op->data_rawdata_ready_lb[0] + && hx_touch_data->hx_rawdata_buf[1] + == pfw_op->data_rawdata_ready_hb[0] + && hx_touch_data->hx_rawdata_buf[2] > 0 + && hx_touch_data->hx_rawdata_buf[3] == diag_cmd) { + RawDataLen_word = hx_touch_data->rawdata_size / 2; + index = (hx_touch_data->hx_rawdata_buf[2] - 1) + * RawDataLen_word; + + /* I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n",index, + * buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + * I("RawDataLen=%d , RawDataLen_word=%d , + * hx_touch_info_size=%d\n", + * RawDataLen, RawDataLen_word, hx_touch_info_size); + */ + for (i = 0; i < RawDataLen_word; i++) { + temp1 = index + i; + + if (temp1 < mul_num) { /*mutual*/ + mutual_data[index + i] = + ((int8_t)hx_touch_data-> + hx_rawdata_buf[i * 2 + 4 + 1]) * 256 + + hx_touch_data-> + hx_rawdata_buf[i * 2 + 4]; + } else { /*self*/ + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + break; + + self_data[i + index - mul_num] = + (((int8_t)hx_touch_data-> + hx_rawdata_buf[i * 2 + 4 + 1]) << 8) + + hx_touch_data-> + hx_rawdata_buf[i * 2 + 4]; + } + } + } +} + +static void himax_mcu_system_reset(void) +{ +#if defined(HX_PON_PIN_SUPPORT) + g_core_fp.fp_register_write(pfw_op->addr_system_reset, + sizeof(pfw_op->data_system_reset), + pfw_op->data_system_reset, + 0); +#else + int ret = 0; + uint8_t tmp_data[DATA_LEN_4]; + int retry = 0; + + g_core_fp.fp_interface_on(); + g_core_fp.fp_register_write(pfw_op->addr_ctrl_fw_isr, + sizeof(pfw_op->data_clear), + pfw_op->data_clear, + 0); + do { + /* reset code*/ + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27 + */ + tmp_data[0] = pic_op->data_i2c_psw_lb[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) + E("%s: i2c access fail!\n", __func__); + + /** + * I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95 + */ + tmp_data[0] = pic_op->data_i2c_psw_ub[0]; + + ret = himax_bus_write(pic_op->adr_i2c_psw_ub[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) + E("%s: i2c access fail!\n", __func__); + + /** + * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x00 + */ + tmp_data[0] = 0x00; + + ret = himax_bus_write(pic_op->adr_i2c_psw_lb[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) + E("%s: i2c access fail!\n", __func__); + + usleep_range(10000, 11000); + + g_core_fp.fp_register_read(pfw_op->addr_flag_reset_event, + DATA_LEN_4, tmp_data, 0); + I("%s:Read status from IC = %X,%X\n", __func__, + tmp_data[0], tmp_data[1]); + } while ((tmp_data[1] != 0x02 || tmp_data[0] != 0x00) && retry++ < 5); +#endif +} + +static int himax_mcu_Calculate_CRC_with_AP(unsigned char *FW_content, + int CRC_from_FW, int len) +{ + int i, j, length = 0; + int fw_data; + int fw_data_2; + int CRC = 0xFFFFFFFF; + int PolyNomial = 0x82F63B78; + + length = len / 4; + + for (i = 0; i < length; i++) { + fw_data = FW_content[i * 4]; + + for (j = 1; j < 4; j++) { + fw_data_2 = FW_content[i * 4 + j]; + fw_data += (fw_data_2) << (8 * j); + } + CRC = fw_data ^ CRC; + for (j = 0; j < 32; j++) { + if ((CRC % 2) != 0) + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; + else + CRC = (((CRC >> 1) & 0x7FFFFFFF)); + } + } + + return CRC; +} + +static uint32_t himax_mcu_check_CRC(uint8_t *start_addr, int reload_length) +{ + uint32_t result = 0; + uint8_t tmp_data[DATA_LEN_4]; + int cnt = 0, ret = 0; + int length = reload_length / DATA_LEN_4; + + ret = g_core_fp.fp_register_write(pfw_op->addr_reload_addr_from, + DATA_LEN_4, start_addr, 0); + if (ret < NO_ERR) { + E("%s: i2c access fail!\n", __func__); + return HW_CRC_FAIL; + } + + tmp_data[3] = 0x00; + tmp_data[2] = 0x99; + tmp_data[1] = (length >> 8); + tmp_data[0] = length; + ret = g_core_fp.fp_register_write(pfw_op->addr_reload_addr_cmd_beat, + DATA_LEN_4, tmp_data, 0); + if (ret < NO_ERR) { + E("%s: i2c access fail!\n", __func__); + return HW_CRC_FAIL; + } + cnt = 0; + + do { + ret = g_core_fp.fp_register_read(pfw_op->addr_reload_status, + DATA_LEN_4, tmp_data, 0); + if (ret < NO_ERR) { + E("%s: i2c access fail!\n", __func__); + return HW_CRC_FAIL; + } + + if ((tmp_data[0] & 0x01) != 0x01) { + ret = g_core_fp.fp_register_read( + pfw_op->addr_reload_crc32_result, + DATA_LEN_4, + tmp_data, + 0); + if (ret < NO_ERR) { + E("%s: i2c access fail!\n", __func__); + return HW_CRC_FAIL; + } + I("%s:data[3]=%X,data[2]=%X,data[1]=%X,data[0]=%X\n", + __func__, + tmp_data[3], + tmp_data[2], + tmp_data[1], + tmp_data[0]); + result = ((tmp_data[3] << 24) + + (tmp_data[2] << 16) + + (tmp_data[1] << 8) + + tmp_data[0]); + goto END; + } else { + I("Waiting for HW ready!\n"); + usleep_range(1000, 1100); + if (cnt >= 100) + g_core_fp.fp_read_FW_status(); + } + + } while (cnt++ < 100); +END: + return result; +} + +static void himax_mcu_set_reload_cmd(uint8_t *write_data, int idx, + uint32_t cmd_from, uint32_t cmd_to, uint32_t cmd_beat) +{ + int index = idx * 12; + int i; + + for (i = 3; i >= 0; i--) { + write_data[index + i] = (cmd_from >> (8 * i)); + write_data[index + 4 + i] = (cmd_to >> (8 * i)); + write_data[index + 8 + i] = (cmd_beat >> (8 * i)); + } +} + +static bool himax_mcu_program_reload(void) +{ + return true; +} + +#if defined(HX_ULTRA_LOW_POWER) +static int himax_mcu_ulpm_in(void) +{ + uint8_t tmp_data[4]; + int rtimes = 0; + int ret = 0; + + I("%s:entering\n", __func__); + + /* 34 -> 11 */ + do { + if (rtimes > 10) { + I("%s:1/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_34[0], + pfw_op->data_ulpm_11, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_34[0], + tmp_data, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x34,correct 0x11=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_11[0]); + + rtimes = 0; + /* 34 -> 11 */ + do { + if (rtimes > 10) { + I("%s:2/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_34[0], + pfw_op->data_ulpm_11, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_34[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x34,correct 0x11=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_11[0]); + + /* 33 -> 33 */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:3/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_33, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33,correct 0x33=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_33[0]); + + /* 34 -> 22 */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:4/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_34[0], + pfw_op->data_ulpm_22, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_34[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x34,correct 0x22=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_22[0]); + + /* 33 -> AA */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:5/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_aa, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33, correct 0xAA=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_aa[0]); + + /* 33 -> 33 */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:6/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_33, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33,correct 0x33=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_33[0]); + + /* 33 -> AA */ + rtimes = 0; + do { + if (rtimes > 10) { + I("%s:7/7 retry over 10 times!\n", __func__); + return false; + } + ret = himax_bus_write(pfw_op->addr_ulpm_33[0], + pfw_op->data_ulpm_aa, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi write fail!\n", __func__); + continue; + } + ret = himax_bus_read(pfw_op->addr_ulpm_33[0], tmp_data, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + I("%s: spi read fail!\n", __func__); + continue; + } + + I("%s:retry times %d,addr=0x33,correct 0xAA=current 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != pfw_op->data_ulpm_aa[0]); + + I("%s:END\n", __func__); + return true; +} + +static int himax_mcu_black_gest_ctrl(bool enable) +{ + int ret = 0; + + I("%s:enable=%d, ts->is_suspended=%d\n", __func__, + enable, private_ts->suspended); + + if (private_ts->suspended) { + if (enable) { +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + I("%s: Please enable TP reset define\n", __func__); +#endif + } else { + g_core_fp.fp_ulpm_in(); + } + } else { + g_core_fp.fp_sense_on(0); + } + return ret; +} +#endif + +static void himax_mcu_set_SMWP_enable(uint8_t SMWP_enable, bool suspended) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t retry_cnt = 0; + + do { + if (SMWP_enable) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_smwp_enable, + DATA_LEN_4, tmp_data, 0); + himax_parse_assign_cmd(fw_func_handshaking_pwd, + back_data, 4); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + g_core_fp.fp_register_write(pfw_op->addr_smwp_enable, + DATA_LEN_4, + tmp_data, + 0); + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + back_data, + 4); + } + + g_core_fp.fp_register_read(pfw_op->addr_smwp_enable, DATA_LEN_4, + tmp_data, 0); + /*I("%s: tmp_data[0]=%d, SMWP_enable=%d, retry_cnt=%d\n", + * __func__, tmp_data[0],SMWP_enable,retry_cnt); + */ + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +static void himax_mcu_set_HSEN_enable(uint8_t HSEN_enable, bool suspended) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t retry_cnt = 0; + + do { + if (HSEN_enable) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_hsen_enable, + DATA_LEN_4, tmp_data, 0); + himax_parse_assign_cmd(fw_func_handshaking_pwd, + back_data, 4); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + + g_core_fp.fp_register_write(pfw_op->addr_hsen_enable, + DATA_LEN_4, tmp_data, 0); + + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + back_data, + 4); + } + + g_core_fp.fp_register_read(pfw_op->addr_hsen_enable, + DATA_LEN_4, tmp_data, 0); + /*I("%s: tmp_data[0]=%d, HSEN_enable=%d, retry_cnt=%d\n", + * __func__, tmp_data[0],HSEN_enable,retry_cnt); + */ + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +static void himax_mcu_usb_detect_set(uint8_t *cable_config) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t retry_cnt = 0; + + do { + if (cable_config[1] == 0x01) { + himax_parse_assign_cmd(fw_func_handshaking_pwd, + tmp_data, 4); + g_core_fp.fp_register_write(pfw_op->addr_usb_detect, + DATA_LEN_4, tmp_data, 0); + himax_parse_assign_cmd(fw_func_handshaking_pwd, + back_data, 4); + I("%s: USB detect status IN!\n", __func__); + } else { + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + tmp_data, + 4); + g_core_fp.fp_register_write(pfw_op->addr_usb_detect, + DATA_LEN_4, tmp_data, 0); + himax_parse_assign_cmd( + fw_data_safe_mode_release_pw_reset, + back_data, + 4); + I("%s: USB detect status OUT!\n", __func__); + } + + g_core_fp.fp_register_read(pfw_op->addr_usb_detect, DATA_LEN_4, + tmp_data, 0); + /*I("%s: tmp_data[0]=%d, USB detect=%d, retry_cnt=%d\n", + * __func__, tmp_data[0],cable_config[1] ,retry_cnt); + */ + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +#define PRT_DATA "%s:[3]=0x%2X, [2]=0x%2X, [1]=0x%2X, [0]=0x%2X\n" +static void himax_mcu_diag_register_set(uint8_t diag_command, + uint8_t storage_type, bool is_dirly) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t back_data[DATA_LEN_4]; + uint8_t cnt = 50; + + if (diag_command > 0 && storage_type % 8 > 0 && !is_dirly) + tmp_data[0] = diag_command + 0x08; + else + tmp_data[0] = diag_command; + I("diag_command = %d, tmp_data[0] = %X\n", diag_command, tmp_data[0]); + g_core_fp.fp_interface_on(); + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; + do { + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + DATA_LEN_4, tmp_data, 0); + g_core_fp.fp_register_read(pfw_op->addr_raw_out_sel, + DATA_LEN_4, back_data, 0); + I(PRT_DATA, __func__, + back_data[3], + back_data[2], + back_data[1], + back_data[0]); + cnt--; + } while (tmp_data[0] != back_data[0] && cnt > 0); +} + +static int himax_mcu_chip_self_test(struct seq_file *s, void *v) +{ + uint8_t tmp_data[FLASH_WRITE_BURST_SZ]; + uint8_t self_test_info[20]; + int pf_value = 0x00; + uint8_t test_result_id = 0; + int i; + + memset(tmp_data, 0x00, sizeof(tmp_data)); + g_core_fp.fp_interface_on(); + g_core_fp.fp_sense_off(true); + g_core_fp.fp_burst_enable(1); + g_core_fp.fp_register_write(pfw_op->addr_selftest_addr_en, DATA_LEN_4, + pfw_op->data_selftest_request, 0); + /*Set criteria 0x10007F1C [0,1]=aa/up,down=, [2-3]=key/up,down, + * [4-5]=avg/up,down + */ + tmp_data[0] = pfw_op->data_criteria_aa_top[0]; + tmp_data[1] = pfw_op->data_criteria_aa_bot[0]; + tmp_data[2] = pfw_op->data_criteria_key_top[0]; + tmp_data[3] = pfw_op->data_criteria_key_bot[0]; + tmp_data[4] = pfw_op->data_criteria_avg_top[0]; + tmp_data[5] = pfw_op->data_criteria_avg_bot[0]; + tmp_data[6] = 0x00; + tmp_data[7] = 0x00; + g_core_fp.fp_register_write(pfw_op->addr_criteria_addr, + FLASH_WRITE_BURST_SZ, tmp_data, 0); + g_core_fp.fp_register_write(pfw_op->addr_set_frame_addr, + DATA_LEN_4, pfw_op->data_set_frame, 0); + /*Disable IDLE Mode*/ + g_core_fp.fp_idle_mode(1); + /*Diable Flash Reload*/ + g_core_fp.fp_reload_disable(1); + /*start selftest // leave safe mode*/ + g_core_fp.fp_sense_on(0x01); + + /*Hand shaking*/ + for (i = 0; i < 1000; i++) { + g_core_fp.fp_register_read(pfw_op->addr_selftest_addr_en, 4, + tmp_data, 0); + I("%s:data0=0x%2X,data1=0x%2X,data2=0x%2X,data3=0x%2X cnt=%d\n", + __func__, + tmp_data[0], + tmp_data[1], + tmp_data[2], + tmp_data[3], + i); + usleep_range(10000, 11000); + + if (tmp_data[1] == pfw_op->data_selftest_ack_hb[0] + && tmp_data[0] == pfw_op->data_selftest_ack_lb[0]) { + I("%s Data ready goto moving data\n", __func__); + break; + } + } + + g_core_fp.fp_sense_off(true); + msleep(20); + /** + * Read test result ==> bit[2][1][0] = [key][AA][avg] => 0xF = PASS + */ + g_core_fp.fp_register_read(pfw_op->addr_selftest_result_addr, 20, + self_test_info, 0); + test_result_id = self_test_info[0]; + I("%s: check test result, test_result_id=%x, test_result=%x\n", + __func__, test_result_id, self_test_info[0]); + I("raw top 1 = %d\n", self_test_info[3] * 256 + self_test_info[2]); + I("raw top 2 = %d\n", self_test_info[5] * 256 + self_test_info[4]); + I("raw top 3 = %d\n", self_test_info[7] * 256 + self_test_info[6]); + I("raw last 1 = %d\n", self_test_info[9] * 256 + self_test_info[8]); + I("raw last 2 = %d\n", self_test_info[11] * 256 + self_test_info[10]); + I("raw last 3 = %d\n", self_test_info[13] * 256 + self_test_info[12]); + I("raw key 1 = %d\n", self_test_info[15] * 256 + self_test_info[14]); + I("raw key 2 = %d\n", self_test_info[17] * 256 + self_test_info[16]); + I("raw key 3 = %d\n", self_test_info[19] * 256 + self_test_info[18]); + + if (test_result_id == pfw_op->data_selftest_pass[0]) { + I("[Himax]: self-test pass\n"); + seq_puts(s, "Self_Test Pass:\n"); + pf_value = 0x0; + } else { + E("[Himax]: self-test fail\n"); + seq_puts(s, "Self_Test Fail:\n"); + /* E("[Himax]: bank_avg = %d, bank_max = %d,%d,%d, bank_min = + * %d,%d,%d, key = %d,%d,%d\n", + * tmp_data[1], tmp_data[2], + * tmp_data[3], tmp_data[4], + * tmp_data[5], tmp_data[6], + * tmp_data[7], tmp_data[8], + * tmp_data[9], tmp_data[10]); + */ + pf_value = 0x1; + } + + /*Enable IDLE Mode*/ + g_core_fp.fp_idle_mode(0); +#if !defined(HX_ZERO_FLASH) + /* Enable Flash Reload //recovery*/ + g_core_fp.fp_reload_disable(0); +#endif + g_core_fp.fp_sense_on(0x00); + msleep(120); + + return pf_value; +} + +#define PRT_TMP_DATA "%s:[0]=0x%2X,[1]=0x%2X, [2]=0x%2X,[3]=0x%2X\n" +static void himax_mcu_idle_mode(int disable) +{ + int retry = 20; + uint8_t tmp_data[DATA_LEN_4]; + uint8_t switch_cmd = 0x00; + + I("%s:entering\n", __func__); + + do { + I("%s,now %d times!\n", __func__, retry); + g_core_fp.fp_register_read(pfw_op->addr_fw_mode_status, + DATA_LEN_4, tmp_data, 0); + + if (disable) + switch_cmd = pfw_op->data_idle_dis_pwd[0]; + else + switch_cmd = pfw_op->data_idle_en_pwd[0]; + + tmp_data[0] = switch_cmd; + g_core_fp.fp_register_write(pfw_op->addr_fw_mode_status, + DATA_LEN_4, tmp_data, 0); + g_core_fp.fp_register_read(pfw_op->addr_fw_mode_status, + DATA_LEN_4, tmp_data, 0); + + I(PRT_TMP_DATA, + __func__, + tmp_data[0], + tmp_data[1], + tmp_data[2], + tmp_data[3]); + + retry--; + usleep_range(10000, 11000); + } while ((tmp_data[0] != switch_cmd) && retry > 0); + + I("%s: setting OK!\n", __func__); +} + +static void himax_mcu_reload_disable(int disable) +{ + I("%s:entering\n", __func__); + + if (disable) { /*reload disable*/ + g_core_fp.fp_register_write( + pdriver_op->addr_fw_define_flash_reload, + DATA_LEN_4, + pdriver_op->data_fw_define_flash_reload_dis, + 0); + } else { /*reload enable*/ + g_core_fp.fp_register_write( + pdriver_op->addr_fw_define_flash_reload, + DATA_LEN_4, + pdriver_op->data_fw_define_flash_reload_en, + 0); + } + + I("%s: setting OK!\n", __func__); +} + +static bool himax_mcu_check_chip_version(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t ret_data = false; + int i = 0; + + for (i = 0; i < 5; i++) { + g_core_fp.fp_register_read(pfw_op->addr_icid_addr, DATA_LEN_4, + tmp_data, 0); + I("%s:Read driver IC ID = %X,%X,%X\n", __func__, + tmp_data[3], tmp_data[2], tmp_data[1]); + + if ((tmp_data[3] == 0x83) + && (tmp_data[2] == 0x10) + && (tmp_data[1] == 0x2a)) { + strlcpy(private_ts->chip_name, + HX_83102A_SERIES_PWON, 30); + ret_data = true; + goto END; + } else { + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + } + } +END: + return ret_data; +} + +static int himax_mcu_read_ic_trigger_type(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + int trigger_type = false; + + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_int_is_edge, + DATA_LEN_4, tmp_data, 0); + + if ((tmp_data[1] & 0x01) == 1) + trigger_type = true; + + return trigger_type; +} + +static int himax_mcu_read_i2c_status(void) +{ + return i2c_error_count; +} + +/* Please call this function after FW finish reload done */ +static void himax_mcu_read_FW_ver(void) +{ + uint8_t data[12] = {0}; +#if 0 + uint8_t retry = 0; + uint8_t reload_status = 0; + + g_core_fp.fp_register_write( + pdriver_op->addr_fw_define_2nd_flash_reload, + DATA_LEN_4, + data, + 0); + + g_core_fp.fp_sense_on(0x00); + + I("%s: waiting for FW reload done\n", __func__); + + while (reload_status == 0) { + g_core_fp.fp_register_read( + pdriver_op->addr_fw_define_2nd_flash_reload, + DATA_LEN_4, + data, + 0); + + /* use all 4 bytes to compare */ + if ((data[3] == 0x00 && data[2] == 0x00 && + data[1] == 0x72 && data[0] == 0xC0)) { + I("%s: FW finish reload done\n", __func__); + reload_status = 1; + break; + } else if (retry == 200) { + E("%s: FW fail reload done !!!!!\n", __func__); + ic_data->vendor_panel_ver = 0; + ic_data->vendor_fw_ver = 0; + ic_data->vendor_config_ver = 0; + ic_data->vendor_touch_cfg_ver = 0; + ic_data->vendor_display_cfg_ver = 0; + ic_data->vendor_cid_maj_ver = 0; + ic_data->vendor_cid_min_ver = 0; + goto END; + } else { + I("%s: wait reload done %d times\n", __func__, retry); + g_core_fp.fp_read_FW_status(); + retry++; + usleep_range(10000, 11000); + } + } + + /** + * Read FW version + */ + g_core_fp.fp_sense_off(true); +#endif + + g_core_fp.fp_register_read(pfw_op->addr_fw_ver_addr, DATA_LEN_4, + data, 0); + ic_data->vendor_panel_ver = data[0]; + ic_data->vendor_fw_ver = data[1] << 8 | data[2]; + I("PANEL_VER : %X\n", ic_data->vendor_panel_ver); + I("FW_VER : %X\n", ic_data->vendor_fw_ver); + g_core_fp.fp_register_read(pfw_op->addr_fw_cfg_addr, DATA_LEN_4, + data, 0); + ic_data->vendor_config_ver = data[2] << 8 | data[3]; + /*I("CFG_VER : %X\n",ic_data->vendor_config_ver);*/ + ic_data->vendor_touch_cfg_ver = data[2]; + I("TOUCH_VER : %X\n", ic_data->vendor_touch_cfg_ver); + ic_data->vendor_display_cfg_ver = data[3]; + I("DISPLAY_VER : %X\n", ic_data->vendor_display_cfg_ver); + g_core_fp.fp_register_read(pfw_op->addr_fw_vendor_addr, + DATA_LEN_4, data, 0); + ic_data->vendor_cid_maj_ver = data[2]; + ic_data->vendor_cid_min_ver = data[3]; + I("CID_VER : %X\n", (ic_data->vendor_cid_maj_ver << 8 + | ic_data->vendor_cid_min_ver)); + g_core_fp.fp_register_read(pfw_op->addr_cus_info, 12, data, 0); + memcpy(ic_data->vendor_cus_info, data, 12); + I("Cusomer ID = %s\n", ic_data->vendor_cus_info); + g_core_fp.fp_register_read(pfw_op->addr_proj_info, 12, data, 0); + memcpy(ic_data->vendor_proj_info, data, 12); + I("Project ID = %s\n", ic_data->vendor_proj_info); +#if 0 +END: + return; +#endif +} + +static bool himax_mcu_read_event_stack(uint8_t *buf, uint8_t length) +{ + uint8_t cmd[DATA_LEN_4]; + struct timespec t_start, t_end, t_delta; + int len = length; + int i2c_speed = 0; + int ret = 0; + + /* AHB_I2C Burst Read Off */ + cmd[0] = pfw_op->data_ahb_dis[0]; + + ret = himax_bus_write(pfw_op->addr_ahb_addr[0], cmd, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + if (private_ts->debug_log_level & BIT(2)) + getnstimeofday(&t_start); + + himax_bus_read(pfw_op->addr_event_addr[0], buf, length, + HIMAX_I2C_RETRY_TIMES); + + if (private_ts->debug_log_level & BIT(2)) { + getnstimeofday(&t_end); + t_delta.tv_nsec = (t_end.tv_sec * 1000000000 + t_end.tv_nsec) + - (t_start.tv_sec * 1000000000 + t_start.tv_nsec); + + i2c_speed = (len * 9 * 1000000 + / (int)t_delta.tv_nsec) * 13 / 10; + private_ts->bus_speed = (int)i2c_speed; + } + + /* AHB_I2C Burst Read On */ + cmd[0] = pfw_op->data_ahb_en[0]; + + ret = himax_bus_write(pfw_op->addr_ahb_addr[0], cmd, 1, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return 0; + } + + return 1; +} + +static void himax_mcu_return_event_stack(void) +{ + int retry = 20, i; + uint8_t tmp_data[DATA_LEN_4]; + + I("%s:entering\n", __func__); + + do { + I("now %d times!\n", retry); + + for (i = 0; i < DATA_LEN_4; i++) + tmp_data[i] = psram_op->addr_rawdata_end[i]; + + g_core_fp.fp_register_write(psram_op->addr_rawdata_addr, + DATA_LEN_4, tmp_data, 0); + g_core_fp.fp_register_read(psram_op->addr_rawdata_addr, + DATA_LEN_4, tmp_data, 0); + retry--; + usleep_range(10000, 11000); + } while ((tmp_data[1] != psram_op->addr_rawdata_end[1] + && tmp_data[0] != psram_op->addr_rawdata_end[0]) + && retry > 0); + + I("%s: End of setting!\n", __func__); +} + +static bool himax_mcu_calculateChecksum(bool change_iref, uint32_t size) +{ + uint8_t CRC_result = 0, i; + uint8_t tmp_data[DATA_LEN_4]; + + I("%s:Now size=%d\n", __func__, size); + for (i = 0; i < DATA_LEN_4; i++) + tmp_data[i] = psram_op->addr_rawdata_end[i]; + + CRC_result = g_core_fp.fp_check_CRC(tmp_data, size); + msleep(50); + + if (CRC_result != 0) + I("%s: CRC Fail=%d\n", __func__, CRC_result); + + return (CRC_result == 0) ? true : false; +} + +static void himax_mcu_read_FW_status(void) +{ + uint8_t len = 0; + uint8_t i = 0; + uint8_t addr[4] = {0}; + uint8_t data[4] = {0}; + + len = (uint8_t)(sizeof(dbg_reg_ary)/sizeof(uint32_t)); + + for (i = 0; i < len; i++) { + himax_parse_assign_cmd(dbg_reg_ary[i], addr, 4); + g_core_fp.fp_register_read(addr, DATA_LEN_4, data, 0); + + I("reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + dbg_reg_ary[i], data[0], data[1], data[2], data[3]); + } +} + +static void himax_mcu_irq_switch(int switch_on) +{ + if (switch_on) { + if (private_ts->use_irq) + himax_int_enable(switch_on); + else + hrtimer_start(&private_ts->timer, ktime_set(1, 0), + HRTIMER_MODE_REL); + + } else { + if (private_ts->use_irq) + himax_int_enable(switch_on); + else { + hrtimer_cancel(&private_ts->timer); + cancel_work_sync(&private_ts->work); + } + } +} + +static int himax_mcu_assign_sorting_mode(uint8_t *tmp_data) +{ + I("%s:addr: 0x%02X%02X%02X%02X, write to:0x%02X%02X%02X%02X\n", + __func__, + pfw_op->addr_sorting_mode_en[3], + pfw_op->addr_sorting_mode_en[2], + pfw_op->addr_sorting_mode_en[1], + pfw_op->addr_sorting_mode_en[0], + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + + g_core_fp.fp_register_write(pfw_op->addr_sorting_mode_en, + DATA_LEN_4, tmp_data, 0); + + return NO_ERR; +} + +static int himax_mcu_check_sorting_mode(uint8_t *tmp_data) +{ + + g_core_fp.fp_register_read(pfw_op->addr_sorting_mode_en, + DATA_LEN_4, tmp_data, 0); + I("%s:addr: 0x%02X%02X%02X%02X, Now is:0x%02X%02X%02X%02X\n", + __func__, + pfw_op->addr_sorting_mode_en[3], + pfw_op->addr_sorting_mode_en[2], + pfw_op->addr_sorting_mode_en[1], + pfw_op->addr_sorting_mode_en[0], + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + + return NO_ERR; +} + +static uint8_t himax_mcu_read_DD_status(uint8_t *cmd_set, uint8_t *tmp_data) +{ + int cnt = 0; + uint8_t req_size = cmd_set[0]; + + cmd_set[3] = pfw_op->data_dd_request[0]; + g_core_fp.fp_register_write(pfw_op->addr_dd_handshak_addr, + DATA_LEN_4, cmd_set, 0); + I("%s:cmd set[0]=0x%2X,set[1]=0x%2X,set[2]=0x%2X,set[3]=0x%2X\n", + __func__, cmd_set[0], cmd_set[1], cmd_set[2], cmd_set[3]); + + /* Doing hand shaking 0xAA -> 0xBB */ + for (cnt = 0; cnt < 100; cnt++) { + g_core_fp.fp_register_read(pfw_op->addr_dd_handshak_addr, + DATA_LEN_4, tmp_data, 0); + usleep_range(10000, 11000); + + if (tmp_data[3] == pfw_op->data_dd_ack[0]) { + I("%s Data ready goto moving data\n", __func__); + goto FINALIZE; + } else { + if (cnt >= 99) { + I("%s Data not ready in FW\n", __func__); + return FW_NOT_READY; + } + } + } +FINALIZE: + g_core_fp.fp_register_read(pfw_op->addr_dd_data_addr, + req_size, tmp_data, 0); + return NO_ERR; +} +static void hx_clr_fw_reord_dd_sts(void) +{ + uint8_t tmp_data[DATA_LEN_4] = {0}; + + g_core_fp.fp_register_read(pic_op->addr_cs_central_state, + ADDR_LEN_4, tmp_data, 0); + I("%s: Check enter_save_mode data[0]=%02X\n", __func__, tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + I("%s: Enter safe mode, OK!\n", __func__); + } else { + E("%s: It doen't enter safe mode, please check it again\n", + __func__); + return; + } + g_core_fp.fp_register_read(pfw_op->addr_clr_fw_record_dd_sts, + DATA_LEN_4, tmp_data, 0); + I("%s,Before Write :Now 10007FCC=0x%02X%02X%02X%02X\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + usleep_range(10000, 10001); + + tmp_data[2] = 0x00; + tmp_data[3] = 0x00; + g_core_fp.fp_register_write(pfw_op->addr_clr_fw_record_dd_sts, + DATA_LEN_4, tmp_data, 0); + usleep_range(10000, 10001); + + g_core_fp.fp_register_read(pfw_op->addr_clr_fw_record_dd_sts, + DATA_LEN_4, tmp_data, 0); + I("%s,After Write :Now 10007FCC=0x%02X%02X%02X%02X\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + +} + +static void hx_ap_notify_fw_sus(int suspend) +{ + int retry = 0; + uint8_t read_tmp[DATA_LEN_4] = {0}; + uint8_t addr_tmp[DATA_LEN_4] = {0}; + uint8_t data_tmp[DATA_LEN_4] = {0}; + + Arr4_to_Arr4(addr_tmp, pfw_op->addr_ap_notify_fw_sus); + + if (suspend) { + I("%s,Suspend mode!\n", __func__); + Arr4_to_Arr4(data_tmp, pfw_op->data_ap_notify_fw_sus_en); + } else { + I("%s,NonSuspend mode!\n", __func__); + Arr4_to_Arr4(data_tmp, pfw_op->data_ap_notify_fw_sus_dis); + } + + I("%s: R%02X%02X%02X%02XH<-0x%02X%02X%02X%02X\n", + __func__, + addr_tmp[3], addr_tmp[2], addr_tmp[1], addr_tmp[0], + data_tmp[3], data_tmp[2], data_tmp[1], data_tmp[0]); + do { + g_core_fp.fp_register_write(addr_tmp, + sizeof(data_tmp), data_tmp, 0); + usleep_range(1000, 1001); + g_core_fp.fp_register_read(addr_tmp, + sizeof(data_tmp), read_tmp, 0); + I("%s: Now retry=%d, data=0x%02X%02X%02X%02X\n", + __func__, retry, + read_tmp[3], read_tmp[2], read_tmp[1], read_tmp[0]); + } while ((retry++ < 10) && + (read_tmp[3] != data_tmp[3] && read_tmp[2] != data_tmp[2] && + read_tmp[1] != data_tmp[1] && read_tmp[0] != data_tmp[0])); +} +/* FW side end*/ +/* CORE_FW */ + +/* CORE_FLASH */ +/* FLASH side start*/ +static void himax_mcu_chip_erase(void) +{ + g_core_fp.fp_interface_on(); + + /* Reset power saving level */ + if (g_core_fp.fp_init_psl != NULL) + g_core_fp.fp_init_psl(); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + DATA_LEN_4, pflash_op->data_spi200_trans_fmt, 0); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + DATA_LEN_4, pflash_op->data_spi200_trans_ctrl_2, 0); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + DATA_LEN_4, pflash_op->data_spi200_cmd_2, 0); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + DATA_LEN_4, pflash_op->data_spi200_cmd_3, 0); + msleep(2000); + + if (!g_core_fp.fp_wait_wip(100)) + E("%s: Chip_Erase Fail\n", __func__); + +} + +static bool himax_mcu_block_erase(int start_addr, int length) +{ + uint32_t page_prog_start = 0; + uint32_t block_size = 0x10000; + + uint8_t tmp_data[4] = {0}; + + g_core_fp.fp_interface_on(); + + g_core_fp.fp_init_psl(); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + DATA_LEN_4, pflash_op->data_spi200_trans_fmt, 0); + + for (page_prog_start = start_addr; + page_prog_start < start_addr + length; + page_prog_start = page_prog_start + block_size) { + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + DATA_LEN_4, pflash_op->data_spi200_trans_ctrl_2, 0); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + DATA_LEN_4, pflash_op->data_spi200_cmd_2, 0); + + tmp_data[3] = (page_prog_start >> 24)&0xFF; + tmp_data[2] = (page_prog_start >> 16)&0xFF; + tmp_data[1] = (page_prog_start >> 8)&0xFF; + tmp_data[0] = page_prog_start&0xFF; + g_core_fp.fp_register_write(pflash_op->addr_spi200_addr, + DATA_LEN_4, tmp_data, 0); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + DATA_LEN_4, pflash_op->data_spi200_trans_ctrl_3, 0); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + DATA_LEN_4, pflash_op->data_spi200_cmd_4, 0); + msleep(1000); + + if (!g_core_fp.fp_wait_wip(100)) { + E("%s:Erase Fail\n", __func__); + return false; + } + } + + I("%s:END\n", __func__); + return true; +} + +static bool himax_mcu_sector_erase(int start_addr) +{ + return true; +} + +static void himax_mcu_flash_programming(uint8_t *FW_content, int FW_Size) +{ + int page_prog_start = 0, i = 0, j = 0, k = 0; + int program_length = PROGRAM_SZ; + uint8_t tmp_data[DATA_LEN_4]; + uint8_t buring_data[FLASH_RW_MAX_LEN]; + int ret = 0; + /* 4 bytes for padding*/ + g_core_fp.fp_interface_on(); + + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_fmt, + DATA_LEN_4, pflash_op->data_spi200_trans_fmt, 0); + + for (page_prog_start = 0; page_prog_start < FW_Size; + page_prog_start += FLASH_RW_MAX_LEN) { + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + DATA_LEN_4, pflash_op->data_spi200_trans_ctrl_2, 0); + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + DATA_LEN_4, pflash_op->data_spi200_cmd_2, 0); + + /*Programmable size = 1 page = 256 bytes,*/ + /*word_number = 256 byte / 4 = 64*/ + g_core_fp.fp_register_write(pflash_op->addr_spi200_trans_ctrl, + DATA_LEN_4, pflash_op->data_spi200_trans_ctrl_4, 0); + + /* Flash start address 1st : 0x0000_0000*/ + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + g_core_fp.fp_register_write(pflash_op->addr_spi200_addr, + DATA_LEN_4, tmp_data, 0); + + for (i = 0; i < ADDR_LEN_4; i++) + buring_data[i] = pflash_op->addr_spi200_data[i]; + + for (i = page_prog_start, j = 0; + i < 16 + page_prog_start; + i++, j++) { + buring_data[j + ADDR_LEN_4] = FW_content[i]; + } + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], + buring_data, + ADDR_LEN_4 + 16, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + g_core_fp.fp_register_write(pflash_op->addr_spi200_cmd, + DATA_LEN_4, pflash_op->data_spi200_cmd_6, 0); + + for (j = 0; j < 5; j++) { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; + i < (page_prog_start + 16 + (j * 48)) + program_length; + i++, k++) + buring_data[k + ADDR_LEN_4] = FW_content[i]; + + ret = himax_bus_write(pic_op->addr_ahb_addr_byte_0[0], + buring_data, + program_length + ADDR_LEN_4, + HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } + + if (!g_core_fp.fp_wait_wip(1)) + E("%s:Flash_Programming Fail\n", __func__); + + } +} + +static void himax_mcu_flash_page_write(uint8_t *write_addr, int length, + uint8_t *write_data) +{ +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_32k(unsigned char *fw, + int len, bool change_iref) +{ + /* Not use */ + return 0; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_60k(unsigned char *fw, + int len, bool change_iref) +{ + /* Not use */ + return 0; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_64k(unsigned char *fw, + int len, bool change_iref) +{ + int burnFW_success = 0; + + if (len != FW_SIZE_64k) { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + g_core_fp.fp_sense_off(true); + g_core_fp.fp_block_erase(0x00, FW_SIZE_64k); + g_core_fp.fp_flash_programming(fw, FW_SIZE_64k); + + if (g_core_fp.fp_check_CRC(pfw_op->addr_program_reload_from, + FW_SIZE_64k) == 0) + burnFW_success = 1; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + sizeof(pfw_op->data_clear), pfw_op->data_clear, 0); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + /*System reset*/ + g_core_fp.fp_system_reset(); +#endif + return burnFW_success; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_124k(unsigned char *fw, + int len, bool change_iref) +{ + /* Not use */ + return 0; +} + +static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_128k(unsigned char *fw, + int len, bool change_iref) +{ + int burnFW_success = 0; + + if (len != FW_SIZE_128k) { + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_ic_reset(false, false); +#else + g_core_fp.fp_system_reset(); +#endif + g_core_fp.fp_sense_off(true); + g_core_fp.fp_block_erase(0x00, FW_SIZE_128k); + g_core_fp.fp_flash_programming(fw, FW_SIZE_128k); + + if (g_core_fp.fp_check_CRC(pfw_op->addr_program_reload_from, + FW_SIZE_128k) == 0) + burnFW_success = 1; + + /*RawOut select initial*/ + g_core_fp.fp_register_write(pfw_op->addr_raw_out_sel, + sizeof(pfw_op->data_clear), pfw_op->data_clear, 0); + /*DSRAM func initial*/ + g_core_fp.fp_assign_sorting_mode(pfw_op->data_clear); + +/*#if defined(HX_RST_PIN_FUNC) + * g_core_fp.fp_ic_reset(false, false); + *#else + * //System reset + * g_core_fp.fp_system_reset(); + *#endif + */ + return burnFW_success; +} + +static void himax_mcu_flash_dump_func(uint8_t local_flash_command, + int Flash_Size, uint8_t *flash_buffer) +{ + uint8_t tmp_addr[DATA_LEN_4]; + uint8_t buffer[256]; + int page_prog_start = 0; + + g_core_fp.fp_sense_off(true); + g_core_fp.fp_burst_enable(1); + + for (page_prog_start = 0; page_prog_start < Flash_Size; + page_prog_start += 128) { + tmp_addr[0] = page_prog_start % 0x100; + tmp_addr[1] = (page_prog_start >> 8) % 0x100; + tmp_addr[2] = (page_prog_start >> 16) % 0x100; + tmp_addr[3] = page_prog_start / 0x1000000; + himax_mcu_register_read(tmp_addr, 128, buffer, 0); + memcpy(&flash_buffer[page_prog_start], buffer, 128); + } + + g_core_fp.fp_burst_enable(0); + + g_core_fp.fp_sense_on(0x01); +} + +static bool himax_mcu_flash_lastdata_check(uint32_t size) +{ + uint8_t tmp_addr[4]; + /* 64K - 0x80, which is the address of + * the last 128bytes in 64K, default value + */ + uint32_t start_addr = 0xFFFFFFFF; + uint32_t temp_addr = 0; + uint32_t flash_page_len = 0x80; + uint8_t flash_tmp_buffer[128]; + + if (size < flash_page_len) { + E("%s: flash size is wrong, terminated\n", __func__); + E("%s: flash size = %08X; flash page len = %08X\n", __func__, + size, flash_page_len); + goto FAIL; + } + + /* In order to match other size of fw */ + start_addr = size - flash_page_len; + I("%s: Now size is %d, the start_addr is 0x%08X\n", + __func__, size, start_addr); + for (temp_addr = start_addr; temp_addr < (start_addr + flash_page_len); + temp_addr = temp_addr + flash_page_len) { + /*I("temp_addr=%d,tmp_addr[0]=0x%2X, tmp_addr[1]=0x%2X, + * tmp_addr[2]=0x%2X,tmp_addr[3]=0x%2X\n", + * temp_addr,tmp_addr[0], tmp_addr[1], + * tmp_addr[2],tmp_addr[3]); + */ + tmp_addr[0] = temp_addr % 0x100; + tmp_addr[1] = (temp_addr >> 8) % 0x100; + tmp_addr[2] = (temp_addr >> 16) % 0x100; + tmp_addr[3] = temp_addr / 0x1000000; + g_core_fp.fp_register_read(tmp_addr, flash_page_len, + &flash_tmp_buffer[0], 0); + } + + I("FLASH[%08X] ~ FLASH[%08X] = %02X%02X%02X%02X\n", size-4, size-1, + flash_tmp_buffer[flash_page_len-4], + flash_tmp_buffer[flash_page_len-3], + flash_tmp_buffer[flash_page_len-2], + flash_tmp_buffer[flash_page_len-1]); + + if ((!flash_tmp_buffer[flash_page_len-4]) + && (!flash_tmp_buffer[flash_page_len-3]) + && (!flash_tmp_buffer[flash_page_len-2]) + && (!flash_tmp_buffer[flash_page_len-1])) { + I("Fail, Last four Bytes are all 0x00:\n"); + goto FAIL; + } else if ((flash_tmp_buffer[flash_page_len-4] == 0xFF) + && (flash_tmp_buffer[flash_page_len-3] == 0xFF) + && (flash_tmp_buffer[flash_page_len-2] == 0xFF) + && (flash_tmp_buffer[flash_page_len-1] == 0xFF)) { + I("Fail, Last four Bytes are all 0xFF:\n"); + goto FAIL; + } else { + return 0; + } + +FAIL: + return 1; +} + +static bool hx_bin_desc_data_get(uint32_t addr, uint8_t *flash_buf) +{ + uint8_t data_sz = 0x10; + uint32_t i = 0, j = 0; + uint16_t chk_end = 0; + uint16_t chk_sum = 0; + uint32_t map_code = 0; + unsigned long flash_addr = 0; + + for (i = 0; i < FW_PAGE_SZ; i = i + data_sz) { + for (j = i; j < (i + data_sz); j++) { + chk_end |= flash_buf[j]; + chk_sum += flash_buf[j]; + } + if (!chk_end) { /*1. Check all zero*/ + I("%s: End in %X\n", __func__, i + addr); + return false; + } else if (chk_sum % 0x100) /*2. Check sum*/ + I("%s: chk sum failed in %X\n", __func__, i + addr); + else { /*3. get data*/ + map_code = flash_buf[i] + (flash_buf[i + 1] << 8) + + (flash_buf[i + 2] << 16) + (flash_buf[i + 3] << 24); + flash_addr = flash_buf[i + 4] + (flash_buf[i + 5] << 8) + + (flash_buf[i + 6] << 16) + (flash_buf[i + 7] << 24); + switch (map_code) { + case FW_CID: + CID_VER_MAJ_FLASH_ADDR = flash_addr; + CID_VER_MIN_FLASH_ADDR = flash_addr + 1; + I("%s: CID_VER in %lX\n", __func__, + CID_VER_MAJ_FLASH_ADDR); + break; + case FW_VER: + FW_VER_MAJ_FLASH_ADDR = flash_addr; + FW_VER_MIN_FLASH_ADDR = flash_addr + 1; + I("%s: FW_VER in %lX\n", __func__, + FW_VER_MAJ_FLASH_ADDR); + break; + case CFG_VER: + CFG_VER_MAJ_FLASH_ADDR = flash_addr; + CFG_VER_MIN_FLASH_ADDR = flash_addr + 1; + I("%s: CFG_VER in = %08lX\n", __func__, + CFG_VER_MAJ_FLASH_ADDR); + break; + case TP_CONFIG_TABLE: + CFG_TABLE_FLASH_ADDR = flash_addr; + I("%s: CONFIG_TABLE in %X\n", + __func__, CFG_TABLE_FLASH_ADDR); + break; + } + } + chk_end = 0; + chk_sum = 0; + } + + return true; +} + +static bool hx_mcu_bin_desc_get(unsigned char *fw, uint32_t max_sz) +{ + uint32_t addr_t = 0; + unsigned char *fw_buf = NULL; + bool keep_on_flag = false; + bool g_bin_desc_flag = false; + + do { + fw_buf = &fw[addr_t]; + + /*Check bin is with description table or not*/ + if (!g_bin_desc_flag) { + if (fw_buf[0x00] == 0x00 && fw_buf[0x01] == 0x00 + && fw_buf[0x02] == 0x00 && fw_buf[0x03] == 0x00 + && fw_buf[0x04] == 0x00 && fw_buf[0x05] == 0x00 + && fw_buf[0x06] == 0x00 && fw_buf[0x07] == 0x00 + && fw_buf[0x0E] == 0x87) + g_bin_desc_flag = true; + } + if (!g_bin_desc_flag) { + I("%s: fw_buf[0x00] = %2X, fw_buf[0x0E] = %2X\n", + __func__, fw_buf[0x00], fw_buf[0x0E]); + I("%s: No description table\n", __func__); + break; + } + + /*Get related data*/ + keep_on_flag = hx_bin_desc_data_get(addr_t, fw_buf); + + addr_t = addr_t + FW_PAGE_SZ; + } while (max_sz > addr_t && keep_on_flag); + + return g_bin_desc_flag; +} + +static int hx_mcu_diff_overlay_flash(void) +{ + int rslt = 0; + int diff_val = 0; + + diff_val = (ic_data->vendor_fw_ver); + I("%s:Now fw ID is 0x%04X\n", __func__, diff_val); + diff_val = (diff_val >> 12); + I("%s:Now diff value=0x%04X\n", __func__, diff_val); + + if (diff_val == 1) + I("%s:Now size should be 128K!\n", __func__); + else + I("%s:Now size should be 64K!\n", __func__); + rslt = diff_val; + return rslt; +} + +/* FLASH side end*/ +/* CORE_FLASH */ + +/* CORE_SRAM */ +/* SRAM side start*/ +static void himax_mcu_sram_write(uint8_t *FW_content) +{ +} + +static bool himax_mcu_sram_verify(uint8_t *FW_File, int FW_Size) +{ + return true; +} + +static bool himax_mcu_get_DSRAM_data(uint8_t *info_data, bool DSRAM_Flag) +{ + unsigned int i = 0; + unsigned char tmp_addr[ADDR_LEN_4]; + unsigned char tmp_data[DATA_LEN_4]; + uint8_t max_i2c_size = MAX_I2C_TRANS_SZ; + uint8_t x_num = ic_data->HX_RX_NUM; + uint8_t y_num = ic_data->HX_TX_NUM; + /*int m_key_num = 0;*/ + int total_size = (x_num * y_num + x_num + y_num) * 2 + 4; + int total_data_size = (x_num * y_num + x_num + y_num) * 2; + int total_size_temp; + /*int mutual_data_size = x_num * y_num * 2;*/ + int total_read_times = 0; + int address = 0; + uint8_t *temp_info_data = NULL; /*max mkey size = 8*/ + uint16_t check_sum_cal = 0; + int fw_run_flag = -1; + + temp_info_data = kcalloc((total_size + 8), sizeof(uint8_t), GFP_KERNEL); + if (temp_info_data == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return false; + } + /* 1. Read number of MKey R100070E8H to determin data size */ + /* m_key_num = ic_data->HX_BT_NUM; */ + /* I("%s,m_key_num=%d\n",__func__ ,m_key_num); */ + /* total_size += m_key_num * 2; */ + /* 2. Start DSRAM Rawdata and Wait Data Ready */ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = psram_op->passwrd_start[1]; + tmp_data[0] = psram_op->passwrd_start[0]; + fw_run_flag = himax_write_read_reg(psram_op->addr_rawdata_addr, + tmp_data, + psram_op->passwrd_end[1], + psram_op->passwrd_end[0]); + + if (fw_run_flag < 0) { + I("%s Data NOT ready => bypass\n", __func__); + g_core_fp.fp_read_FW_status(); + goto FAIL; + } + + /* 3. Read RawData */ + total_size_temp = total_size; + I("%s:data[0]=0x%2X,data[1]=0x%2X,data[2]=0x%2X,data[3]=0x%2X\n", + __func__, + psram_op->addr_rawdata_addr[0], + psram_op->addr_rawdata_addr[1], + psram_op->addr_rawdata_addr[2], + psram_op->addr_rawdata_addr[3]); + + tmp_addr[0] = psram_op->addr_rawdata_addr[0]; + tmp_addr[1] = psram_op->addr_rawdata_addr[1]; + tmp_addr[2] = psram_op->addr_rawdata_addr[2]; + tmp_addr[3] = psram_op->addr_rawdata_addr[3]; + + if (total_size % max_i2c_size == 0) + total_read_times = total_size / max_i2c_size; + else + total_read_times = total_size / max_i2c_size + 1; + + for (i = 0; i < total_read_times; i++) { + address = (psram_op->addr_rawdata_addr[3] << 24) + + (psram_op->addr_rawdata_addr[2] << 16) + + (psram_op->addr_rawdata_addr[1] << 8) + + psram_op->addr_rawdata_addr[0] + + i * max_i2c_size; + /*I("%s address = %08X\n", __func__, address);*/ + + tmp_addr[3] = (uint8_t)((address >> 24) & 0x00FF); + tmp_addr[2] = (uint8_t)((address >> 16) & 0x00FF); + tmp_addr[1] = (uint8_t)((address >> 8) & 0x00FF); + tmp_addr[0] = (uint8_t)((address) & 0x00FF); + + if (total_size_temp >= max_i2c_size) { + g_core_fp.fp_register_read(tmp_addr, max_i2c_size, + &temp_info_data[i * max_i2c_size], 0); + total_size_temp = total_size_temp - max_i2c_size; + } else { + /*I("last total_size_temp=%d\n",total_size_temp);*/ + g_core_fp.fp_register_read(tmp_addr, + total_size_temp % max_i2c_size, + &temp_info_data[i * max_i2c_size], 0); + } + } + + /* 4. FW stop outputing */ + tmp_data[3] = temp_info_data[3]; + tmp_data[2] = temp_info_data[2]; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + g_core_fp.fp_register_write(psram_op->addr_rawdata_addr, + DATA_LEN_4, tmp_data, 0); + + /* 5. Data Checksum Check */ + for (i = 2; i < total_size; i += 2)/* 2:PASSWORD NOT included */ + check_sum_cal += (temp_info_data[i + 1] * 256 + + temp_info_data[i]); + + if (check_sum_cal % 0x10000 != 0) { + I("%s check_sum_cal fail=%2X\n", __func__, check_sum_cal); + goto FAIL; + } else { + memcpy(info_data, &temp_info_data[4], + total_data_size * sizeof(uint8_t)); + /*I("%s checksum PASS\n", __func__);*/ + } + kfree(temp_info_data); + return true; +FAIL: + kfree(temp_info_data); + return false; +} +/* SRAM side end*/ +/* CORE_SRAM */ + +/* CORE_DRIVER */ + +static void himax_mcu_init_ic(void) +{ + I("%s: use default incell init.\n", __func__); +} + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) +static int himax_mcu_fw_ver_bin(void) +{ + I("%s: use default incell address.\n", __func__); + if (hxfw != NULL) { + I("Catch fw version in bin file!\n"); + g_i_FW_VER = (hxfw->data[FW_VER_MAJ_FLASH_ADDR] << 8) + | hxfw->data[FW_VER_MIN_FLASH_ADDR]; + g_i_CFG_VER = (hxfw->data[CFG_VER_MAJ_FLASH_ADDR] << 8) + | hxfw->data[CFG_VER_MIN_FLASH_ADDR]; + g_i_CID_MAJ = hxfw->data[CID_VER_MAJ_FLASH_ADDR]; + g_i_CID_MIN = hxfw->data[CID_VER_MIN_FLASH_ADDR]; + } else { + I("FW data is null!\n"); + return 1; + } + return NO_ERR; +} +#endif + + +#if defined(HX_RST_PIN_FUNC) +static void himax_mcu_pin_reset(void) +{ + I("%s: Now reset the Touch chip.\n", __func__); + himax_rst_gpio_set(private_ts->rst_gpio, 0); + usleep_range(RST_LOW_PERIOD_S, RST_LOW_PERIOD_E); + himax_rst_gpio_set(private_ts->rst_gpio, 1); + usleep_range(RST_HIGH_PERIOD_S, RST_HIGH_PERIOD_E); +} + +static void himax_mcu_ic_reset(uint8_t loadconfig, uint8_t int_off) +{ + struct himax_ts_data *ts = private_ts; + + HX_HW_RESET_ACTIVATE = 0; + I("%s,status: loadconfig=%d,int_off=%d\n", __func__, + loadconfig, int_off); + + if (ts->rst_gpio >= 0) { + if (int_off) + g_core_fp.fp_irq_switch(0); + + g_core_fp.fp_pin_reset(); + + /* if (loadconfig) */ + /* g_core_fp.fp_reload_config(); */ + + if (int_off) + g_core_fp.fp_irq_switch(1); + + } +} +#endif + +#if !defined(HX_FIX_TOUCH_INFO) +static uint8_t himax_mcu_tp_info_check(void) +{ + uint8_t rx = pdriver_op->data_df_rx[0]; + uint8_t tx = pdriver_op->data_df_tx[0]; + uint8_t pt = pdriver_op->data_df_pt[0]; + uint8_t err_cnt = 0; + + if (ic_data->HX_RX_NUM < (rx / 2) + || ic_data->HX_RX_NUM > (rx * 3 / 2)) { + ic_data->HX_RX_NUM = rx; + err_cnt |= 0x01; + } + if (ic_data->HX_TX_NUM < (tx / 2) + || ic_data->HX_TX_NUM > (tx * 3 / 2)) { + ic_data->HX_TX_NUM = tx; + err_cnt |= 0x02; + } + if (ic_data->HX_MAX_PT < (pt / 2) + || ic_data->HX_MAX_PT > (pt * 3 / 2)) { + ic_data->HX_MAX_PT = pt; + err_cnt |= 0x04; + } + + return err_cnt; +} +#endif + +static void himax_mcu_touch_information(void) +{ +#if !defined(HX_FIX_TOUCH_INFO) + char addr[DATA_LEN_4] = {0}; + char data[DATA_LEN_8] = {0}; + uint8_t err_cnt = 0; + + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_rxnum_txnum_maxpt, + DATA_LEN_8, data, 0); + ic_data->HX_RX_NUM = data[2]; + ic_data->HX_TX_NUM = data[3]; + ic_data->HX_MAX_PT = data[4]; + /*I("%s : HX_RX_NUM=%d,ic_data->HX_TX_NUM=%d,ic_data->HX_MAX_PT=%d\n", + * __func__,ic_data->HX_RX_NUM, + * ic_data->HX_TX_NUM,ic_data->HX_MAX_PT); + */ + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_xy_res_enable, + DATA_LEN_4, data, 0); + + /*I("%s : c_data->HX_XY_REVERSE=0x%2.2X\n",__func__,data[1]);*/ + if ((data[1] & 0x04) == 0x04) + ic_data->HX_XY_REVERSE = true; + else + ic_data->HX_XY_REVERSE = false; + + g_core_fp.fp_register_read(pdriver_op->addr_fw_define_int_is_edge, + DATA_LEN_4, data, 0); + /*I("%s : data[0]=0x%2.2X,data[1]=0x%2.2X,data[2]=0x%2.2X, + * data[3]=0x%2.2X\n",__func__,data[0],data[1],data[2],data[3]); + */ + /*I("data[0] & 0x01 = %d\n",(data[0] & 0x01));*/ + if ((data[1] & 0x01) == 1) + ic_data->HX_INT_IS_EDGE = true; + else + ic_data->HX_INT_IS_EDGE = false; + + /*1. Read number of MKey R100070E8H to determin data size*/ + g_core_fp.fp_register_read(psram_op->addr_mkey, DATA_LEN_4, data, 0); + /* I("%s: tmp_data[0] = 0x%02X,tmp_data[1] = 0x%02X,tmp_data[2]=0x%02X, + * tmp_data[3] = 0x%02X\n", + */ + /* __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);*/ + ic_data->HX_BT_NUM = data[0] & 0x03; + + addr[3] = 0x10; + addr[2] = 0x00; + addr[1] = 0x71; + addr[0] = 0x9C; + g_core_fp.fp_register_read(addr, DATA_LEN_4, data, 0); + ic_data->HX_PEN_FUNC = data[3]; + + err_cnt = himax_mcu_tp_info_check(); + if (err_cnt > 0) + E("TP Info from IC is wrong, err_cnt = 0x%X", err_cnt); +#else + ic_data->HX_RX_NUM = FIX_HX_RX_NUM; + ic_data->HX_TX_NUM = FIX_HX_TX_NUM; + ic_data->HX_BT_NUM = FIX_HX_BT_NUM; + ic_data->HX_MAX_PT = FIX_HX_MAX_PT; + ic_data->HX_XY_REVERSE = FIX_HX_XY_REVERSE; + ic_data->HX_INT_IS_EDGE = FIX_HX_INT_IS_EDGE; + ic_data->HX_PEN_FUNC = FIX_HX_PEN_FUNC; +#endif + ic_data->HX_Y_RES = private_ts->pdata->screenHeight; + ic_data->HX_X_RES = private_ts->pdata->screenWidth; + + g_core_fp.fp_ic_id_read(); + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d\n", __func__, + ic_data->HX_RX_NUM, ic_data->HX_TX_NUM); + I("%s:HX_MAX_PT=%d,HX_XY_REVERSE =%d\n", __func__, + ic_data->HX_MAX_PT, ic_data->HX_XY_REVERSE); + I("%s:HX_Y_RES=%d,HX_X_RES =%d\n", __func__, + ic_data->HX_Y_RES, ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d,HX_PEN_FUNC = %d\n", __func__, + ic_data->HX_INT_IS_EDGE, ic_data->HX_PEN_FUNC); +} + +static void himax_mcu_calcTouchDataSize(void) +{ + struct himax_ts_data *ts_data = private_ts; + + ts_data->x_channel = ic_data->HX_RX_NUM; + ts_data->y_channel = ic_data->HX_TX_NUM; + ts_data->nFinger_support = ic_data->HX_MAX_PT; + +#if 0 + ts_data->coord_data_size = 4 * ts_data->nFinger_support; + ts_data->area_data_size = ((ts_data->nFinger_support / 4) + + (ts_data->nFinger_support % 4 ? 1 : 0)) * 4; + ts_data->coordInfoSize = ts_data->coord_data_size + + ts_data->area_data_size + 4; + ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size + - ts_data->area_data_size - 4 - 4 - 2; + + if (ts_data->raw_data_frame_size == 0) { + E("%s: could NOT calculate!\n", __func__); + return; + } + + ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel + * ts_data->y_channel + + ts_data->x_channel + + ts_data->y_channel) + / ts_data->raw_data_frame_size + + (((uint32_t)ts_data->x_channel + * ts_data->y_channel + + ts_data->x_channel + + ts_data->y_channel) + % ts_data->raw_data_frame_size) ? 1 : 0; + + I("%s: coord_dsz:%d,area_dsz:%d,raw_data_fsz:%d,raw_data_nframes:%d", + __func__, + ts_data->coord_data_size, + ts_data->area_data_size, + ts_data->raw_data_frame_size, + ts_data->raw_data_nframes); +#endif + + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4; + if ((ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += + (ic_data->HX_MAX_PT / 4) * 4; + else + HX_TOUCH_INFO_POINT_CNT += + ((ic_data->HX_MAX_PT / 4) + 1) * 4; + + if (himax_report_data_init()) + E("%s: allocate data fail\n", __func__); + +} + +#if 0 +static void himax_mcu_reload_config(void) +{ + if (himax_report_data_init()) + E("%s: allocate data fail\n", __func__); + g_core_fp.fp_sense_on(0x00); +} +#endif + +static int himax_mcu_get_touch_data_size(void) +{ + return HIMAX_TOUCH_DATA_SIZE; +} + +static int himax_mcu_hand_shaking(void) +{ + /* 0:Running, 1:Stop, 2:I2C Fail */ + int result = 0; + return result; +} + +static int himax_mcu_determin_diag_rawdata(int diag_command) +{ + return diag_command % 10; +} + +static int himax_mcu_determin_diag_storage(int diag_command) +{ + return diag_command / 10; +} + +static int himax_mcu_cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, + int raw_cnt_max) +{ + int RawDataLen; + /* rawdata checksum is 2 bytes */ + if (raw_cnt_rmd != 0x00) + RawDataLen = MAX_I2C_TRANS_SZ + - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 2; + else + RawDataLen = MAX_I2C_TRANS_SZ + - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 2; + + return RawDataLen; +} + +static bool himax_mcu_diag_check_sum(struct himax_report_data *hx_touch_data) +{ + uint16_t check_sum_cal = 0; + int i; + + /* Check 128th byte CRC */ + for (i = 0, check_sum_cal = 0; + i < (hx_touch_data->touch_all_size + - hx_touch_data->touch_info_size); + i += 2) { + check_sum_cal += (hx_touch_data->hx_rawdata_buf[i + 1] + * FLASH_RW_MAX_LEN + + hx_touch_data->hx_rawdata_buf[i]); + } + + if (check_sum_cal % HX64K != 0) { + I("%s fail=%2X\n", __func__, check_sum_cal); + return 0; + } + + return 1; +} + +static void himax_mcu_diag_parse_raw_data( + struct himax_report_data *hx_touch_data, + int mul_num, int self_num, uint8_t diag_cmd, + int32_t *mutual_data, int32_t *self_data) +{ + diag_mcu_parse_raw_data(hx_touch_data, mul_num, self_num, + diag_cmd, mutual_data, self_data); +} + +#if defined(HX_EXCP_RECOVERY) +static int himax_mcu_ic_excp_recovery(uint32_t hx_excp_event, + uint32_t hx_zero_event, uint32_t length) +{ + int ret_val = NO_ERR; + + if (hx_excp_event == length) { + g_zero_event_count = 0; + ret_val = HX_EXCP_EVENT; + } else if (hx_zero_event == length) { + if (g_zero_event_count > 5) { + g_zero_event_count = 0; + I("EXCEPTION event checked - ALL Zero.\n"); + ret_val = HX_EXCP_EVENT; + } else { + g_zero_event_count++; + I("ALL Zero event is %d times.\n", + g_zero_event_count); + ret_val = HX_ZERO_EVENT_COUNT; + } + } + + return ret_val; +} + +static void himax_mcu_excp_ic_reset(void) +{ + HX_EXCP_RESET_ACTIVATE = 0; +#if defined(HX_RST_PIN_FUNC) + himax_mcu_pin_reset(); +#else + himax_mcu_system_reset(); +#endif + I("%s:\n", __func__); +} +#endif +#if defined(HX_TP_PROC_GUEST_INFO) +char *g_checksum_str = "check sum fail"; +/* char *g_guest_info_item[] = { + * "projectID", + * "CGColor", + * "BarCode", + * "Reserve1", + * "Reserve2", + * "Reserve3", + * "Reserve4", + * "Reserve5", + * "VCOM", + * "Vcom-3Gar", + * NULL + * }; + */ + +static int himax_guest_info_get_status(void) +{ + return g_guest_info_data->g_guest_info_ongoing; +} +static void himax_guest_info_set_status(int setting) +{ + g_guest_info_data->g_guest_info_ongoing = setting; +} + +static int himax_guest_info_read(uint32_t start_addr, + uint8_t *flash_tmp_buffer) +{ + uint32_t temp_addr = 0; + uint8_t tmp_addr[4]; + uint32_t flash_page_len = 0x1000; + /* uint32_t checksum = 0x00; */ + int result = 0; + + + I("%s:Reading guest info in start_addr = 0x%08X !\n", __func__, + start_addr); + + tmp_addr[0] = start_addr % 0x100; + tmp_addr[1] = (start_addr >> 8) % 0x100; + tmp_addr[2] = (start_addr >> 16) % 0x100; + tmp_addr[3] = start_addr / 0x1000000; + I("addr[0]=0x%2X,addr[1]=0x%2X,addr[2]=0x%2X,addr[3]=0x%2X\n", + tmp_addr[0], tmp_addr[1], + tmp_addr[2], tmp_addr[3]); + + /*result = g_core_fp.fp_check_CRC(tmp_addr, flash_page_len); + I("Checksum = 0x%8X\n", result); + if (result != 0) + goto END_FUNC;*/ + + for (temp_addr = start_addr; + temp_addr < (start_addr + flash_page_len); + temp_addr = temp_addr + 128) { + + /* I("temp_addr=%d,tmp_addr[0]=0x%2X,tmp_addr[1]=0x%2X, + * tmp_addr[2]=0x%2X,tmp_addr[3]=0x%2X\n", + * temp_addr,tmp_addr[0],tmp_addr[1], + * tmp_addr[2],tmp_addr[3]); + */ + tmp_addr[0] = temp_addr % 0x100; + tmp_addr[1] = (temp_addr >> 8) % 0x100; + tmp_addr[2] = (temp_addr >> 16) % 0x100; + tmp_addr[3] = temp_addr / 0x1000000; + g_core_fp.fp_register_read(tmp_addr, 128, + &flash_tmp_buffer[temp_addr - start_addr], false); + /* memcpy(&flash_tmp_buffer[temp_addr - start_addr], + * buffer,128); + */ + } + +//END_FUNC: + return result; +} + +static int hx_read_mcf_data(void) +{ + uint32_t mcf_data_addr = HX_GUEST_INFO_MCF_SADDR; + int rc = 0; + uint32_t mcf_page_len = 0x200; + //unsigned int mcf_data_temp = 0; + uint8_t *mcf_tmp_buffer = NULL; + + himax_guest_info_set_status(1); + + mcf_tmp_buffer = kcalloc(HX_GUEST_INFO_SIZE * mcf_page_len, + sizeof(uint8_t), GFP_KERNEL); + + + rc = himax_guest_info_read(mcf_data_addr,&mcf_tmp_buffer[0]); + memcpy(panel_mcf_data, mcf_tmp_buffer, 512); + + kfree(mcf_tmp_buffer); + himax_guest_info_set_status(0); + + return 0; +} + +static int hx_read_guest_info(void) +{ + /* uint8_t tmp_addr[4]; */ + uint32_t panel_info_addr = HX_GUEST_INFO_FLASH_SADDR; + + uint32_t info_len; + uint32_t flash_page_len = 0x1000;/*4k*/ + uint8_t *flash_tmp_buffer = NULL; + /* uint32_t temp_addr = 0; */ + uint8_t temp_str[128]; + int i = 0; + unsigned int custom_info_temp = 0; + int checksum = 0; + + himax_guest_info_set_status(1); + + flash_tmp_buffer = kcalloc(HX_GUEST_INFO_SIZE * flash_page_len, + sizeof(uint8_t), GFP_KERNEL); + if (flash_tmp_buffer == NULL) { + I("%s: Memory allocate fail!\n", __func__); + return MEM_ALLOC_FAIL; + } + + g_core_fp.fp_sense_off(true); + /* g_core_fp.fp_burst_enable(1); */ + + for (custom_info_temp = 0; + custom_info_temp < HX_GUEST_INFO_SIZE; + custom_info_temp++) { + checksum = himax_guest_info_read(panel_info_addr + + custom_info_temp + * flash_page_len, + &flash_tmp_buffer[custom_info_temp * flash_page_len]); + if (checksum != 0) { + E("%s:Checksum Fail! g_checksum_str len=%d\n", __func__, + (int)strlen(g_checksum_str)); + memcpy(&g_guest_info_data-> + g_guest_str_in_format[custom_info_temp][0], + g_checksum_str, (int)strlen(g_checksum_str)); + memcpy(&g_guest_info_data-> + g_guest_str[custom_info_temp][0], + g_checksum_str, (int)strlen(g_checksum_str)); + continue; + } + + info_len = flash_tmp_buffer[custom_info_temp * flash_page_len] + + (flash_tmp_buffer[custom_info_temp + * flash_page_len + 1] << 8) + + (flash_tmp_buffer[custom_info_temp + * flash_page_len + 2] << 16) + + (flash_tmp_buffer[custom_info_temp + * flash_page_len + 3] << 24); + + I("Now custom_info_temp = %d\n", custom_info_temp); + + I("Now size_buff[0]=0x%02X,[1]=0x%02X,[2]=0x%02X,[3]=0x%02X\n", + flash_tmp_buffer[custom_info_temp*flash_page_len], + flash_tmp_buffer[custom_info_temp*flash_page_len + 1], + flash_tmp_buffer[custom_info_temp*flash_page_len + 2], + flash_tmp_buffer[custom_info_temp*flash_page_len + 3]); + + I("Now total length=%d\n", info_len); + + g_guest_info_data->g_guest_data_len[custom_info_temp] = + info_len; + + I("Now custom_info_id [0]=%d,[1]=%d,[2]=%d,[3]=%d\n", + flash_tmp_buffer[custom_info_temp*flash_page_len + 4], + flash_tmp_buffer[custom_info_temp*flash_page_len + 5], + flash_tmp_buffer[custom_info_temp*flash_page_len + 6], + flash_tmp_buffer[custom_info_temp*flash_page_len + 7]); + + g_guest_info_data->g_guest_data_type[custom_info_temp] = + flash_tmp_buffer[custom_info_temp * flash_page_len + + 7]; + + /* if(custom_info_temp < 3) { */ + if (info_len > 128) { + I("%s: info_len=%d\n", __func__, info_len); + info_len = 128; + } + for (i = 0; i < info_len; i++) + temp_str[i] = flash_tmp_buffer[custom_info_temp + * flash_page_len + + HX_GUEST_INFO_LEN_SIZE + + HX_GUEST_INFO_ID_SIZE + + i]; + + I("g_guest_info_data->g_guest_str_in_format[%d]size=%d\n", + custom_info_temp, info_len); + memcpy(&g_guest_info_data-> + g_guest_str_in_format[custom_info_temp][0], + temp_str, info_len); + /*}*/ + + for (i = 0; i < 128; i++) + temp_str[i] = flash_tmp_buffer[custom_info_temp + * flash_page_len + + i]; + + I("g_guest_info_data->g_guest_str[%d] size = %d\n", + custom_info_temp, 128); + memcpy(&g_guest_info_data->g_guest_str[custom_info_temp][0], + temp_str, 128); + /*if(custom_info_temp == 0) + *{ + * for ( i = 0; i< 256 ; i++) { + * if(i % 16 == 0 && i > 0) + * I("\n"); + * I("g_guest_info_data->g_guest_str[%d][%d] + = 0x%02X", custom_info_temp, i, + g_guest_info_data->g_guest_str[ + custom_info_temp][i]); + * } + *} + */ + } + /* himax_burst_enable(private_ts->client, 0); */ + g_core_fp.fp_sense_on(0x01); + + kfree(flash_tmp_buffer); + himax_guest_info_set_status(0); + return NO_ERR; +} +#endif +/* CORE_DRIVER */ + +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) +static void himax_mcu_resend_cmd_func(bool suspended) +{ +#if defined(HX_SMART_WAKEUP) || defined(HX_HIGH_SENSE) + struct himax_ts_data *ts = private_ts; +#endif +#if defined(HX_SMART_WAKEUP) + g_core_fp.fp_set_SMWP_enable(ts->SMWP_enable, suspended); +#endif +#if defined(HX_HIGH_SENSE) + g_core_fp.fp_set_HSEN_enable(ts->HSEN_enable, suspended); +#endif +#if defined(HX_USB_DETECT_GLOBAL) + himax_cable_detect_func(true); +#endif +} +#endif + +#if defined(HX_ZERO_FLASH) +int G_POWERONOF = 1; +EXPORT_SYMBOL(G_POWERONOF); +void hx_dis_rload_0f(int disable) +{ + /*Diable Flash Reload*/ + g_core_fp.fp_register_write(pdriver_op->addr_fw_define_flash_reload, + DATA_LEN_4, pzf_op->data_dis_flash_reload, 0); +} + +void himax_mcu_clean_sram_0f(uint8_t *addr, int write_len, int type) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int address = 0; + int i = 0; + + uint8_t fix_data = 0x00; + uint8_t tmp_addr[4]; + uint8_t tmp_data[MAX_I2C_TRANS_SZ] = {0}; + + I("%s, Entering\n", __func__); + + max_bus_size = (write_len > HX_MAX_WRITE_SZ - 4) + ? (HX_MAX_WRITE_SZ - 4) + : write_len; + + total_size_temp = write_len; + + g_core_fp.fp_burst_enable(1); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s:addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + + switch (type) { + case 0: + fix_data = 0x00; + break; + case 1: + fix_data = 0xAA; + break; + case 2: + fix_data = 0xBB; + break; + } + + for (i = 0; i < MAX_I2C_TRANS_SZ; i++) + tmp_data[i] = fix_data; + + I("%s, total size=%d\n", __func__, total_size_temp); + + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + for (i = 0; i < (total_read_times); i++) { + I("[log]write %d time start!\n", i); + if (total_size_temp >= max_bus_size) { + g_core_fp.fp_register_write(tmp_addr, + max_bus_size, tmp_data, 0); + total_size_temp = total_size_temp - max_bus_size; + } else { + I("last total_size_temp=%d\n", total_size_temp); + g_core_fp.fp_register_write(tmp_addr, + total_size_temp % max_bus_size, + tmp_data, 0); + } + address = ((i+1) * max_bus_size); + tmp_addr[1] = addr[1] + (uint8_t) ((address>>8) & 0x00FF); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + + usleep_range(10000, 11000); + } + + I("%s, END\n", __func__); +} + +void himax_mcu_write_sram_0f(const struct firmware *fw_entry, uint8_t *addr, + int start_index, uint32_t write_len) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int address = 0; + int i = 0; + + uint8_t tmp_addr[4]; + uint8_t *tmp_data; + + total_size_temp = write_len; + I("%s, Entering - total write size=%d\n", __func__, total_size_temp); + + max_bus_size = (write_len > HX_MAX_WRITE_SZ - 4) + ? (HX_MAX_WRITE_SZ - 4) + : write_len; + + g_core_fp.fp_burst_enable(1); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s, write addr = 0x%02X%02X%02X%02X\n", __func__, + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]); + + /* tmp_data = kcalloc(max_bus_size, sizeof(uint8_t), GFP_KERNEL); + * if (tmp_data == NULL) { + * I("%s: Can't allocate enough buf\n", __func__); + * return; + * } + */ + + /*for(i = 0;i<10;i++) + *{ + * I("[%d] 0x%2.2X", i, tmp_data[i]); + *} + *I("\n"); + */ + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + for (i = 0; i < (total_read_times); i++) { + /*I("[log]write %d time start!\n", i);*/ + /*I("[log]addr[3]=0x%02X, addr[2]=0x%02X, + * addr[1]=0x%02X, + * addr[0]=0x%02X!\n", tmp_addr[3], + * tmp_addr[2], tmp_addr[1], tmp_addr[0]); + */ + + if (total_size_temp >= max_bus_size) { + /*memcpy(tmp_data, &fw_entry->data[start_index+i + * * max_bus_size], max_bus_size); + */ + tmp_data = (uint8_t *)&fw_entry->data[start_index+i + * max_bus_size]; + g_core_fp.fp_register_write(tmp_addr, + max_bus_size, tmp_data, 0); + total_size_temp = total_size_temp - max_bus_size; + } else { + /*memcpy(tmp_data, &fw_entry->data[start_index+i + * * max_bus_size], + * total_size_temp % max_bus_size); + */ + tmp_data = (uint8_t *)&fw_entry->data[start_index+i + * max_bus_size]; + I("last total_size_temp=%d\n", + total_size_temp % max_bus_size); + g_core_fp.fp_register_write(tmp_addr, + total_size_temp % max_bus_size, + tmp_data, 0); + } + + /*I("[log]write %d time end!\n", i);*/ + address = ((i+1) * max_bus_size); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + + if (tmp_addr[0] < addr[0]) + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF) + 1; + else + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF); + + udelay(100); + } + I("%s, End\n", __func__); + /* kfree(tmp_data); */ +} + +int himax_sram_write_crc_check(const struct firmware *fw_entry, uint8_t *addr, + int strt_idx, uint32_t len) +{ + int retry = 0; + int crc = -1; + + do { + g_core_fp.fp_write_sram_0f(fw_entry, addr, strt_idx, len); + crc = g_core_fp.fp_check_CRC(addr, len); + retry++; + I("%s, HW CRC %s in %d time\n", __func__, + (crc == 0) ? "OK" : "Fail", retry); + } while (crc != 0 && retry < 3); + + return crc; +} + +int himax_zf_part_info(const struct firmware *fw_entry) +{ + uint32_t cfg_table_pos = CFG_TABLE_FLASH_ADDR; + int part_num = 0; + int ret = 0; + uint8_t buf[16]; + struct zf_info *zf_info_arr; + uint8_t *FW_buf; + uint8_t sram_min[4]; + int cfg_crc_sw = 0; + int cfg_crc_hw = 0; + int cfg_sz = 0; + int retry = 3; + uint8_t i = 0; + int i_max = 0; + int i_min = 0; + uint32_t dsram_base = 0xFFFFFFFF; + uint32_t dsram_max = 0; +#if defined(HX_CODE_OVERLAY) + uint8_t tmp_addr[4] = {0xFC, 0x7F, 0x00, 0x10}; + uint8_t send_data[4] = {0}; + uint8_t recv_data[4] = {0}; + uint8_t ovl_idx_t = 0; + + uint8_t j = 0; + int allovlidx = 0; + + if (ovl_idx == NULL) { + ovl_idx = kzalloc(ovl_section_num, GFP_KERNEL); + if (ovl_idx == NULL) { + E("%s, ovl_idx alloc failed!\n", + __func__); + return -ENOMEM; + } + } else { + memset(ovl_idx, 0, ovl_section_num); + } +#endif + + /*1. get number of partition*/ + part_num = fw_entry->data[cfg_table_pos + 12]; + + I("%s, Number of partition is %d\n", __func__, part_num); + if (part_num <= 1) { + E("%s, size of cfg part failed! part_num = %d\n", + __func__, part_num); + return LENGTH_FAIL; + } + + /*2. initial struct of array*/ + zf_info_arr = kcalloc(part_num, sizeof(struct zf_info), GFP_KERNEL); + if (zf_info_arr == NULL) { + E("%s, Allocate ZF info array failed!\n", __func__); + ret = MEM_ALLOC_FAIL; + goto ALOC_ZF_INFO_ARR_FAIL; + } + memset(zf_info_arr, 0x0, part_num * sizeof(struct zf_info)); + + /*3. Catch table information */ + memcpy(buf, &fw_entry->data[cfg_table_pos], 16); + memcpy(zf_info_arr[0].sram_addr, buf, 4); + zf_info_arr[0].write_size = buf[7] << 24 + | buf[6] << 16 + | buf[5] << 8 + | buf[4]; + zf_info_arr[0].fw_addr = buf[11] << 24 + | buf[10] << 16 + | buf[9] << 8 + | buf[8]; + + + for (i = 1; i < part_num; i++) { + /*3. get all partition*/ + memcpy(buf, &fw_entry->data[i * 0x10 + cfg_table_pos], 16); + + memcpy(zf_info_arr[i].sram_addr, buf, 4); + zf_info_arr[i].write_size = buf[7] << 24 + | buf[6] << 16 + | buf[5] << 8 + | buf[4]; + zf_info_arr[i].fw_addr = buf[11] << 24 + | buf[10] << 16 + | buf[9] << 8 + | buf[8]; + zf_info_arr[i].cfg_addr = zf_info_arr[i].sram_addr[0]; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[1] << 8; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[2] << 16; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[3] << 24; + +#if defined(HX_CODE_OVERLAY) + /*overlay section*/ + + if ((buf[15] == 0x55 && buf[14] == 0x66) + || (buf[3] == 0x20 && buf[2] == 0x00 + && buf[1] == 0x8C && buf[0] == 0xE0)) { + I("%s: catch overlay section in index %d\n", + __func__, i); + + /* record index of overlay section */ + allovlidx |= 1< zf_info_arr[i].cfg_addr) { + dsram_base = zf_info_arr[i].cfg_addr; + i_min = i; + } + if (dsram_max < zf_info_arr[i].cfg_addr) { + dsram_max = zf_info_arr[i].cfg_addr; + i_max = i; + } + } + for (i = 0; i < ADDR_LEN_4; i++) + sram_min[i] = zf_info_arr[i_min].sram_addr[i]; + + cfg_sz = (dsram_max - dsram_base) + zf_info_arr[i_max].write_size; + if (cfg_sz % 16 != 0) + cfg_sz = cfg_sz + 16 - (cfg_sz % 16); + + I("%s, cfg_sz = %d!, dsram_base = %X, dsram_max = %X\n", __func__, + cfg_sz, dsram_base, dsram_max); + + if (cfg_sz <= DSRAM_SIZE) { + /* config size should be smaller than DSRAM size */ + FW_buf = kcalloc(cfg_sz, sizeof(uint8_t), GFP_KERNEL); + if (FW_buf == NULL) { + E("%s, Allocate FW_buf array failed!\n", __func__); + ret = MEM_ALLOC_FAIL; + goto ALOC_FW_BUF_FAIL; + } + } else { + E("%s: config size is abnormal, please check FW\n", __func__); + ret = LENGTH_FAIL; + goto ALOC_FW_BUF_FAIL; + } + + for (i = 1; i < part_num; i++) { + if (zf_info_arr[i].cfg_addr % 4 != 0) + zf_info_arr[i].cfg_addr = zf_info_arr[i].cfg_addr + - (zf_info_arr[i].cfg_addr % 4); + + I("%s,[%d]SRAM addr=%08X, fw_addr=%08X, write_size=%d\n", + __func__, i, + zf_info_arr[i].cfg_addr, + zf_info_arr[i].fw_addr, + zf_info_arr[i].write_size); + +#if defined(HX_CODE_OVERLAY) + /*overlay section*/ + if (allovlidx & (1<data[zf_info_arr[i].fw_addr], + zf_info_arr[i].write_size); + } + + cfg_crc_sw = g_core_fp.fp_Calculate_CRC_with_AP(FW_buf, 0, cfg_sz); + I("Now cfg_crc_sw=%X\n", cfg_crc_sw); + + /*4. write to sram*/ + if (G_POWERONOF == 1) { + /* FW entity */ + if (himax_sram_write_crc_check(fw_entry, + zf_info_arr[0].sram_addr, + zf_info_arr[0].fw_addr, + zf_info_arr[0].write_size) != 0) { + E("%s, HW CRC FAIL\n", __func__); + } else { + I("%s, HW CRC PASS\n", __func__); + } + + I("Now sram_min[0]=0x%02X,[1]=0x%02X,[2]=0x%02X,[3]=0x%02X\n", + sram_min[0], sram_min[1], sram_min[2], sram_min[3]); + do { + g_core_fp.fp_register_write(sram_min, cfg_sz, + FW_buf, 0); + cfg_crc_hw = g_core_fp.fp_check_CRC(sram_min, cfg_sz); + if (cfg_crc_hw != cfg_crc_sw) { + E("Cfg CRC FAIL,HWCRC=%X,SWCRC=%X,retry=%d\n", + cfg_crc_hw, cfg_crc_sw, retry); + } else + I("Config CRC Pass\n"); + + } while (cfg_crc_hw != cfg_crc_sw && retry-- > 0); + +#if defined(HX_CODE_OVERLAY) + /* ovl_idx[0] - sorting */ + /* ovl_idx[1] - gesture */ + /* ovl_idx[2] - border */ + + ovl_idx_t = ovl_idx[0]; + send_data[0] = ovl_sorting_reply; + + if (private_ts->in_self_test == 0) { +#if defined(HX_SMART_WAKEUP) + if (private_ts->suspended && private_ts->SMWP_enable) { + ovl_idx_t = ovl_idx[1]; + send_data[0] = ovl_gesture_reply; + } else { + ovl_idx_t = ovl_idx[2]; + send_data[0] = ovl_border_reply; + } +#else + ovl_idx_t = ovl_idx[2]; + send_data[0] = ovl_border_reply; +#endif + +#if defined(HX_SMART_WAKEUP) \ + || defined(HX_HIGH_SENSE) \ + || defined(HX_USB_DETECT_GLOBAL) + /*write back system config*/ + g_core_fp.fp_resend_cmd_func(private_ts->suspended); +#endif + } + I("%s: prepare upgrade overlay section = %d\n", + __func__, ovl_idx_t); + + if (zf_info_arr[ovl_idx_t].write_size == 0) { + send_data[0] = ovl_fault; + E("%s, WRONG overlay section, plese check FW!\n", + __func__); + } else { + if (himax_sram_write_crc_check(fw_entry, + zf_info_arr[ovl_idx_t].sram_addr, + zf_info_arr[ovl_idx_t].fw_addr, + zf_info_arr[ovl_idx_t].write_size) != 0) { + send_data[0] = ovl_fault; + E("%s, Overlay HW CRC FAIL\n", __func__); + } else { + I("%s, Overlay HW CRC PASS\n", __func__); + } + } + + retry = 0; + do { + g_core_fp.fp_register_write(tmp_addr, + DATA_LEN_4, send_data, 0); + g_core_fp.fp_register_read(tmp_addr, + DATA_LEN_4, recv_data, 0); + retry++; + } while ((send_data[3] != recv_data[3] + || send_data[2] != recv_data[2] + || send_data[1] != recv_data[1] + || send_data[0] != recv_data[0]) + && retry < HIMAX_REG_RETRY_TIMES); +#endif + + } else { + g_core_fp.fp_clean_sram_0f(zf_info_arr[0].sram_addr, + zf_info_arr[0].write_size, 2); + } + + kfree(FW_buf); +ALOC_FW_BUF_FAIL: + kfree(zf_info_arr); +ALOC_ZF_INFO_ARR_FAIL: + return ret; +} + +void himax_mcu_firmware_update_0f(const struct firmware *fw_entry) +{ + int ret = 0; + uint8_t tmp_data[DATA_LEN_4] = {0x01, 0x00, 0x00, 0x00}; + + I("%s,Entering - total FW size=%d\n", __func__, (int)fw_entry->size); + + g_core_fp.fp_register_write(pzf_op->addr_system_reset, 4, + pzf_op->data_system_reset, 0); + + g_core_fp.fp_sense_off(false); + + if ((int)fw_entry->size > HX64K) { + ret = himax_zf_part_info(fw_entry); + } else { + /* first 48K */ + ret = himax_sram_write_crc_check(fw_entry, + pzf_op->data_sram_start_addr, 0, HX_48K_SZ); + if (ret != 0) + E("%s, HW CRC FAIL - Main SRAM 48K\n", __func__); + + /*config info*/ + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(fw_entry, + pzf_op->data_cfg_info, 0xC000, 128); + if (ret != 0) + E("Config info CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_cfg_info, + 128, 2); + } + + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(fw_entry, + pzf_op->data_fw_cfg_1, 0xC0FE, 528); + if (ret != 0) + E("FW config 1 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_fw_cfg_1, + 528, 1); + } + + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(fw_entry, + pzf_op->data_fw_cfg_3, 0xCA00, 128); + if (ret != 0) + E("FW config 3 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_fw_cfg_3, + 128, 2); + } + + /*ADC config*/ + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(fw_entry, + pzf_op->data_adc_cfg_1, 0xD640, 1200); + if (ret != 0) + E("ADC config 1 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_adc_cfg_1, + 1200, 2); + } + + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(fw_entry, + pzf_op->data_adc_cfg_2, 0xD320, 800); + if (ret != 0) + E("ADC config 2 CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_adc_cfg_2, + 800, 2); + } + + /*mapping table*/ + if (G_POWERONOF == 1) { + ret = himax_sram_write_crc_check(fw_entry, + pzf_op->data_map_table, 0xE000, 1536); + if (ret != 0) + E("Mapping table CRC Fail!\n"); + } else { + g_core_fp.fp_clean_sram_0f(pzf_op->data_map_table, + 1536, 2); + } + } + + /* set n frame=0*/ + /*if (G_POWERONOF == 1) + * g_core_fp.fp_write_sram_0f(fw_entry, + pfw_op->addr_set_frame_addr, + 0xC30C, 4); + *else + * g_core_fp.fp_clean_sram_0f(pfw_op->addr_set_frame_addr, 4, 2); + */ + /* reset N frame back to default value 1 for normal mode */ + g_core_fp.fp_register_write(pfw_op->addr_set_frame_addr, 4, + tmp_data, 0); + + I("%s, End\n", __func__); +} + +int hx_0f_op_file_dirly(char *file_name) +{ + int err = NO_ERR, ret; + const struct firmware *fw_entry = NULL; + + + I("%s, Entering,file name = %s\n", __func__, file_name); + + ret = request_firmware(&fw_entry, file_name, private_ts->dev); + if (ret < 0) { +#if defined(__EMBEDDED_FW__) + fw_entry = &g_embedded_fw; + I("%s: Not find FW in userspace, use embedded FW(size:%zu)\n", + __func__, g_embedded_fw.size); +#else + E("%s,%d: error code = %d, file maybe fail\n", + __func__, __LINE__, ret); + return ret; +#endif + } + + himax_int_enable(0); + + if (g_f_0f_updat == 1) { + I("%s:[Warning]Other thread is updating now!\n", __func__); + err = -1; + goto END; + } else { + I("%s:Entering Update Flow!\n", __func__); + g_f_0f_updat = 1; + } + + g_core_fp.fp_firmware_update_0f(fw_entry); + if (ret >= 0) + release_firmware(fw_entry); + + g_f_0f_updat = 0; +END: + I("%s, END\n", __func__); + return err; +} + +int himax_mcu_0f_operation_dirly(void) +{ + int err = NO_ERR, ret; + const struct firmware *fw_entry = NULL; + + I("%s, Entering,file name = %s\n", __func__, BOOT_UPGRADE_FWNAME); + + ret = request_firmware(&fw_entry, BOOT_UPGRADE_FWNAME, + private_ts->dev); + if (ret < 0) { +#if defined(__EMBEDDED_FW__) + fw_entry = &g_embedded_fw; + I("%s: Not find FW in userspace, use embedded FW(size:%zu)\n", + __func__, g_embedded_fw.size); +#else + E("%s,%d: error code = %d, file maybe fail\n", + __func__, __LINE__, ret); + return ret; +#endif + } + + himax_int_enable(0); + + if (g_f_0f_updat == 1) { + I("%s:[Warning]Other thread is updating now!\n", __func__); + err = -1; + goto END; + } else { + I("%s:Entering Update Flow!\n", __func__); + g_f_0f_updat = 1; + } + + g_core_fp.fp_firmware_update_0f(fw_entry); + if (ret >= 0) + release_firmware(fw_entry); + + g_f_0f_updat = 0; +END: + I("%s, END\n", __func__); + return err; +} + +void himax_mcu_0f_operation(struct work_struct *work) +{ + int err = NO_ERR; + const struct firmware *fw_entry = NULL; + + I("%s, Entering,file name = %s\n", __func__, BOOT_UPGRADE_FWNAME); + + err = request_firmware(&fw_entry, BOOT_UPGRADE_FWNAME, + private_ts->dev); + if (err < 0) { +#if defined(__EMBEDDED_FW__) + fw_entry = &g_embedded_fw; + I("%s: Not find FW in userspace, use embedded FW(size:%zu)", + __func__, g_embedded_fw.size); +#else + E("%s,%d: error code = %d, file maybe fail\n", + __func__, __LINE__, err); + goto END; +#endif + } + + if (g_f_0f_updat == 1) { + I("%s:[Warning]Other thread is updating now!\n", __func__); + goto END; + } else { + I("%s:Entering Update Flow!\n", __func__); + g_f_0f_updat = 1; + } + + himax_int_enable(0); + + g_core_fp.fp_firmware_update_0f(fw_entry); + if (err >= 0) + release_firmware(fw_entry); + + g_core_fp.fp_reload_disable(0); + + g_core_fp.fp_power_on_init(); + g_core_fp.fp_read_FW_ver(); + /*msleep (10);*/ + g_core_fp.fp_touch_information(); + g_core_fp.fp_calc_touch_data_size(); + I("%s:End\n", __func__); + himax_int_enable(1); + + g_f_0f_updat = 0; +END: + I("%s, END\n", __func__); +} + +static int himax_mcu_0f_excp_check(void) +{ + return NO_ERR; +} + + +#if defined(HX_0F_DEBUG) +void himax_mcu_read_sram_0f(const struct firmware *fw_entry, + uint8_t *addr, int start_index, int read_len) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int total_size = 0; + int address = 0; + int i = 0, j = 0; + int not_same = 0; + + uint8_t tmp_addr[4]; + uint8_t *temp_info_data = NULL; + int *not_same_buff = NULL; + + I("%s, Entering\n", __func__); + + /*g_core_fp.fp_burst_enable(1);*/ + + total_size = read_len; + + total_size_temp = read_len; + +#if defined(HX_SPI_OPERATION) + if (read_len > 2048) + max_bus_size = 2048; + else + max_bus_size = read_len; +#else + if (read_len > 240) + max_bus_size = 240; + else + max_bus_size = read_len; +#endif + + if (total_size % max_bus_size == 0) + total_read_times = total_size / max_bus_size; + else + total_read_times = total_size / max_bus_size + 1; + + I("%s, total size=%d, bus size=%d, read time=%d\n", + __func__, + total_size, + max_bus_size, + total_read_times); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s,addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + + temp_info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); + if (temp_info_data == NULL) { + E("%s, Failed to allocate temp_info_data\n", __func__); + goto err_malloc_temp_info_data; + } + + not_same_buff = kcalloc(total_size, sizeof(int), GFP_KERNEL); + if (not_same_buff == NULL) { + E("%s, Failed to allocate not_same_buff\n", __func__); + goto err_malloc_not_same_buff; + } + + g_core_fp.fp_burst_enable(1); + + for (i = 0; i < (total_read_times); i++) { + if (total_size_temp >= max_bus_size) { + g_core_fp.fp_register_read(tmp_addr, max_bus_size, + &temp_info_data[i*max_bus_size], false); + total_size_temp = total_size_temp - max_bus_size; + } else { + g_core_fp.fp_register_read(tmp_addr, + total_size_temp % max_bus_size, + &temp_info_data[i*max_bus_size], + false); + } + + address = ((i+1) * max_bus_size); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + if (tmp_addr[0] < addr[0]) + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF) + 1; + else + tmp_addr[1] = addr[1] + + (uint8_t) ((address>>8) & 0x00FF); + + /*msleep (10);*/ + } + I("%s,READ Start, start_index = %d\n", __func__, start_index); + + j = start_index; + for (i = 0; i < read_len; i++, j++) { + if (fw_entry->data[j] != temp_info_data[i]) { + not_same++; + not_same_buff[i] = 1; + } + + I("0x%2.2X, ", temp_info_data[i]); + + if (i > 0 && i%16 == 15) + pr_info("\n"); + + } + I("%s,READ END,Not Same count=%d\n", __func__, not_same); + + if (not_same != 0) { + j = start_index; + for (i = 0; i < read_len; i++, j++) { + if (not_same_buff[i] == 1) + I("bin=[%d] 0x%2.2X\n", i, fw_entry->data[j]); + } + for (i = 0; i < read_len; i++, j++) { + if (not_same_buff[i] == 1) + I("sram=[%d] 0x%2.2X\n", i, temp_info_data[i]); + } + } + I("%s,READ END, Not Same count=%d\n", __func__, not_same); + + kfree(not_same_buff); +err_malloc_not_same_buff: + kfree(temp_info_data); +err_malloc_temp_info_data: + return; +} + +void himax_mcu_read_all_sram(uint8_t *addr, int read_len) +{ + int total_read_times = 0; + int max_bus_size = MAX_I2C_TRANS_SZ; + int total_size_temp = 0; + int total_size = 0; + int address = 0; + int i = 0; + /* struct file *fn; */ + /* struct filename *vts_name; */ + + uint8_t tmp_addr[4]; + uint8_t *temp_info_data; + + I("%s, Entering\n", __func__); + + /*g_core_fp.fp_burst_enable(1);*/ + + total_size = read_len; + + total_size_temp = read_len; + + if (total_size % max_bus_size == 0) + total_read_times = total_size / max_bus_size; + else + total_read_times = total_size / max_bus_size + 1; + + I("%s, total size=%d\n", __func__, total_size); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + I("%s:addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + + temp_info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); + if (temp_info_data == NULL) { + E("%s, Failed to allocate temp_info_data\n", __func__); + return; + } + + g_core_fp.fp_burst_enable(1); + + for (i = 0; i < (total_read_times); i++) { + if (total_size_temp >= max_bus_size) { + g_core_fp.fp_register_read(tmp_addr, + max_bus_size, + &temp_info_data[i*max_bus_size], + false); + total_size_temp = total_size_temp - max_bus_size; + } else { + g_core_fp.fp_register_read(tmp_addr, + total_size_temp % max_bus_size, + &temp_info_data[i*max_bus_size], + false); + } + + address = ((i+1) * max_bus_size); + tmp_addr[1] = addr[1] + (uint8_t) ((address>>8) & 0x00FF); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + + /*msleep (10);*/ + } + I("%s,addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X\n", + __func__, + tmp_addr[3], + tmp_addr[2], + tmp_addr[1], + tmp_addr[0]); + /*for(i = 0;i 0 && i%16 == 15) + * printk("\n"); + *} + */ + + /* need modify + * I("Now Write File start!\n"); + * vts_name = kp_getname_kernel("/sdcard/dump_dsram.txt"); + * fn = kp_file_open_name(vts_name, O_CREAT | O_WRONLY, 0); + * if (!IS_ERR (fn)) { + * I("%s create file and ready to write\n", __func__); + * fn->f_op->write(fn, temp_info_data, read_len*sizeof (uint8_t), + * &fn->f_pos); + * filp_close (fn, NULL); + * } + * I("Now Write File End!\n"); + */ + + kfree(temp_info_data); + + I("%s, END\n", __func__); + +} + +void himax_mcu_firmware_read_0f(const struct firmware *fw_entry, int type) +{ + uint8_t tmp_addr[4]; + + I("%s, Entering\n", __func__); + if (type == 0) { /* first 48K */ + g_core_fp.fp_read_sram_0f(fw_entry, + pzf_op->data_sram_start_addr, + 0, + HX_48K_SZ); + g_core_fp.fp_read_all_sram(tmp_addr, 0xC000); + } else { /*last 16k*/ + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_cfg_info, + 0xC000, 132); + + /*FW config*/ + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_fw_cfg_1, + 0xC0FE, 484); + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_fw_cfg_2, + 0xC9DE, 36); + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_fw_cfg_3, + 0xCA00, 72); + + /*ADC config*/ + + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_adc_cfg_1, + 0xD630, 1188); + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_adc_cfg_2, + 0xD318, 792); + + + /*mapping table*/ + g_core_fp.fp_read_sram_0f(fw_entry, pzf_op->data_map_table, + 0xE000, 1536); + + /* set n frame=0*/ + g_core_fp.fp_read_sram_0f(fw_entry, pfw_op->addr_set_frame_addr, + 0xC30C, 4); + } + + I("%s, END\n", __func__); +} + +void himax_mcu_0f_operation_check(int type) +{ + int err = NO_ERR; + const struct firmware *fw_entry = NULL; + /* char *firmware_name = "himax.bin"; */ + + I("%s, Entering,file name = %s\n", __func__, BOOT_UPGRADE_FWNAME); + + err = request_firmware(&fw_entry, BOOT_UPGRADE_FWNAME, + private_ts->dev); + if (err < 0) { +#if defined(__EMBEDDED_FW__) + fw_entry = &g_embedded_fw; + I("%s: Not find FW in userspace, use embedded FW(size:%zu)\n", + __func__, g_embedded_fw.size); +#else + E("%s,%d: error code = %d\n", __func__, __LINE__, err); + return; +#endif + } + + I("first 4 bytes 0x%2X, 0x%2X, 0x%2X, 0x%2X !\n", + fw_entry->data[0], + fw_entry->data[1], + fw_entry->data[2], + fw_entry->data[3]); + I("next 4 bytes 0x%2X, 0x%2X, 0x%2X, 0x%2X !\n", + fw_entry->data[4], + fw_entry->data[5], + fw_entry->data[6], + fw_entry->data[7]); + I("and next 4 bytes 0x%2X, 0x%2X, 0x%2X, 0x%2X !\n", + fw_entry->data[8], + fw_entry->data[9], + fw_entry->data[10], + fw_entry->data[11]); + + g_core_fp.fp_firmware_read_0f(fw_entry, type); + + if (err >= 0) + release_firmware(fw_entry); + I("%s, END\n", __func__); +} +#endif + +#if defined(HX_CODE_OVERLAY) +int himax_mcu_0f_overlay(int ovl_type, int mode) +{ + return NO_ERR; +} +#endif + +#endif + +/* CORE_INIT */ +/* init start */ +static void himax_mcu_fp_init(void) +{ +/* CORE_IC */ + g_core_fp.fp_burst_enable = himax_mcu_burst_enable; + g_core_fp.fp_register_read = himax_mcu_register_read; + /* + * g_core_fp.fp_flash_write_burst = himax_mcu_flash_write_burst; + */ + /* + * g_core_fp.fp_flash_write_burst_lenth = + * himax_mcu_flash_write_burst_lenth; + */ + g_core_fp.fp_register_write = himax_mcu_register_write; + g_core_fp.fp_interface_on = himax_mcu_interface_on; + g_core_fp.fp_sense_on = himax_mcu_sense_on; + g_core_fp.fp_sense_off = himax_mcu_sense_off; + g_core_fp.fp_wait_wip = himax_mcu_wait_wip; + g_core_fp.fp_init_psl = himax_mcu_init_psl; + g_core_fp.fp_resume_ic_action = himax_mcu_resume_ic_action; + g_core_fp.fp_suspend_ic_action = himax_mcu_suspend_ic_action; + g_core_fp.fp_power_on_init = himax_mcu_power_on_init; + g_core_fp.fp_dd_clk_set = himax_mcu_dd_clk_set; + g_core_fp.fp_dd_reg_en = himax_mcu_dd_reg_en; + g_core_fp.fp_ic_id_read = himax_mcu_ic_id_read; + g_core_fp.fp_dd_reg_write = himax_mcu_dd_reg_write; + g_core_fp.fp_dd_reg_read = himax_mcu_dd_reg_read; +/* CORE_IC */ +/* CORE_FW */ + g_core_fp.fp_system_reset = himax_mcu_system_reset; + g_core_fp.fp_Calculate_CRC_with_AP = himax_mcu_Calculate_CRC_with_AP; + g_core_fp.fp_check_CRC = himax_mcu_check_CRC; + g_core_fp.fp_set_reload_cmd = himax_mcu_set_reload_cmd; + g_core_fp.fp_program_reload = himax_mcu_program_reload; +#if defined(HX_ULTRA_LOW_POWER) + g_core_fp.fp_ulpm_in = himax_mcu_ulpm_in; + g_core_fp.fp_black_gest_ctrl = himax_mcu_black_gest_ctrl; +#endif + g_core_fp.fp_set_SMWP_enable = himax_mcu_set_SMWP_enable; + g_core_fp.fp_set_HSEN_enable = himax_mcu_set_HSEN_enable; + g_core_fp.fp_usb_detect_set = himax_mcu_usb_detect_set; + g_core_fp.fp_diag_register_set = himax_mcu_diag_register_set; + g_core_fp.fp_chip_self_test = himax_mcu_chip_self_test; + g_core_fp.fp_idle_mode = himax_mcu_idle_mode; + g_core_fp.fp_reload_disable = himax_mcu_reload_disable; + g_core_fp.fp_check_chip_version = himax_mcu_check_chip_version; + g_core_fp.fp_read_ic_trigger_type = himax_mcu_read_ic_trigger_type; + g_core_fp.fp_read_i2c_status = himax_mcu_read_i2c_status; + g_core_fp.fp_read_FW_ver = himax_mcu_read_FW_ver; + g_core_fp.fp_read_event_stack = himax_mcu_read_event_stack; + g_core_fp.fp_return_event_stack = himax_mcu_return_event_stack; + g_core_fp.fp_calculateChecksum = himax_mcu_calculateChecksum; + g_core_fp.fp_read_FW_status = himax_mcu_read_FW_status; + g_core_fp.fp_irq_switch = himax_mcu_irq_switch; + g_core_fp.fp_assign_sorting_mode = himax_mcu_assign_sorting_mode; + g_core_fp.fp_check_sorting_mode = himax_mcu_check_sorting_mode; + g_core_fp.fp_read_DD_status = himax_mcu_read_DD_status; + g_core_fp._clr_fw_reord_dd_sts = hx_clr_fw_reord_dd_sts; + g_core_fp._ap_notify_fw_sus = hx_ap_notify_fw_sus; +/* CORE_FW */ +/* CORE_FLASH */ + g_core_fp.fp_chip_erase = himax_mcu_chip_erase; + g_core_fp.fp_block_erase = himax_mcu_block_erase; + g_core_fp.fp_sector_erase = himax_mcu_sector_erase; + g_core_fp.fp_flash_programming = himax_mcu_flash_programming; + g_core_fp.fp_flash_page_write = himax_mcu_flash_page_write; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_32k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_60k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_64k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_124k; + g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k = + himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_128k; + g_core_fp.fp_flash_dump_func = himax_mcu_flash_dump_func; + g_core_fp.fp_flash_lastdata_check = himax_mcu_flash_lastdata_check; + g_core_fp.fp_bin_desc_get = hx_mcu_bin_desc_get; + g_core_fp._diff_overlay_flash = hx_mcu_diff_overlay_flash; +/* CORE_FLASH */ +/* CORE_SRAM */ + g_core_fp.fp_sram_write = himax_mcu_sram_write; + g_core_fp.fp_sram_verify = himax_mcu_sram_verify; + g_core_fp.fp_get_DSRAM_data = himax_mcu_get_DSRAM_data; +/* CORE_SRAM */ +/* CORE_DRIVER */ + g_core_fp.fp_chip_init = himax_mcu_init_ic; +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + g_core_fp.fp_fw_ver_bin = himax_mcu_fw_ver_bin; +#endif +#if defined(HX_RST_PIN_FUNC) + g_core_fp.fp_pin_reset = himax_mcu_pin_reset; + g_core_fp.fp_ic_reset = himax_mcu_ic_reset; +#endif + g_core_fp.fp_touch_information = himax_mcu_touch_information; + g_core_fp.fp_calc_touch_data_size = himax_mcu_calcTouchDataSize; + /*g_core_fp.fp_reload_config = himax_mcu_reload_config;*/ + g_core_fp.fp_get_touch_data_size = himax_mcu_get_touch_data_size; + g_core_fp.fp_hand_shaking = himax_mcu_hand_shaking; + g_core_fp.fp_determin_diag_rawdata = himax_mcu_determin_diag_rawdata; + g_core_fp.fp_determin_diag_storage = himax_mcu_determin_diag_storage; + g_core_fp.fp_cal_data_len = himax_mcu_cal_data_len; + g_core_fp.fp_diag_check_sum = himax_mcu_diag_check_sum; + g_core_fp.fp_diag_parse_raw_data = himax_mcu_diag_parse_raw_data; +#if defined(HX_EXCP_RECOVERY) + g_core_fp.fp_ic_excp_recovery = himax_mcu_ic_excp_recovery; + g_core_fp.fp_excp_ic_reset = himax_mcu_excp_ic_reset; +#endif +#if defined(HX_SMART_WAKEUP)\ + || defined(HX_HIGH_SENSE)\ + || defined(HX_USB_DETECT_GLOBAL) + g_core_fp.fp_resend_cmd_func = himax_mcu_resend_cmd_func; +#endif +#if defined(HX_TP_PROC_GUEST_INFO) + g_core_fp.guest_info_get_status = himax_guest_info_get_status; + g_core_fp.read_guest_info = hx_read_guest_info; +#endif + g_core_fp.read_mcf_data = hx_read_mcf_data; +/* CORE_DRIVER */ +#if defined(HX_ZERO_FLASH) + g_core_fp.fp_reload_disable = hx_dis_rload_0f; + g_core_fp.fp_clean_sram_0f = himax_mcu_clean_sram_0f; + g_core_fp.fp_write_sram_0f = himax_mcu_write_sram_0f; + g_core_fp.fp_write_sram_0f_crc = himax_sram_write_crc_check; + g_core_fp.fp_firmware_update_0f = himax_mcu_firmware_update_0f; + g_core_fp.fp_0f_operation = himax_mcu_0f_operation; + g_core_fp.fp_0f_operation_dirly = himax_mcu_0f_operation_dirly; + g_core_fp.fp_0f_op_file_dirly = hx_0f_op_file_dirly; + g_core_fp.fp_0f_excp_check = himax_mcu_0f_excp_check; +#if defined(HX_0F_DEBUG) + g_core_fp.fp_read_sram_0f = himax_mcu_read_sram_0f; + g_core_fp.fp_read_all_sram = himax_mcu_read_all_sram; + g_core_fp.fp_firmware_read_0f = himax_mcu_firmware_read_0f; + g_core_fp.fp_0f_operation_check = himax_mcu_0f_operation_check; +#endif +#if defined(HX_CODE_OVERLAY) + g_core_fp.fp_0f_overlay = himax_mcu_0f_overlay; +#endif +#endif +} + +int himax_mcu_in_cmd_struct_init(void) +{ + int err = 0; + + I("%s: Entering!\n", __func__); + himax_mcu_cmd_struct_free = himax_mcu_in_cmd_struct_free; + + g_core_cmd_op = kzalloc(sizeof(struct himax_core_command_operation), + GFP_KERNEL); + if (g_core_cmd_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_fail; + } + + g_core_cmd_op->ic_op = kzalloc(sizeof(struct ic_operation), GFP_KERNEL); + if (g_core_cmd_op->ic_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_ic_op_fail; + } + + g_core_cmd_op->fw_op = kzalloc(sizeof(struct fw_operation), GFP_KERNEL); + if (g_core_cmd_op->fw_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_fw_op_fail; + } + + g_core_cmd_op->flash_op = kzalloc(sizeof(struct flash_operation), + GFP_KERNEL); + if (g_core_cmd_op->flash_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_flash_op_fail; + } + + g_core_cmd_op->sram_op = kzalloc(sizeof(struct sram_operation), + GFP_KERNEL); + if (g_core_cmd_op->sram_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_sram_op_fail; + } + + g_core_cmd_op->driver_op = kzalloc(sizeof(struct driver_operation), + GFP_KERNEL); + if (g_core_cmd_op->driver_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_driver_op_fail; + } + + pic_op = g_core_cmd_op->ic_op; + pfw_op = g_core_cmd_op->fw_op; + pflash_op = g_core_cmd_op->flash_op; + psram_op = g_core_cmd_op->sram_op; + pdriver_op = g_core_cmd_op->driver_op; +#if defined(HX_ZERO_FLASH) + g_core_cmd_op->zf_op = kzalloc(sizeof(struct zf_operation), + GFP_KERNEL); + if (g_core_cmd_op->zf_op == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_zf_op_fail; + } + pzf_op = g_core_cmd_op->zf_op; + +#endif + + g_internal_buffer = kzalloc(sizeof(uint8_t)*HX_MAX_WRITE_SZ, + GFP_KERNEL); + + if (g_internal_buffer == NULL) { + err = -ENOMEM; + goto err_g_core_cmd_op_g_internal_buffer_fail; + } + himax_mcu_fp_init(); + + return NO_ERR; + +err_g_core_cmd_op_g_internal_buffer_fail: +#if defined(HX_ZERO_FLASH) + kfree(g_core_cmd_op->zf_op); + g_core_cmd_op->zf_op = NULL; +err_g_core_cmd_op_zf_op_fail: +#endif + kfree(g_core_cmd_op->driver_op); + g_core_cmd_op->driver_op = NULL; +err_g_core_cmd_op_driver_op_fail: + kfree(g_core_cmd_op->sram_op); + g_core_cmd_op->sram_op = NULL; +err_g_core_cmd_op_sram_op_fail: + kfree(g_core_cmd_op->flash_op); + g_core_cmd_op->flash_op = NULL; +err_g_core_cmd_op_flash_op_fail: + kfree(g_core_cmd_op->fw_op); + g_core_cmd_op->fw_op = NULL; +err_g_core_cmd_op_fw_op_fail: + kfree(g_core_cmd_op->ic_op); + g_core_cmd_op->ic_op = NULL; +err_g_core_cmd_op_ic_op_fail: + kfree(g_core_cmd_op); + g_core_cmd_op = NULL; +err_g_core_cmd_op_fail: + + return err; +} +EXPORT_SYMBOL(himax_mcu_in_cmd_struct_init); + +void himax_mcu_in_cmd_struct_free(void) +{ + pic_op = NULL; + pfw_op = NULL; + pflash_op = NULL; + psram_op = NULL; + pdriver_op = NULL; + kfree(g_internal_buffer); + g_internal_buffer = NULL; +#if defined(HX_ZERO_FLASH) + kfree(g_core_cmd_op->zf_op); + g_core_cmd_op->zf_op = NULL; +#endif + kfree(g_core_cmd_op->driver_op); + g_core_cmd_op->driver_op = NULL; + kfree(g_core_cmd_op->sram_op); + g_core_cmd_op->sram_op = NULL; + kfree(g_core_cmd_op->flash_op); + g_core_cmd_op->flash_op = NULL; + kfree(g_core_cmd_op->fw_op); + g_core_cmd_op->fw_op = NULL; + kfree(g_core_cmd_op->ic_op); + g_core_cmd_op->ic_op = NULL; + kfree(g_core_cmd_op); + g_core_cmd_op = NULL; + + I("%s: release completed\n", __func__); +} + +void himax_mcu_in_cmd_init(void) +{ + I("%s: Entering!\n", __func__); +/* CORE_IC */ + himax_parse_assign_cmd(ic_adr_ahb_addr_byte_0, + pic_op->addr_ahb_addr_byte_0, + sizeof(pic_op->addr_ahb_addr_byte_0)); + himax_parse_assign_cmd(ic_adr_ahb_rdata_byte_0, + pic_op->addr_ahb_rdata_byte_0, + sizeof(pic_op->addr_ahb_rdata_byte_0)); + himax_parse_assign_cmd(ic_adr_ahb_access_direction, + pic_op->addr_ahb_access_direction, + sizeof(pic_op->addr_ahb_access_direction)); + himax_parse_assign_cmd(ic_adr_conti, pic_op->addr_conti, + sizeof(pic_op->addr_conti)); + himax_parse_assign_cmd(ic_adr_incr4, pic_op->addr_incr4, + sizeof(pic_op->addr_incr4)); + himax_parse_assign_cmd(ic_adr_i2c_psw_lb, pic_op->adr_i2c_psw_lb, + sizeof(pic_op->adr_i2c_psw_lb)); + himax_parse_assign_cmd(ic_adr_i2c_psw_ub, pic_op->adr_i2c_psw_ub, + sizeof(pic_op->adr_i2c_psw_ub)); + himax_parse_assign_cmd(ic_cmd_ahb_access_direction_read, + pic_op->data_ahb_access_direction_read, + sizeof(pic_op->data_ahb_access_direction_read)); + himax_parse_assign_cmd(ic_cmd_conti, pic_op->data_conti, + sizeof(pic_op->data_conti)); + himax_parse_assign_cmd(ic_cmd_incr4, pic_op->data_incr4, + sizeof(pic_op->data_incr4)); + himax_parse_assign_cmd(ic_cmd_i2c_psw_lb, pic_op->data_i2c_psw_lb, + sizeof(pic_op->data_i2c_psw_lb)); + himax_parse_assign_cmd(ic_cmd_i2c_psw_ub, pic_op->data_i2c_psw_ub, + sizeof(pic_op->data_i2c_psw_ub)); + himax_parse_assign_cmd(ic_adr_tcon_on_rst, pic_op->addr_tcon_on_rst, + sizeof(pic_op->addr_tcon_on_rst)); + himax_parse_assign_cmd(ic_addr_adc_on_rst, pic_op->addr_adc_on_rst, + sizeof(pic_op->addr_adc_on_rst)); + himax_parse_assign_cmd(ic_adr_psl, pic_op->addr_psl, + sizeof(pic_op->addr_psl)); + himax_parse_assign_cmd(ic_adr_cs_central_state, + pic_op->addr_cs_central_state, + sizeof(pic_op->addr_cs_central_state)); + himax_parse_assign_cmd(ic_cmd_rst, pic_op->data_rst, + sizeof(pic_op->data_rst)); + himax_parse_assign_cmd(ic_adr_osc_en, pic_op->adr_osc_en, + sizeof(pic_op->adr_osc_en)); + himax_parse_assign_cmd(ic_adr_osc_pw, pic_op->adr_osc_pw, + sizeof(pic_op->adr_osc_pw)); +/* CORE_IC */ +/* CORE_FW */ + himax_parse_assign_cmd(fw_addr_system_reset, + pfw_op->addr_system_reset, + sizeof(pfw_op->addr_system_reset)); + himax_parse_assign_cmd(fw_addr_ctrl_fw, + pfw_op->addr_ctrl_fw_isr, + sizeof(pfw_op->addr_ctrl_fw_isr)); + himax_parse_assign_cmd(fw_addr_flag_reset_event, + pfw_op->addr_flag_reset_event, + sizeof(pfw_op->addr_flag_reset_event)); + himax_parse_assign_cmd(fw_addr_hsen_enable, + pfw_op->addr_hsen_enable, + sizeof(pfw_op->addr_hsen_enable)); + himax_parse_assign_cmd(fw_addr_smwp_enable, + pfw_op->addr_smwp_enable, + sizeof(pfw_op->addr_smwp_enable)); + himax_parse_assign_cmd(fw_addr_program_reload_from, + pfw_op->addr_program_reload_from, + sizeof(pfw_op->addr_program_reload_from)); + himax_parse_assign_cmd(fw_addr_program_reload_to, + pfw_op->addr_program_reload_to, + sizeof(pfw_op->addr_program_reload_to)); + himax_parse_assign_cmd(fw_addr_program_reload_page_write, + pfw_op->addr_program_reload_page_write, + sizeof(pfw_op->addr_program_reload_page_write)); + himax_parse_assign_cmd(fw_addr_raw_out_sel, + pfw_op->addr_raw_out_sel, + sizeof(pfw_op->addr_raw_out_sel)); + himax_parse_assign_cmd(fw_addr_reload_status, + pfw_op->addr_reload_status, + sizeof(pfw_op->addr_reload_status)); + himax_parse_assign_cmd(fw_addr_reload_crc32_result, + pfw_op->addr_reload_crc32_result, + sizeof(pfw_op->addr_reload_crc32_result)); + himax_parse_assign_cmd(fw_addr_reload_addr_from, + pfw_op->addr_reload_addr_from, + sizeof(pfw_op->addr_reload_addr_from)); + himax_parse_assign_cmd(fw_addr_reload_addr_cmd_beat, + pfw_op->addr_reload_addr_cmd_beat, + sizeof(pfw_op->addr_reload_addr_cmd_beat)); + himax_parse_assign_cmd(fw_addr_selftest_addr_en, + pfw_op->addr_selftest_addr_en, + sizeof(pfw_op->addr_selftest_addr_en)); + himax_parse_assign_cmd(fw_addr_criteria_addr, + pfw_op->addr_criteria_addr, + sizeof(pfw_op->addr_criteria_addr)); + himax_parse_assign_cmd(fw_addr_set_frame_addr, + pfw_op->addr_set_frame_addr, + sizeof(pfw_op->addr_set_frame_addr)); + himax_parse_assign_cmd(fw_addr_selftest_result_addr, + pfw_op->addr_selftest_result_addr, + sizeof(pfw_op->addr_selftest_result_addr)); + himax_parse_assign_cmd(fw_addr_sorting_mode_en, + pfw_op->addr_sorting_mode_en, + sizeof(pfw_op->addr_sorting_mode_en)); + himax_parse_assign_cmd(fw_addr_fw_mode_status, + pfw_op->addr_fw_mode_status, + sizeof(pfw_op->addr_fw_mode_status)); + himax_parse_assign_cmd(fw_addr_icid_addr, + pfw_op->addr_icid_addr, + sizeof(pfw_op->addr_icid_addr)); + himax_parse_assign_cmd(fw_addr_fw_ver_addr, + pfw_op->addr_fw_ver_addr, + sizeof(pfw_op->addr_fw_ver_addr)); + himax_parse_assign_cmd(fw_addr_fw_cfg_addr, + pfw_op->addr_fw_cfg_addr, + sizeof(pfw_op->addr_fw_cfg_addr)); + himax_parse_assign_cmd(fw_addr_fw_vendor_addr, + pfw_op->addr_fw_vendor_addr, + sizeof(pfw_op->addr_fw_vendor_addr)); + himax_parse_assign_cmd(fw_addr_cus_info, + pfw_op->addr_cus_info, + sizeof(pfw_op->addr_cus_info)); + himax_parse_assign_cmd(fw_addr_proj_info, + pfw_op->addr_proj_info, + sizeof(pfw_op->addr_proj_info)); + himax_parse_assign_cmd(fw_addr_fw_state_addr, + pfw_op->addr_fw_state_addr, + sizeof(pfw_op->addr_fw_state_addr)); + himax_parse_assign_cmd(fw_addr_fw_dbg_msg_addr, + pfw_op->addr_fw_dbg_msg_addr, + sizeof(pfw_op->addr_fw_dbg_msg_addr)); + himax_parse_assign_cmd(fw_addr_chk_fw_status, + pfw_op->addr_chk_fw_status, + sizeof(pfw_op->addr_chk_fw_status)); + himax_parse_assign_cmd(fw_addr_dd_handshak_addr, + pfw_op->addr_dd_handshak_addr, + sizeof(pfw_op->addr_dd_handshak_addr)); + himax_parse_assign_cmd(fw_addr_dd_data_addr, + pfw_op->addr_dd_data_addr, + sizeof(pfw_op->addr_dd_data_addr)); + himax_parse_assign_cmd(fw_addr_clr_fw_record_dd_sts, + pfw_op->addr_clr_fw_record_dd_sts, + sizeof(pfw_op->addr_clr_fw_record_dd_sts)); + himax_parse_assign_cmd(fw_addr_ap_notify_fw_sus, + pfw_op->addr_ap_notify_fw_sus, + sizeof(pfw_op->addr_ap_notify_fw_sus)); + himax_parse_assign_cmd(fw_data_ap_notify_fw_sus_en, + pfw_op->data_ap_notify_fw_sus_en, + sizeof(pfw_op->data_ap_notify_fw_sus_en)); + himax_parse_assign_cmd(fw_data_ap_notify_fw_sus_dis, + pfw_op->data_ap_notify_fw_sus_dis, + sizeof(pfw_op->data_ap_notify_fw_sus_dis)); + himax_parse_assign_cmd(fw_data_system_reset, + pfw_op->data_system_reset, + sizeof(pfw_op->data_system_reset)); + himax_parse_assign_cmd(fw_data_safe_mode_release_pw_active, + pfw_op->data_safe_mode_release_pw_active, + sizeof(pfw_op->data_safe_mode_release_pw_active)); + himax_parse_assign_cmd(fw_data_clear, + pfw_op->data_clear, + sizeof(pfw_op->data_clear)); + himax_parse_assign_cmd(fw_data_clear, + pfw_op->data_clear, + sizeof(pfw_op->data_clear)); + himax_parse_assign_cmd(fw_data_fw_stop, + pfw_op->data_fw_stop, + sizeof(pfw_op->data_fw_stop)); + himax_parse_assign_cmd(fw_data_safe_mode_release_pw_reset, + pfw_op->data_safe_mode_release_pw_reset, + sizeof(pfw_op->data_safe_mode_release_pw_reset)); + himax_parse_assign_cmd(fw_data_program_reload_start, + pfw_op->data_program_reload_start, + sizeof(pfw_op->data_program_reload_start)); + himax_parse_assign_cmd(fw_data_program_reload_compare, + pfw_op->data_program_reload_compare, + sizeof(pfw_op->data_program_reload_compare)); + himax_parse_assign_cmd(fw_data_program_reload_break, + pfw_op->data_program_reload_break, + sizeof(pfw_op->data_program_reload_break)); + himax_parse_assign_cmd(fw_data_selftest_request, + pfw_op->data_selftest_request, + sizeof(pfw_op->data_selftest_request)); + himax_parse_assign_cmd(fw_data_criteria_aa_top, + pfw_op->data_criteria_aa_top, + sizeof(pfw_op->data_criteria_aa_top)); + himax_parse_assign_cmd(fw_data_criteria_aa_bot, + pfw_op->data_criteria_aa_bot, + sizeof(pfw_op->data_criteria_aa_bot)); + himax_parse_assign_cmd(fw_data_criteria_key_top, + pfw_op->data_criteria_key_top, + sizeof(pfw_op->data_criteria_key_top)); + himax_parse_assign_cmd(fw_data_criteria_key_bot, + pfw_op->data_criteria_key_bot, + sizeof(pfw_op->data_criteria_key_bot)); + himax_parse_assign_cmd(fw_data_criteria_avg_top, + pfw_op->data_criteria_avg_top, + sizeof(pfw_op->data_criteria_avg_top)); + himax_parse_assign_cmd(fw_data_criteria_avg_bot, + pfw_op->data_criteria_avg_bot, + sizeof(pfw_op->data_criteria_avg_bot)); + himax_parse_assign_cmd(fw_data_set_frame, + pfw_op->data_set_frame, + sizeof(pfw_op->data_set_frame)); + himax_parse_assign_cmd(fw_data_selftest_ack_hb, + pfw_op->data_selftest_ack_hb, + sizeof(pfw_op->data_selftest_ack_hb)); + himax_parse_assign_cmd(fw_data_selftest_ack_lb, + pfw_op->data_selftest_ack_lb, + sizeof(pfw_op->data_selftest_ack_lb)); + himax_parse_assign_cmd(fw_data_selftest_pass, + pfw_op->data_selftest_pass, + sizeof(pfw_op->data_selftest_pass)); + himax_parse_assign_cmd(fw_data_normal_cmd, + pfw_op->data_normal_cmd, + sizeof(pfw_op->data_normal_cmd)); + himax_parse_assign_cmd(fw_data_normal_status, + pfw_op->data_normal_status, + sizeof(pfw_op->data_normal_status)); + himax_parse_assign_cmd(fw_data_sorting_cmd, + pfw_op->data_sorting_cmd, + sizeof(pfw_op->data_sorting_cmd)); + himax_parse_assign_cmd(fw_data_sorting_status, + pfw_op->data_sorting_status, + sizeof(pfw_op->data_sorting_status)); + himax_parse_assign_cmd(fw_data_dd_request, + pfw_op->data_dd_request, + sizeof(pfw_op->data_dd_request)); + himax_parse_assign_cmd(fw_data_dd_ack, + pfw_op->data_dd_ack, + sizeof(pfw_op->data_dd_ack)); + himax_parse_assign_cmd(fw_data_idle_dis_pwd, + pfw_op->data_idle_dis_pwd, + sizeof(pfw_op->data_idle_dis_pwd)); + himax_parse_assign_cmd(fw_data_idle_en_pwd, + pfw_op->data_idle_en_pwd, + sizeof(pfw_op->data_idle_en_pwd)); + himax_parse_assign_cmd(fw_data_rawdata_ready_hb, + pfw_op->data_rawdata_ready_hb, + sizeof(pfw_op->data_rawdata_ready_hb)); + himax_parse_assign_cmd(fw_data_rawdata_ready_lb, + pfw_op->data_rawdata_ready_lb, + sizeof(pfw_op->data_rawdata_ready_lb)); + himax_parse_assign_cmd(fw_addr_ahb_addr, + pfw_op->addr_ahb_addr, + sizeof(pfw_op->addr_ahb_addr)); + himax_parse_assign_cmd(fw_data_ahb_dis, + pfw_op->data_ahb_dis, + sizeof(pfw_op->data_ahb_dis)); + himax_parse_assign_cmd(fw_data_ahb_en, + pfw_op->data_ahb_en, + sizeof(pfw_op->data_ahb_en)); + himax_parse_assign_cmd(fw_addr_event_addr, + pfw_op->addr_event_addr, + sizeof(pfw_op->addr_event_addr)); + himax_parse_assign_cmd(fw_usb_detect_addr, + pfw_op->addr_usb_detect, + sizeof(pfw_op->addr_usb_detect)); +#if defined(HX_ULTRA_LOW_POWER) + himax_parse_assign_cmd(fw_addr_ulpm_33, pfw_op->addr_ulpm_33, + sizeof(pfw_op->addr_ulpm_33)); + himax_parse_assign_cmd(fw_addr_ulpm_34, pfw_op->addr_ulpm_34, + sizeof(pfw_op->addr_ulpm_34)); + himax_parse_assign_cmd(fw_data_ulpm_11, pfw_op->data_ulpm_11, + sizeof(pfw_op->data_ulpm_11)); + himax_parse_assign_cmd(fw_data_ulpm_22, pfw_op->data_ulpm_22, + sizeof(pfw_op->data_ulpm_22)); + himax_parse_assign_cmd(fw_data_ulpm_33, pfw_op->data_ulpm_33, + sizeof(pfw_op->data_ulpm_33)); + himax_parse_assign_cmd(fw_data_ulpm_aa, pfw_op->data_ulpm_aa, + sizeof(pfw_op->data_ulpm_aa)); +#endif +/* CORE_FW */ +/* CORE_FLASH */ + himax_parse_assign_cmd(flash_addr_spi200_trans_fmt, + pflash_op->addr_spi200_trans_fmt, + sizeof(pflash_op->addr_spi200_trans_fmt)); + himax_parse_assign_cmd(flash_addr_spi200_trans_ctrl, + pflash_op->addr_spi200_trans_ctrl, + sizeof(pflash_op->addr_spi200_trans_ctrl)); + himax_parse_assign_cmd(flash_addr_spi200_fifo_rst, + pflash_op->addr_spi200_fifo_rst, + sizeof(pflash_op->addr_spi200_fifo_rst)); + himax_parse_assign_cmd(flash_addr_spi200_flash_speed, + pflash_op->addr_spi200_flash_speed, + sizeof(pflash_op->addr_spi200_flash_speed)); + himax_parse_assign_cmd(flash_addr_spi200_rst_status, + pflash_op->addr_spi200_rst_status, + sizeof(pflash_op->addr_spi200_rst_status)); + himax_parse_assign_cmd(flash_addr_spi200_cmd, + pflash_op->addr_spi200_cmd, + sizeof(pflash_op->addr_spi200_cmd)); + himax_parse_assign_cmd(flash_addr_spi200_addr, + pflash_op->addr_spi200_addr, + sizeof(pflash_op->addr_spi200_addr)); + himax_parse_assign_cmd(flash_addr_spi200_data, + pflash_op->addr_spi200_data, + sizeof(pflash_op->addr_spi200_data)); + himax_parse_assign_cmd(flash_addr_spi200_bt_num, + pflash_op->addr_spi200_bt_num, + sizeof(pflash_op->addr_spi200_bt_num)); + himax_parse_assign_cmd(flash_data_spi200_trans_fmt, + pflash_op->data_spi200_trans_fmt, + sizeof(pflash_op->data_spi200_trans_fmt)); + himax_parse_assign_cmd(flash_data_spi200_txfifo_rst, + pflash_op->data_spi200_txfifo_rst, + sizeof(pflash_op->data_spi200_txfifo_rst)); + himax_parse_assign_cmd(flash_data_spi200_rxfifo_rst, + pflash_op->data_spi200_rxfifo_rst, + sizeof(pflash_op->data_spi200_rxfifo_rst)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_1, + pflash_op->data_spi200_trans_ctrl_1, + sizeof(pflash_op->data_spi200_trans_ctrl_1)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_2, + pflash_op->data_spi200_trans_ctrl_2, + sizeof(pflash_op->data_spi200_trans_ctrl_2)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_3, + pflash_op->data_spi200_trans_ctrl_3, + sizeof(pflash_op->data_spi200_trans_ctrl_3)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_4, + pflash_op->data_spi200_trans_ctrl_4, + sizeof(pflash_op->data_spi200_trans_ctrl_4)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_5, + pflash_op->data_spi200_trans_ctrl_5, + sizeof(pflash_op->data_spi200_trans_ctrl_5)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_6, + pflash_op->data_spi200_trans_ctrl_6, + sizeof(pflash_op->data_spi200_trans_ctrl_6)); + himax_parse_assign_cmd(flash_data_spi200_trans_ctrl_7, + pflash_op->data_spi200_trans_ctrl_7, + sizeof(pflash_op->data_spi200_trans_ctrl_7)); + himax_parse_assign_cmd(flash_data_spi200_cmd_1, + pflash_op->data_spi200_cmd_1, + sizeof(pflash_op->data_spi200_cmd_1)); + himax_parse_assign_cmd(flash_data_spi200_cmd_2, + pflash_op->data_spi200_cmd_2, + sizeof(pflash_op->data_spi200_cmd_2)); + himax_parse_assign_cmd(flash_data_spi200_cmd_3, + pflash_op->data_spi200_cmd_3, + sizeof(pflash_op->data_spi200_cmd_3)); + himax_parse_assign_cmd(flash_data_spi200_cmd_4, + pflash_op->data_spi200_cmd_4, + sizeof(pflash_op->data_spi200_cmd_4)); + himax_parse_assign_cmd(flash_data_spi200_cmd_5, + pflash_op->data_spi200_cmd_5, + sizeof(pflash_op->data_spi200_cmd_5)); + himax_parse_assign_cmd(flash_data_spi200_cmd_6, + pflash_op->data_spi200_cmd_6, + sizeof(pflash_op->data_spi200_cmd_6)); + himax_parse_assign_cmd(flash_data_spi200_cmd_7, + pflash_op->data_spi200_cmd_7, + sizeof(pflash_op->data_spi200_cmd_7)); + himax_parse_assign_cmd(flash_data_spi200_cmd_8, + pflash_op->data_spi200_cmd_8, + sizeof(pflash_op->data_spi200_cmd_8)); + himax_parse_assign_cmd(flash_data_spi200_addr, + pflash_op->data_spi200_addr, + sizeof(pflash_op->data_spi200_addr)); +/* CORE_FLASH */ +/* CORE_SRAM */ + /* sram start*/ + himax_parse_assign_cmd(sram_adr_mkey, + psram_op->addr_mkey, + sizeof(psram_op->addr_mkey)); + himax_parse_assign_cmd(sram_adr_rawdata_addr, + psram_op->addr_rawdata_addr, + sizeof(psram_op->addr_rawdata_addr)); + himax_parse_assign_cmd(sram_adr_rawdata_end, + psram_op->addr_rawdata_end, + sizeof(psram_op->addr_rawdata_end)); + himax_parse_assign_cmd(sram_passwrd_start, + psram_op->passwrd_start, + sizeof(psram_op->passwrd_start)); + himax_parse_assign_cmd(sram_passwrd_end, + psram_op->passwrd_end, + sizeof(psram_op->passwrd_end)); + /* sram end*/ +/* CORE_SRAM */ +/* CORE_DRIVER */ + himax_parse_assign_cmd(driver_addr_fw_define_flash_reload, + pdriver_op->addr_fw_define_flash_reload, + sizeof(pdriver_op->addr_fw_define_flash_reload)); + himax_parse_assign_cmd(driver_addr_fw_define_2nd_flash_reload, + pdriver_op->addr_fw_define_2nd_flash_reload, + sizeof(pdriver_op->addr_fw_define_2nd_flash_reload)); + himax_parse_assign_cmd(driver_addr_fw_define_int_is_edge, + pdriver_op->addr_fw_define_int_is_edge, + sizeof(pdriver_op->addr_fw_define_int_is_edge)); + himax_parse_assign_cmd(driver_addr_fw_define_rxnum_txnum_maxpt, + pdriver_op->addr_fw_define_rxnum_txnum_maxpt, + sizeof(pdriver_op->addr_fw_define_rxnum_txnum_maxpt)); + himax_parse_assign_cmd(driver_addr_fw_define_xy_res_enable, + pdriver_op->addr_fw_define_xy_res_enable, + sizeof(pdriver_op->addr_fw_define_xy_res_enable)); + himax_parse_assign_cmd(driver_addr_fw_define_x_y_res, + pdriver_op->addr_fw_define_x_y_res, + sizeof(pdriver_op->addr_fw_define_x_y_res)); + himax_parse_assign_cmd(driver_data_df_rx, + pdriver_op->data_df_rx, + sizeof(pdriver_op->data_df_rx)); + himax_parse_assign_cmd(driver_data_df_tx, + pdriver_op->data_df_tx, + sizeof(pdriver_op->data_df_tx)); + himax_parse_assign_cmd(driver_data_df_pt, + pdriver_op->data_df_pt, + sizeof(pdriver_op->data_df_pt)); + himax_parse_assign_cmd(driver_data_fw_define_flash_reload_dis, + pdriver_op->data_fw_define_flash_reload_dis, + sizeof(pdriver_op->data_fw_define_flash_reload_dis)); + himax_parse_assign_cmd(driver_data_fw_define_flash_reload_en, + pdriver_op->data_fw_define_flash_reload_en, + sizeof(pdriver_op->data_fw_define_flash_reload_en)); + himax_parse_assign_cmd( + driver_data_fw_define_rxnum_txnum_maxpt_sorting, + pdriver_op->data_fw_define_rxnum_txnum_maxpt_sorting, + sizeof(pdriver_op->data_fw_define_rxnum_txnum_maxpt_sorting)); + himax_parse_assign_cmd( + driver_data_fw_define_rxnum_txnum_maxpt_normal, + pdriver_op->data_fw_define_rxnum_txnum_maxpt_normal, + sizeof(pdriver_op->data_fw_define_rxnum_txnum_maxpt_normal)); +/* CORE_DRIVER */ +#if defined(HX_ZERO_FLASH) + himax_parse_assign_cmd(zf_data_dis_flash_reload, + pzf_op->data_dis_flash_reload, + sizeof(pzf_op->data_dis_flash_reload)); + himax_parse_assign_cmd(zf_addr_system_reset, + pzf_op->addr_system_reset, + sizeof(pzf_op->addr_system_reset)); + himax_parse_assign_cmd(zf_data_system_reset, + pzf_op->data_system_reset, + sizeof(pzf_op->data_system_reset)); + himax_parse_assign_cmd(zf_data_sram_start_addr, + pzf_op->data_sram_start_addr, + sizeof(pzf_op->data_sram_start_addr)); + himax_parse_assign_cmd(zf_data_cfg_info, + pzf_op->data_cfg_info, + sizeof(pzf_op->data_cfg_info)); + himax_parse_assign_cmd(zf_data_fw_cfg_1, + pzf_op->data_fw_cfg_1, + sizeof(pzf_op->data_fw_cfg_1)); + himax_parse_assign_cmd(zf_data_fw_cfg_2, + pzf_op->data_fw_cfg_2, + sizeof(pzf_op->data_fw_cfg_2)); + himax_parse_assign_cmd(zf_data_fw_cfg_3, + pzf_op->data_fw_cfg_3, + sizeof(pzf_op->data_fw_cfg_3)); + himax_parse_assign_cmd(zf_data_adc_cfg_1, + pzf_op->data_adc_cfg_1, + sizeof(pzf_op->data_adc_cfg_1)); + himax_parse_assign_cmd(zf_data_adc_cfg_2, + pzf_op->data_adc_cfg_2, + sizeof(pzf_op->data_adc_cfg_2)); + himax_parse_assign_cmd(zf_data_adc_cfg_3, + pzf_op->data_adc_cfg_3, + sizeof(pzf_op->data_adc_cfg_3)); + himax_parse_assign_cmd(zf_data_map_table, + pzf_op->data_map_table, + sizeof(pzf_op->data_map_table)); +/* himax_parse_assign_cmd(zf_data_mode_switch, + * pzf_op->data_mode_switch, + * sizeof(pzf_op->data_mode_switch)); + */ + himax_parse_assign_cmd(zf_addr_sts_chk, + pzf_op->addr_sts_chk, + sizeof(pzf_op->addr_sts_chk)); + himax_parse_assign_cmd(zf_data_activ_sts, + pzf_op->data_activ_sts, + sizeof(pzf_op->data_activ_sts)); + himax_parse_assign_cmd(zf_addr_activ_relod, + pzf_op->addr_activ_relod, + sizeof(pzf_op->addr_activ_relod)); + himax_parse_assign_cmd(zf_data_activ_in, + pzf_op->data_activ_in, + sizeof(pzf_op->data_activ_in)); +#endif +} +EXPORT_SYMBOL(himax_mcu_in_cmd_init); + +/* init end*/ +/* CORE_INIT */ diff --git a/drivers/input/touchscreen/hxchipset/himax_inspection.c b/drivers/input/touchscreen/hxchipset/himax_inspection.c new file mode 100644 index 0000000000000000000000000000000000000000..ca5e8dad0f92b0c28bbe2ff41276283e696ca047 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_inspection.c @@ -0,0 +1,2429 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for inspection functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +#include "himax_inspection.h" + +static int g_gap_vertical_partial = 3; +static int *g_gap_vertical_part; +static int g_gap_horizontal_partial = 3; +static int *g_gap_horizontal_part; + +static int g_dc_max; + +static int g_1kind_raw_size; +uint32_t g_rslt_data_len; +int **g_inspection_criteria; +int *g_inspt_crtra_flag; +int *g_test_item_flag; +int do_lpwg_test; +int HX_CRITERIA_ITEM; +int HX_CRITERIA_SIZE; +char *g_rslt_data; +bool file_w_flag; +static char g_file_path[256]; +static char g_rslt_log[256]; +static char g_start_log[512]; +#define FAIL_IN_INDEX "%s: %s FAIL in index %d\n" +#define FAIL_IN_INDEX_CRTRA \ + "%s: %s FAIL in index %d,max=%d, min=%d, RAW=%d\n" +char *g_hx_head_str[] = { + "TP_Info", + "Project_Info", + "TestItem", + "TestCriteria", + NULL +}; + +/*Need to map THP_INSPECTION_ENUM*/ +char *g_himax_inspection_mode[] = { + "HIMAX_OPEN", + "HIMAX_MICRO_OPEN", + "HIMAX_SHORT", + "HIMAX_SC", + "HIMAX_WEIGHT_NOISE", + "HIMAX_ABS_NOISE", + "HIMAX_RAWDATA", + "HIMAX_BPN_RAWDATA", + "HIMAX_SORTING", + "HIMAX_GAPTEST_RAW", + /*"HIMAX_GAPTEST_RAW_X",*/ + /*"HIMAX_GAPTEST_RAW_Y",*/ + + "HIMAX_ACT_IDLE_NOISE", + "HIMAX_ACT_IDLE_RAWDATA", + "HIMAX_ACT_IDLE_BPN_RAWDATA", + + "HIMAX_LPWUG_WEIGHT_NOISE", + "HIMAX_LPWUG_ABS_NOISE", + "HIMAX_LPWUG_RAWDATA", + "HIMAX_LPWUG_BPN_RAWDATA", + + "HIMAX_LPWUG_IDLE_NOISE", + "HIMAX_LPWUG_IDLE_RAWDATA", + "HIMAX_LPWUG_IDLE_BPN_RAWDATA", + + "HIMAX_BACK_NORMAL", + NULL +}; + +/* for criteria */ +char *g_hx_inspt_crtra_name[] = { + "CRITERIA_RAW_MIN", + "CRITERIA_RAW_MAX", + "CRITERIA_RAW_BPN_MIN", + "CRITERIA_RAW_BPN_MAX", + "CRITERIA_SC_MIN", + "CRITERIA_SC_MAX", + "CRITERIA_SC_GOLDEN", + "CRITERIA_SHORT_MIN", + "CRITERIA_SHORT_MAX", + "CRITERIA_OPEN_MIN", + "CRITERIA_OPEN_MAX", + "CRITERIA_MICRO_OPEN_MIN", + "CRITERIA_MICRO_OPEN_MAX", + "CRITERIA_NOISE_WT_MIN", + "CRITERIA_NOISE_WT_MAX", + "CRITERIA_NOISE_ABS_MIN", + "CRITERIA_NOISE_ABS_MAX", + "CRITERIA_SORT_MIN", + "CRITERIA_SORT_MAX", + + "CRITERIA_GAP_RAW_HOR_MIN", + "CRITERIA_GAP_RAW_HOR_MAX", + "CRITERIA_GAP_RAW_VER_MIN", + "CRITERIA_GAP_RAW_VER_MAX", + + "ACT_IDLE_NOISE_MIN", + "ACT_IDLE_NOISE_MAX", + "ACT_IDLE_RAWDATA_MIN", + "ACT_IDLE_RAWDATA_MAX", + "ACT_IDLE_RAW_BPN_MIN", + "ACT_IDLE_RAW_BPN_MAX", + + "LPWUG_NOISE_WT_MIN", + "LPWUG_NOISE_WT_MAX", + "LPWUG_NOISE_ABS_MIN", + "LPWUG_NOISE_ABS_MAX", + "LPWUG_RAWDATA_MIN", + "LPWUG_RAWDATA_MAX", + "LPWUG_RAW_BPN_MIN", + "LPWUG_RAW_BPN_MAX", + + "LPWUG_IDLE_NOISE_MIN", + "LPWUG_IDLE_NOISE_MAX", + "LPWUG_IDLE_RAWDATA_MIN", + "LPWUG_IDLE_RAWDATA_MAX", + "LPWUG_IDLE_RAW_BPN_MIN", + "LPWUG_IDLE_RAW_BPN_MAX", + NULL +}; + + +void (*fp_himax_self_test_init)(void) = himax_inspection_init; + + +static void himax_press_powerkey(void) +{ + I(" %s POWER KEY event %x press\n", __func__, KEY_POWER); + input_report_key(private_ts->input_dev, KEY_POWER, 1); + input_sync(private_ts->input_dev); + + msleep(100); + + I(" %s POWER KEY event %x release\n", __func__, KEY_POWER); + input_report_key(private_ts->input_dev, KEY_POWER, 0); + input_sync(private_ts->input_dev); +} + + +static uint16_t NOISEMAX; +static uint16_t g_recal_thx; + +static int arraydata_max1, arraydata_max2, arraydata_max3; +static int arraydata_min1, arraydata_min2, arraydata_min3; + +void himax_get_arraydata_edge(int *RAW) +{ + int temp, i, j; + int len = ic_data->HX_RX_NUM * ic_data->HX_TX_NUM; + int *ArrayData; + + ArrayData = kcalloc(len, sizeof(int), GFP_KERNEL); + if (ArrayData == NULL) { + E("%s: allocate ArrayData failed\n", __func__); + return; + } + + for (i = 0; i < len; i++) + ArrayData[i] = RAW[i]; + for (j = len-1; j > 0; j--) { /*min to max*/ + for (i = 0; i < j; i++) { + if (ArrayData[i] > ArrayData[i+1]) { + temp = ArrayData[i]; + ArrayData[i] = ArrayData[i+1]; + ArrayData[i+1] = temp; + } + } + } + + arraydata_min1 = ArrayData[0]; + arraydata_min2 = ArrayData[1]; + arraydata_min3 = ArrayData[2]; + arraydata_max1 = ArrayData[len-3]; + arraydata_max2 = ArrayData[len-2]; + arraydata_max3 = ArrayData[len-1]; + +} + +static int hx_test_data_get(int RAW[], char *start_log, char *result, + int now_item) +{ + uint32_t i; + + ssize_t len = 0; + char *testdata = NULL; + uint32_t SZ_SIZE = g_1kind_raw_size; + + I("%s: Entering, Now type=%s!\n", __func__, + g_himax_inspection_mode[now_item]); + + testdata = kzalloc(sizeof(char) * SZ_SIZE, GFP_KERNEL); + if (testdata == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return MEM_ALLOC_FAIL; + } + + len += snprintf((testdata + len), SZ_SIZE - len, "%s", start_log); + for (i = 0; i < ic_data->HX_TX_NUM*ic_data->HX_RX_NUM; i++) { + if (i > 1 && ((i + 1) % ic_data->HX_RX_NUM) == 0) + len += snprintf((testdata + len), SZ_SIZE - len, + "%5d,\n", RAW[i]); + else + len += snprintf((testdata + len), SZ_SIZE - len, + "%5d,", RAW[i]); + } + len += snprintf((testdata + len), SZ_SIZE - len, "\n%s", result); + + memcpy(&g_rslt_data[0], testdata, len); + g_rslt_data_len = len; + I("%s: g_rslt_data_len=%d!\n", __func__, g_rslt_data_len); + + /* dbg */ + /* for(i = 0; i < SZ_SIZE; i++) + * { + * I("0x%04X, ", g_rslt_data[i + (now_item * SZ_SIZE)]); + * if(i > 0 && (i % 16 == 15)) + * PI("\n"); + * } + */ + + kfree(testdata); + I("%s: End!\n", __func__); + return NO_ERR; +} + +static int himax_switch_mode_inspection(int mode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4] = {0}; + + I("%s: Entering\n", __func__); + + /*Stop Handshaking*/ + himax_parse_assign_cmd(sram_adr_rawdata_addr, tmp_addr, + sizeof(tmp_addr)); + g_core_fp.fp_register_write(tmp_addr, 4, tmp_data, 0); + + /*Swtich Mode*/ + switch (mode) { + case HX_SORTING: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_SORTING_START; + tmp_data[0] = PWD_SORTING_START; + break; + case HX_OPEN: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_OPEN_START; + tmp_data[0] = PWD_OPEN_START; + break; + case HX_MICRO_OPEN: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_OPEN_START; + tmp_data[0] = PWD_OPEN_START; + break; + case HX_SHORT: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_SHORT_START; + tmp_data[0] = PWD_SHORT_START; + break; + + case HX_GAPTEST_RAW: + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_RAWDATA_START; + tmp_data[0] = PWD_RAWDATA_START; + break; + + case HX_WT_NOISE: + case HX_ABS_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_NOISE_START; + tmp_data[0] = PWD_NOISE_START; + break; + + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_ACT_IDLE_START; + tmp_data[0] = PWD_ACT_IDLE_START; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_LP_START; + tmp_data[0] = PWD_LP_START; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = PWD_LP_IDLE_START; + tmp_data[0] = PWD_LP_IDLE_START; + break; + + default: + I("%s,Nothing to be done!\n", __func__); + break; + } + + if (g_core_fp.fp_assign_sorting_mode != NULL) + g_core_fp.fp_assign_sorting_mode(tmp_data); + I("%s: End of setting!\n", __func__); + + return 0; + +} + +static uint32_t himax_get_rawdata(int RAW[], uint32_t len, uint8_t checktype) +{ + uint8_t *tmp_rawdata; + bool get_raw_rlst; + uint8_t retry = 0; + uint32_t i = 0; + uint32_t j = 0; + uint32_t index = 0; + int Min_DATA = 99999; + int Max_DATA = -99999; + + /* We use two bytes to combine a value of rawdata.*/ + tmp_rawdata = kzalloc(sizeof(uint8_t) * (len * 2), GFP_KERNEL); + if (tmp_rawdata == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return HX_INSP_MEMALLCTFAIL; + } + + while (retry < 200) { + get_raw_rlst = g_core_fp.fp_get_DSRAM_data(tmp_rawdata, false); + if (get_raw_rlst) + break; + retry++; + } + + if (retry >= 200) + goto DIRECT_END; + + /* Copy Data*/ + for (i = 0; i < ic_data->HX_TX_NUM*ic_data->HX_RX_NUM; i++) { + if (checktype == HX_WT_NOISE || + checktype == HX_ABS_NOISE || + checktype == HX_ACT_IDLE_NOISE || + checktype == HX_LP_WT_NOISE || + checktype == HX_LP_ABS_NOISE || + checktype == HX_LP_IDLE_NOISE) + RAW[i] = ((int8_t)tmp_rawdata[(i * 2) + 1] * 256) + + tmp_rawdata[(i * 2)]; + else + RAW[i] = tmp_rawdata[(i * 2) + 1] * 256 + + tmp_rawdata[(i * 2)]; + } + for (j = 0; j < ic_data->HX_RX_NUM; j++) { + if (j == 0) + PI(" RX%2d", j + 1); + else + PI(" RX%2d", j + 1); + } + PI("\n"); + + Min_DATA = Max_DATA = RAW[0]; + for (i = 0; i < ic_data->HX_TX_NUM; i++) { + if (private_ts->debug_log_level & BIT(4)) + PI("TX%2d", i + 1); + for (j = 0; j < ic_data->HX_RX_NUM; j++) { + if (private_ts->debug_log_level & BIT(4)) + PI("%5d ", RAW[index]); + if (RAW[index] > Max_DATA) + Max_DATA = RAW[index]; + + if (RAW[index] < Min_DATA) + Min_DATA = RAW[index]; + + index++; + } + if (private_ts->debug_log_level & BIT(4)) + PI("\n"); + } + I("Max = %5d, Min = %5d\n", Max_DATA, Min_DATA); +DIRECT_END: + kfree(tmp_rawdata); + + if (get_raw_rlst) + return HX_INSP_OK; + else + return HX_INSP_EGETRAW; + +} + +static void himax_switch_data_type(uint8_t checktype) +{ + uint8_t datatype = 0x00; + + if (private_ts->debug_log_level & BIT(4)) { + I("%s,Expected type[%d]=%s" + , __func__ + , checktype, g_himax_inspection_mode[checktype]); + } + switch (checktype) { + case HX_SORTING: + datatype = DATA_SORTING; + break; + case HX_OPEN: + datatype = DATA_OPEN; + break; + case HX_MICRO_OPEN: + datatype = DATA_MICRO_OPEN; + break; + case HX_SHORT: + datatype = DATA_SHORT; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_GAPTEST_RAW: + datatype = DATA_RAWDATA; + break; + + case HX_WT_NOISE: + case HX_ABS_NOISE: + datatype = DATA_NOISE; + break; + case HX_BACK_NORMAL: + datatype = DATA_BACK_NORMAL; + break; + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + datatype = DATA_ACT_IDLE_RAWDATA; + break; + case HX_ACT_IDLE_NOISE: + datatype = DATA_ACT_IDLE_NOISE; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + datatype = DATA_LP_RAWDATA; + break; + case HX_LP_WT_NOISE: + case HX_LP_ABS_NOISE: + datatype = DATA_LP_NOISE; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + datatype = DATA_LP_IDLE_RAWDATA; + break; + case HX_LP_IDLE_NOISE: + datatype = DATA_LP_IDLE_NOISE; + break; + + default: + E("Wrong type=%d\n", checktype); + break; + } + g_core_fp.fp_diag_register_set(datatype, 0x00, false); +} + +static void himax_bank_search_set(uint16_t Nframe, uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + /*skip frame 0x100070F4*/ + himax_parse_assign_cmd(addr_skip_frame, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + + switch (checktype) { + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + tmp_data[0] = BS_ACT_IDLE; + break; + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + tmp_data[0] = BS_LPWUG; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + tmp_data[0] = BS_LP_dile; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + tmp_data[0] = BS_RAWDATA; + break; + case HX_WT_NOISE: + case HX_ABS_NOISE: + tmp_data[0] = BS_NOISE; + break; + default: + tmp_data[0] = BS_OPENSHORT; + break; + } + if (private_ts->debug_log_level & BIT(4)) { + I("%s,Now BankSearch Value=%d\n", + __func__, tmp_data[0]); + } + g_core_fp.fp_register_write(tmp_addr, 4, tmp_data, 0); +} + +static void himax_neg_noise_sup(uint8_t *data) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + /*0x10007FD8 Check support negative value or not */ + himax_parse_assign_cmd(addr_neg_noise_sup, tmp_addr, + sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + + if ((tmp_data[3] & 0x04) == 0x04) { + himax_parse_assign_cmd(data_neg_noise, tmp_data, + sizeof(tmp_data)); + data[2] = tmp_data[2]; data[3] = tmp_data[3]; + } else + I("%s Not support negative noise\n", __func__); +} + +static void himax_set_N_frame(uint16_t Nframe, uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_bank_search_set(Nframe, checktype); + + /*IIR MAX - 0x10007294*/ + himax_parse_assign_cmd(fw_addr_set_frame_addr, + tmp_addr, sizeof(tmp_addr)); + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)((Nframe & 0xFF00) >> 8); + tmp_data[0] = (uint8_t)(Nframe & 0x00FF); + g_core_fp.fp_register_write(tmp_addr, 4, tmp_data, 0); + + if (checktype == HX_WT_NOISE || + checktype == HX_ABS_NOISE || + checktype == HX_LP_WT_NOISE || + checktype == HX_LP_ABS_NOISE) + himax_neg_noise_sup(tmp_data); + if (private_ts->debug_log_level & BIT(4)) { + I("%s,Now N frame Value=0x%02X%02X\n", + __func__, tmp_data[1], tmp_data[0]); + } + g_core_fp.fp_register_write(tmp_addr, 4, tmp_data, 0); +} + +static void himax_get_noise_base(uint8_t checktype)/*Normal Threshold*/ +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t tmp_addr2[4]; + uint8_t tmp_data2[4]; + + switch (checktype) { + case HX_WT_NOISE: + himax_parse_assign_cmd(addr_normal_noise_thx, + tmp_addr, sizeof(tmp_addr)); + break; + case HX_LP_WT_NOISE: + himax_parse_assign_cmd(addr_lpwug_noise_thx, + tmp_addr, sizeof(tmp_addr)); + break; + default: + I("%s Not support type\n", __func__); + } + himax_parse_assign_cmd(addr_noise_scale, + tmp_addr2, sizeof(tmp_addr2)); + g_core_fp.fp_register_read(tmp_addr2, 4, tmp_data2, false); + tmp_data2[1] = tmp_data2[1]>>4; + if (tmp_data2[1] == 0) + tmp_data2[1] = 1; + + /*normal : 0x1000708F, LPWUG:0x10007093*/ + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + NOISEMAX = tmp_data[3] * tmp_data2[1]; + + himax_parse_assign_cmd(addr_recal_thx, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + g_recal_thx = tmp_data[2] * tmp_data2[1];/*0x10007092*/ + I("%s: NOISEMAX = %d, g_recal_thx = %d\n", __func__, + NOISEMAX, g_recal_thx); +} + +static uint16_t himax_get_palm_num(void)/*Palm Number*/ +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint16_t palm_num; + + himax_parse_assign_cmd(addr_palm_num, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + palm_num = tmp_data[3];/*0x100070AB*/ + I("%s: palm_num = %d ", __func__, palm_num); + + return palm_num; +} + +static int himax_get_noise_weight_test(uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint16_t weight = 0; + uint16_t value = 0; + + himax_parse_assign_cmd(addr_weight_sup, + tmp_addr, sizeof(tmp_addr)); + + /*0x100072C8 weighting value*/ + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + if (tmp_data[3] != tmp_addr[1] || tmp_data[2] != tmp_addr[0]) + return FW_NOT_READY; + + value = (tmp_data[1] << 8) | tmp_data[0]; + I("%s: value = %d, %d, %d ", __func__, value, tmp_data[2], tmp_data[3]); + + switch (checktype) { + case HX_WT_NOISE: + himax_parse_assign_cmd(addr_normal_weight_a, + tmp_addr, sizeof(tmp_addr)); + break; + case HX_LP_WT_NOISE: + himax_parse_assign_cmd(addr_lpwug_weight_a, + tmp_addr, sizeof(tmp_addr)); + break; + default: + I("%s Not support type\n", __func__); + } + + /*Normal:0x1000709C, LPWUG:0x100070A0 weighting threshold*/ + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + weight = tmp_data[0]; + + himax_parse_assign_cmd(addr_weight_b, tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, tmp_data, false); + tmp_data[1] = tmp_data[1]&0x0F; + if (tmp_data[1] == 0) + tmp_data[1] = 1; + weight = tmp_data[1] * weight;/*0x10007095 weighting threshold*/ + I("%s: weight = %d ", __func__, weight); + + if (value > weight) + return ERR_TEST_FAIL; + else + return 0; +} + +static uint32_t himax_check_mode(uint8_t checktype) +{ + uint8_t tmp_data[4] = {0}; + uint8_t wait_pwd[2] = {0}; + + switch (checktype) { + case HX_SORTING: + wait_pwd[0] = PWD_SORTING_END; + wait_pwd[1] = PWD_SORTING_END; + break; + case HX_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_MICRO_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_SHORT: + wait_pwd[0] = PWD_SHORT_END; + wait_pwd[1] = PWD_SHORT_END; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_GAPTEST_RAW: + wait_pwd[0] = PWD_RAWDATA_END; + wait_pwd[1] = PWD_RAWDATA_END; + break; + + case HX_WT_NOISE: + case HX_ABS_NOISE: + wait_pwd[0] = PWD_NOISE_END; + wait_pwd[1] = PWD_NOISE_END; + break; + + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + wait_pwd[0] = PWD_ACT_IDLE_END; + wait_pwd[1] = PWD_ACT_IDLE_END; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + wait_pwd[0] = PWD_LP_END; + wait_pwd[1] = PWD_LP_END; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + wait_pwd[0] = PWD_LP_IDLE_END; + wait_pwd[1] = PWD_LP_IDLE_END; + break; + + default: + E("Wrong type=%d\n", checktype); + break; + } + + if (g_core_fp.fp_check_sorting_mode != NULL) + g_core_fp.fp_check_sorting_mode(tmp_data); + + if ((wait_pwd[0] == tmp_data[0]) && (wait_pwd[1] == tmp_data[1])) { + I("%s,It had been changed to [%d]=%s\n", + __func__, + checktype, g_himax_inspection_mode[checktype]); + return 0; + } else { + return 1; + } +} + +#define TEMP_LOG \ +"%s:%s,tmp_data[0]=%x,tmp_data[1]=%x,tmp_data[2]=%x,tmp_data[3]=%x\n" + +static uint32_t himax_wait_sorting_mode(uint8_t checktype) +{ + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + uint8_t wait_pwd[2] = {0}; + int count = 0; + + if (private_ts->debug_log_level & BIT(4)) + I("%s:start!\n", __func__); + + switch (checktype) { + case HX_SORTING: + wait_pwd[0] = PWD_SORTING_END; + wait_pwd[1] = PWD_SORTING_END; + break; + case HX_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_MICRO_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HX_SHORT: + wait_pwd[0] = PWD_SHORT_END; + wait_pwd[1] = PWD_SHORT_END; + break; + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_GAPTEST_RAW: + wait_pwd[0] = PWD_RAWDATA_END; + wait_pwd[1] = PWD_RAWDATA_END; + break; + case HX_WT_NOISE: + case HX_ABS_NOISE: + wait_pwd[0] = PWD_NOISE_END; + wait_pwd[1] = PWD_NOISE_END; + break; + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + wait_pwd[0] = PWD_ACT_IDLE_END; + wait_pwd[1] = PWD_ACT_IDLE_END; + break; + + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + case HX_LP_WT_NOISE: + wait_pwd[0] = PWD_LP_END; + wait_pwd[1] = PWD_LP_END; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + wait_pwd[0] = PWD_LP_IDLE_END; + wait_pwd[1] = PWD_LP_IDLE_END; + break; + + default: + I("No Change Mode and now type=%d\n", checktype); + break; + } + I("%s:NowType[%d] = %s, Expected=0x%02X%02X\n", + __func__, checktype, g_himax_inspection_mode[checktype], + wait_pwd[1], wait_pwd[0]); + do { + if (private_ts->debug_log_level & BIT(4)) + I("%s:start check_sorting_mode!\n", __func__); + if (g_core_fp.fp_check_sorting_mode != NULL) + g_core_fp.fp_check_sorting_mode(tmp_data); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end check_sorting_mode!\n", __func__); + if ((wait_pwd[0] == tmp_data[0]) && + (wait_pwd[1] == tmp_data[1])) + return HX_INSP_OK; + if (private_ts->debug_log_level & BIT(4)) { + himax_parse_assign_cmd(fw_addr_chk_fw_status, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, + tmp_data, false); + I(TEMP_LOG, __func__, "0x900000A8", + tmp_data[0], tmp_data[1], + tmp_data[2], tmp_data[3]); + + himax_parse_assign_cmd(fw_addr_flag_reset_event, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, + tmp_data, false); + I(TEMP_LOG, __func__, "0x900000E4", + tmp_data[0], tmp_data[1], + tmp_data[2], tmp_data[3]); + + himax_parse_assign_cmd(fw_addr_fw_dbg_msg_addr, + tmp_addr, sizeof(tmp_addr)); + g_core_fp.fp_register_read(tmp_addr, 4, + tmp_data, false); + I(TEMP_LOG, __func__, "0x10007F40", + tmp_data[0], tmp_data[1], + tmp_data[2], tmp_data[3]); + + I("Now retry %d times!\n", count); + } + count++; + msleep(50); + } while (count < 50); + + if (private_ts->debug_log_level & BIT(4)) + I("%s:end\n", __func__); + return HX_INSP_ESWITCHMODE; +} + +static int hx_turn_on_mp_func(int on) +{ + int rslt = 0; + int retry = 3; + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + uint8_t tmp_read[4] = {0}; + /* char *tmp_chipname = private_ts->chip_name; */ + + himax_parse_assign_cmd(addr_ctrl_mpap_ovl, tmp_addr, + sizeof(tmp_addr)); + if (on) { + I("%s : Turn on!\n", __func__); + if (strcmp(HX_83102D_SERIES_PWON, private_ts->chip_name) == 0) { + I("%s: need to enter Mp mode!\n", __func__); + himax_parse_assign_cmd(PWD_TURN_ON_MPAP_OVL, + tmp_data, sizeof(tmp_data)); + do { + g_core_fp.fp_register_write(tmp_addr, 4, + tmp_data, 0); + usleep_range(10000, 10001); + g_core_fp.fp_register_read(tmp_addr, 4, + tmp_read, false); + + I("%s:read2=0x%02X,read1=0x%02X,read0=0x%02X\n", + __func__, + tmp_read[2], + tmp_read[1], + tmp_read[0]); + + retry--; + } while (((retry > 0) + && (tmp_read[2] != tmp_data[2] + && tmp_read[1] != tmp_data[1] + && tmp_read[0] != tmp_data[0]))); + } else { + I("%s:Nothing to be done!\n", __func__); + } + } else { + I("%s : Turn off!\n", __func__); + if (strcmp(HX_83102D_SERIES_PWON, private_ts->chip_name) == 0) { + I("%s: need to enter Mp mode!\n", __func__); + + himax_parse_assign_cmd(ic_cmd_rst, tmp_data, + sizeof(tmp_data)); + do { + g_core_fp.fp_register_write(tmp_addr, 4, + tmp_data, 0); + usleep_range(10000, 10001); + g_core_fp.fp_register_read(tmp_addr, 4, + tmp_read, false); + + I("%s:read2=0x%02X,read1=0x%02X,read0=0x%02X\n", + __func__, + tmp_read[2], + tmp_read[1], + tmp_read[0]); + + retry--; + } while ((retry > 0) + && (tmp_read[2] != tmp_data[2] + && tmp_read[1] != tmp_data[1] + && tmp_read[0] != tmp_data[0])); + } else { + I("%s Nothing to be done!\n", __func__); + } + } + return rslt; +} + +/* HX_GAP START gap test function */ +/* extern int himax_write_to_ic_flash_flow(uint32_t start_addr,*/ +/* uint32_t *write_data, uint32_t write_len);*/ + +static int himax_gap_test_vertical_setting(void) +{ + g_gap_vertical_part[0] = 0; + g_gap_vertical_part[1] = 4; + g_gap_vertical_part[2] = 8; + + return NO_ERR; +} + +static void himax_cal_gap_data_vertical(int start, int end_idx, int direct, + uint32_t *org_raw, uint32_t *result_raw) +{ + int i = 0; + int rx_num = ic_data->HX_RX_NUM; + + I("%s:start=%d,end_idx=%d\n", __func__, start, end_idx); + + for (i = start; i < (start + rx_num*end_idx); i++) { + if (direct == 0) { /* up - down */ + if (i < start+rx_num) + result_raw[i] = 0; + else + result_raw[i] = org_raw[i-rx_num] - org_raw[i]; + + } else { /* down - up */ + if (i > (start + rx_num*(end_idx-1)-1)) + result_raw[i] = 0; + else + result_raw[i] = org_raw[i+rx_num] - org_raw[i]; + + } + } +} + +static int himax_gap_test_vertical_raw(int test_type, int *org_raw) +{ + int i_partial = 0; + int tmp_start = 0; + int tmp_end_idx = 0; + uint32_t *result_raw = NULL; + int i = 0; + int ret_val = NO_ERR; + + int tx_num = ic_data->HX_TX_NUM; + int rx_num = ic_data->HX_RX_NUM; + + g_gap_vertical_part = kcalloc(g_gap_vertical_partial, + sizeof(int), GFP_KERNEL); + if (g_gap_vertical_part == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return MEM_ALLOC_FAIL; + } + + result_raw = kcalloc(tx_num*rx_num, sizeof(uint32_t), GFP_KERNEL); + if (result_raw == NULL) { + E("%s: Memory allocation falied!\n", __func__); + ret_val = MEM_ALLOC_FAIL; + goto alloc_result_raw_failed; + } + + himax_gap_test_vertical_setting(); + + I("Print vertical ORG RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", org_raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i_partial = 0; i_partial < g_gap_vertical_partial; i_partial++) { + + tmp_start = g_gap_vertical_part[i_partial]*rx_num; + if (i_partial+1 == g_gap_vertical_partial) + tmp_end_idx = tx_num - g_gap_vertical_part[i_partial]; + else + tmp_end_idx = g_gap_vertical_part[i_partial+1] - + g_gap_vertical_part[i_partial]; + + if (i_partial % 2 == 0) + himax_cal_gap_data_vertical(tmp_start, tmp_end_idx, 0, + org_raw, result_raw); + else + himax_cal_gap_data_vertical(tmp_start, tmp_end_idx, 1, + org_raw, result_raw); + + } + + I("Print Vertical New RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", result_raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i = 0; i < tx_num*rx_num; i++) { + if (result_raw[i] < g_inspection_criteria[IDX_GAP_VER_RAWMIN][i] + && + result_raw[i] > g_inspection_criteria[IDX_GAP_VER_RAWMAX][i]) { + ret_val = NO_ERR - i; + break; + } + } + + /* himax_write_to_ic_flash_flow(0x1A000,result_raw,tx_num*rx_num); */ + kfree(result_raw); +alloc_result_raw_failed: + kfree(g_gap_vertical_part); + g_gap_vertical_part = NULL; + + return ret_val; +} + +static int himax_gap_test_horizontal_setting(void) +{ + g_gap_horizontal_part[0] = 0; + g_gap_horizontal_part[1] = 8; + g_gap_horizontal_part[2] = 24; + + return NO_ERR; +} + +static void himax_cal_gap_data_horizontal(int start, int end_idx, int direct, + uint32_t *org_raw, uint32_t *result_raw) +{ + int i = 0; + int j = 0; + int rx_num = ic_data->HX_RX_NUM; + int tx_num = ic_data->HX_TX_NUM; + + I("start=%d,end_idx=%d\n", start, end_idx); + + for (j = 0; j < tx_num; j++) { + for (i = (start + (j*rx_num)); + i < (start + (j*rx_num) + end_idx); i++) { + /* left - right */ + if (direct == 0) { + if (i == (start + (j*rx_num))) + result_raw[i] = 0; + else + result_raw[i] = + org_raw[i-1] - org_raw[i]; + + } else { /* right - left */ + if (i == ((start + (j*rx_num) + end_idx) - 1)) + result_raw[i] = 0; + else + result_raw[i] = + org_raw[i + 1] - org_raw[i]; + } + } + } +} + +static int himax_gap_test_honrizontal_raw(int test_type, int *raw) +{ + int rx_num = ic_data->HX_RX_NUM; + int tx_num = ic_data->HX_TX_NUM; + int tmp_start = 0; + int tmp_end_idx = 0; + int i_partial = 0; + int *result_raw; + int i = 0; + int ret_val = NO_ERR; + + g_gap_horizontal_part = kcalloc(g_gap_horizontal_partial, + sizeof(int), GFP_KERNEL); + if (g_gap_horizontal_part == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return MEM_ALLOC_FAIL; + } + + result_raw = kcalloc(tx_num*rx_num, sizeof(int), GFP_KERNEL); + if (result_raw == NULL) { + E("%s: Memory allocation falied!\n", __func__); + ret_val = MEM_ALLOC_FAIL; + goto alloc_result_raw_failed; + } + + himax_gap_test_horizontal_setting(); + + I("Print Horizontal ORG RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i_partial = 0; + i_partial < g_gap_horizontal_partial; + i_partial++) { + tmp_start = g_gap_horizontal_part[i_partial]; + if (i_partial+1 == g_gap_horizontal_partial) + tmp_end_idx = rx_num - g_gap_horizontal_part[i_partial]; + else + tmp_end_idx = g_gap_horizontal_part[i_partial+1] - + g_gap_horizontal_part[i_partial]; + + if (i_partial % 2 == 0) + himax_cal_gap_data_horizontal(tmp_start, tmp_end_idx, + 0, raw, result_raw); + else + himax_cal_gap_data_horizontal(tmp_start, tmp_end_idx, + 1, raw, result_raw); + + } + I("Print Horizontal New RAW\n"); + for (i = 0; i < tx_num*rx_num; i++) { + I("%04d,", result_raw[i]); + if (i > 0 && i%rx_num == (rx_num-1)) + I("\n"); + } + + for (i = 0; i < tx_num*rx_num; i++) { + if (result_raw[i] < g_inspection_criteria[IDX_GAP_HOR_RAWMIN][i] + && + result_raw[i] > g_inspection_criteria[IDX_GAP_HOR_RAWMAX][i]) { + ret_val = NO_ERR - i; + break; + } + } + + /* himax_write_to_ic_flash_flow(0x1A800,result_raw,tx_num*rx_num); */ + kfree(result_raw); +alloc_result_raw_failed: + kfree(g_gap_horizontal_part); + g_gap_horizontal_part = NULL; + + return ret_val; +} + +static uint32_t himax_data_campare(uint8_t checktype, int *RAW, + int ret_val) +{ + int i = 0; + int idx_max = 0; + int idx_min = 0; + int block_num = ic_data->HX_TX_NUM*ic_data->HX_RX_NUM; + uint16_t palm_num = 0; + uint16_t noise_count = 0; + + switch (checktype) { + case HX_SORTING: + idx_min = IDX_SORTMIN; + break; + case HX_OPEN: + idx_max = IDX_OPENMAX; + idx_min = IDX_OPENMIN; + break; + + case HX_MICRO_OPEN: + idx_max = IDX_M_OPENMAX; + idx_min = IDX_M_OPENMIN; + break; + + case HX_SHORT: + idx_max = IDX_SHORTMAX; + idx_min = IDX_SHORTMIN; + break; + + case HX_RAWDATA: + idx_max = IDX_RAWMAX; + idx_min = IDX_RAWMIN; + break; + + case HX_BPN_RAWDATA: + idx_max = IDX_BPN_RAWMAX; + idx_min = IDX_BPN_RAWMIN; + break; + case HX_SC: + idx_max = IDX_SCMAX; + idx_min = IDX_SCMIN; + break; + case HX_WT_NOISE: + idx_max = IDX_WT_NOISEMAX; + idx_min = IDX_WT_NOISEMIN; + break; + case HX_ABS_NOISE: + idx_max = IDX_ABS_NOISEMAX; + idx_min = IDX_ABS_NOISEMIN; + break; + case HX_GAPTEST_RAW: + break; + + case HX_ACT_IDLE_RAWDATA: + idx_max = IDX_ACT_IDLE_RAWDATA_MAX; + idx_min = IDX_ACT_IDLE_RAWDATA_MIN; + break; + + case HX_ACT_IDLE_BPN_RAWDATA: + idx_max = IDX_ACT_IDLE_RAW_BPN_MAX; + idx_min = IDX_ACT_IDLE_RAW_BPN_MIN; + break; + + case HX_ACT_IDLE_NOISE: + idx_max = IDX_ACT_IDLE_NOISE_MAX; + idx_min = IDX_ACT_IDLE_NOISE_MIN; + break; + + case HX_LP_RAWDATA: + idx_max = IDX_LP_RAWDATA_MAX; + idx_min = IDX_LP_RAWDATA_MIN; + break; + + case HX_LP_BPN_RAWDATA: + idx_max = IDX_LP_RAW_BPN_MAX; + idx_min = IDX_LP_RAW_BPN_MIN; + break; + + case HX_LP_WT_NOISE: + idx_max = IDX_LP_WT_NOISEMAX; + idx_min = IDX_LP_WT_NOISEMIN; + break; + + case HX_LP_ABS_NOISE: + idx_max = IDX_LP_NOISE_ABS_MAX; + idx_min = IDX_LP_NOISE_ABS_MIN; + break; + + case HX_LP_IDLE_RAWDATA: + idx_max = IDX_LP_IDLE_RAWDATA_MAX; + idx_min = IDX_LP_IDLE_RAWDATA_MIN; + break; + + case HX_LP_IDLE_BPN_RAWDATA: + idx_max = IDX_LP_IDLE_RAW_BPN_MAX; + idx_min = IDX_LP_IDLE_RAW_BPN_MIN; + break; + + case HX_LP_IDLE_NOISE: + idx_max = IDX_LP_IDLE_NOISE_MAX; + idx_min = IDX_LP_IDLE_NOISE_MIN; + break; + + default: + E("Wrong type=%d\n", checktype); + break; + } + + /*data process*/ + switch (checktype) { + case HX_SORTING: + for (i = 0; i < block_num; i++) + g_inspection_criteria[idx_max][i] = 999999; + break; + case HX_BPN_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + for (i = 0; i < block_num; i++) + RAW[i] = (int)RAW[i] * 100 / g_dc_max; + break; + case HX_SC: + for (i = 0; i < block_num; i++) { + RAW[i] = ((int)RAW[i] + - g_inspection_criteria[IDX_SC_GOLDEN][i]) + * 100 / g_inspection_criteria[IDX_SC_GOLDEN][i]; + } + break; + } + + /*data campare*/ + switch (checktype) { + case HX_GAPTEST_RAW: + if ( + himax_gap_test_vertical_raw(HX_GAPTEST_RAW, RAW) != NO_ERR) { + E("%s: HX_GAPTEST_RAW FAIL\n", __func__); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + if (himax_gap_test_honrizontal_raw(HX_GAPTEST_RAW, RAW) + != NO_ERR) { + E("%s: HX_GAPTEST_RAW FAIL\n", __func__); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + break; + + case HX_WT_NOISE: + case HX_LP_WT_NOISE: + noise_count = 0; + himax_get_noise_base(checktype); + palm_num = himax_get_palm_num(); + for (i = 0; i < (ic_data->HX_TX_NUM * ic_data->HX_RX_NUM); + i++) { + if ((int)RAW[i] > NOISEMAX) + noise_count++; + } + I("noise_count=%d\n", noise_count); + if (noise_count > palm_num) { + E("%s: noise test FAIL\n", __func__); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + snprintf(g_start_log, 256 * sizeof(char), "\n Threshold = %d\n", + NOISEMAX); + /*Check weightingt*/ + if (himax_get_noise_weight_test(checktype) < 0) { + I("%s: %s FAIL %X\n", __func__, + g_himax_inspection_mode[checktype], ret_val); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + + /*Check negative side noise*/ + for (i = 0; i < block_num; i++) { + if ((int)RAW[i] + > (g_inspection_criteria[idx_max][i] + * NOISEMAX / 100) + || (int)RAW[i] + < (g_inspection_criteria[idx_min][i] + * g_recal_thx / 100)) { + E(FAIL_IN_INDEX, __func__, + g_himax_inspection_mode[checktype], i); + ret_val |= 1 << (checktype + ERR_SFT); + break; + } + } + break; + + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + case HX_LP_IDLE_NOISE: + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_BPN_RAWDATA: + case HX_ACT_IDLE_NOISE: + block_num = ic_data->ic_adc_num; + case HX_SORTING: + case HX_OPEN: + case HX_MICRO_OPEN: + case HX_SHORT: + case HX_RAWDATA: + case HX_BPN_RAWDATA: + case HX_SC: + case HX_ABS_NOISE: + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + case HX_LP_ABS_NOISE: + for (i = 0; i < block_num; i++) { + if ((int)RAW[i] > g_inspection_criteria[idx_max][i] + || (int)RAW[i] < g_inspection_criteria[idx_min][i]) { + if (private_ts->debug_log_level & BIT(4)) { + E(FAIL_IN_INDEX_CRTRA, __func__, + g_himax_inspection_mode[checktype], i + , g_inspection_criteria[idx_max][i] + , g_inspection_criteria[idx_min][i] + , RAW[i]); + ret_val |= 1 << (checktype + ERR_SFT); + } else { + E(FAIL_IN_INDEX, __func__, + g_himax_inspection_mode[checktype], i); + ret_val |= 1 << (checktype + ERR_SFT); + } + break; + } +#ifdef HX_INSPT_DBG + if ((private_ts->debug_log_level & BIT(4))) { + I("%s,type=%s, idx[%d]=%d\n", + __func__, + g_himax_inspection_mode[checktype], + i, RAW[i]); + I("%s, crteria,max=%d,min=%d\n", + __func__, + g_inspection_criteria[idx_max][i], + g_inspection_criteria[idx_min][i]); + } +#endif + } + break; + default: + E("Wrong type[%d] = %s\n", + checktype, g_himax_inspection_mode[checktype]); + break; + } + + I("%s: %s %s\n", __func__, g_himax_inspection_mode[checktype], + (ret_val == HX_INSP_OK)?"PASS":"FAIL"); + + return ret_val; +} + +static int himax_get_max_dc(void) +{ + uint8_t tmp_data[DATA_LEN_4]; + uint8_t tmp_addr[DATA_LEN_4]; + int dc_max = 0; + + himax_parse_assign_cmd(addr_max_dc, tmp_addr, sizeof(tmp_addr)); + + g_core_fp.fp_register_read(tmp_addr, DATA_LEN_4, tmp_data, 0); + I("%s: tmp_data[0-3] = %02x%02x%02x%02x\n", __func__, + tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + dc_max = tmp_data[3]<<24 | tmp_data[2]<<16 | + tmp_data[1]<<8 | tmp_data[0]; + I("%s: dc max = %d\n", __func__, dc_max); + return dc_max; +} + +/* HX_GAP END*/ +static uint32_t mpTestFunc(uint8_t checktype, uint32_t datalen) +{ + uint32_t len = 0; + uint32_t *RAW = NULL; + int n_frame = 0; + uint32_t ret_val = HX_INSP_OK; + + /*uint16_t* pInspectGridData = &gInspectGridData[0];*/ + /*uint16_t* pInspectNoiseData = &gInspectNoiseData[0];*/ + + I("Now Check type = %d\n", checktype); + + RAW = kcalloc(datalen, sizeof(uint32_t), GFP_KERNEL); + if (RAW == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return HX_INSP_MEMALLCTFAIL; + } + + if (himax_check_mode(checktype)) { + /*himax_check_mode(checktype);*/ + + I("Need Change Mode ,target=%s\n", + g_himax_inspection_mode[checktype]); + + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense off!\n", __func__); + g_core_fp.fp_sense_off(true); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense off!\n", __func__); +#if !defined(HX_ZERO_FLASH) + hx_turn_on_mp_func(1); + if (g_core_fp.fp_reload_disable != NULL) + g_core_fp.fp_reload_disable(1); +#endif + + himax_switch_mode_inspection(checktype); + + switch (checktype) { + case HX_WT_NOISE: + case HX_ABS_NOISE: + n_frame = NOISEFRAME; + break; + case HX_ACT_IDLE_RAWDATA: + case HX_ACT_IDLE_NOISE: + case HX_ACT_IDLE_BPN_RAWDATA: + n_frame = NORMAL_IDLE_RAWDATA_NOISEFRAME; + break; + case HX_LP_RAWDATA: + case HX_LP_BPN_RAWDATA: + n_frame = LP_RAWDATAFRAME; + break; + case HX_LP_WT_NOISE: + case HX_LP_ABS_NOISE: + n_frame = LP_NOISEFRAME; + break; + case HX_LP_IDLE_RAWDATA: + case HX_LP_IDLE_BPN_RAWDATA: + n_frame = LP_IDLE_RAWDATAFRAME; + break; + case HX_LP_IDLE_NOISE: + n_frame = LP_IDLE_NOISEFRAME; + break; + default: + n_frame = OTHERSFRAME; + } + himax_set_N_frame(n_frame, checktype); + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense on!\n", __func__); + g_core_fp.fp_sense_on(1); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense on!\n", __func__); + + } + + ret_val |= himax_wait_sorting_mode(checktype); + if (ret_val) { + E("%s: himax_wait_sorting_mode FAIL\n", __func__); + ret_val |= (1 << (checktype + ERR_SFT)); + goto fail_wait_sorting_mode; + } + himax_switch_data_type(checktype); + + ret_val |= himax_get_rawdata(RAW, datalen, checktype); + if (ret_val) { + E("%s: himax_get_rawdata FAIL\n", __func__); + ret_val |= (1 << (checktype + ERR_SFT)); + goto fail_get_rawdata; + } + + /*get Max DC from FW*/ + g_dc_max = himax_get_max_dc(); + + /* back to normal */ + himax_switch_data_type(HX_BACK_NORMAL); + + I("%s: Init OK, start to test!\n", __func__); + + len += snprintf(g_start_log+len, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], ": data as follow!\n"); + + ret_val |= himax_data_campare(checktype, RAW, ret_val); + + himax_get_arraydata_edge(RAW); + + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + "\n arraydata_min1 = %d,", arraydata_min1); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_min2 = %d,", arraydata_min2); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_min3 = %d,", arraydata_min3); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + "\n arraydata_max1 = %d,", arraydata_max1); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_max2 = %d,", arraydata_max2); + len += snprintf(g_start_log + len, 256 * sizeof(char) - len, + " arraydata_max3 = %d\n", arraydata_max3); + + if (!ret_val) {/*PASS*/ + snprintf(g_rslt_log, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], ":Test Pass!"); + I("pass write log\n"); + } else {/*FAIL*/ + snprintf(g_rslt_log, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], ":Test Fail!"); + I("fail write log\n"); + } + + hx_test_data_get(RAW, g_start_log, g_rslt_log, checktype); +fail_get_rawdata: +fail_wait_sorting_mode: + kfree(RAW); + return ret_val; +} + +/* claculate 10's power function */ +static int himax_power_cal(int pow, int number) +{ + int i = 0; + int result = 1; + + for (i = 0; i < pow; i++) + result *= 10; + result = result * number; + + return result; + +} + +/* String to int */ +static int hiamx_parse_str2int(char *str) +{ + int i = 0; + int temp_cal = 0; + int result = 0; + unsigned int str_len = strlen(str); + int negtive_flag = 0; + + for (i = 0; i < str_len; i++) { + if (str[i] != '-' && str[i] > '9' && str[i] < '0') { + E("%s: Parsing fail!\n", __func__); + result = -9487; + negtive_flag = 0; + break; + } + if (str[i] == '-') { + negtive_flag = 1; + continue; + } + temp_cal = str[i] - '0'; + result += himax_power_cal(str_len-i-1, temp_cal); + /* str's the lowest char is the number's the highest number + * So we should reverse this number before using the power + * function + * -1: starting number is from 0 ex:10^0 = 1,10^1=10 + */ + } + + if (negtive_flag == 1) + result = 0 - result; + + return result; +} + + + + +/* get idx of criteria whe parsing file */ +int hx_find_crtra_id(char *input) +{ + int i = 0; + int result = 0; + + for (i = 0 ; i < HX_CRITERIA_SIZE ; i++) { + if (strcmp(g_hx_inspt_crtra_name[i], input) == 0) { + result = i; + I("find the str=%s,idx=%d\n", + g_hx_inspt_crtra_name[i], i); + break; + } + } + if (i > (HX_CRITERIA_SIZE - 1)) { + E("%s: find Fail!\n", __func__); + return LENGTH_FAIL; + } + + return result; +} +#ifdef HX_INSPT_DBG +int hx_print_crtra_after_parsing(void) +{ + int i = 0, j = 0; + int all_mut_len = ic_data->HX_TX_NUM*ic_data->HX_RX_NUM; + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + I("Now is %s\n", g_hx_inspt_crtra_name[i]); + if (g_inspt_crtra_flag[i] == 1) { + for (j = 0; j < all_mut_len; j++) { + PI("%d, ", g_inspection_criteria[i][j]); + if (j % 16 == 15) + PI("\n"); + } + } else { + I("No this Item in this criteria file!\n"); + } + PI("\n"); + } + + return 0; +} +#endif + +static int hx_crtra_get(char *result, int himax_count_type, int comprae_data) +{ + int temp = 0; + + temp = hiamx_parse_str2int(result); + + if (temp != -9487) + g_inspection_criteria[himax_count_type][comprae_data] = temp; + else { + I("%s: Parsing Fail in %d, rslt = %d\n", + __func__, comprae_data, temp); + return HX_INSP_EFILE; + } + +#ifdef HX_INSPT_DBG + /* dbg:print all of criteria from parsing file */ + hx_print_crtra_after_parsing(); +#endif + + return HX_INSP_OK; +} + +static int himax_parse_criteria_str(char *str_data, int hx_str_len) +{ + int err = HX_INSP_OK; + char result[100] = {0}; + char str_rslt[100] = {0}; + int str_rslt_nm = 0; + int result_nm = 0; + char str_len = 0; + char *str_addr = NULL; + int str_flag = 1; + int i, j, k = 0; + int crtra_id = 0; + int mul_num = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM; + int flag = 1; + int temp; + + if (private_ts->debug_log_level & BIT(4)) + I("%s,Entering\n", __func__); + + for (str_rslt_nm = 0; str_rslt_nm < hx_str_len; str_rslt_nm++) + str_rslt[str_rslt_nm] = *(str_data + str_rslt_nm); + + crtra_id = hx_find_crtra_id(str_rslt); + if (crtra_id == -1) { + E("Please check criteria file again!\n"); + return HX_INSP_EFILE; + } + g_inspt_crtra_flag[crtra_id] = 1; + + str_data = str_data + hx_str_len + 1; + + for (i = 0; i < mul_num; i++) { + if (i <= mul_num - 2) { + while (flag) { + if (*(str_data + flag) == ',') { + str_addr = str_data + flag; + flag = 1; + break; + } + flag++; + } + if (str_addr == NULL) + continue; + str_flag = 1; + str_len = str_addr - str_data; + for (j = 1; j <= str_len; j++) { + if ((*(str_data+j) == '\r' + || *(str_data+j) == '\n')) { + memset(result, 0, 100); + for (k = 0; k < j ; k++) + result[k] = *(str_data + k); + str_flag = 0; + break; + } + } + if (str_flag) { + memset(result, 0, 100); + for (k = 0; k < str_len; k++) + result[k] = *(str_data + k); + } + err = hx_crtra_get(result, crtra_id, i); + if (err != HX_INSP_OK) { + E("%s:Get crrteria Fail!!\n", __func__); + return HX_INSP_EFILE; + } + str_data = str_addr + 1; + } else{ + temp = 1; + while (*(str_data + temp) <= '9' + && *(str_data + temp) >= '0') + temp++; + str_len = temp; + memset(result, 0, 100); + for (result_nm = 0; result_nm < str_len; result_nm++) + result[result_nm] = *(str_data + result_nm); + + err = hx_crtra_get(result, crtra_id, mul_num - 1); + if (err != HX_INSP_OK) { + E("%s:Get crrteria Fail!\n", __func__); + return HX_INSP_EFILE; + } + } + } + + if (private_ts->debug_log_level & BIT(4)) + I("%s,END\n", __func__); + return err; + /* parsing Criteria end */ +} + +static int himax_test_item_parse(char *str_data, int str_size) +{ + int size = str_size; + char *str_ptr = str_data; + char *end_ptr = NULL; + int i = 0; + int ret = HX_INSP_EFILE; + + I("%s,str_data: %p, str_size: %d\n", __func__, str_data, str_size); + + do { + str_ptr = strnstr(str_ptr, "HIMAX", size); + end_ptr = strnstr(str_ptr, "\x0d\x0a", size); + if (str_ptr != NULL && end_ptr != NULL) { + while (g_himax_inspection_mode[i]) { + if (strncmp(str_ptr, g_himax_inspection_mode[i], + end_ptr - str_ptr) == 0) { + I("%s,Find item : %s\n", __func__, + g_himax_inspection_mode[i]); + g_test_item_flag[i] = 1; + ret = HX_INSP_OK; + break; + } + i++; + } + size = str_size - (end_ptr - str_data); + str_ptr = end_ptr++; + i = 0; + } else { + I("%s,Can't find %s or %s\n", __func__, + "HIMAX", "\x0d\x0a"); + break; + } + } while (size > strlen("HIMAX")); + + return ret; +} + + +static int himax_parse_criteria(const struct firmware *file_entry) +{ + int ret = 0; + int i = 0; + int start_str_len = 0; + char *start_ptr = NULL; + + while (g_hx_inspt_crtra_name[i] != NULL) { + + start_ptr = strnstr(file_entry->data, + g_hx_inspt_crtra_name[i], file_entry->size); + + if (start_ptr != NULL) { + I("g_hx_inspt_crtra_name[%d] = %s\n", + i, g_hx_inspt_crtra_name[i]); + start_str_len = strlen(g_hx_inspt_crtra_name[i]); + + ret |= himax_parse_criteria_str(start_ptr, + start_str_len); + } + i++; + } + + return ret; +} + + +static int himax_parse_test_dri_file(const struct firmware *file_entry) +{ + int start_str_len = 0; + int str_size = 0; + char *start_ptr = NULL; + char *end_ptr = NULL; + int i = 0; + int j = 0; + char str[2][60]; /*[0]->Start string, [1]->End string*/ + char *str_tail[2] = {"_Begin]\x0d\x0a", "_End]\x0d\x0a"}; + int ret = HX_INSP_OK; + + while (g_hx_head_str[i]) { + /*compose header string of .dri file*/ + for (j = 0; j < 2; j++) { + strlcpy(str[j], "[", sizeof(str[j])); + strlcat(str[j], g_hx_head_str[i], sizeof(str[j])); + strlcat(str[j], str_tail[j], sizeof(str[j])); + /*I("%s string[%d] : %s\n", __func__, j, str[j]);*/ + } + + /*find each group of .dri file*/ + start_str_len = strlen(str[0]); + start_ptr = strnstr(file_entry->data, str[0], file_entry->size); + end_ptr = strnstr(file_entry->data, str[1], file_entry->size); + + if (start_ptr == NULL || end_ptr == NULL) { + E("%s,Can't find string %s\n", __func__, + g_hx_head_str[i]); + } else { + /*parse each sub group string*/ + /*if (strncmp(g_hx_head_str[i], "Project_Info",*/ + /*strlen(g_hx_head_str[i])) == 0) {*/ + /* get project informaion - Not Use*/ + /*}*/ + str_size = end_ptr - start_ptr - start_str_len; + /*I("%s,String Length = %d\n", __func__, str_size);*/ + + if (strncmp(g_hx_head_str[i], "TestItem", + strlen(g_hx_head_str[i])) == 0) { + /*get Test Item*/ + I("%s,Start to parse %s\n", __func__, + g_hx_head_str[i]); + ret |= himax_test_item_parse(start_ptr + + start_str_len, + str_size); + } + /*if (strncmp(g_hx_head_str[i], "TestCriteria_Weight",*/ + /*strlen(g_hx_head_str[i])) == 0) {*/ + /*get Test Criteria Weight - Not Use*/ + /*}*/ + if (strncmp(g_hx_head_str[i], "TestCriteria", + strlen(g_hx_head_str[i])) == 0) { + /*get Test Criteria*/ + I("%s,Start to parse %s\n", __func__, + g_hx_head_str[i]); + ret |= himax_parse_criteria(file_entry); + } + } + i++; + } + + return ret; +} + +static void himax_test_item_chk(int csv_test) +{ + int i = 0; + + if (csv_test) + for (i = 0; i < HX_CRITERIA_ITEM - 1; i++) + g_test_item_flag[i] = 1; + + g_test_item_flag[HX_OPEN] &= + (g_inspt_crtra_flag[IDX_OPENMIN] == 1 + && g_inspt_crtra_flag[IDX_OPENMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_MICRO_OPEN] &= + (g_inspt_crtra_flag[IDX_M_OPENMIN] == 1 + && g_inspt_crtra_flag[IDX_M_OPENMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_SHORT] &= + (g_inspt_crtra_flag[IDX_SHORTMIN] == 1 + && g_inspt_crtra_flag[IDX_SHORTMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_RAWDATA] &= + (g_inspt_crtra_flag[IDX_RAWMIN] == 1 + && g_inspt_crtra_flag[IDX_RAWMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_BPN_RAWMIN] == 1 + && g_inspt_crtra_flag[IDX_BPN_RAWMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_SC] &= + (g_inspt_crtra_flag[IDX_SCMIN] == 1 + && g_inspt_crtra_flag[IDX_SCMAX] == 1 + && g_inspt_crtra_flag[IDX_SC_GOLDEN] == 1) ? 1 : 0; + + g_test_item_flag[HX_WT_NOISE] &= + (g_inspt_crtra_flag[IDX_WT_NOISEMIN] == 1 + && g_inspt_crtra_flag[IDX_WT_NOISEMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_ABS_NOISE] &= + (g_inspt_crtra_flag[IDX_ABS_NOISEMIN] == 1 + && g_inspt_crtra_flag[IDX_ABS_NOISEMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_SORTING] &= + (g_inspt_crtra_flag[IDX_SORTMIN] == 1 + && g_inspt_crtra_flag[IDX_SORTMAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_GAPTEST_RAW] &= + (g_inspt_crtra_flag[IDX_GAP_HOR_RAWMAX] == 1 + && g_inspt_crtra_flag[IDX_GAP_HOR_RAWMIN] == 1 + && g_inspt_crtra_flag[IDX_GAP_VER_RAWMAX] == 1 + && g_inspt_crtra_flag[IDX_GAP_VER_RAWMIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_ACT_IDLE_RAWDATA] &= + (g_inspt_crtra_flag[IDX_ACT_IDLE_RAWDATA_MIN] == 1 + && g_inspt_crtra_flag[IDX_ACT_IDLE_RAWDATA_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_ACT_IDLE_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_ACT_IDLE_RAW_BPN_MIN] == 1 + && g_inspt_crtra_flag[IDX_ACT_IDLE_RAW_BPN_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_ACT_IDLE_NOISE] &= + (g_inspt_crtra_flag[IDX_ACT_IDLE_NOISE_MIN] == 1 + && g_inspt_crtra_flag[IDX_ACT_IDLE_NOISE_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_RAWDATA_MIN] == 1 + && g_inspt_crtra_flag[IDX_LP_RAWDATA_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_RAW_BPN_MIN] == 1 + && g_inspt_crtra_flag[IDX_LP_RAW_BPN_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_WT_NOISE] &= + (g_inspt_crtra_flag[IDX_LP_WT_NOISEMAX] == 1 + && g_inspt_crtra_flag[IDX_LP_WT_NOISEMIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_ABS_NOISE] &= + (g_inspt_crtra_flag[IDX_LP_NOISE_ABS_MAX] == 1 + && g_inspt_crtra_flag[IDX_LP_NOISE_ABS_MIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_IDLE_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_IDLE_RAWDATA_MAX] == 1 + && g_inspt_crtra_flag[IDX_LP_IDLE_RAWDATA_MIN] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_IDLE_BPN_RAWDATA] &= + (g_inspt_crtra_flag[IDX_LP_IDLE_RAW_BPN_MIN] == 1 + && g_inspt_crtra_flag[IDX_LP_IDLE_RAW_BPN_MAX] == 1) ? 1 : 0; + + g_test_item_flag[HX_LP_IDLE_NOISE] &= + (g_inspt_crtra_flag[IDX_LP_IDLE_NOISE_MAX] == 1 + && g_inspt_crtra_flag[IDX_LP_IDLE_NOISE_MIN] == 1) ? 1 : 0; + + do_lpwg_test = g_test_item_flag[HX_LP_RAWDATA] + | g_test_item_flag[HX_LP_BPN_RAWDATA] + | g_test_item_flag[HX_LP_WT_NOISE] + | g_test_item_flag[HX_LP_ABS_NOISE] + | g_test_item_flag[HX_LP_IDLE_RAWDATA] + | g_test_item_flag[HX_LP_IDLE_BPN_RAWDATA] + | g_test_item_flag[HX_LP_IDLE_NOISE]; + + if (private_ts->debug_log_level & BIT(4)) { + for (i = 0; i < HX_CRITERIA_ITEM - 1; i++) + I("g_test_item_flag[%d] = %d\n", + i, g_test_item_flag[i]); + } +} + +int hx_get_size_str_arr(char **input) +{ + int i = 0; + int result = 0; + + while (input[i] != NULL) + i++; + + result = i; + if (private_ts->debug_log_level & BIT(4)) + I("There is %d in [0]=%s\n", result, input[0]); + + return result; +} + +static void hx_print_ic_id(void) +{ + uint8_t i; + uint32_t len = 0; + char *prt_data = NULL; + + prt_data = kzalloc(sizeof(char) * HX_SZ_ICID, GFP_KERNEL); + if (prt_data == NULL) { + E("%s: Memory allocation falied!\n", __func__); + return; + } + + len += snprintf(prt_data + len, HX_SZ_ICID - len, + "IC ID : "); + for (i = 0; i < 13; i++) { + len += snprintf(prt_data + len, HX_SZ_ICID - len, + "%02X", ic_data->vendor_ic_id[i]); + } + len += snprintf(prt_data + len, HX_SZ_ICID - len, + "\n"); + + memcpy(&g_rslt_data[0], prt_data, len); + g_rslt_data_len = len; + I("%s: g_rslt_data_len=%d!\n", __func__, g_rslt_data_len); + + kfree(prt_data); +} + +static int himax_self_test_data_init(void) +{ + const struct firmware *file_entry = NULL; + struct himax_ts_data *ts = private_ts; + char *file_name_1 = "hx_criteria.dri"; + char *file_name_2 = "hx_criteria.csv"; + int ret = HX_INSP_OK; + int err = 0; + int i = 0; + + /* + * 5: one value will not over than 99999, so get this size of string + * 2: get twice size + */ + g_1kind_raw_size = 5 * ic_data->HX_RX_NUM * ic_data->HX_TX_NUM * 2; + + /* get test item and its items of criteria*/ + HX_CRITERIA_ITEM = hx_get_size_str_arr(g_himax_inspection_mode); + HX_CRITERIA_SIZE = hx_get_size_str_arr(g_hx_inspt_crtra_name); + I("There is %d HX_CRITERIA_ITEM and %d HX_CRITERIA_SIZE\n", + HX_CRITERIA_ITEM, HX_CRITERIA_SIZE); + + /* init criteria data*/ + g_test_item_flag = kcalloc(HX_CRITERIA_ITEM, sizeof(int), GFP_KERNEL); + if (g_test_item_flag == NULL) { + E("%s,%d: Memory allocation falied!\n", __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_test_item_flag; + } + + g_inspt_crtra_flag = kcalloc(HX_CRITERIA_SIZE, sizeof(int), GFP_KERNEL); + if (g_inspt_crtra_flag == NULL) { + E("%s,%d: Memory allocation falied!\n", __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_inspt_crtra_flag; + } + + g_inspection_criteria = kcalloc(HX_CRITERIA_SIZE, + sizeof(int *), GFP_KERNEL); + if (g_inspection_criteria == NULL) { + E("%s,%d: Memory allocation falied!\n", __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_inspection_criteria; + } + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + g_inspection_criteria[i] = kcalloc((ic_data->HX_TX_NUM + * ic_data->HX_RX_NUM), + sizeof(int), GFP_KERNEL); + if (g_inspection_criteria[i] == NULL) { + E("%s,%d: Memory allocation %d falied!\n", + __func__, __LINE__, i); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_inspection_criteria2; + } + } + + g_rslt_data_len = 0; + if (g_rslt_data == NULL) { + g_rslt_data = kcalloc(g_1kind_raw_size, sizeof(char), + GFP_KERNEL); + if (g_rslt_data == NULL) { + E("%s,%d: Memory allocation falied!\n", + __func__, __LINE__); + ret = HX_INSP_MEMALLCTFAIL; + goto err_malloc_rslt_data; + } + } + I("%s: initialize g_rslt_data, length = %d\n", + __func__, g_1kind_raw_size); + memset(g_rslt_data, 0x00, g_1kind_raw_size * sizeof(char)); + + /* default path is /system/etc/firmware */ + /* request criteria file*/ + err = request_firmware(&file_entry, file_name_1, ts->dev); + if (err < 0) { + E("%s,Fail to get %s\n", __func__, file_name_1); + err = request_firmware(&file_entry, file_name_2, ts->dev); + if (err < 0) { + E("%s,Fail to get %s\n", __func__, file_name_2); + I("No criteria file file"); + ret = HX_INSP_EFILE; + goto err_open_criteria_file; + } else { + I("%s,Success to get %s\n", __func__, file_name_2); + /* parsing criteria from file .csv*/ + ret = himax_parse_criteria(file_entry); + release_firmware(file_entry); + if (ret > 0) + goto err_open_criteria_file; + himax_test_item_chk(true); + } + } else { + /* parsing test file .dri*/ + I("%s,Success to get %s\n", __func__, file_name_1); + ret = himax_parse_test_dri_file(file_entry); + release_firmware(file_entry); + if (ret > 0) + goto err_open_criteria_file; + himax_test_item_chk(false); + } + + if (private_ts->debug_log_level & BIT(4)) { + /* print get criteria string */ + for (i = 0 ; i < HX_CRITERIA_SIZE ; i++) { + if (g_inspt_crtra_flag[i] != 0) + I("%s: [%d]There is String=%s\n", + __func__, i, g_hx_inspt_crtra_name[i]); + } + } + + snprintf(g_file_path, (int)(strlen(HX_RSLT_OUT_PATH) + + strlen(HX_RSLT_OUT_FILE)+1), + "%s%s", HX_RSLT_OUT_PATH, HX_RSLT_OUT_FILE); + + file_w_flag = true; + return ret; + +err_open_criteria_file: + kfree(g_rslt_data); + g_rslt_data = NULL; +err_malloc_rslt_data: + +err_malloc_inspection_criteria2: + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (g_inspection_criteria[i] != NULL) { + kfree(g_inspection_criteria[i]); + g_inspection_criteria[i] = NULL; + } + } + kfree(g_inspection_criteria); + g_inspection_criteria = NULL; +err_malloc_inspection_criteria: + kfree(g_inspt_crtra_flag); + g_inspt_crtra_flag = NULL; +err_malloc_inspt_crtra_flag: + kfree(g_test_item_flag); + g_test_item_flag = NULL; +err_malloc_test_item_flag: + return ret; +} + +static void himax_self_test_data_deinit(void) +{ + int i = 0; + + /*dbg*/ + /* for (i = 0; i < HX_CRITERIA_ITEM; i++) + * I("%s:[%d]%d\n", __func__, i, g_inspection_criteria[i]); + */ + + I("%s: release allocated memory\n", __func__); + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (g_inspection_criteria[i] != NULL) { + kfree(g_inspection_criteria[i]); + g_inspection_criteria[i] = NULL; + } + } + kfree(g_inspection_criteria); + g_inspection_criteria = NULL; + + kfree(g_inspt_crtra_flag); + g_inspt_crtra_flag = NULL; + + kfree(g_test_item_flag); + g_test_item_flag = NULL; + I("%s: release finished\n", __func__); + +} + +static int himax_chip_self_test(struct seq_file *s, void *v) +{ + uint32_t ret = HX_INSP_OK; + uint32_t test_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM + + ic_data->HX_TX_NUM + ic_data->HX_RX_NUM; + int i = 0; + uint8_t tmp_addr[DATA_LEN_4] = {0x94, 0x72, 0x00, 0x10}; + uint8_t tmp_data[DATA_LEN_4] = {0x01, 0x00, 0x00, 0x00}; + struct file *raw_file = NULL; + struct filename *vts_name = NULL; + mm_segment_t fs; + loff_t pos = 0; + uint32_t rslt = HX_INSP_OK; + + I("%s:IN\n", __func__); + + private_ts->suspend_resume_done = 0; + + ret = himax_self_test_data_init(); + if (ret > 0) { + E("%s: initialize self test failed\n", __func__); + goto END; + } + +#if defined(HX_ZERO_FLASH) + g_core_fp.fp_0f_op_file_dirly(MPAP_FWNAME); + hx_turn_on_mp_func(1); + g_core_fp.fp_reload_disable(0); + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense on!\n", __func__); + g_core_fp.fp_sense_on(0x00); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense on!\n", __func__); +#endif + + if (!kp_getname_kernel) { + E("kp_getname_kernel is NULL, not open file!\n"); + file_w_flag = false; + } else + vts_name = kp_getname_kernel(g_file_path); + + if (raw_file == NULL && file_w_flag) { + raw_file = kp_file_open_name(vts_name, + O_TRUNC|O_CREAT|O_RDWR, 0660); + + if (IS_ERR(raw_file)) { + E("%s open file failed = %ld\n", + __func__, PTR_ERR(raw_file)); + file_w_flag = false; + } + } + + fs = get_fs(); + set_fs(get_ds()); + + hx_print_ic_id(); + if (file_w_flag) { + vfs_write(raw_file, g_rslt_data, g_rslt_data_len, &pos); + pos += g_rslt_data_len; + } + + /*Do normal test items*/ + for (i = 0; i < HX_CRITERIA_ITEM; i++) { + if (i < HX_LP_WT_NOISE) { + if (g_test_item_flag[i] == 1) { + I("%d. %s Start\n", i, + g_himax_inspection_mode[i]); + rslt = mpTestFunc(i, test_size); + if (file_w_flag && + ((rslt & HX_INSP_EGETRAW) == 0) && + ((rslt & HX_INSP_ESWITCHMODE) == 0)) { + vfs_write(raw_file, g_rslt_data, + g_rslt_data_len, &pos); + pos += g_rslt_data_len; + } + ret |= rslt; + + I("%d. %s End, ret = %d\n", i, + g_himax_inspection_mode[i], ret); + } + } else { + break; + } + } + + /* Press power key and do LPWUG test items*/ + if (do_lpwg_test) { + himax_press_powerkey(); + /* Wait suspend done */ + while (private_ts->suspend_resume_done != 1) { + usleep_range(1000, 1001); + if (private_ts->debug_log_level & BIT(4)) + I("Waiting for tp suspend!\n"); + } + private_ts->suspend_resume_done = 0; + + for (; i < HX_CRITERIA_ITEM; i++) { + if (g_test_item_flag[i] == 1) { + I("%d.%s Start\n", i, + g_himax_inspection_mode[i]); + rslt = mpTestFunc(i, test_size); + if (file_w_flag && + ((rslt & HX_INSP_EGETRAW) == 0) && + ((rslt & HX_INSP_ESWITCHMODE) == 0)) { + vfs_write(raw_file, g_rslt_data, + g_rslt_data_len, &pos); + pos += g_rslt_data_len; + } + ret |= rslt; + + I("%d.%s End\n", i, g_himax_inspection_mode[i]); + } + } + himax_press_powerkey(); + /* Wait resume done */ + while (private_ts->suspend_resume_done != 1) + usleep_range(1000, 1001); + } + if (file_w_flag) + filp_close(raw_file, NULL); + if (!kp_putname_kernel) { + E("kp_putname_kernel is NULL, not open file!\n"); + file_w_flag = false; + } else if(file_w_flag) + kp_putname_kernel(vts_name); + + set_fs(fs); + +#if defined(HX_ZERO_FLASH) + private_ts->in_self_test = 0; + g_core_fp.fp_0f_op_file_dirly(BOOT_UPGRADE_FWNAME); + hx_turn_on_mp_func(0); + /* set N frame back to default value 1*/ + g_core_fp.fp_register_write(tmp_addr, 4, tmp_data, 0); + g_core_fp.fp_reload_disable(0); +#else + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense off!\n", __func__); + g_core_fp.fp_sense_off(true); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense off!\n", __func__); + hx_turn_on_mp_func(0); + /*himax_set_N_frame(1, HX_INSPECTION_WT_NOISE);*/ + /* set N frame back to default value 1*/ + g_core_fp.fp_register_write(tmp_addr, 4, tmp_data, 0); +#if !defined(HX_ZERO_FLASH) + if (g_core_fp.fp_reload_disable != NULL) + g_core_fp.fp_reload_disable(0); +#endif +#endif + + if (himax_check_mode(HX_RAWDATA)) { + I("%s:try to Need to back to Normal!\n", __func__); + himax_switch_mode_inspection(HX_RAWDATA); + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense on!\n", __func__); + g_core_fp.fp_sense_on(0); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense on!\n", __func__); + himax_wait_sorting_mode(HX_RAWDATA); + } else { + I("%s: It has been in Normal!\n", __func__); + if (private_ts->debug_log_level & BIT(4)) + I("%s:start sense on!\n", __func__); + g_core_fp.fp_sense_on(0); + if (private_ts->debug_log_level & BIT(4)) + I("%s:end sense on!\n", __func__); + } + + if (ret == HX_INSP_OK) + seq_puts(s, "Self_Test Pass:\n"); + else + seq_puts(s, "Self_Test Fail:\n"); + + for (i = 0; i < HX_CRITERIA_ITEM - 1; i++) { + if (g_test_item_flag[i] == 1) { + seq_printf(s, "%s : %s\n", + g_himax_inspection_mode[i], + ((ret & (1 << (i + ERR_SFT))) + == (1 << (i + ERR_SFT))) ? "Fail":"OK"); + } + } + + himax_self_test_data_deinit(); + +END: + I("running status = %X\n", ret); + + /*if (ret != 0)*/ + /*ret = 1;*/ + + I("%s:OUT\n", __func__); + return ret; +} + +void himax_inspect_data_clear(void) +{ + if (!g_rslt_data) { + kfree(g_rslt_data); + g_rslt_data = NULL; + } +} + +void himax_inspection_init(void) +{ + I("%s: enter, %d\n", __func__, __LINE__); + g_core_fp.fp_chip_self_test = himax_chip_self_test; +} diff --git a/drivers/input/touchscreen/hxchipset/himax_inspection.h b/drivers/input/touchscreen/hxchipset/himax_inspection.h new file mode 100644 index 0000000000000000000000000000000000000000..552be834163f0374532fed3c405d56d8771bb825 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_inspection.h @@ -0,0 +1,296 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for inspection functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +#include "himax_platform.h" +#include "himax_common.h" +#include "himax_ic_core.h" + +/*#define HX_GAP_TEST*/ +/*#define HX_INSP_LP_TEST*/ +/*#define HX_ACT_IDLE_TEST*/ + +/*#define HX_INSPT_DBG*/ + +#define HX_RSLT_OUT_PATH "/sdcard/" +#define HX_RSLT_OUT_FILE "hx_test_result.txt" +#define PI(x...) pr_cont(x) +#define HX_SZ_ICID 60 + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +#endif + +#define BS_RAWDATA 10 +#define BS_NOISE 10 +#define BS_OPENSHORT 0 +#define BS_LPWUG 1 +#define BS_LP_dile 1 +#define BS_ACT_IDLE 1 + +/* skip notch & dummy */ +#define SKIP_NOTCH_START 5 +#define SKIP_NOTCH_END 10 +/* TX+SKIP_NOTCH_START */ +#define SKIP_DUMMY_START 23 +/* TX+SKIP_NOTCH_END*/ +#define SKIP_DUMMY_END 28 + + +#define NOISEFRAME (BS_NOISE+1) +#define NORMAL_IDLE_RAWDATA_NOISEFRAME 10 +#define LP_RAWDATAFRAME 1 +#define LP_NOISEFRAME 1 +#define LP_IDLE_RAWDATAFRAME 1 +#define LP_IDLE_NOISEFRAME 1 + +#define OTHERSFRAME 2 + +#define UNIFMAX 500 + + +/*Himax MP Password*/ +#define PWD_OPEN_START 0x77 +#define PWD_OPEN_END 0x88 +#define PWD_SHORT_START 0x11 +#define PWD_SHORT_END 0x33 +#define PWD_RAWDATA_START 0x00 +#define PWD_RAWDATA_END 0x99 +#define PWD_NOISE_START 0x00 +#define PWD_NOISE_END 0x99 +#define PWD_SORTING_START 0xAA +#define PWD_SORTING_END 0xCC + + +#define PWD_ACT_IDLE_START 0x22 +#define PWD_ACT_IDLE_END 0x44 + + + +#define PWD_LP_START 0x55 +#define PWD_LP_END 0x66 + +#define PWD_LP_IDLE_START 0x50 +#define PWD_LP_IDLE_END 0x60 + +#define PWD_TURN_ON_MPAP_OVL 0x107380 + +/*Himax DataType*/ +#define DATA_SORTING 0x0A +#define DATA_OPEN 0x0B +#define DATA_MICRO_OPEN 0x0C +#define DATA_SHORT 0x0A +#define DATA_RAWDATA 0x0A +#define DATA_NOISE 0x0F +#define DATA_BACK_NORMAL 0x00 +#define DATA_LP_RAWDATA 0x0C +#define DATA_LP_NOISE 0x0F +#define DATA_ACT_IDLE_RAWDATA 0x0A +#define DATA_ACT_IDLE_NOISE 0x0F +#define DATA_LP_IDLE_RAWDATA 0x0A +#define DATA_LP_IDLE_NOISE 0x0F + +/*Himax Data Ready Password*/ +#define Data_PWD0 0xA5 +#define Data_PWD1 0x5A + +/* ASCII format */ +#define ASCII_LF (0x0A) +#define ASCII_CR (0x0D) +#define ASCII_COMMA (0x2C) +#define ASCII_ZERO (0x30) +#define CHAR_EL '\0' +#define CHAR_NL '\n' +#define ACSII_SPACE (0x20) +/* INSOECTION Setting */ + +void himax_inspection_init(void); +extern int *g_test_item_flag; +extern int HX_CRITERIA_ITEM; +extern int *g_test_item_flag; +extern char *g_himax_inspection_mode[]; + +/*Inspection register*/ +#define addr_normal_noise_thx 0x1000708C +#define addr_lpwug_noise_thx 0x10007090 +#define addr_noise_scale 0x10007094 +#define addr_recal_thx 0x10007090 +#define addr_palm_num 0x100070A8 +#define addr_weight_sup 0x100072C8 +#define addr_normal_weight_a 0x1000709C +#define addr_lpwug_weight_a 0x100070A0 +#define addr_weight_b 0x10007094 +#define addr_max_dc 0x10007FC8 +#define addr_skip_frame 0x100070F4 +#define addr_neg_noise_sup 0x10007FD8 +#define data_neg_noise 0x7F0C0000 +#define addr_ctrl_mpap_ovl 0x100073EC + +/*Need to map *g_himax_inspection_mode[]*/ +enum THP_INSPECTION_ENUM { + HX_OPEN, + HX_MICRO_OPEN, + HX_SHORT, + HX_SC, + HX_WT_NOISE, + HX_ABS_NOISE, + HX_RAWDATA, + HX_BPN_RAWDATA, + HX_SORTING, + + HX_GAPTEST_RAW, + /*HX_GAPTEST_RAW_X,*/ + /*HX_GAPTEST_RAW_Y,*/ + + HX_ACT_IDLE_NOISE, + HX_ACT_IDLE_RAWDATA, + HX_ACT_IDLE_BPN_RAWDATA, +/*LPWUG test must put after Normal test*/ + HX_LP_WT_NOISE, + HX_LP_ABS_NOISE, + HX_LP_RAWDATA, + HX_LP_BPN_RAWDATA, + + HX_LP_IDLE_NOISE, + HX_LP_IDLE_RAWDATA, + HX_LP_IDLE_BPN_RAWDATA, + + HX_BACK_NORMAL,/*Must put in the end*/ +}; + + +enum HX_CRITERIA_ENUM { + IDX_RAWMIN = 0, + IDX_RAWMAX, + IDX_BPN_RAWMIN, + IDX_BPN_RAWMAX, + IDX_SCMIN, + IDX_SCMAX, + IDX_SC_GOLDEN, + IDX_SHORTMIN, + IDX_SHORTMAX, + IDX_OPENMIN, + IDX_OPENMAX, + IDX_M_OPENMIN, + IDX_M_OPENMAX, + IDX_WT_NOISEMIN, + IDX_WT_NOISEMAX, + IDX_ABS_NOISEMIN, + IDX_ABS_NOISEMAX, + IDX_SORTMIN, + IDX_SORTMAX, + + IDX_GAP_HOR_RAWMAX, + IDX_GAP_HOR_RAWMIN, + IDX_GAP_VER_RAWMAX, + IDX_GAP_VER_RAWMIN, + + IDX_ACT_IDLE_NOISE_MIN, + IDX_ACT_IDLE_NOISE_MAX, + IDX_ACT_IDLE_RAWDATA_MIN, + IDX_ACT_IDLE_RAWDATA_MAX, + IDX_ACT_IDLE_RAW_BPN_MIN, + IDX_ACT_IDLE_RAW_BPN_MAX, + + IDX_LP_WT_NOISEMIN, + IDX_LP_WT_NOISEMAX, + IDX_LP_NOISE_ABS_MIN, + IDX_LP_NOISE_ABS_MAX, + IDX_LP_RAWDATA_MIN, + IDX_LP_RAWDATA_MAX, + IDX_LP_RAW_BPN_MIN, + IDX_LP_RAW_BPN_MAX, + + IDX_LP_IDLE_NOISE_MIN, + IDX_LP_IDLE_NOISE_MAX, + IDX_LP_IDLE_RAWDATA_MIN, + IDX_LP_IDLE_RAWDATA_MAX, + IDX_LP_IDLE_RAW_BPN_MIN, + IDX_LP_IDLE_RAW_BPN_MAX, +}; + +#define ERR_SFT 4 +/* Error code of Inspection */ +enum HX_INSP_ERR_ENUM { + /* OK */ + HX_INSP_OK = 0, + + /* Criteria file error*/ + HX_INSP_EFILE = 1, + + /* Get raw data errors */ + HX_INSP_EGETRAW = 1 << 1, + + /* Memory allocate errors */ + HX_INSP_MEMALLCTFAIL = 1 << 2, + + /* Switch mode error*/ + HX_INSP_ESWITCHMODE = 1 << 3, + + /* Sensor open error */ + HX_EOPEN = 1 << (HX_OPEN + ERR_SFT), + + /* Sensor micro open error */ + HX_EMOPEN = 1 << (HX_MICRO_OPEN + ERR_SFT), + + /* Sensor short error */ + HX_ESHORT = 1 << (HX_SHORT + ERR_SFT), + + /* Raw data error */ + HX_ERAW = 1 << (HX_RAWDATA + ERR_SFT), + + /* Raw data BPN error */ + HX_EBPNRAW = 1 << (HX_BPN_RAWDATA + ERR_SFT), + + /* Get SC errors */ + HX_ESC = 1 << (HX_SC + ERR_SFT), + + /* Noise error */ + HX_WT_ENOISE = 1 << (HX_WT_NOISE + ERR_SFT), + + /* Noise error */ + HX_ABS_ENOISE = 1 << (HX_ABS_NOISE + ERR_SFT), + + /* Sorting error*/ + HX_ESORT = 1 << (HX_SORTING + ERR_SFT), + + /* Raw Data GAP */ + HX_EGAP_RAW = 1 << (HX_GAPTEST_RAW + ERR_SFT), + + /* ACT_IDLE RAW ERROR */ + HX_EACT_IDLE_RAW = 1 << (HX_ACT_IDLE_RAWDATA + ERR_SFT), + + /* ACT_IDLE NOISE ERROR */ + HX_EACT_IDLE_NOISE = 1 << (HX_ACT_IDLE_NOISE + ERR_SFT), + + /* LPWUG RAW ERROR */ + HX_ELP_RAW = 1 << (HX_LP_RAWDATA + ERR_SFT), + + /* LPWUG NOISE ERROR */ + HX_ELP_WT_NOISE = 1 << (HX_LP_WT_NOISE + ERR_SFT), + + /* LPWUG NOISE ERROR */ + HX_ELP_ABS_NOISE = 1 << (HX_LP_ABS_NOISE + ERR_SFT), + + /* LPWUG IDLE RAW ERROR */ + HX_ELP_IDLE_RAW = 1 << (HX_LP_IDLE_RAWDATA + ERR_SFT), + + /* LPWUG IDLE NOISE ERROR */ + HX_ELP_IDLE_NOISE = 1 << (HX_LP_IDLE_NOISE + ERR_SFT), + HX_EACT_IDLE_BPNRAW = 1 << (HX_ACT_IDLE_BPN_RAWDATA + ERR_SFT), + HX_ELP_BPNRAW = 1 << (HX_LP_BPN_RAWDATA + ERR_SFT), + HX_ELP_IDLE_BPNRAW = 1 << (HX_LP_IDLE_BPN_RAWDATA + ERR_SFT), +}; + +extern void himax_inspect_data_clear(void); diff --git a/drivers/input/touchscreen/hxchipset/himax_modular.h b/drivers/input/touchscreen/hxchipset/himax_modular.h new file mode 100644 index 0000000000000000000000000000000000000000..707a1f4f46ef012f5c25a7d6268056db8923cbf8 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_modular.h @@ -0,0 +1,374 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for modularize functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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 __HIMAX_MODULAR_H__ +#define __HIMAX_MODULAR_H__ + +#include "himax_modular_table.h" + +static bool (*this_detect_fp)(void); + +#if defined(HX_USE_KSYM) +static void himax_add_chip_dt(bool (*detect_fp)(void)) +{ + int32_t idx; + struct himax_chip_entry *entry; + + this_detect_fp = detect_fp; + idx = himax_get_ksym_idx(); + if (idx < 0) { + /*TODO: No entry, handle this error*/ + E("%s: no entry exist, please insert ic module first!", + __func__); + } else { + entry = (void *)kallsyms_lookup_name(himax_ksym_lookup[idx]); + if (/*!(entry->core_chip_dt)*/isEmpty(idx) == 1) { + entry->core_chip_dt = kcalloc(HX_DRIVER_MAX_IC_NUM, + sizeof(struct himax_chip_detect), GFP_KERNEL); + if (entry->core_chip_dt == NULL) { + E("%s: Failed to allocate core_chip_dt\n", + __func__); + return; + } + entry->hx_ic_dt_num = 0; + } + entry->core_chip_dt[entry->hx_ic_dt_num++].fp_chip_detect = + detect_fp; + } +} + +#else + +static void himax_add_chip_dt(bool (*detect_fp)(void)) +{ + this_detect_fp = detect_fp; + if (himax_ksym_lookup.core_chip_dt == NULL) { + himax_ksym_lookup.core_chip_dt = kcalloc(HX_DRIVER_MAX_IC_NUM, + sizeof(struct himax_chip_detect), GFP_KERNEL); + if (himax_ksym_lookup.core_chip_dt == NULL) { + E("%s: Failed to allocate core_chip_dt\n", __func__); + return; + } + himax_ksym_lookup.hx_ic_dt_num = 0; + } + + himax_ksym_lookup.core_chip_dt + [himax_ksym_lookup.hx_ic_dt_num].fp_chip_detect = detect_fp; + himax_ksym_lookup.hx_ic_dt_num++; +} + +#endif + +static void free_chip_dt_table(void) +{ + int i, j, idx; + struct himax_chip_entry *entry; + + idx = himax_get_ksym_idx(); + if (idx >= 0) { + if (isEmpty(idx) != 0) { + I("%s: no chip registered or entry clean up\n", + __func__); + return; + } + entry = get_chip_entry_by_index(idx); + + for (i = 0; i < entry->hx_ic_dt_num; i++) { + if (entry->core_chip_dt + [i].fp_chip_detect == this_detect_fp) { + if (i == (entry->hx_ic_dt_num - 1)) { + entry->core_chip_dt + [i].fp_chip_detect = NULL; + entry->hx_ic_dt_num = 0; + } else { + for (j = i; j < entry + ->hx_ic_dt_num; j++) + entry->core_chip_dt + [i].fp_chip_detect = + entry->core_chip_dt + [j].fp_chip_detect; + + entry->core_chip_dt + [j].fp_chip_detect = NULL; + entry->hx_ic_dt_num--; + } + } + } + if (entry->hx_ic_dt_num == 0) { + kfree(entry->core_chip_dt); + entry->core_chip_dt = NULL; + } + } +} + +#if !defined(HX_USE_KSYM) +#define setup_symbol(sym) ({kp_##sym = &(sym); kp_##sym; }) +#define setup_symbol_func(sym) ({kp_##sym = (sym); kp_##sym; }) +#else +#define setup_symbol(sym) ({kp_##sym = (void *)kallsyms_lookup_name(#sym); \ + kp_##sym; }) +#define setup_symbol_func(sym) setup_symbol(sym) +#endif + +#define assert_on_symbol(sym) \ + do { \ + if (!setup_symbol(sym)) { \ + E("%s: setup %s failed!\n", __func__, #sym); \ + ret = -1; \ + } \ + } while (0) + +#define assert_on_symbol_func(sym) \ + do { \ + if (!setup_symbol_func(sym)) { \ + E("%s: setup %s failed!\n", __func__, #sym); \ + ret = -1; \ + } \ + } while (0) +#if !defined(__HIMAX_HX852xH_MOD__) && !defined(__HIMAX_HX852xG_MOD__) +static struct fw_operation **kp_pfw_op; +static struct ic_operation **kp_pic_op; +static struct flash_operation **kp_pflash_op; +static struct driver_operation **kp_pdriver_op; +#endif + +#if defined(HX_ZERO_FLASH) && defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) +static struct zf_operation **kp_pzf_op; +static int *kp_G_POWERONOF; +#endif + +static unsigned char *kp_IC_CHECKSUM; + +#if defined(HX_EXCP_RECOVERY) +static u8 *kp_HX_EXCP_RESET_ACTIVATE; +#endif + +#if defined(HX_ZERO_FLASH) && defined(HX_CODE_OVERLAY) +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) +static uint8_t **kp_ovl_idx; +#endif +#endif + +static unsigned long *kp_FW_VER_MAJ_FLASH_ADDR; +static unsigned long *kp_FW_VER_MIN_FLASH_ADDR; +static unsigned long *kp_CFG_VER_MAJ_FLASH_ADDR; +static unsigned long *kp_CFG_VER_MIN_FLASH_ADDR; +static unsigned long *kp_CID_VER_MAJ_FLASH_ADDR; +static unsigned long *kp_CID_VER_MIN_FLASH_ADDR; +static uint32_t *kp_CFG_TABLE_FLASH_ADDR; + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + static int *kp_g_i_FW_VER; + static int *kp_g_i_CFG_VER; + static int *kp_g_i_CID_MAJ; + static int *kp_g_i_CID_MIN; + static const struct firmware **kp_hxfw; +#endif + +#if defined(HX_TP_PROC_2T2R) + static bool *kp_Is_2T2R; +#endif + +#if defined(HX_USB_DETECT_GLOBAL) + static void (*kp_himax_cable_detect_func)(bool force_renew); +#endif + +#if defined(HX_RST_PIN_FUNC) + static void (*kp_himax_rst_gpio_set)(int pinnum, uint8_t value); +#endif + +static struct himax_ts_data **kp_private_ts; +static struct himax_core_fp *kp_g_core_fp; +static struct himax_ic_data **kp_ic_data; + +#if defined(__HIMAX_HX852xH_MOD__) || defined(__HIMAX_HX852xG_MOD__) +static struct on_driver_operation **kp_on_pdriver_op; +static void (*kp_himax_mcu_on_cmd_init)(void); +static int (*kp_himax_mcu_on_cmd_struct_init)(void); +#else +static void (*kp_himax_mcu_in_cmd_init)(void); +static int (*kp_himax_mcu_in_cmd_struct_init)(void); +#endif +static void (*kp_himax_parse_assign_cmd)(uint32_t addr, uint8_t *cmd, + int len); + +static int (*kp_himax_bus_read)(uint8_t command, uint8_t *data, + uint32_t length, uint8_t toRetry); +static int (*kp_himax_bus_write)(uint8_t command, uint8_t *data, + uint32_t length, uint8_t toRetry); +static int (*kp_himax_bus_write_command)(uint8_t command, uint8_t toRetry); +static void (*kp_himax_int_enable)(int enable); +static int (*kp_himax_ts_register_interrupt)(void); +static uint8_t (*kp_himax_int_gpio_read)(int pinnum); +static int (*kp_himax_gpio_power_config)(struct himax_i2c_platform_data *pdata); + +#if !defined(HX_USE_KSYM) +#if !defined(__HIMAX_HX852xH_MOD__) && !defined(__HIMAX_HX852xG_MOD__) +extern struct fw_operation *pfw_op; +extern struct ic_operation *pic_op; +extern struct flash_operation *pflash_op; +extern struct driver_operation *pdriver_op; +#endif + +#if defined(HX_ZERO_FLASH) && defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) +extern struct zf_operation *pzf_op; +extern int G_POWERONOF; +#endif + +extern unsigned char IC_CHECKSUM; + +#if defined(HX_EXCP_RECOVERY) +extern u8 HX_EXCP_RESET_ACTIVATE; +#endif + +#if defined(HX_ZERO_FLASH) && defined(HX_CODE_OVERLAY) +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) +extern uint8_t *ovl_idx; +#endif +#endif + +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +extern unsigned long CID_VER_MAJ_FLASH_ADDR; +extern unsigned long CID_VER_MIN_FLASH_ADDR; +extern uint32_t CFG_TABLE_FLASH_ADDR; + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + extern int g_i_FW_VER; + extern int g_i_CFG_VER; + extern int g_i_CID_MAJ; + extern int g_i_CID_MIN; + extern const struct firmware *hxfw; +#endif + +#if defined(HX_TP_PROC_2T2R) + extern bool Is_2T2R; +#endif + +#if defined(HX_USB_DETECT_GLOBAL) + extern void (himax_cable_detect_func)(bool force_renew); +#endif + +#if defined(HX_RST_PIN_FUNC) + extern void (himax_rst_gpio_set)(int pinnum, uint8_t value); +#endif + +extern struct himax_ts_data *private_ts; +extern struct himax_core_fp g_core_fp; +extern struct himax_ic_data *ic_data; + +#if defined(__HIMAX_HX852xH_MOD__) || defined(__HIMAX_HX852xG_MOD__) +extern struct on_driver_operation *on_pdriver_op; +extern void (himax_mcu_on_cmd_init)(void); +extern int (himax_mcu_on_cmd_struct_init)(void); +#else +extern void (himax_mcu_in_cmd_init)(void); +extern int (himax_mcu_in_cmd_struct_init)(void); +#endif +extern void (himax_parse_assign_cmd)(uint32_t addr, uint8_t *cmd, int len); + +extern int (himax_bus_read)(uint8_t command, uint8_t *data, uint32_t length, + uint8_t toRetry); +extern int (himax_bus_write)(uint8_t command, uint8_t *data, uint32_t length, + uint8_t toRetry); +extern int (himax_bus_write_command)(uint8_t command, uint8_t toRetry); +extern void (himax_int_enable)(int enable); +extern int (himax_ts_register_interrupt)(void); +extern uint8_t (himax_int_gpio_read)(int pinnum); +extern int (himax_gpio_power_config)(struct himax_i2c_platform_data *pdata); +#endif + +static int32_t himax_ic_setup_external_symbols(void) +{ + int32_t ret = 0; + +#if !defined(__HIMAX_HX852xH_MOD__) && !defined(__HIMAX_HX852xG_MOD__) + assert_on_symbol(pfw_op); + assert_on_symbol(pic_op); + assert_on_symbol(pflash_op); + assert_on_symbol(pdriver_op); +#endif + + assert_on_symbol(private_ts); + assert_on_symbol(g_core_fp); + assert_on_symbol(ic_data); + +#if defined(__HIMAX_HX852xH_MOD__) || defined(__HIMAX_HX852xG_MOD__) + assert_on_symbol(on_pdriver_op); + assert_on_symbol_func(himax_mcu_on_cmd_init); + assert_on_symbol_func(himax_mcu_on_cmd_struct_init); +#else + assert_on_symbol_func(himax_mcu_in_cmd_init); + assert_on_symbol_func(himax_mcu_in_cmd_struct_init); +#endif + assert_on_symbol_func(himax_parse_assign_cmd); + assert_on_symbol_func(himax_bus_read); + assert_on_symbol_func(himax_bus_write); + assert_on_symbol_func(himax_bus_write_command); + assert_on_symbol_func(himax_int_enable); + assert_on_symbol_func(himax_ts_register_interrupt); + assert_on_symbol_func(himax_int_gpio_read); + assert_on_symbol_func(himax_gpio_power_config); + +#if defined(HX_ZERO_FLASH) && defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) + assert_on_symbol(pzf_op); + assert_on_symbol(G_POWERONOF); +#endif + + assert_on_symbol(IC_CHECKSUM); + + assert_on_symbol(FW_VER_MAJ_FLASH_ADDR); + assert_on_symbol(FW_VER_MIN_FLASH_ADDR); + assert_on_symbol(CFG_VER_MAJ_FLASH_ADDR); + assert_on_symbol(CFG_VER_MIN_FLASH_ADDR); + assert_on_symbol(CID_VER_MAJ_FLASH_ADDR); + assert_on_symbol(CID_VER_MIN_FLASH_ADDR); + assert_on_symbol(CFG_TABLE_FLASH_ADDR); + +#if defined(HX_BOOT_UPGRADE) || defined(HX_ZERO_FLASH) + assert_on_symbol(g_i_FW_VER); + assert_on_symbol(g_i_CFG_VER); + assert_on_symbol(g_i_CID_MAJ); + assert_on_symbol(g_i_CID_MIN); + assert_on_symbol(hxfw); +#endif + +#if defined(HX_TP_PROC_2T2R) + assert_on_symbol(Is_2T2R); +#endif + +#if defined(HX_USB_DETECT_GLOBAL) + assert_on_symbol_func(himax_cable_detect_func); +#endif + +#if defined(HX_RST_PIN_FUNC) + assert_on_symbol_func(himax_rst_gpio_set); +#endif + +#if defined(HX_EXCP_RECOVERY) + assert_on_symbol(HX_EXCP_RESET_ACTIVATE); +#endif +#if defined(HX_ZERO_FLASH) && defined(HX_CODE_OVERLAY) +#if defined(CONFIG_TOUCHSCREEN_HIMAX_INCELL) + assert_on_symbol(ovl_idx); +#endif +#endif + return ret; +} + + +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_modular_table.h b/drivers/input/touchscreen/hxchipset/himax_modular_table.h new file mode 100644 index 0000000000000000000000000000000000000000..df3f84eeede431d79792a59cf2a0d8633496ab4f --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_modular_table.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for modularize functions + * + * Copyright (C) 2019 Himax Corporation. + * + * 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 __HIMAX_MODULAR_TABLE_H__ +#define __HIMAX_MODULAR_TABLE_H__ + +#include "himax_ic_core.h" + +#define TO_STR(VAR) #VAR + +enum modular_table { + MODULE_NOT_FOUND = -1, + MODULE_FOUND, + MODULE_EMPTY, +}; + +#if defined(HX_USE_KSYM) +#define DECLARE(sym) struct himax_chip_entry sym; \ + EXPORT_SYMBOL(sym) +static const char * const himax_ksym_lookup[] = { + #if defined(HX_MOD_KSYM_HX852xG) + TO_STR(HX_MOD_KSYM_HX852xG), + #endif + #if defined(HX_MOD_KSYM_HX852xH) + TO_STR(HX_MOD_KSYM_HX852xH), + #endif + #if defined(HX_MOD_KSYM_HX83102) + TO_STR(HX_MOD_KSYM_HX83102), + #endif + #if defined(HX_MOD_KSYM_HX83103) + TO_STR(HX_MOD_KSYM_HX83103), + #endif + #if defined(HX_MOD_KSYM_HX83106) + TO_STR(HX_MOD_KSYM_HX83106), + #endif + #if defined(HX_MOD_KSYM_HX83111) + TO_STR(HX_MOD_KSYM_HX83111), + #endif + #if defined(HX_MOD_KSYM_HX83112) + TO_STR(HX_MOD_KSYM_HX83112), + #endif + #if defined(HX_MOD_KSYM_HX83113) + TO_STR(HX_MOD_KSYM_HX83113), + #endif + #if defined(HX_MOD_KSYM_HX83192) + TO_STR(HX_MOD_KSYM_HX83192), + #endif + #if defined(HX_MOD_KSYM_HX83191) + TO_STR(HX_MOD_KSYM_HX83191), + #endif + NULL +}; + +static struct himax_chip_entry *get_chip_entry_by_index(int32_t idx) +{ + return (void *)kallsyms_lookup_name(himax_ksym_lookup[idx]); +} + +/* + * Return 1 when specified entry is empty, 0 when not, -1 when index error + */ +static int32_t isEmpty(int32_t idx) +{ + int32_t size = sizeof(himax_ksym_lookup) / sizeof(char *); + struct himax_chip_entry *entry; + + if (idx < 0 || idx >= size) + return MODULE_NOT_FOUND; + + entry = get_chip_entry_by_index(idx); + if (entry) + return (entry->core_chip_dt == NULL)?MODULE_EMPTY:MODULE_FOUND; + + return MODULE_NOT_FOUND; +} + +/* + * Search for created entry, if not existed, return 1st + * Return index of himax_ksym_lookup + */ +static int32_t himax_get_ksym_idx(void) +{ + int32_t i, first = -1; + int32_t size = sizeof(himax_ksym_lookup) / sizeof(char *); + struct himax_chip_entry *entry; + + I("%s: symtable size: %d\n", __func__, size); + for (i = 0; i < size; i++) { + if (himax_ksym_lookup[i] == NULL) + break; + + I("%s: %s\n", __func__, himax_ksym_lookup[i]); + entry = get_chip_entry_by_index(i); + if (entry) { + if (first < 0) + first = i; + if (isEmpty(i) == 0) + return i; + } + } + if (first >= 0) + return first; + /*incorrect use state, means no ic defined*/ + return MODULE_NOT_FOUND; +} + +#else +#define DECLARE(sym) +extern struct himax_chip_entry himax_ksym_lookup; + +static struct himax_chip_entry *get_chip_entry_by_index(int32_t idx) +{ + return &himax_ksym_lookup; +} + +static int32_t isEmpty(int32_t idx) +{ + struct himax_chip_entry *entry; + + if (idx < 0) + return MODULE_NOT_FOUND; + + entry = get_chip_entry_by_index(idx); + if (entry) + return (entry->core_chip_dt == NULL)?MODULE_EMPTY:MODULE_FOUND; + + return MODULE_NOT_FOUND; +} + +static int32_t himax_get_ksym_idx(void) +{ + int32_t size; + + size = himax_ksym_lookup.hx_ic_dt_num; + + I("%s: symtable size: %d\n", __func__, size); + return 0; +} + +#endif + + + +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c new file mode 100644 index 0000000000000000000000000000000000000000..006f797888fd5c200c3321d549bf81d1db229044 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -0,0 +1,1209 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for QCT platform + * + * Copyright (C) 2019 Himax Corporation. + * + * 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. + */ + +#include "himax_platform.h" +#include "himax_common.h" +#include "himax_ic_core.h" + +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" + +int i2c_error_count; +u8 *gp_rw_buf; + +struct drm_panel *active_panel; + +int check_dt(struct device_node *np) +{ + int i; + int count; + struct device_node *node; + struct drm_panel *panel; + + count = of_count_phandle_with_args(np, "panel", NULL); + if (count <= 0) + return 0; + + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "panel", i); + panel = of_drm_find_panel(node); + of_node_put(node); + if (!IS_ERR(panel)) { + active_panel = panel; + return 0; + } + } + + return -ENODEV; +} + +int check_default_tp(struct device_node *dt, const char *prop) +{ + const char *active_tp; + const char *compatible; + char *start; + int ret; + + ret = of_property_read_string(dt->parent, prop, &active_tp); + if (ret) { + pr_err(" %s:fail to read %s %d\n", __func__, prop, ret); + return -ENODEV; + } + + ret = of_property_read_string(dt, "compatible", &compatible); + if (ret < 0) { + pr_err(" %s:fail to read %s %d\n", __func__, "compatible", ret); + return -ENODEV; + } + + start = strnstr(active_tp, compatible, strlen(active_tp)); + if (start == NULL) { + pr_err(" %s:no match compatible, %s, %s\n", + __func__, compatible, active_tp); + ret = -ENODEV; + } + + return ret; +} + +int himax_dev_set(struct himax_ts_data *ts) +{ + int ret = 0; + + ts->input_dev = input_allocate_device(); + + if (ts->input_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device-input_dev\n", __func__); + return ret; + } + + ts->input_dev->name = "himax-touchscreen"; + + if (!ic_data->HX_PEN_FUNC) + goto skip_pen_operation; + + ts->hx_pen_dev = input_allocate_device(); + + if (ts->hx_pen_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device-hx_pen_dev\n", __func__); + return ret; + } + + ts->hx_pen_dev->name = "himax-pen"; +skip_pen_operation: + + return ret; +} +int himax_input_register_device(struct input_dev *input_dev) +{ + return input_register_device(input_dev); +} + +void himax_vk_parser(struct device_node *dt, + struct himax_i2c_platform_data *pdata) +{ + u32 data = 0; + uint8_t cnt = 0, i = 0; + uint32_t coords[4] = {0}; + struct device_node *node, *pp = NULL; + struct himax_virtual_key *vk; + + + node = of_parse_phandle(dt, "virtualkey", 0); + + if (node == NULL) { + I(" DT-No vk info in DT\n"); + } else { + while ((pp = of_get_next_child(node, pp))) + cnt++; + + if (!cnt) + return; + + vk = kcalloc(cnt, sizeof(struct himax_virtual_key), GFP_KERNEL); + if (vk == NULL) { + E("%s, Failed to allocate memory\n", __func__); + return; + } + pp = NULL; + + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "idx", &data) == 0) + vk[i].index = data; + + if (of_property_read_u32_array(pp, "range", coords, 4) + == 0) { + vk[i].x_range_min = coords[0]; + vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2]; + vk[i].y_range_max = coords[3]; + } else { + I(" range faile\n"); + } + + i++; + } + + pdata->virtual_key = vk; + + for (i = 0; i < cnt; i++) + I(" vk[%d] idx:%d x_min:%d, y_max:%d\n", i, + pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, + pdata->virtual_key[i].y_range_max); + } +} + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata) +{ + int rc, coords_size = 0; + uint32_t coords[4] = {0}; + struct property *prop; + struct device_node *dt = private_ts->client->dev.of_node; + u32 data = 0; + int ret = 0; + + prop = of_find_property(dt, "himax,panel-coords", NULL); + + if (prop) { + coords_size = prop->length / sizeof(u32); + + if (coords_size != 4) + D(" %s:Invalid panel coords size %d\n", + __func__, coords_size); + } + + ret = of_property_read_u32_array(dt, "himax,panel-coords", + coords, coords_size); + if (ret == 0) { + pdata->abs_x_min = coords[0]; + pdata->abs_x_max = (coords[1] - 1); + pdata->abs_y_min = coords[2]; + pdata->abs_y_max = (coords[3] - 1); + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, + pdata->abs_x_min, + pdata->abs_x_max, + pdata->abs_y_min, + pdata->abs_y_max); + } + + prop = of_find_property(dt, "himax,display-coords", NULL); + + if (prop) { + coords_size = prop->length / sizeof(u32); + + if (coords_size != 4) + D(" %s:Invalid display coords size %d\n", + __func__, coords_size); + } + + rc = of_property_read_u32_array(dt, "himax,display-coords", + coords, coords_size); + + if (rc && (rc != -EINVAL)) { + D(" %s:Fail to read display-coords %d\n", __func__, rc); + return rc; + } + + pdata->screenWidth = coords[1]; + pdata->screenHeight = coords[3]; + I(" DT-%s:display-coords = (%d, %d)\n", __func__, + pdata->screenWidth, + pdata->screenHeight); + pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); + + if (!gpio_is_valid(pdata->gpio_irq)) + I(" DT:gpio_irq value is not valid\n"); + + pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); + + if (!gpio_is_valid(pdata->gpio_reset)) + I(" DT:gpio_rst value is not valid\n"); + +#if defined(HX_PON_PIN_SUPPORT) + pdata->gpio_pon = of_get_named_gpio(dt, "himax,pon-gpio", 0); + + if (!gpio_is_valid(pdata->gpio_pon)) + I(" DT:gpio_pon value is not valid\n"); + + pdata->lcm_rst = of_get_named_gpio(dt, "himax,lcm-rst", 0); + + if (!gpio_is_valid(pdata->lcm_rst)) + I(" DT:tp-rst value is not valid\n"); + + I(" DT:pdata->gpio_pon=%d, pdata->lcm_rst=%d\n", + pdata->gpio_pon, pdata->lcm_rst); +#endif + + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); + + if (!gpio_is_valid(pdata->gpio_3v3_en)) + I(" DT:gpio_3v3_en value is not valid\n"); + + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d\n", + pdata->gpio_irq, + pdata->gpio_reset, + pdata->gpio_3v3_en); + + if (of_property_read_u32(dt, "report_type", &data) == 0) { + pdata->protocol_type = data; + I(" DT:protocol_type=%d\n", pdata->protocol_type); + } + + himax_vk_parser(dt, pdata); + return 0; +} +EXPORT_SYMBOL(himax_parse_dt); + +int himax_bus_read(uint8_t command, uint8_t *data, + uint32_t length, uint8_t toRetry) +{ + int retry; + struct i2c_client *client = private_ts->client; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = gp_rw_buf, + } + }; + mutex_lock(&private_ts->rw_lock); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) { + memcpy(data, gp_rw_buf, length); + break; + } + /*msleep(20);*/ + } + + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + i2c_error_count = toRetry; + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + + mutex_unlock(&private_ts->rw_lock); + return 0; +} +EXPORT_SYMBOL(himax_bus_read); + +int himax_bus_write(uint8_t command, uint8_t *data, + uint32_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + struct i2c_client *client = private_ts->client; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = gp_rw_buf, + } + }; + + + mutex_lock(&private_ts->rw_lock); + gp_rw_buf[0] = command; + if (data != NULL) + memcpy(gp_rw_buf + 1, data, length); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + + /*msleep(20);*/ + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + i2c_error_count = toRetry; + mutex_unlock(&private_ts->rw_lock); + return -EIO; + } + + mutex_unlock(&private_ts->rw_lock); + return 0; +} +EXPORT_SYMBOL(himax_bus_write); + +int himax_bus_write_command(uint8_t command, uint8_t toRetry) +{ + return himax_bus_write(command, NULL, 0, toRetry); +} + +void himax_int_enable(int enable) +{ + struct himax_ts_data *ts = private_ts; + unsigned long irqflags = 0; + int irqnum = ts->client->irq; + + spin_lock_irqsave(&ts->irq_lock, irqflags); + I("%s: Entering!\n", __func__); + if (enable == 1 && atomic_read(&ts->irq_state) == 0) { + atomic_set(&ts->irq_state, 1); + enable_irq(irqnum); + private_ts->irq_enabled = 1; + } else if (enable == 0 && atomic_read(&ts->irq_state) == 1) { + atomic_set(&ts->irq_state, 0); + disable_irq_nosync(irqnum); + private_ts->irq_enabled = 0; + } + + I("enable = %d\n", enable); + spin_unlock_irqrestore(&ts->irq_lock, irqflags); +} +EXPORT_SYMBOL(himax_int_enable); + +#if defined(HX_RST_PIN_FUNC) +void himax_rst_gpio_set(int pinnum, uint8_t value) +{ + gpio_direction_output(pinnum, value); +} +EXPORT_SYMBOL(himax_rst_gpio_set); +#endif + +uint8_t himax_int_gpio_read(int pinnum) +{ + return gpio_get_value(pinnum); +} + +#if defined(CONFIG_HMX_DB) +static int himax_regulator_configure(struct himax_i2c_platform_data *pdata) +{ + int retval; + struct i2c_client *client = private_ts->client; + + pdata->vcc_dig = regulator_get(&client->dev, "vdd"); + + if (IS_ERR(pdata->vcc_dig)) { + E("%s: Failed to get regulator vdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + + pdata->vcc_ana = regulator_get(&client->dev, "avdd"); + + if (IS_ERR(pdata->vcc_ana)) { + E("%s: Failed to get regulator avdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_dig); + return retval; + } + + return 0; +}; + +static void himax_regulator_deinit(struct himax_i2c_platform_data *pdata) +{ + I("%s: entered.\n", __func__); + + if (!IS_ERR(pdata->vcc_ana)) + regulator_put(pdata->vcc_ana); + + if (!IS_ERR(pdata->vcc_dig)) + regulator_put(pdata->vcc_dig); + + I("%s: regulator put, completed.\n", __func__); +}; + +static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) +{ + int retval; + + if (on) { + retval = regulator_enable(pdata->vcc_dig); + + if (retval) { + E("%s: Failed to enable regulator vdd\n", + __func__); + return retval; + } + + /*msleep(100);*/ + usleep_range(1000, 1001); + retval = regulator_enable(pdata->vcc_ana); + + if (retval) { + E("%s: Failed to enable regulator avdd\n", + __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } else { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + + return 0; +} + +int himax_gpio_power_config(struct himax_i2c_platform_data *pdata) +{ + int error; + struct i2c_client *client = private_ts->client; + + + error = himax_regulator_configure(pdata); + + if (error) { + E("Failed to intialize hardware\n"); + goto err_regulator_not_on; + } + +#if defined(HX_RST_PIN_FUNC) + + if (gpio_is_valid(pdata->gpio_reset)) { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_reset); + goto err_regulator_on; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } + +#endif + error = himax_power_on(pdata, true); + + if (error) { + E("Failed to power on hardware\n"); + goto err_power_on; + } + + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_irq); + goto err_req_irq_gpio; + } + + error = gpio_direction_input(pdata->gpio_irq); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_set_gpio_irq; + } + + client->irq = gpio_to_irq(pdata->gpio_irq); + private_ts->hx_irq = client->irq; + } else { + E("irq gpio not provided\n"); + goto err_req_irq_gpio; + } + + /*msleep(20);*/ + usleep_range(2000, 2001); +#if defined(HX_RST_PIN_FUNC) + + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_set_gpio_irq; + } + } + +#endif + return 0; +err_set_gpio_irq: + + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); + +err_req_irq_gpio: + himax_power_on(pdata, false); +err_power_on: +#if defined(HX_RST_PIN_FUNC) +err_gpio_reset_req: + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); + +err_regulator_on: +#endif + himax_regulator_deinit(pdata); +err_regulator_not_on: + return error; +} + +#else +int himax_gpio_power_config(struct himax_i2c_platform_data *pdata) +{ + int error = 0; + struct i2c_client *client = private_ts->client; +#if defined(HX_RST_PIN_FUNC) + + if (pdata->gpio_reset >= 0) { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + + if (error < 0) { + E("%s: request reset pin failed\n", __func__); + goto err_gpio_reset_req; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_dir; + } + } + +#endif + +#if defined(HX_PON_PIN_SUPPORT) + if (pdata->lcm_rst >= 0) { + error = gpio_request(pdata->lcm_rst, "lcm-reset"); + + if (error < 0) { + E("%s: request lcm-reset pin failed\n", __func__); + goto err_lcm_rst_req; + } + + error = gpio_direction_output(pdata->lcm_rst, 0); + if (error) { + E("unable to set direction for lcm_rst [%d]\n", + pdata->lcm_rst); + goto err_lcm_rst_dir; + } + } + + if (gpio_is_valid(pdata->gpio_pon)) { + error = gpio_request(pdata->gpio_pon, "hmx_pon_gpio"); + + if (error) { + E("unable to request scl gpio [%d]\n", pdata->gpio_pon); + goto err_gpio_pon_req; + } + + error = gpio_direction_output(pdata->gpio_pon, 0); + + I("gpio_pon LOW [%d]\n", pdata->gpio_pon); + + if (error) { + E("unable to set direction for pon gpio [%d]\n", + pdata->gpio_pon); + goto err_gpio_pon_dir; + } + } +#endif + + + if (pdata->gpio_3v3_en >= 0) { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + + if (error < 0) { + E("%s: request 3v3_en pin failed\n", __func__); + goto err_gpio_3v3_req; + } + + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en set 1 get pin = %d\n", + gpio_get_value(pdata->gpio_3v3_en)); + } + + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + goto err_gpio_irq_req; + } + + error = gpio_direction_input(pdata->gpio_irq); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_set_input; + } + + client->irq = gpio_to_irq(pdata->gpio_irq); + private_ts->hx_irq = client->irq; + } else { + E("irq gpio not provided\n"); + goto err_gpio_irq_req; + } + + usleep_range(2000, 2001); + +#if defined(HX_PON_PIN_SUPPORT) + msleep(20); + + if (pdata->lcm_rst >= 0) { + error = gpio_direction_output(pdata->lcm_rst, 1); + + if (error) { + E("lcm_rst unable to set direction for gpio [%d]\n", + pdata->lcm_rst); + goto err_lcm_reset_set_high; + } + } + msleep(20); +#endif + +#if defined(HX_RST_PIN_FUNC) + + if (pdata->gpio_reset >= 0) { + error = gpio_direction_output(pdata->gpio_reset, 1); + + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_set_high; + } + } +#endif + +#if defined(HX_PON_PIN_SUPPORT) + msleep(800); + + if (gpio_is_valid(pdata->gpio_pon)) { + + error = gpio_direction_output(pdata->gpio_pon, 1); + + I("gpio_pon HIGH [%d]\n", pdata->gpio_pon); + + if (error) { + E("gpio_pon unable to set direction for gpio [%d]\n", + pdata->gpio_pon); + goto err_gpio_pon_set_high; + } + } +#endif + return error; + +#if defined(HX_PON_PIN_SUPPORT) +err_gpio_pon_set_high: +#endif +#if defined(HX_RST_PIN_FUNC) +err_gpio_reset_set_high: +#endif +#if defined(HX_PON_PIN_SUPPORT) +err_lcm_reset_set_high: +#endif +err_gpio_irq_set_input: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +err_gpio_irq_req: + if (pdata->gpio_3v3_en >= 0) + gpio_free(pdata->gpio_3v3_en); +err_gpio_3v3_req: +#if defined(HX_PON_PIN_SUPPORT) +err_gpio_pon_dir: + if (gpio_is_valid(pdata->gpio_pon)) + gpio_free(pdata->gpio_pon); +err_gpio_pon_req: +err_lcm_rst_dir: + if (gpio_is_valid(pdata->lcm_rst)) + gpio_free(pdata->lcm_rst); +err_lcm_rst_req: +#endif +#if defined(HX_RST_PIN_FUNC) +err_gpio_reset_dir: + if (pdata->gpio_reset >= 0) + gpio_free(pdata->gpio_reset); +err_gpio_reset_req: +#endif + return error; +} + +#endif + +int himax_ts_pinctrl_init(struct himax_ts_data *ts) +{ + int retval; + /* Get pinctrl if target uses pinctrl */ + ts->ts_pinctrl = devm_pinctrl_get(ts->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->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->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->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; +} + +void himax_gpio_power_deconfig(struct himax_i2c_platform_data *pdata) +{ + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); + +#if defined(HX_RST_PIN_FUNC) + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +#endif + +#if defined(CONFIG_HMX_DB) + himax_power_on(pdata, false); + himax_regulator_deinit(pdata); +#else + if (pdata->gpio_3v3_en >= 0) + gpio_free(pdata->gpio_3v3_en); + +#if defined(HX_PON_PIN_SUPPORT) + if (gpio_is_valid(pdata->gpio_pon)) + gpio_free(pdata->gpio_pon); +#endif + +#endif +} + +static void himax_ts_isr_func(struct himax_ts_data *ts) +{ + himax_ts_work(ts); +} + +irqreturn_t himax_ts_thread(int irq, void *ptr) +{ + himax_ts_isr_func((struct himax_ts_data *)ptr); + + return IRQ_HANDLED; +} + +static void himax_ts_work_func(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, + struct himax_ts_data, work); + + + himax_ts_work(ts); +} + +int himax_int_register_trigger(void) +{ + int ret = 0; + struct himax_ts_data *ts = private_ts; + struct i2c_client *client = private_ts->client; + + if (ic_data->HX_INT_IS_EDGE) { + I("%s edge triiger falling\n ", __func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->name, ts); + } + + else { + I("%s level trigger low\n ", __func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); + } + + return ret; +} + +int himax_int_en_set(void) +{ + int ret = NO_ERR; + + + ret = himax_int_register_trigger(); + return ret; +} + +int himax_ts_register_interrupt(void) +{ + struct himax_ts_data *ts = private_ts; + struct i2c_client *client = private_ts->client; + int ret = 0; + + + ts->irq_enabled = 0; + + /* Work functon */ + if (client->irq && private_ts->hx_irq) {/*INT mode*/ + ts->use_irq = 1; + ret = himax_int_register_trigger(); + + if (ret == 0) { + ts->irq_enabled = 1; + atomic_set(&ts->irq_state, 1); + I("%s: irq enabled at gpio: %d\n", __func__, + client->irq); +#if defined(HX_SMART_WAKEUP) + irq_set_irq_wake(client->irq, 1); +#endif + } else { + ts->use_irq = 0; + E("%s: request_irq failed\n", __func__); + } + } else { + I("%s: client->irq is empty, use polling mode.\n", __func__); + } + + /*if use polling mode need to disable HX_ESD_RECOVERY function*/ + if (!ts->use_irq) { + ts->himax_wq = create_singlethread_workqueue("himax_touch"); + INIT_WORK(&ts->work, himax_ts_work_func); + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = himax_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + I("%s: polling mode enabled\n", __func__); + } + + return ret; +} + +int himax_ts_unregister_interrupt(void) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + + I("%s: entered.\n", __func__); + + /* Work functon */ + if (private_ts->hx_irq && ts->use_irq) {/*INT mode*/ +#if defined(HX_SMART_WAKEUP) + irq_set_irq_wake(ts->hx_irq, 0); +#endif + free_irq(ts->hx_irq, ts); + I("%s: irq disabled at qpio: %d\n", __func__, + private_ts->hx_irq); + } + + /*if use polling mode need to disable HX_ESD_RECOVERY function*/ + if (!ts->use_irq) { + hrtimer_cancel(&ts->timer); + cancel_work_sync(&ts->work); + if (ts->himax_wq != NULL) + destroy_workqueue(ts->himax_wq); + I("%s: polling mode destroyed", __func__); + } + + return ret; +} + +static int himax_common_suspend(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); +#if defined(HX_CONFIG_DRM) && !defined(HX_CONFIG_FB) + if (!ts->initialized) + return -ECANCELED; +#endif + himax_chip_common_suspend(ts); + return 0; +} + +static int himax_common_resume(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter\n", __func__); +#if defined(HX_CONFIG_DRM) && !defined(HX_CONFIG_FB) + /* + * wait until device resume for TDDI + * TDDI: Touch and display Driver IC + */ + if (!ts->initialized) + if (himax_chip_common_init()) + return -ECANCELED; +#endif + himax_chip_common_resume(ts); + return 0; +} + +#if defined(HX_CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct himax_ts_data *ts = + container_of(self, struct himax_ts_data, fb_notif); + + + I(" %s\n", __func__); + + if (evdata + && evdata->data + && event == FB_EVENT_BLANK + && ts + && ts->client) { + blank = evdata->data; + + switch (*blank) { + case FB_BLANK_UNBLANK: + himax_common_resume(&ts->client->dev); + break; + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + himax_common_suspend(&ts->client->dev); + break; + } + } + + return 0; +} +#elif defined(HX_CONFIG_DRM) +int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct drm_panel_notifier *evdata = data; + int *blank = NULL; + struct himax_ts_data *ts = + container_of(self, struct himax_ts_data, fb_notif); + + I("in\n"); + + if (!evdata) + return 0; + + if (!(event == DRM_PANEL_EARLY_EVENT_BLANK || + event == DRM_PANEL_EVENT_BLANK)) { + I("event(%lu) do not need process\n", event); + return 0; + } + + blank = evdata->data; + I("FB event:%lu,blank:%d", event, *blank); + switch (*blank) { + case DRM_PANEL_BLANK_UNBLANK: + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { + I("resume: event = %lu, not care\n", event); + } else if (event == DRM_PANEL_EVENT_BLANK) { + himax_common_resume(ts->dev); + } + break; + + case DRM_PANEL_BLANK_POWERDOWN: + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { + himax_common_suspend(ts->dev); + } else if (event == DRM_PANEL_EVENT_BLANK) { + I("suspend: event = %lu, not care\n", event); + } + break; + + default: + E("FB BLANK(%d) do not need process\n", *blank); + break; + } + + return 0; + +} +#endif + +int himax_chip_common_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct himax_ts_data *ts; + struct device_node *dp = client->dev.of_node; + + I("%s:Enter\n", __func__); + + gp_rw_buf = kcalloc(BUS_RW_MAX_LEN, sizeof(uint8_t), GFP_KERNEL); + if (!gp_rw_buf) { + E("Allocate I2C RW Buffer failed\n"); + ret = -ENODEV; + goto err_alloc_rw_buf_failed; + } + + /* Check I2C functionality */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + E("%s: i2c check functionality error\n", __func__); + return -ENODEV; + } + + if (check_dt(dp)) { + if (!check_default_tp(dp, "qcom,i2c-touch-active")) + ret = -EPROBE_DEFER; + else + ret = -ENODEV; + E("check_dt failed, error=%d", ret); + return ret; + } + + ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); + if (ts == NULL) { + E("%s: allocate himax_ts_data failed\n", __func__); + ret = -ENOMEM; + goto err_alloc_data_failed; + } + + i2c_set_clientdata(client, ts); + ts->client = client; + ts->dev = &client->dev; + mutex_init(&ts->rw_lock); + private_ts = ts; + + ret = himax_ts_pinctrl_init(ts); + if (ret || ts->ts_pinctrl == NULL) + E(" Pinctrl init failed\n"); + + ts->initialized = false; + ret = himax_chip_common_init(); + if (ret < 0) + goto err_common_init_failed; + + ret = g_core_fp.fp_read_i2c_status(); + if (ret) { + E("i2c communication error\n"); + goto err_common_init_failed; + } + + g_core_fp.read_mcf_data(); + + return ret; + +err_common_init_failed: + kfree(ts); +err_alloc_data_failed: + kfree(gp_rw_buf); +err_alloc_rw_buf_failed: + + return ret; +} + +int himax_chip_common_remove(struct i2c_client *client) +{ + if (g_hx_chip_inited) + himax_chip_common_deinit(); + + kfree(gp_rw_buf); + + return 0; +} + +static const struct i2c_device_id himax_common_ts_id[] = { + {HIMAX_common_NAME, 0 }, + {} +}; + +static const struct dev_pm_ops himax_common_pm_ops = { +#if (!defined(HX_CONFIG_FB)) && (!defined(HX_CONFIG_DRM)) + .suspend = himax_common_suspend, + .resume = himax_common_resume, +#endif +}; + +#if defined(CONFIG_OF) +static const struct of_device_id himax_match_table[] = { + {.compatible = "himax,hxcommon" }, + {}, +}; +#else +#define himax_match_table NULL +#endif + +static struct i2c_driver himax_common_driver = { + .id_table = himax_common_ts_id, + .probe = himax_chip_common_probe, + .remove = himax_chip_common_remove, + .driver = { + .name = HIMAX_common_NAME, + .owner = THIS_MODULE, + .of_match_table = himax_match_table, +#if defined(CONFIG_PM) + .pm = &himax_common_pm_ops, +#endif + }, +}; + +static int __init himax_common_init(void) +{ + I("Himax common touch panel driver init\n"); + D("Himax check double loading\n"); + if (g_mmi_refcnt++ > 0) { + + I("Himax driver has been loaded! ignoring....\n"); + + return 0; + } + i2c_add_driver(&himax_common_driver); + + return 0; +} + +static void __exit himax_common_exit(void) +{ + i2c_del_driver(&himax_common_driver); +} + +module_init(himax_common_init); +module_exit(himax_common_exit); + +MODULE_DESCRIPTION("Himax_common driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h new file mode 100644 index 0000000000000000000000000000000000000000..0c01246585dda033215ebb636ecc331162406b3a --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -0,0 +1,149 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Himax Android Driver Sample Code for QCT platform + * + * Copyright (C) 2019 Himax Corporation. + * + * 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 HIMAX_PLATFORM_H +#define HIMAX_PLATFORM_H + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_HMX_DB) + #include +#endif + +#define HIMAX_I2C_RETRY_TIMES 3 +#define BUS_RW_MAX_LEN 256 + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_debug("[HXTP] " x) +#define I(x...) pr_info("[HXTP] " x) +#define W(x...) pr_warn("[HXTP][WARNING] " x) +#define E(x...) pr_err("[HXTP][ERROR] " x) +#define DIF(x...) \ +do { \ + if (debug_flag) \ + pr_debug("[HXTP][DEBUG] " x) \ + } while (0) +#else + +#define D(x...) +#define I(x...) +#define W(x...) +#define E(x...) +#define DIF(x...) +#endif + +#if defined(CONFIG_HMX_DB) + + /* Analog voltage @2.7 V */ + #define HX_VTG_MIN_UV 2700000 + #define HX_VTG_MAX_UV 3300000 + #define HX_ACTIVE_LOAD_UA 15000 + #define HX_LPM_LOAD_UA 10 + /* Digital voltage @1.8 V */ + #define HX_VTG_DIG_MIN_UV 1800000 + #define HX_VTG_DIG_MAX_UV 1800000 + #define HX_ACTIVE_LOAD_DIG_UA 10000 + #define HX_LPM_LOAD_DIG_UA 10 + #define HX_I2C_VTG_MIN_UV 1800000 + #define HX_I2C_VTG_MAX_UV 1800000 + #define HX_I2C_LOAD_UA 10000 + #define HX_I2C_LPM_LOAD_UA 10 + +#endif + +#define HIMAX_common_NAME "himax_tp" +#define HIMAX_I2C_ADDR 0x48 +#define INPUT_DEV_NAME "himax-touchscreen" + +struct himax_i2c_platform_data { + int abs_x_min; + int abs_x_max; + int abs_x_fuzz; + int abs_y_min; + int abs_y_max; + int abs_y_fuzz; + int abs_pressure_min; + int abs_pressure_max; + int abs_pressure_fuzz; + int abs_width_min; + int abs_width_max; + int screenWidth; + int screenHeight; + uint8_t fw_version; + uint8_t tw_id; + uint8_t powerOff3V3; + uint8_t cable_config[2]; + uint8_t protocol_type; + int gpio_irq; + int gpio_reset; + int gpio_3v3_en; + int gpio_pon; + int lcm_rst; + int (*power)(int on); + void (*reset)(void); + struct himax_virtual_key *virtual_key; + struct kobject *vk_obj; + struct kobj_attribute *vk2Use; + int hx_config_size; + +#if defined(CONFIG_HMX_DB) + bool i2c_pull_up; + bool digital_pwr_regulator; + int reset_gpio; + u32 reset_gpio_flags; + int irq_gpio; + u32 irq_gpio_flags; + struct regulator *vcc_ana; /* For Dragon Board */ + struct regulator *vcc_dig; /* For Dragon Board */ + struct regulator *vcc_i2c; /* For Dragon Board */ + +#endif + +}; + +extern int himax_bus_read(uint8_t command, uint8_t *data, + uint32_t length, uint8_t toRetry); +extern int himax_bus_write(uint8_t command, uint8_t *data, + uint32_t length, uint8_t toRetry); +extern int himax_bus_write_command(uint8_t command, + uint8_t toRetry); +extern void himax_int_enable(int enable); +extern int himax_ts_register_interrupt(void); +int himax_ts_unregister_interrupt(void); +extern uint8_t himax_int_gpio_read(int pinnum); +extern int himax_gpio_power_config(struct himax_i2c_platform_data *pdata); +void himax_gpio_power_deconfig(struct himax_i2c_platform_data *pdata); + +#if defined(HX_CONFIG_FB) +extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(HX_CONFIG_DRM) +extern int drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#endif +extern struct himax_ts_data *private_ts; +extern void himax_ts_work(struct himax_ts_data *ts); +extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int himax_chip_common_init(void); +extern void himax_chip_common_deinit(void); +int himax_ts_pinctrl_init(struct himax_ts_data *ts); + +#endif + diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index cddb56da62a82ff1e088c05e88cee4869b0349dd..7309c8bdefe4bd8a7f798934d9345fb1727b2afd 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -647,6 +647,8 @@ source "drivers/misc/ocxl/Kconfig" source "drivers/misc/cardreader/Kconfig" source "drivers/misc/fpr_FingerprintCard/Kconfig" source "drivers/misc/qrc/Kconfig" +source "drivers/misc/fpsensor_chipone/Kconfig" +source "drivers/misc/aw8695/Kconfig" endmenu config OKL4_USER_VIPC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 93fda83f75c1c8940bd2b2a07995712672dc7526..6f4ff86d24db4e0d7af0b7486ebf264e05c53279 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -78,3 +78,5 @@ obj-$(CONFIG_QTI_XR_SMRTVWR_MISC) += qxr-stdalonevwr.o obj-$(CONFIG_FPR_FPC) += fpr_FingerprintCard/ obj-y += qrc/ obj-$(CONFIG_KINECTICS_XR_NORDIC) += kxrctrl/ +obj-$(CONFIG_CHIPONE_FINGERPRINT) += fpsensor_chipone/ +obj-$(CONFIG_AW8695_HAPTIC) += aw8695/ diff --git a/drivers/misc/aw8695/Kconfig b/drivers/misc/aw8695/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..7cd5959dccf1fc4032a291848ca04417df88354e --- /dev/null +++ b/drivers/misc/aw8695/Kconfig @@ -0,0 +1,5 @@ +config AW8695_HAPTIC + tristate "Haptic driver for awinic AW8695 series" + depends on I2C + help + This option enables support for AW8695 series Haptic Driver. diff --git a/drivers/misc/aw8695/Makefile b/drivers/misc/aw8695/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ce8657ba08e5673c7dcf2b73ef2896cf8ba1a6d0 --- /dev/null +++ b/drivers/misc/aw8695/Makefile @@ -0,0 +1,2 @@ +#for AWINIC AW8695 Haptic +obj-$(CONFIG_AW8695_HAPTIC) += aw8695.o diff --git a/drivers/misc/aw8695/aw8695.c b/drivers/misc/aw8695/aw8695.c new file mode 100644 index 0000000000000000000000000000000000000000..b25af82892f3ef52b5b85d2861c3b175bcd81ee1 --- /dev/null +++ b/drivers/misc/aw8695/aw8695.c @@ -0,0 +1,4801 @@ +/* + * aw8695.c aw8695 haptic module + * + * Copyright (c) 2018 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AW_UEFI_CAL_F0 +/****************************************************** + * + * Marco + * + ******************************************************/ +#define AW8695_I2C_NAME "aw8695_haptic" +#define AW8695_HAPTIC_NAME "aw8695_haptic" + +#define AW8695_DRIVER_VERSION "v1.4.11" + +#define AWINIC_RAM_UPDATE_DELAY + +#define AW_I2C_RETRIES 2 +#define AW_I2C_RETRY_DELAY 2 +#define AW_READ_CHIPID_RETRIES 5 +#define AW_READ_CHIPID_RETRY_DELAY 2 +#define AW8695_MAX_DSP_START_TRY_COUNT 10 +#define AWINIC_READ_BIN_FLEXBALLY + +#define AW8695_MAX_FIRMWARE_LOAD_CNT 20 +#define PM_QOS_VALUE_VB 100 //Daniel 20201105 modify start +struct pm_qos_request pm_qos_req_vb; +/****************************************************** + * + * variable + * + ******************************************************/ +#define AW8695_RTP_NAME_MAX 64 +static char *aw8695_ram_name = "aw8695_haptic.bin"; +static char aw8695_rtp_name[][AW8695_RTP_NAME_MAX] = { + {"aw8695_osc_rtp_24K_5s.bin"}, +}; + +struct aw8695_container *aw8695_rtp; +struct aw8695 *g_aw8695; + +#ifdef AW_UEFI_CAL_F0 +unsigned int aw8695_f0_cal = 0; +#endif +unsigned int aw8695_test_index = 0; +/****************************************************** + * + * functions + * + ******************************************************/ +static void aw8695_interrupt_clear(struct aw8695 *aw8695); +static int aw8695_haptic_trig_enable_config(struct aw8695 *aw8695); +extern int i2c_check_status_create(char *name,int value); + +static bool aw_debug = false; +module_param(aw_debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(aw_debug, "Debugging mode enabled or not"); + +#define aw_dbg_info(format, arg...) \ + do { \ + if (aw_debug) \ + pr_info(format , ##arg); \ + } while (0) + + /****************************************************** + * + * aw8695 i2c write/read + * + ******************************************************/ +static int aw8695_i2c_write(struct aw8695 *aw8695, + unsigned char reg_addr, unsigned char reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while (cnt < AW_I2C_RETRIES) { + ret = + i2c_smbus_write_byte_data(aw8695->i2c, reg_addr, reg_data); + if (ret < 0) { + pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, + ret); + } else { + break; + } + cnt++; + usleep_range(AW_I2C_RETRY_DELAY * 1000, + AW_I2C_RETRY_DELAY * 1000 + 500); + } + + return ret; +} + +static int aw8695_i2c_read(struct aw8695 *aw8695, + unsigned char reg_addr, unsigned char *reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while (cnt < AW_I2C_RETRIES) { + ret = i2c_smbus_read_byte_data(aw8695->i2c, reg_addr); + if (ret < 0) { + pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, + ret); + } else { + *reg_data = ret; + break; + } + cnt++; + usleep_range(AW_I2C_RETRY_DELAY * 1000, + AW_I2C_RETRY_DELAY * 1000 + 500); + } + + return ret; +} + +static int aw8695_i2c_write_bits(struct aw8695 *aw8695, + unsigned char reg_addr, unsigned int mask, + unsigned char reg_data) +{ + unsigned char reg_val = 0; + + aw8695_i2c_read(aw8695, reg_addr, ®_val); + reg_val &= mask; + reg_val |= reg_data; + aw8695_i2c_write(aw8695, reg_addr, reg_val); + + return 0; +} + +static int aw8695_i2c_writes(struct aw8695 *aw8695, + unsigned char reg_addr, unsigned char *buf, + unsigned int len) +{ + int ret = -1; + unsigned char *data; + + data = kmalloc(len + 1, GFP_KERNEL); + if (data == NULL) { + pr_err("%s: can not allocate memory\n", __func__); + return -ENOMEM; + } + + data[0] = reg_addr; + memcpy(&data[1], buf, len); + + ret = i2c_master_send(aw8695->i2c, data, len + 1); + if (ret < 0) + pr_err("%s: i2c master send error\n", __func__); + + kfree(data); + + return ret; +} + +/***************************************************** + * + * ram update + * + *****************************************************/ +static void aw8695_rtp_loaded(const struct firmware *cont, void *context) +{ + struct aw8695 *aw8695 = context; + + pr_info("%s enter\n", __func__); + + if (!cont) { + pr_err("%s: failed to read %s\n", __func__, + aw8695_rtp_name[aw8695->rtp_file_num]); + release_firmware(cont); + return; + } + + pr_info("%s: loaded %s - size: %zu\n", __func__, + aw8695_rtp_name[aw8695->rtp_file_num], cont ? cont->size : 0); + + /* aw8695 rtp update */ + mutex_lock(&aw8695->rtp_lock); + aw8695_rtp = vmalloc(cont->size + sizeof(int)); + if (!aw8695_rtp) { + release_firmware(cont); + mutex_unlock(&aw8695->rtp_lock); + pr_err("%s: Error allocating memory\n", __func__); + return; + } + aw8695_rtp->len = cont->size; + pr_info("%s: rtp size = %d\n", __func__, aw8695_rtp->len); + memcpy(aw8695_rtp->data, cont->data, cont->size); + release_firmware(cont); + mutex_unlock(&aw8695->rtp_lock); + + aw8695->rtp_init = 1; + pr_info("%s: rtp update complete\n", __func__); +} + +static int aw8695_rtp_update(struct aw8695 *aw8695) +{ + pr_info("%s enter\n", __func__); + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8695_rtp_name[aw8695->rtp_file_num], + aw8695->dev, GFP_KERNEL, aw8695, + aw8695_rtp_loaded); +} + +static void aw8695_container_update(struct aw8695 *aw8695, + struct aw8695_container *aw8695_cont) +{ + int i = 0; + unsigned int shift = 0; + + pr_info("%s enter\n", __func__); + + mutex_lock(&aw8695->lock); + + aw8695->ram.baseaddr_shift = 2; + aw8695->ram.ram_shift = 4; + + /* RAMINIT Enable */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_EN); + + /* base addr */ + shift = aw8695->ram.baseaddr_shift; + aw8695->ram.base_addr = + (unsigned int)((aw8695_cont->data[0 + shift] << 8) | + (aw8695_cont->data[1 + shift])); + pr_info("%s: base_addr=0x%4x\n", __func__, aw8695->ram.base_addr); + + aw8695_i2c_write(aw8695, AW8695_REG_BASE_ADDRH, + aw8695_cont->data[0 + shift]); + aw8695_i2c_write(aw8695, AW8695_REG_BASE_ADDRL, + aw8695_cont->data[1 + shift]); + /*1/2 FIFO */ + aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AEH, + (unsigned char)((aw8695->ram.base_addr >> 1) >> 8)); + /*1/2 FIFO */ + aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AEL, + (unsigned char)((aw8695->ram.base_addr >> 1) & 0x00FF)); + aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AFH, + (unsigned + char)((aw8695->ram.base_addr - + (aw8695->ram.base_addr >> 2)) >> 8)); + aw8695_i2c_write(aw8695, AW8695_REG_FIFO_AFL, + (unsigned + char)((aw8695->ram.base_addr - + (aw8695->ram.base_addr >> 2)) & 0x00FF)); + + /* ram */ + shift = aw8695->ram.baseaddr_shift; + aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, + aw8695_cont->data[0 + shift]); + aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, + aw8695_cont->data[1 + shift]); + shift = aw8695->ram.ram_shift; + for (i = shift; i < aw8695_cont->len; i++) { + aw8695->ramupdate_flag = + aw8695_i2c_write(aw8695, AW8695_REG_RAMDATA, + aw8695_cont->data[i]); + } + +#if 0 + /* ram check */ + shift = aw8695->ram.baseaddr_shift; + aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, + aw8695_cont->data[0 + shift]); + aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, + aw8695_cont->data[1 + shift]); + shift = aw8695->ram.ram_shift; + for (i = shift; i < aw8695_cont->len; i++) { + aw8695_i2c_read(aw8695, AW8695_REG_RAMDATA, ®_val); + if (reg_val != aw8695_cont->data[i]) { + pr_err + ("%s: ram check error addr=0x%04x, file_data=0x%02x, ram_data=0x%02x\n", + __func__, i, aw8695_cont->data[i], reg_val); + return; + } + } +#endif + + /* RAMINIT Disable */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_OFF); + + mutex_unlock(&aw8695->lock); + + pr_info("%s exit\n", __func__); +} + +static void aw8695_ram_loaded(const struct firmware *cont, void *context) +{ + struct aw8695 *aw8695 = context; + struct aw8695_container *aw8695_fw; + int i = 0; + unsigned short check_sum = 0; + +#ifdef AWINIC_READ_BIN_FLEXBALLY + static unsigned char load_cont; + int ram_timer_val = 1000; + + load_cont++; +#endif + pr_info("%s enter\n", __func__); + + if (!cont) { + pr_err("%s: failed to read %s\n", __func__, aw8695_ram_name); + release_firmware(cont); +#ifdef AWINIC_READ_BIN_FLEXBALLY + if (load_cont <= 20) { + schedule_delayed_work(&aw8695->ram_work, + msecs_to_jiffies(ram_timer_val)); + pr_info("%s:start hrtimer:load_cont%d\n", __func__, + load_cont); + } +#endif + return; + } + + pr_info("%s: loaded %s - size: %zu\n", __func__, aw8695_ram_name, + cont ? cont->size : 0); +/* + for(i=0; isize; i++) { + pr_info("%s: addr:0x%04x, data:0x%02x\n", + __func__, i, *(cont->data+i)); + } +*/ + + /* check sum */ + for (i = 2; i < cont->size; i++) + check_sum += cont->data[i]; + if (check_sum != + (unsigned short)((cont->data[0] << 8) | (cont->data[1]))) { + pr_err("%s: check sum err: check_sum=0x%04x\n", __func__, + check_sum); + return; + } else { + pr_info("%s: check sum pass : 0x%04x\n", __func__, check_sum); + aw8695->ram.check_sum = check_sum; + } + + /* aw8695 ram update */ + aw8695_fw = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw8695_fw) { + release_firmware(cont); + pr_err("%s: Error allocating memory\n", __func__); + return; + } + aw8695_fw->len = cont->size; + memcpy(aw8695_fw->data, cont->data, cont->size); + release_firmware(cont); + + aw8695_container_update(aw8695, aw8695_fw); + + aw8695->ram.len = aw8695_fw->len; + + kfree(aw8695_fw); + + aw8695->ram_init = 1; + pr_info("%s: fw update complete\n", __func__); + + aw8695_haptic_trig_enable_config(aw8695); + + aw8695_rtp_update(aw8695); +} + +static int aw8695_ram_update(struct aw8695 *aw8695) +{ + aw8695->ram_init = 0; + aw8695->rtp_init = 0; + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8695_ram_name, aw8695->dev, GFP_KERNEL, + aw8695, aw8695_ram_loaded); +} + +#ifdef AWINIC_RAM_UPDATE_DELAY +static void aw8695_ram_work_routine(struct work_struct *work) +{ + struct aw8695 *aw8695 = + container_of(work, struct aw8695, ram_work.work); + + pr_info("%s enter\n", __func__); + + aw8695_ram_update(aw8695); + +} +#endif + +static int aw8695_ram_init(struct aw8695 *aw8695) +{ +#ifdef AWINIC_RAM_UPDATE_DELAY + int ram_timer_val = 5000; + + INIT_DELAYED_WORK(&aw8695->ram_work, aw8695_ram_work_routine); + schedule_delayed_work(&aw8695->ram_work, + msecs_to_jiffies(ram_timer_val)); +#else + aw8695_ram_update(aw8695); +#endif + return 0; +} + +/***************************************************** + * + * haptic control + * + *****************************************************/ +static int aw8695_haptic_softreset(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + aw8695_i2c_write(aw8695, AW8695_REG_ID, 0xAA); + usleep_range(3000, 3500); + return 0; +} + +static int aw8695_haptic_active(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_WORK_MODE_MASK, + AW8695_BIT_SYSCTRL_ACTIVE); + aw8695_interrupt_clear(aw8695); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_UVLO_MASK, + AW8695_BIT_SYSINTM_UVLO_EN); + return 0; +} + +static int aw8695_haptic_play_mode(struct aw8695 *aw8695, + unsigned char play_mode) +{ + pr_debug("%s enter\n", __func__); + + switch (play_mode) { + case AW8695_HAPTIC_STANDBY_MODE: + aw8695->play_mode = AW8695_HAPTIC_STANDBY_MODE; + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_UVLO_MASK, + AW8695_BIT_SYSINTM_UVLO_OFF); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_WORK_MODE_MASK, + AW8695_BIT_SYSCTRL_STANDBY); + break; + case AW8695_HAPTIC_RAM_MODE: + aw8695->play_mode = AW8695_HAPTIC_RAM_MODE; + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8695_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BYPASS); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RAM_DISABLE); + } + aw8695_haptic_active(aw8695); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RAM_ENABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK & + AW8695_BIT_SYSCTRL_WORK_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BOOST + | AW8695_BIT_SYSCTRL_STANDBY); + aw8695_haptic_active(aw8695); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BOOST); + } + usleep_range(2000, 2500); + break; + case AW8695_HAPTIC_RAM_LOOP_MODE: + aw8695->play_mode = AW8695_HAPTIC_RAM_LOOP_MODE; + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8695_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BYPASS); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RAM_DISABLE); + } + aw8695_haptic_active(aw8695); + break; + case AW8695_HAPTIC_RTP_MODE: + aw8695->play_mode = AW8695_HAPTIC_RTP_MODE; + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8695_BIT_SYSCTRL_PLAY_MODE_RTP); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BYPASS); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RTP_DISABLE); + } + aw8695_haptic_active(aw8695); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RTP_ENABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK & + AW8695_BIT_SYSCTRL_WORK_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BOOST + | AW8695_BIT_SYSCTRL_STANDBY); + aw8695_haptic_active(aw8695); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BOOST); + } + usleep_range(2000, 2500); + break; + case AW8695_HAPTIC_TRIG_MODE: + aw8695->play_mode = AW8695_HAPTIC_TRIG_MODE; + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8695_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BYPASS); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RAM_DISABLE); + } + aw8695_haptic_active(aw8695); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RAM_ENABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK & + AW8695_BIT_SYSCTRL_WORK_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BOOST + | AW8695_BIT_SYSCTRL_STANDBY); + aw8695_haptic_active(aw8695); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BOOST); + } + usleep_range(2000, 2500); + break; + case AW8695_HAPTIC_CONT_MODE: + aw8695->play_mode = AW8695_HAPTIC_CONT_MODE; + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8695_BIT_SYSCTRL_PLAY_MODE_CONT); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BYPASS); + if (aw8695->auto_boost) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_RAM_MASK, + AW8695_BIT_BST_AUTO_BST_RAM_DISABLE); + } + aw8695_haptic_active(aw8695); + break; + default: + dev_err(aw8695->dev, "%s: play mode %d err", + __func__, play_mode); + break; + } + return 0; +} + +static int aw8695_haptic_juge_RTP_is_going_on(struct aw8695 *aw8695) +{ + unsigned char reg_val = 0; + unsigned char rtp_state = 0; + static unsigned char pre_reg_val; + + aw8695_i2c_read(aw8695, AW8695_REG_SYSCTRL, ®_val); + if ((reg_val & AW8695_BIT_SYSCTRL_PLAY_MODE_RTP) + && (!(reg_val & AW8695_BIT_SYSCTRL_STANDBY))) + rtp_state = 1; /*is going on */ + if (pre_reg_val != reg_val) + aw_dbg_info("%sAW8695_REG_SYSCTRL 0x04==%02x rtp_state=%d\n", + __func__, reg_val, rtp_state); + pre_reg_val = reg_val; + if (aw8695->rtp_routine_on) { + aw_dbg_info("%s:rtp_routine_on\n", __func__); + rtp_state = 1; /*is going on */ + } + return rtp_state; +} + +static int aw8695_haptic_play_go(struct aw8695 *aw8695, bool flag) +{ + pr_debug("%s enter, flag = %d\n", __func__, flag); + if (flag) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_GO, + AW8695_BIT_GO_MASK, AW8695_BIT_GO_ENABLE); + do_gettimeofday(&aw8695->pre_enter_time); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_GO, + AW8695_BIT_GO_MASK, + AW8695_BIT_GO_DISABLE); + do_gettimeofday(&aw8695->current_time); + + aw8695->interval_us = (aw8695->current_time.tv_sec - aw8695->pre_enter_time.tv_sec) * 1000000 + + + (aw8695->current_time.tv_usec-aw8695->pre_enter_time.tv_usec); + + if (aw8695->interval_us < 2000) { + + pr_info("aw8695->interval_us t=%d\n", aw8695->interval_us); + + mdelay(2); + } + } + return 0; +} + +static int aw8695_haptic_stop_delay(struct aw8695 *aw8695) +{ + unsigned char reg_val = 0; + unsigned int cnt = 100; + + while (cnt--) { + aw8695_i2c_read(aw8695, AW8695_REG_GLB_STATE, ®_val); + if ((reg_val & 0x0f) == 0x00) + return 0; + usleep_range(2000, 2500); + pr_debug("%s wait for standby, reg glb_state=0x%02x\n", + __func__, reg_val); + } + pr_err("%s do not enter standby automatically\n", __func__); + + return 0; +} + +static int aw8695_haptic_stop(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + aw8695_haptic_play_go(aw8695, false); + aw8695_haptic_stop_delay(aw8695); + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE); + + return 0; +} + +static int aw8695_haptic_start(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + aw8695_haptic_play_go(aw8695, true); + + return 0; +} + +static int aw8695_haptic_set_wav_seq(struct aw8695 *aw8695, + unsigned char wav, unsigned char seq) +{ + aw8695_i2c_write(aw8695, AW8695_REG_WAVSEQ1 + wav, seq); + return 0; +} + +static int aw8695_haptic_set_wav_loop(struct aw8695 *aw8695, + unsigned char wav, unsigned char loop) +{ + unsigned char tmp = 0; + + if (wav % 2) { + tmp = loop << 0; + aw8695_i2c_write_bits(aw8695, AW8695_REG_WAVLOOP1 + (wav / 2), + AW8695_BIT_WAVLOOP_SEQNP1_MASK, tmp); + } else { + tmp = loop << 4; + aw8695_i2c_write_bits(aw8695, AW8695_REG_WAVLOOP1 + (wav / 2), + AW8695_BIT_WAVLOOP_SEQN_MASK, tmp); + } + + return 0; +} + +/* +static int aw8695_haptic_set_main_loop(struct aw8695 *aw8695, + unsigned char loop) +{ + aw8695_i2c_write(aw8695, AW8695_REG_MAIN_LOOP, loop); + return 0; +} +*/ + +static int aw8695_haptic_set_repeat_wav_seq(struct aw8695 *aw8695, + unsigned char seq) +{ + aw8695_haptic_set_wav_seq(aw8695, 0x00, seq); + aw8695_haptic_set_wav_loop(aw8695, 0x00, + AW8695_BIT_WAVLOOP_INIFINITELY); + + return 0; +} + +static int aw8695_haptic_set_bst_vol(struct aw8695 *aw8695, + unsigned char bst_vol) +{ + if (bst_vol & 0xe0) + bst_vol = 0x1f; + aw8695_i2c_write_bits(aw8695, AW8695_REG_BSTDBG4, + AW8695_BIT_BSTDBG4_BSTVOL_MASK, (bst_vol << 1)); + return 0; +} + +static int aw8695_haptic_set_bst_peak_cur(struct aw8695 *aw8695, + unsigned char peak_cur) +{ + peak_cur &= AW8695_BSTCFG_PEAKCUR_LIMIT; + aw8695_i2c_write_bits(aw8695, AW8695_REG_BSTCFG, + AW8695_BIT_BSTCFG_PEAKCUR_MASK, peak_cur); + return 0; +} + +static int aw8695_haptic_set_gain(struct aw8695 *aw8695, unsigned char gain) +{ + aw8695_i2c_write(aw8695, AW8695_REG_DATDBG, gain); + return 0; +} + +static int aw8695_haptic_set_pwm(struct aw8695 *aw8695, unsigned char mode) +{ + switch (mode) { + case AW8695_PWM_48K: + aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG, + AW8695_BIT_PWMDBG_PWM_MODE_MASK, + AW8695_BIT_PWMDBG_PWM_48K); + break; + case AW8695_PWM_24K: + aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG, + AW8695_BIT_PWMDBG_PWM_MODE_MASK, + AW8695_BIT_PWMDBG_PWM_24K); + break; + case AW8695_PWM_12K: + aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMDBG, + AW8695_BIT_PWMDBG_PWM_MODE_MASK, + AW8695_BIT_PWMDBG_PWM_12K); + break; + default: + break; + } + return 0; +} + +static int aw8695_haptic_play_wav_seq(struct aw8695 *aw8695, unsigned char flag) +{ + pr_debug("%s enter\n", __func__); + + if (flag) { + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE); + aw8695_haptic_start(aw8695); + } + return 0; +} + +static int aw8695_haptic_play_repeat_seq(struct aw8695 *aw8695, + unsigned char flag) +{ + pr_debug("%s enter\n", __func__); + + if (flag) { + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_LOOP_MODE); + aw8695_haptic_start(aw8695); + } + + return 0; +} + +/***************************************************** + * + * motor protect + * + *****************************************************/ +static int aw8695_haptic_swicth_motorprotect_config(struct aw8695 *aw8695, + unsigned char addr, + unsigned char val) +{ + pr_debug("%s enter\n", __func__); + if (addr == 1) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL, + AW8695_BIT_DETCTRL_PROTECT_MASK, + AW8695_BIT_DETCTRL_PROTECT_SHUTDOWN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC, + AW8695_BIT_PWMPRC_PRC_MASK, + AW8695_BIT_PWMPRC_PRC_ENABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL, + AW8695_BIT_PRLVL_PR_MASK, + AW8695_BIT_PRLVL_PR_ENABLE); + } else if (addr == 0) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL, + AW8695_BIT_DETCTRL_PROTECT_MASK, + AW8695_BIT_DETCTRL_PROTECT_NO_ACTION); + aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC, + AW8695_BIT_PWMPRC_PRC_MASK, + AW8695_BIT_PWMPRC_PRC_DISABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL, + AW8695_BIT_PRLVL_PR_MASK, + AW8695_BIT_PRLVL_PR_DISABLE); + } else if (addr == 0x2d) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_PWMPRC, + AW8695_BIT_PWMPRC_PRCTIME_MASK, val); + } else if (addr == 0x3e) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_PRLVL, + AW8695_BIT_PRLVL_PRLVL_MASK, val); + } else if (addr == 0x3f) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_PRTIME, + AW8695_BIT_PRTIME_PRTIME_MASK, val); + } else { + /*nothing to do; */ + } + return 0; +} + +/***************************************************** + * + * offset calibration + * + *****************************************************/ +static int aw8695_haptic_offset_calibration(struct aw8695 *aw8695) +{ + unsigned int cont = 2000; + unsigned char reg_val = 0; + + pr_debug("%s enter\n", __func__); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL, + AW8695_BIT_DETCTRL_DIAG_GO_MASK, + AW8695_BIT_DETCTRL_DIAG_GO_ENABLE); + while (1) { + aw8695_i2c_read(aw8695, AW8695_REG_DETCTRL, ®_val); + if ((reg_val & 0x01) == 0 || cont == 0) + break; + cont--; + } + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_OFF); + + return 0; +} + +/***************************************************** + * + * trig config + * + *****************************************************/ +static int aw8695_haptic_trig_param_init(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + aw8695->trig[0].enable = AW8695_TRG1_ENABLE; + aw8695->trig[0].default_level = AW8695_TRG1_DEFAULT_LEVEL; + aw8695->trig[0].dual_edge = AW8695_TRG1_DUAL_EDGE; + aw8695->trig[0].frist_seq = AW8695_TRG1_FIRST_EDGE_SEQ; + aw8695->trig[0].second_seq = AW8695_TRG1_SECOND_EDGE_SEQ; + + aw8695->trig[1].enable = AW8695_TRG2_ENABLE; + aw8695->trig[1].default_level = AW8695_TRG2_DEFAULT_LEVEL; + aw8695->trig[1].dual_edge = AW8695_TRG2_DUAL_EDGE; + aw8695->trig[1].frist_seq = AW8695_TRG2_FIRST_EDGE_SEQ; + aw8695->trig[1].second_seq = AW8695_TRG2_SECOND_EDGE_SEQ; + + aw8695->trig[2].enable = AW8695_TRG3_ENABLE; + aw8695->trig[2].default_level = AW8695_TRG3_DEFAULT_LEVEL; + aw8695->trig[2].dual_edge = AW8695_TRG3_DUAL_EDGE; + aw8695->trig[2].frist_seq = AW8695_TRG3_FIRST_EDGE_SEQ; + aw8695->trig[2].second_seq = AW8695_TRG3_SECOND_EDGE_SEQ; + + return 0; +} + +static int aw8695_haptic_trig_param_config(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + if (aw8695->trig[0].default_level) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG1_POLAR_MASK, + AW8695_BIT_TRGCFG1_TRG1_POLAR_NEG); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG1_POLAR_MASK, + AW8695_BIT_TRGCFG1_TRG1_POLAR_POS); + } + if (aw8695->trig[1].default_level) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG2_POLAR_MASK, + AW8695_BIT_TRGCFG1_TRG2_POLAR_NEG); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG2_POLAR_MASK, + AW8695_BIT_TRGCFG1_TRG2_POLAR_POS); + } + if (aw8695->trig[2].default_level) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG3_POLAR_MASK, + AW8695_BIT_TRGCFG1_TRG3_POLAR_NEG); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG3_POLAR_MASK, + AW8695_BIT_TRGCFG1_TRG3_POLAR_POS); + } + + if (aw8695->trig[0].dual_edge) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG1_EDGE_MASK, + AW8695_BIT_TRGCFG1_TRG1_EDGE_POS_NEG); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG1_EDGE_MASK, + AW8695_BIT_TRGCFG1_TRG1_EDGE_POS); + } + if (aw8695->trig[1].dual_edge) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG2_EDGE_MASK, + AW8695_BIT_TRGCFG1_TRG2_EDGE_POS_NEG); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG2_EDGE_MASK, + AW8695_BIT_TRGCFG1_TRG2_EDGE_POS); + } + if (aw8695->trig[2].dual_edge) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG3_EDGE_MASK, + AW8695_BIT_TRGCFG1_TRG3_EDGE_POS_NEG); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG1, + AW8695_BIT_TRGCFG1_TRG3_EDGE_MASK, + AW8695_BIT_TRGCFG1_TRG3_EDGE_POS); + } + + if (aw8695->trig[0].frist_seq) { + aw8695_i2c_write(aw8695, AW8695_REG_TRG1_WAV_P, + aw8695->trig[0].frist_seq); + } + if (aw8695->trig[0].second_seq && aw8695->trig[0].dual_edge) { + aw8695_i2c_write(aw8695, AW8695_REG_TRG1_WAV_N, + aw8695->trig[0].second_seq); + } + if (aw8695->trig[1].frist_seq) { + aw8695_i2c_write(aw8695, AW8695_REG_TRG2_WAV_P, + aw8695->trig[1].frist_seq); + } + if (aw8695->trig[1].second_seq && aw8695->trig[1].dual_edge) { + aw8695_i2c_write(aw8695, AW8695_REG_TRG2_WAV_N, + aw8695->trig[1].second_seq); + } + if (aw8695->trig[2].frist_seq) { + aw8695_i2c_write(aw8695, AW8695_REG_TRG3_WAV_P, + aw8695->trig[1].frist_seq); + } + if (aw8695->trig[2].second_seq && aw8695->trig[2].dual_edge) { + aw8695_i2c_write(aw8695, AW8695_REG_TRG3_WAV_N, + aw8695->trig[1].second_seq); + } + + return 0; +} + +static int aw8695_haptic_trig_enable_config(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2, + AW8695_BIT_TRGCFG2_TRG1_ENABLE_MASK, + aw8695->trig[0].enable << 0); + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2, + AW8695_BIT_TRGCFG2_TRG2_ENABLE_MASK, + aw8695->trig[1].enable << 1); + aw8695_i2c_write_bits(aw8695, AW8695_REG_TRG_CFG2, + AW8695_BIT_TRGCFG2_TRG3_ENABLE_MASK, + aw8695->trig[2].enable << 2); + + return 0; +} + +static int aw8695_haptic_auto_boost_config(struct aw8695 *aw8695, + unsigned char flag) +{ + aw8695->auto_boost = flag; + if (flag) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_AUTOSW_MASK, + AW8695_BIT_BST_AUTO_BST_AUTOMATIC_BOOST); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_BST_AUTO, + AW8695_BIT_BST_AUTO_BST_AUTOSW_MASK, + AW8695_BIT_BST_AUTO_BST_MANUAL_BOOST); + } + return 0; +} + +/***************************************************** + * + * vbat mode + * + *****************************************************/ +static int aw8695_haptic_cont_vbat_mode(struct aw8695 *aw8695, + unsigned char flag) +{ + if (flag == AW8695_HAPTIC_CONT_VBAT_HW_COMP_MODE) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_ADCTEST, + AW8695_BIT_ADCTEST_VBAT_MODE_MASK, + AW8695_BIT_ADCTEST_VBAT_HW_COMP); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_ADCTEST, + AW8695_BIT_ADCTEST_VBAT_MODE_MASK, + AW8695_BIT_ADCTEST_VBAT_SW_COMP); + } + return 0; +} + +static int aw8695_haptic_get_vbat(struct aw8695 *aw8695) +{ + unsigned char reg_val = 0; + unsigned int cont = 2000; + + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL, + AW8695_BIT_DETCTRL_VBAT_GO_MASK, + AW8695_BIT_DETCTRL_VABT_GO_ENABLE); + + while (1) { + aw8695_i2c_read(aw8695, AW8695_REG_DETCTRL, ®_val); + if ((reg_val & 0x02) == 0 || cont == 0) + break; + cont--; + } + + aw8695_i2c_read(aw8695, AW8695_REG_VBATDET, ®_val); + aw8695->vbat = 6100 * reg_val / 256; + if (aw8695->vbat > AW8695_VBAT_MAX) { + aw8695->vbat = AW8695_VBAT_MAX; + pr_debug("%s vbat max limit = %dmV\n", __func__, aw8695->vbat); + } + if (aw8695->vbat < AW8695_VBAT_MIN) { + aw8695->vbat = AW8695_VBAT_MIN; + pr_debug("%s vbat min limit = %dmV\n", __func__, aw8695->vbat); + } + + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_OFF); + + return 0; +} + +static int aw8695_haptic_ram_vbat_comp(struct aw8695 *aw8695, bool flag) +{ + int temp_gain = 0; + + if (flag) { + if (aw8695->ram_vbat_comp == AW8695_HAPTIC_RAM_VBAT_COMP_ENABLE) { + aw8695_haptic_get_vbat(aw8695); + temp_gain = + aw8695->gain * AW8695_VBAT_REFER / aw8695->vbat; + if (temp_gain > + (128 * AW8695_VBAT_REFER / AW8695_VBAT_MIN)) { + temp_gain = + 128 * AW8695_VBAT_REFER / AW8695_VBAT_MIN; + pr_debug("%s gain limit=%d\n", __func__, + temp_gain); + } + aw8695_haptic_set_gain(aw8695, temp_gain); + } else { + aw8695_haptic_set_gain(aw8695, aw8695->gain); + } + } else { + aw8695_haptic_set_gain(aw8695, aw8695->gain); + } + + return 0; +} + +/***************************************************** + * + * f0 + * + *****************************************************/ +static int aw8695_haptic_set_f0_preset(struct aw8695 *aw8695) +{ + unsigned int f0_reg = 0; + + pr_debug("%s enter\n", __func__); + + f0_reg = 1000000000 / (aw8695->info.f0_pre * aw8695->info.f0_coeff); + aw8695_i2c_write(aw8695, AW8695_REG_F_PRE_H, + (unsigned char)((f0_reg >> 8) & 0xff)); + aw8695_i2c_write(aw8695, AW8695_REG_F_PRE_L, + (unsigned char)((f0_reg >> 0) & 0xff)); + + return 0; +} + +static int aw8695_haptic_read_f0(struct aw8695 *aw8695) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + pr_debug("%s enter\n", __func__); + + ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_F0_H, ®_val); + f0_reg = (reg_val << 8); + ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_F0_L, ®_val); + f0_reg |= (reg_val << 0); + if (!f0_reg) { + pr_info("%s not get f0 because f0_reg value is 0!\n", __func__); + return 0; + } + f0_tmp = 1000000000 / (f0_reg * aw8695->info.f0_coeff); + aw8695->f0 = (unsigned int)f0_tmp; + pr_info("%s f0=%d\n", __func__, aw8695->f0); + + return 0; +} + +static int aw8695_haptic_read_cont_f0(struct aw8695 *aw8695) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + pr_debug("%s enter\n", __func__); + + ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_CONT_H, ®_val); + f0_reg = (reg_val << 8); + ret = aw8695_i2c_read(aw8695, AW8695_REG_F_LRA_CONT_L, ®_val); + f0_reg |= (reg_val << 0); + f0_tmp = 1000000000 / (f0_reg * aw8695->info.f0_coeff); + aw8695->cont_f0 = (unsigned int)f0_tmp; + pr_info("%s f0=%d\n", __func__, aw8695->cont_f0); + + return 0; +} + +static int aw8695_haptic_read_beme(struct aw8695 *aw8695) +{ + int ret = 0; + unsigned char reg_val = 0; + + ret = aw8695_i2c_read(aw8695, AW8695_REG_WAIT_VOL_MP, ®_val); + aw8695->max_pos_beme = (reg_val << 0); + ret = aw8695_i2c_read(aw8695, AW8695_REG_WAIT_VOL_MN, ®_val); + aw8695->max_neg_beme = (reg_val << 0); + + pr_info("%s max_pos_beme=%d\n", __func__, aw8695->max_pos_beme); + pr_info("%s max_neg_beme=%d\n", __func__, aw8695->max_neg_beme); + + return 0; +} + +static int aw8695_haptic_ram_config(struct aw8695 *aw8695) +{ + unsigned char wavloop = 0; + pr_info("%s duration =%d\n", __func__, aw8695->duration); + + if ((aw8695->duration >0 ) && (aw8695->duration <= 50)){//index 3 0~20ms + aw8695->index = 1; + + } else {//index 4 >60ms + aw8695->index = 2; + wavloop = 15; + } + + pr_info("%s wave index =%d\n", __func__, aw8695->index); + aw8695_haptic_set_wav_seq(aw8695, 0, aw8695->index); + aw8695_haptic_set_wav_loop(aw8695, 0, wavloop); + aw8695_haptic_set_wav_seq(aw8695, 1, 0); + aw8695_haptic_set_wav_loop(aw8695, 1, 0); + + return 0; +} + +/***************************************************** + * + * rtp + * + *****************************************************/ +static void aw8695_haptic_set_rtp_aei(struct aw8695 *aw8695, bool flag) +{ + if (flag) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_FF_AE_MASK, + AW8695_BIT_SYSINTM_FF_AE_EN); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_FF_AE_MASK, + AW8695_BIT_SYSINTM_FF_AE_OFF); + } +} + +/* +static void aw8695_haptic_set_rtp_afi(struct aw8695 *aw8695, bool flag) +{ + if(flag) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_FF_AF_MASK, AW8695_BIT_SYSINTM_FF_AF_EN); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_FF_AF_MASK, AW8695_BIT_SYSINTM_FF_AF_OFF); + } +} +*/ + +/* +static unsigned char aw8695_haptic_rtp_get_fifo_aei(struct aw8695 *aw8695) +{ + unsigned char ret; + unsigned char reg_val; + + aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val); + reg_val &= AW8695_BIT_SYSINT_FF_AEI; + ret = reg_val>>4; + + return ret; +} +*/ + +/* +static unsigned char aw8695_haptic_rtp_get_fifo_aes(struct aw8695 *aw8695) +{ + unsigned char ret; + unsigned char reg_val; + + aw8695_i2c_read(aw8695, AW8695_REG_SYSST, ®_val); + reg_val &= AW8695_BIT_SYSST_FF_AES; + ret = reg_val>>4; + + return ret; +} +*/ + +static unsigned char aw8695_haptic_rtp_get_fifo_afi(struct aw8695 *aw8695) +{ + unsigned char ret = 0; + unsigned char reg_val = 0; + + if (aw8695->osc_cali_flag == 1) { + aw8695_i2c_read(aw8695, AW8695_REG_SYSST, ®_val); + reg_val &= AW8695_BIT_SYSST_FF_AES; + ret = reg_val >> 3; + } else { + aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val); + reg_val &= AW8695_BIT_SYSINT_FF_AFI; + ret = reg_val >> 3; + } + return ret; +} + +/* +static unsigned char aw8695_haptic_rtp_get_fifo_afs(struct aw8695 *aw8695) +{ + unsigned char ret = 0; + unsigned char reg_val = 0; + + aw8695_i2c_read(aw8695, AW8695_REG_SYSST, ®_val); + reg_val &= AW8695_BIT_SYSST_FF_AFS; + ret = reg_val>>3; + + return ret; +} +*/ + +/***************************************************** + * + * rtp + * + *****************************************************/ +static int aw8695_haptic_rtp_init(struct aw8695 *aw8695) +{ + unsigned int buf_len = 0; + unsigned char glb_state_val = 0; + + //Daniel 20201105 modify start + pr_info("%s enter\n", __func__); + pm_qos_add_request(&pm_qos_req_vb, PM_QOS_CPU_DMA_LATENCY, PM_QOS_VALUE_VB); + aw8695->rtp_cnt = 0; + mutex_lock(&aw8695->rtp_lock); + while ((!aw8695_haptic_rtp_get_fifo_afi(aw8695)) && + (aw8695->play_mode == AW8695_HAPTIC_RTP_MODE)) { + pr_info("%s rtp cnt = %d\n", __func__, aw8695->rtp_cnt); + if (!aw8695_rtp) { + pr_info("%s:aw8695_rtp is null break\n", __func__); + break; + } + + + if ((aw8695->rtp_cnt < aw8695->ram.base_addr)) { + if((aw8695_rtp->len-aw8695->rtp_cnt) < (aw8695->ram.base_addr)) { + buf_len = aw8695_rtp->len-aw8695->rtp_cnt; + } else { + buf_len = (aw8695->ram.base_addr); + } + } else if ((aw8695_rtp->len - aw8695->rtp_cnt) < (aw8695->ram.base_addr >> 2)) { + buf_len = aw8695_rtp->len - aw8695->rtp_cnt; + } else { + buf_len = (aw8695->ram.base_addr >> 2); + } + pr_info("%s buf_len = %d\n", __func__, buf_len); + aw8695_i2c_writes(aw8695, AW8695_REG_RTP_DATA, + &aw8695_rtp->data[aw8695->rtp_cnt], + buf_len); + + aw8695->rtp_cnt += buf_len; + aw8695_i2c_read(aw8695, AW8695_REG_GLB_STATE, &glb_state_val); + if ((aw8695->rtp_cnt == aw8695_rtp->len) || ((glb_state_val & 0x0f) == 0x00)) { + pr_info("%s: rtp update complete\n", __func__); + aw8695->rtp_cnt = 0; + atomic_set(&aw8695->is_rtp, 0); + mutex_unlock(&aw8695->rtp_lock); + pm_qos_remove_request(&pm_qos_req_vb); + return 0; + } + } + mutex_unlock(&aw8695->rtp_lock); + + if (aw8695->play_mode == AW8695_HAPTIC_RTP_MODE) + aw8695_haptic_set_rtp_aei(aw8695, true); + + pr_info("%s exit\n", __func__); + pm_qos_remove_request(&pm_qos_req_vb);//Daniel 20201105 modify end + return 0; +} + +static int aw8695_rtp_trim_lra_calibration(struct aw8695 *aw8695) +{ + + unsigned int real_code = 0; + unsigned int lra_rtim_code = 0; + unsigned int cali_err_thr = 20; /* 2% */ + unsigned int cali_min_thr = 1; /* 0.1% */ + + if (aw8695->theory_time < aw8695->microsecond) { + /* diff over 2%, test data error */ + if ((aw8695->microsecond - aw8695->theory_time) > + (aw8695->theory_time * cali_err_thr / 1000)) { + return 0; + } + /* diff less 0.1%, no need to cali */ + if ((aw8695->microsecond - aw8695->theory_time) < + (aw8695->theory_time * cali_min_thr / 1000)) { + return 0; + } + real_code = + ((aw8695->microsecond - + aw8695->theory_time) * 4000) / aw8695->theory_time; + real_code = ((real_code % 10 < 5) ? 0 : 1) + real_code / 10; + real_code = 32 + real_code; + } + if (aw8695->theory_time > aw8695->microsecond) { + /* diff over 2%, test data error */ + if ((aw8695->theory_time - aw8695->microsecond) > + (aw8695->theory_time * cali_err_thr / 1000)) { + return 0; + } + /* diff less 0.1%, no need to cali */ + if ((aw8695->theory_time - aw8695->microsecond) < + (aw8695->theory_time * cali_min_thr / 1000)) { + return 0; + } + real_code = + ((aw8695->theory_time - + aw8695->microsecond) * 4000) / aw8695->theory_time; + real_code = ((real_code % 10 < 5) ? 0 : 1) + real_code / 10; + real_code = 32 - real_code; + } + pr_debug("%s microsecond=%ld, aw8695->theory_time=%d, real_code=%d\n", + __func__, aw8695->microsecond, aw8695->theory_time, real_code); + + lra_rtim_code = real_code > 31 ? (real_code - 32) : (real_code + 32); + pr_info("%s lra_rtim_code = %d\n", __func__, lra_rtim_code); + if (lra_rtim_code > 0) { + aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, + (char)lra_rtim_code); + } + return 0; +} + +static unsigned char aw8695_haptic_osc_read_int(struct aw8695 *aw8695) +{ + unsigned char reg_val = 0; + + aw8695_i2c_read(aw8695, AW8695_REG_DBGSTAT, ®_val); + return reg_val; +} + +static int aw8695_rtp_osc_calibration(struct aw8695 *aw8695) +{ + const struct firmware *rtp_file; + int ret = -1; + unsigned int buf_len = 0; + unsigned char osc_int_state = 0; + unsigned char reg_val = 0; + unsigned int fre_val = 0; + + aw8695->rtp_cnt = 0; + aw8695->timeval_flags = 1; + aw8695->osc_cali_flag = 1; + + pr_info("%s enter\n", __func__); + /* fw loaded */ + ret = request_firmware(&rtp_file, + aw8695_rtp_name[0],/*aw8695->rtp_file_num */ + aw8695->dev); + if (ret < 0) { + pr_err("%s: failed to read %s\n", __func__, + aw8695_rtp_name[0]);/*aw8695->rtp_file_num */ + return ret; + } + + aw8695_haptic_stop(aw8695); + aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, 0x00); + aw8695->rtp_init = 0; + mutex_lock(&aw8695->rtp_lock); + vfree(aw8695_rtp); + aw8695_rtp = vmalloc(rtp_file->size + sizeof(int)); + if (!aw8695_rtp) { + release_firmware(rtp_file); + mutex_unlock(&aw8695->rtp_lock); + pr_err("%s: error allocating memory\n", __func__); + return -1; + } + aw8695_rtp->len = rtp_file->size; + aw8695->rtp_len = rtp_file->size; + pr_info("%s: rtp file [%s] size = %d\n", __func__, + aw8695_rtp_name[0], aw8695_rtp->len);/*aw8695->rtp_file_num */ + memcpy(aw8695_rtp->data, rtp_file->data, rtp_file->size); + release_firmware(rtp_file); + mutex_unlock(&aw8695->rtp_lock); + + /* gain */ + aw8695_haptic_ram_vbat_comp(aw8695, false); + + /* rtp mode config */ + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RTP_MODE); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_DBGCTRL, + AW8695_BIT_DBGCTRL_INT_MODE_MASK, + AW8695_BIT_DBGCTRL_INT_MODE_EDGE); + disable_irq(gpio_to_irq(aw8695->irq_gpio)); + /* haptic start */ + aw8695_haptic_start(aw8695); + //Daniel 20201105 modify start + pm_qos_add_request(&pm_qos_req_vb, PM_QOS_CPU_DMA_LATENCY, PM_QOS_VALUE_VB); + aw8695_i2c_read(aw8695, AW8695_REG_PWMDBG, ®_val); + fre_val = (reg_val & 0x006f) >> 5; + + if (fre_val == 3) + /*12K */ + aw8695->theory_time = (aw8695->rtp_len / 12000) * 1000000; + else if (fre_val == 2) + /*24K */ + aw8695->theory_time = (aw8695->rtp_len / 24000) * 1000000; + else if (fre_val == 1 || fre_val == 0) + /*48K */ + aw8695->theory_time = (aw8695->rtp_len / 48000) * 1000000; + pr_info("%s aw8695->theory_time = %d\n", __func__, aw8695->theory_time); + + while (1) { + if (!aw8695_haptic_rtp_get_fifo_afi(aw8695)) { + /* pr_info("%s !aw8695_haptic_rtp_get_fifo_afi done aw8695->rtp_cnt= %d\n", __func__,aw8695->rtp_cnt); */ + mutex_lock(&aw8695->rtp_lock); + if ((aw8695_rtp->len - aw8695->rtp_cnt) < + (aw8695->ram.base_addr >> 2)) + buf_len = aw8695_rtp->len - aw8695->rtp_cnt; + else + buf_len = (aw8695->ram.base_addr >> 2); + + if (aw8695->rtp_cnt != aw8695_rtp->len) { + if (aw8695->timeval_flags == 1) { + do_gettimeofday(&aw8695->start); + aw8695->timeval_flags = 0; + } + aw8695->rtpupdate_flag = + aw8695_i2c_writes(aw8695, + AW8695_REG_RTP_DATA, + &aw8695_rtp->data[aw8695-> + rtp_cnt], buf_len); + aw8695->rtp_cnt += buf_len; + } + mutex_unlock(&aw8695->rtp_lock); + } + + osc_int_state = aw8695_haptic_osc_read_int(aw8695); + /* if(osc_int_state&AW8695_BIT_SYSINT_DONEI) { */ + if (aw8695->rtp_cnt == aw8695_rtp->len) { + do_gettimeofday(&aw8695->end); + pr_info("%s playback done aw8695->rtp_cnt= %d\n", + __func__, aw8695->rtp_cnt); + break; + } else { + do_gettimeofday(&aw8695->end); + } + + aw8695->microsecond = + (aw8695->end.tv_sec - aw8695->start.tv_sec) * 1000000 + + (aw8695->end.tv_usec - aw8695->start.tv_usec); + if (aw8695->microsecond > + (aw8695->theory_time + (aw8695->theory_time / 20))) { + pr_info + ("%s over time out aw8695->rtp_cnt %d osc_int_state %02x\n", + __func__, aw8695->rtp_cnt, osc_int_state); + break; + } + } + pm_qos_remove_request(&pm_qos_req_vb); + enable_irq(gpio_to_irq(aw8695->irq_gpio)); + + aw8695->osc_cali_flag = 0; + aw8695->microsecond = + (aw8695->end.tv_sec - aw8695->start.tv_sec) * 1000000 + + (aw8695->end.tv_usec - aw8695->start.tv_usec); + /*calibration osc */ + pr_info("%s awinic_microsecond:%ld\n", __func__, aw8695->microsecond); + pr_info("%s exit\n", __func__); + + return 0; +} + +static void aw8695_op_clean_status(struct aw8695 *aw8695) +{ + aw8695->audio_ready = false; + aw8695->haptic_ready = false; + aw8695->pre_haptic_number = false; + aw8695->rtp_routine_on = 0; + pr_info("%s enter\n", __func__); +} + +static void aw8695_rtp_work_routine(struct work_struct *work) +{ + const struct firmware *rtp_file; + int ret = -1; + struct aw8695 *aw8695 = container_of(work, struct aw8695, rtp_work); + + pr_info("%s enter\n", __func__); + aw8695->rtp_routine_on = 1; + /* fw loaded */ + ret = request_firmware(&rtp_file, + aw8695_rtp_name[aw8695->rtp_file_num], + aw8695->dev); + if (ret < 0) { + pr_err("%s: failed to read %s\n", __func__, + aw8695_rtp_name[aw8695->rtp_file_num]); + aw8695->rtp_routine_on = 0; + return; + } + aw8695->rtp_init = 0; + mutex_lock(&aw8695->rtp_lock); + vfree(aw8695_rtp); + aw8695_rtp = vmalloc(rtp_file->size + sizeof(int)); + if (!aw8695_rtp) { + release_firmware(rtp_file); + pr_err("%s: error allocating memory\n", __func__); + aw8695_op_clean_status(aw8695); + aw8695->rtp_routine_on = 0; + mutex_unlock(&aw8695->rtp_lock); + return; + } + aw8695_rtp->len = rtp_file->size; + pr_info("%s: rtp file [%s] size = %d\n", __func__, + aw8695_rtp_name[aw8695->rtp_file_num], aw8695_rtp->len); + memcpy(aw8695_rtp->data, rtp_file->data, rtp_file->size); + mutex_unlock(&aw8695->rtp_lock); + release_firmware(rtp_file); + + mutex_lock(&aw8695->lock); + aw8695->rtp_init = 1; + atomic_set(&aw8695->is_rtp, 1); + /* gain */ + aw8695_haptic_ram_vbat_comp(aw8695, false); + + /* rtp mode config */ + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RTP_MODE); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_DBGCTRL, + AW8695_BIT_DBGCTRL_INT_MODE_MASK, + AW8695_BIT_DBGCTRL_INT_MODE_EDGE); + /* haptic start */ + aw8695_haptic_start(aw8695); + aw8695_haptic_rtp_init(aw8695); + aw8695_op_clean_status(aw8695); + mutex_unlock(&aw8695->lock); + aw8695->rtp_routine_on = 0; +} + +/***************************************************** + * + * haptic - audio + * + *****************************************************/ +static int aw8695_haptic_audio_ctr_list_insert(struct haptic_audio + *haptic_audio, + struct haptic_ctr *haptic_ctr) +{ + struct haptic_ctr *p_new = NULL; + + p_new = + (struct haptic_ctr *)kzalloc(sizeof(struct haptic_ctr), GFP_KERNEL); + if (p_new == NULL) { + pr_err("%s: kzalloc memory fail\n", __func__); + return -1; + } + /* update new list info */ + p_new->cnt = haptic_ctr->cnt; + p_new->cmd = haptic_ctr->cmd; + p_new->play = haptic_ctr->play; + p_new->wavseq = haptic_ctr->wavseq; + p_new->loop = haptic_ctr->loop; + p_new->gain = haptic_ctr->gain; + + INIT_LIST_HEAD(&(p_new->list)); + list_add(&(p_new->list), &(haptic_audio->ctr_list)); + + return 0; +} + +static int aw8695_haptic_audio_ctr_list_clear(struct haptic_audio *haptic_audio) +{ + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + list_del(&p_ctr->list); + kfree(p_ctr); + } + + return 0; +} + +static int aw8695_haptic_audio_init(struct aw8695 *aw8695) +{ + + /* pr_debug("%s enter\n", __func__); */ + + aw8695_haptic_set_wav_seq(aw8695, 0x01, 0x00); + /* aw8695->haptic_audio.ori_gain = reg_val & 0xFF; */ + + return 0; +} + +static int aw8695_haptic_audio_off(struct aw8695 *aw8695) +{ + pr_debug("%s enter\n", __func__); + + mutex_lock(&aw8695->lock); + aw8695_haptic_set_gain(aw8695, 0x80); + aw8695_haptic_stop(aw8695); + mutex_unlock(&aw8695->lock); + aw8695->gun_type = 0xff; + aw8695->bullet_nr =0; + aw8695->gun_mode =0; + aw8695_haptic_audio_ctr_list_clear(&aw8695->haptic_audio); + + return 0; +} + +static enum hrtimer_restart aw8695_haptic_audio_timer_func(struct hrtimer + *timer) +{ + struct aw8695 *aw8695 = + container_of(timer, struct aw8695, haptic_audio.timer); + + pr_debug("%s enter\n", __func__); + schedule_work(&aw8695->haptic_audio.work); + + hrtimer_start(&aw8695->haptic_audio.timer, + ktime_set(aw8695->haptic_audio.timer_val / 1000000, + (aw8695->haptic_audio.timer_val % 1000000) * + 1000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +static void aw8695_haptic_audio_work_routine(struct work_struct *work) +{ + struct aw8695 *aw8695 = + container_of(work, struct aw8695, haptic_audio.work); + struct haptic_audio *haptic_audio = NULL; + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + unsigned int ctr_list_flag = 0; + unsigned int ctr_list_input_cnt = 0; + unsigned int ctr_list_output_cnt = 0; + unsigned int ctr_list_diff_cnt = 0; + unsigned int ctr_list_del_cnt = 0; + + int rtp_is_going_on = 0; + + aw_dbg_info("%s enter\n", __func__); + + haptic_audio = &(aw8695->haptic_audio); + mutex_lock(&aw8695->haptic_audio.lock); + memset(&aw8695->haptic_audio.ctr, 0, sizeof(struct haptic_ctr)); + ctr_list_flag = 0; + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + ctr_list_flag = 1; + break; + } + if (ctr_list_flag == 0) + aw_dbg_info("%s: ctr list empty\n", __func__); + if (ctr_list_flag == 1) { + list_for_each_entry_safe(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + ctr_list_input_cnt = p_ctr->cnt; + break; + } + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), + list) { + ctr_list_output_cnt = p_ctr->cnt; + break; + } + if (ctr_list_input_cnt > ctr_list_output_cnt) { + ctr_list_diff_cnt = + ctr_list_input_cnt - ctr_list_output_cnt; + } + if (ctr_list_input_cnt < ctr_list_output_cnt) { + ctr_list_diff_cnt = + 32 + ctr_list_input_cnt - ctr_list_output_cnt; + } + if (ctr_list_diff_cnt > 2) { + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio-> + ctr_list), list) { + if ((p_ctr->play == 0) + && (AW8695_HAPTIC_CMD_ENABLE == + (AW8695_HAPTIC_CMD_HAPTIC & p_ctr-> + cmd))) { + list_del(&p_ctr->list); + kfree(p_ctr); + ctr_list_del_cnt++; + } + if (ctr_list_del_cnt == ctr_list_diff_cnt) + break; + } + } + + } + + /* get the last data from list */ + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, + &(haptic_audio->ctr_list), list) { + aw8695->haptic_audio.ctr.cnt = p_ctr->cnt; + aw8695->haptic_audio.ctr.cmd = p_ctr->cmd; + aw8695->haptic_audio.ctr.play = p_ctr->play; + aw8695->haptic_audio.ctr.wavseq = p_ctr->wavseq; + aw8695->haptic_audio.ctr.loop = p_ctr->loop; + aw8695->haptic_audio.ctr.gain = p_ctr->gain; + list_del(&p_ctr->list); + kfree(p_ctr); + break; + } + if (aw8695->haptic_audio.ctr.play) { + aw_dbg_info + ("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n", + __func__, aw8695->haptic_audio.ctr.cnt, + aw8695->haptic_audio.ctr.cmd, + aw8695->haptic_audio.ctr.play, + aw8695->haptic_audio.ctr.wavseq, + aw8695->haptic_audio.ctr.loop, + aw8695->haptic_audio.ctr.gain); + } + + /* rtp mode jump */ + rtp_is_going_on = aw8695_haptic_juge_RTP_is_going_on(aw8695); + if (rtp_is_going_on) { + mutex_unlock(&aw8695->haptic_audio.lock); + return; + } + mutex_unlock(&aw8695->haptic_audio.lock); + if (aw8695->haptic_audio.ctr.cmd == AW8695_HAPTIC_CMD_ENABLE) { + if + (aw8695->haptic_audio.ctr.play == AW8695_HAPTIC_PLAY_ENABLE) { + aw_dbg_info("%s: haptic_audio_play_start\n", __func__); + mutex_lock(&aw8695->lock); + aw8695_haptic_stop(aw8695); + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_RAM_MODE); + + aw8695_haptic_set_wav_seq(aw8695, 0x00, + aw8695->haptic_audio.ctr. + wavseq); + aw8695_haptic_set_wav_seq(aw8695, 0x01, 0x00); + + aw8695_haptic_set_wav_loop(aw8695, 0x00, + aw8695->haptic_audio.ctr. + loop); + + aw8695_haptic_set_gain(aw8695, + aw8695->haptic_audio.ctr.gain); + + aw8695_haptic_start(aw8695); + mutex_unlock(&aw8695->lock); + } else if (AW8695_HAPTIC_PLAY_STOP == + aw8695->haptic_audio.ctr.play) { + mutex_lock(&aw8695->lock); + aw8695_haptic_stop(aw8695); + mutex_unlock(&aw8695->lock); + } else if (AW8695_HAPTIC_PLAY_GAIN == + aw8695->haptic_audio.ctr.play) { + mutex_lock(&aw8695->lock); + aw8695_haptic_set_gain(aw8695, + aw8695->haptic_audio.ctr.gain); + mutex_unlock(&aw8695->lock); + } + } +} + +//hch 20190917 +static ssize_t aw8695_gun_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->gun_type); +} + +static ssize_t aw8695_gun_type_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8695->lock); + aw8695->gun_type = val; + mutex_unlock(&aw8695->lock); + return count; +} + +//hch 20190917 +static ssize_t aw8695_bullet_nr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->bullet_nr); +} + +static ssize_t aw8695_bullet_nr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8695->lock); + aw8695->bullet_nr = val; + mutex_unlock(&aw8695->lock); + return count; +} + +//hch 20190917 +static ssize_t aw8695_gun_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->gun_mode); +} + +static ssize_t aw8695_gun_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8695->lock); + aw8695->gun_mode = val; + mutex_unlock(&aw8695->lock); + return count; +} + +/***************************************************** + * + * haptic cont + * + *****************************************************/ +static int aw8695_haptic_cont(struct aw8695 *aw8695) +{ + pr_info("%s enter\n", __func__); + + /* work mode */ + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_CONT_MODE); + + /* preset f0 */ + aw8695_haptic_set_f0_preset(aw8695); + + /* lpf */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL, + AW8695_BIT_DATCTRL_FC_MASK, + AW8695_BIT_DATCTRL_FC_1000HZ); + aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL, + AW8695_BIT_DATCTRL_LPF_ENABLE_MASK, + AW8695_BIT_DATCTRL_LPF_ENABLE); + + /* cont config */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_ZC_DETEC_MASK, + AW8695_BIT_CONT_CTRL_ZC_DETEC_ENABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_WAIT_PERIOD_MASK, + AW8695_BIT_CONT_CTRL_WAIT_1PERIOD); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_MODE_MASK, + AW8695_BIT_CONT_CTRL_BY_GO_SIGNAL); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, + AW8695_CONT_PLAYBACK_MODE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, + AW8695_BIT_CONT_CTRL_F0_DETECT_DISABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_O2C_MASK, + AW8695_BIT_CONT_CTRL_O2C_DISABLE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_AUTO_BRK_MASK, + AW8695_BIT_CONT_CTRL_AUTO_BRK_ENABLE); + + /* TD time */ + aw8695_i2c_write(aw8695, AW8695_REG_TD_H, + (unsigned char)(aw8695->info.cont_td >> 8)); + aw8695_i2c_write(aw8695, AW8695_REG_TD_L, + (unsigned char)(aw8695->info.cont_td >> 0)); + aw8695_i2c_write(aw8695, AW8695_REG_TSET, aw8695->info.tset); + + /* zero cross */ + aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_H, + (unsigned char)(aw8695->info.cont_zc_thr >> 8)); + aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_L, + (unsigned char)(aw8695->info.cont_zc_thr >> 0)); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_BEMF_NUM, + AW8695_BIT_BEMF_NUM_BRK_MASK, + aw8695->info.cont_num_brk); + /* 35*171us=5.985ms */ + aw8695_i2c_write(aw8695, AW8695_REG_TIME_NZC, 0x23); + /* f0 driver level */ + aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->info.cont_drv_lvl); + aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL_OV, + aw8695->info.cont_drv_lvl_ov); + + /* cont play go */ + aw8695_haptic_play_go(aw8695, true); + + return 0; +} + +/***************************************************** + * + * haptic f0 cali + * + *****************************************************/ +static int aw8695_haptic_get_f0(struct aw8695 *aw8695) +{ + int ret = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + unsigned char f0_pre_num = 0; + unsigned char f0_wait_num = 0; + unsigned char f0_repeat_num = 0; + unsigned char f0_trace_num = 0; + unsigned int t_f0_ms = 0; + unsigned int t_f0_trace_ms = 0; + unsigned int f0_cali_cnt = 50; + + pr_info("%s enter\n", __func__); + + aw8695->f0 = aw8695->info.f0_pre; + + /* f0 calibrate work mode */ + aw8695_haptic_stop(aw8695); + aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, 0x00); + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_CONT_MODE); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, + AW8695_BIT_CONT_CTRL_OPEN_PLAYBACK); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, + AW8695_BIT_CONT_CTRL_F0_DETECT_ENABLE); + + /* LPF */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL, + AW8695_BIT_DATCTRL_FC_MASK, + AW8695_BIT_DATCTRL_FC_1000HZ); + aw8695_i2c_write_bits(aw8695, AW8695_REG_DATCTRL, + AW8695_BIT_DATCTRL_LPF_ENABLE_MASK, + AW8695_BIT_DATCTRL_LPF_ENABLE); + + /* LRA OSC Source */ + if (aw8695->f0_cali_flag == AW8695_HAPTIC_CALI_F0) { + aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL, + AW8695_BIT_ANACTRL_LRA_SRC_MASK, + AW8695_BIT_ANACTRL_LRA_SRC_REG); + } else { + aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL, + AW8695_BIT_ANACTRL_LRA_SRC_MASK, + AW8695_BIT_ANACTRL_LRA_SRC_EFUSE); + } + + /* preset f0 */ + aw8695_haptic_set_f0_preset(aw8695); + + /* f0 driver level */ + aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, aw8695->info.cont_drv_lvl); + + /* f0 trace parameter */ + f0_pre_num = aw8695->info.f0_trace_parameter[0]; + f0_wait_num = aw8695->info.f0_trace_parameter[1]; + f0_repeat_num = aw8695->info.f0_trace_parameter[2]; + f0_trace_num = aw8695->info.f0_trace_parameter[3]; + aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_1, + (f0_pre_num << 4) | (f0_wait_num << 0)); + aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_2, (f0_repeat_num << 0)); + aw8695_i2c_write(aw8695, AW8695_REG_NUM_F0_3, (f0_trace_num << 0)); + + /* clear aw8695 interrupt */ + ret = aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val); + + /* play go and start f0 calibration */ + aw8695_haptic_play_go(aw8695, true); + + /* f0 trace time */ + t_f0_ms = 1000 * 10 / aw8695->info.f0_pre; + t_f0_trace_ms = + t_f0_ms * (f0_pre_num + f0_wait_num + + (f0_trace_num + f0_wait_num) * (f0_repeat_num - 1)); + usleep_range(t_f0_trace_ms * 1000, t_f0_trace_ms * 1000 + 500); + for (i = 0; i < f0_cali_cnt; i++) { + ret = aw8695_i2c_read(aw8695, AW8695_REG_GLB_STATE, ®_val); + /* f0 calibrate done */ + if ((reg_val & 0x0f) == 0x00) { + aw8695_haptic_read_f0(aw8695); + aw8695_haptic_read_beme(aw8695); + break; + } + usleep_range(10000, 10500); + pr_info("%s f0 cali sleep 10ms\n", __func__); + } + + if (i == f0_cali_cnt) + ret = -1; + else + ret = 0; + + /* restore default config */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK, + AW8695_CONT_PLAYBACK_MODE); + aw8695_i2c_write_bits(aw8695, AW8695_REG_CONT_CTRL, + AW8695_BIT_CONT_CTRL_F0_DETECT_MASK, + AW8695_BIT_CONT_CTRL_F0_DETECT_DISABLE); + + return ret; +} + +static int aw8695_haptic_f0_calibration(struct aw8695 *aw8695) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_limit = 0; + char f0_cali_lra = 0; + int f0_cali_step = 0; + + pr_info("%s enter\n", __func__); + + aw8695->f0_cali_flag = AW8695_HAPTIC_CALI_F0; + + if (aw8695_haptic_get_f0(aw8695)) { + pr_err("%s get f0 error, user defafult f0\n", __func__); + } else { + /* max and min limit */ + f0_limit = aw8695->f0; + if (aw8695->f0 * 100 < + aw8695->info.f0_pre * (100 - aw8695->info.f0_cali_percen)) { + f0_limit = aw8695->info.f0_pre; + } + if (aw8695->f0 * 100 > + aw8695->info.f0_pre * (100 + aw8695->info.f0_cali_percen)) { + f0_limit = aw8695->info.f0_pre; + } + + /* calculate cali step */ + f0_cali_step = + 100000 * ((int)f0_limit - + (int)aw8695->info.f0_pre) / ((int)f0_limit * 25); + pr_info("%s line=%d f0_cali_step=%d\n", __func__, __LINE__, + f0_cali_step); + pr_info("%s line=%d f0_limit=%d\n", __func__, __LINE__, + (int)f0_limit); + pr_info("%s line=%d aw8695->info.f0_pre=%d\n", __func__, + __LINE__, (int)aw8695->info.f0_pre); + + if (f0_cali_step >= 0) { /*f0_cali_step >= 0 */ + if (f0_cali_step % 10 >= 5) + f0_cali_step = f0_cali_step / 10 + 1 + 32; + else + f0_cali_step = f0_cali_step / 10 + 32; + } else { /*f0_cali_step < 0 */ + if (f0_cali_step % 10 <= -5) + f0_cali_step = 32 + (f0_cali_step / 10 - 1); + else + f0_cali_step = 32 + f0_cali_step / 10; + } + + if (f0_cali_step > 31) + f0_cali_lra = (char)f0_cali_step - 32; + else + f0_cali_lra = (char)f0_cali_step + 32; + pr_info("%s f0_cali_lra=%d\n", __func__, (int)f0_cali_lra); + + /* update cali step */ + aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, + (char)f0_cali_lra); + aw8695_i2c_read(aw8695, AW8695_REG_TRIM_LRA, ®_val); + pr_info("%s final trim_lra=0x%02x\n", __func__, reg_val); + } + + /* restore default work mode */ + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE); + aw8695->play_mode = AW8695_HAPTIC_RAM_MODE; + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_PLAY_MODE_MASK, + AW8695_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8695_haptic_stop(aw8695); + + return ret; +} + +/***************************************************** + * + * haptic fops + * + *****************************************************/ +static int aw8695_file_open(struct inode *inode, struct file *file) +{ + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + file->private_data = (void *)g_aw8695; + + return 0; +} + +static int aw8695_file_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + module_put(THIS_MODULE); + + return 0; +} + +static long aw8695_file_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct aw8695 *aw8695 = (struct aw8695 *)file->private_data; + + int ret = 0; + + dev_info(aw8695->dev, "%s: cmd=0x%x, arg=0x%lx\n", __func__, cmd, arg); + + mutex_lock(&aw8695->lock); + + if (_IOC_TYPE(cmd) != AW8695_HAPTIC_IOCTL_MAGIC) { + dev_err(aw8695->dev, "%s: cmd magic err\n", __func__); + mutex_unlock(&aw8695->lock); + return -EINVAL; + } + + switch (cmd) { + default: + dev_err(aw8695->dev, "%s, unknown cmd\n", __func__); + break; + } + + mutex_unlock(&aw8695->lock); + + return ret; +} + +static ssize_t aw8695_file_read(struct file *filp, char *buff, size_t len, + loff_t *offset) +{ + struct aw8695 *aw8695 = (struct aw8695 *)filp->private_data; + int ret = 0; + int i = 0; + unsigned char reg_val = 0; + unsigned char *pbuff = NULL; + + mutex_lock(&aw8695->lock); + + dev_info(aw8695->dev, "%s: len=%zu\n", __func__, len); + + switch (aw8695->fileops.cmd) { + case AW8695_HAPTIC_CMD_READ_REG: + pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL); + if (pbuff != NULL) { + for (i = 0; i < len; i++) { + aw8695_i2c_read(aw8695, aw8695->fileops.reg + i, + ®_val); + pbuff[i] = reg_val; + } + for (i = 0; i < len; i++) { + dev_info(aw8695->dev, "%s: pbuff[%d]=0x%02x\n", + __func__, i, pbuff[i]); + } + ret = copy_to_user(buff, pbuff, len); + if (ret) { + dev_err(aw8695->dev, "%s: copy to user fail\n", + __func__); + } + kfree(pbuff); + } else { + dev_err(aw8695->dev, "%s: alloc memory fail\n", + __func__); + } + break; + default: + dev_err(aw8695->dev, "%s, unknown cmd %d\n", __func__, + aw8695->fileops.cmd); + break; + } + + mutex_unlock(&aw8695->lock); + + return len; +} + +static ssize_t aw8695_file_write(struct file *filp, const char *buff, + size_t len, loff_t *off) +{ + struct aw8695 *aw8695 = (struct aw8695 *)filp->private_data; + int i = 0; + int ret = 0; + unsigned char *pbuff = NULL; + + pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL); + if (pbuff == NULL) { + dev_err(aw8695->dev, "%s: alloc memory fail\n", __func__); + return len; + } + ret = copy_from_user(pbuff, buff, len); + if (ret) { + kfree(pbuff); + dev_err(aw8695->dev, "%s: copy from user fail\n", __func__); + return len; + } + + for (i = 0; i < len; i++) { + dev_info(aw8695->dev, "%s: pbuff[%d]=0x%02x\n", + __func__, i, pbuff[i]); + } + + mutex_lock(&aw8695->lock); + + aw8695->fileops.cmd = pbuff[0]; + + switch (aw8695->fileops.cmd) { + case AW8695_HAPTIC_CMD_READ_REG: + if (len == 2) { + aw8695->fileops.reg = pbuff[1]; + } else { + dev_err(aw8695->dev, "%s: read cmd len %zu err\n", + __func__, len); + } + break; + case AW8695_HAPTIC_CMD_WRITE_REG: + if (len > 2) { + for (i = 0; i < len - 2; i++) { + dev_info(aw8695->dev, + "%s: write reg0x%02x=0x%02x\n", + __func__, pbuff[1] + i, pbuff[i + 2]); + aw8695_i2c_write(aw8695, pbuff[1] + i, + pbuff[2 + i]); + } + } else { + dev_err(aw8695->dev, "%s: write cmd len %zu err\n", + __func__, len); + } + break; + default: + dev_err(aw8695->dev, "%s, unknown cmd %d\n", __func__, + aw8695->fileops.cmd); + break; + } + + mutex_unlock(&aw8695->lock); + + if (pbuff != NULL) + kfree(pbuff); + return len; +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = aw8695_file_read, + .write = aw8695_file_write, + .unlocked_ioctl = aw8695_file_unlocked_ioctl, + .open = aw8695_file_open, + .release = aw8695_file_release, +}; + +static struct miscdevice aw8695_haptic_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = AW8695_HAPTIC_NAME, + .fops = &fops, +}; + +static int aw8695_haptic_init(struct aw8695 *aw8695) +{ + int ret = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + unsigned char bemf_config = 0; +#ifdef AW_UEFI_CAL_F0 + double f0_pre_low,f0_pre_high; +#endif + pr_info("%s enter\n", __func__); + + ret = misc_register(&aw8695_haptic_misc); + if (ret) { + dev_err(aw8695->dev, "%s: misc fail: %d\n", __func__, ret); + return ret; + } + + /* haptic audio */ + aw8695->haptic_audio.delay_val = 1; + aw8695->haptic_audio.timer_val = 21318; + INIT_LIST_HEAD(&(aw8695->haptic_audio.ctr_list)); + + hrtimer_init(&aw8695->haptic_audio.timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + aw8695->haptic_audio.timer.function = aw8695_haptic_audio_timer_func; + INIT_WORK(&aw8695->haptic_audio.work, aw8695_haptic_audio_work_routine); + + mutex_init(&aw8695->haptic_audio.lock); + + aw8695->gun_type = 0xff; + aw8695->bullet_nr = 0x00; + aw8695->gun_mode = 0x00; + INIT_LIST_HEAD(&(aw8695->haptic_audio.list)); + aw8695_op_clean_status(aw8695); + /* haptic init */ + mutex_lock(&aw8695->lock); + + aw8695->activate_mode = aw8695->info.mode; + + ret = aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1, ®_val); + aw8695->index = reg_val & 0x7F; + ret = aw8695_i2c_read(aw8695, AW8695_REG_DATDBG, ®_val); + aw8695->gain = reg_val & 0xFF; + ret = aw8695_i2c_read(aw8695, AW8695_REG_BSTDBG4, ®_val); + aw8695->vmax = (reg_val >> 1) & 0x1F; + for (i = 0; i < AW8695_SEQUENCER_SIZE; i++) { + ret = aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1 + i, ®_val); + aw8695->seq[i] = reg_val; + } + + aw8695_haptic_play_mode(aw8695, AW8695_HAPTIC_STANDBY_MODE); + + aw8695_haptic_set_pwm(aw8695, AW8695_PWM_24K); + + aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG1, aw8695->info.bstdbg[0]); + aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG2, aw8695->info.bstdbg[1]); + aw8695_i2c_write(aw8695, AW8695_REG_BSTDBG3, aw8695->info.bstdbg[2]); + aw8695_i2c_write(aw8695, AW8695_REG_TSET, aw8695->info.tset); + aw8695_i2c_write(aw8695, AW8695_REG_R_SPARE, aw8695->info.r_spare); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_ANADBG, + AW8695_BIT_ANADBG_IOC_MASK, + AW8695_BIT_ANADBG_IOC_4P65A); + + aw8695_haptic_set_bst_peak_cur(aw8695, AW8695_DEFAULT_PEAKCUR); + + aw8695_haptic_swicth_motorprotect_config(aw8695, 0x00, 0x00); + + aw8695_haptic_auto_boost_config(aw8695, false); + + aw8695_haptic_trig_param_init(aw8695); + /*aw8695_haptic_trig_param_config(aw8695);*/ + + aw8695_haptic_offset_calibration(aw8695); + + /* vbat compensation */ + aw8695_haptic_cont_vbat_mode(aw8695, + AW8695_HAPTIC_CONT_VBAT_HW_COMP_MODE); + aw8695->ram_vbat_comp = AW8695_HAPTIC_RAM_VBAT_COMP_ENABLE; + + mutex_unlock(&aw8695->lock); + + /* f0 calibration */ +#ifdef AW_UEFI_CAL_F0 + pr_info("%s pre_f0 = %d \n", __func__,aw8695->info.f0_pre);; + pr_info("%s aw8695_f0_cal = %d \n", __func__,aw8695_f0_cal); + + f0_pre_low = aw8695->info.f0_pre*0.93; + f0_pre_high = aw8695->info.f0_pre * 1.07; + if(aw8695_f0_cal > (aw8695->info.f0_pre * 1.07) || aw8695_f0_cal < (aw8695->info.f0_pre*0.93)){ //dtsi 里定义的校准å差值 7% + mutex_lock(&aw8695->lock); + aw8695_haptic_f0_calibration(aw8695); //调用 1 次振动对 f0 值完æˆé‡æ–°æ£€æµ‹åŠæ ¡å‡† + mutex_unlock(&aw8695->lock); + pr_info("%s new f0 = %d \n", __func__,aw8695->f0); + } + else{ //对 UEFI 传入的 f0 检测值校准 + unsigned int f0_limit = 0; + char f0_cali_lra = 0; + int f0_cali_step = 0; + + aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, 0x00); + + /* max and min limit */ + aw8695->f0 = aw8695_f0_cal; + f0_limit = aw8695->f0; + if (aw8695->f0 * 100 < + aw8695->info.f0_pre * (100 - aw8695->info.f0_cali_percen)) { + f0_limit = aw8695->info.f0_pre; + } + if (aw8695->f0 * 100 > + aw8695->info.f0_pre * (100 + aw8695->info.f0_cali_percen)) { + f0_limit = aw8695->info.f0_pre; + } + /* calculate cali step */ + f0_cali_step = 100000 * ((int)f0_limit - + (int)aw8695->info.f0_pre) / ((int)f0_limit * 25); + + pr_info("%s line=%d f0_cali_step=%d\n", __func__, __LINE__, f0_cali_step); + pr_info("%s line=%d f0_limit=%d\n", __func__, __LINE__, (int)f0_limit); + + if (f0_cali_step >= 0) { /*f0_cali_step >= 0 */ + if (f0_cali_step % 10 >= 5) { + f0_cali_step = f0_cali_step / 10 + 1 + 32; + } else { + f0_cali_step = f0_cali_step / 10 + 32; + } + } else { /*f0_cali_step < 0 */ + if (f0_cali_step % 10 <= -5) { + f0_cali_step = 32 + (f0_cali_step / 10 - 1); + } else { + f0_cali_step = 32 + f0_cali_step / 10; + } + } + if (f0_cali_step > 31) { + f0_cali_lra = (char)f0_cali_step - 32; + } else { + f0_cali_lra = (char)f0_cali_step + 32; + } + pr_info("%s f0_cali_lra=%d\n", __func__, (int)f0_cali_lra); + /* update cali step */ + aw8695_i2c_write(aw8695, AW8695_REG_TRIM_LRA, (char)f0_cali_lra); + aw8695_i2c_read(aw8695, AW8695_REG_TRIM_LRA, ®_val); + pr_info("%s final trim_lra=0x%02x\n", __func__, reg_val); + } +#else + mutex_lock(&aw8695->lock); + + aw8695_haptic_f0_calibration(aw8695); + mutex_unlock(&aw8695->lock); +#endif + /* beme config */ + bemf_config = aw8695->info.bemf_config[0]; + aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_H, bemf_config); + bemf_config = aw8695->info.bemf_config[1]; + aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHH_L, bemf_config); + bemf_config = aw8695->info.bemf_config[2]; + aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_H, bemf_config); + bemf_config = aw8695->info.bemf_config[3]; + aw8695_i2c_write(aw8695, AW8695_REG_BEMF_VTHL_L, bemf_config); + return ret; +} + +/***************************************************** + * + * vibrator + * + *****************************************************/ +#ifdef TIMED_OUTPUT +static int aw8695_vibrator_get_time(struct timed_output_dev *dev) +{ + struct aw8695 *aw8695 = container_of(dev, struct aw8695, to_dev); + + if (hrtimer_active(&aw8695->timer)) { + ktime_t r = hrtimer_get_remaining(&aw8695->timer); + + return ktime_to_ms(r); + } + + return 0; +} + +static void aw8695_vibrator_enable(struct timed_output_dev *dev, int value) +{ + struct aw8695 *aw8695 = container_of(dev, struct aw8695, to_dev); + + mutex_lock(&aw8695->lock); + + pr_debug("%s enter\n", __func__); + + aw8695_haptic_stop(aw8695); + + if (value > 0) { + aw8695_haptic_ram_vbat_comp(aw8695, false); + aw8695_haptic_play_wav_seq(aw8695, value); + } + + mutex_unlock(&aw8695->lock); + + pr_debug("%s exit\n", __func__); +} + +#else +static enum led_brightness aw8695_haptic_brightness_get(struct led_classdev + *cdev) +{ + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); + + return aw8695->amplitude; +} + +static void aw8695_haptic_brightness_set(struct led_classdev *cdev, + enum led_brightness level) +{ + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); + + if (!aw8695->ram_init) + return; + if (aw8695->ramupdate_flag < 0) + return; + aw8695->amplitude = level; + + mutex_lock(&aw8695->lock); + + aw8695_haptic_stop(aw8695); + if (aw8695->amplitude > 0) { + aw8695_haptic_ram_vbat_comp(aw8695, false); + aw8695_haptic_play_wav_seq(aw8695, aw8695->amplitude); + } + + mutex_unlock(&aw8695->lock); + +} +#endif + +static ssize_t aw8695_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->state); +} + +static ssize_t aw8695_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8695_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ktime_t time_rem; + s64 time_ms = 0; + + if (hrtimer_active(&aw8695->timer)) { + time_rem = hrtimer_get_remaining(&aw8695->timer); + time_ms = ktime_to_ms(time_rem); + } + + return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms); +} + +static ssize_t aw8695_duration_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + /* setting 0 on duration is NOP for now */ + if (val <= 0) + return count; + + //Leo 20210105 modify start + mutex_lock(&aw8695->lock); + aw8695->duration = val; + mutex_unlock(&aw8695->lock); + //Leo 20210105 modify end + + return count; +} + +static ssize_t aw8695_activate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->state); +} + +static ssize_t aw8695_activate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8695->lock); + hrtimer_cancel(&aw8695->timer); + + aw8695->state = val; + + mutex_unlock(&aw8695->lock); + schedule_work(&aw8695->vibrator_work); + + return count; +} + +static ssize_t aw8695_activate_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + + return snprintf(buf, PAGE_SIZE, "activate_mode=%d\n", + aw8695->activate_mode); +} + +static ssize_t aw8695_activate_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8695->lock); + aw8695->activate_mode = val; + mutex_unlock(&aw8695->lock); + return count; +} + +static ssize_t aw8695_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned char reg_val = 0; + + aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1, ®_val); + aw8695->index = reg_val; + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8695->index); +} + +static ssize_t aw8695_index_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8695->lock); + aw8695_test_index = val; + aw8695->index = val; + aw8695_haptic_set_repeat_wav_seq(aw8695, aw8695->index); + mutex_unlock(&aw8695->lock); + return count; +} + +static ssize_t aw8695_vmax_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->vmax); +} + +static ssize_t aw8695_vmax_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8695->lock); + aw8695->vmax = val; + aw8695_haptic_set_bst_vol(aw8695, aw8695->vmax); + mutex_unlock(&aw8695->lock); + return count; +} + +static ssize_t aw8695_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8695->gain); +} + +static ssize_t aw8695_gain_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __func__, val); + + mutex_lock(&aw8695->lock); + aw8695->gain = val; + aw8695_haptic_set_gain(aw8695, aw8695->gain); + mutex_unlock(&aw8695->lock); + return count; +} + +static ssize_t aw8695_seq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for (i = 0; i < AW8695_SEQUENCER_SIZE; i++) { + aw8695_i2c_read(aw8695, AW8695_REG_WAVSEQ1 + i, ®_val); + count += snprintf(buf + count, PAGE_SIZE - count, + "seq%d: 0x%02x\n", i + 1, reg_val); + aw8695->seq[i] |= reg_val; + } + return count; +} + +static ssize_t aw8695_seq_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + pr_debug("%s: seq%d=0x%x\n", __func__, databuf[0], + databuf[1]); + mutex_lock(&aw8695->lock); + aw8695->seq[databuf[0]] = (unsigned char)databuf[1]; + aw8695_haptic_set_wav_seq(aw8695, (unsigned char)databuf[0], + aw8695->seq[databuf[0]]); + mutex_unlock(&aw8695->lock); + } + return count; +} + +static ssize_t aw8695_loop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for (i = 0; i < AW8695_SEQUENCER_LOOP_SIZE; i++) { + aw8695_i2c_read(aw8695, AW8695_REG_WAVLOOP1 + i, ®_val); + aw8695->loop[i * 2 + 0] = (reg_val >> 4) & 0x0F; + aw8695->loop[i * 2 + 1] = (reg_val >> 0) & 0x0F; + + count += snprintf(buf + count, PAGE_SIZE - count, + "seq%d loop: 0x%02x\n", i * 2 + 1, + aw8695->loop[i * 2 + 0]); + count += + snprintf(buf + count, PAGE_SIZE - count, + "seq%d loop: 0x%02x\n", i * 2 + 2, + aw8695->loop[i * 2 + 1]); + } + return count; +} + +static ssize_t aw8695_loop_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + pr_debug("%s: seq%d loop=0x%x\n", __func__, databuf[0], + databuf[1]); + mutex_lock(&aw8695->lock); + aw8695->loop[databuf[0]] = (unsigned char)databuf[1]; + aw8695_haptic_set_wav_loop(aw8695, (unsigned char)databuf[0], + aw8695->loop[databuf[0]]); + mutex_unlock(&aw8695->lock); + } + + return count; +} + +static ssize_t aw8695_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for (i = 0; i < AW8695_REG_MAX; i++) { + if (!(aw8695_reg_access[i] & REG_RD_ACCESS)) + continue; + aw8695_i2c_read(aw8695, i, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02x=0x%02x\n", + i, reg_val); + } + return len; +} + +static ssize_t aw8695_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw8695_i2c_write(aw8695, (unsigned char)databuf[0], + (unsigned char)databuf[1]); + } + + return count; +} + +static ssize_t aw8695_rtp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "rtp play: %d\n", + aw8695->rtp_cnt); + + return len; +} + +#define AUDIO_READY_STATUS 1024 +#define FACTORY_MODE_NORMAL_RTP_NUMBER 73 +#define FACTORY_MODE_HIGH_TEMP_RTP_NUMBER 72 + +static ssize_t aw8695_rtp_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + int rtp_is_going_on = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) { + pr_info("%s: kstrtouint fail\n", __func__); + return rc; + } + pr_info("%s: rtp[%d]\n", __func__, val); + + rtp_is_going_on = aw8695_haptic_juge_RTP_is_going_on(aw8695); + if (rtp_is_going_on && (val == AUDIO_READY_STATUS)) { + pr_info("%s: seem audio status rtp[%d]\n", __func__, val); + return count; + } + mutex_lock(&aw8695->lock); + aw8695_haptic_stop(aw8695); + aw8695_haptic_set_rtp_aei(aw8695, false); + aw8695_interrupt_clear(aw8695); + if (val < (sizeof(aw8695_rtp_name) / AW8695_RTP_NAME_MAX)) { + aw8695->rtp_file_num = val; + if (val) + schedule_work(&aw8695->rtp_work); + } else { + pr_err("%s: rtp_file_num 0x%02x over max value\n", __func__, + aw8695->rtp_file_num); + } + mutex_unlock(&aw8695->lock); + return count; +} + +static ssize_t aw8695_ram_update_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + /* struct timed_output_dev *to_dev = dev_get_drvdata(dev); */ + /*struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);*/ +#else + /* struct led_classdev *cdev = dev_get_drvdata(dev); */ + /* struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); */ +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "sram update mode\n"); + return len; +} + +static ssize_t aw8695_ram_update_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val) + aw8695_ram_update(aw8695); + return count; +} + +static ssize_t aw8695_f0_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + mutex_lock(&aw8695->lock); + aw8695->f0_cali_flag = AW8695_HAPTIC_LRA_F0; + aw8695_haptic_get_f0(aw8695); + mutex_unlock(&aw8695->lock); + len += + snprintf(buf + len, PAGE_SIZE - len, "aw8695 lra f0 = %d\n", + aw8695->f0); + return len; +} + +static ssize_t aw8695_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + /* struct timed_output_dev *to_dev = dev_get_drvdata(dev); */ + /*struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev);*/ +#else + /* struct led_classdev *cdev = dev_get_drvdata(dev); */ + /* struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); */ +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + return count; +} + +static ssize_t aw8695_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + mutex_lock(&aw8695->lock); + aw8695->f0_cali_flag = AW8695_HAPTIC_CALI_F0; + aw8695_haptic_get_f0(aw8695); + mutex_unlock(&aw8695->lock); + len += + snprintf(buf + len, PAGE_SIZE - len, "aw8695 cali f0 = %d\n", + aw8695->f0); + return len; +} + +static ssize_t aw8695_cali_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val) { + mutex_lock(&aw8695->lock); + aw8695_haptic_f0_calibration(aw8695); + mutex_unlock(&aw8695->lock); + } + return count; +} + +static ssize_t aw8695_cont_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + aw8695_haptic_read_cont_f0(aw8695); + len += snprintf(buf + len, PAGE_SIZE - len, "aw8695 cont f0 = %d\n", + aw8695->cont_f0); + return len; +} + +static ssize_t aw8695_cont_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + aw8695_haptic_stop(aw8695); + if (val) + aw8695_haptic_cont(aw8695); + return count; +} + +static ssize_t aw8695_cont_td_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "aw8695 cont delay time = 0x%04x\n", + aw8695->info.cont_td); + return len; +} + +static ssize_t aw8695_cont_td_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[1] = { 0 }; + + if (sscanf(buf, "%x", &databuf[0]) == 1) { + aw8695->info.cont_td = databuf[0]; + aw8695_i2c_write(aw8695, AW8695_REG_TD_H, + (unsigned char)(databuf[0] >> 8)); + aw8695_i2c_write(aw8695, AW8695_REG_TD_L, + (unsigned char)(databuf[0] >> 0)); + } + return count; +} + +static ssize_t aw8695_cont_drv_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "aw8695 cont drv level = %d\n", + aw8695->info.cont_drv_lvl); + len += snprintf(buf + len, PAGE_SIZE - len, + "aw8695 cont drv level overdrive= %d\n", + aw8695->info.cont_drv_lvl_ov); + return len; +} + +static ssize_t aw8695_cont_drv_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%d %d", &databuf[0], &databuf[1]) == 2) { + aw8695->info.cont_drv_lvl = databuf[0]; + aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL, + aw8695->info.cont_drv_lvl); + aw8695->info.cont_drv_lvl_ov = databuf[1]; + aw8695_i2c_write(aw8695, AW8695_REG_DRV_LVL_OV, + aw8695->info.cont_drv_lvl_ov); + } + return count; +} + +static ssize_t aw8695_cont_num_brk_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "aw8695 cont break num = %d\n", + aw8695->info.cont_num_brk); + return len; +} + +static ssize_t aw8695_cont_num_brk_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[1] = { 0 }; + + if (sscanf(buf, "%d", &databuf[0]) == 1) { + aw8695->info.cont_num_brk = databuf[0]; + if (aw8695->info.cont_num_brk > 7) + aw8695->info.cont_num_brk = 7; + aw8695_i2c_write_bits(aw8695, AW8695_REG_BEMF_NUM, + AW8695_BIT_BEMF_NUM_BRK_MASK, + aw8695->info.cont_num_brk); + } + return count; +} + +static ssize_t aw8695_cont_zc_thr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "aw8695 cont zero cross thr = 0x%04x\n", + aw8695->info.cont_zc_thr); + return len; +} + +static ssize_t aw8695_cont_zc_thr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[1] = { 0 }; + + if (sscanf(buf, "%x", &databuf[0]) == 1) { + aw8695->info.cont_zc_thr = databuf[0]; + aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_H, + (unsigned char)(databuf[0] >> 8)); + aw8695_i2c_write(aw8695, AW8695_REG_ZC_THRSH_L, + (unsigned char)(databuf[0] >> 0)); + } + return count; +} + +static ssize_t aw8695_vbat_monitor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + mutex_lock(&aw8695->lock); + aw8695_haptic_stop(aw8695); + aw8695_haptic_get_vbat(aw8695); + len += + snprintf(buf + len, PAGE_SIZE - len, "vbat=%dmV\n", aw8695->vbat); + mutex_unlock(&aw8695->lock); + + return len; +} + +static ssize_t aw8695_vbat_monitor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8695_lra_resistance_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + unsigned char reg_val = 0; + + mutex_lock(&aw8695->lock); + aw8695_haptic_stop(aw8695); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BYPASS); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL, + AW8695_BIT_ANACTRL_HD_PD_MASK, + AW8695_BIT_ANACTRL_HD_HZ_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_D2SCFG, + AW8695_BIT_D2SCFG_CLK_ADC_MASK, + AW8695_BIT_D2SCFG_CLK_ASC_1P5MHZ); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL, + AW8695_BIT_DETCTRL_RL_OS_MASK, + AW8695_BIT_DETCTRL_RL_DETECT); + aw8695_i2c_write_bits(aw8695, AW8695_REG_DETCTRL, + AW8695_BIT_DETCTRL_DIAG_GO_MASK, + AW8695_BIT_DETCTRL_DIAG_GO_ENABLE); + usleep_range(3000, 3500); + aw8695_i2c_read(aw8695, AW8695_REG_RLDET, ®_val); + aw8695->lra = 298 * reg_val; + len += + snprintf(buf + len, PAGE_SIZE - len, "r_lra=%dmohm\n", aw8695->lra); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_ANACTRL, + AW8695_BIT_ANACTRL_HD_PD_MASK, + AW8695_BIT_ANACTRL_HD_PD_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_D2SCFG, + AW8695_BIT_D2SCFG_CLK_ADC_MASK, + AW8695_BIT_D2SCFG_CLK_ASC_6MHZ); + + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_OFF); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_BST_MODE_MASK, + AW8695_BIT_SYSCTRL_BST_MODE_BOOST); + mutex_unlock(&aw8695->lock); + + return len; +} + +static ssize_t aw8695_lra_resistance_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8695_auto_boost_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += + snprintf(buf + len, PAGE_SIZE - len, "auto_boost=%d\n", + aw8695->auto_boost); + + return len; +} + +static ssize_t aw8695_auto_boost_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8695->lock); + aw8695_haptic_stop(aw8695); + aw8695_haptic_auto_boost_config(aw8695, val); + mutex_unlock(&aw8695->lock); + + return count; +} + +static ssize_t aw8695_prctmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + unsigned char reg_val = 0; + + aw8695_i2c_read(aw8695, AW8695_REG_RLDET, ®_val); + + len += + snprintf(buf + len, PAGE_SIZE - len, "prctmode=%d\n", + reg_val & 0x20); + return len; +} + +static ssize_t aw8695_prctmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[2] = { 0, 0 }; + unsigned int addr = 0; + unsigned int val = 0; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + addr = databuf[0]; + val = databuf[1]; + mutex_lock(&aw8695->lock); + aw8695_haptic_swicth_motorprotect_config(aw8695, addr, val); + mutex_unlock(&aw8695->lock); + } + return count; +} + +static ssize_t aw8695_trig_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + unsigned char i = 0; + + for (i = 0; i < AW8695_TRIG_NUM; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "trig%d: enable=%d, default_level=%d, dual_edge=%d, frist_seq=%d, second_seq=%d\n", + i + 1, aw8695->trig[i].enable, + aw8695->trig[i].default_level, + aw8695->trig[i].dual_edge, + aw8695->trig[i].frist_seq, + aw8695->trig[i].second_seq); + } + + return len; +} + +static ssize_t aw8695_trig_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[6] = { 0 }; + + if (sscanf(buf, "%d %d %d %d %d %d", + &databuf[0], &databuf[1], &databuf[2], &databuf[3], + &databuf[4], &databuf[5])) { + pr_debug("%s: %d, %d, %d, %d, %d, %d\n", __func__, databuf[0], + databuf[1], databuf[2], databuf[3], databuf[4], + databuf[5]); + if (databuf[0] > 3) + databuf[0] = 3; + if (databuf[0] > 0) + databuf[0] -= 1; + aw8695->trig[databuf[0]].enable = databuf[1]; + aw8695->trig[databuf[0]].default_level = databuf[2]; + aw8695->trig[databuf[0]].dual_edge = databuf[3]; + aw8695->trig[databuf[0]].frist_seq = databuf[4]; + aw8695->trig[databuf[0]].second_seq = databuf[5]; + mutex_lock(&aw8695->lock); + aw8695_haptic_trig_param_config(aw8695); + aw8695_haptic_trig_enable_config(aw8695); + mutex_unlock(&aw8695->lock); + } + return count; +} + +static ssize_t aw8695_ram_vbat_comp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += + snprintf(buf + len, PAGE_SIZE - len, "ram_vbat_comp=%d\n", + aw8695->ram_vbat_comp); + + return len; +} + +static ssize_t aw8695_ram_vbat_comp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8695->lock); + if (val) + aw8695->ram_vbat_comp = AW8695_HAPTIC_RAM_VBAT_COMP_ENABLE; + else + aw8695->ram_vbat_comp = AW8695_HAPTIC_RAM_VBAT_COMP_DISABLE; + mutex_unlock(&aw8695->lock); + + return count; +} + +static ssize_t aw8695_osc_cali_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int val = 0; + + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8695->lock); + if (val == 3) { + aw8695_rtp_osc_calibration(aw8695); + aw8695_rtp_trim_lra_calibration(aw8695); + } else if (val == 1) { + aw8695_rtp_osc_calibration(aw8695); + } + + mutex_unlock(&aw8695->lock); + + return count; +} + +static ssize_t aw8695_haptic_audio_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", + aw8695->haptic_audio.ctr.cnt); + return len; +} + +static ssize_t aw8695_haptic_audio_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[6] = { 0 }; + struct haptic_ctr *hap_ctr = NULL; + + aw_dbg_info("%s: haptic_audio enter\n", __func__); + + if (!(aw8695->ram_init) || atomic_read(&aw8695->is_rtp)) + return count; + if (6 == + sscanf(buf, "%d %d %d %d %d %d", &databuf[0], &databuf[1], + &databuf[2], &databuf[3], &databuf[4], &databuf[5])) { + if (databuf[2]) { + aw_dbg_info + ("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n", + __func__, databuf[0], databuf[1], databuf[2], + databuf[3], databuf[4], databuf[5]); + } + + hap_ctr = + (struct haptic_ctr *)kzalloc(sizeof(struct haptic_ctr), + GFP_KERNEL); + if (hap_ctr == NULL) { + pr_err("%s: kzalloc memory fail\n", __func__); + return count; + } + mutex_lock(&aw8695->haptic_audio.lock); + hap_ctr->cnt = (unsigned char)databuf[0]; + hap_ctr->cmd = (unsigned char)databuf[1]; + hap_ctr->play = (unsigned char)databuf[2]; + hap_ctr->wavseq = (unsigned char)databuf[3]; + hap_ctr->loop = (unsigned char)databuf[4]; + hap_ctr->gain = (unsigned char)databuf[5]; + aw8695_haptic_audio_ctr_list_insert(&aw8695->haptic_audio, + hap_ctr); + + if (hap_ctr->cmd == 0xff) { + aw_dbg_info("%s: haptic_audio stop\n", __func__); + if (hrtimer_active(&aw8695->haptic_audio.timer)) { + aw_dbg_info("%s: cancel haptic_audio_timer\n", + __func__); + hrtimer_cancel(&aw8695->haptic_audio.timer); + aw8695->haptic_audio.ctr.cnt = 0; + aw8695_haptic_audio_off(aw8695); + } + } else { + if (hrtimer_active(&aw8695->haptic_audio.timer)) { + } else { + aw_dbg_info("%s: start haptic_audio_timer\n", + __func__); + aw8695_haptic_audio_init(aw8695); + hrtimer_start(&aw8695->haptic_audio.timer, + ktime_set(aw8695->haptic_audio. + delay_val / 1000000, + (aw8695->haptic_audio. + delay_val % 1000000) * + 1000), + HRTIMER_MODE_REL); + } + } + mutex_unlock(&aw8695->haptic_audio.lock); + kfree(hap_ctr); + } + return count; +} + +static ssize_t aw8695_haptic_audio_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "haptic_audio.delay_val=%dus\n", + aw8695->haptic_audio.delay_val); + len += + snprintf(buf + len, PAGE_SIZE - len, + "haptic_audio.timer_val=%dus\n", + aw8695->haptic_audio.timer_val); + return len; +} + +static ssize_t aw8695_haptic_audio_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(to_dev, struct aw8695, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8695 *aw8695 = container_of(cdev, struct aw8695, cdev); +#endif + unsigned int databuf[2] = { 0 }; + + if (sscanf(buf, "%d %d", &databuf[0], &databuf[1]) == 2) { + aw8695->haptic_audio.delay_val = databuf[0]; + aw8695->haptic_audio.timer_val = databuf[1]; + } + return count; +} + +static DEVICE_ATTR(state, S_IWUSR | S_IRUGO, aw8695_state_show, + aw8695_state_store); +static DEVICE_ATTR(duration, S_IWUSR | S_IRUGO, aw8695_duration_show, + aw8695_duration_store); +static DEVICE_ATTR(activate, S_IWUSR | S_IRUGO, aw8695_activate_show, + aw8695_activate_store); +static DEVICE_ATTR(activate_mode, S_IWUSR | S_IRUGO, aw8695_activate_mode_show, + aw8695_activate_mode_store); +static DEVICE_ATTR(index, S_IWUSR | S_IRUGO, aw8695_index_show, + aw8695_index_store); +static DEVICE_ATTR(vmax, S_IWUSR | S_IRUGO, aw8695_vmax_show, + aw8695_vmax_store); +static DEVICE_ATTR(gain, S_IWUSR | S_IRUGO, aw8695_gain_show, + aw8695_gain_store); +static DEVICE_ATTR(seq, S_IWUSR | S_IRUGO, aw8695_seq_show, aw8695_seq_store); +static DEVICE_ATTR(loop, S_IWUSR | S_IRUGO, aw8695_loop_show, + aw8695_loop_store); +static DEVICE_ATTR(register, S_IWUSR | S_IRUGO, aw8695_reg_show, + aw8695_reg_store); +static DEVICE_ATTR(rtp, S_IWUSR | S_IRUGO, aw8695_rtp_show, aw8695_rtp_store); +static DEVICE_ATTR(ram_update, S_IWUSR | S_IRUGO, aw8695_ram_update_show, + aw8695_ram_update_store); +static DEVICE_ATTR(f0, S_IWUSR | S_IRUGO, aw8695_f0_show, aw8695_f0_store); +static DEVICE_ATTR(cali, S_IWUSR | S_IRUGO, aw8695_cali_show, + aw8695_cali_store); +static DEVICE_ATTR(cont, S_IWUSR | S_IRUGO, aw8695_cont_show, + aw8695_cont_store); +static DEVICE_ATTR(cont_td, S_IWUSR | S_IRUGO, aw8695_cont_td_show, + aw8695_cont_td_store); +static DEVICE_ATTR(cont_drv, S_IWUSR | S_IRUGO, aw8695_cont_drv_show, + aw8695_cont_drv_store); +static DEVICE_ATTR(cont_num_brk, S_IWUSR | S_IRUGO, aw8695_cont_num_brk_show, + aw8695_cont_num_brk_store); +static DEVICE_ATTR(cont_zc_thr, S_IWUSR | S_IRUGO, aw8695_cont_zc_thr_show, + aw8695_cont_zc_thr_store); +static DEVICE_ATTR(vbat_monitor, S_IWUSR | S_IRUGO, aw8695_vbat_monitor_show, + aw8695_vbat_monitor_store); +static DEVICE_ATTR(lra_resistance, S_IWUSR | S_IRUGO, + aw8695_lra_resistance_show, aw8695_lra_resistance_store); +static DEVICE_ATTR(auto_boost, S_IWUSR | S_IRUGO, aw8695_auto_boost_show, + aw8695_auto_boost_store); +static DEVICE_ATTR(prctmode, S_IWUSR | S_IRUGO, aw8695_prctmode_show, + aw8695_prctmode_store); +static DEVICE_ATTR(trig, S_IWUSR | S_IRUGO, aw8695_trig_show, + aw8695_trig_store); +static DEVICE_ATTR(ram_vbat_comp, S_IWUSR | S_IRUGO, aw8695_ram_vbat_comp_show, + aw8695_ram_vbat_comp_store); +static DEVICE_ATTR(osc_cali, S_IWUSR | S_IRUGO, NULL, aw8695_osc_cali_store); +static DEVICE_ATTR(haptic_audio, S_IWUSR | S_IRUGO, aw8695_haptic_audio_show, + aw8695_haptic_audio_store); +static DEVICE_ATTR(haptic_audio_time, S_IWUSR | S_IRUGO, + aw8695_haptic_audio_time_show, + aw8695_haptic_audio_time_store); +static DEVICE_ATTR(gun_type, S_IWUSR | S_IRUGO, aw8695_gun_type_show, + aw8695_gun_type_store); //hch 20190917 +static DEVICE_ATTR(bullet_nr, S_IWUSR | S_IRUGO, aw8695_bullet_nr_show, + aw8695_bullet_nr_store); //hch 20190917 +static DEVICE_ATTR(gun_mode, S_IWUSR | S_IRUGO, aw8695_gun_mode_show, + aw8695_gun_mode_store); //hch 20190917 + +static struct attribute *aw8695_vibrator_attributes[] = { + &dev_attr_state.attr, + &dev_attr_duration.attr, + &dev_attr_activate.attr, + &dev_attr_activate_mode.attr, + &dev_attr_index.attr, + &dev_attr_vmax.attr, + &dev_attr_gain.attr, + &dev_attr_seq.attr, + &dev_attr_loop.attr, + &dev_attr_register.attr, + &dev_attr_rtp.attr, + &dev_attr_ram_update.attr, + &dev_attr_f0.attr, + &dev_attr_cali.attr, + &dev_attr_cont.attr, + &dev_attr_cont_td.attr, + &dev_attr_cont_drv.attr, + &dev_attr_cont_num_brk.attr, + &dev_attr_cont_zc_thr.attr, + &dev_attr_vbat_monitor.attr, + &dev_attr_lra_resistance.attr, + &dev_attr_auto_boost.attr, + &dev_attr_prctmode.attr, + &dev_attr_trig.attr, + &dev_attr_ram_vbat_comp.attr, + &dev_attr_osc_cali.attr, + &dev_attr_haptic_audio.attr, + &dev_attr_haptic_audio_time.attr, + &dev_attr_gun_type.attr, //hch 20190917 + &dev_attr_bullet_nr.attr, //hch 20190917 + &dev_attr_gun_mode.attr, //hch 20190917 + NULL +}; + +static struct attribute_group aw8695_vibrator_attribute_group = { + .attrs = aw8695_vibrator_attributes +}; + +static enum hrtimer_restart aw8695_vibrator_timer_func(struct hrtimer *timer) +{ + struct aw8695 *aw8695 = container_of(timer, struct aw8695, timer); + + pr_debug("%s enter\n", __func__); + aw8695->state = 0; + schedule_work(&aw8695->vibrator_work); + + return HRTIMER_NORESTART; +} + +static void aw8695_vibrator_work_routine(struct work_struct *work) +{ + struct aw8695 *aw8695 = + container_of(work, struct aw8695, vibrator_work); + + pr_debug("%s enter\n", __func__); + + mutex_lock(&aw8695->lock); + + aw8695_haptic_stop(aw8695); + if (aw8695->state) { + if (aw8695->activate_mode == AW8695_HAPTIC_ACTIVATE_RAM_MODE) { + //Leo 20210105 modify start + aw8695_haptic_ram_config(aw8695); + if (aw8695->duration >= 60) { + aw8695_haptic_ram_vbat_comp(aw8695, true); + aw8695_haptic_play_repeat_seq(aw8695, true); + } else { + aw8695_haptic_ram_vbat_comp(aw8695, false); + aw8695_haptic_play_wav_seq(aw8695, true); + } + //Leo 20210105 modify end + + } else if (aw8695->activate_mode == + AW8695_HAPTIC_ACTIVATE_CONT_MODE) { + aw8695_haptic_cont(aw8695); + } else { + } + /* run ms timer */ + if(aw8695->duration >=60){ + hrtimer_start(&aw8695->timer, + ktime_set(aw8695->duration / 1000, + (aw8695->duration % 1000) * 1000000), + HRTIMER_MODE_REL); + } + + } + mutex_unlock(&aw8695->lock); +} + +static int aw8695_vibrator_init(struct aw8695 *aw8695) +{ + int ret = 0; + + pr_info("%s enter\n", __func__); + +#ifdef TIMED_OUTPUT + aw8695->to_dev.name = "vibrator_aw8695"; + aw8695->to_dev.get_time = aw8695_vibrator_get_time; + aw8695->to_dev.enable = aw8695_vibrator_enable; + + ret = timed_output_dev_register(&(aw8695->to_dev)); + if (ret < 0) { + dev_err(aw8695->dev, "%s: fail to create timed output dev\n", + __func__); + return ret; + } + ret = + sysfs_create_group(&aw8695->to_dev.dev->kobj, + &aw8695_vibrator_attribute_group); + if (ret < 0) { + dev_err(aw8695->dev, "%s error creating sysfs attr files\n", + __func__); + return ret; + } +#else + aw8695->cdev.name = "vibrator_aw8695"; + aw8695->cdev.brightness_get = aw8695_haptic_brightness_get; + aw8695->cdev.brightness_set = aw8695_haptic_brightness_set; + + ret = devm_led_classdev_register(&aw8695->i2c->dev, &aw8695->cdev); + if (ret < 0) { + dev_err(aw8695->dev, "%s: fail to create led dev\n", __func__); + return ret; + } + ret = + sysfs_create_group(&aw8695->cdev.dev->kobj, + &aw8695_vibrator_attribute_group); + if (ret < 0) { + dev_err(aw8695->dev, "%s error creating sysfs attr files\n", + __func__); + return ret; + } +#endif + hrtimer_init(&aw8695->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8695->timer.function = aw8695_vibrator_timer_func; + INIT_WORK(&aw8695->vibrator_work, aw8695_vibrator_work_routine); + + INIT_WORK(&aw8695->rtp_work, aw8695_rtp_work_routine); + + mutex_init(&aw8695->lock); + mutex_init(&aw8695->rtp_lock); + + return 0; +} + +/****************************************************** + * + * irq + * + ******************************************************/ +static void aw8695_interrupt_clear(struct aw8695 *aw8695) +{ + unsigned char reg_val = 0; + + pr_debug("%s enter\n", __func__); + aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val); + pr_debug("%s: reg SYSINT=0x%x\n", __func__, reg_val); +} + +static void aw8695_interrupt_setup(struct aw8695 *aw8695) +{ + unsigned char reg_val = 0; + + pr_info("%s enter\n", __func__); + + aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val); + pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); + + /* edge int mode */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_DBGCTRL, + AW8695_BIT_DBGCTRL_INT_MODE_MASK, + AW8695_BIT_DBGCTRL_INT_MODE_EDGE); + + /* int enable */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_BSTERR_MASK, + AW8695_BIT_SYSINTM_BSTERR_OFF); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_OV_MASK, + AW8695_BIT_SYSINTM_OV_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_UVLO_MASK, + AW8695_BIT_SYSINTM_UVLO_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_OCD_MASK, + AW8695_BIT_SYSINTM_OCD_EN); + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSINTM, + AW8695_BIT_SYSINTM_OT_MASK, + AW8695_BIT_SYSINTM_OT_EN); +} + +static irqreturn_t aw8695_irq(int irq, void *data) +{ + struct aw8695 *aw8695 = data; + unsigned char reg_val = 0; + unsigned char dbg_val = 0; + unsigned int buf_len = 0; + unsigned char glb_state_val = 0; + + pr_debug("%s enter\n", __func__); + + aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val); + aw_dbg_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); + aw8695_i2c_read(aw8695, AW8695_REG_DBGSTAT, &dbg_val); + aw_dbg_info("%s: reg DBGSTAT=0x%x\n", __func__, dbg_val); + + if (reg_val & AW8695_BIT_SYSINT_OVI) { + aw8695_op_clean_status(aw8695); + pr_err("%s chip ov int error\n", __func__); + } + if (reg_val & AW8695_BIT_SYSINT_UVLI) { + aw8695_op_clean_status(aw8695); + pr_err("%s chip uvlo int error\n", __func__); + } + if (reg_val & AW8695_BIT_SYSINT_OCDI) { + aw8695_op_clean_status(aw8695); + pr_err("%s chip over current int error\n", __func__); + } + if (reg_val & AW8695_BIT_SYSINT_OTI) { + aw8695_op_clean_status(aw8695); + pr_err("%s chip over temperature int error\n", __func__); + } + if (reg_val & AW8695_BIT_SYSINT_DONEI) { + aw8695_op_clean_status(aw8695); + aw_dbg_info("%s chip playback done\n", __func__); + } + + if (reg_val & AW8695_BIT_SYSINT_FF_AEI) { + aw_dbg_info("%s: aw8695 rtp fifo almost empty int\n", __func__); + if (aw8695->rtp_init) { + while ((!aw8695_haptic_rtp_get_fifo_afi(aw8695)) && + (aw8695->play_mode == AW8695_HAPTIC_RTP_MODE)) { + mutex_lock(&aw8695->rtp_lock); + aw_dbg_info + ("%s: aw8695 rtp mode fifo update, cnt=%d\n", + __func__, aw8695->rtp_cnt); + if (!aw8695_rtp) { + aw_dbg_info("%s:aw8695_rtp is null break\n", + __func__); + mutex_unlock(&aw8695->rtp_lock); + break; + } + if ((aw8695_rtp->len - aw8695->rtp_cnt) < + (aw8695->ram.base_addr >> 2)) { + buf_len = + aw8695_rtp->len - aw8695->rtp_cnt; + } else { + buf_len = (aw8695->ram.base_addr >> 2); + } + aw8695->rtpupdate_flag = + aw8695_i2c_writes(aw8695, + AW8695_REG_RTP_DATA, + &aw8695_rtp->data[aw8695-> + rtp_cnt], buf_len); + aw8695->rtp_cnt += buf_len; + aw8695_i2c_read(aw8695, AW8695_REG_GLB_STATE, &glb_state_val); + if ((aw8695->rtp_cnt == aw8695_rtp->len) || ((glb_state_val & 0x0f) == 0x00)) { + aw8695_op_clean_status(aw8695); + aw_dbg_info("%s: rtp update complete\n", + __func__); + aw8695_haptic_set_rtp_aei(aw8695, + false); + aw8695->rtp_cnt = 0; + aw8695->rtp_init = 0; + atomic_set(&aw8695->is_rtp, 0); + mutex_unlock(&aw8695->rtp_lock); + break; + } + mutex_unlock(&aw8695->rtp_lock); + } + } else { + aw_dbg_info("%s: aw8695 rtp init = %d, init error\n", + __func__, aw8695->rtp_init); + } + } + + if (reg_val & AW8695_BIT_SYSINT_FF_AFI) + aw_dbg_info("%s: aw8695 rtp mode fifo full empty\n", __func__); + + if (aw8695->play_mode != AW8695_HAPTIC_RTP_MODE) + aw8695_haptic_set_rtp_aei(aw8695, false); + + aw8695_i2c_read(aw8695, AW8695_REG_SYSINT, ®_val); + aw_dbg_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); + aw8695_i2c_read(aw8695, AW8695_REG_SYSST, ®_val); + aw_dbg_info("%s: reg SYSST=0x%x\n", __func__, reg_val); + + aw_dbg_info("%s exit\n", __func__); + + return IRQ_HANDLED; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +static int aw8695_parse_dt(struct device *dev, struct aw8695 *aw8695, + struct device_node *np) +{ + unsigned int val = 0; + unsigned int bstdbg[6]; + unsigned int f0_trace_parameter[4]; + unsigned int bemf_config[4]; + + aw8695->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw8695->reset_gpio < 0) { + dev_err(dev, + "%s: no reset gpio provided, will not HW reset device\n", + __func__); + return -1; + } else { + dev_info(dev, "%s: reset gpio provided ok\n", __func__); + } + aw8695->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw8695->irq_gpio < 0) + dev_err(dev, "%s: no irq gpio provided.\n", __func__); + else + dev_info(dev, "%s: irq gpio provided ok.\n", __func__); + + val = of_property_read_u32(np, "vib_mode", &aw8695->info.mode); + if (val != 0) + pr_info("%s: vib_mode not found\n", __func__); + val = of_property_read_u32(np, "vib_f0_pre", &aw8695->info.f0_pre); + if (val != 0) + pr_info("%s: vib_f0_pre not found\n", __func__); + val = + of_property_read_u32(np, "vib_f0_cali_percen", + &aw8695->info.f0_cali_percen); + if (val != 0) + pr_info("%s: vib_f0_cali_percen not found\n", __func__); + val = + of_property_read_u32(np, "vib_cont_drv_lev", + &aw8695->info.cont_drv_lvl); + if (val != 0) + pr_info("%s: vib_cont_drv_lev not found\n", __func__); + val = + of_property_read_u32(np, "vib_cont_drv_lvl_ov", + &aw8695->info.cont_drv_lvl_ov); + if (val != 0) + pr_info("%s: vib_cont_drv_lvl_ov not found\n", __func__); + val = of_property_read_u32(np, "vib_cont_td", &aw8695->info.cont_td); + if (val != 0) + pr_info("%s: vib_cont_td not found\n", __func__); + val = + of_property_read_u32(np, "vib_cont_zc_thr", + &aw8695->info.cont_zc_thr); + if (val != 0) + pr_info("%s: vib_cont_zc_thr not found\n", __func__); + val = + of_property_read_u32(np, "vib_cont_num_brk", + &aw8695->info.cont_num_brk); + if (val != 0) + pr_info("%s: vib_cont_num_brk not found\n", __func__); + val = of_property_read_u32(np, "vib_f0_coeff", &aw8695->info.f0_coeff); + if (val != 0) + pr_info("%s: vib_f0_coeff not found\n", __func__); + + val = of_property_read_u32(np, "vib_tset", &aw8695->info.tset); + if (val != 0) + pr_info("%s vib_tset not found\n", __func__); + val = of_property_read_u32(np, "vib_r_spare", &aw8695->info.r_spare); + if (val != 0) + pr_info("%s vib_r_spare not found\n", __func__); + val = of_property_read_u32_array(np, "vib_bstdbg", + bstdbg, ARRAY_SIZE(bstdbg)); + if (val != 0) + pr_info("%s vib_bstdbg not found\n", __func__); + memcpy(aw8695->info.bstdbg, bstdbg, sizeof(bstdbg)); + val = of_property_read_u32_array(np, "vib_f0_trace_parameter", + f0_trace_parameter, + ARRAY_SIZE(f0_trace_parameter)); + if (val != 0) + pr_info("%s vib_f0_trace_parameter not found\n", __func__); + memcpy(aw8695->info.f0_trace_parameter, f0_trace_parameter, + sizeof(f0_trace_parameter)); + val = + of_property_read_u32_array(np, "vib_bemf_config", bemf_config, + ARRAY_SIZE(bemf_config)); + if (val != 0) + pr_info("%s vib_bemf_config not found\n", __func__); + memcpy(aw8695->info.bemf_config, bemf_config, sizeof(bemf_config)); + + return 0; +} + +static int aw8695_hw_reset(struct aw8695 *aw8695) +{ + pr_info("%s enter\n", __func__); + + if (aw8695 && gpio_is_valid(aw8695->reset_gpio)) { + gpio_set_value_cansleep(aw8695->reset_gpio, 0); + usleep_range(1000, 2000); + gpio_set_value_cansleep(aw8695->reset_gpio, 1); + usleep_range(3500, 4000); + } else { + dev_err(aw8695->dev, "%s: failed\n", __func__); + } + return 0; +} + +/***************************************************** + * + * check chip id + * + *****************************************************/ +static int aw8695_read_chipid(struct aw8695 *aw8695) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char reg = 0; + + while (cnt < AW_READ_CHIPID_RETRIES) { + /* hardware reset */ + aw8695_hw_reset(aw8695); + + ret = aw8695_i2c_read(aw8695, AW8695_REG_ID, ®); + if (ret < 0) { + dev_err(aw8695->dev, + "%s: failed to read register AW8695_REG_ID: %d\n", + __func__, ret); + } + switch (reg) { + case AW8695_CHIPID: + pr_info("%s aw8695 detected\n", __func__); + aw8695->chipid = AW8695_CHIPID; + /* aw8695->flags |= AW8695_FLAG_SKIP_INTERRUPTS; */ + aw8695_haptic_softreset(aw8695); + return 0; + default: + pr_info("%s unsupported device revision (0x%x)\n", + __func__, reg); + break; + } + cnt++; + + usleep_range(AW_READ_CHIPID_RETRY_DELAY * 1000, + AW_READ_CHIPID_RETRY_DELAY * 1000 + 500); + } + + return -EINVAL; +} + +/****************************************************** + * + * sys group attribute: reg + * + ******************************************************/ +static ssize_t aw8695_i2c_reg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8695 *aw8695 = dev_get_drvdata(dev); + + unsigned int databuf[2] = { 0, 0 }; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + aw8695_i2c_write(aw8695, (unsigned char)databuf[0], + (unsigned char)databuf[1]); + } + + return count; +} + +static ssize_t aw8695_i2c_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw8695 *aw8695 = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for (i = 0; i < AW8695_REG_MAX; i++) { + if (!(aw8695_reg_access[i] & REG_RD_ACCESS)) + continue; + aw8695_i2c_read(aw8695, i, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02x=0x%02x\n", + i, reg_val); + } + return len; +} + +static ssize_t aw8695_i2c_ram_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8695 *aw8695 = dev_get_drvdata(dev); + + unsigned int databuf[1] = { 0 }; + + if (sscanf(buf, "%x", &databuf[0]) == 1) { + if (databuf[0] == 1) + aw8695_ram_update(aw8695); + } + + return count; +} + +static ssize_t aw8695_i2c_ram_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw8695 *aw8695 = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int i = 0; + unsigned char reg_val = 0; + + aw8695_haptic_stop(aw8695); + /* RAMINIT Enable */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_EN); + + aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRH, + (unsigned char)(aw8695->ram.base_addr >> 8)); + aw8695_i2c_write(aw8695, AW8695_REG_RAMADDRL, + (unsigned char)(aw8695->ram.base_addr & 0x00ff)); + len += snprintf(buf + len, PAGE_SIZE - len, "aw8695_haptic_ram:\n"); + for (i = 0; i < aw8695->ram.len; i++) { + aw8695_i2c_read(aw8695, AW8695_REG_RAMDATA, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x,", reg_val); + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + /* RAMINIT Disable */ + aw8695_i2c_write_bits(aw8695, AW8695_REG_SYSCTRL, + AW8695_BIT_SYSCTRL_RAMINIT_MASK, + AW8695_BIT_SYSCTRL_RAMINIT_OFF); + + return len; +} + +static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, aw8695_i2c_reg_show, + aw8695_i2c_reg_store); +static DEVICE_ATTR(ram, S_IWUSR | S_IRUGO, aw8695_i2c_ram_show, + aw8695_i2c_ram_store); + +static struct attribute *aw8695_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_ram.attr, + NULL +}; + +static struct attribute_group aw8695_attribute_group = { + .attrs = aw8695_attributes +}; + +/****************************************************** + * + * i2c driver + * + ******************************************************/ +static int aw8695_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct aw8695 *aw8695; + struct device_node *np = i2c->dev.of_node; + int irq_flags = 0; + int ret = -1; + + pr_info("%s enter\n", __func__); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + aw8695 = devm_kzalloc(&i2c->dev, sizeof(struct aw8695), GFP_KERNEL); + if (aw8695 == NULL) + return -ENOMEM; + + aw8695->dev = &i2c->dev; + aw8695->i2c = i2c; + + i2c_set_clientdata(i2c, aw8695); + + /* aw8695 rst & int */ + if (np) { + ret = aw8695_parse_dt(&i2c->dev, aw8695, np); + if (ret) { + dev_err(&i2c->dev, + "%s: failed to parse device tree node\n", + __func__); + goto err_parse_dt; + } + } else { + aw8695->reset_gpio = -1; + aw8695->irq_gpio = -1; + } + + if (gpio_is_valid(aw8695->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8695->reset_gpio, + GPIOF_OUT_INIT_LOW, "aw8695_rst"); + if (ret) { + dev_err(&i2c->dev, "%s: rst request failed\n", + __func__); + goto err_reset_gpio_request; + } + } + + if (gpio_is_valid(aw8695->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8695->irq_gpio, + GPIOF_DIR_IN, "aw8695_int"); + if (ret) { + dev_err(&i2c->dev, "%s: int request failed\n", + __func__); + goto err_irq_gpio_request; + } + } + + /* aw8695 chip id */ + ret = aw8695_read_chipid(aw8695); + if (ret < 0) { + dev_err(&i2c->dev, "%s: aw8695_read_chipid failed ret=%d\n", + __func__, ret); + i2c_check_status_create("viber_aw8695",0); + goto err_id; + } + + /* aw8695 irq */ + if (gpio_is_valid(aw8695->irq_gpio) && + !(aw8695->flags & AW8695_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + aw8695_interrupt_setup(aw8695); + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(aw8695->irq_gpio), + NULL, aw8695_irq, irq_flags, + "aw8695", aw8695); + if (ret != 0) { + dev_err(&i2c->dev, "%s: failed to request IRQ %d: %d\n", + __func__, gpio_to_irq(aw8695->irq_gpio), ret); + goto err_irq; + } + } else { + dev_info(&i2c->dev, "%s skipping IRQ registration\n", __func__); + /* disable feature support if gpio was invalid */ + aw8695->flags |= AW8695_FLAG_SKIP_INTERRUPTS; + } + + dev_set_drvdata(&i2c->dev, aw8695); + + ret = sysfs_create_group(&i2c->dev.kobj, &aw8695_attribute_group); + if (ret < 0) { + dev_info(&i2c->dev, "%s error creating sysfs attr files\n", + __func__); + goto err_sysfs; + } + + g_aw8695 = aw8695; + + aw8695_vibrator_init(aw8695); + + aw8695_haptic_init(aw8695); + + aw8695_ram_init(aw8695); + + pr_info("%s probe completed successfully!\n", __func__); + i2c_check_status_create("viber_aw8695",1); + return 0; + + err_sysfs: + devm_free_irq(&i2c->dev, gpio_to_irq(aw8695->irq_gpio), aw8695); + err_irq: + err_id: + if (gpio_is_valid(aw8695->irq_gpio)) + devm_gpio_free(&i2c->dev, aw8695->irq_gpio); + err_irq_gpio_request: + if (gpio_is_valid(aw8695->reset_gpio)) + devm_gpio_free(&i2c->dev, aw8695->reset_gpio); + err_reset_gpio_request: + err_parse_dt: + devm_kfree(&i2c->dev, aw8695); + aw8695 = NULL; + return ret; +} + +static int aw8695_i2c_remove(struct i2c_client *i2c) +{ + struct aw8695 *aw8695 = i2c_get_clientdata(i2c); + + pr_info("%s enter\n", __func__); + + sysfs_remove_group(&i2c->dev.kobj, &aw8695_attribute_group); + + devm_free_irq(&i2c->dev, gpio_to_irq(aw8695->irq_gpio), aw8695); + + if (gpio_is_valid(aw8695->irq_gpio)) + devm_gpio_free(&i2c->dev, aw8695->irq_gpio); + if (gpio_is_valid(aw8695->reset_gpio)) + devm_gpio_free(&i2c->dev, aw8695->reset_gpio); + + devm_kfree(&i2c->dev, aw8695); + aw8695 = NULL; + + return 0; +} + +static int aw8695_suspend(struct device *dev) +{ + int ret = 0; + struct aw8695 *aw8695 = dev_get_drvdata(dev); + + mutex_lock(&aw8695->lock); + aw8695_haptic_stop(aw8695); + mutex_unlock(&aw8695->lock); + + return ret; +} + +static int aw8695_resume(struct device *dev) +{ + int ret = 0; + return ret; +} + +static SIMPLE_DEV_PM_OPS(aw8695_pm_ops, aw8695_suspend, aw8695_resume); + +#ifdef AW_UEFI_CAL_F0 +static int __init aw8695_get_f0_cmd(char *str) +{ + + if (kstrtol(str, 10, + (unsigned long *)&aw8695_f0_cal)) { + pr_err("invalid f0 : %s. \n", + str); + } + pr_info("cmdline_f0=%ld \n", aw8695_f0_cal); + + return 0; +} +__setup("haptic_f0:f0=",aw8695_get_f0_cmd); +#endif + +static const struct i2c_device_id aw8695_i2c_id[] = { + {AW8695_I2C_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, aw8695_i2c_id); + +static const struct of_device_id aw8695_dt_match[] = { + {.compatible = "awinic,aw8695_haptic"}, + {}, +}; + +static struct i2c_driver aw8695_i2c_driver = { + .driver = { + .name = AW8695_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw8695_dt_match), +#ifdef CONFIG_PM_SLEEP + .pm = &aw8695_pm_ops, +#endif + }, + .probe = aw8695_i2c_probe, + .remove = aw8695_i2c_remove, + .id_table = aw8695_i2c_id, +}; + +static int __init aw8695_i2c_init(void) +{ + int ret = 0; + + pr_info("aw8695 driver version %s\n", AW8695_DRIVER_VERSION); + + ret = i2c_add_driver(&aw8695_i2c_driver); + if (ret) { + pr_err("fail to add aw8695 device into i2c\n"); + return ret; + } + + return 0; +} + +/* late_initcall(aw8695_i2c_init); */ +module_init(aw8695_i2c_init); + +static void __exit aw8695_i2c_exit(void) +{ + i2c_del_driver(&aw8695_i2c_driver); +} + +module_exit(aw8695_i2c_exit); + +MODULE_DESCRIPTION("AW8695 Haptic Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/aw8695/aw8695.h b/drivers/misc/aw8695/aw8695.h new file mode 100644 index 0000000000000000000000000000000000000000..79b384df0ea1db7a94a52f0a6d8eceb3b20eef49 --- /dev/null +++ b/drivers/misc/aw8695/aw8695.h @@ -0,0 +1,403 @@ +#ifndef _AW8695_H_ +#define _AW8695_H_ + +/********************************************************* + * + * kernel version + * + ********************************************************/ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 4, 1) +#define TIMED_OUTPUT +#endif + +/********************************************************* + * + * aw8695.h + * + ********************************************************/ +#include +#include +#include +#include +#include +#include +#ifdef TIMED_OUTPUT +#include <../../../drivers/staging/android/timed_output.h> +#else +#include +#endif + +/********************************************************* + * + * marco + * + ********************************************************/ +#define AW8695_CHIPID 0x95 + +#define MAX_I2C_BUFFER_SIZE 65536 + +#define AW8695_SEQUENCER_SIZE 8 +#define AW8695_SEQUENCER_LOOP_SIZE 4 + +#define AW8695_RTP_I2C_SINGLE_MAX_NUM 512 + +#define HAPTIC_MAX_TIMEOUT 10000 + +#define AW8695_VBAT_REFER 4200 +#define AW8695_VBAT_MIN 3000 +#define AW8695_VBAT_MAX 4500 + +/* trig config */ +#define AW8695_TRIG_NUM 3 +#define AW8695_TRG1_ENABLE 1 +#define AW8695_TRG2_ENABLE 1 +#define AW8695_TRG3_ENABLE 1 + +/* + * trig default high level + * ___________ _________________ + * | | + * | | + * |___________| + * first edge + * second edge + * + * + * trig default low level + * ___________ + * | | + * | | + * __________| |_________________ + * first edge + * second edge + */ +#define AW8695_TRG1_DEFAULT_LEVEL 1 /* 1: high level; 0: low level */ +#define AW8695_TRG2_DEFAULT_LEVEL 1 /* 1: high level; 0: low level */ +#define AW8695_TRG3_DEFAULT_LEVEL 1 /* 1: high level; 0: low level */ + +#define AW8695_TRG1_DUAL_EDGE 1 /* 1: dual edge; 0: first edge */ +#define AW8695_TRG2_DUAL_EDGE 1 /* 1: dual edge; 0: first edge */ +#define AW8695_TRG3_DUAL_EDGE 1 /* 1: dual edge; 0: first edge */ + +#define AW8695_TRG1_FIRST_EDGE_SEQ 1 /* trig1: first edge waveform seq */ +#define AW8695_TRG1_SECOND_EDGE_SEQ 2 /* trig1: second edge waveform seq */ +#define AW8695_TRG2_FIRST_EDGE_SEQ 1 /* trig2: first edge waveform seq */ +#define AW8695_TRG2_SECOND_EDGE_SEQ 2 /* trig2: second edge waveform seq */ +#define AW8695_TRG3_FIRST_EDGE_SEQ 1 /* trig3: first edge waveform seq */ +#define AW8695_TRG3_SECOND_EDGE_SEQ 2 /* trig3: second edge waveform seq */ + +#if AW8695_TRG1_ENABLE +#define AW8695_TRG1_DEFAULT_ENABLE AW8695_BIT_TRGCFG2_TRG1_ENABLE +#else +#define AW8695_TRG1_DEFAULT_ENABLE AW8695_BIT_TRGCFG2_TRG1_DISABLE +#endif + +#if AW8695_TRG2_ENABLE +#define AW8695_TRG2_DEFAULT_ENABLE AW8695_BIT_TRGCFG2_TRG2_ENABLE +#else +#define AW8695_TRG2_DEFAULT_ENABLE AW8695_BIT_TRGCFG2_TRG2_DISABLE +#endif + +#if AW8695_TRG3_ENABLE +#define AW8695_TRG3_DEFAULT_ENABLE AW8695_BIT_TRGCFG2_TRG3_ENABLE +#else +#define AW8695_TRG3_DEFAULT_ENABLE AW8695_BIT_TRGCFG2_TRG3_DISABLE +#endif + +#if AW8695_TRG1_DEFAULT_LEVEL +#define AW8695_TRG1_DEFAULT_POLAR AW8695_BIT_TRGCFG1_TRG1_POLAR_POS +#else +#define AW8695_TRG1_DEFAULT_POLAR AW8695_BIT_TRGCFG1_TRG1_POLAR_NEG +#endif + +#if AW8695_TRG2_DEFAULT_LEVEL +#define AW8695_TRG2_DEFAULT_POLAR AW8695_BIT_TRGCFG1_TRG2_POLAR_POS +#else +#define AW8695_TRG2_DEFAULT_POLAR AW8695_BIT_TRGCFG1_TRG2_POLAR_NEG +#endif + +#if AW8695_TRG3_DEFAULT_LEVEL +#define AW8695_TRG3_DEFAULT_POLAR AW8695_BIT_TRGCFG1_TRG3_POLAR_POS +#else +#define AW8695_TRG3_DEFAULT_POLAR AW8695_BIT_TRGCFG1_TRG3_POLAR_NEG +#endif + +#if AW8695_TRG1_DUAL_EDGE +#define AW8695_TRG1_DEFAULT_EDGE AW8695_BIT_TRGCFG1_TRG1_EDGE_POS_NEG +#else +#define AW8695_TRG1_DEFAULT_EDGE AW8695_BIT_TRGCFG1_TRG1_EDGE_POS +#endif + +#if AW8695_TRG2_DUAL_EDGE +#define AW8695_TRG2_DEFAULT_EDGE AW8695_BIT_TRGCFG1_TRG2_EDGE_POS_NEG +#else +#define AW8695_TRG2_DEFAULT_EDGE AW8695_BIT_TRGCFG1_TRG2_EDGE_POS +#endif + +#if AW8695_TRG3_DUAL_EDGE +#define AW8695_TRG3_DEFAULT_EDGE AW8695_BIT_TRGCFG1_TRG3_EDGE_POS_NEG +#else +#define AW8695_TRG3_DEFAULT_EDGE AW8695_BIT_TRGCFG1_TRG3_EDGE_POS +#endif + +enum aw8695_flags { + AW8695_FLAG_NONR = 0, + AW8695_FLAG_SKIP_INTERRUPTS = 1, +}; + +enum aw8695_haptic_read_write { + AW8695_HAPTIC_CMD_READ_REG = 0, + AW8695_HAPTIC_CMD_WRITE_REG = 1, +}; + +enum aw8695_haptic_work_mode { + AW8695_HAPTIC_STANDBY_MODE = 0, + AW8695_HAPTIC_RAM_MODE = 1, + AW8695_HAPTIC_RTP_MODE = 2, + AW8695_HAPTIC_TRIG_MODE = 3, + AW8695_HAPTIC_CONT_MODE = 4, + AW8695_HAPTIC_RAM_LOOP_MODE = 5, +}; + +enum aw8695_haptic_bst_mode { + AW8695_HAPTIC_BYPASS_MODE = 0, + AW8695_HAPTIC_BOOST_MODE = 1, +}; + +enum aw8695_haptic_activate_mode { + AW8695_HAPTIC_ACTIVATE_RAM_MODE = 0, + AW8695_HAPTIC_ACTIVATE_CONT_MODE = 1, +}; + +enum aw8695_haptic_cont_vbat_comp_mode { + AW8695_HAPTIC_CONT_VBAT_SW_COMP_MODE = 0, + AW8695_HAPTIC_CONT_VBAT_HW_COMP_MODE = 1, +}; + +enum aw8695_haptic_ram_vbat_comp_mode { + AW8695_HAPTIC_RAM_VBAT_COMP_DISABLE = 0, + AW8695_HAPTIC_RAM_VBAT_COMP_ENABLE = 1, +}; + +enum aw8695_haptic_f0_flag { + AW8695_HAPTIC_LRA_F0 = 0, + AW8695_HAPTIC_CALI_F0 = 1, +}; + +enum aw8695_haptic_pwm_mode { + AW8695_PWM_48K = 0, + AW8695_PWM_24K = 1, + AW8695_PWM_12K = 2, +}; + +enum aw8695_haptic_play { + AW8695_HAPTIC_PLAY_NULL = 0, + AW8695_HAPTIC_PLAY_ENABLE = 1, + AW8695_HAPTIC_PLAY_STOP = 2, + AW8695_HAPTIC_PLAY_GAIN = 8, +}; + +enum aw8695_haptic_cmd { + AW8695_HAPTIC_CMD_NULL = 0, + AW8695_HAPTIC_CMD_ENABLE = 1, + AW8695_HAPTIC_CMD_HAPTIC = 0x0f, + AW8695_HAPTIC_CMD_TP = 0x10, + AW8695_HAPTIC_CMD_SYS = 0xf0, + AW8695_HAPTIC_CMD_STOP = 255, +}; + +/********************************************************* + * + * struct + * + ********************************************************/ +struct fileops { + unsigned char cmd; + unsigned char reg; + unsigned char ram_addrh; + unsigned char ram_addrl; +}; + +struct ram { + unsigned int len; + unsigned int check_sum; + unsigned int base_addr; + unsigned char version; + unsigned char ram_shift; + unsigned char baseaddr_shift; +}; + +struct haptic_ctr { + unsigned char cnt; + unsigned char cmd; + unsigned char play; + unsigned char wavseq; + unsigned char loop; + unsigned char gain; + struct list_head list; +}; + +struct haptic_audio { + struct mutex lock; + struct hrtimer timer; + struct work_struct work; + int delay_val; + int timer_val; + struct haptic_ctr ctr; + struct list_head ctr_list; + /* struct tp tp; */ + struct list_head list; + /* struct haptic_audio_tp_size tp_size; */ + /* struct trust_zone_info output_tz_info[10]; */ + int tz_num; + int tz_high_num; + int tz_cnt_thr; + int tz_cnt_max; + unsigned int uevent_report_flag; + unsigned int hap_cnt_outside_tz; + unsigned int hap_cnt_max_outside_tz; +}; + +struct trig { + unsigned char enable; + unsigned char default_level; + unsigned char dual_edge; + unsigned char frist_seq; + unsigned char second_seq; +}; + +struct aw8695_dts_info { + unsigned int mode; + unsigned int f0_pre; + unsigned int f0_cali_percen; + unsigned int cont_drv_lvl; + unsigned int cont_drv_lvl_ov; + unsigned int cont_td; + unsigned int cont_zc_thr; + unsigned int cont_num_brk; + unsigned int f0_coeff; + unsigned int f0_trace_parameter[4]; + unsigned int bemf_config[4]; + unsigned int sw_brake; + unsigned int tset; + unsigned int r_spare; + unsigned int bstdbg[6]; + unsigned int parameter1; +}; + +struct aw8695 { + struct regmap *regmap; + struct i2c_client *i2c; + struct device *dev; + struct input_dev *input; + + struct mutex lock; + struct mutex rtp_lock; + struct hrtimer timer; + struct work_struct vibrator_work; + struct work_struct rtp_work; + struct delayed_work ram_work; +#ifdef TIMED_OUTPUT + struct timed_output_dev to_dev; +#else + struct led_classdev cdev; +#endif + struct fileops fileops; + struct ram ram; + bool haptic_ready; + bool audio_ready; + int pre_haptic_number; + struct timeval current_time; + struct timeval pre_enter_time; + struct timeval start, end; + unsigned int timeval_flags; + unsigned int osc_cali_flag; + unsigned long int microsecond; + unsigned int sys_frequency; + unsigned int rtp_len; + atomic_t is_rtp; + + int reset_gpio; + int irq_gpio; + + unsigned char hwen_flag; + unsigned char flags; + unsigned char chipid; + + unsigned char play_mode; + + unsigned char activate_mode; + + unsigned char auto_boost; + + int state; + int duration; + int amplitude; + int index; + int vmax; + int gain; + + unsigned int gun_type; //hch 20190917 + unsigned int bullet_nr; //hch 20190917 + unsigned int gun_mode;//hch 20190917 + + unsigned char seq[AW8695_SEQUENCER_SIZE]; + unsigned char loop[AW8695_SEQUENCER_SIZE]; + + unsigned int rtp_cnt; + unsigned int rtp_file_num; + + unsigned char rtp_init; + unsigned char ram_init; + unsigned char rtp_routine_on; + + unsigned int f0; + unsigned int cont_f0; + unsigned char max_pos_beme; + unsigned char max_neg_beme; + unsigned char f0_cali_flag; + unsigned int theory_time; + + unsigned char ram_vbat_comp; + unsigned int vbat; + unsigned int lra; + unsigned int interval_us; + + struct trig trig[AW8695_TRIG_NUM]; + + struct haptic_audio haptic_audio; + struct aw8695_dts_info info; + unsigned int ramupdate_flag; + unsigned int rtpupdate_flag; +}; + +struct aw8695_container { + int len; + unsigned char data[]; +}; + +/********************************************************* + * + * ioctl + * + ********************************************************/ +struct aw8695_seq_loop { + unsigned char loop[AW8695_SEQUENCER_SIZE]; +}; + +struct aw8695_que_seq { + unsigned char index[AW8695_SEQUENCER_SIZE]; +}; + +#define AW8695_HAPTIC_IOCTL_MAGIC 'h' + +#define AW8695_HAPTIC_SET_QUE_SEQ _IOWR(AW8695_HAPTIC_IOCTL_MAGIC, 1, struct aw8695_que_seq*) +#define AW8695_HAPTIC_SET_SEQ_LOOP _IOWR(AW8695_HAPTIC_IOCTL_MAGIC, 2, struct aw8695_seq_loop*) +#define AW8695_HAPTIC_PLAY_QUE_SEQ _IOWR(AW8695_HAPTIC_IOCTL_MAGIC, 3, unsigned int) +#define AW8695_HAPTIC_SET_BST_VOL _IOWR(AW8695_HAPTIC_IOCTL_MAGIC, 4, unsigned int) +#define AW8695_HAPTIC_SET_BST_PEAK_CUR _IOWR(AW8695_HAPTIC_IOCTL_MAGIC, 5, unsigned int) +#define AW8695_HAPTIC_SET_GAIN _IOWR(AW8695_HAPTIC_IOCTL_MAGIC, 6, unsigned int) +#define AW8695_HAPTIC_PLAY_REPEAT_SEQ _IOWR(AW8695_HAPTIC_IOCTL_MAGIC, 7, unsigned int) + +#endif + diff --git a/drivers/misc/aw8695/aw8695_config.h b/drivers/misc/aw8695/aw8695_config.h new file mode 100644 index 0000000000000000000000000000000000000000..4d1453d855bee712cf103a19f02978aa84b55ac9 --- /dev/null +++ b/drivers/misc/aw8695/aw8695_config.h @@ -0,0 +1,10 @@ +#ifndef __AW8695_CONFIG_H__ +#define __AW8695_CONFIG_H__ + +#define AW8695_BSTCFG_PEAKCUR_LIMIT 0x03 +#define AW8695_DEFAULT_PEAKCUR AW8695_BIT_BSTCFG_PEAKCUR_2A + +#define AW8695_CONT_PLAYBACK_MODE AW8695_BIT_CONT_CTRL_CLOSE_PLAYBACK + +#endif + diff --git a/drivers/misc/aw8695/aw8695_reg.h b/drivers/misc/aw8695/aw8695_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..f2e2d3cfc90628d1bc474eed22d7d59809180234 --- /dev/null +++ b/drivers/misc/aw8695/aw8695_reg.h @@ -0,0 +1,541 @@ +#ifndef _AW8695_REG_H_ +#define _AW8695_REG_H_ + +/******************************************** + * Register List + *******************************************/ +#define AW8695_REG_ID 0x00 +#define AW8695_REG_SYSST 0x01 +#define AW8695_REG_SYSINT 0x02 +#define AW8695_REG_SYSINTM 0x03 +#define AW8695_REG_SYSCTRL 0x04 +#define AW8695_REG_GO 0x05 +#define AW8695_REG_RTP_DATA 0x06 +#define AW8695_REG_WAVSEQ1 0x07 +#define AW8695_REG_WAVSEQ2 0x08 +#define AW8695_REG_WAVSEQ3 0x09 +#define AW8695_REG_WAVSEQ4 0x0a +#define AW8695_REG_WAVSEQ5 0x0b +#define AW8695_REG_WAVSEQ6 0x0c +#define AW8695_REG_WAVSEQ7 0x0d +#define AW8695_REG_WAVSEQ8 0x0e +#define AW8695_REG_WAVLOOP1 0x0f +#define AW8695_REG_WAVLOOP2 0x10 +#define AW8695_REG_WAVLOOP3 0x11 +#define AW8695_REG_WAVLOOP4 0x12 +#define AW8695_REG_MAIN_LOOP 0x13 +#define AW8695_REG_TRG1_WAV_P 0x14 +#define AW8695_REG_TRG2_WAV_P 0x15 +#define AW8695_REG_TRG3_WAV_P 0x16 +#define AW8695_REG_TRG1_WAV_N 0x17 +#define AW8695_REG_TRG2_WAV_N 0x18 +#define AW8695_REG_TRG3_WAV_N 0x19 +#define AW8695_REG_TRG_PRIO 0x1a +#define AW8695_REG_TRG_CFG1 0x1b +#define AW8695_REG_TRG_CFG2 0x1c +#define AW8695_REG_DBGCTRL 0x20 +#define AW8695_REG_BASE_ADDRH 0x21 +#define AW8695_REG_BASE_ADDRL 0x22 +#define AW8695_REG_FIFO_AEH 0x23 +#define AW8695_REG_FIFO_AEL 0x24 +#define AW8695_REG_FIFO_AFH 0x25 +#define AW8695_REG_FIFO_AFL 0x26 +#define AW8695_REG_WAKE_DLY 0x27 +#define AW8695_REG_START_DLY 0x28 +#define AW8695_REG_END_DLY_H 0x29 +#define AW8695_REG_END_DLY_L 0x2a +#define AW8695_REG_DATCTRL 0x2b +#define AW8695_REG_PWMDEL 0x2c +#define AW8695_REG_PWMPRC 0x2d +#define AW8695_REG_PWMDBG 0x2e +#define AW8695_REG_LDOCTRL 0x2f +#define AW8695_REG_DBGSTAT 0x30 +#define AW8695_REG_BSTDBG1 0x31 +#define AW8695_REG_BSTDBG2 0x32 +#define AW8695_REG_BSTDBG3 0x33 +#define AW8695_REG_BSTCFG 0x34 +#define AW8695_REG_ANADBG 0x35 +#define AW8695_REG_ANACTRL 0x36 +#define AW8695_REG_CPDBG 0x37 +#define AW8695_REG_GLBDBG 0x38 +#define AW8695_REG_DATDBG 0x39 +#define AW8695_REG_BSTDBG4 0x3a +#define AW8695_REG_BSTDBG5 0x3b +#define AW8695_REG_BSTDBG6 0x3c +#define AW8695_REG_HDRVDBG 0x3d +#define AW8695_REG_PRLVL 0x3e +#define AW8695_REG_PRTIME 0x3f +#define AW8695_REG_RAMADDRH 0x40 +#define AW8695_REG_RAMADDRL 0x41 +#define AW8695_REG_RAMDATA 0x42 +#define AW8695_REG_GLB_STATE 0x46 +#define AW8695_REG_BST_AUTO 0x47 +#define AW8695_REG_CONT_CTRL 0x48 +#define AW8695_REG_F_PRE_H 0x49 +#define AW8695_REG_F_PRE_L 0x4a +#define AW8695_REG_TD_H 0x4b +#define AW8695_REG_TD_L 0x4c +#define AW8695_REG_TSET 0x4d +#define AW8695_REG_TRIM_LRA 0x5b +#define AW8695_REG_R_SPARE 0x5d +#define AW8695_REG_D2SCFG 0x5e +#define AW8695_REG_DETCTRL 0x5f +#define AW8695_REG_RLDET 0x60 +#define AW8695_REG_OSDET 0x61 +#define AW8695_REG_VBATDET 0x62 +#define AW8695_REG_TESTDET 0x63 +#define AW8695_REG_DETLO 0x64 +#define AW8695_REG_BEMFDBG 0x65 +#define AW8695_REG_ADCTEST 0x66 +#define AW8695_REG_BEMFTEST 0x67 +#define AW8695_REG_F_LRA_F0_H 0x68 +#define AW8695_REG_F_LRA_F0_L 0x69 +#define AW8695_REG_F_LRA_CONT_H 0x6a +#define AW8695_REG_F_LRA_CONT_L 0x6b +#define AW8695_REG_WAIT_VOL_MP 0x6d +#define AW8695_REG_WAIT_VOL_MN 0x6f +#define AW8695_REG_BEMF_VOL_H 0x70 +#define AW8695_REG_BEMF_VOL_L 0x71 +#define AW8695_REG_ZC_THRSH_H 0x72 +#define AW8695_REG_ZC_THRSH_L 0x73 +#define AW8695_REG_BEMF_VTHH_H 0x74 +#define AW8695_REG_BEMF_VTHH_L 0x75 +#define AW8695_REG_BEMF_VTHL_H 0x76 +#define AW8695_REG_BEMF_VTHL_L 0x77 +#define AW8695_REG_BEMF_NUM 0x78 +#define AW8695_REG_DRV_TIME 0x79 +#define AW8695_REG_TIME_NZC 0x7a +#define AW8695_REG_DRV_LVL 0x7b +#define AW8695_REG_DRV_LVL_OV 0x7c +#define AW8695_REG_NUM_F0_1 0x7d +#define AW8695_REG_NUM_F0_2 0x7e +#define AW8695_REG_NUM_F0_3 0x7f + +/******************************************** + * Register Access + *******************************************/ +#define REG_NONE_ACCESS 0 +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) +#define AW8695_REG_MAX 0xff + +const unsigned char aw8695_reg_access[AW8695_REG_MAX] = { + [AW8695_REG_ID] = REG_RD_ACCESS, + [AW8695_REG_SYSST] = REG_RD_ACCESS, + [AW8695_REG_SYSINT] = REG_RD_ACCESS, + [AW8695_REG_SYSINTM] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_SYSCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_GO] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_RTP_DATA] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ3] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ4] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ5] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ6] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ7] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVSEQ8] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVLOOP1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVLOOP2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVLOOP3] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAVLOOP4] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_MAIN_LOOP] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG1_WAV_P] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG2_WAV_P] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG3_WAV_P] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG1_WAV_N] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG2_WAV_N] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG3_WAV_N] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG_PRIO] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG_CFG1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRG_CFG2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DBGCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BASE_ADDRH] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BASE_ADDRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_FIFO_AEH] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_FIFO_AEL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_FIFO_AFH] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_FIFO_AFL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAKE_DLY] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_START_DLY] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_END_DLY_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_END_DLY_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DATCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_PWMDEL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_PWMPRC] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_PWMDBG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_LDOCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DBGSTAT] = REG_RD_ACCESS, + [AW8695_REG_BSTDBG1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BSTDBG2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BSTDBG3] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BSTCFG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_ANADBG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_ANACTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_CPDBG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_GLBDBG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DATDBG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BSTDBG4] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BSTDBG5] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BSTDBG6] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_HDRVDBG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_PRLVL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_PRTIME] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_RAMADDRH] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_RAMADDRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_RAMDATA] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_GLB_STATE] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BST_AUTO] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_CONT_CTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_F_PRE_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_F_PRE_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TD_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TD_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TSET] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TRIM_LRA] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_R_SPARE] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_D2SCFG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DETCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_RLDET] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_OSDET] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_VBATDET] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TESTDET] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DETLO] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMFDBG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_ADCTEST] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMFTEST] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_F_LRA_F0_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_F_LRA_F0_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_F_LRA_CONT_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_F_LRA_CONT_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAIT_VOL_MP] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_WAIT_VOL_MN] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMF_VOL_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMF_VOL_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_ZC_THRSH_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_ZC_THRSH_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMF_VTHH_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMF_VTHH_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMF_VTHL_H] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMF_VTHL_L] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_BEMF_NUM] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DRV_TIME] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_TIME_NZC] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DRV_LVL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_DRV_LVL_OV] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_NUM_F0_1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_NUM_F0_2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW8695_REG_NUM_F0_3] = REG_RD_ACCESS | REG_WR_ACCESS, +}; + +/****************************************************** + * Register Detail + *****************************************************/ +/* SYSST: reg0x01 */ +#define AW8695_BIT_SYSST_BSTERRS (1<<7) +#define AW8695_BIT_SYSST_OVS (1<<6) +#define AW8695_BIT_SYSST_UVLS (1<<5) +#define AW8695_BIT_SYSST_FF_AES (1<<4) +#define AW8695_BIT_SYSST_FF_AFS (1<<3) +#define AW8695_BIT_SYSST_OCDS (1<<2) +#define AW8695_BIT_SYSST_OTS (1<<1) +#define AW8695_BIT_SYSST_DONES (1<<0) + +/* SYSINT: reg0x02 */ +#define AW8695_BIT_SYSINT_BSTERRI (1<<7) +#define AW8695_BIT_SYSINT_OVI (1<<6) +#define AW8695_BIT_SYSINT_UVLI (1<<5) +#define AW8695_BIT_SYSINT_FF_AEI (1<<4) +#define AW8695_BIT_SYSINT_FF_AFI (1<<3) +#define AW8695_BIT_SYSINT_OCDI (1<<2) +#define AW8695_BIT_SYSINT_OTI (1<<1) +#define AW8695_BIT_SYSINT_DONEI (1<<0) + +/* SYSINTM: reg0x03 */ +#define AW8695_BIT_SYSINTM_BSTERR_MASK (~(1<<7)) +#define AW8695_BIT_SYSINTM_BSTERR_OFF (1<<7) +#define AW8695_BIT_SYSINTM_BSTERR_EN (0<<7) +#define AW8695_BIT_SYSINTM_OV_MASK (~(1<<6)) +#define AW8695_BIT_SYSINTM_OV_OFF (1<<6) +#define AW8695_BIT_SYSINTM_OV_EN (0<<6) +#define AW8695_BIT_SYSINTM_UVLO_MASK (~(1<<5)) +#define AW8695_BIT_SYSINTM_UVLO_OFF (1<<5) +#define AW8695_BIT_SYSINTM_UVLO_EN (0<<5) +#define AW8695_BIT_SYSINTM_FF_AE_MASK (~(1<<4)) +#define AW8695_BIT_SYSINTM_FF_AE_OFF (1<<4) +#define AW8695_BIT_SYSINTM_FF_AE_EN (0<<4) +#define AW8695_BIT_SYSINTM_FF_AF_MASK (~(1<<3)) +#define AW8695_BIT_SYSINTM_FF_AF_OFF (1<<3) +#define AW8695_BIT_SYSINTM_FF_AF_EN (0<<3) +#define AW8695_BIT_SYSINTM_OCD_MASK (~(1<<2)) +#define AW8695_BIT_SYSINTM_OCD_OFF (1<<2) +#define AW8695_BIT_SYSINTM_OCD_EN (0<<2) +#define AW8695_BIT_SYSINTM_OT_MASK (~(1<<1)) +#define AW8695_BIT_SYSINTM_OT_OFF (1<<1) +#define AW8695_BIT_SYSINTM_OT_EN (0<<1) +#define AW8695_BIT_SYSINTM_DONE_MASK (~(1<<0)) +#define AW8695_BIT_SYSINTM_DONE_OFF (1<<0) +#define AW8695_BIT_SYSINTM_DONE_EN (0<<0) + +/* SYSCTRL: reg0x04 */ +#define AW8695_BIT_SYSCTRL_WAVDAT_MODE_MASK (~(3<<6)) +#define AW8695_BIT_SYSCTRL_WAVDAT_MODE_4X (3<<6) +#define AW8695_BIT_SYSCTRL_WAVDAT_MODE_2X (0<<6) +#define AW8695_BIT_SYSCTRL_WAVDAT_MODE_1X (1<<6) +#define AW8695_BIT_SYSCTRL_RAMINIT_MASK (~(1<<5)) +#define AW8695_BIT_SYSCTRL_RAMINIT_EN (1<<5) +#define AW8695_BIT_SYSCTRL_RAMINIT_OFF (0<<5) +#define AW8695_BIT_SYSCTRL_PLAY_MODE_MASK (~(3<<2)) +#define AW8695_BIT_SYSCTRL_PLAY_MODE_CONT (2<<2) +#define AW8695_BIT_SYSCTRL_PLAY_MODE_RTP (1<<2) +#define AW8695_BIT_SYSCTRL_PLAY_MODE_RAM (0<<2) +#define AW8695_BIT_SYSCTRL_BST_MODE_MASK (~(1<<1)) +#define AW8695_BIT_SYSCTRL_BST_MODE_BOOST (1<<1) +#define AW8695_BIT_SYSCTRL_BST_MODE_BYPASS (0<<1) +#define AW8695_BIT_SYSCTRL_WORK_MODE_MASK (~(1<<0)) +#define AW8695_BIT_SYSCTRL_STANDBY (1<<0) +#define AW8695_BIT_SYSCTRL_ACTIVE (0<<0) + +/* GO: reg0x05 */ +#define AW8695_BIT_GO_MASK (~(1<<0)) +#define AW8695_BIT_GO_ENABLE (1<<0) +#define AW8695_BIT_GO_DISABLE (0<<0) + +/* WAVSEQ1: reg0x07 */ +#define AW8695_BIT_WAVSEQ1_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ1_WAV_FRM_SEQ1_MASK (~(127<<0)) + +/* WAVSEQ2: reg0x08 */ +#define AW8695_BIT_WAVSEQ2_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ2_WAV_FRM_SEQ2_MASK (~(127<<0)) + +/* WAVSEQ3: reg0x09 */ +#define AW8695_BIT_WAVSEQ3_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ3_WAV_FRM_SEQ3_MASK (~(127<<0)) + +/* WAVSEQ4: reg0x0a */ +#define AW8695_BIT_WAVSEQ4_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ4_WAV_FRM_SEQ4_MASK (~(127<<0)) + +/* WAVSEQ5: reg0x0b */ +#define AW8695_BIT_WAVSEQ5_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ5_WAV_FRM_SEQ5_MASK (~(127<<0)) + +/* WAVSEQ6: reg0x0c */ +#define AW8695_BIT_WAVSEQ6_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ6_WAV_FRM_SEQ6_MASK (~(127<<0)) + +/* WAVSEQ7: reg0x0d */ +#define AW8695_BIT_WAVSEQ7_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ7_WAV_FRM_SEQ7_MASK (~(127<<0)) + +/* WAVSEQ8: reg0x0e */ +#define AW8695_BIT_WAVSEQ8_WAIT (1<<7) +#define AW8695_BIT_WAVSEQ8_WAV_FRM_SEQ8_MASK (~(127<<0)) + +/* WAVLOOP: */ +#define AW8695_BIT_WAVLOOP_SEQN_MASK (~(15<<4)) +#define AW8695_BIT_WAVLOOP_SEQNP1_MASK (~(15<<0)) +#define AW8695_BIT_WAVLOOP_INIFINITELY (15<<0) + +/* WAVLOOP1: reg0x0f */ +#define AW8695_BIT_WAVLOOP1_SEQ1_MASK (~(15<<4)) +#define AW8695_BIT_WAVLOOP1_SEQ2_MASK (~(15<<0)) + +/* WAVLOOP2: reg0x10 */ +#define AW8695_BIT_WAVLOOP2_SEQ3_MASK (~(15<<4)) +#define AW8695_BIT_WAVLOOP2_SEQ4_MASK (~(15<<0)) + +/* WAVLOOP3: reg0x11 */ +#define AW8695_BIT_WAVLOOP3_SEQ5_MASK (~(15<<4)) +#define AW8695_BIT_WAVLOOP3_SEQ6_MASK (~(15<<0)) + +/* WAVLOOP4: reg0x12 */ +#define AW8695_BIT_WAVLOOP4_SEQ7_MASK (~(15<<4)) +#define AW8695_BIT_WAVLOOP4_SEQ8_MASK (~(15<<0)) + +/* PLAYPRIO: reg0x1a */ +#define AW8695_BIT_PLAYPRIO_GO_MASK (~(3<<6)) +#define AW8695_BIT_PLAYPRIO_TRIG3_MASK (~(3<<4)) +#define AW8695_BIT_PLAYPRIO_TRIG2_MASK (~(3<<2)) +#define AW8695_BIT_PLAYPRIO_TRIG1_MASK (~(3<<0)) + +/* TRGCFG1: reg0x1b */ +#define AW8695_BIT_TRGCFG1_TRG3_POLAR_MASK (~(1<<5)) +#define AW8695_BIT_TRGCFG1_TRG3_POLAR_NEG (1<<5) +#define AW8695_BIT_TRGCFG1_TRG3_POLAR_POS (0<<5) +#define AW8695_BIT_TRGCFG1_TRG3_EDGE_MASK (~(1<<4)) +#define AW8695_BIT_TRGCFG1_TRG3_EDGE_POS (1<<4) +#define AW8695_BIT_TRGCFG1_TRG3_EDGE_POS_NEG (0<<4) +#define AW8695_BIT_TRGCFG1_TRG2_POLAR_MASK (~(1<<3)) +#define AW8695_BIT_TRGCFG1_TRG2_POLAR_NEG (1<<3) +#define AW8695_BIT_TRGCFG1_TRG2_POLAR_POS (0<<3) +#define AW8695_BIT_TRGCFG1_TRG2_EDGE_MASK (~(1<<2)) +#define AW8695_BIT_TRGCFG1_TRG2_EDGE_POS (1<<2) +#define AW8695_BIT_TRGCFG1_TRG2_EDGE_POS_NEG (0<<2) +#define AW8695_BIT_TRGCFG1_TRG1_POLAR_MASK (~(1<<1)) +#define AW8695_BIT_TRGCFG1_TRG1_POLAR_NEG (1<<1) +#define AW8695_BIT_TRGCFG1_TRG1_POLAR_POS (0<<1) +#define AW8695_BIT_TRGCFG1_TRG1_EDGE_MASK (~(1<<0)) +#define AW8695_BIT_TRGCFG1_TRG1_EDGE_POS (1<<0) +#define AW8695_BIT_TRGCFG1_TRG1_EDGE_POS_NEG (0<<0) + +/* TRGCFG2: reg0x1c */ +#define AW8695_BIT_TRGCFG2_TRG3_ENABLE_MASK (~(1<<2)) +#define AW8695_BIT_TRGCFG2_TRG3_ENABLE (1<<2) +#define AW8695_BIT_TRGCFG2_TRG3_DISABLE (0<<2) +#define AW8695_BIT_TRGCFG2_TRG2_ENABLE_MASK (~(1<<1)) +#define AW8695_BIT_TRGCFG2_TRG2_ENABLE (1<<1) +#define AW8695_BIT_TRGCFG2_TRG2_DISABLE (0<<1) +#define AW8695_BIT_TRGCFG2_TRG1_ENABLE_MASK (~(1<<0)) +#define AW8695_BIT_TRGCFG2_TRG1_ENABLE (1<<0) +#define AW8695_BIT_TRGCFG2_TRG1_DISABLE (0<<0) + +/* DBGCTRL: reg0x20 */ +#define AW8695_BIT_DBGCTRL_INT_EDGE_MODE_MASK (~(1<<3)) +#define AW8695_BIT_DBGCTRL_INT_EDGE_MODE_POS (1<<3) +#define AW8695_BIT_DBGCTRL_INT_EDGE_MODE_BOTH (0<<3) +#define AW8695_BIT_DBGCTRL_INT_MODE_MASK (~(1<<2)) +#define AW8695_BIT_DBGCTRL_INT_MODE_EDGE (1<<2) +#define AW8695_BIT_DBGCTRL_INT_MODE_LEVEL (0<<2) + +/* DATCTRL: reg0x2b */ +#define AW8695_BIT_DATCTRL_FC_MASK (~(1<<6)) +#define AW8695_BIT_DATCTRL_FC_1000HZ (3<<6) +#define AW8695_BIT_DATCTRL_FC_800HZ (3<<6) +#define AW8695_BIT_DATCTRL_FC_600HZ (1<<6) +#define AW8695_BIT_DATCTRL_FC_400HZ (0<<6) +#define AW8695_BIT_DATCTRL_LPF_ENABLE_MASK (~(1<<5)) +#define AW8695_BIT_DATCTRL_LPF_ENABLE (1<<5) +#define AW8695_BIT_DATCTRL_LPF_DISABLE (0<<5) +#define AW8695_BIT_DATCTRL_WAKEMODE_ENABLE_MASK (~(1<<0)) +#define AW8695_BIT_DATCTRL_WAKEMODE_ENABLE (1<<0) +#define AW8695_BIT_DATCTRL_WAKEMODE_DISABLE (0<<0) + +/* PWMPRC: reg0x2d */ +#define AW8695_BIT_PWMPRC_PRC_MASK (~(1<<7)) +#define AW8695_BIT_PWMPRC_PRC_ENABLE (1<<7) +#define AW8695_BIT_PWMPRC_PRC_DISABLE (0<<7) +#define AW8695_BIT_PWMPRC_PRCTIME_MASK (~(0x7f<<0)) + +/* PWMDBG: reg0x2e */ +#define AW8695_BIT_PWMDBG_PWM_MODE_MASK (~(3<<5)) +#define AW8695_BIT_PWMDBG_PWM_12K (3<<5) +#define AW8695_BIT_PWMDBG_PWM_24K (2<<5) +#define AW8695_BIT_PWMDBG_PWM_48K (0<<5) + +/* DBGST: reg0x30 */ +#define AW8695_BIT_DBGSTAT_FF_EMPTY (1<<0) + +/* BSTCFG: reg0x34 */ +#define AW8695_BIT_BSTCFG_PEAKCUR_MASK (~(7<<0)) +#define AW8695_BIT_BSTCFG_PEAKCUR_4A (7<<0) +#define AW8695_BIT_BSTCFG_PEAKCUR_3P75A (6<<0) +#define AW8695_BIT_BSTCFG_PEAKCUR_3P5A (5<<0) +#define AW8695_BIT_BSTCFG_PEAKCUR_3P25A (4<<0) +#define AW8695_BIT_BSTCFG_PEAKCUR_3A (3<<0) +#define AW8695_BIT_BSTCFG_PEAKCUR_2P5A (2<<0) +#define AW8695_BIT_BSTCFG_PEAKCUR_2A (1<<0) +#define AW8695_BIT_BSTCFG_PEAKCUR_1P5A (0<<0) + +/* ANADBG: reg0x35 */ +#define AW8695_BIT_ANADBG_IOC_MASK (~(3<<2)) +#define AW8695_BIT_ANADBG_IOC_4P65A (3<<2) +#define AW8695_BIT_ANADBG_IOC_4P15A (2<<2) +#define AW8695_BIT_ANADBG_IOC_3P65A (1<<2) +#define AW8695_BIT_ANADBG_IOC_3P15A (0<<2) + +/* ANACTRL: reg0x36 */ +#define AW8695_BIT_ANACTRL_LRA_SRC_MASK (~(1<<5)) +#define AW8695_BIT_ANACTRL_LRA_SRC_REG (1<<5) +#define AW8695_BIT_ANACTRL_LRA_SRC_EFUSE (0<<5) +#define AW8695_BIT_ANACTRL_HD_PD_MASK (~(1<<3)) +#define AW8695_BIT_ANACTRL_HD_PD_EN (1<<3) +#define AW8695_BIT_ANACTRL_HD_HZ_EN (0<<3) + +/* BSTDBG4: reg0x3a */ +#define AW8695_BIT_BSTDBG4_BSTVOL_MASK (~(31<<1)) + +/* PRLVL: reg0x3e */ +#define AW8695_BIT_PRLVL_PR_MASK (~(1<<7)) +#define AW8695_BIT_PRLVL_PR_ENABLE (1<<7) +#define AW8695_BIT_PRLVL_PR_DISABLE (0<<7) +#define AW8695_BIT_PRLVL_PRLVL_MASK (~(0x7f<<0)) + +/*PRTIME: reg0x3f */ +#define AW8695_BIT_PRTIME_PRTIME_MASK (~(0xff<<0)) + +/* BST_AUTO: reg0x47 */ +#define AW8695_BIT_BST_AUTO_BST_AUTOSW_MASK (~(1<<2)) +#define AW8695_BIT_BST_AUTO_BST_AUTOMATIC_BOOST (1<<2) +#define AW8695_BIT_BST_AUTO_BST_MANUAL_BOOST (0<<2) +#define AW8695_BIT_BST_AUTO_BST_RTP_MASK (~(1<<1)) +#define AW8695_BIT_BST_AUTO_BST_RTP_ENABLE (1<<1) +#define AW8695_BIT_BST_AUTO_BST_RTP_DISABLE (0<<1) +#define AW8695_BIT_BST_AUTO_BST_RAM_MASK (~(1<<0)) +#define AW8695_BIT_BST_AUTO_BST_RAM_ENABLE (1<<0) +#define AW8695_BIT_BST_AUTO_BST_RAM_DISABLE (0<<0) + +/* CONT_CTRL: reg0x48 */ +#define AW8695_BIT_CONT_CTRL_ZC_DETEC_MASK (~(1<<7)) +#define AW8695_BIT_CONT_CTRL_ZC_DETEC_ENABLE (1<<7) +#define AW8695_BIT_CONT_CTRL_ZC_DETEC_DISABLE (0<<7) +#define AW8695_BIT_CONT_CTRL_WAIT_PERIOD_MASK (~(3<<5)) +#define AW8695_BIT_CONT_CTRL_WAIT_8PERIOD (3<<5) +#define AW8695_BIT_CONT_CTRL_WAIT_4PERIOD (2<<5) +#define AW8695_BIT_CONT_CTRL_WAIT_2PERIOD (1<<5) +#define AW8695_BIT_CONT_CTRL_WAIT_1PERIOD (0<<5) +#define AW8695_BIT_CONT_CTRL_MODE_MASK (~(1<<4)) +#define AW8695_BIT_CONT_CTRL_BY_DRV_TIME (1<<4) +#define AW8695_BIT_CONT_CTRL_BY_GO_SIGNAL (0<<4) +#define AW8695_BIT_CONT_CTRL_EN_CLOSE_MASK (~(1<<3)) +#define AW8695_BIT_CONT_CTRL_CLOSE_PLAYBACK (1<<3) +#define AW8695_BIT_CONT_CTRL_OPEN_PLAYBACK (0<<3) +#define AW8695_BIT_CONT_CTRL_F0_DETECT_MASK (~(1<<2)) +#define AW8695_BIT_CONT_CTRL_F0_DETECT_ENABLE (1<<2) +#define AW8695_BIT_CONT_CTRL_F0_DETECT_DISABLE (0<<2) +#define AW8695_BIT_CONT_CTRL_O2C_MASK (~(1<<1)) +#define AW8695_BIT_CONT_CTRL_O2C_ENABLE (1<<1) +#define AW8695_BIT_CONT_CTRL_O2C_DISABLE (0<<1) +#define AW8695_BIT_CONT_CTRL_AUTO_BRK_MASK (~(1<<0)) +#define AW8695_BIT_CONT_CTRL_AUTO_BRK_ENABLE (1<<0) +#define AW8695_BIT_CONT_CTRL_AUTO_BRK_DISABLE (0<<0) + +/* D2SCFG: reg0x5e */ +#define AW8695_BIT_D2SCFG_CLK_ADC_MASK (~(7<<5)) +#define AW8695_BIT_D2SCFG_CLK_ASC_0P09375MHZ (7<<5) +#define AW8695_BIT_D2SCFG_CLK_ASC_0P1875MHZ (6<<5) +#define AW8695_BIT_D2SCFG_CLK_ASC_0P375MHZ (5<<5) +#define AW8695_BIT_D2SCFG_CLK_ASC_0P75MHZ (4<<5) +#define AW8695_BIT_D2SCFG_CLK_ASC_1P5MHZ (3<<5) +#define AW8695_BIT_D2SCFG_CLK_ASC_3MHZ (2<<5) +#define AW8695_BIT_D2SCFG_CLK_ASC_6MHZ (1<<5) +#define AW8695_BIT_D2SCFG_CLK_ASC_12MHZ (0<<5) + +/* DETCTRL: reg0x5f */ +#define AW8695_BIT_DETCTRL_RL_OS_MASK (~(1<<6)) +#define AW8695_BIT_DETCTRL_RL_DETECT (1<<6) +#define AW8695_BIT_DETCTRL_OS_DETECT (0<<6) +#define AW8695_BIT_DETCTRL_PROTECT_MASK (~(1<<5)) +#define AW8695_BIT_DETCTRL_PROTECT_NO_ACTION (1<<5) +#define AW8695_BIT_DETCTRL_PROTECT_SHUTDOWN (0<<5) +#define AW8695_BIT_DETCTRL_ADO_SLOT_MODE_MASK (~(1<<4)) +#define AW8695_BIT_DETCTRL_ADO_SLOT_MODE_ENABLE (1<<4) +#define AW8695_BIT_DETCTRL_ADO_SLOT_MODE_DISABLE (0<<4) +#define AW8695_BIT_DETCTRL_VBAT_GO_MASK (~(1<<1)) +#define AW8695_BIT_DETCTRL_VABT_GO_ENABLE (1<<1) +#define AW8695_BIT_DETCTRL_VBAT_GO_DISBALE (0<<1) +#define AW8695_BIT_DETCTRL_DIAG_GO_MASK (~(1<<0)) +#define AW8695_BIT_DETCTRL_DIAG_GO_ENABLE (1<<0) +#define AW8695_BIT_DETCTRL_DIAG_GO_DISABLE (0<<0) + +/* ADCTEST: reg0x66 */ +#define AW8695_BIT_ADCTEST_VBAT_MODE_MASK (~(1<<6)) +#define AW8695_BIT_ADCTEST_VBAT_HW_COMP (1<<6) +#define AW8695_BIT_ADCTEST_VBAT_SW_COMP (0<<6) + +/* BEMF_NUM: reg0x78 */ +#define AW8695_BIT_BEMF_NUM_BRK_MASK (~(15<<0)) + +#endif + diff --git a/drivers/misc/fpsensor_chipone/Kconfig b/drivers/misc/fpsensor_chipone/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..1f9e7e5679e13306a6f9b8ae0e1fce72c6e47302 --- /dev/null +++ b/drivers/misc/fpsensor_chipone/Kconfig @@ -0,0 +1,6 @@ +config CHIPONE_FINGERPRINT + tristate "Chipone Finger Print Driver" + help + Chipone Finger Print Supported + + diff --git a/drivers/misc/fpsensor_chipone/Makefile b/drivers/misc/fpsensor_chipone/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c12b0d24284a565e447f8de0eeff2bb81acc0997 --- /dev/null +++ b/drivers/misc/fpsensor_chipone/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CHIPONE_FINGERPRINT) += fpsensor_spi_tee.o diff --git a/drivers/misc/fpsensor_chipone/fpsensor_spi_tee.c b/drivers/misc/fpsensor_chipone/fpsensor_spi_tee.c new file mode 100644 index 0000000000000000000000000000000000000000..563ef5fafe2d85dd1d9c512407a34db010dd868b --- /dev/null +++ b/drivers/misc/fpsensor_chipone/fpsensor_spi_tee.c @@ -0,0 +1,741 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_COMPAT +#include +#endif + +#include "fpsensor_spi_tee.h" +#include "fpsensor_wakelock.h" +#define FPSENSOR_FB_DRM 1 +#define FPSENSOR_FB_OLD 2 + +#define FPSENSOR_WAKEUP_SOURCE 1 +#define FPSENSOR_WAKEUP_OLD 2 + +#define FPSENSOR_SPI_VERSION "fpsensor_spi_tee_qcomm_v1.23.1" +#define FPSENSOR_USE_QCOM_POWER_GPIO 1 +#define FPSENSOR_WAKEUP_TYPE FPSENSOR_WAKEUP_SOURCE +#define FP_NOTIFY 1 +#define FP_NOTIFY_TYPE FPSENSOR_FB_DRM + +#if FP_NOTIFY +#if FP_NOTIFY_TYPE == FPSENSOR_FB_DRM +#include +#define FP_NOTIFY_ON MSM_DRM_BLANK_UNBLANK +#define FP_NOTIFY_OFF MSM_DRM_BLANK_POWERDOWN +#define FP_NOTIFY_EVENT_BLANK MSM_DRM_EARLY_EVENT_BLANK //MSM_DRM_EVENT_BLANK +#define fpsensor_fb_register_client(client) msm_drm_register_client(client); +#define fpsensor_fb_unregister_client(client) msm_drm_unregister_client(client); +#else +#define FP_NOTIFY_ON FB_BLANK_UNBLANK +#define FP_NOTIFY_OFF FB_BLANK_POWERDOWN +#define FP_NOTIFY_EVENT_BLANK FB_EVENT_BLANK +#define fpsensor_fb_register_client(client) fb_register_client(client); +#define fpsensor_fb_unregister_client(client) fb_unregister_client(client) +#endif +#endif + +/* debug log setting */ +static u8 fpsensor_debug_level = INFO_LOG; +/* global variables */ +static fpsensor_data_t *g_fpsensor = NULL; +uint32_t g_cmd_sn = 0; + +#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE +#include +#include +struct wakeup_source g_ttw_wl; +struct wakeup_source *p_g_ttw_wl; +#else +#include +struct wake_lock g_ttw_wl; +#endif + +/* -------------------------------------------------------------------- */ +/* fingerprint chip hardware configuration */ +/* -------------------------------------------------------------------- */ +static void fpsensor_gpio_free(fpsensor_data_t *fpsensor) +{ + struct device *dev = &fpsensor->spi->dev; + + if (fpsensor->irq_gpio != 0 ) { + devm_gpio_free(dev, fpsensor->irq_gpio); + fpsensor->irq_gpio = 0; + } + if (fpsensor->reset_gpio != 0) { + devm_gpio_free(dev, fpsensor->reset_gpio); + fpsensor->reset_gpio = 0; + } +#if FPSENSOR_USE_QCOM_POWER_GPIO + if (fpsensor->power_gpio != 0) { + devm_gpio_free(dev, fpsensor->power_gpio); + fpsensor->power_gpio = 0; + } +#endif +} + +static void fpsensor_irq_gpio_cfg(fpsensor_data_t *fpsensor) +{ + int error = 0; + + error = gpio_direction_input(fpsensor->irq_gpio); + if (error) { + fpsensor_debug(ERR_LOG, "setup fpsensor irq gpio for input failed!error[%d]\n", error); + return ; + } + + fpsensor->irq = gpio_to_irq(fpsensor->irq_gpio); + fpsensor_debug(DEBUG_LOG, "fpsensor irq number[%d]\n", fpsensor->irq); + if (fpsensor->irq <= 0) { + fpsensor_debug(ERR_LOG, "fpsensor irq gpio to irq failed!\n"); + return ; + } + + return; +} + +static int fpsensor_request_named_gpio(fpsensor_data_t *fpsensor_dev, const char *label, int *gpio) +{ + struct device *dev = &fpsensor_dev->spi->dev; + struct device_node *np = dev->of_node; + int ret = of_get_named_gpio(np, label, 0); + + if (ret < 0) { + fpsensor_debug(ERR_LOG, "failed to get '%s'\n", label); + return ret; + } + *gpio = ret; + ret = devm_gpio_request(dev, *gpio, label); + if (ret) { + fpsensor_debug(ERR_LOG, "failed to request gpio %d\n", *gpio); + return ret; + } + + fpsensor_debug(ERR_LOG, "%s %d\n", label, *gpio); + return ret; +} + +/* delay us after reset */ +static void fpsensor_hw_reset(int delay) +{ + FUNC_ENTRY(); + gpio_set_value(g_fpsensor->reset_gpio, 1); + + udelay(100); + gpio_set_value(g_fpsensor->reset_gpio, 0); + + udelay(1000); + gpio_set_value(g_fpsensor->reset_gpio, 1); + + if (delay) { + udelay(delay); + } + + FUNC_EXIT(); + return; +} + +static int fpsensor_get_gpio_dts_info(fpsensor_data_t *fpsensor) +{ + int ret = 0; + + FUNC_ENTRY(); + // get interrupt gpio resource + ret = fpsensor_request_named_gpio(fpsensor, "fp-gpio-int", &fpsensor->irq_gpio); + if (ret) { + fpsensor_debug(ERR_LOG, "Failed to request irq GPIO. ret = %d\n", ret); + return -1; + } + + // get reest gpio resourece + ret = fpsensor_request_named_gpio(fpsensor, "fp-gpio-reset", &fpsensor->reset_gpio); + if (ret) { + fpsensor_debug(ERR_LOG, "Failed to request reset GPIO. ret = %d\n", ret); + return -1; + } +#if FPSENSOR_USE_QCOM_POWER_GPIO + // get power gpio resourece + ret = fpsensor_request_named_gpio(fpsensor, "fp-gpio-power", &fpsensor->power_gpio); + if (ret) { + fpsensor_debug(ERR_LOG, "Failed to request power GPIO. ret = %d\n", ret); + return -1; + } + // set power direction output + gpio_direction_output(fpsensor->power_gpio, 1); + gpio_set_value(fpsensor->power_gpio, 1); +#endif + // set reset direction output + gpio_direction_output(fpsensor->reset_gpio, 1); + fpsensor_hw_reset(1250); + + return ret; +} + +static void setRcvIRQ(int val) +{ + fpsensor_data_t *fpsensor_dev = g_fpsensor; + fpsensor_dev->RcvIRQ = val; +} + +static void fpsensor_enable_irq(fpsensor_data_t *fpsensor_dev) +{ + FUNC_ENTRY(); + setRcvIRQ(0); + /* Request that the interrupt should be wakeable */ + if (fpsensor_dev->irq_enabled == 0) { + enable_irq(fpsensor_dev->irq); + fpsensor_dev->irq_enabled = 1; + } + FUNC_EXIT(); + return; +} + +static void fpsensor_disable_irq(fpsensor_data_t *fpsensor_dev) +{ + FUNC_ENTRY(); + + if (0 == fpsensor_dev->device_available) { + fpsensor_debug(ERR_LOG, "%s, devices not available\n", __func__); + goto out; + } + + if (0 == fpsensor_dev->irq_enabled) { + fpsensor_debug(ERR_LOG, "%s, irq already disabled\n", __func__); + goto out; + } + + if (fpsensor_dev->irq) { + disable_irq_nosync(fpsensor_dev->irq); + fpsensor_debug(DEBUG_LOG, "%s disable interrupt!\n", __func__); + } + fpsensor_dev->irq_enabled = 0; + +out: + setRcvIRQ(0); + FUNC_EXIT(); + return; +} + +static irqreturn_t fpsensor_irq(int irq, void *handle) +{ + fpsensor_data_t *fpsensor_dev = (fpsensor_data_t *)handle; + + /* Make sure 'wakeup_enabled' is updated before using it + ** since this is interrupt context (other thread...) */ + smp_rmb(); +#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE + __pm_wakeup_event(&g_ttw_wl, 1000); +#else + wake_lock_timeout(&g_ttw_wl, msecs_to_jiffies(1000)); +#endif + setRcvIRQ(1); + wake_up_interruptible(&fpsensor_dev->wq_irq_return); + + return IRQ_HANDLED; +} + +// release and cleanup fpsensor char device +static void fpsensor_dev_cleanup(fpsensor_data_t *fpsensor) +{ + FUNC_ENTRY(); + + cdev_del(&fpsensor->cdev); + unregister_chrdev_region(fpsensor->devno, FPSENSOR_NR_DEVS); + device_destroy(fpsensor->class, fpsensor->devno); + class_destroy(fpsensor->class); + + FUNC_EXIT(); +} + +static long fpsensor_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + fpsensor_data_t *fpsensor_dev = NULL; + int retval = 0; + uint32_t val = 0; + int irqf; + + fpsensor_debug(INFO_LOG, "[rickon]: fpsensor ioctl cmd : 0x%x \n", cmd ); + fpsensor_dev = (fpsensor_data_t *)filp->private_data; + fpsensor_dev->cancel = 0 ; + switch (cmd) { + case FPSENSOR_IOC_INIT: + fpsensor_debug(INFO_LOG, "%s: fpsensor init started======\n", __func__); + retval = fpsensor_get_gpio_dts_info(fpsensor_dev); + if (retval) { + break; + } + fpsensor_irq_gpio_cfg(fpsensor_dev); + //regist irq + irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT; + retval = devm_request_threaded_irq(&g_fpsensor->spi->dev, g_fpsensor->irq, fpsensor_irq, + NULL, irqf, dev_name(&g_fpsensor->spi->dev), g_fpsensor); + if (retval == 0) { + fpsensor_debug(INFO_LOG, " irq thread reqquest success!\n"); + } else { + fpsensor_debug(INFO_LOG, " irq thread request failed , retval =%d \n", retval); + break; + } + enable_irq_wake(g_fpsensor->irq); + fpsensor_dev->device_available = 1; + // fix Unbalanced enable for IRQ, disable irq at first + fpsensor_dev->irq_enabled = 1; + fpsensor_disable_irq(fpsensor_dev); + fpsensor_debug(INFO_LOG, "%s: fpsensor init finished======\n", __func__); + break; + + case FPSENSOR_IOC_EXIT: + fpsensor_disable_irq(fpsensor_dev); + if (fpsensor_dev->irq) { + free_irq(fpsensor_dev->irq, fpsensor_dev); + fpsensor_dev->irq_enabled = 0; + } + fpsensor_dev->device_available = 0; + fpsensor_gpio_free(fpsensor_dev); + fpsensor_debug(INFO_LOG, "%s: fpsensor exit finished======\n", __func__); + break; + + case FPSENSOR_IOC_RESET: + fpsensor_debug(INFO_LOG, "%s: chip reset command\n", __func__); + fpsensor_hw_reset(1250); + break; + + case FPSENSOR_IOC_ENABLE_IRQ: + fpsensor_debug(INFO_LOG, "%s: chip ENable IRQ command\n", __func__); + fpsensor_enable_irq(fpsensor_dev); + break; + + case FPSENSOR_IOC_DISABLE_IRQ: + fpsensor_debug(INFO_LOG, "%s: chip disable IRQ command\n", __func__); + fpsensor_disable_irq(fpsensor_dev); + break; + case FPSENSOR_IOC_GET_INT_VAL: + val = gpio_get_value(fpsensor_dev->irq_gpio); + if (copy_to_user((void __user *)arg, (void *)&val, sizeof(uint32_t))) { + fpsensor_debug(ERR_LOG, "Failed to copy data to user\n"); + retval = -EFAULT; + break; + } + retval = 0; + break; + case FPSENSOR_IOC_ENABLE_SPI_CLK: + fpsensor_debug(INFO_LOG, "%s: ENABLE_SPI_CLK ======\n", __func__); + break; + case FPSENSOR_IOC_DISABLE_SPI_CLK: + fpsensor_debug(INFO_LOG, "%s: DISABLE_SPI_CLK ======\n", __func__); + break; + case FPSENSOR_IOC_ENABLE_POWER: + fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_ENABLE_POWER ======\n", __func__); + break; + case FPSENSOR_IOC_DISABLE_POWER: + fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_DISABLE_POWER ======\n", __func__); + break; + case FPSENSOR_IOC_REMOVE: + fpsensor_disable_irq(fpsensor_dev); + if (fpsensor_dev->irq) { + free_irq(fpsensor_dev->irq, fpsensor_dev); + fpsensor_dev->irq_enabled = 0; + } + fpsensor_dev->device_available = 0; + fpsensor_gpio_free(fpsensor_dev); + fpsensor_dev_cleanup(fpsensor_dev); +#if FP_NOTIFY + fpsensor_fb_unregister_client(&fpsensor_dev->notifier); +#endif + fpsensor_dev->free_flag = 1; + fpsensor_debug(INFO_LOG, "%s remove finished\n", __func__); + break; + case FPSENSOR_IOC_CANCEL_WAIT: + fpsensor_debug(INFO_LOG, "%s: FPSENSOR CANCEL WAIT\n", __func__); + wake_up_interruptible(&fpsensor_dev->wq_irq_return); + fpsensor_dev->cancel = 1; + break; +#if FP_NOTIFY + case FPSENSOR_IOC_GET_FP_STATUS : + val = fpsensor_dev->fb_status; + fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_GET_FP_STATUS %d \n",__func__, fpsensor_dev->fb_status); + if (copy_to_user((void __user *)arg, (void *)&val, sizeof(uint32_t))) { + fpsensor_debug(ERR_LOG, "Failed to copy data to user\n"); + retval = -EFAULT; + break; + } + retval = 0; + break; +#endif + case FPSENSOR_IOC_ENABLE_REPORT_BLANKON: + if (copy_from_user(&val, (void __user *)arg, sizeof(uint32_t))) { + retval = -EFAULT; + break; + } + fpsensor_dev->enable_report_blankon = val; + fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_ENABLE_REPORT_BLANKON: %d\n", __func__, val); + break; + case FPSENSOR_IOC_UPDATE_DRIVER_SN: + if (copy_from_user(&g_cmd_sn, (void __user *)arg, sizeof(uint32_t))) { + fpsensor_debug(ERR_LOG, "Failed to copy g_cmd_sn from user to kernel\n"); + retval = -EFAULT; + break; + } + //fpsensor_debug(INFO_LOG, "%s: FPSENSOR_IOC_UPDATE_DRIVER_SN: %d\n", __func__, g_cmd_sn); + break; + default: + fpsensor_debug(ERR_LOG, "fpsensor doesn't support this command(0x%x)\n", cmd); + break; + } + + //FUNC_EXIT(); + return retval; +} + +static long fpsensor_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return fpsensor_ioctl(filp, cmd, (unsigned long)(arg)); +} + +static unsigned int fpsensor_poll(struct file *filp, struct poll_table_struct *wait) +{ + unsigned int ret = 0; + + ret |= POLLIN; + poll_wait(filp, &g_fpsensor->wq_irq_return, wait); + if (g_fpsensor->cancel == 1) { + fpsensor_debug(ERR_LOG, " cancle\n"); + ret = POLLERR; + g_fpsensor->cancel = 0; + return ret; + } + + if ( g_fpsensor->RcvIRQ) { + if (g_fpsensor->RcvIRQ == 2) { + fpsensor_debug(ERR_LOG, " get fp on notify\n"); + ret |= POLLHUP; + } else { + fpsensor_debug(ERR_LOG, " get irq\n"); + ret |= POLLRDNORM; + } + } else { + ret = 0; + } + return ret; +} + +static int fpsensor_open(struct inode *inode, struct file *filp) +{ + fpsensor_data_t *fpsensor_dev; + + FUNC_ENTRY(); + fpsensor_dev = container_of(inode->i_cdev, fpsensor_data_t, cdev); + fpsensor_dev->users++; + fpsensor_dev->device_available = 1; + filp->private_data = fpsensor_dev; + FUNC_EXIT(); + return 0; +} + +static int fpsensor_release(struct inode *inode, struct file *filp) +{ + fpsensor_data_t *fpsensor_dev; + int status = 0; + + FUNC_ENTRY(); + fpsensor_dev = filp->private_data; + filp->private_data = NULL; + + /*last close??*/ + fpsensor_dev->users--; + if (fpsensor_dev->users <= 0) { + fpsensor_debug(INFO_LOG, "%s, disble_irq. irq = %d\n", __func__, fpsensor_dev->irq); + fpsensor_disable_irq(fpsensor_dev); + } + fpsensor_dev->device_available = 0; + FUNC_EXIT(); + return status; +} + +static ssize_t fpsensor_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + fpsensor_debug(ERR_LOG, "Not support read opertion in TEE version\n"); + return -EFAULT; +} + +static ssize_t fpsensor_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + fpsensor_debug(ERR_LOG, "Not support write opertion in TEE version\n"); + return -EFAULT; +} + +static const struct file_operations fpsensor_fops = { + .owner = THIS_MODULE, + .write = fpsensor_write, + .read = fpsensor_read, + .unlocked_ioctl = fpsensor_ioctl, + .compat_ioctl = fpsensor_compat_ioctl, + .open = fpsensor_open, + .release = fpsensor_release, + .poll = fpsensor_poll, + +}; + +// create and register a char device for fpsensor +static int fpsensor_dev_setup(fpsensor_data_t *fpsensor) +{ + int ret = 0; + dev_t dev_no = 0; + struct device *dev = NULL; + int fpsensor_dev_major = FPSENSOR_DEV_MAJOR; + int fpsensor_dev_minor = 0; + + FUNC_ENTRY(); + + if (fpsensor_dev_major) { + dev_no = MKDEV(fpsensor_dev_major, fpsensor_dev_minor); + ret = register_chrdev_region(dev_no, FPSENSOR_NR_DEVS, FPSENSOR_DEV_NAME); + } else { + ret = alloc_chrdev_region(&dev_no, fpsensor_dev_minor, FPSENSOR_NR_DEVS, FPSENSOR_DEV_NAME); + fpsensor_dev_major = MAJOR(dev_no); + fpsensor_dev_minor = MINOR(dev_no); + fpsensor_debug(INFO_LOG, "fpsensor device major is %d, minor is %d\n", + fpsensor_dev_major, fpsensor_dev_minor); + } + + if (ret < 0) { + fpsensor_debug(ERR_LOG, "can not get device major number %d\n", fpsensor_dev_major); + goto out; + } + + cdev_init(&fpsensor->cdev, &fpsensor_fops); + fpsensor->cdev.owner = THIS_MODULE; + fpsensor->cdev.ops = &fpsensor_fops; + fpsensor->devno = dev_no; + ret = cdev_add(&fpsensor->cdev, dev_no, FPSENSOR_NR_DEVS); + if (ret) { + fpsensor_debug(ERR_LOG, "add char dev for fpsensor failed\n"); + goto release_region; + } + + fpsensor->class = class_create(THIS_MODULE, FPSENSOR_CLASS_NAME); + if (IS_ERR(fpsensor->class)) { + fpsensor_debug(ERR_LOG, "create fpsensor class failed\n"); + ret = PTR_ERR(fpsensor->class); + goto release_cdev; + } + + dev = device_create(fpsensor->class, &fpsensor->spi->dev, dev_no, fpsensor, FPSENSOR_DEV_NAME); + if (IS_ERR(dev)) { + fpsensor_debug(ERR_LOG, "create device for fpsensor failed\n"); + ret = PTR_ERR(dev); + goto release_class; + } + FUNC_EXIT(); + return ret; + +release_class: + class_destroy(fpsensor->class); + fpsensor->class = NULL; +release_cdev: + cdev_del(&fpsensor->cdev); +release_region: + unregister_chrdev_region(dev_no, FPSENSOR_NR_DEVS); +out: + FUNC_EXIT(); + return ret; +} + +#if FP_NOTIFY +static int fpsensor_fb_notifier_callback(struct notifier_block* self, unsigned long event, void* data) +{ + int retval = 0; + static char screen_status[64] = { '\0' }; + struct fb_event* evdata = data; + unsigned int blank; + fpsensor_data_t *fpsensor_dev = g_fpsensor; + + fpsensor_debug(INFO_LOG,"%s enter, event: 0x%x\n", __func__, (unsigned)event); + if (event != FP_NOTIFY_EVENT_BLANK) { + return 0; + } + + blank = *(int*)evdata->data; + fpsensor_debug(INFO_LOG,"%s enter, blank=0x%x\n", __func__, blank); + + switch (blank) { + case FP_NOTIFY_ON: + fpsensor_debug(INFO_LOG,"%s: lcd on notify\n", __func__); + sprintf(screen_status, "SCREEN_STATUS=%s", "ON"); + fpsensor_dev->fb_status = 1; + if( fpsensor_dev->enable_report_blankon) { + fpsensor_dev->RcvIRQ = 2; + wake_up_interruptible(&fpsensor_dev->wq_irq_return); + } + break; + + case FP_NOTIFY_OFF: + fpsensor_debug(INFO_LOG,"%s: lcd off notify\n", __func__); + sprintf(screen_status, "SCREEN_STATUS=%s", "OFF"); + fpsensor_dev->fb_status = 0; + break; + + default: + fpsensor_debug(INFO_LOG,"%s: other notifier, ignore\n", __func__); + break; + } + + fpsensor_debug(INFO_LOG,"%s %s leave.\n", screen_status, __func__); + return retval; +} +#endif + +static int fpsensor_probe(struct platform_device *pdev) +{ + int status = 0; + fpsensor_data_t *fpsensor_dev = NULL; + + FUNC_ENTRY(); + + /* Allocate driver data */ + fpsensor_dev = kzalloc(sizeof(*fpsensor_dev), GFP_KERNEL); + if (!fpsensor_dev) { + status = -ENOMEM; + fpsensor_debug(ERR_LOG, "%s, Failed to alloc memory for fpsensor device.\n", __func__); + goto out; + } + + /* Initialize the driver data */ + g_fpsensor = fpsensor_dev; + fpsensor_dev->spi = pdev ; + fpsensor_dev->device_available = 0; + fpsensor_dev->users = 0; + fpsensor_dev->irq = 0; + fpsensor_dev->power_gpio = 0; + fpsensor_dev->reset_gpio = 0; + fpsensor_dev->irq_gpio = 0; + fpsensor_dev->irq_enabled = 0; + fpsensor_dev->free_flag = 0; + fpsensor_dev->fb_status = 1; + /* setup a char device for fpsensor */ + status = fpsensor_dev_setup(fpsensor_dev); + if (status) { + fpsensor_debug(ERR_LOG, "fpsensor setup char device failed, %d", status); + goto release_drv_data; + } + init_waitqueue_head(&fpsensor_dev->wq_irq_return); +#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE + //wakeup_source_init(&g_ttw_wl, "fpsensor_ttw_wl"); + //&g_ttw_wl = wakeup_source_create("fpsensor_ttw_wl"); + p_g_ttw_wl = wakeup_source_register(NULL, "fpsensor_ttw_wl"); + g_ttw_wl = *p_g_ttw_wl; +#else + wake_lock_init(&g_ttw_wl, WAKE_LOCK_SUSPEND, "fpsensor_ttw_wl"); +#endif + fpsensor_dev->device_available = 1; +#if FP_NOTIFY + fpsensor_dev->notifier.notifier_call = fpsensor_fb_notifier_callback; + fpsensor_fb_register_client(&fpsensor_dev->notifier); +#endif + + fpsensor_debug(INFO_LOG, "%s finished, driver version: %s\n", __func__, FPSENSOR_SPI_VERSION); + goto out; + +release_drv_data: + kfree(fpsensor_dev); + fpsensor_dev = NULL; +out: + FUNC_EXIT(); + return status; +} + +static int fpsensor_remove(struct platform_device *pdev) +{ + fpsensor_data_t *fpsensor_dev = g_fpsensor; + + FUNC_ENTRY(); + fpsensor_disable_irq(fpsensor_dev); + if (fpsensor_dev->irq) + free_irq(fpsensor_dev->irq, fpsensor_dev); + +#if FP_NOTIFY + fpsensor_fb_unregister_client(&fpsensor_dev->notifier); +#endif + fpsensor_gpio_free(fpsensor_dev); + fpsensor_dev_cleanup(fpsensor_dev); +#if FPSENSOR_WAKEUP_TYPE == FPSENSOR_WAKEUP_SOURCE +// wakeup_source_trash(&g_ttw_wl); +// wakeup_source_destroy(&g_ttw_wl); + wakeup_source_unregister(&g_ttw_wl); +#else + wake_lock_destroy(&g_ttw_wl); +#endif + kfree(fpsensor_dev); + g_fpsensor = NULL; + + FUNC_EXIT(); + return 0; +} + +static int fpsensor_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int fpsensor_resume( struct platform_device *pdev) +{ + return 0; +} + +#ifdef CONFIG_OF +static struct of_device_id fpsensor_of_match[] = { + { .compatible = "qcom,fingerprint-gpio" }, + {} +}; +//MODULE_DEVICE_TABLE(of, fpsensor_of_match); +#endif + +static struct platform_driver fpsensor_driver = { + .driver = { + .name = FPSENSOR_DEV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = fpsensor_of_match, +#endif + }, + .probe = fpsensor_probe, + .remove = fpsensor_remove, + .suspend = fpsensor_suspend, + .resume = fpsensor_resume, +}; + +static int __init fpsensor_init(void) +{ + int status; + + status = platform_driver_register(&fpsensor_driver); + if (status < 0) { + fpsensor_debug(ERR_LOG, "%s, Failed to register SPI driver.\n", __func__); + } + + return status; +} +module_init(fpsensor_init); + +static void __exit fpsensor_exit(void) +{ + platform_driver_unregister(&fpsensor_driver); +} +module_exit(fpsensor_exit); + +MODULE_AUTHOR("xhli"); +MODULE_DESCRIPTION(" Fingerprint chip TEE driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:fpsensor-drivers"); diff --git a/drivers/misc/fpsensor_chipone/fpsensor_spi_tee.h b/drivers/misc/fpsensor_chipone/fpsensor_spi_tee.h new file mode 100644 index 0000000000000000000000000000000000000000..d221490073e2181ca52b6fee84eba458512dc4e5 --- /dev/null +++ b/drivers/misc/fpsensor_chipone/fpsensor_spi_tee.h @@ -0,0 +1,69 @@ +#ifndef __FPSENSOR_SPI_TEE_H +#define __FPSENSOR_SPI_TEE_H + +#include +#include +#include +#include +#include + +#define FPSENSOR_DEV_NAME "fpsensor" +#define FPSENSOR_CLASS_NAME "fpsensor" +#define FPSENSOR_DEV_MAJOR 0 +#define N_SPI_MINORS 32 /* ... up to 256 */ +#define FPSENSOR_NR_DEVS 1 + +#define ERR_LOG (0) +#define INFO_LOG (1) +#define DEBUG_LOG (2) +#define fpsensor_debug(level, fmt, args...) do { \ + if (fpsensor_debug_level >= level) {\ + printk("[fpCoreDriver][SN=%d] " fmt, g_cmd_sn, ##args); \ + } \ + } while (0) +#define FUNC_ENTRY() fpsensor_debug(DEBUG_LOG, "%s, %d, entry\n", __func__, __LINE__) +#define FUNC_EXIT() fpsensor_debug(DEBUG_LOG, "%s, %d, exit\n", __func__, __LINE__) + +/**********************IO Magic**********************/ +#define FPSENSOR_IOC_MAGIC 0xf0 //CHIP + +/* define commands */ +#define FPSENSOR_IOC_INIT _IOWR(FPSENSOR_IOC_MAGIC,0,uint32_t) +#define FPSENSOR_IOC_EXIT _IOWR(FPSENSOR_IOC_MAGIC,1,uint32_t) +#define FPSENSOR_IOC_RESET _IOWR(FPSENSOR_IOC_MAGIC,2,uint32_t) +#define FPSENSOR_IOC_ENABLE_IRQ _IOWR(FPSENSOR_IOC_MAGIC,3,uint32_t) +#define FPSENSOR_IOC_DISABLE_IRQ _IOWR(FPSENSOR_IOC_MAGIC,4,uint32_t) +#define FPSENSOR_IOC_GET_INT_VAL _IOWR(FPSENSOR_IOC_MAGIC,5,uint32_t) +#define FPSENSOR_IOC_DISABLE_SPI_CLK _IOWR(FPSENSOR_IOC_MAGIC,6,uint32_t) +#define FPSENSOR_IOC_ENABLE_SPI_CLK _IOWR(FPSENSOR_IOC_MAGIC,7,uint32_t) +#define FPSENSOR_IOC_ENABLE_POWER _IOWR(FPSENSOR_IOC_MAGIC,8,uint32_t) +#define FPSENSOR_IOC_DISABLE_POWER _IOWR(FPSENSOR_IOC_MAGIC,9,uint32_t) +/* fp sensor has change to sleep mode while screen off */ +#define FPSENSOR_IOC_ENTER_SLEEP_MODE _IOWR(FPSENSOR_IOC_MAGIC,11,uint32_t) +#define FPSENSOR_IOC_REMOVE _IOWR(FPSENSOR_IOC_MAGIC,12,uint32_t) +#define FPSENSOR_IOC_CANCEL_WAIT _IOWR(FPSENSOR_IOC_MAGIC,13,uint32_t) +#define FPSENSOR_IOC_GET_FP_STATUS _IOWR(FPSENSOR_IOC_MAGIC,19,uint32_t) +#define FPSENSOR_IOC_ENABLE_REPORT_BLANKON _IOWR(FPSENSOR_IOC_MAGIC,21,uint32_t) +#define FPSENSOR_IOC_UPDATE_DRIVER_SN _IOWR(FPSENSOR_IOC_MAGIC,22,uint32_t) +typedef struct { + dev_t devno; + struct class *class; + struct cdev cdev; + struct platform_device *spi; + unsigned int users; + u8 device_available; /* changed during fingerprint chip sleep and wakeup phase */ + u8 irq_enabled; + volatile unsigned int RcvIRQ; + int irq; + int irq_gpio; + int reset_gpio; + int power_gpio; + wait_queue_head_t wq_irq_return; + int cancel; + struct notifier_block notifier; + u8 fb_status; + int enable_report_blankon; + int free_flag; +} fpsensor_data_t; + +#endif /* __FPSENSOR_SPI_TEE_H */ diff --git a/drivers/misc/fpsensor_chipone/fpsensor_wakelock.h b/drivers/misc/fpsensor_chipone/fpsensor_wakelock.h new file mode 100644 index 0000000000000000000000000000000000000000..6d5f245f3157cb6ef4d46349fe12d52288fc1dbe --- /dev/null +++ b/drivers/misc/fpsensor_chipone/fpsensor_wakelock.h @@ -0,0 +1,75 @@ +/* include/linux/wakelock.h + * + * Copyright (C) 2007-2012 Google, Inc. + * + * 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 _BF_FP_WAKELOCK_H +#define _BF_FP_WAKELOCK_H + +#include +#include +#include + +/* A wake_lock prevents the system from entering suspend or other low power + * states when active. If the type is set to WAKE_LOCK_SUSPEND, the wake_lock + * prevents a full system suspend. + */ + +enum { + WAKE_LOCK_SUSPEND, /* Prevent suspend */ + WAKE_LOCK_TYPE_COUNT +}; + +struct wake_lock { + struct wakeup_source ws; +}; + +static inline void wake_lock_init(struct wake_lock *lock, int type, + const char *name) +{ +// wakeup_source_init(&lock->ws, name); +// &lock->ws = wakeup_source_create(name); + struct wakeup_source *p_ws; + p_ws = wakeup_source_register(NULL, name); + lock->ws = *p_ws; +} + +static inline void wake_lock_destroy(struct wake_lock *lock) +{ +// wakeup_source_trash(&lock->ws); +// wakeup_source_destroy(&lock->ws); + wakeup_source_unregister(&lock->ws); +} + +static inline void wake_lock(struct wake_lock *lock) +{ + __pm_stay_awake(&lock->ws); +} + +static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) +{ + __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); +} + +static inline void wake_unlock(struct wake_lock *lock) +{ + __pm_relax(&lock->ws); +} + +static inline int wake_lock_active(struct wake_lock *lock) +{ + return lock->ws.active; +} + +#endif + diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 26e114f6c2e41b05dd2b759816e6c0896374fca8..a1cb43fe491ea22061e9f2c81d350a755c2b1207 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -67,3 +67,9 @@ config NFC_NQ This enables the NFC driver for NQx based devices. This is for i2c connected version. NCI protocol logic resides in the usermode and it has no other NFC dependencies. + +config NFC_ST21NFC + bool "ST Microelectronics ST21NFC NFC Controller Driver" + depends on I2C + help + ST Microelectronics ST21NFC Near Field Communication controller support. diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 5661fd6adf96b95ee07a2258b26f9da91762d430..bdf2aedeab872f84601ee54cfe68c71d12b353be 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_NFC_PORT100) += port100.o obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ +obj-$(CONFIG_NFC_ST21NFC) += st21nfc.o obj-$(CONFIG_NFC_ST_NCI) += st-nci/ obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/ diff --git a/drivers/nfc/st21nfc.c b/drivers/nfc/st21nfc.c new file mode 100644 index 0000000000000000000000000000000000000000..2a7b3a0f90914094f423274b18618410e884c228 --- /dev/null +++ b/drivers/nfc/st21nfc.c @@ -0,0 +1,1395 @@ +/* + * Copyright (C) 2016 ST Microelectronics S.A. + * Copyright (C) 2010 Stollmann E+V GmbH + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef LEGACY +#include +#include +#include +#include +#include +#else +#include +#include +#include +#endif +#include +#include "st21nfc.h" + +//#define ST21NFCD_MTK +//#define ST54J_PWRSTATS + +#ifdef ST21NFCD_MTK +// Kernel 4.9 on some platforms is using legacy drivers (kernel-4.9-lc) +// I2C: CONFIG_MACH_MT6735 / 6735M / 6753 / 6580 / 6755 use legacy driver +// CLOCK: 4.9 has right includes, no need for special handling. +// GPIO : same as I2C -- we use the same condition at the moment. +//#if (defined(CONFIG_MACH_MT6735) || defined(CONFIG_MACH_MT6735M) || +// defined(CONFIG_MACH_MT6753) || defined(CONFIG_MACH_MT6580) || +// defined(CONFIG_MACH_MT6755)) +// test on I2C special define instead of listing the platforms +#ifdef CONFIG_MTK_I2C_EXTENSION +#define KRNMTKLEGACY_I2C 1 +#define KRNMTKLEGACY_GPIO 1 +#define KRNMTKLEGACY_CLK 1 +#endif + +/* Set NO_MTK_CLK_MANAGEMENT if using xtal integration */ +#ifndef NO_MTK_CLK_MANAGEMENT +#ifdef KRNMTKLEGACY_CLK +#include +#else +#include +#endif +#endif +#endif // ST21NFCD_MTK + +#define MAX_BUFFER_SIZE 260 +#define HEADER_LENGTH 3 +#define IDLE_CHARACTER 0x7e +#define ST21NFC_POWER_STATE_MAX 3 +// wake up for the duration of a typical transaction +#define WAKEUP_SRC_TIMEOUT (500) + +#define DRIVER_VERSION "2.2.0.14" + +#define PROP_PWR_MON_RW_ON_NTF nci_opcode_pack(NCI_GID_PROPRIETARY, 5) +#define PROP_PWR_MON_RW_OFF_NTF nci_opcode_pack(NCI_GID_PROPRIETARY, 6) + +#define I2C_ID_NAME "st21nfc" + +#ifdef KRNMTKLEGACY_I2C +#include +#define NFC_CLIENT_TIMING 400 /* I2C speed */ +static char *I2CDMAWriteBuf; /*= NULL;*/ /* unnecessary initialise */ +static unsigned int I2CDMAWriteBuf_pa; /* = NULL; */ +static char *I2CDMAReadBuf; /*= NULL;*/ /* unnecessary initialise */ +static unsigned int I2CDMAReadBuf_pa; /* = NULL; */ +#endif /* KRNMTKLEGACY_I2C */ + +static bool enable_debug_log; + +/*The enum is used to index a pw_states array, the values matter here*/ +enum st21nfc_power_state { + ST21NFC_IDLE = 0, + ST21NFC_ACTIVE = 1, + ST21NFC_ACTIVE_RW = 2 +}; + +static const char *const st21nfc_power_state_name[] = {"IDLE", "ACTIVE", + "ACTIVE_RW"}; + +enum st21nfc_read_state { ST21NFC_HEADER, ST21NFC_PAYLOAD }; + +struct nfc_sub_power_stats { + uint64_t count; + uint64_t duration; + uint64_t last_entry; + uint64_t last_exit; +}; + +struct nfc_sub_power_stats_error { + /* error transition header --> payload state machine */ + uint64_t header_payload; + /* error transition from an active state when not in idle state */ + uint64_t active_not_idle; + /* error transition from idle state to idle state */ + uint64_t idle_to_idle; + /* warning transition from active_rw state to idle state */ + uint64_t active_rw_to_idle; + /* error transition from active state to active state */ + uint64_t active_to_active; + /* error transition from idle state to active state with notification */ + uint64_t idle_to_active_ntf; + /* error transition from active_rw state to active_rw state */ + uint64_t act_rw_to_act_rw; + /* error transition from idle state to */ + /* active_rw state with notification */ + uint64_t idle_to_active_rw_ntf; +}; + +/* + * The member 'polarity_mode' defines + * how the wakeup pin is configured and handled. + * it can take the following values : + * IRQF_TRIGGER_RISING + * IRQF_TRIGGER_HIGH + */ +struct st21nfc_device { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct mutex pidle_mutex; + struct i2c_client *client; + struct miscdevice st21nfc_device; + uint8_t buffer[MAX_BUFFER_SIZE]; + bool irq_enabled; + bool irq_wake_up; + bool irq_is_attached; + bool device_open; /* Is device open? */ + spinlock_t irq_enabled_lock; + enum st21nfc_power_state pw_current; + enum st21nfc_read_state r_state_current; + int irq_pw_stats_idle; + int p_idle_last; + struct nfc_sub_power_stats pw_states[ST21NFC_POWER_STATE_MAX]; + struct nfc_sub_power_stats_error pw_states_err; + struct workqueue_struct *st_p_wq; + struct work_struct st_p_work; + /*Power state shadow copies for reading*/ + enum st21nfc_power_state c_pw_current; + struct nfc_sub_power_stats c_pw_states[ST21NFC_POWER_STATE_MAX]; + struct nfc_sub_power_stats_error c_pw_states_err; + + /* CLK control */ + bool clk_run; + struct clk *s_clk; + uint8_t pinctrl_en; + + /* GPIO for NFCC IRQ pin (input) */ + struct gpio_desc *gpiod_irq; + /* GPIO for NFCC Reset pin (output) */ + struct gpio_desc *gpiod_reset; + /* GPIO for NFCC CLK_REQ pin (input) */ + struct gpio_desc *gpiod_clkreq; + /* GPIO for NFCC CLF_MONITOR_PWR (input) */ + struct gpio_desc *gpiod_pidle; + /* irq_gpio polarity to be used */ + unsigned int polarity_mode; +}; + +/* + * Routine to enable clock. + * this routine can be extended to select from multiple + * sources based on clk_src_name. + */ +static int st21nfc_clock_select(struct st21nfc_device *st21nfc_dev) { +#ifdef ST21NFCD_MTK +#ifndef NO_MTK_CLK_MANAGEMENT + /*If use XTAL mode, please remove this function "clk_buf_ctrl" to + *avoid additional power consumption. + */ + clk_buf_ctrl(CLK_BUF_NFC, true); +#endif + return 0; +#else // ST21NFCD_MTK + int ret = 0; + st21nfc_dev->s_clk = clk_get(&st21nfc_dev->client->dev, "nfc_ref_clk"); + + /* if NULL we assume external crystal and dont fail */ + if (IS_ERR_OR_NULL(st21nfc_dev->s_clk)) return 0; + + if (st21nfc_dev->clk_run == false) { + ret = clk_prepare_enable(st21nfc_dev->s_clk); + + if (ret) goto err_clk; + + st21nfc_dev->clk_run = true; + } + return ret; + +err_clk: + return -EINVAL; +#endif // ST21NFCD_MTK +} + +/* + * Routine to disable clocks + */ +static int st21nfc_clock_deselect(struct st21nfc_device *st21nfc_dev) { +#ifdef ST21NFCD_MTK +#ifndef NO_MTK_CLK_MANAGEMENT + clk_buf_ctrl(CLK_BUF_NFC, false); +#endif + return 0; +#else // ST21NFCD_MTK + /* if NULL we assume external crystal and dont fail */ + if (IS_ERR_OR_NULL(st21nfc_dev->s_clk)) return 0; + + if (st21nfc_dev->clk_run == true) { + clk_disable_unprepare(st21nfc_dev->s_clk); + st21nfc_dev->clk_run = false; + } + return 0; +#endif // ST21NFCD_MTK +} + +static void st21nfc_disable_irq(struct st21nfc_device *st21nfc_dev) { + unsigned long flags; + + spin_lock_irqsave(&st21nfc_dev->irq_enabled_lock, flags); + if (st21nfc_dev->irq_enabled) { + disable_irq_nosync(st21nfc_dev->client->irq); + st21nfc_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&st21nfc_dev->irq_enabled_lock, flags); +} + +static void st21nfc_enable_irq(struct st21nfc_device *st21nfc_dev) { + unsigned long flags; + + spin_lock_irqsave(&st21nfc_dev->irq_enabled_lock, flags); + if (!st21nfc_dev->irq_enabled) { + st21nfc_dev->irq_enabled = true; + enable_irq(st21nfc_dev->client->irq); + } + spin_unlock_irqrestore(&st21nfc_dev->irq_enabled_lock, flags); +} + +static irqreturn_t st21nfc_dev_irq_handler(int irq, void *dev_id) { + struct st21nfc_device *st21nfc_dev = dev_id; + + if (device_may_wakeup(&st21nfc_dev->client->dev)) + pm_wakeup_event(&st21nfc_dev->client->dev, WAKEUP_SRC_TIMEOUT); + st21nfc_disable_irq(st21nfc_dev); + + /* Wake up waiting readers */ + wake_up(&st21nfc_dev->read_wq); + + return IRQ_HANDLED; +} + +static int st21nfc_loc_set_polaritymode(struct st21nfc_device *st21nfc_dev, + int mode) { + struct i2c_client *client = st21nfc_dev->client; + struct device *dev = &client->dev; + unsigned int irq_type; + int ret; + + if (enable_debug_log) pr_info("%s:%d mode %d", __FILE__, __LINE__, mode); + + st21nfc_dev->polarity_mode = mode; + /* setup irq_flags */ + switch (mode) { + case IRQF_TRIGGER_RISING: + irq_type = IRQ_TYPE_EDGE_RISING; + break; + case IRQF_TRIGGER_HIGH: + irq_type = IRQ_TYPE_LEVEL_HIGH; + break; + default: + irq_type = IRQ_TYPE_EDGE_RISING; + break; + } + if (st21nfc_dev->irq_is_attached) { + devm_free_irq(dev, client->irq, st21nfc_dev); + st21nfc_dev->irq_is_attached = false; + } + ret = irq_set_irq_type(client->irq, irq_type); + if (ret) { + pr_err("%s : set_irq_type failed\n", __func__); + return -ENODEV; + } + /* request irq. the irq is set whenever the chip has data available + * for reading. it is cleared when all data has been read. + */ + if (enable_debug_log) + pr_debug("%s : requesting IRQ %d\n", __func__, client->irq); + st21nfc_dev->irq_enabled = true; + + ret = devm_request_irq(dev, client->irq, st21nfc_dev_irq_handler, + st21nfc_dev->polarity_mode, client->name, st21nfc_dev); + if (ret) { + pr_err("%s : devm_request_irq failed\n", __func__); + return -ENODEV; + } + st21nfc_dev->irq_is_attached = true; + st21nfc_disable_irq(st21nfc_dev); + + if (enable_debug_log) pr_info("%s:%d ret %d", __FILE__, __LINE__, ret); + return ret; +} + +static void st21nfc_power_stats_switch(struct st21nfc_device *st21nfc_dev, + uint64_t current_time_ms, + enum st21nfc_power_state old_state, + enum st21nfc_power_state new_state, + bool is_ntf) { + mutex_lock(&st21nfc_dev->pidle_mutex); + + if (new_state == old_state) { + if ((st21nfc_dev->pw_states[ST21NFC_IDLE].last_entry != 0) || + (old_state != ST21NFC_IDLE)) { + pr_err("%s Error: Switched from %s to %s!: %llx, ntf=%d\n", __func__, + st21nfc_power_state_name[old_state], + st21nfc_power_state_name[new_state], current_time_ms, is_ntf); + if (new_state == ST21NFC_IDLE) + st21nfc_dev->pw_states_err.idle_to_idle++; + else if (new_state == ST21NFC_ACTIVE) + st21nfc_dev->pw_states_err.active_to_active++; + else if (new_state == ST21NFC_ACTIVE_RW) + st21nfc_dev->pw_states_err.act_rw_to_act_rw++; + + mutex_unlock(&st21nfc_dev->pidle_mutex); + return; + } + } else if (!is_ntf && new_state == ST21NFC_ACTIVE && + old_state != ST21NFC_IDLE) { + st21nfc_dev->pw_states_err.active_not_idle++; + } else if (!is_ntf && new_state == ST21NFC_IDLE && + old_state == ST21NFC_ACTIVE_RW) { + st21nfc_dev->pw_states_err.active_rw_to_idle++; + } else if (is_ntf && new_state == ST21NFC_ACTIVE && + old_state == ST21NFC_IDLE) { + st21nfc_dev->pw_states_err.idle_to_active_ntf++; + } else if (is_ntf && new_state == ST21NFC_ACTIVE_RW && + old_state == ST21NFC_IDLE) { + st21nfc_dev->pw_states_err.idle_to_active_rw_ntf++; + } + + pr_debug("%s Switching from %s to %s: %llx, ntf=%d\n", __func__, + st21nfc_power_state_name[old_state], + st21nfc_power_state_name[new_state], current_time_ms, is_ntf); + st21nfc_dev->pw_states[old_state].last_exit = current_time_ms; + st21nfc_dev->pw_states[old_state].duration += + st21nfc_dev->pw_states[old_state].last_exit - + st21nfc_dev->pw_states[old_state].last_entry; + st21nfc_dev->pw_states[new_state].count++; + st21nfc_dev->pw_current = new_state; + st21nfc_dev->pw_states[new_state].last_entry = current_time_ms; + + mutex_unlock(&st21nfc_dev->pidle_mutex); +} + +static void st21nfc_power_stats_idle_signal( + struct st21nfc_device *st21nfc_dev) { + uint64_t current_time_ms = ktime_to_ms(ktime_get_boottime()); + int value = gpiod_get_value(st21nfc_dev->gpiod_pidle); + + if (value != 0) { + st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, + st21nfc_dev->pw_current, ST21NFC_ACTIVE, false); + } else { + st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, + st21nfc_dev->pw_current, ST21NFC_IDLE, false); + } +} + +void st21nfc_pstate_wq(struct work_struct *work) { + struct st21nfc_device *st21nfc_dev = + container_of(work, struct st21nfc_device, st_p_work); + + st21nfc_power_stats_idle_signal(st21nfc_dev); +} + +static irqreturn_t st21nfc_dev_power_stats_handler(int irq, void *dev_id) { + struct st21nfc_device *st21nfc_dev = dev_id; + + queue_work(st21nfc_dev->st_p_wq, &(st21nfc_dev->st_p_work)); + + return IRQ_HANDLED; +} + +#ifdef ST54J_PWRSTATS +static void st21nfc_power_stats_filter(struct st21nfc_device *st21nfc_dev, + char *buf, size_t count) { + uint64_t current_time_ms = ktime_to_ms(ktime_get_boottime()); + __u16 ntf_opcode = nci_opcode(buf); + + if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) return; + + /* In order to avoid counting active state on PAYLOAD where it would + * match a possible header, power states are filtered only on NCI + * headers. + */ + if (st21nfc_dev->r_state_current != ST21NFC_HEADER) return; + + if (count != HEADER_LENGTH) { + pr_err("%s Warning: expect previous one was idle data\n"); + st21nfc_dev->pw_states_err.header_payload++; + return; + } + + if (nci_mt(buf) != NCI_MT_NTF_PKT && + nci_opcode_gid(ntf_opcode) != NCI_GID_PROPRIETARY) + return; + + switch (ntf_opcode) { + case PROP_PWR_MON_RW_OFF_NTF: + st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, + st21nfc_dev->pw_current, ST21NFC_ACTIVE, true); + break; + case PROP_PWR_MON_RW_ON_NTF: + st21nfc_power_stats_switch(st21nfc_dev, current_time_ms, + st21nfc_dev->pw_current, ST21NFC_ACTIVE_RW, + true); + break; + default: + return; + } + return; +} +#endif + +static ssize_t st21nfc_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) { + struct st21nfc_device *st21nfc_dev = + container_of(filp->private_data, struct st21nfc_device, st21nfc_device); + int ret; +#ifdef ST54J_PWRSTATS + int idle = 0; +#endif // ST54J_PWRSTATS + + if (count == 0) return 0; + + if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; + + if (enable_debug_log) pr_debug("%s : reading %zu bytes.\n", __func__, count); + + if (0 == gpiod_get_value(st21nfc_dev->gpiod_irq)) { + pr_info("%s : read called but no IRQ.\n", __func__); + memset(st21nfc_dev->buffer, 0x7E, count); + if (copy_to_user(buf, st21nfc_dev->buffer, count)) { + pr_warn("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + return count; + } + + mutex_lock(&st21nfc_dev->read_mutex); + + /* Read data */ +#ifdef KRNMTKLEGACY_I2C + st21nfc_dev->client->addr = (st21nfc_dev->client->addr & I2C_MASK_FLAG); + st21nfc_dev->client->ext_flag |= I2C_DMA_FLAG; + /* st21nfc_dev->platform_data.client->ext_flag |= I2C_DIRECTION_FLAG; */ + /* st21nfc_dev->platform_data.client->ext_flag |= I2C_A_FILTER_MSG; */ + st21nfc_dev->client->timing = NFC_CLIENT_TIMING; + + /* Read data */ + ret = i2c_master_recv(st21nfc_dev->client, + (unsigned char *)(uintptr_t)I2CDMAReadBuf_pa, count); + /* copy back to buffer */ + if (ret > 0) { + memcpy(st21nfc_dev->buffer, (unsigned char *)(uintptr_t)I2CDMAReadBuf_pa, + ret); + } +#else + ret = i2c_master_recv(st21nfc_dev->client, st21nfc_dev->buffer, count); +#endif +#ifdef ST54J_PWRSTATS + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + mutex_unlock(&st21nfc_dev->read_mutex); + return ret; + } + if (st21nfc_dev->r_state_current == ST21NFC_HEADER) { + /* Counting idle index */ + for (idle = 0; idle < ret && st21nfc_dev->buffer[idle] == IDLE_CHARACTER; + idle++) + ; + + if (idle > 0 && idle < HEADER_LENGTH) { + memmove(st21nfc_dev->buffer, st21nfc_dev->buffer + idle, ret - idle); + ret = i2c_master_recv(st21nfc_dev->client, + st21nfc_dev->buffer + ret - idle, idle); + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + mutex_unlock(&st21nfc_dev->read_mutex); + return ret; + } + ret = count; + } + } +#endif // ST54J_PWRSTATS + mutex_unlock(&st21nfc_dev->read_mutex); + + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + return ret; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", __func__, ret); + return -EIO; + } + +#ifdef ST54J_PWRSTATS + if (idle < HEADER_LENGTH) { + st21nfc_power_stats_filter(st21nfc_dev, st21nfc_dev->buffer, ret); + /* change state only if a payload is detected, i.e. size > 0*/ + if ((st21nfc_dev->r_state_current == ST21NFC_HEADER) && + (st21nfc_dev->buffer[2] > 0)) { + st21nfc_dev->r_state_current = ST21NFC_PAYLOAD; + if (enable_debug_log) + pr_debug("%s : new state = ST21NFC_PAYLOAD\n", __func__); + } else { + st21nfc_dev->r_state_current = ST21NFC_HEADER; + if (enable_debug_log) + pr_debug("%s : new state = ST21NFC_HEADER\n", __func__); + } + } +#endif // ST54J_PWRSTATS + + if (copy_to_user(buf, st21nfc_dev->buffer, ret)) { + pr_warn("%s : failed to copy to user space\n", __func__); + return -EFAULT; + } + + return ret; +} + +static ssize_t st21nfc_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) { + struct st21nfc_device *st21nfc_dev = + container_of(filp->private_data, struct st21nfc_device, st21nfc_device); + char *tmp = NULL; + int ret = count; + + if (enable_debug_log) { + //pr_debug("%s: st21nfc_dev ptr %p\n", __func__, st21nfc_dev); + pr_debug("%s : writing %zu bytes.\n", __func__, count); + } + + if (count > MAX_BUFFER_SIZE) count = MAX_BUFFER_SIZE; + + tmp = memdup_user(buf, count); + if (IS_ERR_OR_NULL(tmp)) { + pr_err("%s : memdup_user failed\n", __func__); + return -EFAULT; + } + + /* Write data */ +#ifdef KRNMTKLEGACY_I2C + memcpy(I2CDMAWriteBuf, tmp, count); + st21nfc_dev->client->addr = (st21nfc_dev->client->addr & I2C_MASK_FLAG); + + st21nfc_dev->client->ext_flag |= I2C_DMA_FLAG; + /* st21nfc_dev->platform_data.client->ext_flag |= I2C_DIRECTION_FLAG; */ + /* st21nfc_dev->platform_data.client->ext_flag |= I2C_A_FILTER_MSG; */ + st21nfc_dev->client->timing = NFC_CLIENT_TIMING; + + ret = i2c_master_send(st21nfc_dev->client, + (unsigned char *)(uintptr_t)I2CDMAWriteBuf_pa, count); +#else + ret = i2c_master_send(st21nfc_dev->client, tmp, count); +#endif + if (ret != count) { + pr_err("%s : i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + kfree(tmp); + + return ret; +} + +static int st21nfc_dev_open(struct inode *inode, struct file *filp) { + int ret = 0; + struct st21nfc_device *st21nfc_dev = + container_of(filp->private_data, struct st21nfc_device, st21nfc_device); + + if (enable_debug_log) pr_info("%s:%d dev_open", __FILE__, __LINE__); + + if (st21nfc_dev->device_open) { + ret = -EBUSY; + pr_err("%s : device already opened ret= %d\n", __func__, ret); + } else { + st21nfc_dev->device_open = true; + } + return ret; +} + +static int st21nfc_release(struct inode *inode, struct file *file) { + struct st21nfc_device *st21nfc_dev = + container_of(file->private_data, struct st21nfc_device, st21nfc_device); + + st21nfc_dev->device_open = false; + if (enable_debug_log) pr_debug("%s : device_open = false\n", __func__); + return 0; +} + +static void (*st21nfc_st54spi_cb)(int, void *); +static void *st21nfc_st54spi_data; +void st21nfc_register_st54spi_cb(void (*cb)(int, void *), void *data) { + if (enable_debug_log) pr_info("%s\n", __func__); + st21nfc_st54spi_cb = cb; + st21nfc_st54spi_data = data; +} +void st21nfc_unregister_st54spi_cb(void) { + if (enable_debug_log) pr_info("%s\n", __func__); + st21nfc_st54spi_cb = NULL; + st21nfc_st54spi_data = NULL; +} + +static long st21nfc_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) { + struct st21nfc_device *st21nfc_dev = + container_of(filp->private_data, struct st21nfc_device, st21nfc_device); + + int ret = 0; + + u32 tmp; + + /* Check type and command number */ + if (_IOC_TYPE(cmd) != ST21NFC_MAGIC) return -ENOTTY; + + /* Check access direction once here; don't repeat below. + * IOC_DIR is from the user perspective, while access_ok is + * from the kernel perspective; so they look reversed. + */ + if (_IOC_DIR(cmd) & _IOC_READ) + ret = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + if (ret == 0 && _IOC_DIR(cmd) & _IOC_WRITE) + ret = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (ret) return -EFAULT; + + switch (cmd) { + case ST21NFC_SET_POLARITY_RISING: + case ST21NFC_LEGACY_SET_POLARITY_RISING: + pr_info(" ### ST21NFC_SET_POLARITY_RISING ###\n"); + st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_RISING); + break; + + case ST21NFC_SET_POLARITY_HIGH: + case ST21NFC_LEGACY_SET_POLARITY_HIGH: + pr_info(" ### ST21NFC_SET_POLARITY_HIGH ###\n"); + st21nfc_loc_set_polaritymode(st21nfc_dev, IRQF_TRIGGER_HIGH); + break; + + case ST21NFC_PULSE_RESET: + case ST21NFC_LEGACY_PULSE_RESET: + pr_info("%s Double Pulse Request\n", __func__); + if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { + if (st21nfc_st54spi_cb != 0) + (*st21nfc_st54spi_cb)(ST54SPI_CB_RESET_START, st21nfc_st54spi_data); + /* pulse low for 20 millisecs */ + gpiod_set_value(st21nfc_dev->gpiod_reset, 0); + msleep(20); + gpiod_set_value(st21nfc_dev->gpiod_reset, 1); + usleep_range(10000, 11000); + /* pulse low for 20 millisecs */ + gpiod_set_value(st21nfc_dev->gpiod_reset, 0); + msleep(20); + gpiod_set_value(st21nfc_dev->gpiod_reset, 1); + pr_info("%s done Double Pulse Request\n", __func__); + if (st21nfc_st54spi_cb != 0) + (*st21nfc_st54spi_cb)(ST54SPI_CB_RESET_END, st21nfc_st54spi_data); + } + st21nfc_dev->r_state_current = ST21NFC_HEADER; + break; + + case ST21NFC_GET_WAKEUP: + case ST21NFC_LEGACY_GET_WAKEUP: + /* deliver state of Wake_up_pin as return value of ioctl */ + ret = gpiod_get_value(st21nfc_dev->gpiod_irq); + /* + * Warning: depending on gpiod_get_value implementation, + * it can returns a value different than 1 in case of high level + */ + if (ret != 0) ret = 1; + + if (enable_debug_log) pr_debug("%s get gpio result %d\n", __func__, ret); + break; + case ST21NFC_GET_POLARITY: + case ST21NFC_LEGACY_GET_POLARITY: + ret = st21nfc_dev->polarity_mode; + if (enable_debug_log) pr_debug("%s get polarity %d\n", __func__, ret); + break; + case ST21NFC_RECOVERY: + case ST21NFC_LEGACY_RECOVERY: + /* For ST21NFCD usage only */ + pr_info("%s Recovery Request\n", __func__); + if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { + if (st21nfc_dev->irq_is_attached) { + devm_free_irq(&st21nfc_dev->client->dev, st21nfc_dev->client->irq, + st21nfc_dev); + st21nfc_dev->irq_is_attached = false; + } + /* pulse low for 20 millisecs */ + gpiod_set_value(st21nfc_dev->gpiod_reset, 0); + usleep_range(10000, 11000); + /* During the reset, force IRQ OUT as */ + /* DH output instead of input in normal usage */ + ret = gpiod_direction_output(st21nfc_dev->gpiod_irq, 1); + if (ret) { + pr_err("%s : gpiod_direction_output failed\n", __func__); + ret = -ENODEV; + break; + } + + gpiod_set_value(st21nfc_dev->gpiod_irq, 1); + usleep_range(10000, 11000); + gpiod_set_value(st21nfc_dev->gpiod_reset, 1); + + pr_info("%s done Pulse Request\n", __func__); + } + msleep(20); + gpiod_set_value(st21nfc_dev->gpiod_irq, 0); + msleep(20); + gpiod_set_value(st21nfc_dev->gpiod_irq, 1); + msleep(20); + gpiod_set_value(st21nfc_dev->gpiod_irq, 0); + msleep(20); + pr_info("%s Recovery procedure finished\n", __func__); + ret = gpiod_direction_input(st21nfc_dev->gpiod_irq); + if (ret) { + pr_err("%s : gpiod_direction_input failed\n", __func__); + ret = -ENODEV; + } + break; + case ST21NFC_USE_ESE: + ret = __get_user(tmp, (u32 __user *)arg); + if (ret == 0) { + if (st21nfc_st54spi_cb != 0) + (*st21nfc_st54spi_cb)( + tmp ? ST54SPI_CB_ESE_USED : ST54SPI_CB_ESE_NOT_USED, + st21nfc_st54spi_data); + } + if (enable_debug_log) + pr_debug("%s use ESE %d : %d\n", __func__, ret, tmp); + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + ret = -EINVAL; + break; + } + return ret; +} + +static unsigned int st21nfc_poll(struct file *file, poll_table *wait) { + struct st21nfc_device *st21nfc_dev = + container_of(file->private_data, struct st21nfc_device, st21nfc_device); + unsigned int mask = 0; + int pinlev = 0; + + /* wait for Wake_up_pin == high */ + poll_wait(file, &st21nfc_dev->read_wq, wait); + + pinlev = gpiod_get_value(st21nfc_dev->gpiod_irq); + + if (pinlev != 0) { + if (enable_debug_log) pr_debug("%s return ready\n", __func__); + mask = POLLIN | POLLRDNORM; /* signal data avail */ + st21nfc_disable_irq(st21nfc_dev); + } else { + /* Wake_up_pin is low. Activate ISR */ + if (!st21nfc_dev->irq_enabled) { + if (enable_debug_log) pr_debug("%s enable irq\n", __func__); + st21nfc_enable_irq(st21nfc_dev); + } else { + if (enable_debug_log) pr_debug("%s irq already enabled\n", __func__); + } + } + return mask; +} + +#ifdef ST21NFCD_MTK +#ifndef KRNMTKLEGACY_GPIO +static int st21nfc_platform_probe(struct platform_device *pdev) { + if (enable_debug_log) pr_debug("%s\n", __func__); + return 0; +} + +static int st21nfc_platform_remove(struct platform_device *pdev) { + if (enable_debug_log) pr_debug("%s\n", __func__); + return 0; +} +#endif /* KRNMTKLEGACY_GPIO */ +#endif /* ST21NFCD_MTK */ + +static const struct file_operations st21nfc_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = st21nfc_dev_read, + .write = st21nfc_dev_write, + .open = st21nfc_dev_open, + .poll = st21nfc_poll, + .release = st21nfc_release, + .unlocked_ioctl = st21nfc_dev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = st21nfc_dev_ioctl +#endif +}; + +static ssize_t i2c_addr_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct i2c_client *client = to_i2c_client(dev); + + if (client != NULL) + return scnprintf(buf, PAGE_SIZE, "0x%.2x\n", client->addr); + return -ENODEV; +} /* i2c_addr_show() */ + +static ssize_t i2c_addr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct st21nfc_device *data = dev_get_drvdata(dev); + long new_addr = 0; + + if (data != NULL && data->client != NULL) { + if (!kstrtol(buf, 10, &new_addr)) { + mutex_lock(&data->read_mutex); + data->client->addr = new_addr; + mutex_unlock(&data->read_mutex); + return count; + } + return -EINVAL; + } + return 0; +} /* i2c_addr_store() */ + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, + char *buf) { + return scnprintf(buf, PAGE_SIZE, "%s\n", DRIVER_VERSION); +} /* version_show */ + +static uint64_t st21nfc_power_duration(struct st21nfc_device *data, + enum st21nfc_power_state pstate, + uint64_t current_time_ms) { + return data->c_pw_current != pstate + ? data->c_pw_states[pstate].duration + : data->c_pw_states[pstate].duration + + (current_time_ms - data->c_pw_states[pstate].last_entry); +} + +static ssize_t power_stats_show(struct device *dev, + struct device_attribute *attr, char *buf) { + struct st21nfc_device *data = dev_get_drvdata(dev); + uint64_t current_time_ms; + uint64_t idle_duration; + uint64_t active_ce_duration; + uint64_t active_rw_duration; + + mutex_lock(&data->pidle_mutex); + + data->c_pw_current = data->pw_current; + data->c_pw_states_err = data->pw_states_err; + memcpy(data->c_pw_states, data->pw_states, + ST21NFC_POWER_STATE_MAX * sizeof(struct nfc_sub_power_stats)); + + mutex_unlock(&data->pidle_mutex); + + current_time_ms = ktime_to_ms(ktime_get_boottime()); + idle_duration = st21nfc_power_duration(data, ST21NFC_IDLE, current_time_ms); + active_ce_duration = + st21nfc_power_duration(data, ST21NFC_ACTIVE, current_time_ms); + active_rw_duration = + st21nfc_power_duration(data, ST21NFC_ACTIVE_RW, current_time_ms); + + return scnprintf( + buf, PAGE_SIZE, + "NFC subsystem\n" + "Idle mode:\n" + "\tCumulative count: 0x%llx\n" + "\tCumulative duration msec: 0x%llx\n" + "\tLast entry timestamp msec: 0x%llx\n" + "\tLast exit timestamp msec: 0x%llx\n" + "Active mode:\n" + "\tCumulative count: 0x%llx\n" + "\tCumulative duration msec: 0x%llx\n" + "\tLast entry timestamp msec: 0x%llx\n" + "\tLast exit timestamp msec: 0x%llx\n" + "Active Reader/Writer mode:\n" + "\tCumulative count: 0x%llx\n" + "\tCumulative duration msec: 0x%llx\n" + "\tLast entry timestamp msec: 0x%llx\n" + "\tLast exit timestamp msec: 0x%llx\n" + "\nError transition header --> payload state machine: 0x%llx\n" + "Error transition from an Active state when not in Idle state: 0x%llx\n" + "Error transition from Idle state to Idle state: 0x%llx\n" + "Warning transition from Active Reader/Writer state to Idle state: " + "0x%llx\n" + "Error transition from Active state to Active state: 0x%llx\n" + "Error transition from Idle state to Active state with notification: " + "0x%llx\n" + "Error transition from Active Reader/Writer state to Active " + "Reader/Writer state: 0x%llx\n" + "Error transition from Idle state to Active Reader/Writer state with " + "notification: 0x%llx\n" + "\nTotal uptime: 0x%llx Cumulative modes time: 0x%llx\n", + data->c_pw_states[ST21NFC_IDLE].count, idle_duration, + data->c_pw_states[ST21NFC_IDLE].last_entry, + data->c_pw_states[ST21NFC_IDLE].last_exit, + data->c_pw_states[ST21NFC_ACTIVE].count, active_ce_duration, + data->c_pw_states[ST21NFC_ACTIVE].last_entry, + data->c_pw_states[ST21NFC_ACTIVE].last_exit, + data->c_pw_states[ST21NFC_ACTIVE_RW].count, active_rw_duration, + data->c_pw_states[ST21NFC_ACTIVE_RW].last_entry, + data->c_pw_states[ST21NFC_ACTIVE_RW].last_exit, + data->c_pw_states_err.header_payload, + data->c_pw_states_err.active_not_idle, data->c_pw_states_err.idle_to_idle, + data->c_pw_states_err.active_rw_to_idle, + data->c_pw_states_err.active_to_active, + data->c_pw_states_err.idle_to_active_ntf, + data->c_pw_states_err.act_rw_to_act_rw, + data->c_pw_states_err.idle_to_active_rw_ntf, current_time_ms, + idle_duration + active_ce_duration + active_rw_duration); +} + +static DEVICE_ATTR_RW(i2c_addr); + +static DEVICE_ATTR_RO(version); + +static DEVICE_ATTR_RO(power_stats); + +static struct attribute *st21nfc_attrs[] = { + &dev_attr_i2c_addr.attr, + &dev_attr_version.attr, + &dev_attr_power_stats.attr, + NULL, +}; + +static struct attribute_group st21nfc_attr_grp = { + .attrs = st21nfc_attrs, +}; + +#ifndef ST21NFCD_MTK +static const struct acpi_gpio_params irq_gpios = {0, 0, false}; +static const struct acpi_gpio_params reset_gpios = {1, 0, false}; +static const struct acpi_gpio_params pidle_gpios = {2, 0, false}; +static const struct acpi_gpio_params clkreq_gpios = {3, 0, false}; + +static const struct acpi_gpio_mapping acpi_st21nfc_gpios[] = { + {"irq-gpios", &irq_gpios, 1}, + {"reset-gpios", &reset_gpios, 1}, + {"pidle-gpios", &pidle_gpios, 1}, + {"clkreq-gpios", &clkreq_gpios, 1}, +}; +#endif + +static int st21nfc_probe(struct i2c_client *client, + const struct i2c_device_id *id) { + int ret; + struct st21nfc_device *st21nfc_dev; + struct device *dev = &client->dev; +#ifdef ST21NFCD_MTK + int r; + struct device_node *np = dev->of_node; +#endif // ST21NFCD_MTK + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + return -ENODEV; + } + + st21nfc_dev = devm_kzalloc(dev, sizeof(*st21nfc_dev), GFP_KERNEL); + if (st21nfc_dev == NULL) return -ENOMEM; + +#ifdef KRNMTKLEGACY_I2C +#ifdef CONFIG_64BIT + I2CDMAWriteBuf = + (char *)dma_alloc_coherent(&client->dev, MAX_BUFFER_SIZE, + (dma_addr_t *)&I2CDMAWriteBuf_pa, GFP_KERNEL); +#else + I2CDMAWriteBuf = (char *)dma_alloc_coherent( + NULL, MAX_BUFFER_SIZE, (dma_addr_t *)&I2CDMAWriteBuf_pa, GFP_KERNEL); +#endif + + if (I2CDMAWriteBuf == NULL) + pr_err("%s : failed to allocate dma buffer\n", __func__); +#ifdef CONFIG_64BIT + I2CDMAReadBuf = + (char *)dma_alloc_coherent(&client->dev, MAX_BUFFER_SIZE, + (dma_addr_t *)&I2CDMAReadBuf_pa, GFP_KERNEL); +#else + I2CDMAReadBuf = (char *)dma_alloc_coherent( + NULL, MAX_BUFFER_SIZE, (dma_addr_t *)&I2CDMAReadBuf_pa, GFP_KERNEL); +#endif + + if (I2CDMAReadBuf == NULL) + pr_err("%s : failed to allocate dma buffer\n", __func__); + pr_debug("%s :I2CDMAWriteBuf_pa %d, I2CDMAReadBuf_pa,%d\n", __func__, + I2CDMAWriteBuf_pa, I2CDMAReadBuf_pa); +#endif /* KRNMTKLEGACY_I2C */ + + /* store for later use */ + st21nfc_dev->client = client; + st21nfc_dev->r_state_current = ST21NFC_HEADER; + client->adapter->retries = 0; + +#ifndef ST21NFCD_MTK + ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_st21nfc_gpios); + if (ret) pr_debug("Unable to add GPIO mapping table\n"); +#else // ST21NFCD_MTK + np = of_find_compatible_node(NULL, NULL, "mediatek,nfc-gpio-v2"); + if (!np) { + pr_err("%s : cannot find mediatek,nfc-gpio-v2 in DTS.\n", __func__); + return -ENODEV; + } +#endif // ST21NFCD_MTK + +#ifndef ST21NFCD_MTK + st21nfc_dev->gpiod_irq = devm_gpiod_get(dev, "irq", GPIOD_IN); +#else // ST21NFCD_MTK + r = of_get_named_gpio(np, "gpio-irq-std", 0); + if (!gpio_is_valid(r)) { + pr_err("%s: get NFC IRQ GPIO failed (%d)", __FILE__, r); + return -ENODEV; + } + st21nfc_dev->gpiod_irq = gpio_to_desc(r); + ret = gpio_request(r, +#if (!defined(CONFIG_MTK_GPIO) || defined(CONFIG_MTK_GPIOLIB_STAND)) + "gpio-irq-std" +#else + "gpio-irq" +#endif + ); + if (ret) { + pr_err("%s : gpio_request failed\n", __FILE__); + return -ENODEV; + } + pr_info("%s : IRQ GPIO = %d\n", __func__, r); + ret = gpio_direction_input(r); + if (ret) { + pr_err("%s : gpio_direction_input failed\n", __FILE__); + return -ENODEV; + } +#endif // ST21NFCD_MTK + if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_irq)) { + pr_err("%s : Unable to request irq-gpios\n", __func__); + return -ENODEV; + } + +#ifndef ST21NFCD_MTK + st21nfc_dev->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); +#else // ST21NFCD_MTK + r = of_get_named_gpio(np, "gpio-rst-std", 0); + if (!gpio_is_valid(r)) { + pr_err("%s: get NFC RST GPIO failed (%d)", __FILE__, r); + return -ENODEV; + } + st21nfc_dev->gpiod_reset = gpio_to_desc(r); + ret = gpio_request(r, +#if (!defined(CONFIG_MTK_GPIO) || defined(CONFIG_MTK_GPIOLIB_STAND)) + "gpio-rst-std" +#else + "gpio-rst" +#endif + ); + if (ret) { + pr_err("%s : gpio_request failed\n", __FILE__); + return -ENODEV; + } + pr_info("%s : RST GPIO = %d\n", __func__, r); + ret = gpio_direction_output(r, 1); + if (ret) { + pr_err("%s : gpio_direction_output failed\n", __FILE__); + return -ENODEV; + } + gpio_set_value(r, 1); +#endif // ST21NFCD_MTK + if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_reset)) { + pr_warn("%s : Unable to request reset-gpios\n", __func__); + return -ENODEV; + } + +#ifndef ST21NFCD_MTK + st21nfc_dev->gpiod_pidle = devm_gpiod_get(dev, "pidle", GPIOD_IN); +#else // ST21NFCD_MTK + ret = of_get_named_gpio(np, "gpio-pidle-std", 0); + if (gpio_is_valid(ret)) { + st21nfc_dev->gpiod_pidle = gpio_to_desc(ret); + } +#endif // ST21NFCD_MTK + if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { + pr_warn("[OPTIONAL] %s: Unable to request pidle-gpio\n", __func__); + ret = 0; + } else { + /* Start the power stat in power mode idle */ + st21nfc_dev->irq_pw_stats_idle = gpiod_to_irq(st21nfc_dev->gpiod_pidle); + + ret = irq_set_irq_type(st21nfc_dev->irq_pw_stats_idle, IRQ_TYPE_EDGE_BOTH); + if (ret) { + pr_err("%s : set_irq_type failed\n", __func__); + return ret; + } + + /* This next call requests an interrupt line */ + ret = devm_request_irq(dev, st21nfc_dev->irq_pw_stats_idle, + (irq_handler_t)st21nfc_dev_power_stats_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + /* Interrupt on both edges */ + "st21nfc_pw_stats_idle_handle", st21nfc_dev); + if (ret) { + pr_err("%s : devm_request_irq for power stats idle failed\n", __func__); + return ret; + } + + ret = sysfs_create_file(&dev->kobj, &dev_attr_power_stats.attr); + if (ret) { + pr_err("%s : sysfs_create_file for power stats failed\n", __func__); + return ret; + } + mutex_init(&st21nfc_dev->pidle_mutex); + + st21nfc_dev->st_p_wq = create_workqueue("st_pstate_work"); + INIT_WORK(&(st21nfc_dev->st_p_work), st21nfc_pstate_wq); + } + +#ifndef ST21NFCD_MTK + st21nfc_dev->gpiod_clkreq = devm_gpiod_get(dev, "clkreq", GPIOD_IN); + if (IS_ERR_OR_NULL(st21nfc_dev->gpiod_clkreq)) { + pr_warn("[OPTIONAL] %s : Unable to request clkreq-gpios\n", __func__); + ret = 0; + } else { + if (!device_property_read_bool(dev, "st,clk_pinctrl")) { + pr_debug("[dsc]%s:[OPTIONAL] clk_pinctrl not set\n", __func__); + st21nfc_dev->pinctrl_en = 0; + } else { + pr_debug("[dsc]%s:[OPTIONAL] clk_pinctrl set\n", __func__); + st21nfc_dev->pinctrl_en = 1; + } + + /* Set clk_run when clock pinctrl already enabled */ + if (st21nfc_dev->pinctrl_en != 0) st21nfc_dev->clk_run = true; + + ret = st21nfc_clock_select(st21nfc_dev); + if (ret < 0) { + pr_err("%s : st21nfc_clock_select failed\n", __func__); + goto err_sysfs_power_stats; + } + } +#else // ST21NFCD_MTK + ret = st21nfc_clock_select(st21nfc_dev); + if (ret < 0) { + pr_err("%s : st21nfc_clock_select failed\n", __func__); + goto err_sysfs_power_stats; + } +#endif // ST21NFCD_MTK + +#ifndef ST21NFCD_MTK + client->irq = gpiod_to_irq(st21nfc_dev->gpiod_irq); +#else // ST21NFCD_MTK + np = of_find_compatible_node(NULL, NULL, "mediatek,irq_nfc-eint"); + if (np) { + client->irq = irq_of_parse_and_map(np, 0); + pr_info("%s : MT IRQ GPIO = %d\n", __func__, client->irq); + } +#endif // ST21NFCD_MTK + + /* init mutex and queues */ + init_waitqueue_head(&st21nfc_dev->read_wq); + mutex_init(&st21nfc_dev->read_mutex); + spin_lock_init(&st21nfc_dev->irq_enabled_lock); + pr_debug( + "%s : debug irq_gpio = %d, client-irq = %d, pidle_gpio = %d\n", __func__, + IS_ERR_OR_NULL(st21nfc_dev->gpiod_irq) ? -1 : desc_to_gpio(st21nfc_dev->gpiod_irq), + client->irq, + IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle) ? -1 : desc_to_gpio(st21nfc_dev->gpiod_pidle)); + st21nfc_dev->st21nfc_device.minor = MISC_DYNAMIC_MINOR; + st21nfc_dev->st21nfc_device.name = "st21nfc"; + st21nfc_dev->st21nfc_device.fops = &st21nfc_dev_fops; + st21nfc_dev->st21nfc_device.parent = dev; + + i2c_set_clientdata(client, st21nfc_dev); + ret = misc_register(&st21nfc_dev->st21nfc_device); + if (ret) { + pr_err("%s : misc_register failed\n", __func__); + goto err_misc_register; + } + + ret = sysfs_create_group(&dev->kobj, &st21nfc_attr_grp); + if (ret) { + pr_err("%s : sysfs_create_group failed\n", __func__); + goto err_sysfs_create_group_failed; + } + device_init_wakeup(&client->dev, true); + device_set_wakeup_capable(&client->dev, true); + st21nfc_dev->irq_wake_up = false; + + return 0; + +err_sysfs_create_group_failed: + misc_deregister(&st21nfc_dev->st21nfc_device); +err_misc_register: + mutex_destroy(&st21nfc_dev->read_mutex); +err_sysfs_power_stats: + if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { + sysfs_remove_file(&client->dev.kobj, &dev_attr_power_stats.attr); + mutex_destroy(&st21nfc_dev->pidle_mutex); + } + return ret; +} + +static int st21nfc_remove(struct i2c_client *client) { + struct st21nfc_device *st21nfc_dev = i2c_get_clientdata(client); + +#ifdef KRNMTKLEGACY_I2C + if (I2CDMAWriteBuf) { +#ifdef CONFIG_64BIT + dma_free_coherent(&client->dev, MAX_BUFFER_SIZE, I2CDMAWriteBuf, + I2CDMAWriteBuf_pa); +#else + dma_free_coherent(NULL, MAX_BUFFER_SIZE, I2CDMAWriteBuf, I2CDMAWriteBuf_pa); +#endif + I2CDMAWriteBuf = NULL; + I2CDMAWriteBuf_pa = 0; + } + + if (I2CDMAReadBuf) { +#ifdef CONFIG_64BIT + dma_free_coherent(&client->dev, MAX_BUFFER_SIZE, I2CDMAReadBuf, + I2CDMAReadBuf_pa); +#else + dma_free_coherent(NULL, MAX_BUFFER_SIZE, I2CDMAReadBuf, I2CDMAReadBuf_pa); +#endif + I2CDMAReadBuf = NULL; + I2CDMAReadBuf_pa = 0; + } +#endif /* KRNMTKLEGACY_I2C */ + + st21nfc_clock_deselect(st21nfc_dev); + misc_deregister(&st21nfc_dev->st21nfc_device); + if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { + sysfs_remove_file(&client->dev.kobj, &dev_attr_power_stats.attr); + mutex_destroy(&st21nfc_dev->pidle_mutex); + } + sysfs_remove_group(&client->dev.kobj, &st21nfc_attr_grp); + mutex_destroy(&st21nfc_dev->read_mutex); + acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); + + return 0; +} + +static int st21nfc_suspend(struct device *device) { + struct i2c_client *client = to_i2c_client(device); + struct st21nfc_device *st21nfc_dev = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev) && st21nfc_dev->irq_enabled) { + if (!enable_irq_wake(client->irq)) st21nfc_dev->irq_wake_up = true; + } + + if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { + st21nfc_dev->p_idle_last = gpiod_get_value(st21nfc_dev->gpiod_pidle); + } + + return 0; +} + +static int st21nfc_resume(struct device *device) { + struct i2c_client *client = to_i2c_client(device); + struct st21nfc_device *st21nfc_dev = i2c_get_clientdata(client); + int pidle; + + if (device_may_wakeup(&client->dev) && st21nfc_dev->irq_wake_up) { + if (!disable_irq_wake(client->irq)) st21nfc_dev->irq_wake_up = false; + } + + if (!IS_ERR_OR_NULL(st21nfc_dev->gpiod_pidle)) { + pidle = gpiod_get_value(st21nfc_dev->gpiod_pidle); + if ((st21nfc_dev->p_idle_last != pidle) || + (st21nfc_dev->pw_current == ST21NFC_IDLE && pidle != 0) || + (st21nfc_dev->pw_current == ST21NFC_ACTIVE && pidle == 0)) { + queue_work(st21nfc_dev->st_p_wq, &(st21nfc_dev->st_p_work)); + } + } + return 0; +} + +static const struct i2c_device_id st21nfc_id[] = {{"st21nfc", 0}, {}}; + +static const struct of_device_id st21nfc_of_match[] = { +#ifndef ST21NFCD_MTK + { + .compatible = "st,st21nfc", + }, +#else + {.compatible = "mediatek,nfc"}, +#endif + {}}; +MODULE_DEVICE_TABLE(of, st21nfc_of_match); + +static const struct dev_pm_ops st21nfc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(st21nfc_suspend, st21nfc_resume)}; + +#ifndef ST21NFCD_MTK +static const struct acpi_device_id st21nfc_acpi_match[] = {{"SMO2104"}, {}}; +MODULE_DEVICE_TABLE(acpi, st21nfc_acpi_match); +#endif + +static struct i2c_driver st21nfc_driver = { + .id_table = st21nfc_id, + .probe = st21nfc_probe, + .remove = st21nfc_remove, + .driver = + { + .owner = THIS_MODULE, + .name = I2C_ID_NAME, + .of_match_table = st21nfc_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &st21nfc_pm_ops, +#ifndef ST21NFCD_MTK + .acpi_match_table = ACPI_PTR(st21nfc_acpi_match), +#endif + }, +}; + +#ifdef ST21NFCD_MTK +#ifndef KRNMTKLEGACY_GPIO +/* platform driver */ +static const struct of_device_id nfc_dev_of_match[] = { + { + .compatible = "mediatek,nfc-gpio-v2", + }, + {}, +}; + +static struct platform_driver st21nfc_platform_driver = { + .probe = st21nfc_platform_probe, + .remove = st21nfc_platform_remove, + .driver = + { + .name = I2C_ID_NAME, + .owner = THIS_MODULE, + .of_match_table = nfc_dev_of_match, + }, +}; +#endif /* KRNMTKLEGACY_GPIO */ +#endif /* ST21NFCD_MTK */ + +/* module load/unload record keeping */ +static int __init st21nfc_dev_init(void) { + pr_info("Loading st21nfc driver\n"); +#ifdef ST21NFCD_MTK +#ifndef KRNMTKLEGACY_GPIO + platform_driver_register(&st21nfc_platform_driver); + if (enable_debug_log) pr_debug("Loading st21nfc i2c driver\n"); +#endif +#endif + return i2c_add_driver(&st21nfc_driver); +} + +module_init(st21nfc_dev_init); + +static void __exit st21nfc_dev_exit(void) { + pr_info("Unloading st21nfc driver\n"); + i2c_del_driver(&st21nfc_driver); +} + +module_exit(st21nfc_dev_exit); + +MODULE_AUTHOR("STMicroelectronics"); +MODULE_DESCRIPTION("NFC ST21NFC driver"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/nfc/st21nfc.h b/drivers/nfc/st21nfc.h new file mode 100644 index 0000000000000000000000000000000000000000..8ab95b56c991066016f077846dede6722c4c6cb2 --- /dev/null +++ b/drivers/nfc/st21nfc.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 ST Microelectronics S.A. + * Copyright (C) 2010 Stollmann E+V GmbH + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#define ST21NFC_MAGIC 0xEA + +#define ST21NFC_NAME "st21nfc" +/* + * ST21NFC power control via ioctl + * ST21NFC_GET_WAKEUP : poll gpio-level for Wakeup pin + */ +#define ST21NFC_GET_WAKEUP _IO(ST21NFC_MAGIC, 0x01) +#define ST21NFC_PULSE_RESET _IO(ST21NFC_MAGIC, 0x02) +#define ST21NFC_SET_POLARITY_RISING _IO(ST21NFC_MAGIC, 0x03) +#define ST21NFC_SET_POLARITY_HIGH _IO(ST21NFC_MAGIC, 0x05) +#define ST21NFC_GET_POLARITY _IO(ST21NFC_MAGIC, 0x07) +#define ST21NFC_RECOVERY _IO(ST21NFC_MAGIC, 0x08) +#define ST21NFC_USE_ESE _IOW(ST21NFC_MAGIC, 0x09, unsigned int) + +// Keep compatibility with older user applications. +#define ST21NFC_LEGACY_GET_WAKEUP _IOR(ST21NFC_MAGIC, 0x01, unsigned int) +#define ST21NFC_LEGACY_PULSE_RESET _IOR(ST21NFC_MAGIC, 0x02, unsigned int) +#define ST21NFC_LEGACY_SET_POLARITY_RISING \ + _IOR(ST21NFC_MAGIC, 0x03, unsigned int) +#define ST21NFC_LEGACY_SET_POLARITY_HIGH _IOR(ST21NFC_MAGIC, 0x05, unsigned int) +#define ST21NFC_LEGACY_GET_POLARITY _IOR(ST21NFC_MAGIC, 0x07, unsigned int) +#define ST21NFC_LEGACY_RECOVERY _IOR(ST21NFC_MAGIC, 0x08, unsigned int) + +#define ST54SPI_CB_RESET_END 0 +#define ST54SPI_CB_RESET_START 1 +#define ST54SPI_CB_ESE_NOT_USED 2 +#define ST54SPI_CB_ESE_USED 3 +void st21nfc_register_st54spi_cb(void (*cb)(int, void *), void *data); +void st21nfc_unregister_st54spi_cb(void); diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c index 0a6ad38653d78a0c757212cce6000d8fbfd52b6b..e033ea325838a86a6b710979116d6df3ed3fb521 100644 --- a/drivers/of/of_batterydata.c +++ b/drivers/of/of_batterydata.c @@ -371,6 +371,16 @@ struct device_node *of_batterydata_get_best_profile( if (best_node == NULL) { pr_err("No battery data found\n"); +#if defined(CONFIG_TCT_PM7250_COMMON) + for_each_child_of_node(batterydata_container_node, node) + { + if(of_property_read_bool(node,"qcom,default-battery-type")) + { + best_node = node; + break; + } + } +#endif return best_node; } diff --git a/drivers/pinctrl/qcom/pinctrl-lagoon.c b/drivers/pinctrl/qcom/pinctrl-lagoon.c index dcf3d2609fe4998ed0acf307d2742c7824fb12bf..4239a6afd291d688c8fe404d2ce3253d2cb88cf0 100644 --- a/drivers/pinctrl/qcom/pinctrl-lagoon.c +++ b/drivers/pinctrl/qcom/pinctrl-lagoon.c @@ -1617,7 +1617,7 @@ static const struct msm_pingroup lagoon_groups[] = { }; static const int lagoon_reserved_gpios[] = { - 13, 14, 15, 16, 45, 46, 56, 57, -1 + 13, 14, 15, 16, 56, 57, -1 }; static struct msm_dir_conn lagoon_dir_conn[] = { diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index c1b0799963e624d20f10ef6138fd40d83b96a77d..322e8919e91ea8c64580b6ba76ec1c869b8cdb9b 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -62,7 +62,11 @@ 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; FP4-2872, disable ramdump, liquan.zhou.t2m, 20210908 +//+ FP4S-812. Add ramdump debug way on user release. liquan.zhou.t2m. 20230103. +static bool t2m_download_enable = 0; +module_param_named(t2m_download_enable, t2m_download_enable, bool, 0664); +//- FP4S-812. Add ramdump debug way on user release. liquan.zhou.t2m. 20230103. static struct kobject dload_kobj; static int in_panic; @@ -644,6 +648,11 @@ static int msm_restart_probe(struct platform_device *pdev) if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DEASSERT_PS_HOLD) > 0) scm_deassert_ps_hold_supported = true; + //+ FP4S-812. Add ramdump debug way on user release. liquan.zhou.t2m. 20230103. + if (t2m_download_enable) { + download_mode = 1; + } + //- FP4S-812. Add ramdump debug way on user release. liquan.zhou.t2m. 20230103. set_dload_mode(download_mode); if (!download_mode) scm_disable_sdi(); diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index bbccf3f836c04b1c6feb57db24dc26514f05e99a..9a0fef728502c355430e77015a2927d1d6b28b0c 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -645,6 +645,18 @@ config CHARGER_CROS_USBPD what is connected to USB PD ports from the EC and converts that into power_supply properties. +config BATTERY_BQ27541_HDQ + tristate "BQ27541 battery driver" + depends on OF + help + Say Y here to enable support for batteries with BQ27541 (HDQ) chips. + +config BATTERY_QNOVO_CHARGE_ALGO + tristate "Qnovo charge algorithm " + depends on OF + help + Say Y here to enable support for Qnovo charge algorithm. + source "drivers/power/supply/qcom/Kconfig" endif # POWER_SUPPLY diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 31305eb2e128cc229d78067ccb3089c8f8379224..0b7eb853f4d9e5c734b0c094f5205c7101cc72b6 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -86,3 +86,5 @@ obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o obj-$(CONFIG_ARCH_QCOM) += qcom/ +obj-$(CONFIG_BATTERY_BQ27541_HDQ) += bq27541_fuelgauger_hdq.o +obj-$(CONFIG_BATTERY_QNOVO_CHARGE_ALGO) += qns_system_v2.o diff --git a/drivers/power/supply/bq27541-hdq-gpio.h b/drivers/power/supply/bq27541-hdq-gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..58ef159bc9c46927139a44bfbe2d38236dafd3bb --- /dev/null +++ b/drivers/power/supply/bq27541-hdq-gpio.h @@ -0,0 +1,146 @@ +/* + * hdq-gpio interface to platform code + * + * Copyright (C) 2014 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ +#ifndef _LINUX_BQ27541_HDQ_GPIO_H +#define _LINUX_BQ27541_HDQ_GPIO_H + +#define DRIVER_VERSION "1.1.0" + /* Bq27541 standard/extended data commands */ +#define bq27541CMD_CNTL_LSB 0x00 +#define bq27541CMD_CNTL_MSB 0x01 +#define bq27541CMD_AR_LSB 0x02 +#define bq27541CMD_AR_MSB 0x03 +#define bq27541CMD_ARTTE_LSB 0x04 +#define bq27541CMD_ARTTE_MSB 0x05 +#define bq27541CMD_TEMP_LSB 0x06 +#define bq27541CMD_TEMP_MSB 0x07 +#define bq27541CMD_VOLT_LSB 0x08 +#define bq27541CMD_VOLT_MSB 0x09 +#define bq27541CMD_FLAGS_LSB 0x0A +#define bq27541CMD_FLAGS_MSB 0x0B +#define bq27541CMD_NAC_LSB 0x0C +#define bq27541CMD_NAC_MSB 0x0D +#define bq27541CMD_FAC_LSB 0x0E +#define bq27541CMD_FAC_MSB 0x0F +#define bq27541CMD_RM_LSB 0x10 +#define bq27541CMD_RM_MSB 0x11 +#define bq27541CMD_FCC_LSB 0x12 +#define bq27541CMD_FCC_MSB 0x13 +#define bq27541CMD_AI_LSB 0x14 +#define bq27541CMD_AI_MSB 0x15 +#define bq27541CMD_TTE_LSB 0x16 +#define bq27541CMD_TTE_MSB 0x17 +#define bq27541CMD_TTF_LSB 0x18 +#define bq27541CMD_TTF_MSB 0x19 +#define bq27541CMD_SI_LSB 0x1A +#define bq27541CMD_SI_MSB 0x1B +#define bq27541CMD_STTE_LSB 0x1C +#define bq27541CMD_STTE_MSB 0x1D +#define bq27541CMD_MLI_LSB 0x1E +#define bq27541CMD_MLI_MSB 0x1F +#define bq27541CMD_MLTTE_LSB 0x20 +#define bq27541CMD_MLTTE_MSB 0x21 +#define bq27541CMD_AE_LSB 0x22 +#define bq27541CMD_AE_MSB 0x23 +#define bq27541CMD_AP_LSB 0x24 +#define bq27541CMD_AP_MSB 0x25 +#define bq27541CMD_TTECP_LSB 0x26 +#define bq27541CMD_TTECP_MSB 0x27 +#define bq27541CMD_RSVD_LSB 0x28 +#define bq27541CMD_RSVD_MSB 0x29 +#define bq27541CMD_CC_LSB 0x2A +#define bq27541CMD_CC_MSB 0x2B +#define bq27541CMD_SOC_LSB 0x2C +#define bq27541CMD_SOC_MSB 0x2D +#define bq27541CMD_SOH_LSB 0x2E +#define bq27541CMD_DCAP_LSB 0x3C +#define bq27541CMD_DCAP_MSB 0x3D +#define bq27541CMD_DFCLS 0x3E +#define bq27541CMD_DFBLK 0x3F +#define bq27541CMD_ADF 0x40 +#define bq27541CMD_ACKSDFD 0x54 +#define bq27541CMD_DFDCKS 0x60 +#define bq27541CMD_DFDCNTL 0x61 +#define bq27541CMD_DNAMELEN 0x62 +#define bq27541CMD_DNAME 0x63 + +#define BQ27541_FLAG_DSC BIT(0) +#define BQ27541_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ +#define BQ27541_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ +#define BQ27541_FLAG_FC BIT(9) +#define BQ27541_FLAG_OTD BIT(14) +#define BQ27541_FLAG_OTC BIT(15) + +#define BQ27541_CS_SS BIT(13) +#define BQ27541_CS_DLOGEN BIT(15) + +/* Control subcommands */ +#define BQ27541_SUBCMD_CTNL_STATUS 0x0000 +#define BQ27541_SUBCMD_DEVCIE_TYPE 0x0001 +#define BQ27541_SUBCMD_FW_VER 0x0002 +#define BQ27541_SUBCMD_HW_VER 0x0003 +#define BQ27541_SUBCMD_DF_CSUM 0x0004 +#define BQ27541_SUBCMD_PREV_MACW 0x0007 +#define BQ27541_SUBCMD_CHEM_ID 0x0008 +#define BQ27541_SUBCMD_BD_OFFSET 0x0009 +#define BQ27541_SUBCMD_INT_OFFSET 0x000a +#define BQ27541_SUBCMD_CC_VER 0x000b +#define BQ27541_SUBCMD_OCV 0x000c +#define BQ27541_SUBCMD_BAT_INS 0x000d +#define BQ27541_SUBCMD_BAT_REM 0x000e +#define BQ27541_SUBCMD_SET_HIB 0x0011 +#define BQ27541_SUBCMD_CLR_HIB 0x0012 +#define BQ27541_SUBCMD_SET_SLP 0x0013 +#define BQ27541_SUBCMD_CLR_SLP 0x0014 +#define BQ27541_SUBCMD_FCT_RES 0x0015 +#define BQ27541_SUBCMD_ENABLE_DLOG 0x0018 +#define BQ27541_SUBCMD_DISABLE_DLOG 0x0019 +#define BQ27541_SUBCMD_SEALED 0x0020 +#define BQ27541_SUBCMD_ENABLE_IT 0x0021 +#define BQ27541_SUBCMD_DISABLE_IT 0x0023 +#define BQ27541_SUBCMD_CAL_MODE 0x0040 +#define BQ27541_SUBCMD_RESET 0x0041 + +#define BQ27542_DEVICE_ID 0x542 + +#include + +static enum power_supply_property bq27541_battery_props[] = { + //POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, // jason.kim 2015.10.15 + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + //POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + //POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + //POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_ENERGY_NOW, + //POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_TEMP, +}; + +#if 0 +int bq27541_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val); + +void bq27541_external_power_changed(struct power_supply *psy); +#endif + + +#endif /* _LINUX_HDQ_GPIO_H */ + diff --git a/drivers/power/supply/bq27541_fuelgauger_hdq.c b/drivers/power/supply/bq27541_fuelgauger_hdq.c new file mode 100644 index 0000000000000000000000000000000000000000..c0d472ca24fd5926fab4c53fba895bfc9d30e5d5 --- /dev/null +++ b/drivers/power/supply/bq27541_fuelgauger_hdq.c @@ -0,0 +1,2700 @@ +/* Copyright (C) 2008 Rodolfo Giometti + * Copyright (C) 2008 Eurotech S.p.A. + * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. + * + * Copyright (c) 2011, 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. + */ +// jason.kim 2015.11.12 update driver +// Fix failure often to read from battery through HDQ +// Tidy up codes that update and check parameters of battery +// Add reporting current +// Add writing to battery through HDQ + +#include +#include +#include "bq27541-hdq-gpio.h" +#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 +#include +//#define ZXZ_BQ27541 + #define DEBUG_BQ + //#define DEBUG_HDQ + //#define DEBUG_UPDATE_VALUE + //#define DEBUG_INIT_VALUE +#define NOT_USE_HDQ_TEMPERATURE // modefied by robin.cho. charger and HDQ has a gap for temperature. For remove it, i get temperature from charger. + + +#define USE_REMAP_TABLE // jason.kim 2015.11.23 use remap table +// #define USE_SW_TUNE // jason.kim 2015.11.27 use increase 100%, 0% ranges +#define USE_SERIAL_32_BYTES // jason.kim 2015.12.08 use only 12 bytes for the serial number +#ifdef USE_SERIAL_32_BYTES + +typedef struct _serial_number +{ + unsigned char length_SN; + char SN[13]; + unsigned char pad1; + unsigned char length_ModelName; + char ModelName[10]; + unsigned char pad2; + unsigned char length_MF_date; + char MF_date[4]; +}PM85_SERIAL; +#endif +//+ jason.kim 2015.11.24 dump registers +#define BQ27541_REG_CNTL 0x00 /* Control Register */ +#define BQ27541_REG_AR 0x02 /* At rate */ +#define BQ27541_REG_UFSOC 0x04 /* Unfiltered SOC */ +#define BQ27541_REG_TEMP 0x06 /* Temperature */ +#define BQ27541_REG_VOLT 0x08 /* Voltage */ +#define BQ27541_REG_FLAGS 0x0A +#define BQ27541_REG_NAC 0x0C /* Nominal available capacity */ +#define BQ27541_REG_FAC 0x0E /* Full available capacity */ +#define BQ27541_REG_RM 0x10 /* Remaining available capacity */ +#define BQ27541_REG_FCC 0x12 /* Full charge capacity */ +#define BQ27541_REG_AI 0x14 /* Average current */ +#define BQ27541_REG_TTE 0x16 /* Time to empty */ +#define BQ27541_REG_FFCC 0x18 /* Filtered FCC */ +#define BQ27541_REG_SI 0x1A /* Standby current */ +#define BQ27541_REG_UFFCC 0x1C /* Unfiltered FCC */ +#define BQ27541_REG_MLI 0x1E /* Max load current */ +#define BQ27541_REG_UFRM 0x20 /* Unfiltered RM */ +#define BQ27541_REG_FRM 0x22 /* Filtered RM */ +#define BQ27541_REG_AP 0x24 /* Average power */ + +#define BQ27541_REG_INTTEMP 0x28 /* Internal temperature */ +#define BQ27541_REG_CC 0x2A /* Cycle count */ +#define BQ27541_REG_SOC 0x2C /* State of charge */ +#define BQ27541_REG_SOH 0x2E /* State of health */ + +#define BQ27541_REG_PCHG 0x34 /* Passed charge */ +#define BQ27541_REG_DOD0 0x36 /* Depth of discharge during the most recent OCV reading */ +#define BQ27541_REG_SDSG 0x38 /* Self-discharge current */ +//- jason.kim 2015.11.24 dump registers + +//+ jason.kim 2015.12.07 serial number +#define BQ27541_REG_DFCLS 0x3E /* DataFlashClass */ +#define BQ27541_REG_DFBLK 0x3F /* DataFlashBlock */ +#define BQ27541_REG_ADF 0x40 +#define BQ27541_REG_DFDCKS 0x60 +#define BQ27541_REG_DFDCNTL 0x61 + +#define BQ27541_FLAG_CS_QEN BIT(0) +#define BQ27541_FLAG_CS_VOK BIT(1) +#define BQ27541_FLAG_CS_RUP_DIS BIT(2) +#define BQ27541_FLAG_CS_LDMD BIT(3) +#define BQ27541_FLAG_CS_SLEEP BIT(4) +#define BQ27541_FLAG_CS_FULLSLEEP BIT(5) +#define BQ27541_FLAG_CS_HIBERNATE BIT(6) +#define BQ27541_FLAG_CS_SHUTDWN BIT(7) +#define BQ27541_FLAG_CS_HDQHOSTIN BIT(8) +#define BQ27541_FLAG_CS_RSVD BIT(9) +#define BQ27541_FLAG_CS_BCA BIT(10) +#define BQ27541_FLAG_CS_CCA BIT(11) +#define BQ27541_FLAG_CS_CALMODE BIT(12) +#define BQ27541_FLAG_CS_SS BIT(13) +#define BQ27541_FLAG_CS_FAS BIT(14) +#define BQ27541_FLAG_CS_SE BIT(15) +//- jason.kim 2015.12.07 serial number + +static DEFINE_MUTEX(battery_mutex); + +// host to bq27541 +#define tBreak 400 // HDQ Break Time (min 190us) +#define tBR 100 // HDQ Break Recovery Time (min 40us) +#define tHW1 20 // Host sends 1 time (0.5~50us) +#define tHW0 115 // Host sends 0 time (86~145us) +#define tCYCH 230 // Host bit window timing (min 190us) + +// bq27541 to host +#define tDW1 41 // Slave sends 1 time (32~50us) +#define tDW0 113 // Slave sends 0 time (80~145us) +#define tCYCD_T_ONE 60 // FIRST TEST POINT IN CYCD time (max tDW1 50 + alpha) +#define tCYCD_T_TWO 145 // SECOND TEST POINT AFTER FIRST (max tDW0 145 + alpha) +#define tRND 210 // Turnaround time +#define tCYCD 250 // The max of Cycle time of device +#define tRSPS_HIGH 150 + +#define tTO 500 // Time-Out Bit Receiption (500us) + +#define HDQ_ERROR 0xFFFF // Time-Out Error Condition +#define BitCount 8 //8 bit + +#define BATTERY_FUEL_GAUGER_SEC 10 // 10 secs +#define BATTERY_FUEL_GAUGER_SEC_LOW 5 // 5 secs +#define TIMER_HDQ 400 //About 230us. +#define BUFFERSIZE 32 //# of bytes for Tx & Rx buffers +#define ATRATE_MA -100 // USER CONFIG: AtRate setting (mA) +#define DEFAULT_CAPACITY (50) +#define _KELVIN 2731 +#define TEMP_DEFAULT (273 + _KELVIN) // 27.3 +#define TEMP_LIMIT_LOW (-250 + _KELVIN) // -25 +#define TEMP_LIMIT_HIGH (750 + _KELVIN) // 75C + + +#define NEED_SN_READ 0xBC +//#define DUMMY_GAUGE +//#define _FAIL_CNT // [robin.cho] save fail count and read count +struct bq27541_device_info; +struct bq27541_access_methods { + int (*read)(struct bq27541_device_info *di, u8 reg); + int (*write)(struct bq27541_device_info *di, u8 reg, u8 val); +}; + +struct bq27541_reg_cache { + int temperature; + int time_to_empty; + //int time_to_empty_avg; + //int time_to_full; + int charge_full; + int cycle_count; + int remaining_life; + int capacity; + int energy; + int flags; + //int power_avg; + int health; + + int voltage_now; + int current_now; + int charge_now; +}; +enum bq27541_chip { BQ27541}; + +/** + * struct bq27541_device_data - Platform-dependent data for hdq-gpio + * @pin: GPIO pin to use + * @is_open_drain: GPIO pin is configured as open drain + */ +struct bq27541_device_info { + const char *name; + unsigned int pin; + unsigned int is_open_drain:1; + struct device *dev; + int id; + enum bq27541_chip chip; + struct bq27541_reg_cache cache; + int charge_design_full; + unsigned long last_update; + struct delayed_work battery_work; + struct power_supply *bat; + spinlock_t hdq_lock; + // struct mutex lock; + struct mutex poll_lock; // jason.kim 2015.10.15 + struct bq27541_access_methods bus; + int battery_exist; + int battery_init; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_state_active; + // jason.kim 2015.12.07 serial number + char serial_no[33]; + int serial_len; +#ifdef _FAIL_CNT + int fail_count; + int read_count; + int id_fail_count; + int Last_fail_bat_id; +#endif +/* PLATFORM]-add by T2MNB.ZXZ,add hotswap feature,2018/06/27,defect-6502875,Begin */ + int poll_interval; + int poll_enable; + bool hot_swap; + int test_temp_enable; // jason.kim 2016.6.2 + int test_temp; // jason.kim 2016.3.25 SW temperature control + + // jason.kim 2016.7.12 Test battery capacity + int test_cap_enable; + int test_cap; + int test_health_enable; + int test_health; + + // jason.kim 2016.7.18 Test battery voltage + int test_voltage_enable; + int test_voltage; +/* PLATFORM]-add by T2MNB.ZXZ,add hotswap feature,2018/06/27,defect-6502875,End */ + +}; + +unsigned char *DeviceName; +/*Add begin Defect-6099797, for HDQ charge safe time */ +int BatteryDesignCap =0; +/*Add end Defect-6099797, for HDQ charge safe time */ + +/* + *set gpio as input/output + *bit = nozero,input,usually bit = 1 + *bit = 0,output,and default value = 1 +*/ +static inline void hdq_gpio_dir(struct bq27541_device_info *pdata, u8 bit) +{ + if (bit) + gpio_direction_input(pdata->pin); + else + gpio_direction_output(pdata->pin, 1); +} + +/* Issue break pulse to the device + * Local function to send a HDQ break-transmission for providing a safe + * communication start. + */ +static inline void gpio_hdq_break(struct bq27541_device_info *pdata) +{ + gpio_set_value(pdata->pin, 0); + udelay(tBreak); + gpio_set_value(pdata->pin, 1); + udelay(tBR); +} + +/* + *bit = 0,HDQ = 0;which means tHW0 LOW and tCYCH-tHW0 High + *bit = 1,HDQ = 1;Which means tHW1 LOW and tCYCH-tHW1 High + */ +static inline void gpio_hdq_bit_Write(struct bq27541_device_info *pdata, u8 bit) +{ + int tTime; + if(bit) + tTime = tHW1; + else + tTime = tHW0; + + gpio_set_value(pdata->pin, 0); + udelay(tTime); + + gpio_set_value(pdata->pin, 1); + udelay(tCYCH-tTime); +} + +//+ jason.kim 2015.12.01 tidy codes up +// Error rates verified with 2 units is around 3 times for around 12 hours +static void gpio_hdq_byte_Write(struct bq27541_device_info *pdata, u8 val) +{ + int i; + for(i=0; i<8; i++) { + gpio_hdq_bit_Write(pdata, val & (1<pin)) { + now = ktime_get_real(); + if (ktime_to_us(ktime_sub(now, start)) > tCYCD) { +#ifdef _FAIL_CNT + if(pdata->fail_count!=0xFFFFFFFF) + pdata->fail_count++; +#endif + dev_err(pdata->dev, "%s: error\n", __func__); + return -1; + } + } + udelay(tCYCD_T_ONE); + bit = gpio_get_value(pdata->pin) ? 1 : 0; + val = val | (bit << i); + udelay(tCYCD_T_TWO-tCYCD_T_ONE); + } +#ifdef _FAIL_CNT + if(pdata->read_count!=0xFFFFFFFF) + pdata->read_count++; +#endif + + return val; +} + +static int hdq_gpio_rw(struct bq27541_device_info *pdata, int write, u8 reg, u8 val) +{ + unsigned long flags; + int value = 0; + int t_rnd; + + spin_lock_irqsave(&pdata->hdq_lock, flags); + + hdq_gpio_dir(pdata, 0);// output reg + gpio_hdq_break(pdata); + + gpio_hdq_byte_Write(pdata, write ? (reg | 0x80) : (reg & 0x7f)); + + if(write) { + udelay(tCYCH); + gpio_hdq_byte_Write(pdata, val); + t_rnd = tRND; + + } else { + hdq_gpio_dir(pdata, 1);// input to read + value = gpio_hdq_byte_read(pdata); + t_rnd = tRND + tCYCD - tCYCD_T_ONE - tCYCD_T_TWO; + } + + spin_unlock_irqrestore(&pdata->hdq_lock, flags); + udelay(t_rnd); // jason.kim 2016.9.29 Fixes timing for bq27542 + +#ifdef DEBUG_HDQ + if(value < 0) + printk("%s,%d,%d\n",__FUNCTION__,__LINE__, val); +#endif + return value; +} +//- jason.kim 2015.12.01 tidy codes up + +#if 0 +//sort for decrease +static int compare(const void *lhs, const void *rhs) { + int lhs_integer = *(const int *)(lhs); + int rhs_integer = *(const int *)(rhs); + + if (lhs_integer < rhs_integer) return -1; + if (lhs_integer > rhs_integer) return 1; + return 0; +} +#endif + +static inline int hdq_gpio_read(struct bq27541_device_info *di, u8 reg) +{ +#if 0 + int try_cnt = 5; + int temp_value[5]={0,}; + int i; + for(i=0;idev, "temp_value[0]0x%x temp_value[1]0x%x temp_value[2]0x%x temp_value[3]0x%x temp_value[4]0x%x return temp_value[3] 0x%x",temp_value[0],temp_value[1],temp_value[2],temp_value[3],temp_value[4],temp_value[3]); + return temp_value[3]; +#else + return hdq_gpio_rw(di, 0, reg, 0); +#endif +} + +static inline int hdq_gpio_write(struct bq27541_device_info *di, u8 reg, u8 val) +{ + return hdq_gpio_rw(di, 1, reg, val); +} + +/* + * Common code for BQ27541 devices + */ +static int bq27541_write8(struct bq27541_device_info *di, u8 reg, u8 val) +{ + return di->bus.write(di, reg, val); +} + +static int bq27541_write16(struct bq27541_device_info *di, u8 reg, u16 val) +{ + int ret; + ret = bq27541_write8(di, reg, val & 0xff); + if(ret >= 0) + ret = bq27541_write8(di, reg+1, val >> 8); + return ret; +} + +static int bq27541_read8(struct bq27541_device_info *di, u8 reg) +{ + return di->bus.read(di, reg); +} + +static int bq27541_read16 (struct bq27541_device_info *di, u8 reg) +{ + int upper, lower, val; + + upper = bq27541_read8(di, reg+1); + if(upper < 0) + return upper; + lower = bq27541_read8(di, reg); + if(lower < 0) + return lower; + + val = upper << 8 | lower; + +#ifdef DEBUG_HDQ + printk("Upper 0x%x, lower 0x%x, ret = 0x%x\n", upper, lower, val); +#endif + return val; +} + +static int bq27541_pinctrl_init(struct bq27541_device_info *di) +{ + int ret; + + di->pinctrl = devm_pinctrl_get(di->dev); + if (IS_ERR_OR_NULL(di->pinctrl)) { + ret = PTR_ERR(di->pinctrl); + goto err_pinctrl_get; + } + + di->pinctrl_state_active = pinctrl_lookup_state(di->pinctrl, "bq27541_hdq"); + if (IS_ERR_OR_NULL(di->pinctrl_state_active)) { + ret = PTR_ERR(di->pinctrl_state_active); + goto err_pinctrl_lookup; + } + + ret = pinctrl_select_state(di->pinctrl, di->pinctrl_state_active); + if (ret) { + return ret; + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(di->pinctrl); + +err_pinctrl_get: + di->pinctrl = NULL; + + return ret; +} + +//+ jason.kim 2015.12.07 serial number +static int set_mfg_block(struct bq27541_device_info *di, int sealed) +{ + u8 block = 1; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + if (sealed) { + block = 2; + } else { + int dfd_cntl_status = 0; + dfd_cntl_status = bq27541_read8(di, BQ27541_REG_DFDCNTL); + if (dfd_cntl_status != 0) { + bq27541_write8(di, BQ27541_REG_DFDCNTL, 0); + } + bq27541_write8(di, BQ27541_REG_DFCLS, 58); + block = 1; + } + + bq27541_write8(di, BQ27541_REG_DFBLK, block); + msleep(1); + return 0; +} + +#ifdef USE_SERIAL_32_BYTES +#define SERIAL_BYTES 32 +#if 0 +static int is_good_serial(char *serial) +{ + int i; + for(i=0; iserial_len = 0; + sealed = (flags & BQ27541_FLAG_CS_SS) == BQ27541_FLAG_CS_SS; + if (flags < 0 || set_mfg_block(di, sealed)) { + dev_err(di->dev, "set_mfg_block failed\n"); + return; + } + +#ifdef USE_SERIAL_32_BYTES + serial_len = SERIAL_BYTES; + sum = 0; +#else + serial_len = bq27541_read8(di, BQ27541_REG_ADF); + sum = serial_len; +#endif + if (serial_len <= 0 || serial_len > 32) { + dev_err(di->dev, "serial_len %d is not valid\n", serial_len); + return; + } + + memset(di->serial_no, 0, sizeof(di->serial_no)); + for (i = 0; i < serial_len; i++) { +#ifdef USE_SERIAL_32_BYTES + data = bq27541_read8(di, BQ27541_REG_ADF + i); +#else + data = bq27541_read8(di, BQ27541_REG_ADF + i + 1); +#endif +// dev_err(di->dev, "## data 0x%x \n", data); + + if(data < 0) { + dev_info(di->dev, "Read %ith failed\n", i); + return; + } + di->serial_no[i] = (char)data; + sum += di->serial_no[i]; + } + + data = bq27541_read8(di, BQ27541_REG_DFDCKS); + sum += data; + if (data < 0 || sum != 0xFF) { + dev_err(di->dev, "check-sum 0x%x data 0x%x error \n", sum , data); + return; + } +#ifdef USE_SERIAL_32_BYTES + if( di->serial_no[0]<=0) + { + dev_err(di->dev, "serial number:error ::di->serial_no[0] 0x%x di->serial_len 0x%x\n",di->serial_no[0],di->serial_len ); + return; + + } +#endif + di->serial_len = serial_len; +} + +static int bq27541_battery_write_serial(struct bq27541_device_info *di, const char* serial_no) +{ + u8 sum = 0; + int sealed = 0; + int serial_len = strlen(serial_no); + u8 buf_w[32], buf_v[32]; + int i; + int flags = 0; + int data; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + if (serial_len && serial_no[serial_len-1] == 0x0a) { + serial_len = serial_len - 1; + } + +#ifdef USE_SERIAL_32_BYTES + if(serial_len != SERIAL_BYTES) { + dev_err(di->dev, "serial_len %d(%d) is not valid\n", serial_len, SERIAL_BYTES); + return 0; + } +#endif + + if (serial_len <= 0 || serial_len > 32) { + dev_err(di->dev, "serial_len %d is not valid\n", serial_len); + return 0; + } + + bq27541_write16(di, BQ27541_REG_CNTL, BQ27541_SUBCMD_CTNL_STATUS); + udelay(66); + flags = bq27541_read16(di, BQ27541_REG_CNTL); + sealed = (flags & BQ27541_FLAG_CS_SS) == BQ27541_FLAG_CS_SS; + if (flags < 0 || set_mfg_block(di, sealed)) { + dev_err(di->dev, "set_mfg_block failed\n"); + return 0; + } + +#ifdef USE_SERIAL_32_BYTES + memset(buf_w, 0, sizeof(buf_w)); + memcpy(buf_w, serial_no, serial_len); + dev_info(di->dev, "Write serial [%s] to battery\n", buf_w); +#else + // prepare data + memset(buf_w, 0, sizeof(buf_w)); + buf_w[0] = serial_len; + memcpy(buf_w+1, serial_no, serial_len); + dev_info(di->dev, "Write serial [%s] to battery\n", buf_w+1); +#endif + + // write it to battery + for (i = 0; i < sizeof(buf_w); i++) { + bq27541_write8(di, BQ27541_REG_ADF+i, buf_w[i]); + sum += buf_w[i]; + } + sum = 0xff - sum; + + // read it back + memset(buf_v, 0, sizeof(buf_w)); + for (i = 0; i < sizeof(buf_w); i++) { + data = bq27541_read8(di, BQ27541_REG_ADF + i); + if(data < 0) { + dev_info(di->dev, "Read %ith failed\n", i); + return 0; + } + buf_v[i] = (char)data; + } + + // check it + if(memcmp(buf_w, buf_v, sizeof(buf_w))) { + dev_err(di->dev, "Verification failed\n"); + return 0; + } + // write check-sum to battery + dev_info(di->dev, "Check-sum=0x%x\n", sum); + bq27541_write8(di, BQ27541_REG_DFDCKS, sum); + msleep(200); + return serial_len; +} +//- jason.kim 2015.12.07 serial number + +//+ jason.kim 2015.12.08 dump MFG-B +#define DUMP_COL 16 +static void dump_bin(u8 *buf, int size) +{ + int i, j; + int lc; + char line[DUMP_COL]; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + pr_info("========================\n"); + for(lc=0, i=0; i= ' ' && line[j] <= '~') + pr_cont( "%c", line[j]); + else + pr_cont( "."); + } + pr_cont("\n"); + } + } + pr_info("========================\n"); +} + +static void bq27541_battery_dump_mfg_B(struct bq27541_device_info *di) +{ + int flags; + int data; + u8 sum = 0; + int sealed = 0; + char serial_no[32]; + int serial_len; + int i; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + bq27541_write16(di, BQ27541_REG_CNTL, BQ27541_SUBCMD_CTNL_STATUS); + udelay(66); + flags = bq27541_read16(di, BQ27541_REG_CNTL); + di->serial_len = 0; + sealed = (flags & BQ27541_FLAG_CS_SS) == BQ27541_FLAG_CS_SS; + if (flags < 0 || set_mfg_block(di, sealed)) { + dev_err(di->dev, "set_mfg_block failed\n"); + return; + } + + serial_len = 32; + for (i = 0; i < serial_len; i++) { + data = (char)bq27541_read8(di, BQ27541_REG_ADF + i); + if(data < 0) { + dev_info(di->dev, "Read %ith failed\n", i); + return; + } + serial_no[i] = (char)data; + sum += serial_no[i]; + } + data = bq27541_read8(di, BQ27541_REG_DFDCKS); + if(data < 0) { + dev_info(di->dev, "Read check-sum failed\n"); + return; + } + + dump_bin((u8 *)serial_no, 32); + dev_info(di->dev, "Check sum=0x%x(0x%x)\n", sum, data); +} +//- jason.kim 2015.12.08 dump MFG-B + +//+ jason.kim 2016.01.20 Check and update battery parameters +static int bq27541_get_sealing(struct bq27541_device_info *di) +{ + int flags; + int sealed; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + bq27541_write16(di, BQ27541_REG_CNTL, BQ27541_SUBCMD_CTNL_STATUS); + udelay(66); + flags = bq27541_read16(di, BQ27541_REG_CNTL); + dev_info(di->dev, "flags 0x%X\n", flags); + sealed = (flags & BQ27541_FLAG_CS_SS) == BQ27541_FLAG_CS_SS; + if (flags < 0) { + dev_err(di->dev, "Failed to read BQ27541_REG_CNTL\n"); + return flags; + } + return sealed; +} + +static int bq27541_set_sealing(struct bq27541_device_info *di, int sealing) +{ + int sealed; + int ret; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + if (sealing) { + bq27541_write16(di, BQ27541_REG_CNTL, BQ27541_SUBCMD_SEALED); + msleep(200); + bq27541_write16(di, BQ27541_REG_CNTL, BQ27541_SUBCMD_CTNL_STATUS); + udelay(66); + } else { + bq27541_write16(di, BQ27541_REG_CNTL, 0x0414); + bq27541_write16(di, BQ27541_REG_CNTL, 0x3672); + msleep(100); + bq27541_write16(di, BQ27541_REG_CNTL, BQ27541_SUBCMD_CTNL_STATUS); + udelay(66); + } + + sealed = bq27541_get_sealing(di); + ret = (sealed == sealed) ? 0 : -1; + if(ret < 0) + dev_err(di->dev, "Failed to set sealing(%d)\n", sealing); + + return ret; +} + +static int bq27541_rw_block(struct bq27541_device_info *di, int subcmd, int offset) +{ + int ret; + + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + ret = bq27541_write8(di, BQ27541_REG_DFCLS, subcmd); + if (ret >= 0) + ret = bq27541_write8(di, BQ27541_REG_DFBLK, offset / 32); + if (ret >= 0) + ret = bq27541_write8(di, BQ27541_REG_DFDCNTL, 0); + return ret; +} + +static int bq27541_rw_flash(struct bq27541_device_info *di, int subcmd, int offset, u8 *buf, int bytes, int write) +{ + int ret; + int i; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + ret = bq27541_rw_block(di, subcmd, offset); + if (ret < 0) + return ret; + + // i must be less then 32 + for(i = offset%32; i < (offset%32 + bytes); i++) { + if(write) { + ret = bq27541_write8(di, BQ27541_REG_ADF + i, *buf++); + if (ret < 0) + return ret; + } else { + ret = bq27541_read8(di, BQ27541_REG_ADF + i); + if (ret < 0) + return ret; + *buf++ = (u8)ret; + } + } + return 0; +} + +static int bq27541_read_flash16(struct bq27541_device_info *di, int subcmd, int offset) +{ + int ret; + u8 buf[2]; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + ret = bq27541_rw_flash(di, subcmd, offset, buf, 2, 0); + if (ret < 0) + return ret; + + return ((int)buf[0] << 8) | buf[1]; +} + +__attribute__ ((unused)) static int bq27541_write_flash16(struct bq27541_device_info *di, int subcmd, int offset, int data) +{ + u8 buf[2]; + buf[0] = (data >> 8) & 0xff; + buf[1] = data & 0xff; + + return bq27541_rw_flash(di, subcmd, offset, buf, 2, 1); +} + +static int bq27541_battery_reset_param(struct bq27541_device_info *di) +{ + int ret; + u8 buf[34] = { + 0x0A,0xF0,0x00,0x0A,0x05,0x00,0x32,0x01,0xC2,0x14,0x14,0x00,0x08,0x09,0xF6,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + u8 sum; + int i; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + ret = bq27541_set_sealing(di, 0); // unseal + if (ret < 0) + return ret; + + bq27541_rw_flash(di, 68, 0, buf, 32, 1); + sum = 0; + for (i=0; i<32; i++) { + sum += buf[i]; + } + sum = 0xff - sum; + bq27541_write8(di, BQ27541_REG_DFDCKS, sum); + msleep(200); + bq27541_rw_flash(di, 68, 0, buf, 32, 0); + dump_bin(buf, 32); + di->battery_init = 0; + + ret = bq27541_set_sealing(di, 1); // seal + if (ret < 0) + return ret; + return 0; +} + +static int bq27541_battery_init_param(struct bq27541_device_info *di) +{ + int ret; + int h_current = 0; + int h_voltage = 0; + u8 buf[34]; + u8 sum; + int i; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + ret = bq27541_set_sealing(di, 0); // unseal + if (ret < 0) + return ret; + + h_current = bq27541_read_flash16(di, 68, 11); + h_voltage = bq27541_read_flash16(di, 68, 13); + dev_info(di->dev, "Current %d, Voltage %d\n", h_current, h_voltage); + if(h_current != 0 || h_voltage != 0) { + bq27541_rw_flash(di, 68, 0, buf, 32, 0); + dump_bin(buf, 32); + buf[11] = 0; + buf[12] = 0; + buf[13] = 0; + buf[14] = 0; + bq27541_rw_flash(di, 68, 0, buf, 32, 1); + sum = 0; + for (i=0; i<32; i++) { + sum += buf[i]; + } + sum = 0xff - sum; + bq27541_write8(di, BQ27541_REG_DFDCKS, sum); + msleep(200); + h_current = bq27541_read_flash16(di, 68, 11); + h_voltage = bq27541_read_flash16(di, 68, 13); + if(h_current == 0 && h_voltage == 0) + di->battery_init = 1; + dev_info(di->dev, "Current %d, Voltage %d\n", h_current, h_voltage); + } else { + di->battery_init = 1; + } + bq27541_rw_flash(di, 68, 0, buf, 32, 0); + dump_bin(buf, 32); + ret = bq27541_set_sealing(di, 1); // seal + if (ret < 0) + ret = bq27541_set_sealing(di, 1); // seal + if (ret < 0) + ret = bq27541_set_sealing(di, 1); // seal + + return ret; +} +//- jason.kim 2016.01.20 Check and update battery parameters + +static int bq27541_simple_value(int value, + union power_supply_propval *val) +{ + if (value < 0) + return value; + + val->intval = value; + + return 0; +} +#if 0 +static int bq27541_s16_value(int value, union power_supply_propval *val) +{ + if (value < 0) + return value; + + val->intval = (int)((s16)value); + return 0; +} +#endif +static int bq27541_battery_read_id(struct bq27541_device_info *di) +{ + int retry = 5; + int value; +#ifdef DEBUG_BQ + printk("zxz ------- %s ,line=%d \n", __FUNCTION__,__LINE__); + dev_err(di->dev, "zxz bq27541_battery_read_id\n"); +#endif +#if 0 + bq27541_write16(di, bq27541CMD_CNTL_LSB, BQ27541_SUBCMD_DEVCIE_TYPE); // this code removed by robin.cho + value = bq27541_read16(di, bq27541CMD_CNTL_LSB); + retry=0; +#else + do { + bq27541_write16(di, bq27541CMD_CNTL_LSB, BQ27541_SUBCMD_DEVCIE_TYPE); + value = bq27541_read16(di, bq27541CMD_CNTL_LSB); + //mdelay(100); + + } while((value !=BQ27542_DEVICE_ID) && retry--); + #endif +#ifdef DEBUG_BQ + dev_err(di->dev, "zxz bq27541_battery_read_id , value=%x ,retry=%d \n",value,retry); + printk("zxz ------- %s ,line=%d ,value=%x \n", __FUNCTION__,__LINE__,value); +#endif + return value; +} + +/* + * Return the battery average current in µA + * Note that current can be negative signed as well + * Or 0 if something fails. + */ +static int bq27541_battery_read_current(struct bq27541_device_info *di) +{ + int curr; + curr = bq27541_read16(di, bq27541CMD_AI_LSB); + if(curr < 0){ + dev_err(di->dev, "error reading curr\n"); + } + return curr; +} + +/* + * Return the battery Cycle count total + * Or < 0 if something fails. + */ +static int bq27541_battery_read_cc(struct bq27541_device_info *di) +{ + int cyct; + + cyct = bq27541_read16(di, bq27541CMD_CC_LSB); + if (cyct < 0) + dev_err(di->dev, "error reading cycle count total\n"); + + return cyct; +} +#if 0 + +/* + * Read a power avg register. + * Return < 0 if something fails. + */ +static int bq27541_battery_read_pwr_avg(struct bq27541_device_info *di, u8 reg) +{ + int tval; + + tval = bq27541_read16(di, reg, reg+1); + if (tval < 0) { + dev_err(di->dev, "error reading power avg rgister %02x: %d\n", + reg, tval); + return tval; + } + return tval; +} +#endif + +/* + * Higher versions of the chip like BQ27425 and BQ27500 + * differ from BQ27000 and BQ27200 in calculation of certain + * parameters. Hence we need to check for the chip type. + */ +static bool bq27xxx_is_chip_version_higher(struct bq27541_device_info *di) +{ + + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + if (di->chip == BQ27541) + return true; + return false; +} + +/*Remove by T2M Q.Z for PR1003449 +* Do not use status detection from bq27541. +* Use smb1357 status detection. +*/ +/* +static int bq27541_battery_status(struct bq27541_device_info *di, + union power_supply_propval *val) +{ + int status; + + if(di->battery_exist == 0) + status = POWER_SUPPLY_STATUS_UNKNOWN; + else{ + if (bq27xxx_is_chip_version_higher(di)) { + if (di->cache.flags & BQ27541_FLAG_FC) + status = POWER_SUPPLY_STATUS_FULL; + else if (di->cache.flags & BQ27541_FLAG_DSC) + status = POWER_SUPPLY_STATUS_DISCHARGING; + else + status = POWER_SUPPLY_STATUS_CHARGING; + } + } + val->intval = status; + + return 0; +} +*/ + +/* +* get FLAGS from bq27541. many marker bits in the FLAGS. +* FC means full-charged . OTC means Over-Temperature and so on. +*/ +static int bq27541_get_battery_flags(struct bq27541_device_info *di) +{ + int flags; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + flags = bq27541_read16(di, bq27541CMD_FLAGS_LSB); + if (flags < 0){ + dev_err(di->dev, "error reading flags\n"); + } + + return flags; +} + +static int bq27541_battery_read_volt(struct bq27541_device_info *di) +{ + int volt; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line = %d\n",__FUNCTION__,__LINE__); + #endif + volt = bq27541_read16(di, bq27541CMD_VOLT_LSB); + if (volt < 0) { + dev_err(di->dev, "error reading voltage\n"); + return volt; + } + + return volt *1000; +} + +/* + * Return a battery charge value in µAh + * Or < 0 if something fails. + */ +static int bq27541_battery_read_charge(struct bq27541_device_info *di, u8 reg) +{ + int charge; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line =%d \n",__FUNCTION__,__LINE__); + #endif + charge = bq27541_read16(di, reg); + if (charge < 0) { + dev_dbg(di->dev, "error reading charge \n"); + return charge; + } + + if (bq27xxx_is_chip_version_higher(di)) + charge *= 1000; + + return charge; +} + +/* + * Return the battery FullChargeCapacity in mAh + * Or < 0 if something fails. + */ +static inline int bq27541_battery_read_fcc(struct bq27541_device_info *di) +{ + return bq27541_battery_read_charge(di, bq27541CMD_FCC_LSB); +} + + +/* + * Return the battery Nominal available capaciy in µAh + * Or < 0 if something fails. + */ +static int bq27541_battery_read_nac(struct bq27541_device_info *di) +{ + int charge; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line =%d \n",__FUNCTION__,__LINE__); + #endif + charge = bq27541_read16(di, bq27541CMD_NAC_LSB); + if (charge < 0) { + dev_err(di->dev, "error reading NAC\n"); + return charge; + } + + return charge * 1000; +} + +/* + * Return the battery Relative State-of-Charge + * Or = 0xff if something fails. + */ +static int bq27541_battery_read_rsoc(struct bq27541_device_info *di) +{ + int rsoc; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line =%d \n",__FUNCTION__,__LINE__); + #endif + rsoc = bq27541_read16(di, bq27541CMD_SOC_LSB); + if (rsoc < 0){ + dev_err(di->dev, "error reading State-of-Charge:CAPACITY\n"); + return rsoc; + } + + return rsoc; +} + +/* + * Return the battery Available energy in µWh + * Or < 0 if something fails. + */ +static int bq27541_battery_read_energy(struct bq27541_device_info *di) +{ + int ae; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line =%d \n",__FUNCTION__,__LINE__); + #endif + ae = bq27541_read16(di, bq27541CMD_AE_LSB); + if (ae < 0) { + dev_err(di->dev, "error reading available energy\n"); + return ae; + } + + if (di->chip == BQ27541) + ae *= 1000; + + return ae; +} + +/* + * Read flag register. + * Return < 0 if something fails. + */ +// START removed by chase.jang(2018.04.18) +// unsed function +#if 0 +static int bq27541_battery_read_health(struct bq27541_device_info *di) +{ + int tval; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line = %d\n",__FUNCTION__,__LINE__); + #endif + tval = bq27541_read16(di, bq27541CMD_FLAGS_LSB); + if (tval < 0) { + dev_err(di->dev, "error reading health\n"); + return tval; + } + + if (tval & BQ27541_FLAG_SOCF) + tval = POWER_SUPPLY_HEALTH_DEAD; + else if (tval & BQ27541_FLAG_OTC) + tval = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (tval & BQ27541_FLAG_OTD) // for overtemperature when discharging + tval = POWER_SUPPLY_HEALTH_OVERHEAT; + else + tval = POWER_SUPPLY_HEALTH_GOOD; + return tval; +} +#endif +// END + +static int get_health_from_qpnp_smbcharger(struct bq27541_device_info *di) +{ + struct power_supply * bms_supply = NULL; + union power_supply_propval prop = {0,}; + /* + char *str_power_supply[]= + { + "POWER_SUPPLY_HEALTH_UNKNOWN", + "POWER_SUPPLY_HEALTH_GOOD", + "POWER_SUPPLY_HEALTH_OVERHEAT", + "POWER_SUPPLY_HEALTH_DEAD", + "POWER_SUPPLY_HEALTH_OVERVOLTAGE", + "POWER_SUPPLY_HEALTH_UNSPEC_FAILURE", + "POWER_SUPPLY_HEALTH_COLD", + "POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE", + "POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE", + "POWER_SUPPLY_HEALTH_WARM", + "POWER_SUPPLY_HEALTH_COOL", + };*/ +/* + chip->bms_psy = + power_supply_get_by_name((char *)chip->bms_psy_name); + if (chip->bms_psy) { + chip->bms_psy->get_property(chip->bms_psy, + POWER_SUPPLY_PROP_BATTERY_TYPE, &prop); + en = (strcmp(prop.strval, UNKNOWN_BATT_TYPE) != 0 + || chip->charge_unknown_battery) + && (strcmp(prop.strval, LOADING_BATT_TYPE) != 0); + vote(chip->battchg_suspend_votable, + BATTCHG_UNKNOWN_BATTERY_EN_VOTER, !en, 0); + */ + + bms_supply = power_supply_get_by_name("battery"); + if(bms_supply == NULL) + { + dev_err(di->dev, "robin.cho]can't get battery-SO return goood status----------\n"); + return POWER_SUPPLY_HEALTH_GOOD; + } + else + { + power_supply_get_property(bms_supply,POWER_SUPPLY_PROP_HEALTH, &prop); + //dev_err(di->dev, "robin.cho] health status %s\n",str_power_supply[prop.intval]); + } + return prop.intval; +} + +/* + * Return the battery temperature in tenths of degree Kelvin + * Or < 0 if something fails. + */ + +static int bq27541_battery_read_temperature(struct bq27541_device_info *di) +{ + +#ifdef NOT_USE_HDQ_TEMPERATURE + struct power_supply * bms_supply = NULL; + union power_supply_propval prop = {0,}; + bms_supply = power_supply_get_by_name("bms"); + if(bms_supply == NULL) + { + dev_err(di->dev, "robin.cho]can't get bms-SO Defaut temp 27.3C----------\n"); + return TEMP_DEFAULT; + } + else + { + power_supply_get_property(bms_supply,POWER_SUPPLY_PROP_TEMP, &prop); + // dev_err(di->dev, "robin.cho]can get bms temp %d----------\n",prop.intval); + } + return prop.intval+_KELVIN; + +#else + return bq27541_read16(di,bq27541CMD_TEMP_LSB); +#endif +} + +/* + * Return the battery design capacity in mAh + * Or < 0 if something fails. + */ +static int bq27541_battery_read_dcap(struct bq27541_device_info *di) +{ + int ilmd; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line =%d \n",__FUNCTION__,__LINE__); + #endif + if (bq27xxx_is_chip_version_higher(di)) + ilmd = bq27541_read16(di, bq27541CMD_DCAP_LSB); + + if (ilmd < 0) { + dev_err(di->dev, "error reading DESIGN CAPACITY\n"); + return ilmd; + } + + if (bq27xxx_is_chip_version_higher(di)) + ilmd *= 1000; + return ilmd; +} + +/* + * Return remaining life (unit : %) + */ +static int bq27541_battery_read_remaining_life(struct bq27541_device_info *di) +{ + int remaining_life = 0; + + remaining_life = bq27541_read16(di, bq27541CMD_SOH_LSB); + if ((remaining_life < 0) || (remaining_life > 100)) + dev_err(di->dev, "error reading remaining_life\n"); + + return remaining_life; +} +// jason.kim 2015.11.23 use remap table +#ifdef USE_REMAP_TABLE +static int bq27541_battery_capacity(struct bq27541_device_info *di, + union power_supply_propval *val) +{ + const char remap_capacity[101] = { + 0, 0, 0, 0, 1, 3, 4, 5, 7, 8, + 9, 10, 12, 14, 15, 16, 18, 19, 20, 22, + 23, 24, 26, 27, 28, 30, 31, 32, 34, 35, + 36, 38, 39, 41, 42, 43, 45, 46, 47, 49, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 90, 90, + 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, + 96, 96, 97, 97, 98, 99, 99, 100, 100, 100, + 100 + }; + int rsoc = di->cache.capacity; + + if (rsoc < 0 || rsoc > 100) + return -1; + + rsoc = remap_capacity[rsoc]; + val->intval = rsoc; + // printk("%s: rsoc %d => %d\n", __func__, di->cache.capacity, rsoc); // MODIFIED by liquan.zhou, 2018-09-08,BUG-6904042 + return 0; +} +#elif defined(USE_SW_TUNE) +// jason.kim 2015.11.21 fake capacity +#define CAPACITY_0 4 +#define CAPACITY_100 97 +#define CAPACITY_CUT (CAPACITY_0 + (100 - CAPACITY_100 + 1)) +static int bq27541_battery_capacity(struct bq27541_device_info *di, + union power_supply_propval *val) +{ + int rsoc = di->cache.capacity; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line = %d\n",__FUNCTION__,__LINE__); + #endif + if (rsoc < 0) + return rsoc; + + if(rsoc >= CAPACITY_100) { + rsoc = 100; + } else { + rsoc = rsoc * (100+CAPACITY_CUT) / 100 - CAPACITY_0; + if(rsoc < 0) + rsoc = 0; + if(rsoc > 100) + rsoc = 100; + } + + val->intval = rsoc; + printk("%s: rsoc %d => %d\n", __func__, di->cache.capacity, rsoc); + return 0; +} +#else +// jason.kim 2015.11.27 Reports original capacity +static int bq27541_battery_capacity(struct bq27541_device_info *di, + union power_supply_propval *val) +{ + int rsoc = di->cache.capacity; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line = %d\n",__FUNCTION__,__LINE__); + #endif + val->intval = rsoc; + return rsoc; +} +#endif + +static int bq27541_battery_capacity_level(struct bq27541_device_info *di, + union power_supply_propval *val) +{ + int level; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz %s , Line = %d\n",__FUNCTION__,__LINE__); + #endif + if (bq27xxx_is_chip_version_higher(di)){ + if (di->cache.flags & BQ27541_FLAG_FC) + level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; + else if (di->cache.flags & BQ27541_FLAG_SOC1) + level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; + else if (di->cache.flags & BQ27541_FLAG_SOCF) + level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + else + level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; + } + + val->intval = level; + + return 0; +} + +/* + * Read a time register. + * Return < 0 if something fails. + */ +static int bq27541_battery_read_time(struct bq27541_device_info *di, u8 reg) +{ + int tval; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + tval = bq27541_read16(di, reg); + if (tval < 0) { + dev_err(di->dev, "error reading time register\n"); + return tval; + } + return tval; +} + + +// jason.kim 2015.11.12 +#define CAPACITY_0_CHECK_COUNT 4 // [2018/05/28 robin.cho]Add for issue #12070 +static void bq27541_update(struct bq27541_device_info *di) +{ + + + struct bq27541_reg_cache cache = {0, }; + int battery_exist; + int value; + int value2; + int bat_id; + static int CAPACITY_0_check=0;//[2018/05/28 robin.cho]Add for issue #12070 + if(di->cache.flags == 0) + di->cache.flags = 0x100; + + cache = di->cache; + +#ifdef DEBUG_BQ + printk("zxz ------- %s ,line=%d \n", __FUNCTION__,__LINE__); +#endif + +#ifdef DEBUG_BQ + dev_err(di->dev, "zxz 111 bq27541_update\n"); +#endif + bat_id=0; + bat_id = bq27541_battery_read_id(di); + battery_exist = (bat_id == BQ27542_DEVICE_ID); + #ifdef DEBUG_BQ + dev_err(di->dev, "zxz 222 bq27541_update\n"); +#endif + + +#if 1 + /*get HDQ flags*/ + value = bq27541_get_battery_flags(di); + if(value >= 0) { + cache.flags = value; + } + #ifdef DEBUG_BQ + dev_err(di->dev, "zxz 333 bq27541_update\n"); +#endif +#endif + +#ifdef DEBUG_BQ + dev_err(di->dev, "zxz 444 bq27541_update\n"); + #endif + if(battery_exist != di->battery_exist) { + di->battery_exist = battery_exist; + if(di->battery_exist) { + printk("%s: Battery is detected\n", __func__); + } else { + printk("%s: Battery is not detected\n", __func__); +#ifdef _FAIL_CNT + if(di->id_fail_count!=0xFFFFFFFF) + di->id_fail_count++; + di->Last_fail_bat_id=bat_id; +#endif + di->serial_len = NEED_SN_READ; // jason.kim 2015.12.07 srial number + di->battery_init = 0; + di->poll_interval = BATTERY_FUEL_GAUGER_SEC_LOW; + goto battery_not_exist; + } + } +#ifdef DEBUG_BQ + printk("zxz ------- %s ,line=%d , battery_exist=%d \n", __FUNCTION__,__LINE__,battery_exist); +#endif + // jason.kim 2015.12.07 srial number + if(battery_exist) { + /*Defect-6099592 no need read battery serial number*/ +#if 1 + if(di->serial_len==NEED_SN_READ) { + bq27541_battery_read_serial(di); + //dev_info(di->dev, "Serial=%s\n", di->serial_len ? di->serial_no : "unknown"); + } +#endif + // jason.kim 2016.01.20 Check and update battery parameters + if(!di->battery_init) { + bq27541_battery_init_param(di); + } + } + /*get HDQ flags*/ + value = bq27541_get_battery_flags(di); + if(value >= 0) { + cache.flags = value; + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.flags = 0x%x\n",__FUNCTION__,__LINE__,cache.flags); + dev_err(di->dev, "zxz 5555 bq27541_update, cache.flags=%d\n",cache.flags); +#endif + + /*get voltage*/ + value = bq27541_battery_read_volt(di); + if( (value >= 0) && (value < 4400000) ) { + cache.voltage_now = value; + } + +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.voltage_now = %d\n",__FUNCTION__,__LINE__,cache.voltage_now); + dev_err(di->dev, "zxz 6666 bq27541_update, cache.voltage_now=%d\n",cache.voltage_now); + +#endif + + /*get current*/ + value = bq27541_battery_read_current(di); + if(value >= 0) { + cache.current_now = value; + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.voltage_now = %d\n",__FUNCTION__,__LINE__,cache.current_now); + dev_err(di->dev, "zxz 77777 bq27541_update, cache.current_now=%d\n",cache.current_now); +#endif + + // jason.kim 2015.11.27 check capacity error + /*capacity*/ + value = bq27541_battery_read_rsoc(di); + if(value >= 0) { + msleep(10); + value2 = bq27541_battery_read_rsoc(di); + if( value2 >=0 && abs(value2 - value) <= 1 && value >= 0 && value<=100 ) { + // +(2018.05.28 robin.cho) + // [issue #12070] if battery gauge chip reporting as 0 percent,we check it 4 times because gauge chip sometime wrong value reporting + if( value == 0 ) { + ++CAPACITY_0_check; +#ifdef DEBUG_UPDATE_VALUE + dev_info(di->dev, "robin.cho]%s,%d,CAPACITY_0_check = %d value = %d value2 = %d\n",__FUNCTION__,__LINE__,CAPACITY_0_check,value,value2); +#endif + if(CAPACITY_0_check >= CAPACITY_0_CHECK_COUNT ) { + CAPACITY_0_check = 0; + cache.capacity = value; + } + }else { + CAPACITY_0_check = 0; + cache.capacity = value; + } + //-(2018.05.28 robin.cho) + } + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.capacity = %d\n",__FUNCTION__,__LINE__,cache.capacity); + dev_err(di->dev, "zxz 8888 bq27541_update, cache.capacity=%d\n",cache.capacity); +#endif + + /*get available energy*/ + value = bq27541_battery_read_energy(di); + if(value >= 0){ + cache.energy = value; + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.energy = %d\n",__FUNCTION__,__LINE__,cache.energy); + dev_err(di->dev, "zxz 9999 bq27541_update, cache.energy=%d\n",cache.energy); +#endif + + /*get nominal available capacity*/ + value = bq27541_battery_read_nac(di); + if(value >= 0){ + cache.charge_now = value; + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.charge_now = %d\n",__FUNCTION__,__LINE__,cache.charge_now); + dev_err(di->dev, "zxz AAAAA bq27541_update, cache.charge_now=%d\n",cache.charge_now); +#endif +#if 0 + /*get health*/ + value = bq27541_battery_read_health(di); + if(value >= 0){ + cache.health = value; + } +#endif + cache.health = get_health_from_qpnp_smbcharger(di); // get battery health status smbcharger + + +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.health = %d\n",__FUNCTION__,__LINE__,cache.health); + dev_err(di->dev, "zxz BBBB bq27541_update, cache.health=%d\n",cache.health); +#endif + + // jason.kim 2015.11.27 check temperature error + /*get temperature*/ + value = bq27541_battery_read_temperature(di); + if(value >= 0) { + msleep(10); + value2 = bq27541_battery_read_temperature(di); + if( abs(value2-value) <= 10 && value >= TEMP_LIMIT_LOW && value <= TEMP_LIMIT_HIGH ) { + cache.temperature = value; + } else { + if(di->cache.temperature == 0) + cache.temperature = TEMP_DEFAULT; + } + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.temperature = %d\n",__FUNCTION__,__LINE__,cache.temperature); + dev_err(di->dev, "zxz CCCC bq27541_update, cache.temperature=%d\n",cache.temperature); +#endif + + /*get fcc*/ + value = bq27541_battery_read_fcc(di); + if(value >= 0 ){ + cache.charge_full = value; + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.charge_full = %d\n",__FUNCTION__,__LINE__,cache.charge_full); + dev_err(di->dev, "zxz DDDD bq27541_update, cache.charge_full=%d\n",cache.charge_full); +#endif + + /* time to empty */ + value = bq27541_battery_read_time(di,bq27541CMD_TTE_LSB); + if(value >= 0) { + cache.time_to_empty = value; + } +#ifdef DEBUG_UPDATE_VALUE + printk("%s,%d,cache.time_to_empty = %d\n",__FUNCTION__,__LINE__,cache.time_to_empty); + dev_err(di->dev, "zxz EEEE bq27541_update, cache.time_to_empty=%d\n",cache.time_to_empty); +#endif + + /*Modified by T2M Q.Z + * For 3000mah/4000mah change. + */ + +battery_not_exist: + if(!battery_exist){ + cache.capacity = DEFAULT_CAPACITY; +/*Modify-Begin ,task-5373326 ,T2M zxz,2017/10/20, power off when use fake battery*/ + cache.voltage_now = 3800000; +/*Modify-End ,task-5373326 ,T2M zxz,2017/10/20, power off when use fake battery*/ + cache.energy = 0; + cache.charge_now = 0; + cache.health = POWER_SUPPLY_HEALTH_UNKNOWN; +/*Add-BEGIN by T2M.xcm. 2015.5.15 1003151 power off auto.*/ + cache.temperature = TEMP_DEFAULT; +//Add-END by T2M.xcm + cache.charge_full = 0; + cache.time_to_empty = 0; + } + value = bq27541_battery_read_cc(di); + if(value >= 0) { + cache.cycle_count = value; + } +#ifdef DEBUG_UPDATE_VALUE + dev_info(di->dev, "%s,%d,cycle_count = %d\n",__FUNCTION__,__LINE__, cache.cycle_count); +#endif + value = bq27541_battery_read_remaining_life(di); + if(value >= 0) { + cache.remaining_life = value; + } +#ifdef DEBUG_UPDATE_VALUE + dev_info(di->dev, "%s,%d,remaining_life = %d\n",__FUNCTION__,__LINE__, cache.remaining_life); +#endif + +#ifdef DUMMY_GAUGE + cache.capacity = DEFAULT_CAPACITY; +/*Modify-Begin ,task-5373326 ,T2M zxz,2017/10/20, power off when use fake battery*/ + cache.voltage_now = 3800000; +/*Modify-End ,task-5373326 ,T2M zxz,2017/10/20, power off when use fake battery*/ + cache.energy = 0; + cache.charge_now = 0; + cache.health = POWER_SUPPLY_HEALTH_UNKNOWN; +/*Add-BEGIN by T2M.xcm. 2015.5.15 1003151 power off auto.*/ + cache.temperature = TEMP_DEFAULT; +//Add-END by T2M.xcm + cache.charge_full = 0; + cache.time_to_empty = 0; + +#endif +#ifdef _FAIL_CNT + dev_err(di->dev, "zxz battery_exist %d cache.capacity %d cache.voltage_now %d cache.charge_now %d cache.temperature %d fail_count %d read_count %d ,id_fail_count %d Last_fail_bat_id 0x%x\n",battery_exist,cache.capacity,cache.voltage_now,cache.charge_now,cache.temperature,di->fail_count,di->read_count,di->id_fail_count,di->Last_fail_bat_id); +#endif + if(memcmp(&di->cache, &cache, sizeof(cache)) != 0){ + di->cache = cache; + power_supply_changed(di->bat); + } +} + +static void bq27541_battery_poll(struct work_struct *work) +{ + struct bq27541_device_info *di = + container_of(work, struct bq27541_device_info, battery_work.work); + +#ifdef DEBUG_BQ + printk("++%s, %d\n",__FUNCTION__ , __LINE__); + dev_err(di->dev, "zxz bq27541_battery_poll Begin \n"); + +#endif +#ifdef ZXZ_BQ27541 + dev_err(di->dev, "zxz bq27541_battery_poll Begin \n"); +#endif + // jason.kim 2015.10.15 for canceling the polling + mutex_lock(&di->poll_lock); + + if (di->poll_enable) { + if (!di->hot_swap) + bq27541_update(di); + schedule_delayed_work(&di->battery_work, di->poll_interval * HZ); + } + mutex_unlock(&di->poll_lock); + +#ifdef DEBUG_BQ + dev_info(di->dev, "--%s, %d\n",__FUNCTION__ , __LINE__); +#endif +#ifdef ZXZ_BQ27541 + dev_err(di->dev, "zxz bq27541_battery_poll End \n"); +#endif +} + +/* PLATFORM]-add by T2MNB.ZXZ,add hotswap feature,2018/06/27,defect-6502875,Begin */ +static void bq27541_battery_poll_start(struct bq27541_device_info *di, int ptime) +{ + mutex_lock(&di->poll_lock); + di->poll_enable = 1; + mutex_unlock(&di->poll_lock); + dev_info(di->dev, "%s: schedule_delayed_work\n", __func__); + schedule_delayed_work(&di->battery_work, ptime * HZ); +} + +static void bq27541_battery_poll_stop(struct bq27541_device_info *di) +{ + mutex_lock(&di->poll_lock); + di->poll_enable = 0; + mutex_unlock(&di->poll_lock); + if (delayed_work_pending(&di->battery_work)) { + dev_info(di->dev, "%s: cancel_delayed_work\n", __func__); + cancel_delayed_work_sync(&di->battery_work); + } +} + +/* PLATFORM]-add by T2MNB.ZXZ,add hotswap feature,2018/06/27,defect-6502875,End */ + + +static int bq27541_battery_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + int rc; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + switch (prop) { + case POWER_SUPPLY_PROP_CAPACITY: + rc = 1; + break; + default: + rc = 0; + break; + } + return rc; +} + +static int bq27541_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int ret = 0; + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + + if (di->cache.flags < 0) + { + #ifdef DEBUG_BQ + printk("%s, %d ,return error !\n", __FUNCTION__,__LINE__); + #endif + return -ENODEV; + } + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: // jason.kim 2015.10.15 report the battery present (POWER_SUPPLY_PROP_PRESENT) + if (di->test_cap_enable) + val->intval = 1; + else + val->intval = di->battery_exist; + break; + + + /*Remove by T2M Q.Z for PR1003449 + * Do not use status detection from bq27541. + * Use smb1357 status detection. + */ + //case POWER_SUPPLY_PROP_STATUS: + // ret = bq27541_battery_status(di, val); + // break; + + case POWER_SUPPLY_PROP_TECHNOLOGY: + if(di->battery_exist) + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + else + val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; + break; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (di->test_voltage_enable) + ret = bq27541_simple_value(di->test_voltage, val); + else + ret = bq27541_simple_value(di->cache.voltage_now, val); + + break; + + case POWER_SUPPLY_PROP_CURRENT_NOW: + //ret = bq27541_s16_value(di->cache.current_now, val); + val->intval = (int)(s16)bq27541_battery_read_current(di); + val->intval *= 1000; // uA + break; + + case POWER_SUPPLY_PROP_CAPACITY: + if (di->test_cap_enable) { + val->intval = di->test_cap; + } else { + ret = bq27541_battery_capacity(di, val); + } + if (val->intval < 20 || di->cache.current_now <= 0) // low battery or charging + di->poll_interval = BATTERY_FUEL_GAUGER_SEC_LOW; + else + di->poll_interval = BATTERY_FUEL_GAUGER_SEC; + break; + + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + ret = bq27541_battery_capacity_level(di, val); + break; + + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: + if (di->cache.time_to_empty == 65535) + val->intval = -1; // jason.kim 2015.11.16 for suppressing debug message + else + ret = bq27541_simple_value(di->cache.time_to_empty * 60, val); + break; + + //case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: + // ret = bq27541_simple_value(di->cache.time_to_empty_avg, val); + // break; + + //case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + // ret = bq27541_simple_value(di->cache.time_to_full, val); + // break; + + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret = bq27541_simple_value(di->charge_design_full, val); + break; + + //case POWER_SUPPLY_PROP_CYCLE_COUNT: + // ret = bq27541_simple_value(di->cache.cycle_count, val); + // break; + + //case POWER_SUPPLY_PROP_POWER_AVG: + // ret = bq27541_simple_value(di->cache.power_avg, val); + // break; + + case POWER_SUPPLY_PROP_TEMP: + if (di->test_temp_enable) { + ret = bq27541_simple_value(di->test_temp, val); + } + else + { + ret = bq27541_simple_value(di->cache.temperature, val); + } + val->intval -= _KELVIN; // swich kelvin to Celsius + break; + + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret = bq27541_simple_value(di->cache.charge_now, val); + break; + + case POWER_SUPPLY_PROP_ENERGY_NOW: + ret = bq27541_simple_value(di->cache.energy, val); + break; + + case POWER_SUPPLY_PROP_HEALTH: + if (di->test_health_enable) + val->intval = di->test_health; + else + ret = bq27541_simple_value(di->cache.health, val); + break; + + case POWER_SUPPLY_PROP_CHARGE_FULL: + ret = bq27541_simple_value(di->cache.charge_full, val); + break; + default: + return -EINVAL; + } + + +#ifdef DEBUG_BQ + printk("%s ,line=%d ,prop=%d ; val->intval=%d\n", __FUNCTION__,__LINE__,psp,val->intval); +#endif + + + return ret; + +} + +static int bq27541_battery_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + int rc = 0, update_psy = 0; + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + switch (prop) { + case POWER_SUPPLY_PROP_CAPACITY: + di->cache.capacity = val->intval; + update_psy = 1; + break; + default: + rc = -EINVAL; + } + + if (!rc && update_psy) + power_supply_changed(di->bat); + return rc; +} + +//+ jason.kim 2015.11.24 dump registers +static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + + int value; + char *_buf = buf; + + bq27541_battery_poll_stop(di); + + value = bq27541_read16(di, BQ27541_REG_CNTL); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_CNTL, value); + value = bq27541_read16(di, BQ27541_REG_AR); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_AR, value); + value = bq27541_read16(di, BQ27541_REG_UFSOC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_UFSOC, value); + value = bq27541_read16(di, BQ27541_REG_TEMP); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_TEMP, value); + value = bq27541_read16(di, BQ27541_REG_VOLT); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_VOLT, value); + value = bq27541_read16(di, BQ27541_REG_FLAGS); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_FLAGS, value); + value = bq27541_read16(di, BQ27541_REG_NAC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_NAC, value); + value = bq27541_read16(di, BQ27541_REG_FAC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_FAC, value); + value = bq27541_read16(di, BQ27541_REG_RM); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_RM, value); + value = bq27541_read16(di, BQ27541_REG_FCC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_FCC, value); + value = bq27541_read16(di, BQ27541_REG_AI); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_AI, value); + value = bq27541_read16(di, BQ27541_REG_TTE); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_TTE, value); + value = bq27541_read16(di, BQ27541_REG_FFCC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_FFCC, value); + value = bq27541_read16(di, BQ27541_REG_SI); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_SI, value); + value = bq27541_read16(di, BQ27541_REG_UFFCC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_UFFCC, value); + value = bq27541_read16(di, BQ27541_REG_MLI); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_MLI, value); + value = bq27541_read16(di, BQ27541_REG_UFRM); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_UFRM, value); + value = bq27541_read16(di, BQ27541_REG_FRM); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_FRM, value); + value = bq27541_read16(di, BQ27541_REG_AP); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_AP, value); + + value = bq27541_read16(di, BQ27541_REG_INTTEMP); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_INTTEMP, value); + value = bq27541_read16(di, BQ27541_REG_CC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_CC, value); + value = bq27541_read16(di, BQ27541_REG_SOC); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_SOC, value); + value = bq27541_read16(di, BQ27541_REG_SOH); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_SOH, value); + + value = bq27541_read16(di, BQ27541_REG_PCHG); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_PCHG, value); + value = bq27541_read16(di, BQ27541_REG_DOD0); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_DOD0, value); +/*Add begin Defect-6099797, for HDQ charge safe time */ + value = bq27541_read16(di, 0x3c); + buf += sprintf(buf, "%02X %04X\n", 0x3c, value); +/*Add end Defect-6099797, for HDQ charge safe time */ + value = bq27541_read16(di, BQ27541_REG_SDSG); + buf += sprintf(buf, "%02X %04X\n", BQ27541_REG_SDSG, value); + + bq27541_battery_poll_start(di, 0); + return (buf-_buf); +} + +//+ jason.kim 2015.12.07 serial number +static ssize_t store_serial_no(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + if (!di->battery_exist) + return 0; + + bq27541_battery_poll_stop(di); + + bq27541_battery_write_serial(di, buf); + bq27541_battery_read_serial(di); + dev_info(di->dev, "Serial=%s\n", di->serial_len ? di->serial_no : "unknown"); + + bq27541_battery_poll_start(di, 0); + return count; +} + +static ssize_t show_serial_no(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + +#ifdef USE_SERIAL_32_BYTES + printk("%s######\n", __func__); + + if(di->serial_len == NEED_SN_READ) + { + return sprintf(buf, "%s\n","unknown"); + } + else + { + + PM85_SERIAL *serial_number; + serial_number = (PM85_SERIAL *)di->serial_no; + + printk( "%s::%d######di->serial_len 0x%x\n", __func__,__LINE__,di->serial_len); + if(di->serial_len != NEED_SN_READ) + { +// char str_serial[20]={0,}; +// char str_manufacture_date[20]={0,}; + printk("%s::%d :di->serial_len 0x%x ###### SN : %s MF %s\n", __func__,__LINE__,di->serial_len ,serial_number->SN,serial_number->MF_date); + +// memcpy((void *)str_serial , (void *)serial_number->SN,serial_number->length_SN); +// memcpy((void *)str_manufacture_date , (void *)serial_number->MF_date,serial_number->length_MF_date); +// printk( "%s::%d###### SN : %s MF %s\n", __func__,__LINE__,str_serial,str_manufacture_date); + return sprintf(buf,"%s-%s\n",serial_number->SN,serial_number->MF_date); + + + }else + { + return sprintf(buf,"%s\n","unknown"); + + } + // return sprintf(buf, "%s\n", (di->serial_len && is_good_serial(di->serial_no)) ? di->serial_no : "unknown"); + } +#else + if(di->serial_len == NEED_SN_READ) + { + return sprintf(buf, "%s\n","unknown"); + } + else + { + return sprintf(buf, "%s\n", di->serial_len ? di->serial_no : "unknown"); + } +#endif +} +//+ jason.kim 2015.12.07 serial number + +//+ jason.kim 2015.12.08 dump MFG-B +static ssize_t show_mfg_b(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + bq27541_battery_dump_mfg_B(di); + return 0; +} +//- jason.kim 2015.12.08 dump MFG-B + +// jason.kim 2016.01.20 Check and update battery parameters +static ssize_t show_reset_battery(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + + bq27541_battery_poll_stop(di); + bq27541_battery_reset_param(di); + bq27541_battery_poll_start(di, 0); + return 0; +} + +static ssize_t show_battery_remaining_life(struct device *dev,struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + + return sprintf(buf, "%d\n", di->cache.remaining_life); +} +static ssize_t show_battery_cycle_count(struct device *dev,struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + + return sprintf(buf, "%d\n", di->cache.cycle_count); +} +static ssize_t show_real_soc(struct device *dev, struct device_attribute *attr, char *buf) // it add for stress test tool +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + + return sprintf(buf, "%d", di->cache.capacity); +} + +//+ jason.kim 2016.3.24 test temperature control +static ssize_t store_test_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + int param, ret; + ret = kstrtoint(buf, 10, ¶m); + if (ret < 0) + return count; + + // jason.kim 2016.6.2 + if (param == 1000) { + di->test_temp_enable = 0; + di->test_temp = 300+ _KELVIN; + } else if (param == 1001) { + di->test_temp_enable = 1; + di->test_temp = 300+_KELVIN; + } else + di->test_temp = param + _KELVIN; + dev_info(di->dev, "temp=%d\n", di->test_temp - _KELVIN); + return count; +} + +static ssize_t show_test_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + return sprintf(buf, "test_temp %d\n", di->test_temp - _KELVIN); +} +//- jason.kim 2016.3.24 test temperature control + +//+ jason.kim 2016.7.12 Test battery capacity +static ssize_t store_test_cap(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + int param, ret; + ret = kstrtoint(buf, 10, ¶m); + if (ret < 0) + return count; + + // jason.kim 2016.6.2 + if (param == 1000) { + di->test_cap_enable = 0; + di->test_cap = 50; + } else if (param == 1001) { + di->test_cap_enable = 1; + di->test_cap = 50; + } else + di->test_cap = param; + + dev_info(di->dev, "test_cap =%d\n", di->test_cap); + return count; +} + +static ssize_t show_test_cap(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + return sprintf(buf, "test_cap %d\n", di->test_cap); +} +//- jason.kim 2016.7.12 Test battery capacity + +//+ jason.kim 2016.7.18 Test battery voltage +static ssize_t store_test_voltage(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + int param, ret; + ret = kstrtoint(buf, 10, ¶m); + if (ret < 0) + return count; + + // jason.kim 2016.6.2 + if (param == 1000) { + di->test_voltage_enable = 0; + di->test_voltage = 3700 * 1000; + } else if (param == 1001) { + di->test_voltage_enable = 1; + di->test_voltage = 3700 * 1000; + } else + di->test_voltage = param * 1000; + dev_info(di->dev, "test_voltage =%d\n", di->test_voltage / 1000); + return count; +} + +static ssize_t show_test_voltage(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + return sprintf(buf, "test_voltage %d\n", di->test_voltage / 1000); +} +//- jason.kim 2016.7.18 Test battery voltage + +static ssize_t store_test_health(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + char *str_power_supply[]= + { + "POWER_SUPPLY_HEALTH_UNKNOWN", + "POWER_SUPPLY_HEALTH_GOOD", + "POWER_SUPPLY_HEALTH_OVERHEAT", + "POWER_SUPPLY_HEALTH_DEAD", + "POWER_SUPPLY_HEALTH_OVERVOLTAGE", + "POWER_SUPPLY_HEALTH_UNSPEC_FAILURE", + "POWER_SUPPLY_HEALTH_COLD", + "POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE", + "POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE", + "POWER_SUPPLY_HEALTH_WARM", + "POWER_SUPPLY_HEALTH_COOL", + }; + + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + int param, ret; + ret = kstrtoint(buf, 10, ¶m); + if (ret < 0) + return count; + + // jason.kim 2016.6.2 + if (param == 1000) { + di->test_health_enable = 0; + di->test_health = POWER_SUPPLY_HEALTH_GOOD; + } else if (param == 1001) { + di->test_health_enable = 1; + di->test_health = POWER_SUPPLY_HEALTH_GOOD; + } else + { + if(param >10) + { + dev_info(di->dev, "Error input param %d \n", param); + return count; + } + else + di->test_health = param; + } + + dev_info(di->dev, "Enable:: %d test_health =%d [%s]\n", di->test_health_enable ,di->test_health ,str_power_supply[di->test_health]); + return count; +} + +static ssize_t show_test_health(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *str_power_supply[]= + { + "POWER_SUPPLY_HEALTH_UNKNOWN", + "POWER_SUPPLY_HEALTH_GOOD", + "POWER_SUPPLY_HEALTH_OVERHEAT", + "POWER_SUPPLY_HEALTH_DEAD", + "POWER_SUPPLY_HEALTH_OVERVOLTAGE", + "POWER_SUPPLY_HEALTH_UNSPEC_FAILURE", + "POWER_SUPPLY_HEALTH_COLD", + "POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE", + "POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE", + "POWER_SUPPLY_HEALTH_WARM", + "POWER_SUPPLY_HEALTH_COOL", + }; + struct power_supply *psy = dev_get_drvdata(dev); + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + return sprintf(buf, "Enable:: %d test_health =%d [%s]\n", di->test_health_enable , di->test_health ,str_power_supply[di->test_health]); +} + + + +static struct device_attribute bq27541_battery_attrs[] = { + __ATTR(dump_regs, 0444, show_dump_regs, NULL), // jason.kim 2015.03.02 dump all registers + __ATTR(serial_no, 0664, show_serial_no, store_serial_no), // jason.kim 2015.12.07 serial number + __ATTR(mfg_b, 0444, show_mfg_b, NULL), // jason.kim 2015.12.08 dump MFG-B + __ATTR(reset, 0444, show_reset_battery, NULL), // jason.kim 2016.01.20 Check and update battery parameters + __ATTR(remaining_life, S_IRUGO, show_battery_remaining_life, NULL), + __ATTR(cycle_count, S_IRUGO, show_battery_cycle_count, NULL), + __ATTR(real_soc, 0444, show_real_soc, NULL), // [robin.cho] it add for strees test tool:show real SOC + __ATTR(test_temp, 0664, show_test_temp, store_test_temp), // jason.kim 2016.3.25 SW temperature control + __ATTR(test_cap, 0664, show_test_cap, store_test_cap), // jason.kim 2016.7.12 Test battery capacity + __ATTR(test_voltage, 0664, show_test_voltage, store_test_voltage), // jason.kim 2016.7.18 Test battery voltage + __ATTR(test_health, 0664, show_test_health, store_test_health), // robin.cho +}; + +static int bq27541_create_attrs(struct device *dev) +{ + unsigned int i; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + for (i = 0; i < ARRAY_SIZE(bq27541_battery_attrs); i++) + if (device_create_file(dev, &bq27541_battery_attrs[i])) + goto bq27541_create_attrs_failed; + + return 0; + +bq27541_create_attrs_failed: + dev_err(dev, "failed creating bq27541 battery attrs.\n"); + while (i--) + device_remove_file(dev, &bq27541_battery_attrs[i]); + + return -EIO; +} + +static void bq27541_remove_attrs(struct device *dev) +{ + unsigned int i; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + for (i = 0; i < ARRAY_SIZE(bq27541_battery_attrs); i++) + device_remove_file(dev, &bq27541_battery_attrs[i]); +} +//- jason.kim 2015.11.24 dump registers + + + +/* PLATFORM]-add by T2MNB.ZXZ,add hotswap feature,2018/06/27,defect-6502875,Begin */ +void bq27541_poll_stop(struct power_supply *psy) +{ + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + bq27541_battery_poll_stop(di); +} + +int bq27541_read_rsoc(struct power_supply *psy) +{ + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + return bq27541_battery_read_rsoc(di); +} + +int bq27541_read_temp(struct power_supply *psy) +{ + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + return bq27541_battery_read_temperature(di); +} + + + +//void bq24086_set_lowbattery(bool low_battery); +void bq27541_set_hot_swap(struct power_supply *psy, int low_battery) +{ + struct bq27541_device_info *di = power_supply_get_drvdata(psy); + + //bq24086_set_lowbattery(low_battery); + if (low_battery) { + di->hot_swap = true; + bq27541_battery_poll_stop(di); + di->battery_exist = 0; + di->serial_len = NEED_SN_READ; + //di->serial_retry = 0; + di->battery_init = 0; + di->poll_interval = BATTERY_FUEL_GAUGER_SEC_LOW; + power_supply_changed(di->bat); + } else { + di->hot_swap = false; + bq27541_battery_poll_start(di, 0); + } + +} +/* PLATFORM]-add by T2MNB.ZXZ,add hotswap feature,2018/06/27,defect-6502875,End */ + +static const struct power_supply_desc batt_psy_desc = { + .name = "bq27541_battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = bq27541_battery_props, + .num_properties = ARRAY_SIZE(bq27541_battery_props), + .get_property = bq27541_battery_get_property, + .set_property = bq27541_battery_set_property, + .property_is_writeable = bq27541_battery_is_writeable, +}; + +static int bq27541_powersupply_init(struct bq27541_device_info *di) +{ + + struct power_supply_config batt_cfg = {}; + int ret = 0; + + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + + batt_cfg.drv_data = di; + batt_cfg.of_node = di->dev->of_node; + di->bat = devm_power_supply_register(di->dev, + &batt_psy_desc, + &batt_cfg); + if (IS_ERR(di->bat)) { + pr_err("Couldn't register battery power supply bq27541 !\n"); + return PTR_ERR(di->bat); + } + + #ifdef DEBUG_BQ + printk("%s,%d\n",__FUNCTION__,__LINE__); + #endif + + #ifdef _FAIL_CNT + di->read_count=0; + di->fail_count=0; + di->id_fail_count=0; + di->Last_fail_bat_id=0; + #endif + + + INIT_DELAYED_WORK(&di->battery_work, bq27541_battery_poll); + // mutex_init(&di->lock); + + // jason.kim 2015.11.24 dump registers + ret = bq27541_create_attrs(di->dev); + if (ret) { + dev_err(di->dev, "fail to create main sysfs: %d\n", ret); + return ret; + } + return 0; +} + +static int hdq_parse_dt(struct platform_device *pdev, + struct bq27541_device_info *pdata) +{ + //int rc; + struct device_node *np = pdev->dev.of_node; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + pdata->pin = of_get_named_gpio(np,"qcom,hdq-gpio", 0); + if(!pdata->pin){ + dev_err(&pdev->dev, "Unable to get hdq_gpio\n"); + return -ENODEV; + } + + pdev->dev.platform_data = pdata; + + return 0; +} + +static int bq27541_probe(struct platform_device *pdev) +{ + int err; + int value; + struct bq27541_device_info *di = pdev->dev.platform_data; + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) { + dev_err(&pdev->dev, "failed to allocate device info data\n"); + return -ENOMEM; + } +#ifdef DEBUG_BQ + printk("%s ,line=%d ,probe 00000000000 \n", __FUNCTION__,__LINE__); +#endif + platform_set_drvdata(pdev, di); // jason.kim 2015.10.15 + + /*hdq parse dt*/ + err = hdq_parse_dt(pdev,di); + if (err < 0) { + dev_err(&pdev->dev, "Failed to parse DT\n"); + return err; + } +#ifdef DEBUG_BQ + printk("%s ,line=%d ,probe 11111111 \n", __FUNCTION__,__LINE__); +#endif + /*request gpio*/ + if(gpio_is_valid(di->pin)){ + err = gpio_request(di->pin, "hdq"); + if (err) { + dev_err(&pdev->dev, "gpio_request (pin) failed\n"); + goto free_gpio; + } + } +#ifdef DEBUG_BQ + printk("%s ,line=%d ,probe 22222222222 ---di->pin =%d \n", __FUNCTION__,__LINE__,di->pin); +#endif + mutex_init(&di->poll_lock); // jason.kim 2015.10.15 + spin_lock_init(&di->hdq_lock); + + /* timer */ + //my_timer->data = 0xff; + //my_timer->function = &timer_function; + //my_timer->expires = jiffies + HZ/10000; + //init_timer(my_timer); + + /*fill the struct*/ + di->battery_exist = 0; + di->dev = &pdev->dev; + di->chip = BQ27541; + di->bus.read = &hdq_gpio_read; + di->bus.write = &hdq_gpio_write; + di->poll_interval = BATTERY_FUEL_GAUGER_SEC; +#ifdef DEBUG_BQ + printk("%s ,line=%d ,probe 3333333 \n", __FUNCTION__,__LINE__); +#endif + + err=bq27541_pinctrl_init(di); + if(err) + dev_err(di->dev, " bq27541_pinctrl_init failed \n"); + + err = bq27541_powersupply_init(di); + if (err) + goto err_free; +#ifdef DEBUG_BQ + printk("%s ,line=%d ,probe 4444444444444 \n", __FUNCTION__,__LINE__); +#endif +#ifdef DEBUG_INIT_VALUE + dev_info(di->dev, "Initial capacity %d, current %d\n", + bq27541_battery_read_rsoc(di), + (int)((s16)bq27541_battery_read_current(di))); +#endif +#ifdef DEBUG_BQ + printk("%s ,line=%d ,probe 555555555 \n", __FUNCTION__,__LINE__); +#endif + +/*Add begin Defect-6099797, for HDQ charge safe time */ + value = bq27541_battery_read_dcap(di); + if(value >= 0) + di->charge_design_full = value; + BatteryDesignCap=di->charge_design_full; + printk(" %s,%d,BatteryDesignCap = %d\n",__FUNCTION__,__LINE__,BatteryDesignCap); +/*Add end Defect-6099797, for HDQ charge safe time */ + + di->serial_len = NEED_SN_READ; + + + bq27541_battery_poll_start(di, 0); + dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); + + +#ifdef DEBUG_BQ + printk("%s ,line=%d ,probe success !!!!!!\n", __FUNCTION__,__LINE__); +#endif + + return 0; + + err_free: + kfree(di); + #ifdef DEBUG_BQ + printk("%s ,line=%d ,probe FAIL !!!!!!\n", __FUNCTION__,__LINE__); + #endif + return err; + + free_gpio: + gpio_free(di->pin); + #ifdef DEBUG_BQ + printk("%s ,line=%d ,probe FAIL !!!!!!\n", __FUNCTION__,__LINE__); + #endif + return err; +} + +// jason.kim 2015.10.15 +static int bq27541_remove(struct platform_device *pdev) +{ + struct bq27541_device_info *di = dev_get_drvdata(&pdev->dev); + +#ifdef DEBUG_BQ + printk("%s,%d\n",__FUNCTION__,__LINE__); +#endif + bq27541_battery_poll_stop(di); + + bq27541_remove_attrs(di->dev); // jason.kim 2015.11.24 dump registers + power_supply_unregister(di->bat); + // mutex_destroy(&di->lock); + mutex_destroy(&di->poll_lock); + gpio_free(di->pin); + + platform_set_drvdata(pdev, NULL); + kfree(di); + + return 0; +} + +static int bq27541_battery_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bq27541_device_info *di = platform_get_drvdata(pdev); + + dev_info(dev, "++%s\n", __func__); + + bq27541_battery_poll_stop(di); + + dev_info(dev, "--%s\n", __func__); + return 0; +} + + +static int bq27541_battery_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct bq27541_device_info *di = platform_get_drvdata(pdev); + + #ifdef DEBUG_BQ + printk("%s, %d, \n",__FUNCTION__ , __LINE__); + #endif + + +/* PLATFORM]-add by T2MNB.ZXZ,add hotswap feature,2018/06/27,defect-6502875 */ + if(!di->hot_swap) { + bq27541_battery_poll_start(di, 0); + } + dev_info(dev, "--%s\n", __func__); + return 0; +} +//-- jason.kim 2015.10.15 + +static const struct dev_pm_ops bq27541_battery_pm_ops = { + .suspend = bq27541_battery_suspend, + .resume = bq27541_battery_resume, +}; + +static struct of_device_id hdq_gpio_dt_ids[] = { + { .compatible = "qcom,bq27541-fuel-hdq" }, + {}, +}; +MODULE_DEVICE_TABLE(of, hdq_gpio_dt_ids); + +static struct platform_driver bq27541_driver = { + .driver = { + .name = "bq27541", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(hdq_gpio_dt_ids), + .pm = &bq27541_battery_pm_ops, + }, + .probe = bq27541_probe, + .remove = bq27541_remove, +}; + +module_platform_driver(bq27541_driver); + +MODULE_DESCRIPTION("GPIO HDQ driver"); +MODULE_AUTHOR("AaronZeng "); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 633e006b398433a593d98c263a076a3978601d27..4edfe51ee57e24a5450832aa88ec9152b91c1405 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -122,7 +122,12 @@ void power_supply_changed(struct power_supply *psy) psy->changed = true; pm_stay_awake(&psy->dev); spin_unlock_irqrestore(&psy->changed_lock, flags); + +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_work(private_chg_wq, &psy->changed_work); +#else schedule_work(&psy->changed_work); +#endif } EXPORT_SYMBOL_GPL(power_supply_changed); diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index a8ad7464e251bb8bcc7a6a5d3c2b847e7f1f6748..aedb4bd72662adae8567c04b52818b7cadd427cd 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -81,14 +81,26 @@ static const char * const power_supply_scope_text[] = { "Unknown", "System", "Device" }; +#if defined(CONFIG_TCT_PM7250_COMMON) static const char * const power_supply_usbc_text[] = { "Nothing attached", "Sink attached", "Powered cable w/ sink", "Debug Accessory", "Audio Adapter", "Powered cable w/o sink", + "Source Debug Accessory (FMB)", "Source attached (default current)", "Source attached (medium current)", "Source attached (high current)", "Non compliant", }; +#else +static const char * const power_supply_usbc_text[] = { + "Nothing attached", "Sink attached", "Powered cable w/ sink", + "Debug Accessory", "Audio Adapter", "Powered cable w/o sink", + "Source attached (default current)", + "Source attached (medium current)", + "Source attached (high current)", + "Non compliant", +}; +#endif static const char * const power_supply_usbc_pr_text[] = { "none", "dual power role", "sink", "source" @@ -383,7 +395,13 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(esr_count), POWER_SUPPLY_ATTR(buck_freq), POWER_SUPPLY_ATTR(boost_current), +#if defined(CONFIG_TCT_PM7250_COMMON) + POWER_SUPPLY_ATTR(safety_timer_enable), +#else POWER_SUPPLY_ATTR(safety_timer_enabled), +#endif + POWER_SUPPLY_ATTR(connector_temp), + POWER_SUPPLY_ATTR(charge_done), POWER_SUPPLY_ATTR(flash_active), POWER_SUPPLY_ATTR(flash_trigger), @@ -479,6 +497,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(cp_toggle_switcher), POWER_SUPPLY_ATTR(cp_irq_status), POWER_SUPPLY_ATTR(cp_ilim), +#if defined(CONFIG_TCT_PM7250_COMMON) + POWER_SUPPLY_ATTR(tcl_fixtemp), +#endif POWER_SUPPLY_ATTR(irq_status), POWER_SUPPLY_ATTR(parallel_output_mode), POWER_SUPPLY_ATTR(cc_toggle_enable), diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 9581455fc4d2be22d4289f0c7aed9232f81ab7c0..4cb88767fe34db1fdba9a8a60932e9ed5ee5068d 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -162,6 +162,15 @@ config HL6111R sizes. The HL6111R has voltage, current and temperature protection mechanisms, an I2C interface, and a PSNS output. +# [start] dis-/enable chg common patches based on pm7250b chipset. +config TCT_PM7250_COMMON + bool "Enable common chg patches for pm7250&pm7250B platform" + default n + select TCT_INIT_SPEED_UP + help + Say Y here to enable common chg patches. + Say N to disable these chg patches. +# [ended] config SMB1398_CHARGER tristate "SMB1398 power supply framework based driver" depends on MFD_I2C_PMIC diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index ec45b7d1c502dab0b83666a08773d805d20ec015..4181f7aca35e0dfab93c569f213b01df41287cb6 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -103,6 +103,9 @@ struct pl_data { enum power_supply_type charger_type; /* debugfs directory */ struct dentry *dfs_root; +#if defined(CONFIG_TCT_PM7250_COMMON) + bool last_input_present; +#endif u32 float_voltage_uv; }; @@ -119,6 +122,15 @@ enum { static int debug_mask; +#if defined(CONFIG_TCT_PM7250_COMMON) +#define pl_dbg(chip, reason, fmt, ...) \ + do { \ + if (debug_mask & (reason)) \ + pr_err_ratelimited(fmt, ##__VA_ARGS__); \ + else \ + pr_debug(fmt, ##__VA_ARGS__); \ + } while (0) +#else #define pl_dbg(chip, reason, fmt, ...) \ do { \ if (debug_mask & (reason)) \ @@ -126,6 +138,7 @@ static int debug_mask; else \ pr_debug(fmt, ##__VA_ARGS__); \ } while (0) +#endif #define IS_USBIN(mode) ((mode == POWER_SUPPLY_PL_USBIN_USBIN) \ || (mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)) @@ -153,6 +166,20 @@ static bool is_usb_available(struct pl_data *chip) return !!chip->usb_psy; } +#if defined(CONFIG_TCT_PM7250_COMMON) +static bool is_dc_available(struct pl_data *chip) +{ + if (chip->dc_psy) + return true; + + chip->dc_psy = power_supply_get_by_name("dc"); + if (!chip->dc_psy) + return false; + + return true; +} +#endif + static bool is_cp_available(struct pl_data *chip) { if (!chip->cp_master_psy) @@ -260,7 +287,12 @@ static int get_adapter_icl_based_ilim(struct pl_data *chip) */ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) { - int rc, fcc, target_icl; + #if defined(CONFIG_TCT_PM7250_COMMON) + int rc, fcc; + #else + int rc, fcc, target_icl; + #endif + union power_supply_propval pval = {0, }; if (!is_usb_available(chip)) @@ -269,12 +301,15 @@ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) if (!is_cp_available(chip)) return; +#if !defined(CONFIG_TCT_PM7250_COMMON) if (cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE) == POWER_SUPPLY_PL_OUTPUT_VPH) return; + target_icl = get_adapter_icl_based_ilim(chip); ilim = (target_icl > 0) ? min(ilim, target_icl) : ilim; +#endif rc = power_supply_get_property(chip->cp_master_psy, POWER_SUPPLY_PROP_MIN_ICL, &pval); @@ -286,6 +321,10 @@ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) if (chip->cp_ilim_votable) { fcc = get_effective_result_locked(chip->fcc_votable); + +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chip->cp_ilim_votable, voter, true, ilim); +#else /* * If FCC >= (2 * MIN_ICL) then it is safe to enable CP * with MIN_ICL. @@ -297,6 +336,7 @@ static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim) vote(chip->cp_ilim_votable, voter, true, pval.intval); else vote(chip->cp_ilim_votable, voter, true, ilim); +#endif /* * Rerun FCC votable to ensure offset for ILIM compensation is @@ -938,6 +978,64 @@ static int pl_fcc_main_vote_callback(struct votable *votable, void *data, &pval); } +#if defined(CONFIG_TCT_PM7250_COMMON) +static int pl_fcc_vote_callback(struct votable *votable, void *data, + int total_fcc_ua, const char *client) +{ + struct pl_data *chip = data; + int master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0; + int cp_output_mode = POWER_SUPPLY_PL_OUTPUT_NONE; + union power_supply_propval pval = {0, }; + int rc = 0; + + if (total_fcc_ua < 0) + return 0; + + if (!chip->main_psy) + return 0; + + if (!chip->cp_disable_votable) + chip->cp_disable_votable = find_votable("CP_DISABLE"); + + if (chip->cp_disable_votable) { + cp_output_mode = cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE); + if (cp_output_mode == POWER_SUPPLY_PL_OUTPUT_VBAT + || cp_output_mode == POWER_SUPPLY_PL_OUTPUT_VPH) { + rc = power_supply_get_property(chip->cp_master_psy, + POWER_SUPPLY_PROP_MIN_ICL, &pval); + if (!rc) { + /* + * With VPH output configuration ILIM is configured + * independent of battery FCC, disable CP here if FCC/2 + * falls below MIN_ICL supported by CP. + */ + if (total_fcc_ua <= (pval.intval << 1)) + vote(chip->cp_disable_votable, FCC_VOTER, + true, 0); + else + vote(chip->cp_disable_votable, FCC_VOTER, + false, 0); + } + } + } + + if (chip->pl_mode != POWER_SUPPLY_PL_NONE) { + get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, + &slave_fcc_ua); + + if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) { + vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, + false, 0); + } else { + vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER, + true, 0); + } + } + + rerun_election(chip->pl_disable_votable); + return 0; +} +#else static int pl_fcc_vote_callback(struct votable *votable, void *data, int total_fcc_ua, const char *client) { @@ -1022,6 +1120,7 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, return 0; } +#endif static void fcc_stepper_work(struct work_struct *work) { @@ -1185,8 +1284,13 @@ static void fcc_stepper_work(struct work_struct *work) cp_configure_ilim(chip, FCC_VOTER, chip->slave_fcc_ua / 2); if (reschedule_ms) { +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chip->fcc_stepper_work, + msecs_to_jiffies(reschedule_ms)); +#else schedule_delayed_work(&chip->fcc_stepper_work, msecs_to_jiffies(reschedule_ms)); +#endif pr_debug("Rescheduling FCC_STEPPER work\n"); return; } @@ -1206,6 +1310,80 @@ static bool is_batt_available(struct pl_data *chip) return true; } +#if defined(CONFIG_TCT_PM7250_COMMON) +static bool is_usb_present(struct pl_data *chip) +{ + union power_supply_propval pval = {0, }; + + if (is_usb_available(chip)) + power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + + return pval.intval ? true : false; +} + +static bool is_dc_present(struct pl_data *chip) +{ + union power_supply_propval pval = {0, }; + + if (is_dc_available(chip)) + power_supply_get_property(chip->dc_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + + return pval.intval ? true : false; +} + +static bool is_input_present(struct pl_data *chip) +{ + return is_usb_present(chip) || is_dc_present(chip); +} + +static void handle_safety_timer(struct pl_data *chip) +{ + int rc = 0; + union power_supply_propval pval = {1, }; + + if (!chip->batt_psy || !chip->last_input_present) { + pl_dbg(chip, PR_PARALLEL, "skip, input:%d\n", + chip->last_input_present); + return; + } + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE, &pval); + if (rc < 0 || pval.intval) { + pl_dbg(chip, PR_PARALLEL, "skip, rc=%d, val=%d\n", + rc, pval.intval); + return; + } + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_HEALTH, &pval); + if (rc < 0 + || pval.intval != POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE) { + pl_dbg(chip, PR_PARALLEL, "skip, rc=%d, health=%d\n", + rc, pval.intval); + return; + } + + pval.intval = 0; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGING_ENABLED, &pval); + if (rc < 0) { + pl_dbg(chip, PR_PARALLEL, "failed to set chg disabled\n"); + return; + } + + pval.intval = 1; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGING_ENABLED, &pval); + if (rc < 0) { + pl_dbg(chip, PR_PARALLEL, "failed to set chg enabled\n"); + return; + } +} +#endif + #define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000 static int pl_fv_vote_callback(struct votable *votable, void *data, int fv_uv, const char *client) @@ -1229,7 +1407,11 @@ static int pl_fv_vote_callback(struct votable *votable, void *data, return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chip->pl_psy && chip->pl_mode != POWER_SUPPLY_PL_NONE) { +#else if (chip->pl_mode != POWER_SUPPLY_PL_NONE) { +#endif pval.intval += PARALLEL_FLOAT_VOLTAGE_DELTA_UV; rc = power_supply_set_property(chip->pl_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); @@ -1283,6 +1465,7 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, if (client == NULL) icl_ua = INT_MAX; +#if !defined(CONFIG_TCT_PM7250_COMMON) /* * Disable parallel for new ICL vote - the call to split_settled will * ensure that all the input current limit gets assigned to the main @@ -1304,6 +1487,7 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, else schedule_delayed_work(&chip->status_change_work, msecs_to_jiffies(PL_DELAY_MS)); +#endif /* rerun AICL */ /* get the settled current */ @@ -1333,7 +1517,9 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); +#if !defined(CONFIG_TCT_PM7250_COMMON) vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); +#endif /* Configure ILIM based on AICL result only if input mode is USBMID */ if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE) @@ -1352,10 +1538,10 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, if (!dc_present) cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua); } - - return 0; + return 0;//zxzcheck } + static void pl_disable_forever_work(struct work_struct *work) { struct pl_data *chip = container_of(work, @@ -1369,6 +1555,14 @@ static void pl_disable_forever_work(struct work_struct *work) vote(chip->hvdcp_hw_inov_dis_votable, PL_VOTER, false, 0); } + +#define QC3_ICL_MAX 2000000 +#define QC3_ICL_FP4_CP_MAX 2000000 +#define QC3_ICL_FP4_CP_MAX_LCD_ON 1600000 +#if defined(CONFIG_TCT_PM7250_COMMON) +extern bool g_lcd_on; +#endif + static int pl_disable_vote_callback(struct votable *votable, void *data, int pl_disable, const char *client) { @@ -1416,8 +1610,19 @@ static int pl_disable_vote_callback(struct votable *votable, } total_fcc_ua = get_effective_result_locked(chip->fcc_votable); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (total_fcc_ua < 0) { + pr_err("skip, Invalid FCC:%d\n", total_fcc_ua); + return -EINVAL; + } +#endif +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chip->pl_psy && chip->pl_mode != POWER_SUPPLY_PL_NONE + && !pl_disable) { +#else if (chip->pl_mode != POWER_SUPPLY_PL_NONE && !pl_disable) { +#endif rc = validate_parallel_icl(chip, &disable); if (rc < 0) return rc; @@ -1452,8 +1657,13 @@ static int pl_disable_vote_callback(struct votable *votable, if (chip->step_fcc) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chip->fcc_stepper_work, + 0); +#else schedule_delayed_work(&chip->fcc_stepper_work, 0); +#endif } } else { /* @@ -1555,8 +1765,24 @@ static int pl_disable_vote_callback(struct votable *votable, /* main psy gets all share */ vote(chip->fcc_main_votable, MAIN_FCC_VOTER, true, total_fcc_ua); +//#if defined(CONFIG_TCT_PM7250_COMMON) && !defined(CONFIG_TCT_OTTAWA_CHG_PATCH) +#if defined(CONFIG_TCT_PM7250_COMMON) + cp_ilim = total_fcc_ua; + rc = power_supply_get_property(chip->usb_psy,POWER_SUPPLY_PROP_PD_ACTIVE, &pval); + if (rc < 0) + pr_err("%s,Failed to read PD_ACTIVE status rc=%d\n",__func__,rc); + /*zxzadd for fp4 hvdcp usb icl should be less than 2A*/ + + if((pval.intval == POWER_SUPPLY_PD_INACTIVE)&&(cp_ilim>(QC3_ICL_MAX*2))){ + if(g_lcd_on) + cp_ilim =QC3_ICL_FP4_CP_MAX_LCD_ON*2; + else + cp_ilim=QC3_ICL_FP4_CP_MAX*2; + } +#else cp_ilim = total_fcc_ua - get_effective_result_locked( chip->fcc_main_votable); +#endif if (cp_ilim > 0) cp_configure_ilim(chip, FCC_VOTER, cp_ilim / 2); @@ -1569,8 +1795,13 @@ static int pl_disable_vote_callback(struct votable *votable, if (chip->step_fcc) { vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chip->fcc_stepper_work, + 0); +#else schedule_delayed_work(&chip->fcc_stepper_work, 0); +#endif } } @@ -1584,8 +1815,10 @@ static int pl_disable_vote_callback(struct votable *votable, chip->pl_disable = (bool)pl_disable; } +#if !defined(CONFIG_TCT_PM7250_COMMON) pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n", pl_disable ? "disabled" : "enabled"); +#endif return 0; } @@ -1593,9 +1826,11 @@ static int pl_disable_vote_callback(struct votable *votable, static int pl_enable_indirect_vote_callback(struct votable *votable, void *data, int pl_enable, const char *client) { +#if !defined(CONFIG_TCT_PM7250_COMMON) struct pl_data *chip = data; vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, !pl_enable, 0); +#endif return 0; } @@ -1614,6 +1849,7 @@ static int pl_awake_vote_callback(struct votable *votable, return 0; } +#if !defined(CONFIG_TCT_PM7250_COMMON) static bool is_parallel_available(struct pl_data *chip) { union power_supply_propval pval = {0, }; @@ -1678,7 +1914,9 @@ static bool is_parallel_available(struct pl_data *chip) return true; } +#endif +#if !defined(CONFIG_TCT_PM7250_COMMON) static void handle_main_charge_type(struct pl_data *chip) { union power_supply_propval pval = {0, }; @@ -1733,10 +1971,12 @@ static void handle_main_charge_type(struct pl_data *chip) /* remember the new state only if it isn't any of the above */ chip->charge_type = pval.intval; } +#endif #define MIN_ICL_CHANGE_DELTA_UA 300000 static void handle_settled_icl_change(struct pl_data *chip) { +#if !defined(CONFIG_TCT_PM7250_COMMON) union power_supply_propval pval = {0, }; int new_total_settled_ua; int rc; @@ -1776,9 +2016,11 @@ static void handle_settled_icl_change(struct pl_data *chip) vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); else vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0); +#endif rerun_election(chip->fcc_votable); +#if !defined(CONFIG_TCT_PM7250_COMMON) if (IS_USBIN(chip->pl_mode)) { /* * call aicl split only when USBIN_USBIN and enabled @@ -1805,8 +2047,10 @@ static void handle_settled_icl_change(struct pl_data *chip) split_settled(chip); } } +#endif } +#if !defined(CONFIG_TCT_PM7250_COMMON) static void handle_parallel_in_taper(struct pl_data *chip) { union power_supply_propval pval = {0, }; @@ -1835,7 +2079,9 @@ static void handle_parallel_in_taper(struct pl_data *chip) return; } } +#endif +#if 1//!defined(CONFIG_TCT_PM7250_COMMON) static void handle_usb_change(struct pl_data *chip) { int rc; @@ -1873,12 +2119,25 @@ static void handle_usb_change(struct pl_data *chip) chip->charger_type = pval.intval; } } +#endif static void status_change_work(struct work_struct *work) { struct pl_data *chip = container_of(work, struct pl_data, status_change_work.work); +#if defined(CONFIG_TCT_PM7250_COMMON) + bool input_present = false; +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!is_batt_available(chip)) { + pl_dbg(chip, PR_PARALLEL, "skip for batt_psy is NULL\n"); + __pm_relax(chip->pl_ws); + return; + } +#endif + if (!chip->main_psy && is_main_available(chip)) { /* * re-run election for FCC/FV/ICL once main_psy @@ -1890,18 +2149,58 @@ static void status_change_work(struct work_struct *work) rerun_election(chip->fv_votable); } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!chip->main_psy) { + pl_dbg(chip, PR_PARALLEL, "skip for main_psy is NULL\n"); + __pm_relax(chip->pl_ws); + return; + } +#else if (!chip->main_psy) return; +#endif +#if !defined(CONFIG_TCT_PM7250_COMMON) if (!is_batt_available(chip)) return; +#endif +#if defined(CONFIG_TCT_PM7250_COMMON) + input_present = is_input_present(chip); + if (!input_present && !chip->last_input_present) { + pl_dbg(chip, PR_PARALLEL, "skip for input_present=%d\n", + input_present); + __pm_relax(chip->pl_ws); + return; + } + chip->last_input_present = input_present; +#endif + +#if !defined(CONFIG_TCT_PM7250_COMMON) is_parallel_available(chip); +#endif +#if 1//!defined(CONFIG_TCT_PM7250_COMMON) handle_usb_change(chip); +#endif + +#if !defined(CONFIG_TCT_PM7250_COMMON) handle_main_charge_type(chip); +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) + handle_safety_timer(chip); +#endif + handle_settled_icl_change(chip); + +#if !defined(CONFIG_TCT_PM7250_COMMON) handle_parallel_in_taper(chip); +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) + __pm_relax(chip->pl_ws); +#endif } static int pl_notifier_call(struct notifier_block *nb, @@ -1913,10 +2212,25 @@ static int pl_notifier_call(struct notifier_block *nb, if (ev != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (delayed_work_pending(&chip->status_change_work)) { + pr_debug("status_change_work pending now, skip\n"); + return NOTIFY_OK; + } +#endif + if ((strcmp(psy->desc->name, "parallel") == 0) || (strcmp(psy->desc->name, "battery") == 0) || (strcmp(psy->desc->name, "main") == 0)) +#if defined(CONFIG_TCT_PM7250_COMMON) + { + __pm_stay_awake(chip->pl_ws); + queue_delayed_work(private_chg_wq, + &chip->status_change_work, 0); + } +#else schedule_delayed_work(&chip->status_change_work, 0); +#endif return NOTIFY_OK; } @@ -1937,7 +2251,12 @@ static int pl_register_notifier(struct pl_data *chip) static int pl_determine_initial_status(struct pl_data *chip) { +#if defined(CONFIG_TCT_PM7250_COMMON) + __pm_stay_awake(chip->pl_ws); + status_change_work(&chip->status_change_work.work); +#else status_change_work(&chip->status_change_work.work); +#endif return 0; } @@ -2052,6 +2371,11 @@ int qcom_batt_init(struct charger_param *chg_param) chip->pl_disable_votable = NULL; goto destroy_votable; } + +#if defined(CONFIG_TCT_PM7250_COMMON) + chip->pl_psy = NULL; +#endif + vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0); vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0); vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, true, 0); diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 6b7432746fbec5c32717eda3249bba28556a83e4..bc3982ffd333a3f9224646fdf62b20d239c75b1a 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -69,6 +69,9 @@ struct qg_dt { bool qg_ext_sense; bool use_cp_iin_sns; bool use_s7_ocv; +#if defined(CONFIG_TCT_PM7250_COMMON) + bool tt_enabled; +#endif bool qg_sleep_config; bool qg_fast_chg_cfg; bool fvss_enable; @@ -108,6 +111,11 @@ struct qpnp_qg { struct mutex data_lock; struct mutex soc_lock; wait_queue_head_t qg_wait_q; + +#if defined(CONFIG_TCT_PM7250_COMMON) + struct wakeup_source *qg_ws; +#endif + struct votable *awake_votable; struct votable *vbatt_irq_disable_votable; struct votable *fifo_irq_disable_votable; diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h index 5caeb493b3e4e2ea6fb5459d1dd580c2958b872a..2fa3fcbdb52df31a949ae482013cab4045f26809 100644 --- a/drivers/power/supply/qcom/qg-defs.h +++ b/drivers/power/supply/qcom/qg-defs.h @@ -6,6 +6,15 @@ #ifndef __QG_DEFS_H__ #define __QG_DEFS_H__ +#if defined(CONFIG_TCT_PM7250_COMMON) +#define qg_dbg(chip, reason, fmt, ...) \ + do { \ + if (*chip->debug_mask & (reason)) \ + pr_err(fmt, ##__VA_ARGS__); \ + else \ + pr_debug(fmt, ##__VA_ARGS__); \ + } while (0) +#else #define qg_dbg(chip, reason, fmt, ...) \ do { \ if (*chip->debug_mask & (reason)) \ @@ -13,6 +22,7 @@ else \ pr_debug(fmt, ##__VA_ARGS__); \ } while (0) +#endif #define is_between(left, right, value) \ (((left) >= (right) && (left) >= (value) \ diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c index 5b6a70bce855d4e0660cc7a536f02dadd42613ee..010a4e14e0af9074c4ad770baaaad4107e2ac567 100644 --- a/drivers/power/supply/qcom/qg-soc.c +++ b/drivers/power/supply/qcom/qg-soc.c @@ -629,7 +629,12 @@ static enum alarmtimer_restart /* timer callback runs in atomic context, cannot use voter */ pm_stay_awake(chip->dev); + +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_work(private_chg_wq, &chip->scale_soc_work); +#else schedule_work(&chip->scale_soc_work); +#endif return ALARMTIMER_NORESTART; } diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c index 36b5fefa42aa069df36b9186d508c650cbb778d3..6b738b6f058fc5236bf978c5770abf99e457285b 100644 --- a/drivers/power/supply/qcom/qg-util.c +++ b/drivers/power/supply/qcom/qg-util.c @@ -374,7 +374,13 @@ int qg_get_battery_temp(struct qpnp_qg *chip, int *temp) pr_err("Failed reading BAT_TEMP over ADC rc=%d\n", rc); return rc; } - pr_debug("batt_temp = %d\n", *temp); + +#if defined(CONFIG_TCT_PM7250_COMMON) +#if defined(DISABLE_TEMPERATURE_DETECTION_AND_THERMAL_POLICY) + pr_debug("temperature fixed at 25 degree! The real temp is=%d\n", *temp); + *temp = 250; +#endif +#endif return 0; } diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 0032df497d2a4c1bbb73563dcae75eff7de177af..aabe3f1d9fb2fd4c8395535beb449d0006213d4f 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -120,6 +120,34 @@ static bool is_battery_present(struct qpnp_qg *chip) return present; } +#if defined(CONFIG_TCT_PM7250_COMMON) +#if defined(CONFIG_TCT_GCF) || \ + defined(CONFIG_TCT_IEEE1725) || \ + defined(CONFIG_TCT_CB) +#define VALID_BATT_ID_82K_LOW (69700) +#define VALID_BATT_ID_82K_HIGH (94300) + +#define VALID_BATT_ID_18K_LOW (15300) +#define VALID_BATT_ID_18K_HIGH (20700) +static bool is_debug_batt_id(struct qpnp_qg *chip) +{ + if (is_between(VALID_BATT_ID_82K_LOW, VALID_BATT_ID_82K_HIGH, + chip->batt_id_ohm)) + return false; + + if (is_between(VALID_BATT_ID_18K_LOW, VALID_BATT_ID_18K_HIGH, + chip->batt_id_ohm)) + return false; + + return true; +} +#else +static bool is_debug_batt_id(struct qpnp_qg *chip) +{ + return false; +} +#endif +#else #define DEBUG_BATT_ID_LOW 6000 #define DEBUG_BATT_ID_HIGH 8500 static bool is_debug_batt_id(struct qpnp_qg *chip) @@ -130,6 +158,7 @@ static bool is_debug_batt_id(struct qpnp_qg *chip) return false; } +#endif static int qg_read_ocv(struct qpnp_qg *chip, u32 *ocv_uv, u32 *ocv_raw, u8 type) { @@ -836,6 +865,12 @@ static void qg_retrieve_esr_params(struct qpnp_qg *chip) rc = qg_sdam_read(SDAM_ESR_CHARGE_DELTA, &data); if (!rc && data) { +#if defined(CONFIG_TCT_PM7250_COMMON) + if (abs((int)data) > 10) { + pr_err("abnormal chg esr: 0x%x\n", data); + data = 0; + } +#endif chip->kdata.param[QG_ESR_CHARGE_DELTA].data = data; chip->kdata.param[QG_ESR_CHARGE_DELTA].valid = true; qg_dbg(chip, QG_DEBUG_ESR, @@ -846,6 +881,12 @@ static void qg_retrieve_esr_params(struct qpnp_qg *chip) rc = qg_sdam_read(SDAM_ESR_DISCHARGE_DELTA, &data); if (!rc && data) { +#if defined(CONFIG_TCT_PM7250_COMMON) + if (abs((int)data) > 10) { + pr_err("abnormal dischg esr: 0x%x\n", data); + data = 0; + } +#endif chip->kdata.param[QG_ESR_DISCHARGE_DELTA].data = data; chip->kdata.param[QG_ESR_DISCHARGE_DELTA].valid = true; qg_dbg(chip, QG_DEBUG_ESR, @@ -883,16 +924,34 @@ static void qg_store_esr_params(struct qpnp_qg *chip) if (chip->udata.param[QG_ESR_CHARGE_DELTA].valid) { esr = chip->udata.param[QG_ESR_CHARGE_DELTA].data; + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (abs((int)esr) < 10) { + qg_sdam_write(SDAM_ESR_CHARGE_DELTA, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_CHARGE_DELTA=0x%x\n", esr); + } +#else qg_sdam_write(SDAM_ESR_CHARGE_DELTA, esr); qg_dbg(chip, QG_DEBUG_ESR, "SDAM store ESR_CHARGE_DELTA=%d\n", esr); +#endif } if (chip->udata.param[QG_ESR_DISCHARGE_DELTA].valid) { esr = chip->udata.param[QG_ESR_DISCHARGE_DELTA].data; + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (abs((int)esr) < 10) { + qg_sdam_write(SDAM_ESR_DISCHARGE_DELTA, esr); + qg_dbg(chip, QG_DEBUG_ESR, + "SDAM store ESR_DISCHARGE_DELTA=0x%x\n", esr); + } +#else qg_sdam_write(SDAM_ESR_DISCHARGE_DELTA, esr); qg_dbg(chip, QG_DEBUG_ESR, "SDAM store ESR_DISCHARGE_DELTA=%d\n", esr); +#endif } if (chip->udata.param[QG_ESR_CHARGE_SF].valid) { @@ -1208,6 +1267,10 @@ static void process_udata_work(struct work_struct *work) struct qpnp_qg, udata_work); int rc; +#if defined(CONFIG_TCT_PM7250_COMMON) + mutex_lock(&chip->data_lock); +#endif + if (chip->udata.param[QG_CC_SOC].valid) chip->cc_soc = chip->udata.param[QG_CC_SOC].data; @@ -1240,6 +1303,18 @@ static void process_udata_work(struct work_struct *work) chip->catch_up_soc = chip->udata.param[QG_SOC].data; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chip->catch_up_soc == 0) { + int vbat_uv = 0; + int vcutoff_uv = chip->dt.vbatt_cutoff_mv * 1000; + qg_get_battery_voltage(chip, &vbat_uv); + if (vbat_uv >= vcutoff_uv) { + pr_debug("%d >= %d, keep report soc=1\n", vbat_uv, vcutoff_uv); + chip->catch_up_soc = 1; + } + } +#endif + qg_scale_soc(chip, chip->force_soc); chip->force_soc = false; @@ -1259,6 +1334,12 @@ static void process_udata_work(struct work_struct *work) if (chip->udata.param[QG_ESR].valid) chip->esr_last = chip->udata.param[QG_ESR].data; +#if defined(CONFIG_TCT_PM7250_COMMON) + pr_err_ratelimited("userspace write rbat=%d, esr=%d\n", + chip->sdam_data[SDAM_RBAT_MOHM], + chip->esr_last); +#endif + if (chip->esr_actual != -EINVAL && chip->udata.param[QG_ESR].valid) { chip->esr_nominal = chip->udata.param[QG_ESR].data; if (chip->qg_psy) @@ -1272,6 +1353,11 @@ static void process_udata_work(struct work_struct *work) (chip->batt_soc != INT_MIN) ? chip->batt_soc : -EINVAL, (chip->cc_soc != INT_MIN) ? chip->cc_soc : -EINVAL, chip->full_soc, chip->esr_last); + +#if defined(CONFIG_TCT_PM7250_COMMON) + mutex_unlock(&chip->data_lock); +#endif + vote(chip->awake_votable, UDATA_READY_VOTER, false, 0); } @@ -1397,9 +1483,19 @@ static irqreturn_t qg_vbat_empty_handler(int irq, void *data) pr_warn("VBATT EMPTY SOC = 0\n"); +#if defined(CONFIG_TCT_PM7250_COMMON) + mutex_lock(&chip->soc_lock); +#endif chip->catch_up_soc = 0; +#if defined(CONFIG_TCT_PM7250_COMMON) + mutex_unlock(&chip->soc_lock); +#endif qg_scale_soc(chip, true); +#if defined(CONFIG_TCT_PM7250_COMMON) + mutex_lock(&chip->data_lock); +#endif + qg_sdam_read(SDAM_OCV_UV, &ocv_uv); chip->sdam_data[SDAM_SOC] = 0; chip->sdam_data[SDAM_OCV_UV] = ocv_uv; @@ -1407,6 +1503,10 @@ static irqreturn_t qg_vbat_empty_handler(int irq, void *data) qg_store_soc_params(chip); +#if defined(CONFIG_TCT_PM7250_COMMON) + mutex_unlock(&chip->data_lock); +#endif + if (chip->qg_psy) power_supply_changed(chip->qg_psy); @@ -1487,6 +1587,21 @@ static struct qg_irq_info qg_irqs[] = { }, }; +#if defined(CONFIG_TCT_PM7250_COMMON) +static int qg_awake_cb(struct votable *votable, void *data, int awake, + const char *client) +{ + struct qpnp_qg *chip = data; + + if (awake) + __pm_stay_awake(chip->qg_ws); + else + __pm_relax(chip->qg_ws); + + pr_debug("client: %s awake: %d\n", client, awake); + return 0; +} +#else static int qg_awake_cb(struct votable *votable, void *data, int awake, const char *client) { @@ -1504,6 +1619,7 @@ static int qg_awake_cb(struct votable *votable, void *data, int awake, pr_debug("client: %s awake: %d\n", client, awake); return 0; } +#endif static int qg_fifo_irq_disable_cb(struct votable *votable, void *data, int disable, const char *client) @@ -2238,13 +2354,27 @@ static int qg_psy_get_property(struct power_supply *psy, rc = get_cycle_count(chip->counter, &pval->intval); break; case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chip->dt.tt_enabled) + rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + else + rc = -ENODATA; +#else rc = ttf_get_time_to_full(chip->ttf, &pval->intval); +#endif break; case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: rc = ttf_get_time_to_full(chip->ttf, &pval->intval); break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chip->dt.tt_enabled) + rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); + else + rc = -ENODATA; +#else rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); +#endif break; case POWER_SUPPLY_PROP_ESR_ACTUAL: pval->intval = (chip->esr_actual == -EINVAL) ? -EINVAL : @@ -2286,9 +2416,17 @@ static int qg_psy_get_property(struct power_supply *psy, break; default: pr_debug("Unsupported property %d\n", psp); +#if defined(CONFIG_TCT_PM7250_COMMON) + rc = -EINVAL; +#endif break; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (rc < 0) + rc = -ENODATA; +#endif + return rc; } @@ -2718,7 +2856,13 @@ static void qg_status_change_work(struct work_struct *work) if (rc < 0) pr_err("Failed in charge_full_update, rc=%d\n", rc); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chip->dt.tt_enabled) + ttf_update(chip->ttf, input_present); +#else ttf_update(chip->ttf, input_present); +#endif + out: pm_relax(chip->dev); } @@ -2732,8 +2876,15 @@ static int qg_notifier_cb(struct notifier_block *nb, if (event != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (work_pending(&chip->qg_status_change_work)) { + pr_debug("qg_status_change_work pending now, skip\n"); + return NOTIFY_OK; + } +#else if (work_pending(&chip->qg_status_change_work)) return NOTIFY_OK; +#endif if ((strcmp(psy->desc->name, "battery") == 0) || (strcmp(psy->desc->name, "parallel") == 0) @@ -2745,7 +2896,12 @@ static int qg_notifier_cb(struct notifier_block *nb, * a mutex lock and this is executed in an atomic context. */ pm_stay_awake(chip->dev); + +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_work(private_chg_wq, &chip->qg_status_change_work); +#else schedule_work(&chip->qg_status_change_work); +#endif } return NOTIFY_OK; @@ -2809,6 +2965,17 @@ static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count, goto fail_read; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if ((chip->sdam_data[SDAM_RBAT_MOHM] != 0) && + (chip->sdam_data[SDAM_RBAT_MOHM] > 170 || + chip->sdam_data[SDAM_RBAT_MOHM] < 80)) { + chip->kdata.param[QG_CLEAR_LEARNT_DATA].data = 1; + chip->kdata.param[QG_CLEAR_LEARNT_DATA].valid = true; + qg_dbg(chip, QG_DEBUG_ESR, + "fg rbatt(%d) abnormal, reset hvdcp_opti data\n", + chip->sdam_data[SDAM_RBAT_MOHM]); + } +#endif if (copy_to_user(buf, &chip->kdata, data_size)) { pr_err("Failed in copy_to_user\n"); @@ -2866,8 +3033,16 @@ static ssize_t qg_device_write(struct file *file, const char __user *buf, rc = data_size; vote(chip->awake_votable, UDATA_READY_VOTER, true, 0); + +#if defined(CONFIG_TCT_PM7250_COMMON) + mutex_unlock(&chip->data_lock); + qg_dbg(chip, QG_DEBUG_DEVICE, "QG write complete size=%d\n", rc); + queue_work(private_chg_wq, &chip->udata_work); + return rc; +#else schedule_work(&chip->udata_work); qg_dbg(chip, QG_DEBUG_DEVICE, "QG write complete size=%d\n", rc); +#endif fail: mutex_unlock(&chip->data_lock); return rc; @@ -3231,6 +3406,20 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) pr_err("Failed to read shutdown params rc=%d\n", rc); goto use_pon_ocv; } + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (abs((int)shutdown[SDAM_ESR_CHARGE_DELTA]) > 10) { + pr_err("found abnormal esr chg delta(0x%x)\n", + shutdown[SDAM_ESR_CHARGE_DELTA]); + qg_sdam_write(SDAM_ESR_CHARGE_DELTA, 0); + } + if (abs((int)shutdown[SDAM_ESR_DISCHARGE_DELTA]) > 10) { + pr_err("found abnormal esr dischg delta(0x%x)\n", + shutdown[SDAM_ESR_DISCHARGE_DELTA]); + qg_sdam_write(SDAM_ESR_DISCHARGE_DELTA, 0); + } +#endif + shutdown_temp = sign_extend32(shutdown[SDAM_TEMP], 15); rc = lookup_soc_ocv(&pon_soc, ocv[S7_PON_OCV].ocv_uv, batt_temp, false); @@ -3253,6 +3442,38 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) * 2. The device was powered off for < ignore_shutdown_time * 2. Batt temp has not changed more than shutdown_temp_diff */ +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!shutdown[SDAM_VALID]) { + pr_err("WARNING: sdram data invalid\n"); + goto use_pon_ocv; + } + + if (!is_between(0, chip->dt.ignore_shutdown_soc_secs, + abs(rtc_sec - shutdown[SDAM_TIME_SEC]))) { + pr_err("WARNING: too long time interval(%ld,%d,%d)\n", + rtc_sec, shutdown[SDAM_TIME_SEC], + chip->dt.ignore_shutdown_soc_secs); + goto use_pon_ocv; + } + + if (!is_between(0, chip->dt.shutdown_temp_diff, + abs(shutdown_temp - batt_temp)) && + (shutdown_temp < 0 || batt_temp < 0)) { + pr_err("WARNING: too big gaps of temperature(%d,%d,%d)\n", + shutdown_temp, batt_temp, + chip->dt.shutdown_temp_diff); + goto use_pon_ocv; + } + + if ((chip->dt.shutdown_soc_threshold != -EINVAL) && + !is_between(0, chip->dt.shutdown_soc_threshold, + abs(pon_soc - shutdown[SDAM_SOC]))) { + pr_err("WARNING: too big gaps of soc(%d,%d,%d)\n", + pon_soc, shutdown[SDAM_SOC], + chip->dt.shutdown_soc_threshold); + goto use_pon_ocv; + } +#else if (!shutdown[SDAM_VALID]) goto use_pon_ocv; @@ -3269,6 +3490,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) !is_between(0, chip->dt.shutdown_soc_threshold, abs(pon_soc - shutdown[SDAM_SOC]))) goto use_pon_ocv; +#endif use_pon_ocv = false; ocv_uv = shutdown[SDAM_OCV_UV]; @@ -4605,7 +4827,9 @@ static int process_resume(struct qpnp_qg *chip) chip->suspend_data = false; } +#if !defined(CONFIG_TCT_PM7250_COMMON) schedule_delayed_work(&chip->ttf->ttf_work, 0); +#endif return rc; } @@ -4821,7 +5045,9 @@ static int qpnp_qg_probe(struct platform_device *pdev) pr_err("Error in restoring cycle_count, rc=%d\n", rc); return rc; } +#if !defined(CONFIG_TCT_PM7250_COMMON) schedule_delayed_work(&chip->ttf->ttf_work, 10000); +#endif } rc = qg_determine_pon_soc(chip); @@ -4830,6 +5056,12 @@ static int qpnp_qg_probe(struct platform_device *pdev) goto fail_device; } +#if defined(CONFIG_TCT_PM7250_COMMON) + chip->qg_ws = wakeup_source_register(&pdev->dev, "qg_voted_ws"); + if (!chip->qg_ws) + goto fail_device; +#endif + chip->awake_votable = create_votable("QG_WS", VOTE_SET_ANY, qg_awake_cb, chip); if (IS_ERR(chip->awake_votable)) { @@ -4902,6 +5134,11 @@ static int qpnp_qg_probe(struct platform_device *pdev) device_destroy(chip->qg_class, chip->dev_no); cdev_del(&chip->qg_cdev); unregister_chrdev_region(chip->dev_no, 1); + +#if defined(CONFIG_TCT_PM7250_COMMON) + wakeup_source_unregister(chip->qg_ws); + pr_err("QG probe failed with err:%d\n", rc); +#endif return rc; } @@ -4925,6 +5162,9 @@ static int qpnp_qg_remove(struct platform_device *pdev) mutex_destroy(&chip->soc_lock); if (chip->awake_votable) destroy_votable(chip->awake_votable); +#if defined(CONFIG_TCT_PM7250_COMMON) + wakeup_source_unregister(chip->qg_ws); +#endif return 0; } diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index ce5a63dfb3b2f3601d8195907050ac7f43d23f0c..f2884c5d7d51c3cff37077d22d378bd8c99e42e3 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -3,6 +3,9 @@ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. */ +#if defined(CONFIG_TCT_PM7250_COMMON) +#define pr_fmt(fmt) "[SMB5]: %s: " fmt, __func__ +#endif #include #include #include @@ -227,6 +230,46 @@ struct smb5 { struct smb_dt_props dt; }; +#if defined(CONFIG_TCT_PM7250_COMMON) +static int thermal_disable = 0; +module_param_named( + thermal_disable, thermal_disable, + int, S_IRUSR | S_IWUSR +); + +static int fixtemp = 0; +static int fixtemp_val = 250; +module_param_named( + fixtemp_val, fixtemp_val, + int, S_IRUSR | S_IWUSR +); + +static int stopchg_en = 1; +module_param_named( + stopchg_en, stopchg_en, + int, S_IRUSR | S_IWUSR +); +static int safety_timer_en = 1; +module_param_named( + safety_timer_en, safety_timer_en, + int, S_IRUSR | S_IWUSR +); +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) +static int force_icl = 400000; +module_param_named( + force_icl, force_icl, + int, S_IRUSR | S_IWUSR +); + +static int force_fcc = 800000; +module_param_named( + force_fcc, force_fcc, + int, S_IRUSR | S_IWUSR +); +#endif + static int __debug_mask; static ssize_t pd_disabled_show(struct device *dev, struct device_attribute @@ -335,8 +378,15 @@ static int smb5_chg_config_init(struct smb5 *chip) chip->chg.chg_param.smb_version = PM7250B_SUBTYPE; chg->param = smb5_pm8150b_params; chg->name = "pm7250b_charger"; +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->hw_max_icl_ua = HW_ICL_MAX; + chg->uusb_moisture_protection_capable = false; + chg->main_fcc_max = PM6150_MAX_FCC_UA; + chg->wa_flags |= SW_THERM_REGULATION_WA | CHG_TERMINATION_WA; +#else chg->wa_flags |= CHG_TERMINATION_WA; chg->uusb_moisture_protection_capable = true; +#endif break; case PM6150_SUBTYPE: chip->chg.chg_param.smb_version = PM6150_SUBTYPE; @@ -504,6 +554,43 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) } } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (of_find_property(node, "qcom,thermal-mitigation-lcdon", &byte_len)) { + chg->thermal_mitigation_lcdon = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_lcdon == NULL) { + dev_err(chg->dev, "thermal_mitigation_lcdon NULL\n"); + chg->thermal_levels = 0; + return -ENOMEM; + } + + if (chg->thermal_levels != (byte_len / sizeof(u32))) { + dev_err(chg->dev, "thermal on-off levels %d not equal\n", + chg->thermal_levels); + chg->thermal_levels = 0; + return -EINVAL; + } + + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-lcdon", + chg->thermal_mitigation_lcdon, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read thermal-lcdon limits rc = %d\n", rc); + chg->thermal_levels = 0; + return rc; + } + } else if (chg->thermal_levels) { + /* if qcom,thermal-mitigation defined but not this one. */ + dev_err(chg->dev, + "ERROR: thermal-lcdon must defined!\n"); + chg->thermal_levels = 0; + //return -EINVAL; // let boot up with debug later. + } +#endif + rc = of_property_read_u32(node, "qcom,charger-temp-max", &chg->charger_temp_max); if (rc < 0) @@ -575,6 +662,9 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) chip->dt.disable_suspend_on_collapse = of_property_read_bool(node, "qcom,disable-suspend-on-collapse"); +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->disable_suspend_on_collapse = chip->dt.disable_suspend_on_collapse; +#endif chg->smb_pull_up = -EINVAL; of_property_read_u32(node, "qcom,smb-internal-pull-kohm", &chg->smb_pull_up); @@ -891,6 +981,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_APSD_TIMEOUT, POWER_SUPPLY_PROP_CHARGER_STATUS, POWER_SUPPLY_PROP_INPUT_VOLTAGE_SETTLED, + POWER_SUPPLY_PROP_CONNECTOR_TEMP, }; static int smb5_usb_get_prop(struct power_supply *psy, @@ -906,6 +997,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_PRESENT: rc = smblib_get_prop_usb_present(chg, val); +#if defined(CONFIG_TCT_CHG_AUTOTEST) + pr_err_ratelimited("TCTNB_PRESENT:%d\n", val->intval); +#endif break; case POWER_SUPPLY_PROP_ONLINE: rc = smblib_get_usb_online(chg, val); @@ -936,6 +1030,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_REAL_TYPE: val->intval = chg->real_charger_type; +#if defined(CONFIG_TCT_CHG_AUTOTEST) + pr_err_ratelimited("TCTNB_REALTYPE:%d\n", val->intval); +#endif break; case POWER_SUPPLY_PROP_TYPEC_MODE: rc = smblib_get_usb_prop_typec_mode(chg, val); @@ -998,6 +1095,11 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: val->intval = smblib_get_prop_connector_health(chg); break; + + case POWER_SUPPLY_PROP_CONNECTOR_TEMP: + val->intval = chg->connector_temp; + break; + case POWER_SUPPLY_PROP_SCOPE: rc = smblib_get_prop_scope(chg, val); break; @@ -1028,6 +1130,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_THERM_ICL_LIMIT: val->intval = get_client_vote(chg->usb_icl_votable, THERMAL_THROTTLE_VOTER); +#if defined(CONFIG_TCT_CHG_AUTOTEST) + pr_err_ratelimited("TCTNB_THRO_ICL:%d\n", val->intval); +#endif break; case POWER_SUPPLY_PROP_ADAPTER_CC_MODE: val->intval = chg->adapter_cc_mode; @@ -1099,14 +1204,22 @@ static int smb5_usb_set_prop(struct power_supply *psy, rc = smblib_set_prop_pd_in_hard_reset(chg, val); break; case POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED: +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->system_suspend_supported = false; +#else chg->system_suspend_supported = val->intval; +#endif break; case POWER_SUPPLY_PROP_BOOST_CURRENT: rc = smblib_set_prop_boost_current(chg, val); break; case POWER_SUPPLY_PROP_CTM_CURRENT_MAX: +#if defined(CONFIG_TCT_PM7250_COMMON) + rc = -EINVAL; +#else rc = vote(chg->usb_icl_votable, CTM_VOTER, val->intval >= 0, val->intval); +#endif break; case POWER_SUPPLY_PROP_PR_SWAP: rc = smblib_set_prop_pr_swap_in_progress(chg, val); @@ -1125,6 +1238,12 @@ static int smb5_usb_set_prop(struct power_supply *psy, power_supply_changed(chg->usb_psy); break; case POWER_SUPPLY_PROP_THERM_ICL_LIMIT: +#if defined(CONFIG_TCT_PM7250_COMMON) + return 0; +#endif + + + if (!is_client_vote_enabled(chg->usb_icl_votable, THERMAL_THROTTLE_VOTER)) { chg->init_thermal_ua = get_effective_result( @@ -1235,9 +1354,13 @@ static int smb5_usb_port_get_prop(struct power_supply *psy, if (!val->intval) break; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) +#else if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) +#endif val->intval = 1; else val->intval = 0; @@ -1402,10 +1525,19 @@ static int smb5_usb_main_get_prop(struct power_supply *psy, rc = -EINVAL; break; } + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (rc < 0) { + pr_debug("Couldn't get prop %d rc = %d\n", psp, rc); + return -ENODATA; + } + return 0; +#else if (rc < 0) pr_debug("Couldn't get prop %d rc = %d\n", psp, rc); return rc; +#endif } static int smb5_usb_main_set_prop(struct power_supply *psy, @@ -1418,6 +1550,10 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, enum power_supply_type real_chg_type = chg->real_charger_type; int rc = 0, offset_ua = 0; +#if defined(CONFIG_TCT_PM7250_COMMON) + int proper_fcc; +#endif + switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval); @@ -1428,8 +1564,23 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, if (rc < 0) offset_ua = 0; +#if defined(CONFIG_TCT_PM7250_COMMON) + if ((val->intval + offset_ua) > chg->batt_profile_fcc_ua) { + proper_fcc = chg->batt_profile_fcc_ua; + } else if ((rc == -ENXIO) + && (is_override_vote_enabled_locked(chg->fcc_main_votable))) { + proper_fcc = get_effective_result_locked(chg->fcc_votable); + } else { + proper_fcc = val->intval + offset_ua; + } + pr_err("set final main_fcc = %d, %d + %d\n", proper_fcc, + val->intval, offset_ua); + rc = smblib_set_charge_param(chg, &chg->param.fcc, + proper_fcc); +#else rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval + offset_ua); +#endif break; case POWER_SUPPLY_PROP_CURRENT_MAX: rc = smblib_set_icl_current(chg, val->intval); @@ -1473,8 +1624,21 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, rerun_election(chg->fcc_votable); break; case POWER_SUPPLY_PROP_FORCE_MAIN_FCC: +#if defined(CONFIG_TCT_PM7250_COMMON) + if ((val->intval > 0) && (force_fcc >= 0)) { + pr_err("FORCE_MAIN_FCC: %d -> %d\n", val->intval, + force_fcc); + vote_override(chg->fcc_main_votable, CC_MODE_VOTER, + true, force_fcc); + } else { + pr_err("FORCE_MAIN_FCC: %d\n", val->intval); + vote_override(chg->fcc_main_votable, CC_MODE_VOTER, + (val->intval < 0) ? false : true, val->intval); + } +#else vote_override(chg->fcc_main_votable, CC_MODE_VOTER, (val->intval < 0) ? false : true, val->intval); +#endif if (val->intval >= 0) chg->chg_param.forced_main_fcc = val->intval; /* @@ -1488,8 +1652,21 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, rerun_election(chg->fcc_votable); break; case POWER_SUPPLY_PROP_FORCE_MAIN_ICL: +#if defined(CONFIG_TCT_PM7250_COMMON) + if ((val->intval > 0) && (force_icl >= 0)) { + pr_err("FORCE_MAIN_ICL: %d -> %d\n", val->intval, + force_icl); + vote_override(chg->usb_icl_votable, CC_MODE_VOTER, + true, force_icl); + } else { + pr_err("FORCE_MAIN_ICL: %d\n", val->intval); + vote_override(chg->usb_icl_votable, CC_MODE_VOTER, + (val->intval < 0) ? false : true, val->intval); + } +#else vote_override(chg->usb_icl_votable, CC_MODE_VOTER, (val->intval < 0) ? false : true, val->intval); +#endif /* Main ICL updated re-calculate ILIM */ if (real_chg_type == POWER_SUPPLY_TYPE_USB_HVDCP_3 || real_chg_type == POWER_SUPPLY_TYPE_USB_HVDCP_3P5) @@ -1738,6 +1915,11 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, +#if defined(CONFIG_TCT_PM7250_COMMON) + POWER_SUPPLY_PROP_TCL_FIXTEMP, + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE, +#endif }; #define DEBUG_ACCESSORY_TEMP_DECIDEGC 250 @@ -1766,6 +1948,9 @@ static int smb5_batt_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_get_prop_batt_capacity(chg, val); +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->real_soc = val->intval; +#endif break; case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: rc = smblib_get_prop_system_temp_level(chg, val); @@ -1821,11 +2006,21 @@ static int smb5_batt_get_prop(struct power_supply *psy, rc = smblib_get_prop_batt_iterm(chg, val); break; case POWER_SUPPLY_PROP_TEMP: +#if defined(CONFIG_TCT_PM7250_COMMON) + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_TEMP, val); +#else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY) val->intval = DEBUG_ACCESSORY_TEMP_DECIDEGC; else rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val); +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) + if(fixtemp == 1) + val->intval = fixtemp_val; +#endif break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -1890,9 +2085,25 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_enable; break; +#if defined(CONFIG_TCT_PM7250_COMMON) + case POWER_SUPPLY_PROP_TCL_FIXTEMP: + val->intval = fixtemp; + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + val->intval = !get_client_vote(chg->chg_disable_votable, + USER_VOTER); + break; + case POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE: + val->intval = safety_timer_en; + break; +#endif default: pr_err("batt power supply prop %d not supported\n", psp); +#if defined(CONFIG_TCT_PM7250_COMMON) + return -ENODATA; +#else return -EINVAL; +#endif } if (rc < 0) { @@ -1914,10 +2125,37 @@ static int smb5_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_STATUS: rc = smblib_set_prop_batt_status(chg, val); break; + +#if defined(CONFIG_TCT_PM7250_COMMON) + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + if (!stopchg_en) { + pr_emerg("stop battery chg not allowed\n"); + return -EINVAL; + } + vote(chg->chg_disable_votable, USER_VOTER, + (val->intval > 0) ? false : true, 0); + pr_emerg("WARNING: userspace %s battery chg function!\n", + (val->intval > 0) ? "enable" : "disable"); + break; +#endif + case POWER_SUPPLY_PROP_INPUT_SUSPEND: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!stopchg_en) { + pr_emerg("stop chg not allowed\n"); + return -EINVAL; + } +#endif rc = smblib_set_prop_input_suspend(chg, val); +#if defined(CONFIG_TCT_PM7250_COMMON) + pr_emerg("WARNING: userspace disabled charge function! \n"); +#endif break; case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (thermal_disable) + break; +#endif rc = smblib_set_prop_system_temp_level(chg, val); break; case POWER_SUPPLY_PROP_CAPACITY: @@ -1972,8 +2210,20 @@ static int smb5_batt_set_prop(struct power_supply *psy, rc = smblib_run_aicl(chg, RERUN_AICL); break; case POWER_SUPPLY_PROP_DP_DM: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (val->intval == POWER_SUPPLY_DP_DM_FORCE_12V) { + return -EINVAL; + } else if((chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) + && (val->intval == POWER_SUPPLY_DP_DM_FORCE_9V) + && (chg->real_soc > 90)) { + return -EINVAL; + } else if (!chg->flash_active) { + rc = smblib_dp_dm(chg, val->intval); + } +#else if (!chg->flash_active) rc = smblib_dp_dm(chg, val->intval); +#endif break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: rc = smblib_set_prop_input_current_limited(chg, val); @@ -1997,6 +2247,15 @@ static int smb5_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: chg->fcc_stepper_enable = val->intval; break; +#if defined(CONFIG_TCT_PM7250_COMMON) + case POWER_SUPPLY_PROP_TCL_FIXTEMP: + fixtemp = val->intval; + break; + case POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE: + safety_timer_en = val->intval; + pr_err("set safety timer %d done\n", safety_timer_en); + break; +#endif default: rc = -EINVAL; } @@ -2010,7 +2269,9 @@ static int smb5_batt_prop_is_writeable(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: case POWER_SUPPLY_PROP_INPUT_SUSPEND: +#if !defined(CONFIG_TCT_PM7250_COMMON) case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: +#endif case POWER_SUPPLY_PROP_CAPACITY: case POWER_SUPPLY_PROP_PARALLEL_DISABLE: case POWER_SUPPLY_PROP_DP_DM: @@ -2018,6 +2279,16 @@ static int smb5_batt_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: case POWER_SUPPLY_PROP_DIE_HEALTH: +#if defined(CONFIG_TCT_PM7250_COMMON) + case POWER_SUPPLY_PROP_TCL_FIXTEMP: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: + case POWER_SUPPLY_PROP_FORCE_RECHARGE: + case POWER_SUPPLY_PROP_SET_SHIP_MODE: + case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE: +#endif return 1; default: break; @@ -2183,6 +2454,14 @@ static int smb5_configure_typec(struct smb_charger *chg) smblib_apsd_enable(chg, true); +#if defined(CONFIG_TCT_PM7250_COMMON) + rc = smblib_masked_write(chg, TYPE_C_CFG_REG, + BC1P2_START_ON_CC_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, "failed to write TYPE_C_CFG_REG rc=%d\n", rc); + return rc; + } +#else rc = smblib_read(chg, TYPE_C_SNK_STATUS_REG, &val); if (rc < 0) { dev_err(chg->dev, "failed to read TYPE_C_SNK_STATUS_REG rc=%d\n", @@ -2201,6 +2480,7 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } } +#endif /* Use simple write to clear interrupts */ rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG, 0); @@ -2692,13 +2972,27 @@ static int smb5_init_hw(struct smb5 *chip) pr_err("Couldn't clear SDAM ADC status rc=%d\n", rc); } + +/* zxz add for connect usb boot up, but the charge current is very low (is a negative value) , +the reason is because of the "proper_fcc"=0; in smb5_usb_main_set_prop 'POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX' , +batt_profile_fcc_ua =0 when boot up . +*/ if (chip->dt.batt_profile_fcc_ua < 0) smblib_get_charge_param(chg, &chg->param.fcc, &chg->batt_profile_fcc_ua); + else{ + if((chg->batt_profile_fcc_ua<0)||(chg->batt_profile_fcc_ua==0)) + chg->batt_profile_fcc_ua= chip->dt.batt_profile_fcc_ua; + } + +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->batt_profile_fv_uv = 4400000; +#else if (chip->dt.batt_profile_fv_uv < 0) smblib_get_charge_param(chg, &chg->param.fv, &chg->batt_profile_fv_uv); +#endif smblib_get_charge_param(chg, &chg->param.usb_icl, &chg->default_icl_ua); @@ -2821,7 +3115,11 @@ static int smb5_init_hw(struct smb5 *chip) } rc = smblib_write(chg, AICL_RERUN_TIME_CFG_REG, +#if defined(CONFIG_TCT_PM7250_COMMON) + AICL_RERUN_TIME_3MIN_VAL); +#else AICL_RERUN_TIME_12S_VAL); +#endif if (rc < 0) { dev_err(chg->dev, "Couldn't configure AICL rerun interval rc=%d\n", rc); @@ -2917,7 +3215,15 @@ static int smb5_init_hw(struct smb5 *chip) } rc = smblib_write(chg, CHGR_FAST_CHARGE_SAFETY_TIMER_CFG_REG, +#if defined(CONFIG_TCT_PM7250_COMMON) +#if defined(CONFIG_TCT_IEEE1725) + FAST_CHARGE_SAFETY_TIMER_192_MIN); +#else + FAST_CHARGE_SAFETY_TIMER_1536_MIN); +#endif +#else FAST_CHARGE_SAFETY_TIMER_768_MIN); +#endif if (rc < 0) { dev_err(chg->dev, "Couldn't set CHGR_FAST_CHARGE_SAFETY_TIMER_CFG_REG rc=%d\n", rc); @@ -2953,6 +3259,16 @@ static int smb5_init_hw(struct smb5 *chip) } } +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->qc2_unsupported_voltage = QC2_NON_COMPLIANT_12V; + rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, + HVDCP_PULSE_COUNT_MAX_QC2_MASK, + HVDCP_PULSE_COUNT_MAX_QC2_9V); + if (rc < 0) + dev_err(chg->dev, "Couldn't write max pulses rc=%d\n", + rc); +#endif + if (chg->smb_pull_up != -EINVAL) { rc = smb5_configure_internal_pull(chg, SMB_THERM, get_valid_pullup(chg->smb_pull_up)); @@ -3084,7 +3400,9 @@ static struct smb_irq_info smb5_irqs[] = { }, [INPUT_CURRENT_LIMITING_IRQ] = { .name = "input-current-limiting", +#if !defined(CONFIG_TCT_PM7250_COMMON) .handler = default_irq_handler, +#endif }, [CONCURRENT_MODE_DISABLE_IRQ] = { .name = "concurrent-mode-disable", @@ -3337,7 +3655,9 @@ static int smb5_request_interrupt(struct smb5 *chip, irq_data->storm_data = smb5_irqs[irq_index].storm_data; mutex_init(&irq_data->storm_data.storm_lock); +#if !defined(CONFIG_TCT_PM7250_COMMON) smb5_irqs[irq_index].enabled = true; +#endif rc = devm_request_threaded_irq(chg->dev, irq, NULL, smb5_irqs[irq_index].handler, IRQF_ONESHOT, irq_name, irq_data); @@ -3346,6 +3666,9 @@ static int smb5_request_interrupt(struct smb5 *chip, return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + smb5_irqs[irq_index].enabled = true; +#endif smb5_irqs[irq_index].irq = irq; smb5_irqs[irq_index].irq_data = irq_data; if (smb5_irqs[irq_index].wake) @@ -3671,7 +3994,9 @@ static int smb5_probe(struct platform_device *pdev) switch (chg->chg_param.smb_version) { case PM8150B_SUBTYPE: case PM6150_SUBTYPE: +#if defined(CONFIG_TCT_PM7250_COMMON) case PM7250B_SUBTYPE: +#endif rc = smb5_init_dc_psy(chip); if (rc < 0) { pr_err("Couldn't initialize dc psy rc=%d\n", rc); @@ -3712,12 +4037,14 @@ static int smb5_probe(struct platform_device *pdev) goto cleanup; } +#if !defined(CONFIG_TCT_PM7250_COMMON) rc = smb5_determine_initial_status(chip); if (rc < 0) { pr_err("Couldn't determine initial status rc=%d\n", rc); goto cleanup; } +#endif rc = smb5_request_interrupts(chip); if (rc < 0) { @@ -3747,6 +4074,19 @@ static int smb5_probe(struct platform_device *pdev) device_init_wakeup(chg->dev, true); +#if defined(CONFIG_TCT_PM7250_COMMON) + rc = smb5_determine_initial_status(chip); + if (rc < 0) { + pr_err("Couldn't determine initial status rc=%d\n", + rc); + goto free_irq; + } +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) + recheck_unknown_typec(chg); +#endif + pr_info("QPNP SMB5 probed successfully\n"); return rc; diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 513b49c0a31f032d5347365a46c4be361cfa8f33..32cea7783ff988c540cb63d047766292c6df435e 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -1045,9 +1045,17 @@ static int div2_cp_master_get_prop(struct power_supply *psy, chip->div2_cp_disable_votable); break; case POWER_SUPPLY_PROP_CP_SWITCHER_EN: +#if defined(CONFIG_TCT_PM7250_COMMON) rc = smb1398_get_enable_status(chip); if (!rc) val->intval = chip->switcher_en; + else + val->intval = 0; +#else + rc = smb1398_get_enable_status(chip); + if (!rc) + val->intval = chip->switcher_en; +#endif break; case POWER_SUPPLY_PROP_CP_ISNS: rc = smb1398_div2_cp_get_master_isns(chip, &isns_ua); @@ -1112,6 +1120,10 @@ static int div2_cp_master_get_prop(struct power_supply *psy, rc = -EINVAL; break; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (rc < 0) + rc = -ENODATA; +#endif return rc; } @@ -1406,16 +1418,29 @@ static int smb1398_div2_cp_ilim_vote_cb(struct votable *votable, min_ilim_ua = smb1398_div2_cp_get_min_icl(chip); +#if !defined(CONFIG_TCT_PM7250_COMMON) ilim_ua = (ilim_ua * DIV2_ILIM_CFG_PCT) / 100; - max_ilim_ua = is_cps_available(chip) ? DIV2_MAX_ILIM_DUAL_CP_UA : DIV2_MAX_ILIM_UA; ilim_ua = min(ilim_ua, max_ilim_ua); +#endif +#if defined(CONFIG_TCT_PM7250_COMMON) + if (ilim_ua <= min_ilim_ua) { +#else if (ilim_ua < min_ilim_ua) { - dev_dbg(chip->dev, "ilim %duA is too low to config CP charging\n", +#endif + dev_err(chip->dev, "ilim %duA is too low to config CP charging\n", ilim_ua); vote(chip->div2_cp_disable_votable, ILIM_VOTER, true, 0); } else { +#if defined(CONFIG_TCT_PM7250_COMMON) + ilim_ua = (ilim_ua * DIV2_ILIM_CFG_PCT) / 100; + + max_ilim_ua = is_cps_available(chip) ? + DIV2_MAX_ILIM_DUAL_CP_UA : DIV2_MAX_ILIM_UA; + ilim_ua = min(ilim_ua, max_ilim_ua); + +#endif if (is_cps_available(chip)) { split_ilim = true; slave_dis = ilim_ua < (2 * min_ilim_ua); @@ -1705,9 +1730,13 @@ static void smb1398_status_change_work(struct work_struct *work) * valid due to the battery discharging later, remove * vote from CUTOFF_SOC_VOTER. */ +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chip->div2_cp_disable_votable, CUTOFF_SOC_VOTER, + is_cutoff_soc_reached(chip), 0); +#else if (!is_cutoff_soc_reached(chip)) vote(chip->div2_cp_disable_votable, CUTOFF_SOC_VOTER, false, 0); - +#endif rc = power_supply_get_property(chip->usb_psy, POWER_SUPPLY_PROP_PRESENT, &pval); if (rc < 0) { @@ -1827,6 +1856,11 @@ static void smb1398_status_change_work(struct work_struct *work) queue_work(system_long_wq, &chip->taper_work); } } + +#if defined(CONFIG_TCT_PM7250_COMMON) + rerun_election(chip->div2_cp_ilim_votable); +#endif + out: pm_relax(chip->dev); chip->status_change_running = false; @@ -1850,7 +1884,12 @@ static int smb1398_notifier_cb(struct notifier_block *nb, if (!chip->status_change_running) { chip->status_change_running = true; pm_stay_awake(chip->dev); + +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_work(private_chg_wq, &chip->status_change_work); +#else schedule_work(&chip->status_change_work); +#endif } spin_unlock_irqrestore(&chip->status_change_lock, flags); } @@ -2052,9 +2091,15 @@ static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + /* Configure window (Vin/2 - Vout) UV level to 20mV */ + rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, + DIV2_WIN_UV_SEL_BIT, DIV2_WIN_UV_SEL_BIT); +#else /* Configure window (Vin/2 - Vout) UV level to 10mV */ rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG, DIV2_WIN_UV_SEL_BIT, 0); +#endif if (rc < 0) { dev_err(chip->dev, "Couldn't set WIN_UV_10_MV rc=%d\n", rc); return rc; @@ -2718,6 +2763,12 @@ static int smb1398_probe(struct platform_device *pdev) struct smb1398_chip *chip; int rc = 0; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!power_supply_get_by_name("usb")) { + pr_err("Could not get USB power_supply, deferring smb1398 probe\n"); + return -EPROBE_DEFER; + } +#endif chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -2797,6 +2848,12 @@ static int smb1398_resume(struct device *dev) chip->in_suspend = false; +#if defined(CONFIG_TCT_PM7250_COMMON) + if(get_effective_result(chip->div2_cp_disable_votable)) { + return 0; + } +#endif + if (chip->div2_cp_role == DIV2_CP_MASTER) { rerun_election(chip->div2_cp_ilim_votable); rerun_election(chip->div2_cp_disable_votable); diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 086f2d9229e036ee62fa1e20142504ff2945f504..eeb33bd982c2c10f05f2d11efb6134315339db7e 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -3,6 +3,10 @@ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. */ +#if defined(CONFIG_TCT_PM7250_COMMON) +#define pr_fmt(fmt) "[SMBLIB5]: " fmt +#endif + #include #include #include @@ -21,6 +25,20 @@ #include "storm-watch.h" #include "schgm-flash.h" +#if defined(CONFIG_TCT_PM7250_COMMON) +#define smblib_err(chg, fmt, ...) \ + pr_err_ratelimited("%s: " fmt, \ + __func__, ##__VA_ARGS__) +#define smblib_dbg(chg, reason, fmt, ...) \ + do { \ + if (*chg->debug_mask & (reason)) \ + pr_err_ratelimited("%s: " fmt, \ + __func__, ##__VA_ARGS__); \ + else \ + pr_debug_ratelimited("%s: " fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) +#else #define smblib_err(chg, fmt, ...) \ pr_err("%s: %s: " fmt, chg->name, \ __func__, ##__VA_ARGS__) \ @@ -34,6 +52,7 @@ pr_debug("%s: %s: " fmt, chg->name, \ __func__, ##__VA_ARGS__); \ } while (0) +#endif #define typec_rp_med_high(chg, typec_mode) \ ((typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM \ @@ -174,7 +193,11 @@ int smblib_icl_override(struct smb_charger *chg, enum icl_override_mode mode) break; case SW_OVERRIDE_HC_MODE: usb51_mode = USBIN_MODE_CHG_BIT; +#if defined(CONFIG_TCT_PM7250_COMMON) + icl_override = ICL_OVERRIDE_BIT; +#else icl_override = 0; +#endif apsd_override = ICL_OVERRIDE_AFTER_APSD_BIT; break; case HW_AUTO_MODE: @@ -323,7 +346,12 @@ static void smblib_notify_extcon_props(struct smb_charger *chg, int id) val.intval = ((prop_val.intval == 2) ? 1 : 0); extcon_set_property(chg->extcon, id, EXTCON_PROP_USB_TYPEC_POLARITY, val); +//support USB3.0 +#if 0//defined(CONFIG_TCT_PM7250_COMMON) + val.intval = false; +#else val.intval = true; +#endif extcon_set_property(chg->extcon, id, EXTCON_PROP_USB_SS, val); } else if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { @@ -926,8 +954,13 @@ int smblib_get_qc3_main_icl_offset(struct smb_charger *chg, int *offset_ua) return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!pval.intval) + return -ENXIO; +#else if (!pval.intval) return -EINVAL; +#endif rc = power_supply_get_property(chg->cp_psy, POWER_SUPPLY_PROP_CP_ILIM, &pval); @@ -982,8 +1015,14 @@ void smblib_hvdcp_detect_enable(struct smb_charger *chg, bool enable) static void smblib_hvdcp_detect_try_enable(struct smb_charger *chg, bool enable) { +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->hvdcp_disable) + return; +#else if (chg->hvdcp_disable || chg->pd_not_supported) return; +#endif + smblib_hvdcp_detect_enable(chg, enable); } @@ -1115,11 +1154,21 @@ static int smblib_notifier_call(struct notifier_block *nb, if (!chg->bms_psy) chg->bms_psy = psy; if (ev == PSY_EVENT_PROP_CHANGED) +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_work(private_chg_wq, &chg->bms_update_work); +#else schedule_work(&chg->bms_update_work); +#endif } +#if defined(CONFIG_TCT_PM7250_COMMON) + if ((!chg->sw_jeita_enabled) && + (chg->jeita_configured == JEITA_CFG_NONE)) + schedule_work(&chg->jeita_update_work); +#else if (chg->jeita_configured == JEITA_CFG_NONE) schedule_work(&chg->jeita_update_work); +#endif if (chg->sec_pl_present && !chg->pl.psy && !strcmp(psy->desc->name, "parallel")) { @@ -1230,6 +1279,9 @@ static void smblib_uusb_removal(struct smb_charger *chg) vote(chg->usb_icl_votable, SW_THERM_REGULATION_VOTER, false, 0); vote(chg->pl_disable_votable, SW_THERM_REGULATION_VOTER, false, 0); vote(chg->dc_suspend_votable, SW_THERM_REGULATION_VOTER, false, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->apsd_rerun_done = false; +#endif if (chg->cp_disable_votable) vote(chg->cp_disable_votable, SW_THERM_REGULATION_VOTER, false, 0); @@ -1280,14 +1332,25 @@ static void smblib_uusb_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't restore max pulses rc=%d\n", rc); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->disable_suspend_on_collapse) { + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT, + SUSPEND_ON_COLLAPSE_USBIN_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", + rc); + } + chg->qc2_unsupported_voltage = QC2_NON_COMPLIANT_12V; +#else rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, SUSPEND_ON_COLLAPSE_USBIN_BIT, SUSPEND_ON_COLLAPSE_USBIN_BIT); if (rc < 0) smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", rc); - chg->qc2_unsupported_voltage = QC2_COMPLIANT; +#endif } chg->qc3p5_detected = false; @@ -1434,15 +1497,22 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto set_mode; /* configure current */ +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) { +#else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB && (chg->typec_legacy || chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) { +#endif rc = set_sdp_current(chg, icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc); goto out; } +#if defined(CONFIG_TCT_PM7250_COMMON) + icl_override = SW_OVERRIDE_USB51_MODE; +#endif } else { /* * Try USB 2.0/3,0 option first on USB path when maximum input @@ -1912,9 +1982,22 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev) int smblib_get_prop_input_suspend(struct smb_charger *chg, union power_supply_propval *val) { +#if defined(CONFIG_TCT_PM7250_COMMON) + int rc = 0; + u8 stat=0; + + rc = smblib_read(chg, USBIN_CMD_IL_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read USBIN_CMD_IL rc=%d\n", rc); + val->intval = 0; + return rc; + } + val->intval = (bool)(stat & USBIN_SUSPEND_BIT); +#else val->intval = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0) && get_client_vote(chg->dc_suspend_votable, USER_VOTER); +#endif return 0; } @@ -1972,7 +2055,11 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, union power_supply_propval pval = {0, }; bool usb_online, dc_online; u8 stat; +#if defined(CONFIG_TCT_PM7250_COMMON) + int rc, suspend = 0; +#else int rc, suspend = 0, input_present = 0; +#endif if (chg->fake_chg_status_on_debug_batt) { rc = smblib_get_prop_from_bms(chg, @@ -1986,6 +2073,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, } } +#if !defined(CONFIG_TCT_PM7250_COMMON) rc = smblib_get_prop_batt_health(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't get batt health rc=%d\n", rc); @@ -2001,7 +2089,9 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; return 0; } +#endif +#if !defined(CONFIG_TCT_PM7250_COMMON) /* * If SOC = 0 and we are discharging with input connected, report * the battery status as DISCHARGING. @@ -2023,6 +2113,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, } else { chg->cutoff_count = 0; } +#endif if (chg->dbc_usbov) { rc = smblib_get_prop_usb_present(chg, &pval); @@ -2159,6 +2250,21 @@ int smblib_get_prop_batt_charge_type(struct smb_charger *chg, return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + switch (stat & BATTERY_CHARGER_STATUS_MASK) { + case TRICKLE_CHARGE: + case PRE_CHARGE: + val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case FULLON_CHARGE: + case TAPER_CHARGE: + val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + default: + val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + } +#else switch (stat & BATTERY_CHARGER_STATUS_MASK) { case TRICKLE_CHARGE: case PRE_CHARGE: @@ -2173,6 +2279,7 @@ int smblib_get_prop_batt_charge_type(struct smb_charger *chg, default: val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; } +#endif return rc; } @@ -2194,6 +2301,14 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, smblib_dbg(chg, PR_REGISTER, "BATTERY_CHARGER_STATUS_2 = 0x%02x\n", stat); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (stat & CHARGER_ERROR_STATUS_SFT_EXPIRE_BIT) { + val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; + smblib_err(chg, "safety timer expired: 0x%02x\n", stat); + return 0; + } +#endif + if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); @@ -2230,6 +2345,29 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, else val->intval = POWER_SUPPLY_HEALTH_GOOD; +#if defined(CONFIG_TCT_PM7250_COMMON) +#define JEITA_HARD_COLD_TEMP (50) +#define JEITA_SOFT_COLD_TEMP (100) +#define JEITA_SOFT_HOT_TEMP (450) +#define JEITA_HARD_HOT_TEMP (550) + + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_TEMP, &pval); + if (!rc) { + + if (pval.intval < JEITA_HARD_COLD_TEMP) + val->intval = POWER_SUPPLY_HEALTH_COLD; + else if (pval.intval < JEITA_SOFT_COLD_TEMP) + val->intval = POWER_SUPPLY_HEALTH_COOL; + else if (pval.intval < JEITA_SOFT_HOT_TEMP) + val->intval = POWER_SUPPLY_HEALTH_GOOD; + else if (pval.intval < JEITA_HARD_HOT_TEMP) + val->intval = POWER_SUPPLY_HEALTH_WARM; + else + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + } +#endif + done: return rc; } @@ -2397,6 +2535,46 @@ int smblib_set_prop_batt_status(struct smb_charger *chg, return 0; } + +#if defined(CONFIG_TCT_PM7250_COMMON) +extern bool g_lcd_on; +int smblib_set_prop_system_temp_level(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int *thermal_array = NULL; + /* MODIFIED-END by jin.wang,BUG-9172506*/ + + if (val->intval < 0) + return -EINVAL; + + if (chg->thermal_levels <= 0) + return -EINVAL; + + if (val->intval > chg->thermal_levels) + return -EINVAL; + + /* MODIFIED-BEGIN by jin.wang, 2020-04-07,BUG-9172506*/ + /* 1: LCD on ; 0: LCD off */ + thermal_array = g_lcd_on ? + chg->thermal_mitigation_lcdon : + chg->thermal_mitigation; + + pr_err("[%d]level: %d -> %d\n", g_lcd_on, + chg->system_temp_level, val->intval); + + chg->system_temp_level = val->intval; + if (chg->system_temp_level == chg->thermal_levels) + return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, + thermal_array[chg->thermal_levels-1]); + + if (chg->system_temp_level == 0) + return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0); + + vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, + thermal_array[chg->system_temp_level]); + return 0; +} +#else int smblib_set_prop_system_temp_level(struct smb_charger *chg, const union power_supply_propval *val) { @@ -2423,6 +2601,7 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, chg->thermal_mitigation[chg->system_temp_level]); return 0; } +#endif // MODIFIED by jin.wang, 2020-04-07,BUG-9172506 int smblib_set_prop_input_current_limited(struct smb_charger *chg, const union power_supply_propval *val) @@ -2541,6 +2720,11 @@ static void smblib_hvdcp_set_fsw(struct smb_charger *chg, int bit) #define QC3_PULSES_FOR_6V 5 #define QC3_PULSES_FOR_9V 20 #define QC3_PULSES_FOR_12V 35 +#if defined(CONFIG_TCT_PM7250_COMMON) +#define QC3P5_PULSES_FOR_6V 50 +#define QC3P5_PULSES_FOR_9V 200 +#define QC3P5_PULSES_FOR_12V 350 +#endif static int smblib_hvdcp3_set_fsw(struct smb_charger *chg) { int pulse_count, rc; @@ -2551,6 +2735,25 @@ static int smblib_hvdcp3_set_fsw(struct smb_charger *chg) return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3P5) { + if (pulse_count < QC3P5_PULSES_FOR_6V) + smblib_set_opt_switcher_freq(chg, + chg->chg_freq.freq_5V); + else if (pulse_count < QC3P5_PULSES_FOR_9V) + smblib_set_opt_switcher_freq(chg, + chg->chg_freq.freq_6V_8V); + else if (pulse_count < QC3P5_PULSES_FOR_12V) + smblib_set_opt_switcher_freq(chg, + chg->chg_freq.freq_9V); + else + smblib_set_opt_switcher_freq(chg, + chg->chg_freq.freq_12V); + return 0; + } +#endif + + if (pulse_count < QC3_PULSES_FOR_6V) smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_5V); @@ -2602,6 +2805,21 @@ int smblib_dp_dm(struct smb_charger *chg, int val) switch (val) { case POWER_SUPPLY_DP_DM_DP_PULSE: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3P5) { + if (QC3P5_PULSES_FOR_12V <= chg->pulse_cnt) { + smblib_err(chg, "QC3.5 pulse_cnt %d too large, skipped\n", + chg->pulse_cnt); + rc = -EINVAL; + break; + } + } else if (QC3_PULSES_FOR_12V <= chg->pulse_cnt) { + smblib_err(chg, "QC3.0 pulse_cnt %d too large, skipped\n", + chg->pulse_cnt); + rc = -EINVAL; + break; + } +#endif /* * Pre-emptively increment pulse count to enable the setting * of FSW prior to increasing voltage. @@ -2627,9 +2845,23 @@ int smblib_dp_dm(struct smb_charger *chg, int val) rc, chg->pulse_cnt); break; case POWER_SUPPLY_DP_DM_DM_PULSE: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->pulse_cnt <= 0) { + smblib_dbg(chg, PR_INTERRUPT, "pulse_cnt(%d), skip down\n", + chg->pulse_cnt); + return -EINVAL; + } +#endif rc = smblib_dm_pulse(chg); if (!rc && chg->pulse_cnt) chg->pulse_cnt--; + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (smblib_hvdcp3_set_fsw(chg) < 0) { + smblib_err(chg, "dm:Couldn't set QC3.0 Fsw\n"); + } +#endif + smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n", rc, chg->pulse_cnt); break; @@ -2664,6 +2896,10 @@ int smblib_dp_dm(struct smb_charger *chg, int val) target_icl_ua, chg->usb_icl_delta_ua); break; case POWER_SUPPLY_DP_DM_FORCE_5V: +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->pulse_cnt = 0; + smblib_hvdcp_set_fsw(chg, QC_5V_BIT); +#endif rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT); if (rc < 0) pr_err("Failed to force 5V\n"); @@ -2789,7 +3025,11 @@ static int smblib_set_sw_thermal_regulation(struct smb_charger *chg, SW_THERM_REGULATION_VOTER)) { vote(chg->awake_votable, SW_THERM_REGULATION_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->thermal_regulation_work, 0); +#else schedule_delayed_work(&chg->thermal_regulation_work, 0); +#endif } } else { cancel_delayed_work_sync(&chg->thermal_regulation_work); @@ -2836,8 +3076,13 @@ static int smblib_update_thermal_readings(struct smb_charger *chg) rc = power_supply_get_property(chg->cp_psy, POWER_SUPPLY_PROP_CP_DIE_TEMP, &pval); if (rc < 0) { +#if defined(CONFIG_TCT_PM7250_COMMON) + smblib_dbg(chg, PR_MISC, "Couldn't get smb charger temp, rc=%d\n", + rc); +#else smblib_err(chg, "Couldn't get smb1390 charger temp, rc=%d\n", rc); +#endif return rc; } chg->smb_temp = pval.intval; @@ -2867,9 +3112,9 @@ static int smblib_update_thermal_readings(struct smb_charger *chg) #define DIE_TEMP_REG_H_THRESH 800 #define DIE_TEMP_REG_L_THRESH 600 -#define CONNECTOR_TEMP_SHDN_THRESH 700 -#define CONNECTOR_TEMP_RST_THRESH 600 -#define CONNECTOR_TEMP_REG_H_THRESH 550 +#define CONNECTOR_TEMP_SHDN_THRESH 900 +#define CONNECTOR_TEMP_RST_THRESH 850 +#define CONNECTOR_TEMP_REG_H_THRESH 800 #define CONNECTOR_TEMP_REG_L_THRESH 500 #define SMB_TEMP_SHDN_THRESH 1400 @@ -2937,7 +3182,11 @@ static int smblib_process_thermal_readings(struct smb_charger *chg) chg->smb_temp > SMB_TEMP_REG_H_THRESH || chg->die_temp > DIE_TEMP_REG_H_THRESH) { thermal_status = TEMP_ABOVE_RANGE; +#if defined(CONFIG_TCT_PM7250_COMMON) + wdog_timeout = SNARL_WDOG_TMOUT_8S; +#else wdog_timeout = SNARL_WDOG_TMOUT_1S; +#endif goto out; } @@ -3004,8 +3253,13 @@ static int smblib_process_thermal_readings(struct smb_charger *chg) */ if (is_client_vote_enabled(chg->usb_icl_votable, SW_THERM_REGULATION_VOTER)) { +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->thermal_regulation_work, + msecs_to_jiffies(THERM_REG_RECHECK_DELAY_1S)); +#else schedule_delayed_work(&chg->thermal_regulation_work, msecs_to_jiffies(THERM_REG_RECHECK_DELAY_1S)); +#endif return 0; } @@ -3289,6 +3543,15 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc); + return rc; + } + val->intval = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); + return 0; +#else rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", @@ -3301,6 +3564,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, val->intval = (stat & USE_USBIN_BIT) && (stat & VALID_INPUT_POWER_SOURCE_STS_BIT); return rc; +#endif } int smblib_get_usb_online(struct smb_charger *chg, @@ -3312,9 +3576,13 @@ int smblib_get_usb_online(struct smb_charger *chg, if (!val->intval) goto exit; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) +#else if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) +#endif val->intval = 0; else val->intval = 1; @@ -3397,7 +3665,11 @@ static int smblib_estimate_adaptor_voltage(struct smb_charger *chg, switch (chg->real_charger_type) { case POWER_SUPPLY_TYPE_USB_HVDCP: +#if defined(CONFIG_TCT_PM7250_COMMON) + val->intval = MICRO_9V; +#else val->intval = MICRO_12V; +#endif break; case POWER_SUPPLY_TYPE_USB_HVDCP_3P5: step_uv = HVDCP3P5_STEP_UV; @@ -3499,6 +3771,9 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, * OTG mode. */ if (!pval.intval) { +#if defined(CONFIG_TCT_PM7250_COMMON) + val->intval = 0; +#endif rc = smblib_read(chg, DCDC_CMD_OTG_REG, ®); if (rc < 0) { smblib_err(chg, "Couldn't read CMD_OTG rc=%d", rc); @@ -3679,6 +3954,9 @@ static const char * const smblib_typec_mode_name[] = { [POWER_SUPPLY_TYPEC_SOURCE_DEFAULT] = "SOURCE_DEFAULT", [POWER_SUPPLY_TYPEC_SOURCE_MEDIUM] = "SOURCE_MEDIUM", [POWER_SUPPLY_TYPEC_SOURCE_HIGH] = "SOURCE_HIGH", +#if defined(CONFIG_TCT_PM7250_COMMON) + [POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY] = "SOURCE_DEBUG_ACCESSORY", +#endif [POWER_SUPPLY_TYPEC_NON_COMPLIANT] = "NON_COMPLIANT", [POWER_SUPPLY_TYPEC_SINK] = "SINK", [POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE] = "SINK_POWERED_CABLE", @@ -3699,19 +3977,33 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg) } smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat); + /* config 0x154A to 0x17 */ + if (stat &(SNK_RP_STD_DAM_BIT | SNK_RP_1P5_DAM_BIT | SNK_RP_3P0_DAM_BIT)){ + smblib_masked_write(chg, TYPE_C_DEBUG_ACCESS_SINK_REG,TYPEC_DEBUG_ACCESS_SINK_MASK,0x17); + } + switch (stat & DETECTED_SRC_TYPE_MASK) { case SNK_RP_STD_BIT: + case SNK_RP_STD_DAM_BIT: return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; case SNK_RP_1P5_BIT: + case SNK_RP_1P5_DAM_BIT: return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM; case SNK_RP_3P0_BIT: + case SNK_RP_3P0_DAM_BIT: return POWER_SUPPLY_TYPEC_SOURCE_HIGH; case SNK_RP_SHORT_BIT: return POWER_SUPPLY_TYPEC_NON_COMPLIANT; +/* case SNK_DAM_500MA_BIT: case SNK_DAM_1500MA_BIT: case SNK_DAM_3000MA_BIT: +#if defined(CONFIG_TCT_PM7250_COMMON) + return POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY; +#else return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY; +#endif +*/ default: break; } @@ -3834,8 +4126,13 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, static inline bool typec_in_src_mode(struct smb_charger *chg) { +#if defined(CONFIG_TCT_PM7250_COMMON) + return (chg->typec_mode > POWER_SUPPLY_TYPEC_NONE && + chg->typec_mode < POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY); +#else return (chg->typec_mode > POWER_SUPPLY_TYPEC_NONE && chg->typec_mode < POWER_SUPPLY_TYPEC_SOURCE_DEFAULT); +#endif } int smblib_get_prop_typec_select_rp(struct smb_charger *chg, @@ -3969,11 +4266,22 @@ int smblib_get_prop_input_current_max(struct smb_charger *chg, if (rc < 0) return rc; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (((chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) + || (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) + || (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_PD) + || (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3P5)) + && (icl_ua < HW_ICL_MAX)) { + val->intval = HW_ICL_MAX; + return 0; + } +#else if (is_override_vote_enabled_locked(chg->usb_icl_votable) && icl_ua < USBIN_1000MA) { val->intval = USBIN_1000MA; return 0; } +#endif return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval); } @@ -4224,6 +4532,7 @@ int smblib_get_prop_connector_health(struct smb_charger *chg) return POWER_SUPPLY_HEALTH_COOL; } +#if !defined(CONFIG_TCT_PM7250_COMMON) static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode) { int rp_ua; @@ -4241,6 +4550,7 @@ static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode) return rp_ua; } +#endif /******************* * USB PSY SETTERS * @@ -4266,7 +4576,11 @@ int smblib_set_prop_pd_current_max(struct smb_charger *chg, static int smblib_handle_usb_current(struct smb_charger *chg, int usb_current) { +#if defined(CONFIG_TCT_PM7250_COMMON) + int rc = 0; +#else int rc = 0, rp_ua, typec_mode; +#endif union power_supply_propval val = {0, }; if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) { @@ -4286,6 +4600,12 @@ static int smblib_handle_usb_current(struct smb_charger *chg, return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + rc = vote(chg->usb_icl_votable, + SW_ICL_MAX_VOTER, true, USBIN_500MA); + if (rc < 0) + return rc; +#else if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) { /* @@ -4305,6 +4625,7 @@ static int smblib_handle_usb_current(struct smb_charger *chg, if (rc < 0) return rc; } +#endif } else { /* * FLOAT charger detected as SDP by USB driver, @@ -4312,6 +4633,12 @@ static int smblib_handle_usb_current(struct smb_charger *chg, * real_charger_type */ chg->real_charger_type = POWER_SUPPLY_TYPE_USB; + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (usb_current < SDP_CURRENT_UA) + usb_current = SDP_CURRENT_UA; +#endif + rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, true, usb_current); if (rc < 0) @@ -4475,10 +4802,15 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, if (typec_mode >= POWER_SUPPLY_TYPEC_SINK && typec_mode <= POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) snk_attached = true; +#if defined(CONFIG_TCT_PM7250_COMMON) + else if (typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY && + typec_mode <= POWER_SUPPLY_TYPEC_SOURCE_HIGH) + src_attached = true; +#else else if (typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEFAULT && typec_mode <= POWER_SUPPLY_TYPEC_SOURCE_HIGH) src_attached = true; - +#endif /* * If current power role is in DRP, and type-c is already in the * mode (source or sink) that's being requested, it means this is @@ -4623,7 +4955,11 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, const struct apsd_result *apsd = smblib_get_apsd_result(chg); int rc = 0; +#if defined(CONFIG_TCT_PM7250_COMMON) + int sec_charger; +#else int sec_charger, typec_mode; +#endif /* * Ignore repetitive notification while PD is active, which @@ -4696,9 +5032,13 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB && !chg->ok_to_pd) { +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, SDP_CURRENT_UA); +#else typec_mode = smblib_get_prop_typec_mode(chg); if (typec_rp_med_high(chg, typec_mode)) vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); +#endif } power_supply_changed(chg->usb_psy); @@ -4933,10 +5273,20 @@ int smblib_get_charge_current(struct smb_charger *chg, typec_source_rd = smblib_get_prop_ufp_mode(chg); /* QC 2.0/3.0 adapter */ +#if defined(CONFIG_TCT_PM7250_COMMON) + if (apsd_result->bit & (QC_3P0_BIT)) { + *total_current_ua = QC3_ICL_MAX; + return 0; + } else if (apsd_result->bit & (QC_2P0_BIT)) { + *total_current_ua = QC2_ICL_MAX; + return 0; + } +#else if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) { *total_current_ua = HVDCP_CURRENT_UA; return 0; } +#endif if (non_compliant && !chg->typec_legacy_use_rp_icl) { switch (apsd_result->bit) { @@ -4945,12 +5295,21 @@ int smblib_get_charge_current(struct smb_charger *chg, break; case DCP_CHARGER_BIT: case OCP_CHARGER_BIT: +#if defined(CONFIG_TCT_PM7250_COMMON) + current_ua = DCP_CURRENT_UA; + break; + case FLOAT_CHARGER_BIT: + default: + current_ua = SDP_CURRENT_UA; + break; +#else case FLOAT_CHARGER_BIT: current_ua = DCP_CURRENT_UA; break; default: current_ua = 0; break; +#endif } *total_current_ua = max(current_ua, val.intval); @@ -4958,6 +5317,9 @@ int smblib_get_charge_current(struct smb_charger *chg, } switch (typec_source_rd) { +#if defined(CONFIG_TCT_PM7250_COMMON) + case POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY: +#endif case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: switch (apsd_result->bit) { case CDP_CHARGER_BIT: @@ -4965,19 +5327,60 @@ int smblib_get_charge_current(struct smb_charger *chg, break; case DCP_CHARGER_BIT: case OCP_CHARGER_BIT: +#if defined(CONFIG_TCT_PM7250_COMMON) + current_ua = DCP_CURRENT_UA; + break; + case FLOAT_CHARGER_BIT: + default: + current_ua = SDP_CURRENT_UA; + break; +#else case FLOAT_CHARGER_BIT: current_ua = chg->default_icl_ua; break; default: current_ua = 0; break; +#endif } break; case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: +#if defined(CONFIG_TCT_PM7250_COMMON) + switch (apsd_result->bit) { + case CDP_CHARGER_BIT: + current_ua = CDP_CURRENT_UA; + break; + case DCP_CHARGER_BIT: + case OCP_CHARGER_BIT: + current_ua = DCP_CURRENT_UA; + break; + case FLOAT_CHARGER_BIT: + default: + current_ua = SDP_CURRENT_UA; + break; + } +#else current_ua = TYPEC_MEDIUM_CURRENT_UA; +#endif break; case POWER_SUPPLY_TYPEC_SOURCE_HIGH: +#if defined(CONFIG_TCT_PM7250_COMMON) + switch (apsd_result->bit) { + case CDP_CHARGER_BIT: + current_ua = CDP_CURRENT_UA; + break; + case DCP_CHARGER_BIT: + case OCP_CHARGER_BIT: + current_ua = DCP_CURRENT_UA; + break; + case FLOAT_CHARGER_BIT: + default: + current_ua = SDP_CURRENT_UA; + break; + } +#else current_ua = TYPEC_HIGH_CURRENT_UA; +#endif break; case POWER_SUPPLY_TYPEC_NON_COMPLIANT: case POWER_SUPPLY_TYPEC_NONE: @@ -5154,6 +5557,15 @@ irqreturn_t batt_temp_changed_irq_handler(int irq, void *data) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->sw_jeita_enabled) { + if (chg->batt_psy) + power_supply_changed(chg->batt_psy); + + return IRQ_HANDLED; + } +#endif + if (chg->jeita_configured != JEITA_CFG_COMPLETE) return IRQ_HANDLED; @@ -5253,15 +5665,29 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) reset_storm_count(wdata); } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->wa_flags & BOOST_BACK_WA) { + if (!chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data) + return IRQ_HANDLED; + + wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data; + reset_storm_count(wdata); + } +#else if (!chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data) return IRQ_HANDLED; wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data; reset_storm_count(wdata); +#endif /* Workaround for non-QC2.0-compliant chargers follows */ +#if defined(CONFIG_TCT_PM7250_COMMON) + if (apsd->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { +#else if (!chg->qc2_unsupported_voltage && apsd->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { +#endif rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); if (rc < 0) smblib_err(chg, @@ -5298,21 +5724,41 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->disable_suspend_on_collapse) { + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT, + 0); + if (rc < 0) + smblib_err(chg, "Couldn't turn off SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", + rc); + } +#else rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, SUSPEND_ON_COLLAPSE_USBIN_BIT, 0); if (rc < 0) smblib_err(chg, "Couldn't turn off SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", rc); +#endif smblib_rerun_apsd(chg); + +#if defined(CONFIG_TCT_PM7250_COMMON) + smblib_run_aicl(chg, RERUN_AICL_BIT); +#endif } return IRQ_HANDLED; } #define USB_WEAK_INPUT_UA 1400000 + +#if defined(CONFIG_TCT_PM7250_COMMON) +#define ICL_CHANGE_DELAY_MS 3000 +#else #define ICL_CHANGE_DELAY_MS 1000 +#endif irqreturn_t icl_change_irq_handler(int irq, void *data) { u8 stat; @@ -5353,13 +5799,20 @@ irqreturn_t icl_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } +#if !defined(CONFIG_TCT_PM7250_COMMON) /* If AICL settled then schedule work now */ if (settled_ua == get_effective_result(chg->usb_icl_votable)) delay = 0; +#endif cancel_delayed_work_sync(&chg->icl_change_work); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->icl_change_work, + msecs_to_jiffies(delay)); +#else schedule_delayed_work(&chg->icl_change_work, msecs_to_jiffies(delay)); +#endif } return IRQ_HANDLED; @@ -5543,6 +5996,15 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) if (vbus_rising) { cancel_delayed_work_sync(&chg->pr_swap_detach_work); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->disable_suspend_on_collapse) { + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT, 0); + if (rc < 0) + smblib_err(chg, "Couldn't turn off SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", + rc); + } +#endif vote(chg->awake_votable, DETACH_DETECT_VOTER, false, 0); rc = smblib_request_dpdm(chg, true); if (rc < 0) @@ -5558,10 +6020,12 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) if (chg->fcc_stepper_enable) vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0); +#if !defined(CONFIG_TCT_PM7250_COMMON) /* Schedule work to enable parallel charger */ vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); schedule_delayed_work(&chg->pl_enable_work, msecs_to_jiffies(PL_DELAY_MS)); +#endif } else { /* Disable SW Thermal Regulation */ rc = smblib_set_sw_thermal_regulation(chg, false); @@ -5618,18 +6082,58 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN; +#else smblib_update_usb_type(chg); +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0); + vote(chg->pl_disable_votable, PL_FCC_LOW_VOTER, false, 0); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); + vote(chg->fcc_main_votable, MAIN_FCC_VOTER, false, 0); + chg->adapter_cc_mode = 0; + chg->thermal_overheat = 0; + chg->pd_active = 0; + vote_override(chg->fcc_main_votable, CC_MODE_VOTER, false, 0); + vote_override(chg->usb_icl_votable, CC_MODE_VOTER, false, 0); + vote(chg->cp_disable_votable, OVERHEAT_LIMIT_VOTER, false, 0); + vote(chg->usb_icl_votable, OVERHEAT_LIMIT_VOTER, false, 0); + if (chg->disable_suspend_on_collapse) { + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT, SUSPEND_ON_COLLAPSE_USBIN_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", + rc); + } + vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); +#endif } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (unlikely(chg->connector_type == + POWER_SUPPLY_CONNECTOR_MICRO_USB)) { + smblib_micro_usb_plugin(chg, vbus_rising); + } else if (!vbus_rising) { + smblib_notify_device_mode(chg, false); + } +#else if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) smblib_micro_usb_plugin(chg, vbus_rising); +#endif vote(chg->temp_change_irq_disable_votable, DEFAULT_VOTER, !vbus_rising, 0); power_supply_changed(chg->usb_psy); +#if defined(CONFIG_TCT_PM7250_COMMON) + smblib_err(chg, "IRQ: usbin-plugin %s\n", + vbus_rising ? "attached" : "detached"); +#else smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n", vbus_rising ? "attached" : "detached"); +#endif } irqreturn_t usb_plugin_irq_handler(int irq, void *data) @@ -5645,6 +6149,7 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data) return IRQ_HANDLED; } +#if !defined(CONFIG_TCT_PM7250_COMMON) static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg, bool rising) { @@ -5658,6 +6163,7 @@ static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg, smblib_dbg(chg, PR_INTERRUPT, "IRQ: sdp-enumeration-done %s\n", rising ? "rising" : "falling"); } +#endif #define APSD_EXTENDED_TIMEOUT_MS 400 /* triggers when HVDCP 3.0 authentication has finished */ @@ -5677,6 +6183,10 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, apsd_result = smblib_get_apsd_result(chg); if (apsd_result->bit & QC_3P0_BIT) { +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, + true, QC3_ICL_MAX); +#endif /* for QC3, switch to CP if present */ if (chg->sec_cp_present) { rc = smblib_select_sec_charger(chg, @@ -5722,8 +6232,14 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, CHARGER_TYPE_VOTER, false, 0); vote(chg->hdc_irq_disable_votable, CHARGER_TYPE_VOTER, false, 0); + +#if defined(CONFIG_TCT_PM7250_COMMON) vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - hvdcp_ua); + QC2_ICL_MAX); +#else + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CURRENT_UA); +#endif } else { /* A plain DCP, enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, @@ -5735,6 +6251,7 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, rising ? "rising" : "falling"); } +#if !defined(CONFIG_TCT_PM7250_COMMON) /* triggers when HVDCP is detected */ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, bool rising) @@ -5742,11 +6259,14 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-detect-done %s\n", rising ? "rising" : "falling"); } +#endif static void update_sw_icl_max(struct smb_charger *chg, int pst) { +#if !defined(CONFIG_TCT_PM7250_COMMON) int typec_mode; int rp_ua; +#endif /* while PD is active it should have complete ICL control */ if (chg->pd_active) @@ -5764,6 +6284,7 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) || pst == POWER_SUPPLY_TYPE_USB_HVDCP_3) return; +#if !defined(CONFIG_TCT_PM7250_COMMON) /* TypeC rp med or high, use rp value */ typec_mode = smblib_get_prop_typec_mode(chg); if (typec_rp_med_high(chg, typec_mode)) { @@ -5771,6 +6292,7 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); return; } +#endif /* rp-std or legacy, USB BC 1.2 */ switch (pst) { @@ -5782,9 +6304,14 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) if (!is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER)) { /* if flash is active force 500mA */ +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, + SDP_CURRENT_UA); +#else vote(chg->usb_icl_votable, USB_PSY_VOTER, true, is_flash_active(chg) ? SDP_CURRENT_UA : SDP_100_MA); +#endif } vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); break; @@ -5793,16 +6320,27 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) CDP_CURRENT_UA); break; case POWER_SUPPLY_TYPE_USB_DCP: +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + DCP_CURRENT_UA); + vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); +#else rp_ua = get_rp_based_dcp_current(chg, typec_mode); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); +#endif break; case POWER_SUPPLY_TYPE_USB_FLOAT: /* * limit ICL to 100mA, the USB driver will enumerate to check * if this is a SDP and appropriately set the current */ +#if defined(CONFIG_TCT_PM7250_COMMON) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + SDP_CURRENT_UA); +#else vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); +#endif break; case POWER_SUPPLY_TYPE_UNKNOWN: default: @@ -5815,21 +6353,54 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { const struct apsd_result *apsd_result; +#if defined(CONFIG_TCT_PM7250_COMMON) + int rc; + union power_supply_propval val = {0, }; +#endif if (!rising) return; apsd_result = smblib_update_usb_type(chg); +#if defined(CONFIG_TCT_PM7250_COMMON) + if ((chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) + || (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) + || (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3P5)) { + rc = smblib_get_prop_usb_voltage_now(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't read usbin_v, rc=%d\n", rc); + return; + } + if (val.intval >= 11000000) { + smblib_dbg(chg, PR_MISC, "USBOV: type=%d, v=%duV\n", + chg->real_charger_type, val.intval); + chg->qc3p5_detected = false; + smblib_hvdcp_detect_enable(chg, false); + smblib_rerun_apsd(chg); + smblib_run_aicl(chg, RERUN_AICL_BIT); + return; + } + } +#endif update_sw_icl_max(chg, apsd_result->pst); switch (apsd_result->bit) { case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->use_extcon || + (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY)) { + smblib_notify_device_mode(chg, true); + } + break; + case FLOAT_CHARGER_BIT: +#else case FLOAT_CHARGER_BIT: if (chg->use_extcon) smblib_notify_device_mode(chg, true); break; +#endif case OCP_CHARGER_BIT: case DCP_CHARGER_BIT: break; @@ -5841,6 +6412,75 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) apsd_result->name); } +#if defined(CONFIG_TCT_PM7250_COMMON) +#define PLUGIN_DELAY_MS (60000) +irqreturn_t usb_source_change_irq_handler(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + int rc = 0; + u8 stat; + + /* PD session is ongoing, ignore BC1.2 and QC detection */ + if (chg->pd_active) + goto out2; + + rc = smblib_read(chg, APSD_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc); + goto out2; + } + + /* skip for no necessary actions. */ + if (!(stat & APSD_DTC_STATUS_DONE_BIT) + || (stat & VADP_CHANGE_DONE_AFTER_AUTH_BIT) + || (stat & APSD_STATUS_7_BIT)) { + smblib_dbg(chg, PR_MISC, "skip with 0x%02x\n", stat); + goto out1; + } + + /* if this's the first time detect as float/ocp/unknown type, + we can recheck this type via rerun apsd. */ + if (!chg->apsd_rerun_done) { + const struct apsd_result *first_type = smblib_get_apsd_result(chg); + if ((first_type->bit == FLOAT_CHARGER_BIT) + || (first_type->bit == OCP_CHARGER_BIT) + || (!first_type->bit) + || (stat == 0x21 && first_type->bit == SDP_CHARGER_BIT)) { + smblib_err(chg, "type:'%s', stat:0x%x, rerun apsd now.\n", + first_type->name, stat); + chg->apsd_rerun_done = true; + smblib_rerun_apsd(chg); + goto out2; + } + } + + smblib_err(chg, "IRQ: APSD_STATUS_REG=0x%02x\n", stat); + cancel_delayed_work_sync(&chg->pl_enable_work); + vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); + + smblib_handle_apsd_done(chg, + (bool)(stat & APSD_DTC_STATUS_DONE_BIT)); + + smblib_handle_hvdcp_check_timeout(chg, + (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT), + (bool)(stat & QC_CHARGER_BIT)); + + smblib_handle_hvdcp_3p0_auth_done(chg, + (bool)(stat & QC_AUTH_DONE_STATUS_BIT)); + + queue_delayed_work(private_chg_wq, &chg->pl_enable_work, + msecs_to_jiffies(PLUGIN_DELAY_MS)); + smblib_err(chg, "sleeping with psy:%d\n", + chg->real_charger_type); + +out1: + power_supply_changed(chg->usb_psy); + smblib_hvdcp_adaptive_voltage_change(chg); +out2: + return IRQ_HANDLED; +} +#else irqreturn_t usb_source_change_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; @@ -5903,6 +6543,7 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } +#endif enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, ktime_t time) @@ -6026,6 +6667,9 @@ static void typec_src_insertion(struct smb_charger *chg) { int rc = 0; u8 stat; +#if defined(CONFIG_TCT_PM7250_COMMON) + int typec_mode = POWER_SUPPLY_TYPEC_NONE; +#endif if (chg->pr_swap_in_progress) { vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); @@ -6043,6 +6687,17 @@ static void typec_src_insertion(struct smb_charger *chg) chg->ok_to_pd = (!(chg->typec_legacy || chg->pd_disabled) || chg->early_usb_attach) && !chg->pd_not_supported; +#if defined(CONFIG_TCT_PM7250_COMMON) + typec_mode = smblib_get_prop_ufp_mode(chg); + if (typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY) { + chg->ok_to_pd = false; + } + + pr_err("ok_to_pd=%d {%d,%d,%d,0x%02x}\n", chg->ok_to_pd, + typec_mode, chg->typec_legacy, + chg->early_usb_attach, stat); +#endif + /* allow apsd proceed to detect QC2/3 */ if (!chg->ok_to_pd) smblib_hvdcp_detect_try_enable(chg, true); @@ -6231,7 +6886,13 @@ static void typec_src_removal(struct smb_charger *chg) chg->qc3p5_detected = false; typec_src_fault_condition_cfg(chg, false); smblib_hvdcp_detect_try_enable(chg, false); + +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->pd_active = 0; + chg->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN; +#else smblib_update_usb_type(chg); +#endif if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; @@ -6297,7 +6958,11 @@ static void typec_src_removal(struct smb_charger *chg) vote(chg->fcc_main_votable, MAIN_FCC_VOTER, false, 0); chg->adapter_cc_mode = 0; chg->thermal_overheat = 0; +#if defined(CONFIG_TCT_PM7250_COMMON) + vote_override(chg->fcc_main_votable, CC_MODE_VOTER, false, 0); +#else vote_override(chg->fcc_votable, CC_MODE_VOTER, false, 0); +#endif vote_override(chg->usb_icl_votable, CC_MODE_VOTER, false, 0); vote(chg->cp_disable_votable, OVERHEAT_LIMIT_VOTER, false, 0); vote(chg->usb_icl_votable, OVERHEAT_LIMIT_VOTER, false, 0); @@ -6345,14 +7010,25 @@ static void typec_src_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't restore max pulses rc=%d\n", rc); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chg->disable_suspend_on_collapse) { + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT, + SUSPEND_ON_COLLAPSE_USBIN_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", + rc); + } + chg->qc2_unsupported_voltage = QC2_NON_COMPLIANT_12V; +#else rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, SUSPEND_ON_COLLAPSE_USBIN_BIT, SUSPEND_ON_COLLAPSE_USBIN_BIT); if (rc < 0) smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", rc); - chg->qc2_unsupported_voltage = QC2_COMPLIANT; +#endif } if (chg->use_extcon) @@ -6360,6 +7036,10 @@ static void typec_src_removal(struct smb_charger *chg) chg->typec_legacy = false; +#if defined(CONFIG_TCT_PM7250_COMMON) + chg->apsd_rerun_done = false; +#endif + del_timer_sync(&chg->apsd_timer); chg->apsd_ext_timeout = false; } @@ -6414,8 +7094,13 @@ static void smblib_lpd_launch_ra_open_work(struct smb_charger *chg) chg->lpd_stage = LPD_STAGE_FLOAT; cancel_delayed_work_sync(&chg->lpd_ra_open_work); vote(chg->awake_votable, LPD_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->lpd_ra_open_work, + msecs_to_jiffies(300)); +#else schedule_delayed_work(&chg->lpd_ra_open_work, msecs_to_jiffies(300)); +#endif } } @@ -6481,8 +7166,13 @@ irqreturn_t typec_state_change_irq_handler(int irq, void *data) smblib_handle_rp_change(chg, typec_mode); chg->typec_mode = typec_mode; +#if defined(CONFIG_TCT_PM7250_COMMON) + smblib_err(chg, "IRQ: Type-C %s detected\n", + smblib_typec_mode_name[chg->typec_mode]); +#else smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", smblib_typec_mode_name[chg->typec_mode]); +#endif power_supply_changed(chg->usb_psy); @@ -6513,7 +7203,9 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) return IRQ_HANDLED; +#if !defined(CONFIG_TCT_PM7250_COMMON) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); +#endif rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); if (rc < 0) { @@ -6522,6 +7214,10 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) return IRQ_HANDLED; } +#if defined(CONFIG_TCT_PM7250_COMMON) + smblib_err(chg, "IRQ: 0x%02x\n", stat); +#endif + attached = !!(stat & TYPEC_ATTACH_DETACH_STATE_BIT); if (attached) { @@ -6604,8 +7300,13 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) mutex_unlock(&chg->typec_lock); if (chg->lpd_stage == LPD_STAGE_FLOAT_CANCEL) +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->lpd_detach_work, + msecs_to_jiffies(1000)); +#else schedule_delayed_work(&chg->lpd_detach_work, msecs_to_jiffies(1000)); +#endif } rc = smblib_masked_write(chg, USB_CMD_PULLDOWN_REG, @@ -6720,7 +7421,9 @@ static enum alarmtimer_restart dcin_aicl_alarm_cb(struct alarm *alarm, smblib_dbg(chg, PR_WLS, "rerunning DCIN AICL\n"); +#if !defined(CONFIG_TCT_PM7250_COMMON) pm_stay_awake(chg->dev); +#endif schedule_work(&chg->dcin_aicl_work); return ALARMTIMER_NORESTART; @@ -6737,7 +7440,11 @@ static void dcin_icl_decrement(struct smb_charger *chg) return; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (icl <= DCIN_ICL_MIN_UA) { +#else if (icl == DCIN_ICL_MIN_UA) { +#endif /* Cannot possibly decrease ICL any further - do nothing */ smblib_dbg(chg, PR_WLS, "hit min ICL: stop\n"); return; @@ -6918,7 +7625,12 @@ irqreturn_t high_duty_cycle_irq_handler(int irq, void *data) */ vote(chg->hdc_irq_disable_votable, HDC_IRQ_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->clear_hdc_work, + msecs_to_jiffies(60)); +#else schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60)); +#endif return IRQ_HANDLED; } @@ -7002,7 +7714,11 @@ irqreturn_t wdog_snarl_irq_handler(int irq, void *data) if (chg->wa_flags & SW_THERM_REGULATION_WA) { cancel_delayed_work_sync(&chg->thermal_regulation_work); vote(chg->awake_votable, SW_THERM_REGULATION_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->thermal_regulation_work, 0); +#else schedule_delayed_work(&chg->thermal_regulation_work, 0); +#endif } power_supply_changed(chg->batt_psy); @@ -7094,8 +7810,13 @@ irqreturn_t usbin_ov_irq_handler(int irq, void *data) if (stat & USBIN_OV_RT_STS_BIT) { chg->dbc_usbov = true; vote(chg->awake_votable, USBOV_DBC_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->usbov_dbc_work, + msecs_to_jiffies(USB_OV_DBC_PERIOD_MS)); +#else schedule_delayed_work(&chg->usbov_dbc_work, msecs_to_jiffies(USB_OV_DBC_PERIOD_MS)); +#endif } else { cancel_delayed_work_sync(&chg->usbov_dbc_work); chg->dbc_usbov = false; @@ -7133,8 +7854,13 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, if (!chg->pr_swap_in_progress) { cancel_delayed_work_sync(&chg->pr_swap_detach_work); vote(chg->awake_votable, DETACH_DETECT_VOTER, true, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_delayed_work(private_chg_wq, &chg->pr_swap_detach_work, + msecs_to_jiffies(DETACH_DETECT_DELAY_MS)); +#else schedule_delayed_work(&chg->pr_swap_detach_work, msecs_to_jiffies(DETACH_DETECT_DELAY_MS)); +#endif } rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG, @@ -7365,7 +8091,10 @@ static void smblib_pl_enable_work(struct work_struct *work) pl_enable_work.work); smblib_dbg(chg, PR_PARALLEL, "timer expired, enabling parallel\n"); + +#if !defined(CONFIG_TCT_PM7250_COMMON) vote(chg->pl_disable_votable, PL_DELAY_VOTER, false, 0); +#endif vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); } @@ -7376,9 +8105,15 @@ static void smblib_thermal_regulation_work(struct work_struct *work) int rc; rc = smblib_update_thermal_readings(chg); +#if defined(CONFIG_TCT_PM7250_COMMON) + if (rc < 0) + smblib_dbg(chg, PR_MISC, "Couldn't read current thermal values %d\n", + rc); +#else if (rc < 0) smblib_err(chg, "Couldn't read current thermal values %d\n", rc); +#endif rc = smblib_process_thermal_readings(chg); if (rc < 0) @@ -7500,8 +8235,17 @@ static void smblib_chg_termination_work(struct work_struct *work) vote(chg->awake_votable, CHG_TERMINATION_VOTER, true, 0); rc = smblib_is_input_present(chg, &input_present); + +#if defined(CONFIG_TCT_PM7250_COMMON) + if ((rc < 0) || !input_present) { + vote(chg->usb_icl_votable, CHG_TERMINATION_VOTER, false, 0); + vote(chg->dc_suspend_votable, CHG_TERMINATION_VOTER, false, 0); + goto out; + } +#else if ((rc < 0) || !input_present) goto out; +#endif rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_REAL_CAPACITY, &pval); @@ -7622,6 +8366,9 @@ static void smblib_chg_termination_work(struct work_struct *work) alarm_start_relative(&chg->chg_termination_alarm, ms_to_ktime(delay)); out: vote(chg->awake_votable, CHG_TERMINATION_VOTER, false, 0); +#if defined(CONFIG_TCT_PM7250_COMMON) + pm_relax(chg->dev); +#endif } static enum alarmtimer_restart chg_termination_alarm_cb(struct alarm *alarm, @@ -7635,7 +8382,12 @@ static enum alarmtimer_restart chg_termination_alarm_cb(struct alarm *alarm, /* Atomic context, cannot use voter */ pm_stay_awake(chg->dev); + +#if defined(CONFIG_TCT_PM7250_COMMON) + queue_work(private_chg_wq, &chg->chg_termination_work); +#else schedule_work(&chg->chg_termination_work); +#endif return ALARMTIMER_NORESTART; } @@ -7941,6 +8693,37 @@ static void smblib_cp_status_change_work(struct work_struct *work) pm_relax(chg->dev); } +#if defined(CONFIG_TCT_PM7250_COMMON) +int recheck_unknown_typec(struct smb_charger *chg) +{ + int rc; + u8 stat = 0; + + if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) + return -1; + + if(chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) + return -1; + + if(chg->real_charger_type != POWER_SUPPLY_TYPE_UNKNOWN) + return -1; + + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read USBIN_RT_STS rc=%d\n", rc); + return rc; + } + if (!(stat & USBIN_PLUGIN_RT_STS_BIT)) { + return -1; + } + pr_err("detected non-compliant cc line\n"); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, USBIN_500MA); + smblib_request_dpdm(chg, true); + smblib_rerun_apsd(chg); + return 0; +} +#endif + static int smblib_create_votables(struct smb_charger *chg) { int rc = 0; diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 6294edca9efa2c04dc5d1b6c646d4de06b576dcf..5d67ec2f9c3058fd9e9acf67944525c97a2316c4 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -95,7 +95,13 @@ enum print_reason { #define SDP_100_MA 100000 #define SDP_CURRENT_UA 500000 #define CDP_CURRENT_UA 1500000 + +#if defined(CONFIG_TCT_PM7250_COMMON) +#define DCP_CURRENT_UA 2000000 +#else #define DCP_CURRENT_UA 1500000 +#endif + #define HVDCP_CURRENT_UA 3000000 #define TYPEC_DEFAULT_CURRENT_UA 900000 #define TYPEC_MEDIUM_CURRENT_UA 1500000 @@ -105,6 +111,14 @@ enum print_reason { #define DCIN_ICL_STEP_UA 100000 #define ROLE_REVERSAL_DELAY_MS 500 +#if defined(CONFIG_TCT_PM7250_COMMON) + +#define QC3_ICL_MAX 2000000 +#define QC2_ICL_MAX 1500000 +#define HW_ICL_MAX 2050000 +#endif + + enum smb_mode { PARALLEL_MASTER = 0, PARALLEL_SLAVE, @@ -399,6 +413,11 @@ struct smb_charger { struct mutex dpdm_lock; struct mutex typec_lock; +#if defined(CONFIG_TCT_PM7250_COMMON) + bool apsd_rerun_done; + bool disable_suspend_on_collapse; +#endif + /* power supplies */ struct power_supply *batt_psy; struct power_supply *usb_psy; @@ -506,9 +525,15 @@ struct smb_charger { int system_temp_level; int thermal_levels; int *thermal_mitigation; +#if defined(CONFIG_TCT_PM7250_COMMON) + int *thermal_mitigation_lcdon; +#endif int dcp_icl_ua; int fake_capacity; int fake_batt_status; +#if defined(CONFIG_TCT_PM7250_COMMON) + int real_soc; +#endif bool step_chg_enabled; bool sw_jeita_enabled; bool jeita_arb_enable; @@ -676,6 +701,11 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data); irqreturn_t temp_change_irq_handler(int irq, void *data); irqreturn_t usbin_ov_irq_handler(int irq, void *data); irqreturn_t sdam_sts_change_irq_handler(int irq, void *data); + +#if defined(CONFIG_TCT_PM7250_COMMON) +int recheck_unknown_typec(struct smb_charger *chg); +#endif + int smblib_get_prop_input_suspend(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_present(struct smb_charger *chg, diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 311e810c31c0d344c9d10df6250c3ebb043672bf..ecaf6961b10155cf03bdf21d9a183bef0af08eea 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -42,6 +42,9 @@ enum { #define BATTERY_CHARGER_STATUS_2_REG (CHGR_BASE + 0x07) #define CHARGER_ERROR_STATUS_BAT_OV_BIT BIT(1) +#if defined(CONFIG_TCT_PM7250_COMMON) +#define CHARGER_ERROR_STATUS_SFT_EXPIRE_BIT BIT(2) +#endif #define BATTERY_CHARGER_STATUS_5_REG (CHGR_BASE + 0x0B) #define ENABLE_TRICKLE_BIT BIT(2) @@ -334,7 +337,17 @@ enum { * TYPEC Peripheral Registers * ********************************/ #define TYPE_C_SNK_STATUS_REG (TYPEC_BASE + 0x06) + + #define DETECTED_SRC_TYPE_MASK GENMASK(6, 0) +#define SNK_RP_STD_DAM_BIT BIT(6) +#define SNK_RP_1P5_DAM_BIT BIT(5) +#define SNK_RP_3P0_DAM_BIT BIT(4) + +#define TYPE_C_DEBUG_ACCESS_SINK_REG (TYPEC_BASE + 0x4A) +#define TYPEC_DEBUG_ACCESS_SINK_MASK GENMASK(4, 0) + + #define SNK_DAM_MASK GENMASK(6, 4) #define SNK_DAM_500MA_BIT BIT(6) #define SNK_DAM_1500MA_BIT BIT(5) @@ -526,6 +539,9 @@ enum { #define AICL_RERUN_TIME_CFG_REG (MISC_BASE + 0x61) #define AICL_RERUN_TIME_12S_VAL 0x01 +#if defined(CONFIG_TCT_PM7250_COMMON) +#define AICL_RERUN_TIME_3MIN_VAL 0x03 +#endif #define MISC_THERMREG_SRC_CFG_REG (MISC_BASE + 0x70) #define THERMREG_SW_ICL_ADJUST_BIT BIT(7) diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c index 369fc660107073475048538908c6e43d516bb788..2a56fb5f0dd6b8adc6c5a02d0a1d49cc81aaafbd 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.c +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -18,6 +18,11 @@ #define JEITA_VOTER "JEITA_VOTER" #define JEITA_FCC_SCALE_VOTER "JEITA_FCC_SCALE_VOTER" +#if defined(CONFIG_TCT_PM7250_COMMON) +#define CHG_CTL_VOTER "CHG_CTL_VOTER" +#define VBAT_LMT_VOTER "VBAT_LMT_VOTER" +#endif + #define is_between(left, right, value) \ (((left) >= (right) && (left) >= (value) \ && (value) >= (right)) \ @@ -64,6 +69,11 @@ struct step_chg_info { long jeita_max_fcc_ua; long jeita_fcc_step_size; +#if defined(CONFIG_TCT_PM7250_COMMON) + int max_fv_uv; + bool last_input_present; +#endif + struct step_chg_cfg *step_chg_config; struct jeita_fcc_cfg *jeita_fcc_config; struct jeita_fv_cfg *jeita_fv_config; @@ -71,6 +81,8 @@ struct step_chg_info { struct votable *fcc_votable; struct votable *fv_votable; struct votable *usb_icl_votable; + struct votable *chg_disable_votable; + struct wakeup_source *step_chg_ws; struct power_supply *batt_psy; struct power_supply *bms_psy; @@ -83,6 +95,10 @@ struct step_chg_info { static struct step_chg_info *the_chip; +#if defined(CONFIG_TCT_PM7250_COMMON) +#define STEP_CHG_HYSTERISIS_DELAY_MS 10000 +#endif + #define STEP_CHG_HYSTERISIS_DELAY_US 5000000 /* 5 secs */ #define BATT_HOT_DECIDEGREE_MAX 600 @@ -112,6 +128,7 @@ static bool is_bms_available(struct step_chg_info *chip) return true; } +#if !defined(CONFIG_TCT_PM7250_COMMON) static bool is_usb_available(struct step_chg_info *chip) { if (!chip->usb_psy) @@ -122,6 +139,7 @@ static bool is_usb_available(struct step_chg_info *chip) return true; } +#endif static bool is_input_present(struct step_chg_info *chip) { @@ -289,6 +307,10 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) + chip->max_fv_uv = max_fv_uv; +#endif + rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma", &max_fcc_ma); if (rc < 0) { @@ -312,11 +334,23 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) chip->ocv_based_step_chg = of_property_read_bool(profile_node, "qcom,ocv-based-step-chg"); if (chip->ocv_based_step_chg) { +#if defined(CONFIG_TCT_PM7250_COMMON) + chip->step_chg_config->param.psy_prop = + POWER_SUPPLY_PROP_VOLTAGE_NOW; +#else chip->step_chg_config->param.psy_prop = POWER_SUPPLY_PROP_VOLTAGE_OCV; +#endif chip->step_chg_config->param.prop_name = "OCV"; + +#if defined(CONFIG_TCT_PM7250_COMMON) + + chip->step_chg_config->param.rise_hys = 50000; + chip->step_chg_config->param.fall_hys = 50000; +#else chip->step_chg_config->param.rise_hys = 0; chip->step_chg_config->param.fall_hys = 0; +#endif chip->step_chg_config->param.use_bms = true; } @@ -476,8 +510,16 @@ static int get_val(struct range_data *range, int rise_hys, int fall_hys, * If the threshold is lesser than the minimum allowed range, * return -ENODATA. */ +#if defined(CONFIG_TCT_PM7250_COMMON) + if (threshold < 0 || threshold < range[0].low_threshold) { + pr_debug("invalid lowest value: %d < %d\n", + threshold, range[0].low_threshold); + return -ENODATA; + } +#else if (threshold < range[0].low_threshold) return -ENODATA; +#endif /* First try to find the matching index without hysteresis */ for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++) { @@ -485,6 +527,12 @@ static int get_val(struct range_data *range, int rise_hys, int fall_hys, /* First invalid table entry; exit loop */ break; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (range[i].high_threshold == range[i].low_threshold) { + /* invalid table entry; exit loop */ + break; + } +#endif if (is_between(range[i].low_threshold, range[i].high_threshold, threshold)) { @@ -504,7 +552,11 @@ static int get_val(struct range_data *range, int rise_hys, int fall_hys, if (*new_index == -EINVAL) { if (i == 0) { /* Battery profile data array is completely invalid */ +#if defined(CONFIG_TCT_PM7250_COMMON) + return -EINVAL; +#else return -ENODATA; +#endif } *new_index = (i - 1); @@ -547,6 +599,7 @@ static int get_val(struct range_data *range, int rise_hys, int fall_hys, return 0; } +#if !defined(CONFIG_TCT_PM7250_COMMON) #define TAPERED_STEP_CHG_FCC_REDUCTION_STEP_MA 50000 /* 50 mA */ static void taper_fcc_step_chg(struct step_chg_info *chip, int index, int current_voltage) @@ -589,7 +642,176 @@ static void taper_fcc_step_chg(struct step_chg_info *chip, int index, current_fcc - TAPERED_STEP_CHG_FCC_REDUCTION_STEP_MA)); } } +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) +#define OV_VOTER "OV_VOTER" +#define SOC_VOTER "SOC_VOTER" +#define VBATT_VOTER "VBATT_VOTER" + +#define LIMIT_VBAT_OV (4430000) +#define LIMIT_VBAT_MAX (4400000) +#define LIMIT_VBAT_MIN (4300000) +#define LIMIT_VBAT_CV (4350000) +#define CV_DOWN_DELTA_UA (200000) +#define CV_UP_DELTA_UA (50000) +#define MIN_FCC_UA (500000) +#define MAX_FCC_UA (2000000) +static int handle_vbatt_ov(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0; + + if (!chip->fcc_votable) + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) { + pr_err("fcc voter NULL\n"); + return -EINVAL; + } + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + if (rc < 0 || (pval.intval <= LIMIT_VBAT_MAX)) { + pr_debug("vbatt-%d lower or rc-%d, restored\n", + pval.intval, rc); + vote(chip->fcc_votable, OV_VOTER, false, 0); + return rc; + } + + if (pval.intval >= LIMIT_VBAT_OV) { + pr_err("OV-%d, disabled chg\n", pval.intval); + vote(chip->fcc_votable, OV_VOTER, true, 0); + } + + return 0; +} + +static int handle_vbatt_limit(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0; + int fcc_val_uA = 500000; + + if (!chip->fcc_votable) + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) { + pr_err("fcc voter NULL\n"); + return -EINVAL; + } + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &pval); + if (rc < 0 || pval.intval < 80) { + vote(chip->fcc_votable, SOC_VOTER, false, 0); + } else if (pval.intval >= 90) { + vote(chip->fcc_votable, SOC_VOTER, true, 1500000); + } else if (pval.intval >= 85) { + vote(chip->fcc_votable, SOC_VOTER, true, 1800000); + } + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + if (rc < 0 || (pval.intval < LIMIT_VBAT_MIN)) { + pr_err_ratelimited("vbatt-%d lower or rc-%d, restored\n", + pval.intval, rc); + vote(chip->fcc_votable, VBATT_VOTER, false, 0); + return rc; + } + + fcc_val_uA = get_effective_result(chip->fcc_votable); + pr_err_ratelimited("f=%d, v=%d\n", fcc_val_uA, pval.intval); + + if (pval.intval > LIMIT_VBAT_MAX) { + if (fcc_val_uA >= (MIN_FCC_UA + CV_DOWN_DELTA_UA)) { + fcc_val_uA -= CV_DOWN_DELTA_UA; + vote(chip->fcc_votable, VBATT_VOTER, true, fcc_val_uA); + pr_err_ratelimited("down FCC to %d\n", fcc_val_uA); + } + } else if (pval.intval < LIMIT_VBAT_CV) { + if ((fcc_val_uA > 0) && + (fcc_val_uA <= (MAX_FCC_UA - CV_UP_DELTA_UA))) { + fcc_val_uA += CV_UP_DELTA_UA; + vote(chip->fcc_votable, VBATT_VOTER, true, fcc_val_uA); + pr_err_ratelimited("up FCC to %d\n", fcc_val_uA); + } + } + return 0; +} +#endif +#if defined(CONFIG_TCT_PM7250_COMMON) +static int handle_step_chg_config(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0, fcc_ua = 0; + u64 elapsed_ms; + + if (!chip->step_chg_enable || !chip->step_chg_cfg_valid) { + pr_debug("step_chg disabled or invalid, %d, %d\n", + chip->step_chg_enable, chip->step_chg_cfg_valid); + return 0; + } + + if (!chip->fcc_votable) + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) + /* changing FCC is a must */ + return -EINVAL; + + elapsed_ms = ktime_ms_delta(ktime_get(), chip->step_last_update_time); + /* skip processing, event too early */ + if (elapsed_ms < STEP_CHG_HYSTERISIS_DELAY_MS) + return 0; + + rc = handle_vbatt_ov(chip); + if (rc < 0) + pr_err("Couldn't limit ov rc = %d\n", rc); + + rc = handle_vbatt_limit(chip); + if (rc < 0) + pr_err("Couldn't limit vbat rc = %d\n", rc); + + if (chip->step_chg_config->param.use_bms) + rc = power_supply_get_property(chip->bms_psy, + chip->step_chg_config->param.psy_prop, &pval); + else + rc = power_supply_get_property(chip->batt_psy, + chip->step_chg_config->param.psy_prop, &pval); + + if (rc < 0) { + pr_debug("Couldn't read %s property rc=%d\n", + chip->step_chg_config->param.prop_name, rc); + vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0); + return rc; + } + + rc = get_val(chip->step_chg_config->fcc_cfg, + chip->step_chg_config->param.rise_hys, + chip->step_chg_config->param.fall_hys, + chip->step_index, + pval.intval, + &chip->step_index, + &fcc_ua); + if (rc < 0) { + pr_debug("Couldn't get_val:%d from step_chg_config, rc=%d\n", + pval.intval, rc); + vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0); + goto update_time; + } + + fcc_ua = chip->step_chg_config->fcc_cfg[chip->step_index].value; + vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua); + + pr_debug("%s=%d, Step-FCC=%duA, index=%d\n", + chip->step_chg_config->param.prop_name, + pval.intval, + get_client_vote(chip->fcc_votable, STEP_CHG_VOTER), + chip->step_index); +update_time: + chip->step_last_update_time = ktime_get(); + return 0; +} +#else static int handle_step_chg_config(struct step_chg_info *chip) { union power_supply_propval pval = {0, }; @@ -671,6 +893,7 @@ static int handle_step_chg_config(struct step_chg_info *chip) chip->step_last_update_time = ktime_get(); return 0; } +#endif static void handle_jeita_fcc_scaling(struct step_chg_info *chip) { @@ -742,6 +965,161 @@ static void handle_jeita_fcc_scaling(struct step_chg_info *chip) } } +#if defined(CONFIG_TCT_PM7250_COMMON) +#define FV_LVL_1 (300000) +#define FV_LVL_2 (200000) +#define FV_LVL_3 (100000) +#define FV_LVL_4 (50000) +#define FCC_LVL_1 (1500000) +#define FCC_LVL_2 (1000000) +#define FCC_LVL_3 (500000) +static int handle_jeita(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0, fcc_ua = 0, fv_uv = 0; + u64 elapsed_ms = 0; + + + + /* Handle jeita-fcc-scaling if enabled */ + if (chip->jeita_fcc_scaling) + handle_jeita_fcc_scaling(chip); + + if (!chip->sw_jeita_enable || !chip->sw_jeita_cfg_valid) { + pr_debug("sw_jeita disabled or invalid, %d, %d\n", + chip->sw_jeita_enable, chip->sw_jeita_cfg_valid); + return 0; + } + + if (!chip->fcc_votable) + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) + /* changing FCC is a must */ + return -EINVAL; + + elapsed_ms = ktime_ms_delta(ktime_get(), chip->jeita_last_update_time); + /* skip processing, event too early */ + if (elapsed_ms < STEP_CHG_HYSTERISIS_DELAY_MS) + return 0; + + if (chip->jeita_fcc_config->param.use_bms) + rc = power_supply_get_property(chip->bms_psy, + chip->jeita_fcc_config->param.psy_prop, &pval); + else + rc = power_supply_get_property(chip->batt_psy, + chip->jeita_fcc_config->param.psy_prop, &pval); + + if (rc < 0) { + pr_debug("Couldn't read %s property rc=%d\n", + chip->jeita_fcc_config->param.prop_name, rc); + vote(chip->fcc_votable, JEITA_VOTER, false, 0); + vote(chip->fcc_votable, VBAT_LMT_VOTER, false, 0); + vote(chip->fcc_votable, CHG_CTL_VOTER, false, 0); + return rc; + } + + rc = get_val(chip->jeita_fcc_config->fcc_cfg, + chip->jeita_fcc_config->param.rise_hys, + chip->jeita_fcc_config->param.fall_hys, + chip->jeita_fcc_index, + pval.intval, + &chip->jeita_fcc_index, + &fcc_ua); + if (rc < 0) { + pr_debug("Couldn't get_val:%d from jeita_fcc_config, rc=%d\n", + pval.intval, rc); + if (rc == -ENODATA) + fcc_ua = 0; + else + fcc_ua = -EINVAL; + } + +//zxz add ,we not vote fcc 0 here +//vote(chip->fcc_votable, JEITA_VOTER, (fcc_ua>=0) ? true : false, fcc_ua); + vote(chip->fcc_votable, JEITA_VOTER, (fcc_ua>0) ? true : false, fcc_ua); + + pr_err("handle_jeita ,temp:%d, fcc_ua:%d \n",pval.intval,fcc_ua); + +/*zxz add comment : +1.why not use hardware PMIC hard cold/Hot ? +because if use hardware PMIC hard cold/Hot is cutoff USBIN current when reach the hard cold/Hot , +the device PMIC will stop USBIN current, but the FP4 adapter charger have a protect feature ,to avoid leakage current , +it will cutoff the output, so when the temperature recover ,but the adapter no output will cause charge abnormal . +2.why not use vote fcc 0 to control charge current, if fcc to 0 the VPHPWR have current and fp4 adapter not cut off in theory ? +not sure why if vote fcc to 0, it like usbicl to 0; +if temperature recover to normal, the charge current is low, because cp charge is disabled when current is low, +but the force main fcc and force main icl is 800, so the current may low, if redo charge enable it will be ok . + +*/ + if (!chip->chg_disable_votable) + chip->chg_disable_votable = find_votable("CHG_DISABLE"); + if (!chip->chg_disable_votable) + /* chg_disable_votable is a must */ + return -EINVAL; + + if(fcc_ua==0){ + pr_err("handle_jeita ,FCC vote chg_disable_votable:true \n"); + vote(chip->chg_disable_votable, JEITA_VOTER, true, 0); + }else if(fcc_ua>0){ + pr_err("handle_jeita ,FCC vote chg_disable_votable:false \n"); + vote(chip->chg_disable_votable, JEITA_VOTER, false, 0); + }else{ + pr_err("handle_jeita ,FCC fcc_ua=%d \n",fcc_ua); + } + + rc = get_val(chip->jeita_fv_config->fv_cfg, + chip->jeita_fv_config->param.rise_hys, + chip->jeita_fv_config->param.fall_hys, + chip->jeita_fv_index, + pval.intval, + &chip->jeita_fv_index, + &fv_uv); + if (rc < 0) + fv_uv = 0; + + if (fv_uv > 3600000 && fv_uv < chip->max_fv_uv) { + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + if(rc < 0) { + vote(chip->fcc_votable, VBAT_LMT_VOTER, false, 0); + vote(chip->fcc_votable, CHG_CTL_VOTER, false, 0); + } else { + if (pval.intval > fv_uv) { + //vote(chip->fcc_votable, CHG_CTL_VOTER, true, 0); + pr_err("handle_jeita ,FV vote chg_disable_votable:true \n"); + vote(chip->chg_disable_votable, CHG_CTL_VOTER, true, 0); + }else{ + pr_err("handle_jeita ,FV vote chg_disable_votable:false \n"); + vote(chip->chg_disable_votable, CHG_CTL_VOTER, false, 0); + } + + if ((pval.intval+FV_LVL_4) < fv_uv) { + if ((pval.intval+FV_LVL_3) >= fv_uv) { + vote(chip->fcc_votable, VBAT_LMT_VOTER, true, FCC_LVL_3); + } else if ((pval.intval+FV_LVL_2) >= fv_uv) { + vote(chip->fcc_votable, VBAT_LMT_VOTER, true, FCC_LVL_2); + } else if ((pval.intval+FV_LVL_1) >= fv_uv) { + vote(chip->fcc_votable, VBAT_LMT_VOTER, true, FCC_LVL_1); + } else { + vote(chip->fcc_votable, VBAT_LMT_VOTER, false, 0); + } + //vote(chip->fcc_votable, CHG_CTL_VOTER, false, 0); + } + } + } else { + vote(chip->fcc_votable, VBAT_LMT_VOTER, false, 0); + vote(chip->fcc_votable, CHG_CTL_VOTER, false, 0); + } + + pr_debug("current FV=%d, Jeita-FV-FCC=%d,%d, index=%d\n", + pval.intval, fv_uv, + get_effective_result(chip->fcc_votable), + chip->jeita_fv_index); + + chip->jeita_last_update_time = ktime_get(); + return 0; +} +#else #define JEITA_SUSPEND_HYST_UV 50000 static int handle_jeita(struct step_chg_info *chip) { @@ -858,6 +1236,7 @@ static int handle_jeita(struct step_chg_info *chip) return 0; } +#endif static int handle_battery_insertion(struct step_chg_info *chip) { @@ -892,18 +1271,91 @@ static int handle_battery_insertion(struct step_chg_info *chip) return rc; } +#if defined(CONFIG_TCT_PM7250_COMMON) +#if defined(CONFIG_TCT_IEEE1725) +#define IEEE_VOTER "IEEE_VOTER" +#define LIMIT_LOWER_TEMP_LVL (30) +#define LIMIT_UPPER_TEMP_LVL (50) +static int handle_ieee_limit(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0; + + if (!chip->fcc_votable) + chip->fcc_votable = find_votable("FCC"); + if (!chip->fcc_votable) + return -EINVAL; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_TEMP, &pval); + if (rc < 0) { + pr_err("Couldn't read batt temp, rc=%d\n", rc); + vote(chip->fcc_votable, IEEE_VOTER, false, 0); + return rc; + } + + if (pval.intval < LIMIT_LOWER_TEMP_LVL) { + vote(chip->fcc_votable, IEEE_VOTER, true, 0); + } else if (pval.intval > LIMIT_UPPER_TEMP_LVL) { + vote(chip->fcc_votable, IEEE_VOTER, false, 0); + } + return 0; +} +#endif +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) +static void step_chg_status_change_work(struct work_struct *work) +#else static void status_change_work(struct work_struct *work) +#endif { struct step_chg_info *chip = container_of(work, struct step_chg_info, status_change_work.work); int rc = 0; + +#if defined(CONFIG_TCT_PM7250_COMMON) + bool input_present = false; +#endif +#if !defined(CONFIG_TCT_PM7250_COMMON) union power_supply_propval prop = {0, }; +#endif if (!is_batt_available(chip) || !is_bms_available(chip)) goto exit_work; handle_battery_insertion(chip); +#if defined(CONFIG_TCT_PM7250_COMMON) + input_present = is_input_present(chip); + if (!input_present && !chip->last_input_present) { + pr_debug("skip for input_present=%d\n", + input_present); + goto exit_work; + } + chip->last_input_present = input_present; + if (!input_present) { + if (chip->fcc_votable) { + vote(chip->fcc_votable, VBAT_LMT_VOTER, false, 0); + vote(chip->fcc_votable, CHG_CTL_VOTER, false, 0); + vote(chip->fcc_votable, JEITA_VOTER, false, 0); + vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0); + chip->step_index = -EINVAL; + chip->jeita_fcc_index = -EINVAL; + chip->jeita_fv_index = -EINVAL; + } + goto exit_work; + } +#endif + +#if defined(CONFIG_TCT_PM7250_COMMON) +#if defined(CONFIG_TCT_IEEE1725) + rc = handle_ieee_limit(chip); + if (rc < 0) + pr_err("Couldn't limit ieee rc = %d\n", rc); +#endif +#endif + /* skip elapsed_us debounce for handling battery temperature */ rc = handle_jeita(chip); if (rc < 0) @@ -913,6 +1365,7 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Couldn't handle step rc = %d\n", rc); +#if !defined(CONFIG_TCT_PM7250_COMMON) /* Remove stale votes on USB removal */ if (is_usb_available(chip)) { prop.intval = 0; @@ -924,6 +1377,7 @@ static void status_change_work(struct work_struct *work) false, 0); } } +#endif exit_work: __pm_relax(chip->step_chg_ws); @@ -938,10 +1392,25 @@ static int step_chg_notifier_call(struct notifier_block *nb, if (ev != PSY_EVENT_PROP_CHANGED) return NOTIFY_OK; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (delayed_work_pending(&chip->status_change_work)) { + pr_debug("step_chg_status_change_work pending now, skip\n"); + return NOTIFY_OK; + } +#endif + if ((strcmp(psy->desc->name, "battery") == 0) || (strcmp(psy->desc->name, "usb") == 0)) { +#if defined(CONFIG_TCT_PM7250_COMMON) + if (chip->config_is_read) { + __pm_stay_awake(chip->step_chg_ws); + queue_delayed_work(private_chg_wq, + &chip->status_change_work, 0); + } +#else __pm_stay_awake(chip->step_chg_ws); schedule_delayed_work(&chip->status_change_work, 0); +#endif } if ((strcmp(psy->desc->name, "bms") == 0)) { @@ -995,6 +1464,10 @@ int qcom_step_chg_init(struct device *dev, chip->jeita_fcc_index = -EINVAL; chip->jeita_fv_index = -EINVAL; +#if defined(CONFIG_TCT_PM7250_COMMON) + chip->max_fv_uv = -EINVAL; +#endif + chip->step_chg_config = devm_kzalloc(dev, sizeof(struct step_chg_cfg), GFP_KERNEL); if (!chip->step_chg_config) @@ -1014,14 +1487,29 @@ int qcom_step_chg_init(struct device *dev, chip->jeita_fcc_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP; chip->jeita_fcc_config->param.prop_name = "BATT_TEMP"; +#if defined(CONFIG_TCT_PM7250_COMMON) + chip->jeita_fcc_config->param.rise_hys = 10; + chip->jeita_fcc_config->param.fall_hys = 20; +#else chip->jeita_fcc_config->param.rise_hys = 10; chip->jeita_fcc_config->param.fall_hys = 10; +#endif + chip->jeita_fv_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP; chip->jeita_fv_config->param.prop_name = "BATT_TEMP"; +#if defined(CONFIG_TCT_PM7250_COMMON) + chip->jeita_fv_config->param.rise_hys = 10; + chip->jeita_fv_config->param.fall_hys = 20; +#else chip->jeita_fv_config->param.rise_hys = 10; chip->jeita_fv_config->param.fall_hys = 10; +#endif +#if defined(CONFIG_TCT_PM7250_COMMON) + INIT_DELAYED_WORK(&chip->status_change_work, step_chg_status_change_work); +#else INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); +#endif INIT_DELAYED_WORK(&chip->get_config_work, get_config_work); rc = step_chg_register_notifier(chip); diff --git a/drivers/power/supply/qcom/tct-customized-fr.c b/drivers/power/supply/qcom/tct-customized-fr.c new file mode 100644 index 0000000000000000000000000000000000000000..1743e7ba9b12907bec9fecfdf83bc6e0ef92fed7 --- /dev/null +++ b/drivers/power/supply/qcom/tct-customized-fr.c @@ -0,0 +1,376 @@ +#define pr_fmt(fmt) "[SMBLIB5]: " fmt + +#include +#include +#include "smb5-lib.h" +#if defined(CONFIG_DRM) +#include +#if defined(CONFIG_DRM_PANEL) +#include +#endif +#elif defined(CONFIG_FB) +#include +#include +#endif +#include +#include + +#define smblib_err(chg, fmt, ...) \ + pr_err_ratelimited("%s: " fmt, \ + __func__, ##__VA_ARGS__) +#define smblib_dbg(chg, reason, fmt, ...) \ + do { \ + if (*chg->debug_mask & (reason)) \ + pr_err_ratelimited("%s: " fmt, \ + __func__, ##__VA_ARGS__); \ + else \ + pr_debug_ratelimited("%s: " fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +/************** battery current thermal for screen on or off ******************/ +/* smb5-lib.h qpnp-smb5.c add some patch */ +#if defined(CONFIG_DRM) +#if defined(CONFIG_DRM_PANEL) +static int smblib_check_panel_dt(struct smb_charger *chg) +{ + int i; + int count; + struct device_node *node, *np; + struct drm_panel *panel; + + np = of_find_compatible_node(NULL, NULL, "qcom,msm-notifier"); + if (!np) { + smblib_err(chg, "failed to find qcom,msm-notifier node\n"); + return -ENODEV; + } + count = of_count_phandle_with_args(np, "panel", NULL); + if (count <= 0) + return 0; + + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "panel", i); + panel = of_drm_find_panel(node); + of_node_put(node); + if (!IS_ERR(panel)) { + chg->active_panel = panel; + return 0; + } + } + + return -ENODEV; +} +#endif +static int smblib_drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct msm_drm_notifier *evdata = data; + int *blank = NULL; + union power_supply_propval pval; + struct smb_charger *chg = container_of(self, struct smb_charger, fb_nb); + + if (!evdata) { + smblib_err(chg, "evdata is null\n"); + return 0; + } + + if (event != MSM_DRM_EVENT_BLANK) { + smblib_dbg(chg, PR_MISC, "DRM event(%lu) do not need process\n", event); + return 0; + } + + if (evdata->data && event == MSM_DRM_EVENT_BLANK && chg) { + blank = evdata->data; + pval.intval = chg->system_temp_level; + switch (*blank) { + case MSM_DRM_BLANK_UNBLANK: + chg->is_screen_on = true; + smblib_set_prop_system_temp_level(chg, &pval); + break; + case MSM_DRM_BLANK_POWERDOWN: + chg->is_screen_on = false; + smblib_set_prop_system_temp_level(chg, &pval); + break; + default: + smblib_dbg(chg, PR_MISC, "DRM blank(%d) do not need process\n", *blank); + break; + } + } + + return 0; + +} + +#elif defined(CONFIG_FB) +static int smblib_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank = NULL; + union power_supply_propval pval; + struct smb_charger *chg = container_of(self, struct smb_charger, fb_nb); + + if (!evdata) { + smblib_err(chg, "evdata is null\n"); + return 0; + } + + if (event != FB_EVENT_BLANK) { + smblib_dbg(chg, PR_MISC, "FB event(%lu) do not need process\n", event); + return 0; + } + + if (evdata->data && event == FB_EVENT_BLANK && chg) { + blank = evdata->data; + pval.intval = chg->system_temp_level; + switch (*blank) { + case FB_BLANK_UNBLANK: + chg->is_screen_on = true; + smblib_set_prop_system_temp_level(chg, &pval); + break; + case FB_BLANK_POWERDOWN: + chg->is_screen_on = false; + smblib_set_prop_system_temp_level(chg, &pval); + break; + default: + smblib_dbg(chg, PR_MISC, "FB blank(%d) do not need process\n", *blank); + break; + } + } + + return 0; +} +#endif + +static int __init tct_thermal_init(void) +{ + struct power_supply *batt_psy = NULL; + struct smb_charger *chg = NULL; + int rc = 0; + batt_psy = power_supply_get_by_name("battery"); + if (!batt_psy) + return -ENODEV; + + chg = power_supply_get_drvdata(batt_psy); + if (chg) { + chg->is_screen_on = true; +#if defined(CONFIG_DRM) + chg->fb_nb.notifier_call = smblib_drm_notifier_callback; +#if defined(CONFIG_DRM_PANEL) + smblib_check_panel_dt(chg); + if (chg->active_panel) { + smblib_err(chg, "find active_panel\n"); + rc = drm_panel_notifier_register(chg->active_panel, &chg->fb_nb); + if (rc < 0) { + smblib_err(chg, "Couldn't register DRM_PANEL notifier rc = %d\n", rc); + goto err_notifier_register; + } + } else { + smblib_err(chg, "Couldn't find active_panel\n"); + goto err_notifier_register; + } +#else + rc = msm_drm_register_client(&chg->fb_nb); + if (rc < 0) { + smblib_err(chg, "Couldn't register DRM notifier rc = %d\n", rc); + goto err_notifier_register; + } +#endif +#elif defined(CONFIG_FB) + chg->fb_nb.notifier_call = smblib_fb_notifier_callback; + rc = fb_register_client(&chg->fb_nb); + if (rc < 0) { + smblib_err(chg, "Couldn't register FB notifier rc = %d\n", rc); + goto err_notifier_register; + } +#endif + } else { + pr_err("[%s]chg is null\n", __func__); + return -ENODATA; + } + + return 0; +err_notifier_register: + chg->is_screen_on = false; + return rc; +} +late_initcall(tct_thermal_init); + +/************ print charger and battery log for hw test every 10s *************/ +static int g_log_en = 0; +static unsigned int g_alarm_time = 10; +static struct delayed_work print_tct_charge_worker; +static struct alarm fg_log_thread_alarm; +static struct smb_charger *g_qcom_chg; + +static const char * const power_supply_status_text[] = { + "Unknown", "Charging", "Discharging", "Not charging", "Full" +}; + +static const char * const power_supply_charge_type_text[] = { + "Unknown", "N/A", "Trickle", "Fast", "Taper" +}; + +static const char * const power_supply_health_text[] = { + "Unknown", "Good", "Overheat", "Dead", "Over voltage", + "Unspecified failure", "Cold", "Watchdog timer expire", + "Safety timer expire", + "Warm", "Cool", "Hot" +}; + +void print_log_for_fg(void) +{ + union power_supply_propval Vbat = {0,}, Ibat = {0,}, batt_temp = {0,}, soc = {0,}; + union power_supply_propval Vbus = {0,}, status = {0,}, health = {0,}, Vph = {0,}, thermal_icl = {0,}; + union power_supply_propval charging_type = {0,}, Ibus = {0,}, Isns = {0,}; + union power_supply_propval cp_temp = {0,}; + int v_int_ext = 0, i_int_ext = 0; + + if (g_qcom_chg->batt_psy) { + power_supply_get_property(g_qcom_chg->batt_psy, POWER_SUPPLY_PROP_STATUS, &status); + power_supply_get_property(g_qcom_chg->batt_psy, POWER_SUPPLY_PROP_HEALTH, &health); + power_supply_get_property(g_qcom_chg->batt_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &Vbat); + power_supply_get_property(g_qcom_chg->batt_psy, POWER_SUPPLY_PROP_CAPACITY, &soc); + power_supply_get_property(g_qcom_chg->batt_psy, POWER_SUPPLY_PROP_CURRENT_NOW, &Ibat); + power_supply_get_property(g_qcom_chg->batt_psy, POWER_SUPPLY_PROP_TEMP, &batt_temp); + power_supply_get_property(g_qcom_chg->batt_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &charging_type); + } + + if (g_qcom_chg->usb_psy) { + power_supply_get_property(g_qcom_chg->usb_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &Vbus); + power_supply_get_property(g_qcom_chg->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, &Ibus); + power_supply_get_property(g_qcom_chg->usb_psy, POWER_SUPPLY_PROP_VOLTAGE_VPH, &Vph); + power_supply_get_property(g_qcom_chg->usb_psy, POWER_SUPPLY_PROP_THERM_ICL_LIMIT, &thermal_icl); + } + + if (g_qcom_chg->cp_psy) { + power_supply_get_property(g_qcom_chg->cp_psy, POWER_SUPPLY_PROP_CP_ISNS, &Isns); + power_supply_get_property(g_qcom_chg->cp_psy, POWER_SUPPLY_PROP_CP_DIE_TEMP, &cp_temp); + } + + if (g_qcom_chg->iio.v_i_int_ext_chan) { + iio_read_channel_processed_two(g_qcom_chg->iio.v_i_int_ext_chan, &v_int_ext, &i_int_ext); + } + + printk(KERN_ERR "%s: status:%s,health:%s,voltage:%dmV,capacity:%d,current:%dmA,temperature:%d,chgvoltage:%dmV,charging_type:%s,Ibus:%d,Thermal_icl:%d,VPH:%d,Isns:%d,cp_temp:%d,die_temp:%d,connector_temp:%d,skin_temp=%d,I_pmic=%d,I_smb=%d\n", + __func__, power_supply_status_text[status.intval], + power_supply_health_text[health.intval], + Vbat.intval/1000, soc.intval, Ibat.intval/1000, batt_temp.intval, + Vbus.intval/1000, power_supply_charge_type_text[charging_type.intval], + Ibus.intval/1000, thermal_icl.intval/1000, Vph.intval/1000, Isns.intval/1000, + cp_temp.intval, g_qcom_chg->die_temp, g_qcom_chg->connector_temp, g_qcom_chg->skin_temp, + -i_int_ext/1000, Ibat.intval/1000 + i_int_ext/1000); +} + +static void print_tct_charge_work(struct work_struct *work) +{ + print_log_for_fg(); +} + +static ssize_t enable_show(struct device *dev, struct device_attribute + *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", g_log_en); +} + +static ssize_t enable_store(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) +{ + int val; + if (kstrtos32(buf, 0, &val)) + return -EINVAL; + + g_log_en = val; + if (g_log_en) + alarm_start_relative(&fg_log_thread_alarm, + ns_to_ktime((unsigned long long)(g_alarm_time) * NSEC_PER_SEC)); + else + alarm_cancel(&fg_log_thread_alarm); + + return count; +} +static DEVICE_ATTR_RW(enable); + +static ssize_t alarm_time_show(struct device *dev, struct device_attribute + *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", g_alarm_time); +} + +static ssize_t alarm_time_store(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) +{ + int val; + if (kstrtos32(buf, 0, &val)) + return -EINVAL; + + g_alarm_time = val; + + return count; +} +static DEVICE_ATTR_RW(alarm_time); + +static struct attribute *log_attrs[] = { + &dev_attr_enable.attr, + &dev_attr_alarm_time.attr, + NULL, +}; +ATTRIBUTE_GROUPS(log); + +static enum alarmtimer_restart fg_log_thread_func(struct alarm *alarm, ktime_t now) +{ + queue_delayed_work(private_chg_wq, &print_tct_charge_worker, 0); + alarm_forward_now(&fg_log_thread_alarm, + ns_to_ktime((unsigned long long)(g_alarm_time) * NSEC_PER_SEC)); + return ALARMTIMER_RESTART; +} + +static void fg_log_thread_init(void) +{ + alarm_init(&fg_log_thread_alarm, ALARM_REALTIME, fg_log_thread_func); +} + +static int __init tct_charger_battery_log_init(void) +{ + int rc = 0; + struct platform_device *log_pdev = NULL; + struct power_supply *batt_psy = NULL; + struct smb_charger *chg = NULL; + batt_psy = power_supply_get_by_name("battery"); + if (!batt_psy) + return -ENODEV; + chg = power_supply_get_drvdata(batt_psy); + if (!chg) { + pr_err("[%s]chg is null\n", __func__); + return -ENODATA; + } + g_qcom_chg = chg; + + log_pdev = platform_device_register_data(NULL, "tct_charge_log", + PLATFORM_DEVID_NONE, chg, sizeof(*chg)); + if (IS_ERR(log_pdev)) { + pr_err("Failed to register tct_charge_log platform device\n"); + rc = PTR_ERR(log_pdev); + goto err_pdev_register; + } + + rc = sysfs_create_groups(&log_pdev->dev.kobj, log_groups); + if (rc < 0) { + pr_err("Couldn't create sysfs files rc=%d\n", rc); + goto err_group; + } + + fg_log_thread_init(); + + INIT_DELAYED_WORK(&print_tct_charge_worker, print_tct_charge_work); + if (g_log_en) + alarm_start_relative(&fg_log_thread_alarm, + ns_to_ktime((unsigned long long)(g_alarm_time) * NSEC_PER_SEC)); + + return 0; +err_group: + platform_device_unregister(log_pdev); +err_pdev_register: + return rc; +} +late_initcall(tct_charger_battery_log_init); diff --git a/drivers/power/supply/qns_system_v2.c b/drivers/power/supply/qns_system_v2.c new file mode 100644 index 0000000000000000000000000000000000000000..6e035185b17555a7a939d5b83d6205052696845a --- /dev/null +++ b/drivers/power/supply/qns_system_v2.c @@ -0,0 +1,631 @@ +/* + * qns_system.c version 2.0 + * Qnovo QNS wrapper implementation. Compatible with kernel 4.14. + * Copyright (C) 2014 Qnovo Corp + * Miro Zmrzli + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include + +// Set the sign (-1 or 1) so that /sys/class/qns/current_now returns negative +// values while discharging and positive while charging. +#define READ_CURRENT_SIGN (1) + +#define CHARGE_CURRENT_PROP POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX +#define CHARGE_VOLTAGE_PROP POWER_SUPPLY_PROP_VOLTAGE_MAX + +#define IBATMANAME "battery" + +#define QNS_OK 0 +#define QNS_ERROR (-1) + +struct qns_data +{ + struct power_supply * battery_psy; + struct alarm alarm; + bool alarm_inited; + int alarm_value; + struct wakeup_source *wakelock; + bool wakelock_inited; + bool wakelock_held; + struct wakeup_source *charge_wakelock; + bool charge_wakelock_inited; + bool charge_wakelock_held; + int options; +}; + +static struct qns_data data; + +static bool qns_has_psy(void) +{ + if(data.battery_psy == NULL) + { + data.battery_psy = power_supply_get_by_name(IBATMANAME); + if(data.battery_psy == NULL) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME); + return false; + } + } + return true; +} + +static int qns_set_ibat(int ibatmA) +{ + union power_supply_propval propVal = {ibatmA * 1000,}; + + pr_info("QNS: new charge current:%d mA", ibatmA); + + if(!qns_has_psy()) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't set the current!"); + return QNS_ERROR; + } + + if(power_supply_set_property(data.battery_psy, + CHARGE_CURRENT_PROP, &propVal) != 0) + { + pr_info("QNS: ERROR: unable to set charging current! Does " IBATMANAME " have " + "POWER_SUPPLY_PROP_MAX_CHARGE_CURRENT property?"); + return QNS_ERROR; + } + return QNS_OK; +} + +static int qns_set_vbat(int vbatmV) +{ + union power_supply_propval propVal = {vbatmV * 1000,}; + + pr_info("QNS: new charge voltage:%d mV", vbatmV); + + if(!qns_has_psy()) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't set the voltage!"); + return QNS_ERROR; + } + + if(power_supply_set_property(data.battery_psy, + CHARGE_VOLTAGE_PROP, &propVal) != 0) + { + pr_info("QNS: ERROR: unable to set charging voltage! Does " IBATMANAME " have " + "POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE property?"); + return QNS_ERROR; + } + return QNS_OK; +} + +static bool qns_is_charging(void) +{ + union power_supply_propval propVal = {0, }; + + if(!qns_has_psy()) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't read charging state!"); + return false; + } + + if(power_supply_get_property(data.battery_psy, POWER_SUPPLY_PROP_STATUS, + &propVal) != 0) + { + pr_info("QNS: ERROR: unable to read charger properties! Does " IBATMANAME " have " + "POWER_SUPPLY_PROP_STATUS property?"); + return false; + } + + return propVal.intval == POWER_SUPPLY_STATUS_CHARGING; +} + +static int qns_get_scvt(int *soc, int *c, int *v, int *tx10) +{ + /* + soc in % + c in ma + v in mv + t in 0.1 deg c + */ + union power_supply_propval ret = {0,}; + int retVal = QNS_OK; + + if(!qns_has_psy()) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't read soc/c/v/t!"); + retVal = QNS_ERROR; + } + + if (data.battery_psy) + { + if(c != NULL) + { + if(power_supply_get_property(data.battery_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_CURRENT_NOW"); + *c = 0; + retVal = QNS_ERROR; + } + else + *c = READ_CURRENT_SIGN * ret.intval / 1000; + } + + if(v != NULL) + { + if(power_supply_get_property(data.battery_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_VOLTAGE_NOW"); + *v = 0; + retVal = QNS_ERROR; + } + else + *v = ret.intval / 1000; + } + + if(tx10 != NULL) + { + if(power_supply_get_property(data.battery_psy, + POWER_SUPPLY_PROP_TEMP, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_TEMP"); + *tx10 = 0; + retVal = QNS_ERROR; + } + else + *tx10 = ret.intval; + } + + if(soc != NULL) + { + if(power_supply_get_property(data.battery_psy, + POWER_SUPPLY_PROP_CAPACITY, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery property POWER_SUPPLY_PROP_CAPACITY"); + *soc = 0; + retVal = QNS_ERROR; + } + else + *soc = ret.intval; + } + } + else + { + pr_info("QNS: battery power supply is not registered yet."); + if(c != NULL) *c = 0; + if(v != NULL) *v = 4000; + if(tx10 != NULL) *tx10 = 250; + if(soc != NULL) *soc = 50; + retVal = QNS_ERROR; + } + return retVal; +} + +static int qns_get_fcc(int *fcc, int *design) +{ + union power_supply_propval ret = {0,}; + int retVal = QNS_OK; + + if(!qns_has_psy()) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't read fcc/design!"); + return QNS_ERROR; + } + + if(fcc != NULL) + { + if(power_supply_get_property(data.battery_psy, + POWER_SUPPLY_PROP_CHARGE_FULL, &ret) != 0) + { + pr_info("QNS: ERRROR: unable to read battery POWER_SUPPLY_PROP_CHARGE_FULL property."); + *fcc = 0; + retVal = QNS_ERROR; + } + else + *fcc = ret.intval / 1000; + } + if(design != NULL) + { + if(power_supply_get_property(data.battery_psy, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, &ret) != 0) + { + pr_info("QNS: ERROR: unable to read battery POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN property."); + *design = 0; + retVal = QNS_ERROR; + } + else + *design = ret.intval / 1000; + } + + return retVal; +} + +static int qns_get_battery_type(const char **battery_type) +{ + union power_supply_propval ret = {0,}; + int retVal = QNS_OK; + + if(!qns_has_psy()) + { + pr_info("QNS: ERROR: unable to get " IBATMANAME ". Can't read battery_type!"); + *battery_type = "Unknown"; + return QNS_ERROR; + } + + if(battery_type != NULL) + { + if(power_supply_get_property(data.battery_psy, + POWER_SUPPLY_PROP_BATTERY_TYPE, &ret) != 0) + { + //pr_info("QNS: ERRROR: unable to read battery POWER_SUPPLY_PROP_BATTERY_TYPE property."); + *battery_type = "fp4-veken_v4"; + retVal = QNS_OK; + } + else + *battery_type = ret.strval; + } + + return retVal; +} + +/* charging_state handlers */ + +static ssize_t charging_state_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", qns_is_charging() ? 1 : 0); +} + +static CLASS_ATTR_RO(charging_state); + + +/* current_now handlers */ + +static int c, v; + +static ssize_t current_now_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + qns_get_scvt(NULL, &c, &v, NULL); + return scnprintf(buf, PAGE_SIZE, "%d\n", c); +} + +static CLASS_ATTR_RO(current_now); + + +/* voltage handlers */ + +static ssize_t voltage_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", v); +} + +static CLASS_ATTR_RO(voltage); + + +/* temp handlers */ + +static ssize_t temp_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + int t; + qns_get_scvt(NULL, NULL, NULL, &t); + return scnprintf(buf, PAGE_SIZE, "%d\n", t); +} + +static CLASS_ATTR_RO(temp); + + +/* fcc handlers */ + +static ssize_t fcc_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + int t = 0; + qns_get_fcc(&t, NULL); + return scnprintf(buf, PAGE_SIZE, "%d\n", t); +} + +static CLASS_ATTR_RO(fcc); + + +/* design handlers */ + +static ssize_t design_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + int t = 0; + qns_get_fcc(NULL, &t); + return scnprintf(buf, PAGE_SIZE, "%d\n", t); +} + +static CLASS_ATTR_RO(design); + + +/* soc handlers */ + +static ssize_t soc_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + int t = 0; + qns_get_scvt(&t, NULL, NULL, NULL); + return scnprintf(buf, PAGE_SIZE, "%d\n", t); +} + +static CLASS_ATTR_RO(soc); + + +/* battery_type handlers */ + +static ssize_t battery_type_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + const char *battery_type; + qns_get_battery_type(&battery_type); + return scnprintf(buf, PAGE_SIZE, "%s\n", battery_type); +} + +static CLASS_ATTR_RO(battery_type); + + +/* charge_current handlers */ + +static ssize_t charge_current_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + int val = 0, ret = -EINVAL; + + ret = kstrtoint(buf, 10, &val); + + if (!ret && (val > 0)) + { + qns_set_ibat(val); + return count; + } + + return -EINVAL; +} + +static CLASS_ATTR_WO(charge_current); + + +/* charge_voltage handlers */ + +static ssize_t charge_voltage_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + int val = 0, ret = -EINVAL; + + ret = kstrtoint(buf, 10, &val); + + if (!ret && (val > 0)) + { + qns_set_vbat(val); + return count; + } + + return -EINVAL; +} + +static CLASS_ATTR_WO(charge_voltage); + + +/* options handlers */ + +static ssize_t options_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", data.options); +} + +static ssize_t options_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + int val = 0, ret = -EINVAL; + + ret = kstrtoint(buf, 10, &val); + + if (!ret && (val >= 0)) + { + data.options = val; + return count; + } + + return -EINVAL; +} + +static CLASS_ATTR_RW(options); + + +/* alarm handlers */ + +static enum alarmtimer_restart qns_alarm_handler(struct alarm * alarm, ktime_t now) +{ + pr_info("QNS: ALARM! System wakeup!"); + __pm_stay_awake(data.wakelock); + data.wakelock_held = true; + data.alarm_value = 1; + return ALARMTIMER_NORESTART; +} + +enum alarm_values +{ + CHARGE_WAKELOCK = -4, + CHARGE_WAKELOCK_RELEASE = -3, + HANDLED = -2, + CANCEL = -1, + IMMEDIATE = 0, +}; + +static ssize_t alarm_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", data.alarm_value); +} + +static ssize_t alarm_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + int val = 0, ret = -EINVAL; + ktime_t next_alarm; + + ret = kstrtoint(buf, 10, &val); + if(!data.wakelock_inited) + { + data.wakelock=wakeup_source_register(NULL, "QnovoQNS"); + data.wakelock_inited = true; + } + + if(!data.charge_wakelock_inited) + { + data.charge_wakelock=wakeup_source_register(NULL, "QnovoQNS"); + data.charge_wakelock_inited = true; + } + if (!ret) + { + if(val == CHARGE_WAKELOCK) + { + if(!data.charge_wakelock_held) + { + pr_info("QNS: Alarm: acquiring charge_wakelock via CHARGE_WAKELOCK"); + __pm_stay_awake(data.charge_wakelock); + data.charge_wakelock_held = true; + } + } + else if(val == CHARGE_WAKELOCK_RELEASE) + { + if(data.charge_wakelock_held) + { + pr_info("QNS: Alarm: releasing charge_wakelock via CHARGE_WAKELOCK_RELEASE"); + __pm_relax(data.charge_wakelock); + data.charge_wakelock_held = false; + } + } + else if(val == HANDLED) + { + if(data.wakelock_held) + { + pr_info("QNS: Alarm: releasing wakelock via HANDLED"); + __pm_relax(data.wakelock); + } + data.alarm_value = 0; + data.wakelock_held = false; + } + else if(val == CANCEL) + { + if(data.alarm_inited) + { + alarm_cancel(&data.alarm); + } + data.alarm_value = 0; + if(data.wakelock_held) + { + pr_info("QNS: Alarm: releasing wakelock via CANCEL"); + __pm_relax(data.wakelock); + } + data.wakelock_held = false; + } + else if(val == IMMEDIATE) + { + if(!data.wakelock_held) + { + pr_info("QNS: Alarm: acquiring wakelock via IMMEDIATE"); + __pm_stay_awake(data.wakelock); + data.wakelock_held = true; + } + } + else if(val > 0) + { + if(!data.alarm_inited) + { + alarm_init(&data.alarm, ALARM_REALTIME, qns_alarm_handler); + data.alarm_inited = true; + } + + next_alarm = ktime_set(val, 0); + alarm_start_relative(&data.alarm, next_alarm); + + if(data.wakelock_held) + { + pr_info("QNS: Alarm: releasing wakelock via alarm>0"); + __pm_relax(data.wakelock); + } + data.alarm_value = 0; + data.wakelock_held = false; + } + return count; + } + + return -EINVAL; +} + +static CLASS_ATTR_RW(alarm); + + +static struct attribute *qns_class_attrs[] = { + &class_attr_charging_state.attr, + &class_attr_current_now.attr, + &class_attr_voltage.attr, + &class_attr_temp.attr, + &class_attr_fcc.attr, + &class_attr_design.attr, + &class_attr_soc.attr, + &class_attr_battery_type.attr, + &class_attr_charge_current.attr, + &class_attr_charge_voltage.attr, + &class_attr_options.attr, + &class_attr_alarm.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(qns_class); + +static struct class qns_class = +{ + .name = "qns", + .owner = THIS_MODULE, + .class_groups = qns_class_groups +}; + +static int qns_init(void) +{ + memset(&data, 0, sizeof(data)); + data.options = -1; + + class_register(&qns_class); + return 0; +} + +static void qns_exit(void) +{ + if(data.wakelock_held) + __pm_relax(data.wakelock); + + data.wakelock_held = false; + wakeup_source_unregister(data.wakelock); + + if(data.charge_wakelock_held) + __pm_relax(data.charge_wakelock); + + data.charge_wakelock_held = false; + wakeup_source_unregister(data.charge_wakelock); + + class_unregister(&qns_class); +} + +module_init(qns_init); +module_exit(qns_exit); + +MODULE_AUTHOR("Miro Zmrzli "); +MODULE_DESCRIPTION("QNS System Driver v2"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("QNS"); diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 45394b8452458e26baf723164215bc11e1d25772..73deeea465c744b1bf7e89ecee174d93c6f26769 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -145,5 +145,6 @@ obj-$(CONFIG_REGULATOR_REFGEN) += refgen.o obj-$(CONFIG_REGULATOR_SPM) += spm-regulator.o obj-$(CONFIG_REGULATOR_RPMH) += rpmh-regulator.o obj-$(CONFIG_REGULATOR_STUB) += stub-regulator.o +obj-y += esim-regulator.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/esim-regulator.c b/drivers/regulator/esim-regulator.c new file mode 100644 index 0000000000000000000000000000000000000000..9e0c80ca9563e057acd82814cf293de32411bff2 --- /dev/null +++ b/drivers/regulator/esim-regulator.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include + +struct regulator *regulator_l5e = NULL; +const char *regulator_name = "esim_regulator"; + + +static int regulator_status = 0; + + +static ssize_t esim_power_store(struct class *class, + struct class_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + + if ((!strncmp(buf,"1",1))) { + ret = regulator_enable(regulator_l5e); + regulator_status = 1; + } + else { + ret = regulator_enable(regulator_l5e); + regulator_status = 0; + } + + return count; + +} +static ssize_t esim_power_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", regulator_status); +} + + + + + +static struct class_attribute esim_regulator_power = + __ATTR(esim_power, 0665, esim_power_show, esim_power_store); + + + + + + +static int esim_regulator_creat_file(void) +{ + int ret; + struct class *esim_regulator_class; + + /* esim_regulator create (//class/esim_regulator) */ + esim_regulator_class = class_create(THIS_MODULE, "esim_regulator"); + if (IS_ERR(esim_regulator_class)) { + ret = PTR_ERR(esim_regulator_class); + printk(KERN_ERR "esim_regulator_class: couldn't create esim_regulator\n"); + } + if (class_create_file(esim_regulator_class, &esim_regulator_power)) { + + pr_err("%s: esim_regulator_class: couldn't create sub file node\n", __func__); + } + + return 0; + +} + + +static int esim_regulator_probe(struct platform_device *pdev) +{ + int ret = 0; + + regulator_l5e = regulator_get(&pdev->dev, regulator_name); + if (IS_ERR(regulator_l5e)) { + printk("regulator_get regulator fail\n"); + //return -EINVAL; + } + else { + ret = regulator_set_voltage(regulator_l5e, 1810000, 1810000); + if (ret) + { + printk("Could not set to 1.81v.\n"); + } + } + + ret = esim_regulator_creat_file(); + + return ret; + +} + + +static int esim_regulator_remove(struct platform_device *pdev) +{ + + + return 0; +} + + +static const struct of_device_id esim_regulator_dt_match[] = { + {.compatible = "qcom,esim-power"}, + {} +}; + +MODULE_DEVICE_TABLE(of, esim_regulator_dt_match); + +static struct platform_driver esim_regulator_driver = { + .probe = esim_regulator_probe, + .remove = esim_regulator_remove, + .shutdown = NULL, + .driver = { + .name = "esim-power", + .of_match_table = esim_regulator_dt_match, + }, +}; + +static int esim_regulator_register_driver(void) +{ + return platform_driver_register(&esim_regulator_driver); +} + + + +static int __init esim_regulator_init(void) +{ + + int ret = 0; + + ret = esim_regulator_register_driver(); + if (ret) { + pr_err("esim_regulator_driver() failed!\n"); + return ret; + } + + return ret; + +} + +module_init(esim_regulator_init); + +static void __exit esim_regulator_exit(void) +{ +} +module_exit(esim_regulator_exit); + +MODULE_DESCRIPTION("Get esim power"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index 972437a2f3cf31304fed55517ce14d0b3b36028b..62cd2520f0c0eb0dc150e8c6890bd4b653f14229 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -1509,7 +1509,7 @@ static struct regulator_ops qpnp_lcdb_ncp_ops = { static int qpnp_lcdb_regulator_register(struct qpnp_lcdb *lcdb, u8 type) { - int rc = 0, off_on_delay = 0, voltage_step = VOLTAGE_STEP_50_MV; + int rc = 0, off_on_delay = 0; struct regulator_init_data *init_data; struct regulator_config cfg = {}; struct regulator_desc *rdesc; @@ -1524,16 +1524,12 @@ static int qpnp_lcdb_regulator_register(struct qpnp_lcdb *lcdb, u8 type) rdesc = &lcdb->ldo.rdesc; rdesc->ops = &qpnp_lcdb_ldo_ops; rdesc->off_on_delay = off_on_delay; - rdesc->n_voltages = ((MAX_VOLTAGE_MV - MIN_VOLTAGE_MV) - / voltage_step) + 1; rdev = lcdb->ldo.rdev; } else if (type == NCP) { node = lcdb->ncp.node; rdesc = &lcdb->ncp.rdesc; rdesc->ops = &qpnp_lcdb_ncp_ops; rdesc->off_on_delay = off_on_delay; - rdesc->n_voltages = ((MAX_VOLTAGE_MV - MIN_VOLTAGE_MV) - / voltage_step) + 1; rdev = lcdb->ncp.rdev; } else { pr_err("Invalid regulator type %d\n", type); diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 9dfe4b32fb320ba56c0219c9f9199202920eb13b..691b14adc111cb230fd8427a9a26ae36425300b7 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3374,15 +3374,13 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb, mdwc->vbus_active = event; } - /* - * Drive a pulse on DP to ensure proper CDP detection - * and only when the vbus connect event is a valid one. - */ +#if !defined(CONFIG_TCT_PM7250_COMMON) if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP && - mdwc->vbus_active && !mdwc->check_eud_state) { + mdwc->vbus_active) { dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n"); usb_phy_drive_dp_pulse(mdwc->hs_phy, DP_PULSE_WIDTH_MSEC); } +#endif if (dwc3_is_otg_or_drd(dwc) && !mdwc->in_restart) queue_work(mdwc->dwc3_wq, &mdwc->resume_work); @@ -3695,6 +3693,23 @@ static int dwc3_msm_probe(struct platform_device *pdev) int ret = 0, size = 0, i; u32 val; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (dev && node && of_property_read_bool(node, "extcon")) { + struct extcon_dev *edev=NULL; + edev = extcon_get_edev_by_phandle(dev, 0); + if (IS_ERR(edev)) { + if (PTR_ERR(edev) == -EPROBE_DEFER) { + pr_err("Could not get extcon, deferring dwc3-msm probe\n"); + return -EPROBE_DEFER; + } else { + pr_err("Could not get extcon(%ld), stop dwc3-msm probe\n", + PTR_ERR(edev)); + return PTR_ERR(edev); + } + } + } +#endif + mdwc = devm_kzalloc(&pdev->dev, sizeof(*mdwc), GFP_KERNEL); if (!mdwc) return -ENOMEM; @@ -4280,8 +4295,11 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) } if (on) { +#if defined(CONFIG_TCT_PM7250_COMMON) + dev_err(mdwc->dev, "%s: turn on host\n", __func__); +#else dev_dbg(mdwc->dev, "%s: turn on host\n", __func__); - +#endif mdwc->hs_phy->flags |= PHY_HOST_MODE; pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "StrtHost gync", @@ -4364,7 +4382,11 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) schedule_delayed_work(&mdwc->perf_vote_work, msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); } else { +#if defined(CONFIG_TCT_PM7250_COMMON) + dev_err(mdwc->dev, "%s: turn off host\n", __func__); +#else dev_dbg(mdwc->dev, "%s: turn off host\n", __func__); +#endif usb_unregister_atomic_notify(&mdwc->usbdev_nb); if (!IS_ERR_OR_NULL(mdwc->vbus_reg)) @@ -4440,8 +4462,13 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) atomic_read(&mdwc->dev->power.usage_count)); if (on) { +#if defined(CONFIG_TCT_PM7250_COMMON) + dev_err(mdwc->dev, "%s: turn on gadget %s\n", + __func__, dwc->gadget.name); +#else dev_dbg(mdwc->dev, "%s: turn on gadget %s\n", __func__, dwc->gadget.name); +#endif dwc3_override_vbus_status(mdwc, true); usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); @@ -4483,8 +4510,13 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) schedule_delayed_work(&mdwc->perf_vote_work, msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); } else { + #if defined(CONFIG_TCT_PM7250_COMMON) + dev_err(mdwc->dev, "%s: turn off gadget %s\n", + __func__, dwc->gadget.name); + #else dev_dbg(mdwc->dev, "%s: turn off gadget %s\n", __func__, dwc->gadget.name); + #endif cancel_delayed_work_sync(&mdwc->perf_vote_work); msm_dwc3_perf_vote_update(mdwc, false); pm_qos_remove_request(&mdwc->pm_qos_req_dma); diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5d99fb6900ffce5b5f6bf4cd64c8ae477b1ce4ac..d5d38670f936dd15d1c23a2db76817df87a6c6a3 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2303,7 +2303,8 @@ int composite_dev_prepare(struct usb_composite_driver *composite, if (!cdev->req) return -ENOMEM; - cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ, GFP_KERNEL); + cdev->req->buf = kzalloc(USB_COMP_EP0_BUFSIZ + + (gadget->extra_buf_alloc), GFP_KERNEL); if (!cdev->req->buf) goto fail; diff --git a/drivers/usb/pd/Kconfig b/drivers/usb/pd/Kconfig index 19b5228aec63d0f9df46114a9f7992cbe7a719d6..6c15e0b4c1840a81fd559d0d8151a0d14379bda8 100644 --- a/drivers/usb/pd/Kconfig +++ b/drivers/usb/pd/Kconfig @@ -28,4 +28,15 @@ config QPNP_USB_PDPHY The is used to handle the PHY layer communication of the Power Delivery stack. +# Jin.wang added here to enable different usbpd logs level +config USB_PD_LOG_LVL + int "USBPD Log level(0,3)" + range 0 3 + default 1 + help + enable different log level for usbpd debug. 0 for no logs, + 1 for error logs only, 2 for debug logs only(no error log), + 3 for all logs. +# Jin.wang added done. + endmenu diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6dca69d619b46c2c32565bc71af7f94b5f5a3e63..57e59e3ce20c61d121492d54cae660fdce8f85fb 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -3,6 +3,10 @@ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ +#if defined(CONFIG_TCT_PM7250_COMMON) +#define pr_fmt(fmt) "[PE]:" fmt +#endif + #include #include #include @@ -193,6 +197,36 @@ enum vdm_state { }; static void *usbpd_ipc_log; +#if defined(CONFIG_TCT_PM7250_COMMON) +enum { + LOG_LEVEL_ERR = BIT(0), + LOG_LEVEL_DEBUG = BIT(1), + LOG_LEVEL_ALL = 0xFF, +}; + +static int pdlog = CONFIG_USB_PD_LOG_LVL; +module_param(pdlog, int, S_IRUGO|S_IWUSR); + +#define usbpd_err(dev, fmt, ...) \ + do { \ + if (pdlog & LOG_LEVEL_ERR) { \ + ipc_log_string(usbpd_ipc_log, "%s(): " fmt, __func__, \ + ##__VA_ARGS__); \ + pr_err_ratelimited("%s: " fmt, __func__, ##__VA_ARGS__); \ + } \ + } while (0) + +#define usbpd_dbg(dev, fmt, ...) \ + do { \ + if (pdlog & LOG_LEVEL_DEBUG) \ + ipc_log_string(usbpd_ipc_log, "%s(): " fmt, __func__, \ + ##__VA_ARGS__); \ + pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \ + } while (0) + +#define usbpd_info usbpd_err +#define usbpd_warn usbpd_dbg +#else #define usbpd_dbg(dev, fmt, ...) do { \ ipc_log_string(usbpd_ipc_log, "%s: %s: " fmt, dev_name(dev), __func__, \ ##__VA_ARGS__); \ @@ -216,8 +250,13 @@ static void *usbpd_ipc_log; ##__VA_ARGS__); \ dev_err(dev, fmt, ##__VA_ARGS__); \ } while (0) +#endif +#if defined(CONFIG_TCT_PM7250_COMMON) +#define NUM_LOG_PAGES (30) +#else #define NUM_LOG_PAGES 10 +#endif /* Timeouts (in ms) */ #define ERROR_RECOVERY_TIME 25 @@ -351,9 +390,18 @@ static void *usbpd_ipc_log; #define STOP_USB_HOST 0 #define START_USB_HOST 1 +#if defined(CONFIG_TCT_PM7250_COMMON) +#define PD_MIN_SINK_CURRENT 500 +#else #define PD_MIN_SINK_CURRENT 900 +#endif +#if defined(CONFIG_TCT_PM7250_COMMON) +static const u32 default_src_caps[] = { 0x26019032 }; /* VSafe5V @ 0.5A */ +#else static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */ +#endif + static const u32 default_snk_caps[] = { 0x2601912C }; /* VSafe5V @ 3A */ struct vdm_tx { @@ -541,6 +589,10 @@ static unsigned int get_connector_type(struct usbpd *pd) static inline void stop_usb_host(struct usbpd *pd) { +#if defined(CONFIG_TCT_PM7250_COMMON) + usbpd_info(&pd->dev, "stop usb host \n"); +#endif + extcon_set_state_sync(pd->extcon, EXTCON_USB_HOST, 0); } @@ -550,11 +602,19 @@ static inline void start_usb_host(struct usbpd *pd, bool ss) union extcon_property_value val; int ret = 0; +#if defined(CONFIG_TCT_PM7250_COMMON) + usbpd_info(&pd->dev, "start usb host with ss:%d, cc=%d\n", ss, cc); +#endif + val.intval = (cc == ORIENTATION_CC2); extcon_set_property(pd->extcon, EXTCON_USB_HOST, EXTCON_PROP_USB_TYPEC_POLARITY, val); - +//support USB3.0 +#if 0//defined(CONFIG_TCT_PM7250_COMMON) + val.intval = 0; +#else val.intval = ss; +#endif extcon_set_property(pd->extcon, EXTCON_USB_HOST, EXTCON_PROP_USB_SS, val); @@ -570,6 +630,10 @@ static inline void start_usb_host(struct usbpd *pd, bool ss) static inline void stop_usb_peripheral(struct usbpd *pd) { +#if defined(CONFIG_TCT_PM7250_COMMON) + usbpd_info(&pd->dev, "stop usb peripheral \n"); +#endif + extcon_set_state_sync(pd->extcon, EXTCON_USB, 0); } @@ -578,14 +642,26 @@ static inline void start_usb_peripheral(struct usbpd *pd) enum plug_orientation cc = usbpd_get_plug_orientation(pd); union extcon_property_value val; +#if defined(CONFIG_TCT_PM7250_COMMON) + usbpd_info(&pd->dev, "start usb peripheral with cc=%d\n", cc); +#endif + val.intval = (cc == ORIENTATION_CC2); extcon_set_property(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_TYPEC_POLARITY, val); +#if 0// defined(CONFIG_TCT_PM7250_COMMON) + val.intval = 0; +#else val.intval = 1; +#endif extcon_set_property(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_SS, val); +#if defined(CONFIG_TCT_PM7250_COMMON) + val.intval = 0; +#else val.intval = pd->typec_mode > POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ? 1 : 0; +#endif extcon_set_property(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_TYPEC_MED_HIGH_CURRENT, val); @@ -2022,15 +2098,30 @@ static int enable_vbus(struct usbpd *pd) if (!pd->vbus) { pd->vbus = devm_regulator_get(pd->dev.parent, "vbus"); if (IS_ERR(pd->vbus)) { +#if defined(CONFIG_TCT_PM7250_COMMON) + pd->vbus = NULL; +#endif usbpd_err(&pd->dev, "Unable to get vbus\n"); return -EAGAIN; } } + +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!pd->vbus_enabled) { + usbpd_err(&pd->dev, "[Enable]:otg_vbus\n"); + ret = regulator_enable(pd->vbus); + if (ret) + usbpd_err(&pd->dev, "Unable to enable vbus (%d)\n", ret); + + pd->vbus_enabled = true; + } +#else ret = regulator_enable(pd->vbus); if (ret) usbpd_err(&pd->dev, "Unable to enable vbus (%d)\n", ret); else pd->vbus_enabled = true; +#endif count = 10; /* @@ -3405,12 +3496,23 @@ static void handle_state_vcs_wait_for_vconn(struct usbpd *pd, /* Enters new state and executes actions on entry */ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) { +#if defined(CONFIG_TCT_PM7250_COMMON) + usbpd_dbg(&pd->dev, "cs: %d->%d\n", + pd->current_state, next_state); + usbpd_dbg(&pd->dev, "pr:%d, dr:%d, tm:%d, ips:%d, hrr:%d\n", + pd->current_pr, pd->current_dr, + pd->typec_mode, pd->in_pr_swap, + pd->hard_reset_recvd); +#endif + if (pd->hard_reset_recvd) /* let usbpd_sm handle it */ return; +#if !defined(CONFIG_TCT_PM7250_COMMON) usbpd_dbg(&pd->dev, "%s -> %s\n", usbpd_state_strings[pd->current_state], usbpd_state_strings[next_state]); +#endif pd->current_state = next_state; @@ -3515,15 +3617,23 @@ static void handle_disconnect(struct usbpd *pd) POWER_SUPPLY_PROP_PD_ACTIVE, &val); if (pd->vbus_enabled) { +#if defined(CONFIG_TCT_PM7250_COMMON) + usbpd_err(&pd->dev, "[Disable]:otg_vbus\n"); +#endif regulator_disable(pd->vbus); pd->vbus_enabled = false; } reset_vdm_state(pd); +#if defined(CONFIG_TCT_PM7250_COMMON) + stop_usb_host(pd); + stop_usb_peripheral(pd); +#else if (pd->current_dr == DR_UFP) stop_usb_peripheral(pd); else if (pd->current_dr == DR_DFP) stop_usb_host(pd); +#endif pd->current_dr = DR_NONE; @@ -3637,6 +3747,12 @@ static void usbpd_sm(struct work_struct *w) } spin_unlock_irqrestore(&pd->rx_lock, flags); +#if defined(CONFIG_TCT_PM7250_COMMON) + if(rx_msg) + usbpd_dbg(&pd->dev, "rx_msg={%04x,%04x}\n", + rx_msg->hdr, rx_msg->data_len); +#endif + /* Disconnect? */ if (pd->current_pr == PR_NONE) { if (pd->current_state == PE_UNKNOWN && @@ -3754,8 +3870,12 @@ static int usbpd_process_typec_mode(struct usbpd *pd, pd->current_pr = PR_SINK; +#if defined(CONFIG_TCT_PM7250_COMMON) + eval.intval = 0; +#else eval.intval = typec_mode > POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ? 1 : 0; +#endif extcon_set_property(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_TYPEC_MED_HIGH_CURRENT, eval); break; @@ -3774,8 +3894,17 @@ static int usbpd_process_typec_mode(struct usbpd *pd, break; case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY: +#if defined(CONFIG_TCT_PM7250_COMMON) + usbpd_info(&pd->dev, "Type-C Sink Debug Accessory connected\n"); +#else usbpd_info(&pd->dev, "Type-C Debug Accessory connected\n"); +#endif break; +#if defined(CONFIG_TCT_PM7250_COMMON) + case POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY: + usbpd_info(&pd->dev, "Type-C Source Debug Accessory connected\n"); + break; +#endif case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: usbpd_info(&pd->dev, "Type-C Analog Audio Adapter connected\n"); break; @@ -3826,9 +3955,14 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) return ret; } +#if defined(CONFIG_TCT_PM7250_COMMON) + if (val.intval == POWER_SUPPLY_TYPE_USB || + val.intval == POWER_SUPPLY_TYPE_USB_CDP) { +#else if (val.intval == POWER_SUPPLY_TYPE_USB || val.intval == POWER_SUPPLY_TYPE_USB_CDP || val.intval == POWER_SUPPLY_TYPE_USB_FLOAT) { +#endif usbpd_dbg(&pd->dev, "typec mode:%d type:%d\n", typec_mode, val.intval); pd->typec_mode = typec_mode; @@ -3927,6 +4061,13 @@ static int usbpd_typec_dr_set(const struct typec_capability *cap, bool do_swap = false; int ret; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (1) { + pr_err("Not support dr set\n"); + return -ENOTSUPP; + } +#endif + usbpd_dbg(&pd->dev, "Setting data role to %d\n", role); if (role == TYPEC_HOST) { @@ -3964,6 +4105,13 @@ static int usbpd_typec_pr_set(const struct typec_capability *cap, bool do_swap = false; int ret; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (1) { + pr_err("Not support pr set\n"); + return -ENOTSUPP; + } +#endif + usbpd_dbg(&pd->dev, "Setting power role to %d\n", role); if (role == TYPEC_SOURCE) { @@ -4001,6 +4149,13 @@ static int usbpd_typec_port_type_set(const struct typec_capability *cap, union power_supply_propval value; int wait_count = 5; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (1) { + pr_err("Not support mode set\n"); + return -ENOTSUPP; + } +#endif + usbpd_dbg(&pd->dev, "Setting mode to %d\n", type); if (type == TYPEC_PORT_DRP) @@ -4114,7 +4269,11 @@ static ssize_t initial_pr_show(struct device *dev, struct usbpd *pd = dev_get_drvdata(dev); const char *pr = "none"; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (pd->typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY) +#else if (pd->typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) +#endif pr = "sink"; else if (pd->typec_mode >= POWER_SUPPLY_TYPEC_SINK) pr = "source"; @@ -4144,7 +4303,11 @@ static ssize_t initial_dr_show(struct device *dev, struct usbpd *pd = dev_get_drvdata(dev); const char *dr = "none"; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (pd->typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY) +#else if (pd->typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) +#endif dr = "ufp"; else if (pd->typec_mode >= POWER_SUPPLY_TYPEC_SINK) dr = "dfp"; diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index fd798920676cf5f4daa90274fc8066c668e65b3e..0ffc8d95c13ff25065052f77e12b8f3389b44c37 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -3,6 +3,10 @@ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ +#if defined(CONFIG_TCT_PM7250_COMMON) +#define pr_fmt(fmt) "[PDPHY]: %s: " fmt, __func__ +#endif + #include #include #include @@ -20,6 +24,11 @@ #include #include "usbpd.h" +#if defined(CONFIG_TCT_PM7250_COMMON) +#include +#endif + + #define USB_PDPHY_MAX_DATA_OBJ_LEN 28 #define USB_PDPHY_MSG_HDR_LEN 2 @@ -790,6 +799,13 @@ static int pdphy_probe(struct platform_device *pdev) unsigned int base; struct usb_pdphy *pdphy; +#if defined(CONFIG_TCT_PM7250_COMMON) + if (!power_supply_get_by_name("usb")) { + pr_err("Could not get USB power_supply, deferring pdphy probe\n"); + return -EPROBE_DEFER; + } +#endif + pdphy = devm_kzalloc(&pdev->dev, sizeof(*pdphy), GFP_KERNEL); if (!pdphy) return -ENOMEM; diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 47d49c92c6710907ca3a766f2237d5d92b521241..cbaef5a8f6a6f335e9c0b44dbedd27c1f516c552 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -3,6 +3,9 @@ * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. */ +#if defined(CONFIG_TCT_PM7250_COMMON) +#define pr_fmt(fmt) "[USB2_PHY]: %s: " fmt, __func__ +#endif #include #include #include diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index 33a47180c2110717978399d7951ad036f3731840..e387f2db7ca93b6c131c973bce7e6216f3cf0855 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -3,6 +3,10 @@ * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. */ +#if defined(CONFIG_TCT_PM7250_COMMON) +#define pr_fmt(fmt) "[USB3_PHY]: %s: " fmt, __func__ +#endif + #include #include #include diff --git a/gen_headers_arm.bp b/gen_headers_arm.bp index 2894fb4a72f1d98cd471448740d4bf159f7cb91f..6b7458e650c4f39d824564fb65df038b868227e4 100644 --- a/gen_headers_arm.bp +++ b/gen_headers_arm.bp @@ -109,6 +109,7 @@ gen_headers_out_arm = [ "drm/via_drm.h", "drm/virtgpu_drm.h", "drm/vmwgfx_drm.h", + "drm/msm_drm_iris.h", "linux/acct.h", "linux/adb.h", "linux/adfs_fs.h", diff --git a/gen_headers_arm64.bp b/gen_headers_arm64.bp index f90c1b771b137cf458ec5c3cf10827809e01ce66..3cd6ecbe4997a2b01e03aed872d7d42f51932701 100644 --- a/gen_headers_arm64.bp +++ b/gen_headers_arm64.bp @@ -104,6 +104,7 @@ gen_headers_out_arm64 = [ "drm/via_drm.h", "drm/virtgpu_drm.h", "drm/vmwgfx_drm.h", + "drm/msm_drm_iris.h", "linux/acct.h", "linux/adb.h", "linux/adfs_fs.h", diff --git a/include/linux/fs.h b/include/linux/fs.h index 33211a2ac522683a1fcbbf22e7ecb1fff17c65d3..ddb36f673e7e2b450e96de9f0a3efe607854a356 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -920,6 +920,7 @@ struct file { struct rcu_head fu_rcuhead; } f_u; struct path f_path; +#define f_dentry f_path.dentry struct inode *f_inode; /* cached value */ const struct file_operations *f_op; diff --git a/include/linux/msm_drm_notify.h b/include/linux/msm_drm_notify.h new file mode 100755 index 0000000000000000000000000000000000000000..67bb67b96e7e9913dd9f1a9d7b579455719ef316 --- /dev/null +++ b/include/linux/msm_drm_notify.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _MSM_DRM_NOTIFY_H_ +#define _MSM_DRM_NOTIFY_H_ + +#include + +/* A hardware display blank change occurred */ +#define MSM_DRM_EVENT_BLANK 0x01 +/* A hardware display blank early change occurred */ +#define MSM_DRM_EARLY_EVENT_BLANK 0x02 + +enum { + /* panel: power on */ + MSM_DRM_BLANK_UNBLANK, + /* panel: power off */ + MSM_DRM_BLANK_POWERDOWN, +}; + +enum msm_drm_display_id { + /* primary display */ + MSM_DRM_PRIMARY_DISPLAY, + /* external display */ + MSM_DRM_EXTERNAL_DISPLAY, + MSM_DRM_DISPLAY_MAX +}; + +struct msm_drm_notifier { + enum msm_drm_display_id id; + void *data; +}; + +#ifdef CONFIG_DRM_MSM +int msm_drm_register_client(struct notifier_block *nb); +int msm_drm_unregister_client(struct notifier_block *nb); +#else +static inline int msm_drm_register_client(struct notifier_block *nb) +{ + return 0; +} + +static inline int msm_drm_unregister_client(struct notifier_block *nb) +{ + return 0; +} +#endif +#endif diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 72fe67bf5efc0f090013d6cb6d3a7518fe5a2458..6a9bc9281e56ae51f6882547e1e40bd469b9f096 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -266,6 +266,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_BUCK_FREQ, POWER_SUPPLY_PROP_BOOST_CURRENT, POWER_SUPPLY_PROP_SAFETY_TIMER_ENABLE, + POWER_SUPPLY_PROP_CONNECTOR_TEMP, POWER_SUPPLY_PROP_CHARGE_DONE, POWER_SUPPLY_PROP_FLASH_ACTIVE, POWER_SUPPLY_PROP_FLASH_TRIGGER, @@ -361,6 +362,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_CP_TOGGLE_SWITCHER, POWER_SUPPLY_PROP_CP_IRQ_STATUS, POWER_SUPPLY_PROP_CP_ILIM, +#if defined(CONFIG_TCT_PM7250_COMMON) + POWER_SUPPLY_PROP_TCL_FIXTEMP, +#endif POWER_SUPPLY_PROP_IRQ_STATUS, POWER_SUPPLY_PROP_PARALLEL_OUTPUT_MODE, POWER_SUPPLY_PROP_CC_TOGGLE_ENABLE, @@ -432,6 +436,9 @@ enum power_supply_typec_mode { POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY, /* Ra only */ /* Acting as sink */ +#if defined(CONFIG_TCT_PM7250_COMMON) + POWER_SUPPLY_TYPEC_SOURCE_DEBUG_ACCESSORY,/* Rd/Rd */ +#endif POWER_SUPPLY_TYPEC_SOURCE_DEFAULT, /* Rp default */ POWER_SUPPLY_TYPEC_SOURCE_MEDIUM, /* Rp 1.5A */ POWER_SUPPLY_TYPEC_SOURCE_HIGH, /* Rp 3A */ diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 342f374792280506175a5fc6a2d67009eca743e3..94ff0460121d83bacd45fb7fa7b4d42624a7c9b8 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -396,6 +396,10 @@ extern struct workqueue_struct *system_freezable_wq; extern struct workqueue_struct *system_power_efficient_wq; extern struct workqueue_struct *system_freezable_power_efficient_wq; +#if defined(CONFIG_TCT_PM7250_COMMON) +extern struct workqueue_struct *private_chg_wq; +#endif + extern struct workqueue_struct * __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6); diff --git a/include/sound/aw882xx_afe.h b/include/sound/aw882xx_afe.h new file mode 100644 index 0000000000000000000000000000000000000000..f8348da49fb4512c03664339b5405d0c3fcbe903 --- /dev/null +++ b/include/sound/aw882xx_afe.h @@ -0,0 +1,14 @@ + +#ifndef __AW882xx_AFE_H__ +#define __AW882xx_AFE_H__ + +struct aw_afe_func { + int (*afe_get_topology)(int port_id); + int (*aw_send_afe_cal_apr)(uint32_t param_id,void *buf, int cmd_size, bool write); + int (*aw_send_afe_rx_module_enable)(void *buf, int size); + int (*aw_send_afe_tx_module_enable)(void *buf, int size); + int (*aw_adm_param_enable)(int port_id, int module_id, int param_id, int enable); +}; + +void aw_reg_fae_func(struct aw_afe_func * fn); +#endif diff --git a/include/uapi/drm/msm_drm_iris.h b/include/uapi/drm/msm_drm_iris.h new file mode 100644 index 0000000000000000000000000000000000000000..c9d19d6d82910de051280b3df68be0a0ac308e5d --- /dev/null +++ b/include/uapi/drm/msm_drm_iris.h @@ -0,0 +1,58 @@ +#ifndef __MSM_DRM_IRIS_H__ +#define __MSM_DRM_IRIS_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DRM_MSM_IRIS_OPERATE_CONF 0x50 +#define DRM_MSM_IRIS_OPERATE_TOOL 0x51 + +enum iris_oprt_type { + IRIS_OPRT_TOOL_DSI, + IRIS_OPRT_CONFIGURE, + IRIS_OPRT_CONFIGURE_NEW, + IRIS_OPRT_CONFIGURE_NEW_GET, + IRIS_OPRT_MAX_TYPE, +}; + +struct msmfb_mipi_dsi_cmd { + __u8 dtype; + __u8 vc; +#define MSMFB_MIPI_DSI_COMMAND_LAST 1 +#define MSMFB_MIPI_DSI_COMMAND_ACK 2 +#define MSMFB_MIPI_DSI_COMMAND_HS 4 +#define MSMFB_MIPI_DSI_COMMAND_BLLP 8 +#define MSMFB_MIPI_DSI_COMMAND_DEBUG 16 +#define MSMFB_MIPI_DSI_COMMAND_TO_PANEL 32 +#define MSMFB_MIPI_DSI_COMMAND_T 64 + + __u32 iris_ocp_type; + __u32 iris_ocp_addr; + __u32 iris_ocp_value; + __u32 iris_ocp_size; + + __u16 flags; + __u16 length; + __u8 *payload; + __u8 response[16]; + __u16 rx_length; + __u8 *rx_buf; +}; + +struct msm_iris_operate_value { + unsigned int type; + unsigned int count; + void *values; +}; + +#define DRM_IOCTL_MSM_IRIS_OPERATE_CONF DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_IRIS_OPERATE_CONF, struct msm_iris_operate_value) +#define DRM_IOCTL_MSM_IRIS_OPERATE_TOOL DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_IRIS_OPERATE_TOOL, struct msm_iris_operate_value) + +#if defined(__cplusplus) +} +#endif + +#endif // __MSM_DRM_IRIS_H__ diff --git a/kernel/workqueue.c b/kernel/workqueue.c index f3ca7e0394b931d4ed354431ce5b095704b5a4e2..75158d34b8fca410a55ec0ed79fd8127b198f70a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -352,6 +352,10 @@ EXPORT_SYMBOL_GPL(system_power_efficient_wq); struct workqueue_struct *system_freezable_power_efficient_wq __read_mostly; EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq); +#if defined(CONFIG_TCT_PM7250_COMMON) +struct workqueue_struct *private_chg_wq __read_mostly; +EXPORT_SYMBOL_GPL(private_chg_wq); +#endif static int worker_thread(void *__worker); static void workqueue_sysfs_unregister(struct workqueue_struct *wq); @@ -5817,6 +5821,13 @@ int __init workqueue_init_early(void) system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient", WQ_FREEZABLE | WQ_POWER_EFFICIENT, 0); + +#if defined(CONFIG_TCT_PM7250_COMMON) + private_chg_wq = alloc_workqueue("private_chg_wq", + WQ_FREEZABLE, 0); + BUG_ON(!private_chg_wq); +#endif + BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq || !system_unbound_wq || !system_freezable_wq || !system_power_efficient_wq || diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c46ecc5508bca244fa2256c2819470af4e6c8a3c..156b55a35a2a37a90bb7a8c098ed122f1c943548 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1102,7 +1102,7 @@ menu "Lock Debugging (spinlocks, mutexes, etc...)" config LOCK_DEBUGGING_SUPPORT bool depends on TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT - default y + default n choice prompt "Perform Action on spinlock bug" diff --git a/mm/shmem.c b/mm/shmem.c index 3a657d3288add9326fa9d0ec9161d1e72a410b7a..7ee6985ddfd946becdfc7b413071e83f1439d3de 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3225,6 +3225,14 @@ static const struct xattr_handler shmem_trusted_xattr_handler = { .set = shmem_xattr_handler_set, }; +//FP4-263, mount tmpfs on /data with tmpfs in production mode, liquan.zhou.t2m, 20210624 +// Task: 9949950, should support user.* in production mode +static const struct xattr_handler shmem_user_xattr_handler = { + .prefix = XATTR_USER_PREFIX, + .get = shmem_xattr_handler_get, + .set = shmem_xattr_handler_set, +}; + static const struct xattr_handler *shmem_xattr_handlers[] = { #ifdef CONFIG_TMPFS_POSIX_ACL &posix_acl_access_xattr_handler, @@ -3232,6 +3240,7 @@ static const struct xattr_handler *shmem_xattr_handlers[] = { #endif &shmem_security_xattr_handler, &shmem_trusted_xattr_handler, + &shmem_user_xattr_handler, // Task: 9949950 //FP4-263, mount tmpfs on /data with tmpfs in production mode, liquan.zhou.t2m, 20210624 NULL }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 33184d00ac4ad094bc4d1581d75481951847a2e5..cefd60ed4837b6dc31b6ad1e6b35bb1275c17ef4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1311,4 +1311,11 @@ config SND_SOC_TPA6130A2 tristate "Texas Instruments TPA6130A2 headphone amplifier" depends on I2C +config SND_SMARTPA_AW882XX + tristate "AW882xx" + depends on I2C + +config T2M_SND_FP4 + tristate "T2M audio changes for FP4" + endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ae7c85e8219f5ff035dacaea3abc4b831296056..d456398fd86459835243e3df7a5764936f269ca0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -515,3 +515,7 @@ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o + +#$(CONFIG_SND_SMARTPA_AW881XX) +#obj-$(CONFIG_SND_SMARTPA_AW881XX) += aw881xx/aw881xx.o aw881xx/aw881xx_monitor.o aw881xx/aw881xx_cali.o +obj-$(CONFIG_SND_SMARTPA_AW882XX) += aw882xx/aw882xx.o aw882xx/awinic_monitor.o aw882xx/awinic_cali.o aw882xx/awinic_dsp.o \ No newline at end of file diff --git a/sound/soc/codecs/aw881xx/aw881xx.c b/sound/soc/codecs/aw881xx/aw881xx.c new file mode 100644 index 0000000000000000000000000000000000000000..feb19c3c4f8817cbeb75b9eeb723044b695bbc30 --- /dev/null +++ b/sound/soc/codecs/aw881xx/aw881xx.c @@ -0,0 +1,2473 @@ +/* Copyright (C) 2020 Tcl Corporation Limited */ +/* + * aw881xx.c aw881xx codec module + * + * Version: v0.1.6 + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw881xx.h" +#include "aw881xx_reg.h" +#include "aw881xx_monitor.h" +#include "aw881xx_cali.h" + +/****************************************************** + * + * Marco + * + ******************************************************/ +#define AW881XX_I2C_NAME "aw881xx_smartpa" + +#define AW881XX_VERSION "v0.1.6" + +#define AW881XX_RATES SNDRV_PCM_RATE_8000_48000 +#define AW881XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define AW_I2C_RETRIES 5 +#define AW_I2C_RETRY_DELAY 5 /* 5ms */ +#define AW_READ_CHIPID_RETRIES 5 +#define AW_READ_CHIPID_RETRY_DELAY 5 /* 5ms */ + +static uint16_t aw881xx_base_addr[] = { + AW881XX_SPK_REG_ADDR, + AW881XX_SPK_DSP_FW_ADDR, + AW881XX_SPK_DSP_CFG_ADDR, + AW881XX_VOICE_REG_ADDR, + AW881XX_VOICE_DSP_FW_ADDR, + AW881XX_VOICE_DSP_CFG_ADDR, + AW881XX_FM_REG_ADDR, + AW881XX_FM_DSP_FW_ADDR, + AW881XX_FM_DSP_CFG_ADDR, + AW881XX_RCV_REG_ADDR, + AW881XX_RCV_DSP_FW_ADDR, + AW881XX_RCV_DSP_CFG_ADDR, +}; + +/****************************************************** + * + * Value + * + ******************************************************/ +static char aw881xx_cfg_name[][AW881XX_CFG_NAME_MAX] = { + /* spk */ + {"aw881xx_pid_xx_spk_reg.bin"}, + {"aw881xx_pid_01_spk_fw.bin"}, + {"aw881xx_pid_01_spk_cfg.bin"}, + /* voice */ + {"aw881xx_pid_xx_voice_reg.bin"}, + {"aw881xx_pid_01_voice_fw.bin"}, + {"aw881xx_pid_01_voice_cfg.bin"}, + /* fm */ + {"aw881xx_pid_xx_fm_reg.bin"}, + {"aw881xx_pid_01_fm_fw.bin"}, + {"aw881xx_pid_01_fm_cfg.bin"}, + /* rcv */ + {"aw881xx_pid_xx_rcv_reg.bin"}, + {"aw881xx_pid_01_rcv_fw.bin"}, + {"aw881xx_pid_01_rcv_cfg.bin"}, +}; + +/****************************************************** + * + * aw881xx append suffix sound channel information + * + ******************************************************/ +static void *aw881xx_devm_kstrdup(struct device *dev, char *buf) +{ + char *str; + + str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (!str) + return str; + + memcpy(str, buf, strlen(buf)); + return str; +} + +void aw881xx_append_suffix(char *format, const char **change_name, + struct aw881xx *aw881xx) +{ + char buf[50]; + + if (!aw881xx->name_suffix) + return; + + snprintf(buf, 50, format, *change_name, aw881xx->name_suffix); + *change_name = aw881xx_devm_kstrdup(aw881xx->dev, buf); + aw_dev_dbg(aw881xx->dev, "%s:change name :%s\n", + __func__, *change_name); +} + +/****************************************************** + * + * aw881xx reg write/read + * + ******************************************************/ +static int aw881xx_i2c_writes(struct aw881xx *aw881xx, + uint8_t reg_addr, uint8_t *buf, uint16_t len) +{ + int ret = -1; + uint8_t *data = NULL; + + data = kmalloc(len + 1, GFP_KERNEL); + if (data == NULL) { + aw_dev_err(aw881xx->dev, "%s: can not allocate memory\n", + __func__); + return -ENOMEM; + } + + data[0] = reg_addr; + memcpy(&data[1], buf, len); + + ret = i2c_master_send(aw881xx->i2c, data, len + 1); + if (ret < 0) + aw_dev_err(aw881xx->dev, + "%s: i2c master send error\n", __func__); + + kfree(data); + + return ret; +} + +static int aw881xx_i2c_reads(struct aw881xx *aw881xx, + uint8_t reg_addr, uint8_t *data_buf, + uint16_t data_len) +{ + int ret; + struct i2c_msg msg[] = { + [0] = { + .addr = aw881xx->i2c->addr, + .flags = 0, + .len = sizeof(uint8_t), + .buf = ®_addr, + }, + [1] = { + .addr = aw881xx->i2c->addr, + .flags = I2C_M_RD, + .len = data_len, + .buf = data_buf, + }, + }; + + ret = i2c_transfer(aw881xx->i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: transfer failed.", __func__); + return ret; + } else if (ret != AW881XX_READ_MSG_NUM) { + aw_dev_err(aw881xx->dev, "%s: transfer failed(size error).\n", + __func__); + return -ENXIO; + } + + return 0; +} + +static int aw881xx_i2c_write(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t reg_data) +{ + int ret = -1; + uint8_t cnt = 0; + uint8_t buf[2]; + + buf[0] = (reg_data & 0xff00) >> 8; + buf[1] = (reg_data & 0x00ff) >> 0; + + while (cnt < AW_I2C_RETRIES) { + ret = aw881xx_i2c_writes(aw881xx, reg_addr, buf, 2); + if (ret < 0) + aw_dev_err(aw881xx->dev, + "%s: i2c_write cnt=%d error=%d\n", + __func__, cnt, ret); + else + break; + cnt++; + } + + return ret; +} + +static int aw881xx_i2c_read(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t *reg_data) +{ + int ret = -1; + uint8_t cnt = 0; + uint8_t buf[2]; + + while (cnt < AW_I2C_RETRIES) { + ret = aw881xx_i2c_reads(aw881xx, reg_addr, buf, 2); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: i2c_read cnt=%d error=%d\n", + __func__, cnt, ret); + } else { + *reg_data = (buf[0] << 8) | (buf[1] << 0); + break; + } + cnt++; + } + + return ret; +} + +static int aw881xx_i2c_write_bits(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t mask, + uint16_t reg_data) +{ + int ret = -1; + uint16_t reg_val = 0; + + ret = aw881xx_i2c_read(aw881xx, reg_addr, ®_val); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: i2c read error, ret=%d\n", + __func__, ret); + return ret; + } + reg_val &= mask; + reg_val |= reg_data; + ret = aw881xx_i2c_write(aw881xx, reg_addr, reg_val); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: i2c read error, ret=%d\n", + __func__, ret); + return ret; + } + + return 0; +} + +int aw881xx_reg_writes(struct aw881xx *aw881xx, + uint8_t reg_addr, uint8_t *buf, uint16_t len) +{ + int ret = -1; + + mutex_lock(&aw881xx->i2c_lock); + ret = aw881xx_i2c_writes(aw881xx, reg_addr, buf, len); + if (ret < 0) + aw_dev_err(aw881xx->dev, "%s: aw881x_i2c_writes fail, ret=%d", + __func__, ret); + mutex_unlock(&aw881xx->i2c_lock); + + return ret; +} + +int aw881xx_reg_write(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t reg_data) +{ + int ret = -1; + + mutex_lock(&aw881xx->i2c_lock); + ret = aw881xx_i2c_write(aw881xx, reg_addr, reg_data); + if (ret < 0) + aw_dev_err(aw881xx->dev, "%s: aw881xx_i2c_write fail, ret=%d", + __func__, ret); + mutex_unlock(&aw881xx->i2c_lock); + + return ret; +} + +int aw881xx_reg_read(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t *reg_data) +{ + int ret = -1; + + mutex_lock(&aw881xx->i2c_lock); + ret = aw881xx_i2c_read(aw881xx, reg_addr, reg_data); + if (ret < 0) + aw_dev_err(aw881xx->dev, "%s: aw881xx_i2c_read fail, ret=%d", + __func__, ret); + mutex_unlock(&aw881xx->i2c_lock); + + return ret; +} + +int aw881xx_reg_write_bits(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t mask, uint16_t reg_data) +{ + int ret = -1; + + mutex_lock(&aw881xx->i2c_lock); + ret = aw881xx_i2c_write_bits(aw881xx, reg_addr, mask, reg_data); + if (ret < 0) + aw_dev_err(aw881xx->dev, + "%s: aw881xx_i2c_write_bits fail, ret=%d", + __func__, ret); + mutex_unlock(&aw881xx->i2c_lock); + + return ret; +} + +int aw881xx_dsp_write(struct aw881xx *aw881xx, + uint16_t dsp_addr, uint16_t dsp_data) +{ + int ret = -1; + + mutex_lock(&aw881xx->i2c_lock); + ret = aw881xx_i2c_write(aw881xx, AW881XX_REG_DSPMADD, dsp_addr); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: i2c write error, ret=%d\n", + __func__, ret); + goto dsp_write_err; + } + + ret = aw881xx_i2c_write(aw881xx, AW881XX_REG_DSPMDAT, dsp_data); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: i2c write error, ret=%d\n", + __func__, ret); + goto dsp_write_err; + } + mutex_unlock(&aw881xx->i2c_lock); + + return ret; + + dsp_write_err: + mutex_unlock(&aw881xx->i2c_lock); + return ret; + +} + +int aw881xx_dsp_read(struct aw881xx *aw881xx, + uint16_t dsp_addr, uint16_t *dsp_data) +{ + int ret = -1; + + mutex_lock(&aw881xx->i2c_lock); + ret = aw881xx_i2c_write(aw881xx, AW881XX_REG_DSPMADD, dsp_addr); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: i2c write error, ret=%d\n", + __func__, ret); + goto dsp_read_err; + } + + ret = aw881xx_i2c_read(aw881xx, AW881XX_REG_DSPMDAT, dsp_data); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: i2c read error, ret=%d\n", + __func__, ret); + goto dsp_read_err; + } + mutex_unlock(&aw881xx->i2c_lock); + + return ret; + + dsp_read_err: + mutex_unlock(&aw881xx->i2c_lock); + return ret; +} + +/****************************************************** + * + * aw881xx control + * + ******************************************************/ +static void aw881xx_run_mute(struct aw881xx *aw881xx, bool mute) +{ + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + if (mute) { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_PWMCTRL, + AW881XX_BIT_PWMCTRL_HMUTE_MASK, + AW881XX_BIT_PWMCTRL_HMUTE_ENABLE); + } else { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_PWMCTRL, + AW881XX_BIT_PWMCTRL_HMUTE_MASK, + AW881XX_BIT_PWMCTRL_HMUTE_DISABLE); + } +} + +void aw881xx_run_pwd(struct aw881xx *aw881xx, bool pwd) +{ + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + if (pwd) { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_SYSCTRL, + AW881XX_BIT_SYSCTRL_PW_MASK, + AW881XX_BIT_SYSCTRL_PW_PDN); + } else { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_SYSCTRL, + AW881XX_BIT_SYSCTRL_PW_MASK, + AW881XX_BIT_SYSCTRL_PW_ACTIVE); + } +} + +static void aw881xx_dsp_enable(struct aw881xx *aw881xx, bool dsp) +{ + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + if (dsp) { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_SYSCTRL, + AW881XX_BIT_SYSCTRL_DSP_MASK, + AW881XX_BIT_SYSCTRL_DSP_WORK); + } else { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_SYSCTRL, + AW881XX_BIT_SYSCTRL_DSP_MASK, + AW881XX_BIT_SYSCTRL_DSP_BYPASS); + } +} + +static void aw881xx_memclk_select(struct aw881xx *aw881xx, unsigned char flag) +{ + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + if (flag == AW881XX_MEMCLK_PLL) { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_SYSCTRL2, + AW881XX_BIT_SYSCTRL2_MEMCLK_MASK, + AW881XX_BIT_SYSCTRL2_MEMCLK_PLL); + } else if (flag == AW881XX_MEMCLK_OSC) { + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_SYSCTRL2, + AW881XX_BIT_SYSCTRL2_MEMCLK_MASK, + AW881XX_BIT_SYSCTRL2_MEMCLK_OSC); + } else { + aw_dev_err(aw881xx->dev, + "%s: unknown memclk config, flag=0x%x\n", + __func__, flag); + } +} + +static int aw881xx_sysst_check(struct aw881xx *aw881xx) +{ + int ret = -1; + unsigned char i; + uint16_t reg_val = 0; + + for (i = 0; i < AW881XX_SYSST_CHECK_MAX; i++) { + aw881xx_reg_read(aw881xx, AW881XX_REG_SYSST, ®_val); + if ((reg_val & (~AW881XX_BIT_SYSST_CHECK_MASK)) == + AW881XX_BIT_SYSST_CHECK) { + ret = 0; + return ret; + } else { + aw_dev_dbg(aw881xx->dev, + "%s: check fail, cnt=%d, reg_val=0x%04x\n", + __func__, i, reg_val); + msleep(2); + } + } + aw_dev_info(aw881xx->dev, "%s: check fail\n", __func__); + + return ret; +} + +int aw881xx_get_sysint(struct aw881xx *aw881xx, uint16_t *sysint) +{ + int ret = -1; + uint16_t reg_val = 0; + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_SYSINT, ®_val); + if (ret < 0) + aw_dev_info(aw881xx->dev, "%s: read sysint fail, ret=%d\n", + __func__, ret); + else + *sysint = reg_val; + + return ret; +} + +int aw881xx_get_iis_status(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_reg_read(aw881xx, AW881XX_REG_SYSST, ®_val); + if (reg_val & AW881XX_BIT_SYSST_PLLS) + ret = 0; + + return ret; +} + +int aw881xx_get_dsp_status(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_reg_read(aw881xx, AW881XX_REG_WDT, ®_val); + if (reg_val) + ret = 0; + + return ret; +} + +int aw881xx_get_dsp_config(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_reg_read(aw881xx, AW881XX_REG_SYSCTRL, ®_val); + if (reg_val & AW881XX_BIT_SYSCTRL_DSP_BYPASS) + aw881xx->dsp_cfg = AW881XX_DSP_BYPASS; + else + aw881xx->dsp_cfg = AW881XX_DSP_WORK; + + return ret; +} + +int aw881xx_get_hmute(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_reg_read(aw881xx, AW881XX_REG_PWMCTRL, ®_val); + if (reg_val & AW881XX_BIT_PWMCTRL_HMUTE_ENABLE) + ret = 1; + else + ret = 0; + + return ret; +} + +static int aw881xx_get_icalk(struct aw881xx *aw881xx, int16_t *icalk) +{ + int ret = -1; + uint16_t reg_val = 0; + uint16_t reg_icalk = 0; + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_EFRM, ®_val); + reg_icalk = (uint16_t) reg_val & AW881XX_EF_ISENSE_GAINERR_SLP_MASK; + + if (reg_icalk & AW881XX_EF_ISENSE_GAINERR_SLP_SIGN_MASK) + reg_icalk = reg_icalk | AW881XX_EF_ISENSE_GAINERR_SLP_NEG; + + *icalk = (int16_t) reg_icalk; + + return ret; +} + +static int aw881xx_get_vcalk(struct aw881xx *aw881xx, int16_t *vcalk) +{ + int ret = -1; + uint16_t reg_val = 0; + uint16_t reg_vcalk = 0; + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_PRODUCT_ID, ®_val); + reg_val = reg_val >> AW881XX_EF_VSENSE_GAIN_SHIFT; + + reg_vcalk = (uint16_t) reg_val & AW881XX_EF_VSENSE_GAIN_MASK; + + if (reg_vcalk & AW881XX_EF_VSENSE_GAIN_SIGN_MASK) + reg_vcalk = reg_vcalk | AW881XX_EF_VSENSE_GAIN_NEG; + + *vcalk = (int16_t) reg_vcalk; + + return ret; +} + +static int aw881xx_dsp_set_vcalb(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + int vcalb; + int icalk; + int vcalk; + int16_t icalk_val = 0; + int16_t vcalk_val = 0; + + ret = aw881xx_get_icalk(aw881xx, &icalk_val); + ret = aw881xx_get_vcalk(aw881xx, &vcalk_val); + + icalk = AW881XX_CABL_BASE_VALUE + AW881XX_ICABLK_FACTOR * icalk_val; + vcalk = AW881XX_CABL_BASE_VALUE + AW881XX_VCABLK_FACTOR * vcalk_val; + + vcalb = (AW881XX_VCAL_FACTOR * AW881XX_VSCAL_FACTOR / + AW881XX_ISCAL_FACTOR) * vcalk / icalk; + + reg_val = (uint16_t) vcalb; + aw_dev_dbg(aw881xx->dev, + "%s: icalk=%d, vcalk=%d, vcalb=%d, reg_val=%d\n", + __func__, icalk, vcalk, vcalb, reg_val); + + ret = aw881xx_dsp_write(aw881xx, AW881XX_DSP_REG_VCALB, reg_val); + + return ret; +} + +static int aw881xx_set_intmask(struct aw881xx *aw881xx, bool flag) +{ + int ret = -1; + + if (flag) + ret = aw881xx_reg_write(aw881xx, AW881XX_REG_SYSINTM, + aw881xx->intmask); + else + ret = aw881xx_reg_write(aw881xx, AW881XX_REG_SYSINTM, + AW881XX_REG_SYSINTM_MASK); + return ret; +} + +static int aw881xx_start(struct aw881xx *aw881xx) +{ + int ret = -1; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_run_pwd(aw881xx, false); + ret = aw881xx_sysst_check(aw881xx); + if (ret < 0) { + aw881xx_run_mute(aw881xx, true); + } else { + aw881xx_run_mute(aw881xx, false); + aw881xx_set_intmask(aw881xx, true); + + if ((aw881xx->monitor.monitor_flag) && + ((aw881xx->scene_mode == AW881XX_SPK_MODE) || + (aw881xx->scene_mode == AW881XX_VOICE_MODE) || + (aw881xx->scene_mode == AW881XX_FM_MODE))) { + aw881xx_monitor_start(&aw881xx->monitor); + } + } + + return ret; +} + +static void aw881xx_stop(struct aw881xx *aw881xx) +{ + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_set_intmask(aw881xx, true); + aw881xx_run_mute(aw881xx, true); + aw881xx_run_pwd(aw881xx, true); + + if (aw881xx->monitor.monitor_flag) + aw881xx_monitor_stop(&aw881xx->monitor); +} + +/***************************************************** + * + * check chip id + * + *****************************************************/ +int aw881xx_update_cfg_name(struct aw881xx *aw881xx) +{ + char aw881xx_head[] = { "aw881xx_pid_" }; + char buf[3]; + uint8_t i = 0, j = 0, j_shift = 0; + uint8_t head_index = 0; + uint16_t cfg_num = 0; + + memcpy(aw881xx->cfg_name, aw881xx_cfg_name, sizeof(aw881xx_cfg_name)); + head_index = sizeof(aw881xx_head) - 1; + + /*add product information */ + snprintf(buf, sizeof(buf), "%02x", aw881xx->pid); + for (i = 0; i < sizeof(aw881xx->cfg_name) / AW881XX_CFG_NAME_MAX; i++) + if (i % AW881XX_MODE_CFG_NUM_MAX) + memcpy(aw881xx->cfg_name[i] + head_index, buf, + sizeof(buf) - 1); + + /*add sound channel information */ + if (aw881xx->name_suffix) { + head_index += AW881XX_ADD_CHAN_NAME_SHIFT; + snprintf(buf, sizeof(buf), "_%s", aw881xx->name_suffix); + for (i = 0; i < sizeof(aw881xx->cfg_name) / AW881XX_CFG_NAME_MAX; i++) { + for (j = strlen(aw881xx->cfg_name[i]); j >= head_index; j--) { + j_shift = j + AW881XX_ADD_CHAN_NAME_SHIFT; + aw881xx->cfg_name[i][j_shift] = aw881xx->cfg_name[i][j]; + } + memcpy(aw881xx->cfg_name[i] + head_index, buf, + sizeof(buf) - 1); + } + } + + cfg_num = sizeof(aw881xx->cfg_name) / AW881XX_CFG_NAME_MAX; + for (i = 0; i < cfg_num; i++) + aw_dev_dbg(aw881xx->dev, "%s: id[%d], [%s]\n", + __func__, i, aw881xx->cfg_name[i]); + + return 0; +} + +int aw881xx_read_dsp_pid(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + + ret = aw881xx_dsp_read(aw881xx, AW881XX_REG_DSP_PID, ®_val); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: failed to read AW881XX_REG_DSP_PID: %d\n", + __func__, ret); + return -EIO; + } + + switch (reg_val) { + case AW881XX_DSP_PID_01: + aw881xx->pid = AW881XX_PID_01; + break; + case AW881XX_DSP_PID_03: + aw881xx->pid = AW881XX_PID_03; + break; + default: + aw_dev_info(aw881xx->dev, "%s: unsupported dsp_pid=0x%04x\n", + __func__, reg_val); + return -EIO; + } + + aw881xx_update_cfg_name(aw881xx); + + return 0; +} + +int aw881xx_read_product_id(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + uint16_t product_id = 0; + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_PRODUCT_ID, ®_val); + if (ret < 0) { + dev_err(aw881xx->dev, "%s: failed to read REG_EFRL: %d\n", + __func__, ret); + return -EIO; + } + + product_id = reg_val & (~AW881XX_BIT_PRODUCT_ID_MASK); + switch (product_id) { + case AW881XX_PID_01: + aw881xx->pid = AW881XX_PID_01; + break; + case AW881XX_PID_03: + aw881xx->pid = AW881XX_PID_03; + break; + default: + aw881xx->pid = AW881XX_PID_03; + } + + aw881xx_update_cfg_name(aw881xx); + + return 0; +} + +int aw881xx_read_chipid(struct aw881xx *aw881xx) +{ + int ret = -1; + uint8_t cnt = 0; + uint16_t reg_val = 0; + + while (cnt < AW_READ_CHIPID_RETRIES) { + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_ID, ®_val); + if (ret < 0) { + dev_err(aw881xx->dev, + "%s: failed to read chip id, ret=%d\n", + __func__, ret); + return -EIO; + } + switch (reg_val) { + case AW881XX_CHIPID: + aw881xx->chipid = AW881XX_CHIPID; + aw881xx->flags |= AW881XX_FLAG_START_ON_MUTE; + aw881xx->flags |= AW881XX_FLAG_SKIP_INTERRUPTS; + + aw881xx_read_product_id(aw881xx); + + dev_info(aw881xx->dev, + "%s: chipid=0x%04x, product_id=0x%02x\n", + __func__, aw881xx->chipid, aw881xx->pid); + return 0; + default: + dev_info(aw881xx->dev, + "%s: unsupported device revision (0x%x)\n", + __func__, reg_val); + break; + } + cnt++; + + msleep(AW_READ_CHIPID_RETRY_DELAY); + } + + return -EINVAL; +} + +/****************************************************** + * + * aw881xx dsp + * + ******************************************************/ +static int aw881xx_dsp_check(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t reg_val = 0; + uint16_t iis_check_max = 5; + uint16_t i = 0; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_run_pwd(aw881xx, false); + aw881xx_memclk_select(aw881xx, AW881XX_MEMCLK_PLL); + for (i = 0; i < iis_check_max; i++) { + ret = aw881xx_get_iis_status(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: iis signal check error, reg=0x%x\n", + __func__, reg_val); + msleep(2); + } else { + if (aw881xx->dsp_cfg == AW881XX_DSP_WORK) { + aw881xx_dsp_enable(aw881xx, false); + aw881xx_dsp_enable(aw881xx, true); + msleep(1); + ret = aw881xx_get_dsp_status(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: dsp wdt status error=%d\n", + __func__, ret); + } else { + return 0; + } + } else if (aw881xx->dsp_cfg == AW881XX_DSP_BYPASS) { + return 0; + } else { + aw_dev_err(aw881xx->dev, "%s: unknown dsp cfg=%d\n", + __func__, aw881xx->dsp_cfg); + return -EINVAL; + } + } + } + return -EINVAL; +} + +int aw881xx_dsp_update_cali_re(struct aw881xx *aw881xx) +{ + aw881xx_get_cali_re(&aw881xx->cali_attr); + aw881xx_set_cali_re(&aw881xx->cali_attr); + + return 0; +} + +static void aw881xx_dsp_container_update(struct aw881xx *aw881xx, + struct aw881xx_container *aw881xx_cont, + uint16_t base) +{ + int i = 0; +#ifdef AW881XX_DSP_I2C_WRITES + uint8_t tmp_val = 0; + uint32_t tmp_len = 0; +#else + uint16_t reg_val = 0; +#endif + + aw_dev_dbg(aw881xx->dev, "%s enter\n", __func__); + +#ifdef AW881XX_DSP_I2C_WRITES + /* i2c writes */ + aw881xx_reg_write(aw881xx, AW881XX_REG_DSPMADD, base); + for (i = 0; i < aw881xx_cont->len; i += 2) { + tmp_val = aw881xx_cont->data[i + 0]; + aw881xx_cont->data[i + 0] = aw881xx_cont->data[i + 1]; + aw881xx_cont->data[i + 1] = tmp_val; + } + for (i = 0; i < aw881xx_cont->len; i += AW881XX_MAX_RAM_WRITE_BYTE_SIZE) { + if ((aw881xx_cont->len - i) < AW881XX_MAX_RAM_WRITE_BYTE_SIZE) + tmp_len = aw881xx_cont->len - i; + else + tmp_len = AW881XX_MAX_RAM_WRITE_BYTE_SIZE; + aw881xx_reg_writes(aw881xx, AW881XX_REG_DSPMDAT, + &aw881xx_cont->data[i], tmp_len); + } +#else + /* i2c write */ + aw881xx_reg_write(aw881xx, AW881XX_REG_DSPMADD, base); + for (i = 0; i < aw881xx_cont->len; i += 2) { + reg_val = (aw881xx_cont->data[i + 1] << 8) + aw881xx_cont->data[i + 0]; + aw881xx_reg_write(aw881xx, AW881XX_REG_DSPMDAT, reg_val); + } +#endif + aw_dev_dbg(aw881xx->dev, "%s: exit\n", __func__); +} + +static void aw881xx_dsp_cfg_loaded(const struct firmware *cont, void *context) +{ + struct aw881xx *aw881xx = context; + struct aw881xx_container *aw881xx_cfg; + int ret = -1; + + if (!cont) { + aw_dev_err(aw881xx->dev, "%s: failed to read %s\n", + __func__, aw881xx->cfg_name[aw881xx->cfg_num]); + release_firmware(cont); + return; + } + + aw_dev_info(aw881xx->dev, + "%s: loaded %s - size: %zu\n", __func__, + aw881xx->cfg_name[aw881xx->cfg_num], cont ? cont->size : 0); + + aw881xx_cfg = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw881xx_cfg) { + release_firmware(cont); + aw_dev_err(aw881xx->dev, "%s: error allocating memory\n", + __func__); + return; + } + aw881xx->dsp_cfg_len = cont->size; + aw881xx_cfg->len = cont->size; + memcpy(aw881xx_cfg->data, cont->data, cont->size); + release_firmware(cont); + + if (aw881xx->work_flag == false) { + kfree(aw881xx_cfg); + aw_dev_info(aw881xx->dev, "%s: mode_flag = %d\n", + __func__, aw881xx->work_flag); + return; + } + + mutex_lock(&aw881xx->lock); + aw881xx_dsp_container_update(aw881xx, aw881xx_cfg, + aw881xx_base_addr[aw881xx->cfg_num]); + + kfree(aw881xx_cfg); + + aw881xx_dsp_update_cali_re(aw881xx); + aw881xx_dsp_set_vcalb(aw881xx); + + ret = aw881xx_dsp_check(aw881xx); + if (ret < 0) { + aw881xx->init = AW881XX_INIT_NG; + aw881xx_run_mute(aw881xx, true); + aw_dev_info(aw881xx->dev, "%s: fw/cfg update error\n", + __func__); + } else { + aw_dev_info(aw881xx->dev, "%s: fw/cfg update complete\n", + __func__); + + ret = aw881xx_start(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: start fail, ret=%d\n", + __func__, ret); + } else { + aw_dev_info(aw881xx->dev, "%s: start success\n", + __func__); + aw881xx->init = AW881XX_INIT_OK; + } + } + mutex_unlock(&aw881xx->lock); +} + +static int aw881xx_load_dsp_cfg(struct aw881xx *aw881xx) +{ + aw_dev_info(aw881xx->dev, "%s enter\n", __func__); + + aw881xx->cfg_num++; + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw881xx->cfg_name[aw881xx->cfg_num], + aw881xx->dev, GFP_KERNEL, aw881xx, + aw881xx_dsp_cfg_loaded); +} + +static void aw881xx_dsp_fw_loaded(const struct firmware *cont, void *context) +{ + struct aw881xx *aw881xx = context; + struct aw881xx_container *aw881xx_cfg; + int ret = -1; + + if (!cont) { + aw_dev_err(aw881xx->dev, "%s: failed to read %s\n", + __func__, aw881xx->cfg_name[aw881xx->cfg_num]); + release_firmware(cont); + return; + } + + aw_dev_info(aw881xx->dev, "%s: loaded %s - size: %zu\n", + __func__, aw881xx->cfg_name[aw881xx->cfg_num], + cont ? cont->size : 0); + + aw881xx_cfg = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw881xx_cfg) { + release_firmware(cont); + aw_dev_err(aw881xx->dev, "%s: error allocating memory\n", + __func__); + return; + } + aw881xx->dsp_fw_len = cont->size; + aw881xx_cfg->len = cont->size; + memcpy(aw881xx_cfg->data, cont->data, cont->size); + release_firmware(cont); + + if (aw881xx->work_flag == true) { + mutex_lock(&aw881xx->lock); + aw881xx_dsp_container_update(aw881xx, aw881xx_cfg, + aw881xx_base_addr[aw881xx->cfg_num]); + mutex_unlock(&aw881xx->lock); + } + kfree(aw881xx_cfg); + + if (aw881xx->work_flag == false) { + aw_dev_info(aw881xx->dev, "%s: mode_flag = %d\n", + __func__, aw881xx->work_flag); + return; + } + + ret = aw881xx_load_dsp_cfg(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: cfg loading requested failed: %d\n", + __func__, ret); + } +} + +static int aw881xx_load_dsp_fw(struct aw881xx *aw881xx) +{ + int ret = -1; + + aw_dev_info(aw881xx->dev, "%s enter\n", __func__); + + aw881xx->cfg_num++; + + if (aw881xx->work_flag == true) { + mutex_lock(&aw881xx->lock); + aw881xx_run_mute(aw881xx, true); + aw881xx_dsp_enable(aw881xx, false); + aw881xx_memclk_select(aw881xx, AW881XX_MEMCLK_PLL); + mutex_unlock(&aw881xx->lock); + } else { + aw_dev_info(aw881xx->dev, "%s: mode_flag = %d\n", + __func__, aw881xx->work_flag); + return ret; + } + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw881xx->cfg_name[aw881xx->cfg_num], + aw881xx->dev, GFP_KERNEL, aw881xx, + aw881xx_dsp_fw_loaded); +} + +void aw881xx_get_cfg_shift(struct aw881xx *aw881xx) +{ + aw881xx->cfg_num = aw881xx->scene_mode * AW881XX_MODE_CFG_NUM_MAX; + aw_dev_dbg(aw881xx->dev, "%s: cfg_num=%d\n", + __func__, aw881xx->cfg_num); +} + +static void aw881xx_update_dsp(struct aw881xx *aw881xx) +{ + uint16_t iis_check_max = 5; + int i = 0; + int ret = -1; + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_get_cfg_shift(aw881xx); + aw881xx_get_dsp_config(aw881xx); + + for (i = 0; i < iis_check_max; i++) { + mutex_lock(&aw881xx->lock); + ret = aw881xx_get_iis_status(aw881xx); + mutex_unlock(&aw881xx->lock); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: get no iis signal, ret=%d\n", + __func__, ret); + msleep(2); + } else { + ret = aw881xx_load_dsp_fw(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: cfg loading requested failed: %d\n", + __func__, ret); + } + break; + } + } +} + +/****************************************************** + * + * aw881xx reg config + * + ******************************************************/ +static void aw881xx_reg_container_update(struct aw881xx *aw881xx, + struct aw881xx_container *aw881xx_cont) +{ + int i = 0; + uint16_t reg_addr = 0; + uint16_t reg_val = 0; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + for (i = 0; i < aw881xx_cont->len; i += 4) { + reg_addr = (aw881xx_cont->data[i + 1] << 8) + + aw881xx_cont->data[i + 0]; + reg_val = (aw881xx_cont->data[i + 3] << 8) + + aw881xx_cont->data[i + 2]; + aw_dev_dbg(aw881xx->dev, "%s: reg=0x%04x, val = 0x%04x\n", + __func__, reg_addr, reg_val); + if (reg_addr == AW881XX_REG_SYSINTM) { + aw881xx->intmask = reg_val; + reg_val = AW881XX_REG_SYSINTM_MASK; + } + aw881xx_reg_write(aw881xx, + (uint8_t) reg_addr, (uint16_t) reg_val); + } + + aw_dev_dbg(aw881xx->dev, "%s: exit\n", __func__); +} + +static void aw881xx_reg_loaded(const struct firmware *cont, void *context) +{ + struct aw881xx *aw881xx = context; + struct aw881xx_container *aw881xx_cfg; + int ret = -1; + uint16_t iis_check_max = 5; + int i = 0; + + if (!cont) { + aw_dev_err(aw881xx->dev, "%s: failed to read %s\n", + __func__, aw881xx->cfg_name[aw881xx->cfg_num]); + release_firmware(cont); + return; + } + + aw_dev_info(aw881xx->dev, "%s: loaded %s - size: %zu\n", + __func__, aw881xx->cfg_name[aw881xx->cfg_num], + cont ? cont->size : 0); + + aw881xx_cfg = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw881xx_cfg) { + release_firmware(cont); + aw_dev_err(aw881xx->dev, "%s: error allocating memory\n", + __func__); + return; + } + aw881xx_cfg->len = cont->size; + memcpy(aw881xx_cfg->data, cont->data, cont->size); + release_firmware(cont); + + if (aw881xx->work_flag == true) { + mutex_lock(&aw881xx->lock); + aw881xx_reg_container_update(aw881xx, aw881xx_cfg); + mutex_unlock(&aw881xx->lock); + } + kfree(aw881xx_cfg); + + if (aw881xx->work_flag == false) { + aw_dev_info(aw881xx->dev, "%s: mode_flag = %d\n", + __func__, aw881xx->work_flag); + return; + } + + for (i = 0; i < iis_check_max; i++) { + mutex_lock(&aw881xx->lock); + ret = aw881xx_get_iis_status(aw881xx); + mutex_unlock(&aw881xx->lock); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: get no iis signal, ret=%d\n", + __func__, ret); + msleep(2); + } else { + aw881xx_read_dsp_pid(aw881xx); + aw881xx_update_dsp(aw881xx); + break; + } + } +} + +static int aw881xx_load_reg(struct aw881xx *aw881xx) +{ + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw881xx->cfg_name[aw881xx->cfg_num], + aw881xx->dev, GFP_KERNEL, aw881xx, + aw881xx_reg_loaded); +} + +static void aw881xx_cold_start(struct aw881xx *aw881xx) +{ + int ret = -1; + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_get_cfg_shift(aw881xx); + + ret = aw881xx_load_reg(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s: cfg loading requested failed: %d\n", + __func__, ret); + } +} + +void aw881xx_smartpa_cfg(struct aw881xx *aw881xx, bool flag) +{ + int ret = -1; + + aw_dev_info(aw881xx->dev, "%s: flag = %d\n", __func__, flag); + + aw881xx->work_flag = flag; + if (flag == true) { + if ((aw881xx->init == AW881XX_INIT_ST) + || (aw881xx->init == AW881XX_INIT_NG)) { + aw_dev_info(aw881xx->dev, "%s: init = %d\n", + __func__, aw881xx->init); + aw881xx_cold_start(aw881xx); + } else { + ret = aw881xx_start(aw881xx); + if (ret < 0) + aw_dev_err(aw881xx->dev, + "%s: start fail, ret=%d\n", + __func__, ret); + else + aw_dev_info(aw881xx->dev, "%s: start success\n", + __func__); + } + } else { + aw881xx_stop(aw881xx); + } +} + +/****************************************************** + * + * kcontrol + * + ******************************************************/ +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 50, 0); + +struct soc_mixer_control aw881xx_mixer = { + .reg = AW881XX_REG_HAGCCFG7, + .shift = AW881XX_VOL_REG_SHIFT, + .min = AW881XX_VOLUME_MIN, + .max = AW881XX_VOLUME_MAX, +}; + +static int aw881xx_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + /* set kcontrol info */ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mc->max - mc->min; + + return 0; +} + +static int aw881xx_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + uint16_t reg_val = 0; + uint16_t vol_val = 0; + unsigned int value = 0; + + aw881xx_reg_read(aw881xx, AW881XX_REG_HAGCCFG7, ®_val); + vol_val = (reg_val >> AW881XX_VOL_REG_SHIFT); + + value = (vol_val >> 4) * AW881XX_VOL_6DB_STEP + + ((vol_val & 0x0f) % AW881XX_VOL_6DB_STEP); + + ucontrol->value.integer.value[0] = value; + + return 0; +} + +static int aw881xx_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + unsigned int value = 0; + uint16_t reg_val = 0; + uint16_t vol_val = 0; + + /* value is right */ + value = ucontrol->value.integer.value[0]; + if (value > (mc->max - mc->min) || value < 0) { + aw_dev_err(aw881xx->dev, "%s:value over range\n", __func__); + return -EINVAL; + } + + /* cal real value */ + vol_val = ((value / AW881XX_VOL_6DB_STEP) << 4) + + (value % AW881XX_VOL_6DB_STEP); + + reg_val = (vol_val << AW881XX_VOL_REG_SHIFT); + + /* write value */ + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_HAGCCFG7, + (uint16_t) AW881XX_BIT_HAGCCFG7_VOL_MASK, + reg_val); + + return 0; +} + +static struct snd_kcontrol_new aw881xx_volume = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "aw881xx_rx_volume", + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_READWRITE, + .tlv.p = (digital_gain), + .info = aw881xx_volume_info, + .get = aw881xx_volume_get, + .put = aw881xx_volume_put, + .private_value = (unsigned long)&aw881xx_mixer, +}; + +static const char *const mode_function[] = { + "spk", + "voice", + "fm", + "rcv" +}; + +static int aw881xx_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + aw_dev_dbg(aw881xx->dev, "%s: scene_mode=%d\n", + __func__, aw881xx->scene_mode); + + ucontrol->value.integer.value[0] = aw881xx->scene_mode; + + return 0; +} + +static int aw881xx_mode_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + aw_dev_dbg(aw881xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", + __func__, ucontrol->value.integer.value[0]); + if (ucontrol->value.integer.value[0] == aw881xx->scene_mode) + return 1; + + aw881xx->scene_mode = ucontrol->value.integer.value[0]; + + aw881xx->init = AW881XX_INIT_ST; + + return 0; +} + +static const struct soc_enum aw881xx_snd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mode_function), mode_function), +}; + +static struct snd_kcontrol_new aw881xx_controls[] = { + SOC_ENUM_EXT("aw881xx_mode_switch", aw881xx_snd_enum[0], + aw881xx_mode_get, aw881xx_mode_set), +}; + +static void aw881xx_kcontrol_append_suffix(struct aw881xx *aw881xx, + struct snd_kcontrol_new *src_control, int num) +{ + int i = 0; + struct snd_kcontrol_new *dst_control; + + dst_control = devm_kzalloc(aw881xx->dev, + num * sizeof(struct snd_kcontrol_new), + GFP_KERNEL); + if (!dst_control) { + aw_dev_err(aw881xx->dev, "%s:kcontrol kzalloc faild\n", + __func__); + return; + } + memcpy(dst_control, src_control, num * sizeof(struct snd_kcontrol_new)); + + for (i = 0; i < num; i++) { + aw881xx_append_suffix("%s_%s", + (const char **)&dst_control[i].name, + aw881xx); + } + snd_soc_add_component_controls(aw881xx->component, dst_control, num); +} + +static void aw881xx_add_codec_controls(struct aw881xx *aw881xx) +{ + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_kcontrol_append_suffix(aw881xx, + aw881xx_controls, + ARRAY_SIZE(aw881xx_controls)); + aw881xx_kcontrol_append_suffix(aw881xx, &aw881xx_volume, 1); +} + +/****************************************************** + * + * Digital Audio Interface + * + ******************************************************/ +static int aw881xx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *codec = dai->component; + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + mutex_lock(&aw881xx->lock); + aw881xx_run_pwd(aw881xx, false); + mutex_unlock(&aw881xx->lock); + } + + return 0; +} + +static int aw881xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + /*struct aw881xx *aw881xx = snd_soc_codec_get_drvdata(dai->codec); */ + struct snd_soc_component *codec = dai->component; + + aw_dev_info(codec->dev, "%s: fmt=0x%x\n", __func__, fmt); + + /* supported mode: regular I2S, slave, or PDM */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != + SND_SOC_DAIFMT_CBS_CFS) { + aw_dev_err(codec->dev, + "%s: invalid codec master mode\n", + __func__); + return -EINVAL; + } + break; + default: + aw_dev_err(codec->dev, "%s: unsupported DAI format %d\n", + __func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + return 0; +} + +static int aw881xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec_dai->component); + + aw_dev_info(aw881xx->dev, "%s: freq=%d\n", __func__, freq); + + aw881xx->sysclk = freq; + return 0; +} + +int aw881xx_update_hw_params(struct aw881xx *aw881xx) +{ + uint16_t reg_val = 0; + + /* match rate */ + switch (aw881xx->rate) { + case 8000: + reg_val = AW881XX_BIT_I2SCTRL_SR_8K; + break; + case 16000: + reg_val = AW881XX_BIT_I2SCTRL_SR_16K; + break; + case 32000: + reg_val = AW881XX_BIT_I2SCTRL_SR_32K; + break; + case 44100: + reg_val = AW881XX_BIT_I2SCTRL_SR_44P1K; + break; + case 48000: + reg_val = AW881XX_BIT_I2SCTRL_SR_48K; + break; + case 96000: + reg_val = AW881XX_BIT_I2SCTRL_SR_96K; + break; + case 192000: + reg_val = AW881XX_BIT_I2SCTRL_SR_192K; + break; + default: + reg_val = AW881XX_BIT_I2SCTRL_SR_48K; + aw_dev_err(aw881xx->dev, "%s: rate can not support\n", + __func__); + break; + } + /* set chip rate */ + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_I2SCTRL, + AW881XX_BIT_I2SCTRL_SR_MASK, reg_val); + + /* match bit width */ + switch (aw881xx->width) { + case 16: + reg_val = AW881XX_BIT_I2SCTRL_FMS_16BIT; + break; + case 20: + reg_val = AW881XX_BIT_I2SCTRL_FMS_20BIT; + break; + case 24: + reg_val = AW881XX_BIT_I2SCTRL_FMS_24BIT; + break; + case 32: + reg_val = AW881XX_BIT_I2SCTRL_FMS_32BIT; + break; + default: + reg_val = AW881XX_BIT_I2SCTRL_FMS_16BIT; + aw_dev_err(aw881xx->dev, "%s: width can not support\n", + __func__); + break; + } + /* set width */ + aw881xx_reg_write_bits(aw881xx, AW881XX_REG_I2SCTRL, + AW881XX_BIT_I2SCTRL_FMS_MASK, reg_val); + + return 0; +} + +static int aw881xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *codec = dai->component; + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + aw_dev_dbg(aw881xx->dev, + "%s: requested rate: %d, sample size: %d\n", + __func__, params_rate(params), + snd_pcm_format_width(params_format(params))); + return 0; + } + /* get rate param */ + aw881xx->rate = params_rate(params); + aw_dev_dbg(aw881xx->dev, "%s: requested rate: %d, sample size: %d\n", + __func__, aw881xx->rate, + snd_pcm_format_width(params_format(params))); + + /* get bit width */ + aw881xx->width = params_width(params); + aw_dev_dbg(aw881xx->dev, "%s: width = %d\n", __func__, aw881xx->width); + + mutex_lock(&aw881xx->lock); + aw881xx_update_hw_params(aw881xx); + mutex_unlock(&aw881xx->lock); + + return 0; +} + +static int aw881xx_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *codec = dai->component; + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + aw_dev_info(aw881xx->dev, "%s: mute state=%d\n", __func__, mute); + + if (!(aw881xx->flags & AW881XX_FLAG_START_ON_MUTE)) + return 0; + + if (mute) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + mutex_lock(&aw881xx->lock); + aw881xx_smartpa_cfg(aw881xx, false); + mutex_unlock(&aw881xx->lock); + } + } else { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + mutex_lock(&aw881xx->lock); + aw881xx_smartpa_cfg(aw881xx, true); + mutex_unlock(&aw881xx->lock); + } + } + + return 0; +} + +static void aw881xx_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *codec = dai->component; + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw881xx->rate = 0; + mutex_lock(&aw881xx->lock); + aw881xx_run_pwd(aw881xx, true); + mutex_unlock(&aw881xx->lock); + } +} + +static const struct snd_soc_dai_ops aw881xx_dai_ops = { + .startup = aw881xx_startup, + .set_fmt = aw881xx_set_fmt, + .set_sysclk = aw881xx_set_dai_sysclk, + .hw_params = aw881xx_hw_params, + .mute_stream = aw881xx_mute, + .shutdown = aw881xx_shutdown, +}; + +static struct snd_soc_dai_driver aw881xx_dai[] = { + { +#ifdef CONFIG_SND_SMARTPA_COMPATIBLE + .name = "compatible-aif", +#else + .name = "aw881xx-aif", +#endif + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW881XX_RATES, + .formats = AW881XX_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW881XX_RATES, + .formats = AW881XX_FORMATS, + }, + .ops = &aw881xx_dai_ops, + .symmetric_rates = 1, + }, +}; + +/***************************************************** + * + * codec driver + * + *****************************************************/ +static int aw881xx_probe(struct snd_soc_component *codec) +{ + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + int ret = -1; + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx->component = codec; + + aw881xx_add_codec_controls(aw881xx); + + if (codec->dev->of_node) { + if (aw881xx->name_suffix) + dev_set_name(aw881xx->dev, "%s_%s", "aw881xx_smartpa", + aw881xx->name_suffix); + else + dev_set_name(aw881xx->dev, "%s", "aw881xx_smartpa"); + } + + aw_dev_info(aw881xx->dev, "%s: exit\n", __func__); + + ret = 0; + return ret; +} + +static void aw881xx_remove(struct snd_soc_component *codec) +{ + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + +} +/* +static unsigned int aw881xx_codec_read(struct snd_soc_component *codec, + unsigned int reg) +{ + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + uint16_t value = 0; + int ret = -1; + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + if (aw881xx_reg_access[reg] & REG_RD_ACCESS) { + ret = aw881xx_reg_read(aw881xx, reg, &value); + if (ret < 0) { + aw_dev_dbg(aw881xx->dev, "%s: read register failed\n", + __func__); + return ret; + } + } else { + aw_dev_dbg(aw881xx->dev, "%s: register 0x%x no read access\n", + __func__, reg); + return ret; + } + return ret; +} + +static int aw881xx_codec_write(struct snd_soc_component *codec, + unsigned int reg, unsigned int value) +{ + int ret = -1; + struct aw881xx *aw881xx = snd_soc_component_get_drvdata(codec); + + aw_dev_dbg(aw881xx->dev, "%s: enter ,reg is 0x%x value is 0x%x\n", + __func__, reg, value); + + if (aw881xx_reg_access[reg] & REG_WR_ACCESS) + ret = aw881xx_reg_write(aw881xx, (uint8_t) reg, + (uint16_t) value); + else + aw_dev_dbg(aw881xx->dev, "%s: register 0x%x no write access\n", + __func__, reg); + + return ret; +} +*/ +static struct snd_soc_component_driver soc_codec_dev_aw881xx = { + .probe = aw881xx_probe, + .remove = aw881xx_remove, +/* .read = aw881xx_codec_read, + .write = aw881xx_codec_write, + .reg_cache_size = AW881XX_REG_MAX, + .reg_word_size = 2,*/ +}; + +/****************************************************** + * + * irq + * + ******************************************************/ +void aw881xx_interrupt_setup(struct aw881xx *aw881xx) +{ + uint16_t reg_val = 0; + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_reg_read(aw881xx, AW881XX_REG_SYSINTM, ®_val); + reg_val &= (~AW881XX_BIT_SYSINTM_PLLM); + reg_val &= (~AW881XX_BIT_SYSINTM_OTHM); + reg_val &= (~AW881XX_BIT_SYSINTM_OCDM); + aw881xx_reg_write(aw881xx, AW881XX_REG_SYSINTM, reg_val); +} + +void aw881xx_interrupt_handle(struct aw881xx *aw881xx) +{ + uint16_t reg_val = 0; + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_reg_read(aw881xx, AW881XX_REG_SYSST, ®_val); + aw_dev_info(aw881xx->dev, "%s: reg SYSST=0x%x\n", __func__, reg_val); + + aw881xx_reg_read(aw881xx, AW881XX_REG_SYSINT, ®_val); + aw_dev_info(aw881xx->dev, "%s: reg SYSINT=0x%x\n", __func__, reg_val); + + aw881xx_reg_read(aw881xx, AW881XX_REG_SYSINTM, ®_val); + aw_dev_info(aw881xx->dev, "%s: reg SYSINTM=0x%x\n", __func__, reg_val); +} + +static irqreturn_t aw881xx_irq(int irq, void *data) +{ + struct aw881xx *aw881xx = data; + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + aw881xx_interrupt_handle(aw881xx); + + aw_dev_info(aw881xx->dev, "%s: exit\n", __func__); + + return IRQ_HANDLED; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +static int aw881xx_parse_gpio_dt(struct aw881xx *aw881xx, + struct device_node *np) +{ + aw881xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw881xx->reset_gpio < 0) { + dev_err(aw881xx->dev, + "%s: no reset gpio provided, will not hw reset\n", + __func__); + return -EIO; + } else { + dev_info(aw881xx->dev, "%s: reset gpio provided ok\n", + __func__); + } + + aw881xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw881xx->irq_gpio < 0) + dev_info(aw881xx->dev, "%s: no irq gpio provided.\n", __func__); + else + dev_info(aw881xx->dev, "%s: irq gpio provided ok.\n", __func__); + + return 0; +} + +static void aw881xx_parse_channel_dt(struct aw881xx *aw881xx, + struct device_node *np) +{ + int ret = -1; + const char *channel_value; + + ret = of_property_read_string(np, "sound-channel", &channel_value); + if (ret < 0) { + dev_info(aw881xx->dev, + "%s:read sound-channel failed,use default\n", + __func__); + goto chan_default; + } + dev_info(aw881xx->dev, + "%s: read sound-channel value is : %s\n", + __func__, channel_value); + + if (!strcmp(channel_value, "left")) { + aw881xx->name_suffix = "l"; + } else if (!strcmp(channel_value, "right")) { + aw881xx->name_suffix = "r"; + } else { + dev_info(aw881xx->dev, + "%s:not stereo channel,use default single track\n", + __func__); + goto chan_default; + } + return; + + chan_default: + aw881xx->name_suffix = NULL; +} + +static void aw881xx_parse_monitor_dt(struct aw881xx *aw881xx, + struct device_node *np) +{ + int ret; + struct aw881xx_monitor *monitor = &aw881xx->monitor; + + ret = of_property_read_u32(np, "monitor-flag", &monitor->monitor_flag); + if (ret) { + dev_err(aw881xx->dev, + "%s: find no monitor-flag, use default config\n", + __func__); + monitor->monitor_flag = AW881XX_MONITOR_DFT_FLAG; + } else { + dev_info(aw881xx->dev, "%s: monitor-flag = %d\n", + __func__, monitor->monitor_flag); + } + ret = of_property_read_u32(np, "monitor-timer-val", + &monitor->monitor_timer_val); + if (ret) { + dev_err(aw881xx->dev, + "%s: find no monitor-timer-val, use default config\n", + __func__); + monitor->monitor_timer_val = AW881XX_MONITOR_TIMER_DFT_VAL; + } else { + dev_info(aw881xx->dev, "%s: monitor-timer-val = %d\n", + __func__, monitor->monitor_timer_val); + } + +} + +static int aw881xx_parse_dt(struct device *dev, struct aw881xx *aw881xx, + struct device_node *np) +{ + int ret; + + ret = aw881xx_parse_gpio_dt(aw881xx, np); + aw881xx_parse_channel_dt(aw881xx, np); + aw881xx_parse_monitor_dt(aw881xx, np); + return ret; +} + +int aw881xx_hw_reset(struct aw881xx *aw881xx) +{ + dev_info(aw881xx->dev, "%s: enter\n", __func__); + + if (aw881xx && gpio_is_valid(aw881xx->reset_gpio)) { + gpio_set_value_cansleep(aw881xx->reset_gpio, 0); + msleep(1); + gpio_set_value_cansleep(aw881xx->reset_gpio, 1); + msleep(1); + } else { + dev_err(aw881xx->dev, "%s: failed\n", __func__); + } + return 0; +} + +/****************************************************** + * + * sys group attribute: reg + * + ******************************************************/ +static ssize_t aw881xx_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + + unsigned int databuf[2] = { 0 }; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) + aw881xx_reg_write(aw881xx, databuf[0], databuf[1]); + + return count; +} + +static ssize_t aw881xx_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + + ssize_t len = 0; + uint8_t i = 0; + uint16_t reg_val = 0; + + for (i = 0; i < AW881XX_REG_MAX; i++) { + if (aw881xx_reg_access[i] & REG_RD_ACCESS) { + aw881xx_reg_read(aw881xx, i, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02x=0x%04x\n", i, reg_val); + } + } + return len; +} + +static ssize_t aw881xx_rw_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + + unsigned int databuf[2] = { 0 }; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw881xx->reg_addr = (uint8_t) databuf[0]; + aw881xx_reg_write(aw881xx, databuf[0], databuf[1]); + } else if (1 == sscanf(buf, "%x", &databuf[0])) { + aw881xx->reg_addr = (uint8_t) databuf[0]; + } + + return count; +} + +static ssize_t aw881xx_rw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + ssize_t len = 0; + uint16_t reg_val = 0; + + if (aw881xx_reg_access[aw881xx->reg_addr] & REG_RD_ACCESS) { + aw881xx_reg_read(aw881xx, aw881xx->reg_addr, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "reg:0x%02x=0x%04x\n", aw881xx->reg_addr, + reg_val); + } + return len; +} + +static ssize_t aw881xx_dsp_rw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + ssize_t len = 0; + uint16_t reg_val = 0; + + aw881xx_reg_read(aw881xx, AW881XX_REG_DSPMADD, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "dsp:0x%04x=0x%04x\n", aw881xx->dsp_addr, reg_val); + aw881xx_reg_read(aw881xx, AW881XX_REG_DSPMDAT, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "dsp:0x%04x=0x%04x\n", aw881xx->dsp_addr + 1, reg_val); + + return len; +} + +static ssize_t aw881xx_dsp_rw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + unsigned int databuf[2] = { 0 }; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw881xx->dsp_addr = (unsigned int)databuf[0]; + aw881xx_dsp_write(aw881xx, databuf[0], databuf[1]); + aw_dev_dbg(aw881xx->dev, "%s: get param: %x %x\n", __func__, + databuf[0], databuf[1]); + } else if (1 == sscanf(buf, "%x", &databuf[0])) { + aw881xx->dsp_addr = (unsigned int)databuf[0]; + aw881xx_reg_write(aw881xx, AW881XX_REG_DSPMADD, databuf[0]); + aw_dev_dbg(aw881xx->dev, "%s: get param: %x\n", __func__, + databuf[0]); + } + + return count; +} + +static ssize_t aw881xx_update_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + unsigned int val = 0; + int ret = 0; + + ret = kstrtouint(buf, 0, &val); + if (ret < 0) + return ret; + + aw_dev_dbg(aw881xx->dev, "%s: value=%d\n", __func__, val); + + if (val) { + aw881xx->init = AW881XX_INIT_ST; + aw881xx_smartpa_cfg(aw881xx, false); + aw881xx_smartpa_cfg(aw881xx, true); + } + return count; +} + +static ssize_t aw881xx_update_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /*struct aw881xx *aw881xx = dev_get_drvdata(dev); */ + ssize_t len = 0; + + return len; +} + +static ssize_t aw881xx_dsp_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + unsigned int val = 0; + int ret = 0; + + ret = kstrtouint(buf, 0, &val); + if (ret < 0) + return ret; + + aw_dev_dbg(aw881xx->dev, "%s: value=%d\n", __func__, val); + + if (val) { + aw881xx->init = AW881XX_INIT_ST; + aw881xx_update_dsp(aw881xx); + } + return count; +} + +static ssize_t aw881xx_dsp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int i = 0; + uint16_t reg_val = 0; + int ret = -1; + + aw881xx_get_dsp_config(aw881xx); + if (aw881xx->dsp_cfg == AW881XX_DSP_BYPASS) { + len += snprintf((char *)(buf + len), PAGE_SIZE - len, + "%s: aw881xx dsp bypass\n", __func__); + } else { + len += snprintf(buf + len, PAGE_SIZE - len, + "aw881xx dsp working\n"); + ret = aw881xx_get_iis_status(aw881xx); + if (ret < 0) { + len += snprintf((char *)(buf + len), + PAGE_SIZE - len, + "%s: aw881xx no iis signal\n", + __func__); + } else { + aw_dev_dbg(aw881xx->dev, "%s: aw881xx_dsp_firmware:\n", + __func__); + aw881xx_reg_write(aw881xx, AW881XX_REG_DSPMADD, + AW881XX_SPK_DSP_FW_ADDR); + for (i = 0; i < aw881xx->dsp_fw_len; i += 2) { + aw881xx_reg_read(aw881xx, + AW881XX_REG_DSPMDAT, ®_val); + aw_dev_dbg(aw881xx->dev, + "%s: dsp_fw[0x%04x]:0x%02x,0x%02x\n", + __func__, i, (reg_val >> 0) & 0xff, + (reg_val >> 8) & 0xff); + } + aw_dev_dbg(aw881xx->dev, "\n"); + + aw_dev_dbg(aw881xx->dev, "%s: aw881xx_dsp_cfg:\n", + __func__); + aw881xx_reg_write(aw881xx, AW881XX_REG_DSPMADD, + AW881XX_SPK_DSP_FW_ADDR); + len += snprintf(buf + len, PAGE_SIZE - len, + "aw881xx dsp config:\n"); + aw881xx_reg_write(aw881xx, AW881XX_REG_DSPMADD, + AW881XX_SPK_DSP_CFG_ADDR); + for (i = 0; i < aw881xx->dsp_cfg_len; i += 2) { + aw881xx_reg_read(aw881xx, + AW881XX_REG_DSPMDAT, ®_val); + len += snprintf(buf + len, PAGE_SIZE - len, + "%02x,%02x,", (reg_val >> 0) & 0xff, + (reg_val >> 8) & 0xff); + aw_dev_dbg(aw881xx->dev, + "%s: dsp_cfg[0x%04x]:0x%02x,0x%02x\n", + __func__, i, (reg_val >> 0) & 0xff, + (reg_val >> 8) & 0xff); + if ((i / 2 + 1) % 8 == 0) { + len += snprintf(buf + len, + PAGE_SIZE - len, "\n"); + } + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + } + } + + return len; +} + +static ssize_t aw881xx_dsp_fw_ver_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + /*struct aw881xx *aw881xx = dev_get_drvdata(dev);*/ + + return count; +} + +static ssize_t aw881xx_dsp_fw_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + ssize_t len = 0; + uint16_t dsp_addr = 0x8c00; + uint16_t temp_val = 0; + uint32_t dsp_val = 0; + + for (dsp_addr = 0x8c00; dsp_addr < 0x9000; dsp_addr++) { + dsp_val = 0; + aw881xx_dsp_read(aw881xx, dsp_addr, &temp_val); + dsp_val |= (temp_val << 0); + aw881xx_dsp_read(aw881xx, dsp_addr + 1, &temp_val); + dsp_val |= (temp_val << 16); + if ((dsp_val & 0x7fffff00) == 0x7fffff00) { + len += snprintf(buf + len, PAGE_SIZE - len, + "dsp fw ver: v1.%d\n", + 0xff - (dsp_val & 0xff)); + break; + } + } + + return len; +} + +static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, + aw881xx_reg_show, aw881xx_reg_store); +static DEVICE_ATTR(rw, S_IWUSR | S_IRUGO, + aw881xx_rw_show, aw881xx_rw_store); +static DEVICE_ATTR(dsp_rw, S_IWUSR | S_IRUGO, + aw881xx_dsp_rw_show, aw881xx_dsp_rw_store); +static DEVICE_ATTR(update, S_IWUSR | S_IRUGO, + aw881xx_update_show, aw881xx_update_store); +static DEVICE_ATTR(dsp, S_IWUSR | S_IRUGO, + aw881xx_dsp_show, aw881xx_dsp_store); +static DEVICE_ATTR(dsp_fw_ver, S_IWUSR | S_IRUGO, + aw881xx_dsp_fw_ver_show, aw881xx_dsp_fw_ver_store); + +static struct attribute *aw881xx_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_rw.attr, + &dev_attr_dsp_rw.attr, + &dev_attr_update.attr, + &dev_attr_dsp.attr, + &dev_attr_dsp_fw_ver.attr, + NULL +}; + +static struct attribute_group aw881xx_attribute_group = { + .attrs = aw881xx_attributes +}; +#ifdef CONFIG_SND_SMARTPA_COMPATIBLE +extern unsigned int compatible_smartpa_find; +#endif +extern int i2c_check_status_create(char *name,int value); // MODIFIED by hongwei.tian, 2020-01-20,BUG-8770360 +/****************************************************** + * + * i2c driver + * + ******************************************************/ +static int aw881xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_dai_driver *dai; + struct aw881xx *aw881xx; + struct device_node *np = i2c->dev.of_node; + const char *aw881xx_rst = "aw882xx_rst"; + const char *aw881xx_int = "aw882xx_int"; + const char *aw881xx_irq_name = "aw882xx"; + int irq_flags = 0; + int ret = -1; + + dev_info(&i2c->dev, "%s: enter\n", __func__); +#ifdef CONFIG_SND_SMARTPA_COMPATIBLE + if(compatible_smartpa_find) + { + dev_err(&i2c->dev, "Other smartPA had found \n"); + return 0; + } +#endif + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + aw881xx = devm_kzalloc(&i2c->dev, sizeof(struct aw881xx), GFP_KERNEL); + if (aw881xx == NULL) + return -ENOMEM; + + aw881xx->dev = &i2c->dev; + aw881xx->i2c = i2c; + + i2c_set_clientdata(i2c, aw881xx); + mutex_init(&aw881xx->lock); + mutex_init(&aw881xx->i2c_lock); + + if(aw881xx->i2c->addr == 0x43) + { + dev_info(&i2c->dev, "%s: change addr form 0x%x to 0x34\n", __func__,aw881xx->i2c->addr); + aw881xx->i2c->addr = 0x34; + } + /* aw881xx rst & int */ + if (np) { + ret = aw881xx_parse_dt(&i2c->dev, aw881xx, np); + if (ret) { + dev_err(&i2c->dev, + "%s:failed to parse device tree node\n", + __func__); + goto err_parse_dt; + } + } else { + aw881xx->reset_gpio = -1; + aw881xx->irq_gpio = -1; + } + + if (gpio_is_valid(aw881xx->reset_gpio)) { + aw881xx_append_suffix("%s_%s", &aw881xx_rst, aw881xx); + ret = devm_gpio_request_one(&i2c->dev, aw881xx->reset_gpio, + GPIOF_OUT_INIT_LOW, aw881xx_rst); + if (ret) { + dev_err(&i2c->dev, "%s: rst request failed\n", + __func__); + goto err_reset_gpio_request; + } + } + + if (gpio_is_valid(aw881xx->irq_gpio)) { + aw881xx_append_suffix("%s_%s", &aw881xx_int, aw881xx); + ret = devm_gpio_request_one(&i2c->dev, aw881xx->irq_gpio, + GPIOF_DIR_IN, aw881xx_int); + if (ret) { + dev_err(&i2c->dev, "%s: int request failed\n", + __func__); + goto err_irq_gpio_request; + } + } + + /* hardware reset */ + aw881xx_hw_reset(aw881xx); + + /* aw881xx chip id */ + ret = aw881xx_read_chipid(aw881xx); + if (ret < 0) { + dev_err(&i2c->dev, "%s: aw881xx_read_chipid failed ret=%d\n", + __func__, ret); + goto err_id; + } + + /* aw881xx device name */ +#ifdef CONFIG_SND_SMARTPA_COMPATIBLE + if (i2c->dev.of_node) { + if (aw881xx->name_suffix) + dev_set_name(&i2c->dev, "%s_%s", "compatible_smartpa", + aw881xx->name_suffix); + else + dev_set_name(&i2c->dev, "%s", "compatible_smartpa"); + } else + aw_dev_err(&i2c->dev, "%s failed to set device name: %d\n", + __func__, ret); + compatible_smartpa_find = 1; +#else + if (i2c->dev.of_node) { + if (aw881xx->name_suffix) + dev_set_name(&i2c->dev, "%s_%s", "aw881xx_smartpa", + aw881xx->name_suffix); + else + dev_set_name(&i2c->dev, "%s", "aw881xx_smartpa"); + } else + aw_dev_err(&i2c->dev, "%s failed to set device name: %d\n", + __func__, ret); +#endif + /* register codec */ + dai = devm_kzalloc(&i2c->dev, sizeof(aw881xx_dai), GFP_KERNEL); + if (!dai) + goto err_dai_kzalloc; + + memcpy(dai, aw881xx_dai, sizeof(aw881xx_dai)); + aw881xx_append_suffix("%s-%s", &dai->name, aw881xx); + aw881xx_append_suffix("%s_%s", &dai->playback.stream_name, aw881xx); + aw881xx_append_suffix("%s_%s", &dai->capture.stream_name, aw881xx); + + ret = devm_snd_soc_register_component(&i2c->dev, &soc_codec_dev_aw881xx, + dai, ARRAY_SIZE(aw881xx_dai)); + if (ret < 0) { + aw_dev_err(&i2c->dev, "%s failed to register aw881xx: %d\n", + __func__, ret); + goto err_register_codec; + } + + /* aw881xx irq */ + if (gpio_is_valid(aw881xx->irq_gpio) && + !(aw881xx->flags & AW881XX_FLAG_SKIP_INTERRUPTS)) { + + aw881xx_append_suffix("%s_%s", &aw881xx_irq_name, aw881xx); + aw881xx_interrupt_setup(aw881xx); + /* register irq handler */ + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(aw881xx->irq_gpio), + NULL, aw881xx_irq, irq_flags, + aw881xx_irq_name, aw881xx); + if (ret != 0) { + aw_dev_err(&i2c->dev, + "failed to request IRQ %d: %d\n", + gpio_to_irq(aw881xx->irq_gpio), ret); + goto err_irq; + } + } else { + aw_dev_info(&i2c->dev, + "%s skipping IRQ registration\n", __func__); + /* disable feature support if gpio was invalid */ + aw881xx->flags |= AW881XX_FLAG_SKIP_INTERRUPTS; + } + + dev_set_drvdata(&i2c->dev, aw881xx); + ret = sysfs_create_group(&i2c->dev.kobj, &aw881xx_attribute_group); + if (ret < 0) { + aw_dev_info(&i2c->dev, + "%s error creating sysfs attr files\n", + __func__); + goto err_sysfs; + } + aw881xx_cali_init(&aw881xx->cali_attr); + aw881xx_monitor_init(&aw881xx->monitor); + + aw_dev_info(&i2c->dev, "%s: probe completed successfully!\n", __func__); + i2c_check_status_create("audio_smpart_pa",1); // MODIFIED by hongwei.tian, 2020-01-20,BUG-8770360 + return 0; + + err_sysfs: + devm_free_irq(&i2c->dev, gpio_to_irq(aw881xx->irq_gpio), aw881xx); + err_irq: + snd_soc_unregister_component(&i2c->dev); + err_register_codec: + devm_kfree(&i2c->dev, dai); + dai = NULL; + err_dai_kzalloc: + err_id: + if (gpio_is_valid(aw881xx->irq_gpio)) + devm_gpio_free(&i2c->dev, aw881xx->irq_gpio); + err_irq_gpio_request: + if (gpio_is_valid(aw881xx->reset_gpio)) + devm_gpio_free(&i2c->dev, aw881xx->reset_gpio); + err_reset_gpio_request: + err_parse_dt: + devm_kfree(&i2c->dev, aw881xx); + aw881xx = NULL; + return ret; +} + +static int aw881xx_i2c_remove(struct i2c_client *i2c) +{ + struct aw881xx *aw881xx = i2c_get_clientdata(i2c); + + pr_info("%s: enter\n", __func__); + + if (gpio_to_irq(aw881xx->irq_gpio)) + devm_free_irq(&i2c->dev, gpio_to_irq(aw881xx->irq_gpio), + aw881xx); + + snd_soc_unregister_component(&i2c->dev); + + if (gpio_is_valid(aw881xx->irq_gpio)) + devm_gpio_free(&i2c->dev, aw881xx->irq_gpio); + if (gpio_is_valid(aw881xx->reset_gpio)) + devm_gpio_free(&i2c->dev, aw881xx->reset_gpio); + + devm_kfree(&i2c->dev, aw881xx); + aw881xx = NULL; + + return 0; +} + +static const struct i2c_device_id aw881xx_i2c_id[] = { + {AW881XX_I2C_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, aw881xx_i2c_id); + +static struct of_device_id aw881xx_dt_match[] = { + {.compatible = "awinic,aw881xx_smartpa"}, + {.compatible = "awinic,aw881xx_smartpa_l"}, + {.compatible = "awinic,aw881xx_smartpa_r"}, + {}, +}; + +static struct i2c_driver aw881xx_i2c_driver = { + .driver = { + .name = AW881XX_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw881xx_dt_match), + }, + .probe = aw881xx_i2c_probe, + .remove = aw881xx_i2c_remove, + .id_table = aw881xx_i2c_id, +}; + +static int __init aw881xx_i2c_init(void) +{ + int ret = -1; + + pr_info("%s: aw881xx driver version %s\n", __func__, AW881XX_VERSION); + + ret = i2c_add_driver(&aw881xx_i2c_driver); + if (ret) + pr_err("%s: fail to add aw881xx device into i2c\n", __func__); + + return ret; +} + +module_init(aw881xx_i2c_init); + +static void __exit aw881xx_i2c_exit(void) +{ + i2c_del_driver(&aw881xx_i2c_driver); +} + +module_exit(aw881xx_i2c_exit); + +MODULE_DESCRIPTION("ASoC AW881XX Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw881xx/aw881xx.h b/sound/soc/codecs/aw881xx/aw881xx.h new file mode 100644 index 0000000000000000000000000000000000000000..baacd76f688e436f87ddc6fec6e1fd3b7a291b9d --- /dev/null +++ b/sound/soc/codecs/aw881xx/aw881xx.h @@ -0,0 +1,188 @@ +/* Copyright (C) 2020 Tcl Corporation Limited */ +#ifndef __AW881XX_H__ +#define __AW881XX_H__ + +#include "aw881xx_monitor.h" +#include "aw881xx_cali.h" + +/******************************************** + * + * enum + * + *******************************************/ +enum aw881xx_scene_mode { + AW881XX_SPK_MODE, + AW881XX_VOICE_MODE, + AW881XX_FM_MODE, + AW881XX_RCV_MODE, + AW881XX_MODE_MAX, +}; + +enum aw881xx_id { + AW881XX_CHIPID = 0x1806, + AW881XX_PID_01 = 0x01, + AW881XX_PID_02 = 0x02, + AW881XX_PID_03 = 0x03, +}; + +enum aw881xx_dsp_pid { + AW881XX_DSP_PID_01 = 0x0000, + AW881XX_DSP_PID_02 = 0x0001, + AW881XX_DSP_PID_03 = 0x6E90, +}; + +enum aw881xx_memclk { + AW881XX_MEMCLK_OSC = 0, + AW881XX_MEMCLK_PLL = 1, +}; + +enum aw881xx_init { + AW881XX_INIT_ST = 0, + AW881XX_INIT_OK = 1, + AW881XX_INIT_NG = 2, +}; + +enum aw881xx_dsp_cfg { + AW881XX_DSP_WORK = 0, + AW881XX_DSP_BYPASS = 1, +}; + +enum aw881xx_baseaddr { + AW881XX_SPK_REG_ADDR = 0x00, + AW881XX_SPK_DSP_FW_ADDR = 0x8c00, + AW881XX_SPK_DSP_CFG_ADDR = 0x8600, + AW881XX_VOICE_REG_ADDR = 0x00, + AW881XX_VOICE_DSP_FW_ADDR = 0x8c00, + AW881XX_VOICE_DSP_CFG_ADDR = 0x8600, + AW881XX_FM_REG_ADDR = 0x00, + AW881XX_FM_DSP_FW_ADDR = 0x8c00, + AW881XX_FM_DSP_CFG_ADDR = 0x8600, + AW881XX_RCV_REG_ADDR = 0x00, + AW881XX_RCV_DSP_FW_ADDR = 0x8c00, + AW881XX_RCV_DSP_CFG_ADDR = 0x8600, +}; + +#define AW881XX_ADD_CHAN_NAME_SHIFT 2 + +#define AW881XX_READ_MSG_NUM 2 + +/* + * i2c transaction on Linux limited to 64k + * (See Linux kernel documentation: Documentation/i2c/writing-clients) +*/ +#define MAX_I2C_BUFFER_SIZE (65536) + +#define AW881XX_FLAG_START_ON_MUTE (1 << 0) +#define AW881XX_FLAG_SKIP_INTERRUPTS (1 << 1) + +#define AW881XX_NUM_RATES (9) +#define AW881XX_SYSST_CHECK_MAX (10) + +#define AW881XX_DFT_CALI_RE (0x8000) + +#define AW881XX_MONITOR_DFT_FLAG (0) +#define AW881XX_MONITOR_TIMER_DFT_VAL (30000) + +#define AW881XX_VBAT_COEFF_INT_10BIT (1023) + +#define AW881XX_MODE_CFG_NUM_MAX (3) +#define AW881XX_CFG_NUM_MAX (AW881XX_MODE_MAX * AW881XX_MODE_CFG_NUM_MAX) +#define AW881XX_CFG_NAME_MAX (64) + +/******************************************** + * + * DSP I2C WRITES + * + *******************************************/ +#define AW881XX_DSP_I2C_WRITES +#define AW881XX_MAX_RAM_WRITE_BYTE_SIZE (128) + +/******************************************** + * + * print information control + * + *******************************************/ +#define aw_dev_err(dev, format, ...) \ + pr_err("[%s]" format, dev_name(dev), ##__VA_ARGS__) + +#define aw_dev_info(dev, format, ...) \ + pr_info("[%s]" format, dev_name(dev), ##__VA_ARGS__) + +#define aw_dev_dbg(dev, format, ...) \ + pr_debug("[%s]" format, dev_name(dev), ##__VA_ARGS__) + +/******************************************** + * + * aw881xx struct + * + *******************************************/ +struct aw881xx { + struct regmap *regmap; + struct i2c_client *i2c; + struct snd_soc_component *component; + struct device *dev; + struct mutex lock; + struct mutex i2c_lock; + struct aw881xx_monitor monitor; + struct aw881xx_cali_attr cali_attr; + + int sysclk; + int rate; + int width; + int pstream; + int cstream; + + int reset_gpio; + int irq_gpio; + + uint8_t flags; + bool work_flag; + uint8_t init; + uint8_t scene_mode; + + uint16_t chipid; + uint8_t pid; + + uint8_t reg_addr; + uint16_t dsp_addr; + + uint8_t dsp_cfg; + char cfg_name[AW881XX_CFG_NUM_MAX][AW881XX_CFG_NAME_MAX]; + uint16_t cfg_num; + uint32_t dsp_fw_len; + uint32_t dsp_cfg_len; + + uint16_t intmask; + char *name_suffix; +}; + +struct aw881xx_container { + int len; + unsigned char data[]; +}; + +/****************************************************** + * + * aw881xx i2c write/read + * + ******************************************************/ +int aw881xx_reg_writes(struct aw881xx *aw881xx, + uint8_t reg_addr, uint8_t *buf, uint16_t len); + +int aw881xx_reg_write(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t reg_data); +int aw881xx_reg_read(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t *reg_data); +int aw881xx_reg_write_bits(struct aw881xx *aw881xx, + uint8_t reg_addr, uint16_t mask, uint16_t reg_data); +int aw881xx_dsp_write(struct aw881xx *aw881xx, + uint16_t dsp_addr, uint16_t dsp_data); +int aw881xx_dsp_read(struct aw881xx *aw881xx, + uint16_t dsp_addr, uint16_t *dsp_data); + +int aw881xx_get_iis_status(struct aw881xx *aw881xx); +int aw881xx_get_dsp_status(struct aw881xx *aw881xx); +int aw881xx_get_sysint(struct aw881xx *aw881xx, uint16_t *sysint); +int aw881xx_get_hmute(struct aw881xx *aw881xx); + +#endif diff --git a/sound/soc/codecs/aw881xx/aw881xx_cali.c b/sound/soc/codecs/aw881xx/aw881xx_cali.c new file mode 100644 index 0000000000000000000000000000000000000000..61944f7a71084f579d49c8139c0940a3b4bfea7d --- /dev/null +++ b/sound/soc/codecs/aw881xx/aw881xx_cali.c @@ -0,0 +1,352 @@ +/* Copyright (C) 2020 Tcl Corporation Limited */ +/* + * aw881xx_cali.c cali_module + * + * Version: v0.1.6 + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include "aw881xx.h" +#include "aw881xx_reg.h" +#include "aw881xx_cali.h" +#include "aw881xx_monitor.h" + +/****************************************************** + * + * aw881xx cali store + * + ******************************************************/ + +/*write cali to persist file example */ +#ifdef AW_CALI_STORE_EXAMPLE + +#define AWINIC_CALI_FILE "/oempersist/audio/aw_cali.bin" // MODIFIED by hongwei.tian, 2020-03-27,BUG-8980828 +#define AW_INT_DEC_DIGIT 10 +static int aw881xx_write_cali_re_to_file(uint32_t cali_re, char *name_suffix) +{ + struct file *fp; + char buf[50] = { 0 }; + loff_t pos = 0; + mm_segment_t fs; + char *channel; + + if (name_suffix == NULL){ + channel = "mono"; + }else if (!strcmp(name_suffix, "l")){ + channel = "left"; + }else if (!strcmp(name_suffix, "r")){ + channel = "right"; + pos = AW_INT_DEC_DIGIT; + }else { + pr_err("%s: name_suffix:%s error\n", __func__, channel); + return -EINVAL; + } + + fp = filp_open(AWINIC_CALI_FILE, O_RDWR | O_CREAT, 0664); // MODIFIED by hongwei.tian, 2020-03-31,BUG-8980828 + if (IS_ERR(fp)) { + pr_err("%s:channel:%s open %s failed!\n", + __func__, channel, AWINIC_CALI_FILE); + return -EINVAL; + } + + snprintf(buf, 50, "%10d", cali_re); + + fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, buf, strlen(buf), &pos); + + set_fs(fs); + + pr_info("%s: channel:%s buf:%s cali_re:%d\n", + __func__, channel, buf, cali_re); + + filp_close(fp, NULL); + return 0; +} + +static int aw881xx_get_cali_re_from_file(uint32_t *cali_re, char *name_suffix) +{ + struct file *fp; + int f_size; + char *buf; + int32_t int_cali_re = 0; + loff_t pos = 0; + mm_segment_t fs; + char *channel; + + if (name_suffix == NULL){ + channel = "mono"; + }else if (!strcmp(name_suffix, "l")){ + channel = "left"; + }else if (!strcmp(name_suffix, "r")){ + channel = "right"; + pos = AW_INT_DEC_DIGIT; + }else { + pr_err("%s: name_suffix:%s error\n", __func__, channel); + return -EINVAL; + } + + fp = filp_open(AWINIC_CALI_FILE, O_RDWR, 0); + if (IS_ERR(fp)) { + pr_err("%s:channel:%s open %s failed!\n", + __func__, channel, AWINIC_CALI_FILE); + return -EINVAL; + } + + f_size = AW_INT_DEC_DIGIT; + + buf = kzalloc(f_size + 1, GFP_ATOMIC); + if (!buf) { + pr_err("%s: channel:%s malloc mem %d failed!\n", + __func__, channel, f_size); + filp_close(fp, NULL); + return -EINVAL; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_read(fp, buf, f_size, &pos); + + set_fs(fs); + + if (sscanf(buf, "%d", &int_cali_re) == 1) + *cali_re = int_cali_re; + else + *cali_re = 0x8000; + + pr_info("%s: channel:%s buf:%s int_cali_re: %d\n", + __func__, channel, buf, int_cali_re); + + filp_close(fp, NULL); + + return 0; + +} +#endif + + +static int aw881xx_get_cali_re_from_phone(struct aw881xx *aw881xx) +{ + /* customer add, get re from nv or persist or cali file */ +#ifdef AW_CALI_STORE_EXAMPLE + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + + aw881xx_get_cali_re_from_file(&cali_attr->cali_re, + aw881xx->name_suffix); + +#endif + + return 0; +} + +void aw881xx_get_cali_re(struct aw881xx_cali_attr *cali_attr) +{ + struct aw881xx *aw881xx = + container_of(cali_attr, struct aw881xx, cali_attr); + + aw881xx_get_cali_re_from_phone(aw881xx); + + /* user the default cali re */ + if (0 == cali_attr->cali_re) { + cali_attr->cali_re = AW881XX_DFT_CALI_RE; + aw_dev_dbg(aw881xx->dev, + "%s: find no re, use default re=0x%x\n", __func__, + cali_attr->cali_re); + } +} + +static int aw881xx_set_cali_re_to_phone(struct aw881xx *aw881xx) +{ + /* customer add, set re to nv or persist or cali file */ +#ifdef AW_CALI_STORE_EXAMPLE + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + + aw881xx_write_cali_re_to_file(cali_attr->cali_re, aw881xx->name_suffix); + +#endif + + return 0; +} + +void aw881xx_set_cali_re_to_dsp(struct aw881xx *aw881xx) +{ + uint16_t cali_re = 0; + uint16_t dsp_ra = 0; + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + + aw881xx_dsp_read(aw881xx, AW881XX_DSP_REG_CFG_ADPZ_RA, &dsp_ra); + + cali_re = cali_attr->cali_re + dsp_ra; + + /* set cali re to aw881xx */ + aw881xx_dsp_write(aw881xx, AW881XX_DSP_REG_CFG_ADPZ_RE, + cali_attr->cali_re); + +} + +void aw881xx_set_cali_re(struct aw881xx_cali_attr *cali_attr) +{ + struct aw881xx *aw881xx = + container_of(cali_attr, struct aw881xx, cali_attr); + + aw881xx_set_cali_re_to_phone(aw881xx); + + /* set cali re to aw881xx */ + aw881xx_set_cali_re_to_dsp(aw881xx); + +} + +static ssize_t aw881xx_cali_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + int ret = -1; + unsigned int databuf[2] = { 0 }; + + ret = kstrtouint(buf, 0, &databuf[0]); + if (ret < 0) + return ret; + + cali_attr->cali_re = databuf[0] * (1 << AW881XX_DSP_RE_SHIFT) / 1000; + + pr_info("%s : re = %d \n ",__func__,cali_attr->re); // MODIFIED by hongwei.tian, 2020-03-27,BUG-8980828 + + aw881xx_set_cali_re(cali_attr); + + return count; +} + +static ssize_t aw881xx_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "cali_re=%dmohm\n", + (uint32_t) (cali_attr->cali_re * 1000) / + (1 << AW881XX_DSP_RE_SHIFT)); + + return len; +} + +static ssize_t aw881xx_re_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + int ret = -1; + unsigned int databuf[2] = { 0 }; + /* MODIFIED-BEGIN by hongwei.tian, 2020-03-27,BUG-8980828*/ + pr_info("%s : \n ",__func__); + ret = kstrtouint(buf, 0, &databuf[0]); + if (ret < 0) + return ret; + + cali_attr->re = databuf[0]; + pr_info("%s : re = %d \n ",__func__,cali_attr->re); + cali_attr->cali_re = cali_attr->re * (1 << AW881XX_DSP_RE_SHIFT) / 1000; + + pr_info("%s : cali_re = %d \n ",__func__,cali_attr->cali_re); + + aw881xx_set_cali_re(cali_attr); + /* MODIFIED-END by hongwei.tian,BUG-8980828*/ + return count; +} + +static ssize_t aw881xx_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "re=%dmohm\n", cali_attr->re); + + return len; +} + +static ssize_t aw881xx_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + int ret = -1; + unsigned int databuf[2] = { 0 }; + + ret = kstrtouint(buf, 0, &databuf[0]); + /* MODIFIED-BEGIN by hongwei.tian, 2020-03-27,BUG-8980828*/ + pr_info("%s : \n ",__func__); + if (ret < 0) + return ret; + + cali_attr->f0 = databuf[0]; + pr_info("%s : f0 = %d \n ",__func__,cali_attr->f0); + /* MODIFIED-END by hongwei.tian,BUG-8980828*/ + return count; +} + +static ssize_t aw881xx_f0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + struct aw881xx_cali_attr *cali_attr = &aw881xx->cali_attr; + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "f0=%dHz\n", cali_attr->f0); + + return len; +} + +static DEVICE_ATTR(cali, S_IWUSR | S_IRUGO, + aw881xx_cali_show, aw881xx_cali_store); +static DEVICE_ATTR(re, S_IWUSR | S_IRUGO, + aw881xx_re_show, aw881xx_re_store); +static DEVICE_ATTR(f0, S_IWUSR | S_IRUGO, + aw881xx_f0_show, aw881xx_f0_store); + +static struct attribute *aw881xx_cali_attr[] = { + &dev_attr_cali.attr, + &dev_attr_re.attr, + &dev_attr_f0.attr, + NULL +}; + +static struct attribute_group aw881xx_cali_attr_group = { + .attrs = aw881xx_cali_attr +}; + +void aw881xx_cali_init(struct aw881xx_cali_attr *cali_attr) +{ + int ret; + struct aw881xx *aw881xx = + container_of(cali_attr, struct aw881xx, cali_attr); + + ret = sysfs_create_group(&aw881xx->dev->kobj, &aw881xx_cali_attr_group); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s error creating sysfs attr files\n", __func__); + } +} diff --git a/sound/soc/codecs/aw881xx/aw881xx_cali.h b/sound/soc/codecs/aw881xx/aw881xx_cali.h new file mode 100644 index 0000000000000000000000000000000000000000..1d0ab936b1bb8076c7a8c01b43a761e7ab0c7271 --- /dev/null +++ b/sound/soc/codecs/aw881xx/aw881xx_cali.h @@ -0,0 +1,17 @@ +/* Copyright (C) 2020 Tcl Corporation Limited */ +#ifndef __AW881XX_CALI_H__ +#define __AW881XX_CALI_H__ + +#define AW_CALI_STORE_EXAMPLE + +struct aw881xx_cali_attr { + uint32_t cali_re; + uint32_t re; + uint32_t f0; +}; + +void aw881xx_set_cali_re(struct aw881xx_cali_attr *cali_attr); +void aw881xx_get_cali_re(struct aw881xx_cali_attr *cali_attr); +void aw881xx_cali_init(struct aw881xx_cali_attr *cali_attr); + +#endif diff --git a/sound/soc/codecs/aw881xx/aw881xx_monitor.c b/sound/soc/codecs/aw881xx/aw881xx_monitor.c new file mode 100644 index 0000000000000000000000000000000000000000..b5d90b21e04105da526b34e9defb68ac77e660fe --- /dev/null +++ b/sound/soc/codecs/aw881xx/aw881xx_monitor.c @@ -0,0 +1,641 @@ +/* Copyright (C) 2020 Tcl Corporation Limited */ +/* + * aw881xx_monitor.c monitor_module + * + * Version: v0.1.6 + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw881xx.h" +#include "aw881xx_reg.h" +#include "aw881xx_monitor.h" + +/* +static int aw88194_monitor_get_gain_value( + struct aw881xx *aw88194, uint16_t *reg_val) +{ + int ret = -1; + + if ((aw88194 == NULL) || (reg_val == NULL)) { + aw_dev_err(aw881xx->dev, "%s: aw88194 is %p, reg_val=%p\n", + __func__, aw88194, reg_val); + return ret; + } + + ret = aw88194_reg_read(aw88194, AW88194_REG_HAGCCFG7, reg_val); + *reg_val = *reg_val >> AW88194_HAGC_GAIN_SHIFT; + + return ret; +} +*/ + +static int aw881xx_monitor_set_gain_value(struct aw881xx *aw881xx, + uint16_t gain_value) +{ + int ret = -1; + uint16_t reg_val = 0; + uint16_t read_reg_val; + + if (aw881xx == NULL) { + aw_dev_err(aw881xx->dev, "%s: aw881xx is %p\n", + __func__, aw881xx); + return ret; + } + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_HAGCCFG7, ®_val); + if (ret) + return ret; + + /* check gain */ + read_reg_val = reg_val; + read_reg_val = read_reg_val >> AW881XX_HAGC_GAIN_SHIFT; + if (read_reg_val == gain_value) { + aw_dev_dbg(aw881xx->dev, "%s: gain_value=0x%x, no change\n", + __func__, gain_value); + return ret; + } + + reg_val &= AW881XX_HAGC_GAIN_MASK; + reg_val |= gain_value << AW881XX_HAGC_GAIN_SHIFT; + + ret = aw881xx_reg_write(aw881xx, AW881XX_REG_HAGCCFG7, reg_val); + if (ret < 0) + return ret; + + aw_dev_dbg(aw881xx->dev, "%s: set reg_val=0x%x, gain_value=0x%x\n", + __func__, reg_val, gain_value); + + return ret; +} + +/* +static int aw881xx_monitor_get_bst_ipeak( + struct aw881xx *aw881xx, uint16_t *reg_val) +{ + int ret = -1; + + if ((aw881xx == NULL) || (reg_val == NULL)) { + aw_dev_err(aw881xx->dev, "%s: aw881xx is %p, reg_val=%p\n", + __func__, aw881xx, reg_val); + return ret; + } + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_SYSCTRL2, reg_val); + *reg_val = *reg_val & (AW881XX_BIT_SYSCTRL2_BST_IPEAK_MASK); + + return ret; +} +*/ +static int aw881xx_monitor_set_bst_ipeak(struct aw881xx *aw881xx, + uint16_t bst_ipeak) +{ + int ret = -1; + uint16_t reg_val = 0; + uint16_t read_reg_val; + + if (aw881xx == NULL) { + aw_dev_err(aw881xx->dev, "%s: aw881xx is %p\n", + __func__, aw881xx); + return ret; + } + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_SYSCTRL2, ®_val); + if (ret < 0) + return ret; + + /* check ipeak */ + read_reg_val = reg_val; + read_reg_val = read_reg_val & (~AW881XX_BIT_SYSCTRL2_BST_IPEAK_MASK); + if (read_reg_val == bst_ipeak) { + aw_dev_dbg(aw881xx->dev, "%s: ipeak=0x%x, no change\n", + __func__, bst_ipeak); + return ret; + } + + reg_val &= AW881XX_BIT_SYSCTRL2_BST_IPEAK_MASK; + reg_val |= bst_ipeak; + + ret = aw881xx_reg_write(aw881xx, AW881XX_REG_SYSCTRL2, reg_val); + if (ret < 0) + return ret; + + aw_dev_dbg(aw881xx->dev, "%s: set reg_val=0x%x, bst_ipeak=0x%x\n", + __func__, reg_val, bst_ipeak); + + return ret; +} + +static int aw881xx_monitor_vmax_check(struct aw881xx *aw881xx) +{ + int ret = -1; + + ret = aw881xx_get_iis_status(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: no iis signal\n", __func__); + return ret; + } + + ret = aw881xx_get_dsp_status(aw881xx); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: dsp not work\n", __func__); + return ret; + } + + return 0; +} + +static int aw881xx_monitor_set_vmax(struct aw881xx *aw881xx, uint16_t vmax) +{ + int ret = -1; + uint16_t reg_val = 0; + + ret = aw881xx_monitor_vmax_check(aw881xx); + if (ret) { + aw_dev_err(aw881xx->dev, "%s: vamx_check fail, ret=%d\n", + __func__, ret); + return ret; + } + + ret = aw881xx_dsp_read(aw881xx, AW881XX_DSP_REG_VMAX, ®_val); + if (ret) + return ret; + + if (reg_val == vmax) { + aw_dev_info(aw881xx->dev, "%s: read vmax=0x%x\n", + __func__, reg_val); + return ret; + } + + ret = aw881xx_dsp_write(aw881xx, AW881XX_DSP_REG_VMAX, vmax); + if (ret) + return ret; + + return ret; +} + +static int aw881xx_monitor_get_voltage(struct aw881xx *aw881xx, + uint16_t *voltage) +{ + int ret = -1; + + if ((aw881xx == NULL) || (voltage == NULL)) { + aw_dev_err(aw881xx->dev, "%s aw881xx is %p, voltage=%p\n", + __func__, aw881xx, voltage); + return ret; + } + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_VBAT, voltage); + if (ret < 0) + return ret; + + *voltage = (*voltage) * AW881XX_VBAT_RANGE / + AW881XX_VBAT_COEFF_INT_10BIT; + + aw_dev_dbg(aw881xx->dev, "%s: chip voltage=%dmV\n", __func__, *voltage); + + return ret; +} + +static int aw881xx_monitor_get_temperature(struct aw881xx *aw881xx, + int16_t *temp) +{ + int ret = -1; + uint16_t reg_val = 0; + + if ((aw881xx == NULL) || (temp == NULL)) { + aw_dev_err(aw881xx->dev, "%s aw881xx= %p, temp=%p\n", + __func__, aw881xx, temp); + return ret; + } + + ret = aw881xx_reg_read(aw881xx, AW881XX_REG_TEMP, ®_val); + if (ret < 0) + return ret; + + if (reg_val & AW881XX_TEMP_SIGN_MASK) + reg_val |= AW881XX_TEMP_NEG_MASK; + + *temp = (int)reg_val; + + aw_dev_dbg(aw881xx->dev, "%s: chip_temperature=%d\n", __func__, *temp); + + return ret; +} + +static int aw881xx_monitor_check_voltage(struct aw881xx *aw881xx, + uint16_t *bst_ipeak, + uint16_t *gain_db) +{ + int ret = -1; + uint16_t voltage = 0; + struct aw881xx_monitor *monitor = &aw881xx->monitor; + + if ((aw881xx == NULL) || (bst_ipeak == NULL) || (gain_db == NULL)) { + aw_dev_err(aw881xx->dev, + "aw881xx is %p, bst_ipeak is %p, gain_db is %p\n", + aw881xx, bst_ipeak, gain_db); + return ret; + } + + ret = aw881xx_monitor_get_voltage(aw881xx, &voltage); + + if (voltage > AW881XX_VOL_LIMIT_40) { + *bst_ipeak = AW881XX_IPEAK_350; + *gain_db = AW881XX_GAIN_00DB; + monitor->pre_vol_bst_ipeak = *bst_ipeak; + monitor->pre_vol_gain_db = *gain_db; + } else if (voltage < AW881XX_VOL_LIMIT_39 && + voltage > AW881XX_VOL_LIMIT_38) { + *bst_ipeak = AW881XX_IPEAK_300; + *gain_db = AW881XX_GAIN_NEG_05DB; + monitor->pre_vol_bst_ipeak = *bst_ipeak; + monitor->pre_vol_gain_db = *gain_db; + } else if (voltage < AW881XX_VOL_LIMIT_37 && + voltage > AW881XX_VOL_LIMIT_36) { + *bst_ipeak = AW881XX_IPEAK_275; + *gain_db = AW881XX_GAIN_NEG_10DB; + monitor->pre_vol_bst_ipeak = *bst_ipeak; + monitor->pre_vol_gain_db = *gain_db; + } else if (voltage < AW881XX_VOL_LIMIT_35) { + *bst_ipeak = AW881XX_IPEAK_250; + *gain_db = AW881XX_GAIN_NEG_15DB; + monitor->pre_vol_bst_ipeak = *bst_ipeak; + monitor->pre_vol_gain_db = *gain_db; + } else { + *bst_ipeak = AW881XX_IPEAK_NONE; + *gain_db = AW881XX_GAIN_NONE; + } + aw_dev_info(aw881xx->dev, "%s: bst_ipeak=0x%x, gain_db=0x%x\n", + __func__, *bst_ipeak, *gain_db); + + return ret; +} + +static void aw881xx_monitor_check_temperature_deglitch(uint16_t *bst_ipeak, + uint16_t *gain_db, uint16_t *vmax, + int16_t temperature, int16_t pre_temp) +{ + if (temperature <= pre_temp) { + if (temperature <= AW881XX_TEMP_LIMIT_7 && + temperature >= AW881XX_TEMP_LIMIT_5) { + *bst_ipeak = AW881XX_IPEAK_350; + *gain_db = AW881XX_GAIN_00DB; + *vmax = AW881XX_VMAX_80; + } else if (temperature <= AW881XX_TEMP_LIMIT_2 && + temperature >= AW881XX_TEMP_LIMIT_0) { + *bst_ipeak = AW881XX_IPEAK_300; + *gain_db = AW881XX_GAIN_NEG_30DB; + *vmax = AW881XX_VMAX_70; + } else if (temperature <= AW881XX_TEMP_LIMIT_NEG_2 && + temperature >= AW881XX_TEMP_LIMIT_NEG_5) { + *bst_ipeak = AW881XX_IPEAK_275; + *gain_db = AW881XX_GAIN_NEG_45DB; + *vmax = AW881XX_VMAX_60; + } + } else { + if (temperature <= AW881XX_TEMP_LIMIT_7 && + temperature >= AW881XX_TEMP_LIMIT_5) { + *bst_ipeak = AW881XX_IPEAK_300; + *gain_db = AW881XX_GAIN_NEG_30DB; + *vmax = AW881XX_VMAX_70; + } else if (temperature <= AW881XX_TEMP_LIMIT_2 && + temperature >= AW881XX_TEMP_LIMIT_0) { + *bst_ipeak = AW881XX_IPEAK_275; + *gain_db = AW881XX_GAIN_NEG_45DB; + *vmax = AW881XX_VMAX_60; + } else if (temperature <= AW881XX_TEMP_LIMIT_NEG_2 && + temperature >= AW881XX_TEMP_LIMIT_NEG_5) { + *bst_ipeak = AW881XX_IPEAK_250; + *gain_db = AW881XX_GAIN_NEG_60DB; + *vmax = AW881XX_VMAX_50; + } + } +} + +static int aw881xx_monitor_check_temperature(struct aw881xx *aw881xx, + uint16_t *bst_ipeak, uint16_t *gain_db, uint16_t *vmax) +{ + int ret = -1; + int16_t temperature = 0; + int16_t pre_temp; + struct aw881xx_monitor *monitor = &aw881xx->monitor; + + if ((aw881xx == NULL) || (bst_ipeak == NULL) || + (gain_db == NULL) || (vmax == NULL)) { + aw_dev_err(aw881xx->dev, + "%s: aw881xx=%p, bst_ipeak=%p, gain_db=%p, vmax=%p\n", + __func__, aw881xx, bst_ipeak, gain_db, vmax); + return ret; + } + pre_temp = aw881xx->monitor.pre_temp; + + ret = aw881xx_monitor_get_temperature(aw881xx, &temperature); + aw881xx->monitor.pre_temp = temperature; + if (temperature > AW881XX_TEMP_LIMIT_7) { + *bst_ipeak = AW881XX_IPEAK_350; + *gain_db = AW881XX_GAIN_00DB; + *vmax = AW881XX_VMAX_80; + } else if (temperature < AW881XX_TEMP_LIMIT_5 && + temperature > AW881XX_TEMP_LIMIT_2) { + *bst_ipeak = AW881XX_IPEAK_300; + *gain_db = AW881XX_GAIN_NEG_30DB; + *vmax = AW881XX_VMAX_70; + } else if (temperature < AW881XX_TEMP_LIMIT_0 && + temperature > AW881XX_TEMP_LIMIT_NEG_2) { + *bst_ipeak = AW881XX_IPEAK_275; + *gain_db = AW881XX_GAIN_NEG_45DB; + *vmax = AW881XX_VMAX_60; + } else if (temperature < AW881XX_TEMP_LIMIT_NEG_5) { + *bst_ipeak = AW881XX_IPEAK_250; + *gain_db = AW881XX_GAIN_NEG_60DB; + *vmax = AW881XX_VMAX_50; + } else { + if (temperature == pre_temp) { + *bst_ipeak = monitor->pre_temp_bst_ipeak; + *gain_db = monitor->pre_temp_gain_db; + *vmax = monitor->pre_temp_vmax; + } else { + aw881xx_monitor_check_temperature_deglitch(bst_ipeak, + gain_db, vmax, temperature, pre_temp); + } + } + monitor->pre_temp_bst_ipeak = *bst_ipeak; + monitor->pre_temp_gain_db = *gain_db; + monitor->pre_temp_vmax = *vmax; + + aw_dev_info(aw881xx->dev, + "%s: bst_ipeak=0x%x, gain_db=0x%x, vmax=0x%0x\n", + __func__, *bst_ipeak, *gain_db, *vmax); + + return ret; +} + +static int aw881xx_monitor_check_sysint(struct aw881xx *aw881xx) +{ + int ret = -1; + uint16_t sysint = 0; + + if (aw881xx == NULL) { + aw_dev_err(aw881xx->dev, "%s: aw881xx is NULL\n", __func__); + return ret; + } + + ret = aw881xx_get_sysint(aw881xx, &sysint); + if (ret < 0) + aw_dev_err(aw881xx->dev, "%s: get_sysint fail, ret=%d\n", + __func__, ret); + else + aw_dev_info(aw881xx->dev, "%s: get_sysint=0x%04x\n", + __func__, ret); + + return ret; +} + +/* +void aw881xx_monitor_cal_ipeak(uint16_t *real_ipeak, + uint16_t vol_ipeak, uint16_t temp_ipeak) +{ + if (real_ipeak == NULL) { + aw_dev_err(aw881xx->dev, "%s: real_ipeak=%p\n", + __func__, real_ipeak); + return; + } + + if (vol_ipeak == AW881XX_IPEAK_NONE && + temp_ipeak == AW881XX_IPEAK_NONE) + *real_ipeak = AW881XX_IPEAK_NONE; + else + *real_ipeak = (vol_ipeak < temp_ipeak ? vol_ipeak : temp_ipeak); +} + +void aw881xx_monitor_cal_gain(uint16_t *real_gain, + uint16_t vol_gain, uint16_t temp_gain) +{ + if (real_gain == NULL) { + aw_dev_err(aw881xx->dev, "%s: real_gain=%p\n", + __func__, real_gain); + return; + } + + if (vol_gain == AW881XX_GAIN_NONE || + temp_gain == AW881XX_GAIN_NONE) { + if (vol_gain == AW881XX_GAIN_NONE && + temp_gain == AW881XX_GAIN_NONE) + *real_gain = AW881XX_GAIN_NONE; + else if (vol_gain == AW881XX_GAIN_NONE) + *real_gain = temp_gain; + else + *real_gain = vol_gain; + } else { + *real_gain = (vol_gain > temp_gain ? vol_gain : temp_gain); + } +} +*/ +void aw881xx_monitor_work(struct aw881xx *aw881xx) +{ + int ret; + uint16_t vol_ipeak = 0; + uint16_t vol_gain = 0; + uint16_t temp_ipeak = 0; + uint16_t temp_gain = 0; + uint16_t vmax = 0; + uint16_t real_ipeak; + uint16_t real_gain; + + /* get ipeak and gain value by voltage and temperature */ + ret = aw881xx_monitor_check_voltage(aw881xx, &vol_ipeak, &vol_gain); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: check voltage failed\n", + __func__); + return; + } + ret = + aw881xx_monitor_check_temperature(aw881xx, + &temp_ipeak, &temp_gain, &vmax); + if (ret < 0) { + aw_dev_err(aw881xx->dev, "%s: check temperature failed\n", + __func__); + return; + } + /* get min Ipeak */ + if (vol_ipeak == AW881XX_IPEAK_NONE && temp_ipeak == AW881XX_IPEAK_NONE) + real_ipeak = AW881XX_IPEAK_NONE; + else + real_ipeak = (vol_ipeak < temp_ipeak ? vol_ipeak : temp_ipeak); + + /* get min gain */ + if (vol_gain == AW881XX_GAIN_NONE || temp_gain == AW881XX_GAIN_NONE) { + if (vol_gain == AW881XX_GAIN_NONE && + temp_gain == AW881XX_GAIN_NONE) + real_gain = AW881XX_GAIN_NONE; + else if (vol_gain == AW881XX_GAIN_NONE) + real_gain = temp_gain; + else + real_gain = vol_gain; + } else { + real_gain = (vol_gain > temp_gain ? vol_gain : temp_gain); + } + + if (real_ipeak != AW881XX_IPEAK_NONE) + aw881xx_monitor_set_bst_ipeak(aw881xx, real_ipeak); + + if (real_gain != AW881XX_GAIN_NONE) + aw881xx_monitor_set_gain_value(aw881xx, real_gain); + + if (vmax != AW881XX_VMAX_NONE) + aw881xx_monitor_set_vmax(aw881xx, vmax); + + aw881xx_monitor_check_sysint(aw881xx); +} + +int aw881xx_monitor_stop(struct aw881xx_monitor *monitor) +{ + struct aw881xx *aw881xx = + container_of(monitor, struct aw881xx, monitor); + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + + if (hrtimer_active(&monitor->monitor_timer)) { + aw_dev_info(aw881xx->dev, "%s: cancel monitor\n", __func__); + hrtimer_cancel(&monitor->monitor_timer); + } + return 0; +} + +int aw881xx_monitor_start(struct aw881xx_monitor *monitor) +{ + int timer_val = monitor->monitor_timer_val; + struct aw881xx *aw881xx = + container_of(monitor, struct aw881xx, monitor); + + aw_dev_info(aw881xx->dev, "%s enter\n", __func__); + + if (!hrtimer_active(&monitor->monitor_timer)) { + aw_dev_info(aw881xx->dev, "%s: start monitor\n", __func__); + hrtimer_start(&monitor->monitor_timer, + ktime_set(timer_val / 1000, + (timer_val % 1000) * 1000000), + HRTIMER_MODE_REL); + } + return 0; +} + +static enum hrtimer_restart aw881xx_monitor_timer_func(struct hrtimer *timer) +{ + struct aw881xx_monitor *monitor = + container_of(timer, struct aw881xx_monitor, monitor_timer); + struct aw881xx *aw881xx = + container_of(monitor, struct aw881xx, monitor); + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + if (monitor->monitor_flag) + schedule_work(&monitor->monitor_work); + + return HRTIMER_NORESTART; +} + +static void aw881xx_monitor_work_routine(struct work_struct *work) +{ + struct aw881xx_monitor *monitor = + container_of(work, struct aw881xx_monitor, monitor_work); + struct aw881xx *aw881xx = + container_of(monitor, struct aw881xx, monitor); + + aw_dev_dbg(aw881xx->dev, "%s: enter\n", __func__); + + mutex_lock(&aw881xx->lock); + if (!aw881xx_get_hmute(aw881xx)) { + aw881xx_monitor_work(aw881xx); + aw881xx_monitor_start(monitor); + } + mutex_unlock(&aw881xx->lock); +} + +static ssize_t aw881xx_monitor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + int ret = -1; + unsigned int databuf[2] = { 0 }; + + ret = kstrtouint(buf, 0, &databuf[0]); + if (ret < 0) + return ret; + + mutex_lock(&aw881xx->lock); + if (aw881xx->monitor.monitor_flag == databuf[0]) + return 1; + + aw881xx->monitor.monitor_flag = databuf[0]; + if (databuf[0]) + schedule_work(&aw881xx->monitor.monitor_work); + mutex_unlock(&aw881xx->lock); + + return count; +} + +static ssize_t aw881xx_monitor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw881xx *aw881xx = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "aw881xx monitor_flag=%d\n", + aw881xx->monitor.monitor_flag); + + return len; +} + +static DEVICE_ATTR(monitor, S_IWUSR | S_IRUGO, + aw881xx_monitor_show, aw881xx_monitor_store); + +static struct attribute *aw881xx_monitor_attr[] = { + &dev_attr_monitor.attr, + NULL +}; + +static struct attribute_group aw881xx_monitor_attr_group = { + .attrs = aw881xx_monitor_attr +}; + +int aw881xx_monitor_init(struct aw881xx_monitor *monitor) +{ + int ret; + struct aw881xx *aw881xx = + container_of(monitor, struct aw881xx, monitor); + + aw_dev_info(aw881xx->dev, "%s: enter\n", __func__); + hrtimer_init(&monitor->monitor_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + monitor->monitor_timer.function = aw881xx_monitor_timer_func; + INIT_WORK(&monitor->monitor_work, aw881xx_monitor_work_routine); + + ret = sysfs_create_group(&aw881xx->dev->kobj, + &aw881xx_monitor_attr_group); + if (ret < 0) { + aw_dev_err(aw881xx->dev, + "%s error creating sysfs attr files\n", __func__); + } + + return 0; +} diff --git a/sound/soc/codecs/aw881xx/aw881xx_monitor.h b/sound/soc/codecs/aw881xx/aw881xx_monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..36d9b5ae1499551d44aa756aa89f20121dea56b7 --- /dev/null +++ b/sound/soc/codecs/aw881xx/aw881xx_monitor.h @@ -0,0 +1,77 @@ +/* Copyright (C) 2020 Tcl Corporation Limited */ +#ifndef __AW881XX_MONITOR_H__ +#define __AW881XX_MONITOR_H__ + +/******************************************** + * + * enum + * + *******************************************/ +enum { + AW881XX_VOL_LIMIT_35 = 3500, + AW881XX_VOL_LIMIT_36 = 3600, + AW881XX_VOL_LIMIT_37 = 3700, + AW881XX_VOL_LIMIT_38 = 3800, + AW881XX_VOL_LIMIT_39 = 3900, + AW881XX_VOL_LIMIT_40 = 4000, +}; + +enum { + AW881XX_TEMP_LIMIT_NEG_5 = -5, + AW881XX_TEMP_LIMIT_NEG_2 = -2, + AW881XX_TEMP_LIMIT_0 = 0, + AW881XX_TEMP_LIMIT_2 = 2, + AW881XX_TEMP_LIMIT_5 = 5, + AW881XX_TEMP_LIMIT_7 = 7, +}; + +enum { + AW881XX_IPEAK_350 = 0X04, + AW881XX_IPEAK_300 = 0X02, + AW881XX_IPEAK_275 = 0X01, + AW881XX_IPEAK_250 = 0X00, + AW881XX_IPEAK_NONE = 0XFF, +}; + +enum { + AW881XX_GAIN_00DB = 0X00, + AW881XX_GAIN_NEG_05DB = 0X01, + AW881XX_GAIN_NEG_10DB = 0X02, + AW881XX_GAIN_NEG_15DB = 0X03, + AW881XX_GAIN_NEG_30DB = 0X06, + AW881XX_GAIN_NEG_45DB = 0X09, + AW881XX_GAIN_NEG_60DB = 0X10, + AW881XX_GAIN_NONE = 0XFF, +}; + +enum { + AW881XX_VMAX_80 = 0XFA41, + AW881XX_VMAX_70 = 0XF918, + AW881XX_VMAX_60 = 0XF7C2, + AW881XX_VMAX_50 = 0XF6C2, + AW881XX_VMAX_NONE = 0XFFFF, +}; + +/******************************************** + * + * struct aw881xx_monitor + * + *******************************************/ +struct aw881xx_monitor { + struct hrtimer monitor_timer; + struct work_struct monitor_work; + uint32_t monitor_flag; + uint32_t monitor_timer_val; + int32_t pre_temp; + int32_t pre_vol_bst_ipeak; + int32_t pre_vol_gain_db; + int32_t pre_temp_bst_ipeak; + int32_t pre_temp_gain_db; + int32_t pre_temp_vmax; +}; + +int aw881xx_monitor_stop(struct aw881xx_monitor *monitor); +int aw881xx_monitor_start(struct aw881xx_monitor *monitor); +int aw881xx_monitor_init(struct aw881xx_monitor *monitor); + +#endif diff --git a/sound/soc/codecs/aw881xx/aw881xx_reg.h b/sound/soc/codecs/aw881xx/aw881xx_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..11103a91b5e6cc70be5364fbcdf75c657022114f --- /dev/null +++ b/sound/soc/codecs/aw881xx/aw881xx_reg.h @@ -0,0 +1,377 @@ +/* Copyright (C) 2020 Tcl Corporation Limited */ +#ifndef _AW881xx_REG_H_ +#define _AW881xx_REG_H_ + +/******************************************** + * Register List + *******************************************/ +#define AW881XX_REG_ID (0x00) +#define AW881XX_REG_SYSST (0x01) +#define AW881XX_REG_SYSINT (0x02) +#define AW881XX_REG_SYSINTM (0x03) +#define AW881XX_REG_SYSCTRL (0x04) +#define AW881XX_REG_I2SCTRL (0x05) +#define AW881XX_REG_I2SCFG1 (0x06) +#define AW881XX_REG_PWMCTRL (0x08) +#define AW881XX_REG_HAGCCFG1 (0x09) +#define AW881XX_REG_HAGCCFG2 (0x0A) +#define AW881XX_REG_HAGCCFG3 (0x0B) +#define AW881XX_REG_HAGCCFG4 (0x0C) +#define AW881XX_REG_HAGCCFG5 (0x0D) +#define AW881XX_REG_HAGCCFG6 (0x0E) +#define AW881XX_REG_HAGCCFG7 (0x0F) +#define AW881XX_REG_HAGCCFG8 (0x10) +#define AW881XX_REG_SYSCTRL2 (0x11) +#define AW881XX_REG_PRODID (0x12) +#define AW881XX_REG_DBGCTRL (0x20) +#define AW881XX_REG_I2SCFG2 (0x21) +#define AW881XX_REG_I2SSTAT (0x22) +#define AW881XX_REG_I2SCAPCNT (0x23) +#define AW881XX_REG_TM (0x34) +#define AW881XX_REG_CRCIN (0x38) +#define AW881XX_REG_CRCOUT (0x39) +#define AW881XX_REG_DSPMADD (0x40) +#define AW881XX_REG_DSPMDAT (0x41) +#define AW881XX_REG_WDT (0x42) +#define AW881XX_REG_ACR1 (0x43) +#define AW881XX_REG_ACR2 (0x44) +#define AW881XX_REG_ASR1 (0x45) +#define AW881XX_REG_ASR2 (0x46) +#define AW881XX_REG_DSPCFG (0x47) +#define AW881XX_REG_ASR3 (0x48) +#define AW881XX_REG_ASR4 (0x49) +#define AW881XX_REG_BSTCTRL1 (0x60) +#define AW881XX_REG_BSTCTRL2 (0x61) +#define AW881XX_REG_BSTCTRL3 (0x62) +#define AW881XX_REG_BSTDBG1 (0x63) +#define AW881XX_REG_BSTDBG2 (0x64) +#define AW881XX_REG_PLLCTRL1 (0x65) +#define AW881XX_REG_PLLCTRL2 (0x66) +#define AW881XX_REG_AMPDBG1 (0x67) +#define AW881XX_REG_AMPDBG2 (0x68) +#define AW881XX_REG_CDACTRL1 (0x69) +#define AW881XX_REG_CDACTRL2 (0x6A) +#define AW881XX_REG_ISECTRL1 (0x6B) +#define AW881XX_REG_SADCCTRL (0x6C) +#define AW881XX_REG_VBAT (0x6D) +#define AW881XX_REG_TEMP (0x6E) +#define AW881XX_REG_TEST (0x70) +#define AW881XX_REG_TEST2 (0x71) +#define AW881XX_REG_EFCTR1 (0x72) +#define AW881XX_REG_EFCTR2 (0x73) +#define AW881XX_REG_EFWH (0x74) +#define AW881XX_REG_EFWM (0x75) +#define AW881XX_REG_EFWL (0x76) +#define AW881XX_REG_EFRH (0x77) +#define AW881XX_REG_EFRM (0x78) +#define AW881XX_REG_PRODUCT_ID (0x79) +#define AW881XX_REG_TESTDET (0x7A) + +#define AW881XX_REG_MAX (0x7F) + +/******************************************** + * Register Access + *******************************************/ +#define REG_NONE_ACCESS (0) +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) + +static const unsigned char aw881xx_reg_access[AW881XX_REG_MAX] = { + [AW881XX_REG_ID] = REG_RD_ACCESS, + [AW881XX_REG_SYSST] = REG_RD_ACCESS, + [AW881XX_REG_SYSINT] = REG_RD_ACCESS, + [AW881XX_REG_SYSINTM] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_SYSCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_I2SCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_I2SCFG1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_PWMCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG3] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG4] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG5] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG6] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG7] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_HAGCCFG8] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_SYSCTRL2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_PRODID] = REG_RD_ACCESS, + [AW881XX_REG_DBGCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_I2SCFG2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_I2SSTAT] = REG_RD_ACCESS, + [AW881XX_REG_I2SCAPCNT] = REG_RD_ACCESS, + [AW881XX_REG_TM] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_CRCIN] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_CRCOUT] = REG_RD_ACCESS, + [AW881XX_REG_DSPMADD] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_DSPMDAT] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_WDT] = REG_RD_ACCESS, + [AW881XX_REG_ACR1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_ACR2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_ASR1] = REG_RD_ACCESS, + [AW881XX_REG_ASR2] = REG_RD_ACCESS, + [AW881XX_REG_DSPCFG] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_ASR3] = REG_RD_ACCESS, + [AW881XX_REG_ASR4] = REG_RD_ACCESS, + [AW881XX_REG_BSTCTRL1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_BSTCTRL2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_BSTCTRL3] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_BSTDBG1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_BSTDBG2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_PLLCTRL1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_PLLCTRL2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_AMPDBG1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_AMPDBG2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_CDACTRL1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_CDACTRL2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_ISECTRL1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_SADCCTRL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_VBAT] = REG_RD_ACCESS, + [AW881XX_REG_TEMP] = REG_RD_ACCESS, + [AW881XX_REG_TEST] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_TEST2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_EFCTR1] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_EFCTR2] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_EFWH] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_EFWM] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_EFWL] = REG_RD_ACCESS | REG_WR_ACCESS, + [AW881XX_REG_EFRH] = REG_RD_ACCESS, + [AW881XX_REG_EFRM] = REG_RD_ACCESS, + [AW881XX_REG_PRODUCT_ID] = REG_RD_ACCESS, + [AW881XX_REG_TESTDET] = REG_RD_ACCESS, +}; + +/****************************************************** + * Register Detail + *****************************************************/ +/* SYSST */ +#define AW881XX_BIT_SYSST_OVP2S (1 << 15) +#define AW881XX_BIT_SYSST_UVLOS (1 << 14) +#define AW881XX_BIT_SYSST_ADPS (1 << 13) +#define AW881XX_BIT_SYSST_DSPS (1 << 12) +#define AW881XX_BIT_SYSST_BSTOCS (1 << 11) +#define AW881XX_BIT_SYSST_OVPS (1 << 10) +#define AW881XX_BIT_SYSST_BSTS (1 << 9) +#define AW881XX_BIT_SYSST_SWS (1 << 8) +#define AW881XX_BIT_SYSST_CLIPS (1 << 7) +#define AW881XX_BIT_SYSST_WDS (1 << 6) +#define AW881XX_BIT_SYSST_NOCLKS (1 << 5) +#define AW881XX_BIT_SYSST_CLKS (1 << 4) +#define AW881XX_BIT_SYSST_OCDS (1 << 3) +#define AW881XX_BIT_SYSST_CLIP_PRES (1 << 2) +#define AW881XX_BIT_SYSST_OTHS (1 << 1) +#define AW881XX_BIT_SYSST_PLLS (1 << 0) +#define AW881XX_BIT_SYSST_CHECK_MASK \ + (~(AW881XX_BIT_SYSST_UVLOS | \ + AW881XX_BIT_SYSST_BSTOCS | \ + AW881XX_BIT_SYSST_BSTS | \ + AW881XX_BIT_SYSST_SWS | \ + AW881XX_BIT_SYSST_NOCLKS | \ + AW881XX_BIT_SYSST_CLKS | \ + AW881XX_BIT_SYSST_OCDS | \ + AW881XX_BIT_SYSST_OTHS | \ + AW881XX_BIT_SYSST_PLLS)) + +#define AW881XX_BIT_SYSST_CHECK \ + (AW881XX_BIT_SYSST_BSTS | \ + AW881XX_BIT_SYSST_SWS | \ + AW881XX_BIT_SYSST_CLKS | \ + AW881XX_BIT_SYSST_PLLS) + +#define AW881XX_BIT_IIS_CHECK_MASK \ + (~(AW881XX_BIT_SYSST_UVLOS | \ + AW881XX_BIT_SYSST_NOCLKS | \ + AW881XX_BIT_SYSST_CLKS | \ + AW881XX_BIT_SYSST_OCDS | \ + AW881XX_BIT_SYSST_OTHS | \ + AW881XX_BIT_SYSST_PLLS)) + +#define AW881XX_BIT_IIS_CHECK \ + (AW881XX_BIT_SYSST_CLKS | \ + AW881XX_BIT_SYSST_PLLS) + +/* SYSINT */ +#define AW881XX_BIT_SYSINT_OVP2I (1 << 15) +#define AW881XX_BIT_SYSINT_UVLOI (1 << 14) +#define AW881XX_BIT_SYSINT_ADPI (1 << 13) +#define AW881XX_BIT_SYSINT_DSPI (1 << 12) +#define AW881XX_BIT_SYSINT_BSTOCI (1 << 11) +#define AW881XX_BIT_SYSINT_OVPI (1 << 10) +#define AW881XX_BIT_SYSINT_BSTI (1 << 9) +#define AW881XX_BIT_SYSINT_SWI (1 << 8) +#define AW881XX_BIT_SYSINT_CLIPI (1 << 7) +#define AW881XX_BIT_SYSINT_WDI (1 << 6) +#define AW881XX_BIT_SYSINT_NOCLKI (1 << 5) +#define AW881XX_BIT_SYSINT_CLKI (1 << 4) +#define AW881XX_BIT_SYSINT_OCDI (1 << 3) +#define AW881XX_BIT_SYSINT_CLIP_PREI (1 << 2) +#define AW881XX_BIT_SYSINT_OTHI (1 << 1) +#define AW881XX_BIT_SYSINT_PLLI (1 << 0) + +/* SYSINTM */ +#define AW881XX_REG_SYSINTM_MASK (0xffff) +#define AW881XX_BIT_SYSINTM_OVP2SM (1 << 15) +#define AW881XX_BIT_SYSINTM_UVLOM (1 << 14) +#define AW881XX_BIT_SYSINTM_ADPM (1 << 13) +#define AW881XX_BIT_SYSINTM_DSPM (1 << 12) +#define AW881XX_BIT_SYSINTM_BSTOCM (1 << 11) +#define AW881XX_BIT_SYSINTM_OVPM (1 << 10) +#define AW881XX_BIT_SYSINTM_BSTM (1 << 9) +#define AW881XX_BIT_SYSINTM_SWM (1 << 8) +#define AW881XX_BIT_SYSINTM_CLIPM (1 << 7) +#define AW881XX_BIT_SYSINTM_WDM (1 << 6) +#define AW881XX_BIT_SYSINTM_NOCLKM (1 << 5) +#define AW881XX_BIT_SYSINTM_CLKM (1 << 4) +#define AW881XX_BIT_SYSINTM_OCDM (1 << 3) +#define AW881XX_BIT_SYSINTM_CLIP_PREM (1 << 2) +#define AW881XX_BIT_SYSINTM_OTHM (1 << 1) +#define AW881XX_BIT_SYSINTM_PLLM (1 << 0) + +/* SYSCTRL */ +#define AW881XX_BIT_SYSCTRL_MODE_MASK (~(1 << 7)) +#define AW881XX_BIT_SYSCTRL_RCV_MODE (1 << 7) +#define AW881XX_BIT_SYSCTRL_SPK_MODE (0 << 7) +#define AW881XX_BIT_SYSCTRL_DSP_MASK (~(1 << 2)) +#define AW881XX_BIT_SYSCTRL_DSP_BYPASS (1 << 2) +#define AW881XX_BIT_SYSCTRL_DSP_WORK (0 << 2) +#define AW881XX_BIT_SYSCTRL_PW_MASK (~(1 << 0)) +#define AW881XX_BIT_SYSCTRL_PW_PDN (1 << 0) +#define AW881XX_BIT_SYSCTRL_PW_ACTIVE (0 << 0) + +/* I2SCTRL */ +#define AW881XX_BIT_I2SCTRL_INPLEV_MASK (~(1 << 13)) +#define AW881XX_BIT_I2SCTRL_INPLEV_0DB (1 << 13) +#define AW881XX_BIT_I2SCTRL_INPLEV_NEG_6DB (0 << 13) +#define AW881XX_BIT_I2SCTRL_STEREO_MASK (~(1 << 12)) +#define AW881XX_BIT_I2SCTRL_STEREO_ENABLE (1 << 12) +#define AW881XX_BIT_I2SCTRL_STEREO_DISABLE (0 << 12) +#define AW881XX_BIT_I2SCTRL_CHS_MASK (~(3 << 10)) +#define AW881XX_BIT_I2SCTRL_CHS_MONO (3 << 10) +#define AW881XX_BIT_I2SCTRL_CHS_RIGHT (2 << 10) +#define AW881XX_BIT_I2SCTRL_CHS_LEFT (1 << 10) +#define AW881XX_BIT_I2SCTRL_MD_MASK (~(3 << 8)) +#define AW881XX_BIT_I2SCTRL_MD_LSB (2 << 8) +#define AW881XX_BIT_I2SCTRL_MD_MSB (1 << 8) +#define AW881XX_BIT_I2SCTRL_MD_STD (0 << 8) +#define AW881XX_BIT_I2SCTRL_FMS_MASK (~(3 << 6)) +#define AW881XX_BIT_I2SCTRL_FMS_32BIT (3 << 6) +#define AW881XX_BIT_I2SCTRL_FMS_24BIT (2 << 6) +#define AW881XX_BIT_I2SCTRL_FMS_20BIT (1 << 6) +#define AW881XX_BIT_I2SCTRL_FMS_16BIT (0 << 6) +#define AW881XX_BIT_I2SCTRL_BCK_MASK (~(3 << 4)) +#define AW881XX_BIT_I2SCTRL_BCK_64FS (2 << 4) +#define AW881XX_BIT_I2SCTRL_BCK_48FS (1 << 4) +#define AW881XX_BIT_I2SCTRL_BCK_32FS (0 << 4) +#define AW881XX_BIT_I2SCTRL_SR_MASK (~(15 << 0)) +#define AW881XX_BIT_I2SCTRL_SR_192K (10 << 0) +#define AW881XX_BIT_I2SCTRL_SR_96K (9 << 0) +#define AW881XX_BIT_I2SCTRL_SR_48K (8 << 0) +#define AW881XX_BIT_I2SCTRL_SR_44P1K (7 << 0) +#define AW881XX_BIT_I2SCTRL_SR_32K (6 << 0) +#define AW881XX_BIT_I2SCTRL_SR_24K (5 << 0) +#define AW881XX_BIT_I2SCTRL_SR_22K (4 << 0) +#define AW881XX_BIT_I2SCTRL_SR_16K (3 << 0) +#define AW881XX_BIT_I2SCTRL_SR_12K (2 << 0) +#define AW881XX_BIT_I2SCTRL_SR_11K (1 << 0) +#define AW881XX_BIT_I2SCTRL_SR_8K (0 << 0) + +/* PWMCTRL */ +#define AW881XX_BIT_PWMCTRL_HMUTE_MASK (~(1 << 0)) +#define AW881XX_BIT_PWMCTRL_HMUTE_ENABLE (1 << 0) +#define AW881XX_BIT_PWMCTRL_HMUTE_DISABLE (0 << 0) + +/* SYSCTRL2 */ +#define AW881XX_BIT_SYSCTRL2_MEMCLK_MASK (~(1 << 12)) +#define AW881XX_BIT_SYSCTRL2_MEMCLK_PLL (1 << 12) +#define AW881XX_BIT_SYSCTRL2_MEMCLK_OSC (0 << 12) +#define AW881XX_BIT_SYSCTRL2_BST_IPEAK_MASK (~(7 << 0)) + +/* HAGCCFG7 */ +#define AW881XX_BIT_HAGCCFG7_VOL_MASK (~(255 << 8)) +#define AW881XX_VOLUME_MAX (0) +#define AW881XX_VOLUME_MIN (-192) +#define AW881XX_VOL_REG_SHIFT (8) +#define AW881XX_VOL_6DB_STEP (6 * 2) + +/* BSTCTRL3 */ +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_MASK (~(15 << 0)) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_10P25V (15 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_10V (14 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_9P75V (13 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_9P5V (12 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_9P25V (11 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_9V (10 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_8P75V (9 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_8P5V (8 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_8P25V (7 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_8V (6 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_7P75V (5 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_7P5V (4 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_7P25V (3 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_7V (2 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_6P75V (1 << 0) +#define AW881XX_BIT_BSTCTRL3_BST_VOUT_6P5V (0 << 0) + +/* PRODUCT ID */ +#define AW881XX_BIT_PRODUCT_ID_MASK (~(15 << 0)) + +/******************************************** + * DSP + *******************************************/ +#define AW881XX_DSP_RE_SHIFT (12) +#define AW881XX_REG_DSP_PID (0x1F80) +#define AW881XX_DSP_BASE_ADDR (0x8600) +#define AW881XX_DSP_REG_CFG_MBMEC_GLBCFG (0x8662) +#define AW881XX_DSP_REG_CFG_MBMEC_ACTAMPTH (0x8664) +#define AW881XX_DSP_REG_CFG_MBMEC_NOISEAMPTH (0x8666) +#define AW881XX_DSP_REG_CFG_ADPZ_USTEPN (0x867B) +#define AW881XX_DSP_REG_CFG_ADPZ_RE (0x8677) +#define AW881XX_DSP_REG_CFG_ADPZ_RA (0x8678) + +#define AW881XX_DSP_REG_ST_STE_RE (0x81A6) +#define AW881XX_DSP_REG_ST_STE_RE_DECIMAL_SHIFT (12) +#define AW881XX_DSP_REG_ST_STE_TE (0x81A8) +#define AW881XX_DSP_REG_ST_STE_TE_DECIMAL_SHIFT (0) +#define AW881XX_DSP_REG_ST_ADPZ_A1FILTER (0x8732) +#define AW881XX_DSP_REG_ST_ADPZ_A1_DECIMAL_SHIFT (17) +#define AW881XX_DSP_REG_ST_ADPZ_A2FILTER (0x8734) +#define AW881XX_DSP_REG_ST_ADPZ_A2_DECIMAL_SHIFT (17) +#define AW881XX_DSP_REG_VCALB (0x866D) +#define AW881XX_DSP_REG_VMAX (0x8614) +#define AW881XX_DSP_REG_TEMP_FACTOR (0x8682) + + + +/******************************************** + * Vcalb + *******************************************/ +#define AW881XX_VCAL_FACTOR (1 << 12) +#define AW881XX_VSCAL_FACTOR (1550) +#define AW881XX_EF_ISENSE_GAINERR_SLP (0x78) +#define AW881XX_EF_ISENSE_GAINERR_SLP_MASK (255 << 0) +#define AW881XX_EF_ISENSE_GAINERR_SLP_NEG (0xff00) +#define AW881XX_EF_ISENSE_GAINERR_SLP_SIGN_MASK (1 << 7) + +#define AW881XX_ISCAL_FACTOR (426) +#define AW881XX_EF_VSENSE_GAIN (0x79) +#define AW881XX_EF_VSENSE_GAIN_MASK (63 << 0) +#define AW881XX_EF_VSENSE_GAIN_SHIFT (10) +#define AW881XX_EF_VSENSE_GAIN_NEG (0xffe0) +#define AW881XX_EF_VSENSE_GAIN_SIGN_MASK (1 << 5) + +#define AW881XX_ICABLK_FACTOR (2) +#define AW881XX_VCABLK_FACTOR (5) +#define AW881XX_CABL_BASE_VALUE (1000) + +/******************************************** + * Monitor + *******************************************/ +#define AW881XX_BST_IPEAK_DFT_LIMIT (0) +#define AW881XX_VBAT_RANGE (6025) +#define AW881XX_HAGC_GAIN_SHIFT (8) +#define AW881XX_HAGC_GAIN_MASK (0x00ff) + +#define AW881XX_TEMP_SIGN_MASK (1 << 9) +#define AW881XX_TEMP_NEG_MASK (0xFC00) +#define AW881XX_INT_10BIT (1023) + +#endif diff --git a/sound/soc/codecs/aw882xx/aw882xx.c b/sound/soc/codecs/aw882xx/aw882xx.c new file mode 100644 index 0000000000000000000000000000000000000000..cb84a35e1255cc850c7fcd73043c36fcefbdf750 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx.c @@ -0,0 +1,2253 @@ +/* + * aw882xx.c aw882xx codec module + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx.h" +#include "aw882xx_reg.h" +#include "awinic_cali.h" +#include "awinic_monitor.h" +#include "awinic_dsp.h" + + +/****************************************************** + * + * Marco + * + ******************************************************/ +#define AW882XX_I2C_NAME "aw882xx_smartpa" + +#define AW882XX_DRIVER_VERSION "v0.2.4" + +#define AW882XX_RATES SNDRV_PCM_RATE_8000_48000 +#define AW882XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define AW_I2C_RETRIES 5 /* 5 times */ +#define AW_I2C_RETRY_DELAY 5 /* 5 ms */ +#define AW_READ_CHIPID_RETRIES 5 /* 5 times */ +#define AW_READ_CHIPID_RETRY_DELAY 5 /* 5 ms */ + +/****************************************************** + * + * copp enable + * + ******************************************************/ +static DEFINE_MUTEX(g_aw_copp_lock); +unsigned int g_copp_en = 0; + +extern int i2c_check_status_create(char *name,int value); +bool aw882xx_i2c_check = false; +static int aw_select_pin_ctl(struct aw882xx *aw882xx, const char *name); +/****************************************************** + * The prefix of the bin file name + * The file suffix is added based on the channel + * example : aw882xx_spk_reg_l.bin + * notice : The mono file name suffix is ".bin" + ******************************************************/ +static char aw882xx_cfg_name[][AW882XX_CFG_NAME_MAX] = { + {"aw882xx_spk_reg"}, + {"aw882xx_rcv_reg"}, + {"aw882xx_voice_reg"}, +}; + +static unsigned int aw882xx_mode_cfg_shift[AW882XX_MODE_SHIFT_MAX] = { + AW882XX_MODE_SPK_SHIFT, + AW882XX_MODE_RCV_SHIFT, + AW882XX_MODE_VOICE_SHIFT, +}; + +/****************************************************** + * + * aw882xx distinguish between codecs and components by version + * + ******************************************************/ +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static const struct aw_componet_codec_ops aw_componet_codec_ops = { + .aw_snd_soc_kcontrol_codec = snd_soc_kcontrol_component, + .aw_snd_soc_codec_get_drvdata = snd_soc_component_get_drvdata, + .aw_snd_soc_add_codec_controls = snd_soc_add_component_controls, + .aw_snd_soc_unregister_codec = snd_soc_unregister_component, + .aw_snd_soc_register_codec = snd_soc_register_component, +}; +#else +static const struct aw_componet_codec_ops aw_componet_codec_ops = { + .aw_snd_soc_kcontrol_codec = snd_soc_kcontrol_codec, + .aw_snd_soc_codec_get_drvdata = snd_soc_codec_get_drvdata, + .aw_snd_soc_add_codec_controls = snd_soc_add_codec_controls, + .aw_snd_soc_unregister_codec = snd_soc_unregister_codec, + .aw_snd_soc_register_codec = snd_soc_register_codec, +}; +#endif + +static aw_snd_soc_codec_t *aw_get_codec(struct snd_soc_dai *dai) +{ +#ifdef AW_KERNEL_VER_OVER_4_19_1 + return dai->component; +#else + return dai->codec; +#endif +} + + +/****************************************************** + * + * aw882xx append suffix sound channel information + * + ******************************************************/ +static void *aw882xx_devm_kstrdup(struct device *dev, char *buf) +{ + char *str = NULL; + + str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (str == NULL) + return str; + memcpy(str, buf, strlen(buf)); + return str; +} + +int aw882xx_append_suffix(char *format, const char **change_name, + struct aw882xx *aw882xx) +{ + char buf[64] = { 0 }; + + if (!aw882xx->chan_info.name_suffix) + return 0; + + snprintf(buf, sizeof(buf), format, *change_name, aw882xx->chan_info.name_suffix); + *change_name = aw882xx_devm_kstrdup(aw882xx->dev, buf); + if (!(*change_name)) { + pr_err("%s: %s devm_kstrdup failed\n", __func__, buf); + return -ENOMEM; + } + aw_dev_dbg(aw882xx->dev, "%s:change name :%s\n", + __func__, *change_name); + return 0; +} + + + +/****************************************************** + * + * aw882xx i2c write/read + * + ******************************************************/ +static int aw882xx_i2c_writes(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned char *buf, unsigned int len) +{ + int ret = -1; + unsigned char *data = NULL; + + data = kmalloc(len+1, GFP_KERNEL); + if (data == NULL) { + aw_dev_err(aw882xx->dev, "%s: can not allocate memory\n", + __func__); + return -ENOMEM; + } + + data[0] = reg_addr; + memcpy(&data[1], buf, len); + + ret = i2c_master_send(aw882xx->i2c, data, len+1); + if (ret < 0) + aw_dev_err(aw882xx->dev, + "%s: i2c master send error\n", __func__); + + kfree(data); + data = NULL; + + return ret; +} + +static int aw882xx_i2c_reads(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned char *data_buf, unsigned int data_len) +{ + int ret; + struct i2c_msg msg[] = { + [0] = { + .addr = aw882xx->i2c->addr, + .flags = 0, + .len = sizeof(uint8_t), + .buf = ®_addr, + }, + [1] = { + .addr = aw882xx->i2c->addr, + .flags = I2C_M_RD, + .len = data_len, + .buf = data_buf, + }, + }; + + ret = i2c_transfer(aw882xx->i2c->adapter, msg, ARRAY_SIZE(msg)); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: transfer failed.", __func__); + return ret; + } else if (ret != AW882XX_I2C_READ_MSG_NUM) { + aw_dev_err(aw882xx->dev, "%s: transfer failed(size error).\n", + __func__); + return -ENXIO; + } + + return 0; +} + +int aw882xx_i2c_write(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char buf[2]; + + buf[0] = (reg_data&0xff00)>>8; + buf[1] = (reg_data&0x00ff)>>0; + + while (cnt < AW_I2C_RETRIES) { + ret = aw882xx_i2c_writes(aw882xx, reg_addr, buf, 2); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s: i2c_write cnt=%d error=%d\n", + __func__, cnt, ret); + else + break; + cnt++; + } + + return ret; +} + +int aw882xx_i2c_read(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int *reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char buf[2]; + + while (cnt < AW_I2C_RETRIES) { + ret = aw882xx_i2c_reads(aw882xx, reg_addr, buf, 2); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: i2c_read cnt=%d error=%d\n", + __func__, cnt, ret); + } else { + *reg_data = (buf[0]<<8) | (buf[1]<<0); + break; + } + cnt++; + } + + return ret; +} + +static int aw882xx_i2c_write_bits(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int mask, unsigned int reg_data) +{ + int ret = -1; + unsigned int reg_val = 0; + + ret = aw882xx_i2c_read(aw882xx, reg_addr, ®_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, + "%s: i2c read error, ret=%d\n", __func__, ret); + return ret; + } + reg_val &= mask; + reg_val |= reg_data; + ret = aw882xx_i2c_write(aw882xx, reg_addr, reg_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, + "%s: i2c read error, ret=%d\n", __func__, ret); + return ret; + } + + return 0; +} + +/****************************************************** + * + * aw882xx control + * + ******************************************************/ +/*[7 : 4]: -6DB ; [3 : 0]: 0.5DB real_value = value * 2 : 0.5db --> 1*/ +uint32_t aw882xx_reg_val_to_db(uint32_t value) +{ + return ((value >> 4) * AW882XX_VOL_6DB_STEP + (value & 0x0f)); +} + +/*[7 : 4]: -6DB ; [3 : 0]: -0.5DB reg_value = value / step << 4 + value % step ; step = 6 * 2*/ +static uint32_t aw882xx_db_val_to_reg(uint32_t value) +{ + return (((value / AW882XX_VOL_6DB_STEP) << 4) + + (value % AW882XX_VOL_6DB_STEP)); +} + +int aw882xx_set_volume(struct aw882xx *aw882xx, uint32_t value) +{ + uint32_t reg_value = 0; + uint32_t real_value = aw882xx_db_val_to_reg(value); + + /* cal real value */ + aw882xx_i2c_read(aw882xx, AW882XX_HAGCCFG4_REG, ®_value); + + aw_dev_dbg(aw882xx->dev, "%s: value %d , 0x%x\n", + __func__, value, real_value); + + /*15 : 8] volume*/ + real_value = (real_value << 8) | (reg_value & 0x00ff); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW882XX_HAGCCFG4_REG, real_value); + + return 0; +} + +int aw882xx_get_volume(struct aw882xx *aw882xx, uint32_t *value) +{ + uint32_t reg_value = 0; + uint32_t real_value = 0; + + /* read value */ + aw882xx_i2c_read(aw882xx, AW882XX_HAGCCFG4_REG, ®_value); + + /*[15 : 8] volume*/ + real_value = reg_value >> 8; + + real_value = aw882xx_reg_val_to_db(real_value); + *value = real_value; + + return 0; +} + +static int aw882xx_fade_in_out(struct aw882xx *aw882xx, bool fade_in) +{ + int i = 0; + uint32_t start_volume = 0; + + /*volume up*/ + if (fade_in) { + for (i = AW_FADE_OUT_TARGET_VOL; i >= (int32_t)aw882xx->db_offset; + i -= aw882xx->fade_step) { + if (i < (int32_t)aw882xx->fade_step) + i = aw882xx->db_offset; + aw882xx_set_volume(aw882xx, i); + usleep_range(1400, 1600); + } + if (i != (int32_t)aw882xx->db_offset) + aw882xx_set_volume(aw882xx, aw882xx->db_offset); + } else { + /*volume down*/ + aw882xx_get_volume(aw882xx, &start_volume); + for (i = start_volume; i <= AW_FADE_OUT_TARGET_VOL; i += aw882xx->fade_step) { + aw882xx_set_volume(aw882xx, i); + usleep_range(1400, 1600); + } + if (i != AW_FADE_OUT_TARGET_VOL) + aw882xx_set_volume(aw882xx, AW_FADE_OUT_TARGET_VOL); + } + return 0; +} + +static void aw882xx_run_mute(struct aw882xx *aw882xx, bool mute) +{ + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + if (mute) { + aw882xx_fade_in_out(aw882xx, false); + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_HMUTE_MASK, + AW882XX_HMUTE_ENABLE_VALUE); + } else { + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_HMUTE_MASK, + AW882XX_HMUTE_DISABLE_VALUE); + aw882xx_fade_in_out(aw882xx, true); + } +} + +static void aw882xx_run_i2s_tx(struct aw882xx *aw882xx, bool flag) +{ + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + if (flag) { + aw882xx_i2c_write_bits(aw882xx, AW882XX_I2SCFG1_REG, + AW882XX_I2STXEN_MASK, + AW882XX_I2STXEN_ENABLE_VALUE); + } else { + aw882xx_i2c_write_bits(aw882xx, AW882XX_I2SCFG1_REG, + AW882XX_I2STXEN_MASK, + AW882XX_I2STXEN_DISABLE_VALUE); + } +} + +static void aw882xx_run_pwd(struct aw882xx *aw882xx, bool pwd) +{ + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + if (pwd) { + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL_REG, + AW882XX_PWDN_MASK, + AW882XX_PWDN_POWER_DOWN_VALUE); + } else { + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL_REG, + AW882XX_PWDN_MASK, + AW882XX_PWDN_NORMAL_WORKING_VALUE); + } +} + +static int aw882xx_sysst_check(struct aw882xx *aw882xx) +{ + int ret = -1; + unsigned char i; + unsigned int reg_val = 0; + + for (i = 0; i < AW882XX_SYSST_CHECK_MAX; i++) { + aw882xx_i2c_read(aw882xx, AW882XX_SYSST_REG, ®_val); + if ((((reg_val & (~AW882XX_SYSST_CHECK_MASK))) & AW882XX_SYSST_CHECK) + == AW882XX_SYSST_CHECK) { + ret = 0; + break; + } else { + aw_dev_dbg(aw882xx->dev, "%s: check fail, cnt=%d, reg_val=0x%04x\n", + __func__, i, reg_val); + msleep(2); + } + } + if (ret < 0) + aw_dev_info(aw882xx->dev, "%s: check fail\n", __func__); + + return ret; +} + +int aw882xx_get_sysint(struct aw882xx *aw882xx, uint16_t *sysint) +{ + int ret = -1; + unsigned int reg_val = 0; + + ret = aw882xx_i2c_read(aw882xx, AW882XX_SYSINT_REG, ®_val); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s: read sysint fail, ret=%d\n", + __func__, ret); + else + *sysint = reg_val; + + return ret; +} + +static int aw882xx_get_icalk(struct aw882xx *aw882xx, int16_t *icalk) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t reg_icalk = 0; + + ret = aw882xx_i2c_read(aw882xx, AW882XX_EFRM1_REG, ®_val); + reg_icalk = (uint16_t)reg_val & AW882XX_EF_ISN_GESLP_MASK; + + if (reg_icalk & AW882XX_EF_ISN_GESLP_SIGN_MASK) + reg_icalk = reg_icalk | AW882XX_EF_ISN_GESLP_NEG; + + *icalk = (int16_t)reg_icalk; + + return ret; +} + +static int aw882xx_get_vcalk(struct aw882xx *aw882xx, int16_t *vcalk) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t reg_vcalk = 0; + + ret = aw882xx_i2c_read(aw882xx, AW882XX_EFRH_REG, ®_val); + + reg_vcalk = (uint16_t)reg_val & AW882XX_EF_VSN_GESLP_MASK; + + if (reg_vcalk & AW882XX_EF_VSN_GESLP_SIGN_MASK) + reg_vcalk = reg_vcalk | AW882XX_EF_VSN_GESLP_NEG; + + *vcalk = (int16_t)reg_vcalk; + + return ret; +} + +static int aw882xx_set_vcalb(struct aw882xx *aw882xx) +{ + int ret = -1; + unsigned int reg_val; + int vcalb; + int icalk; + int vcalk; + int16_t icalk_val = 0; + int16_t vcalk_val = 0; + + ret = aw882xx_get_icalk(aw882xx, &icalk_val); + ret = aw882xx_get_vcalk(aw882xx, &vcalk_val); + + icalk = AW882XX_CABL_BASE_VALUE + AW882XX_ICABLK_FACTOR * icalk_val; + vcalk = AW882XX_CABL_BASE_VALUE + AW882XX_VCABLK_FACTOR * vcalk_val; + + vcalb = AW882XX_VCAL_FACTOR * icalk / vcalk; + + reg_val = (unsigned int)vcalb; + aw_dev_dbg(aw882xx->dev, "%s: icalk=%d, vcalk=%d, vcalb=%d, reg_val=%d\n", + __func__, icalk, vcalk, vcalb, reg_val); + + ret = aw882xx_i2c_write(aw882xx, AW882XX_VTMCTRL3_REG, reg_val); + + return ret; +} + +static int aw882xx_set_intmask(struct aw882xx *aw882xx, bool flag) +{ + int ret = -1; + + if (flag) + ret = aw882xx_i2c_write(aw882xx, AW882XX_SYSINTM_REG, + aw882xx->intmask); + else + ret = aw882xx_i2c_write(aw882xx, AW882XX_SYSINTM_REG, + AW882XX_SYSINTM_DEFAULT); + return ret; +} + +static void aw882xx_set_cali_re_to_dsp(struct aw882xx *aw882xx) +{ + int ret; + + aw_dev_dbg(aw882xx->dev, "%s : cali re = 0x%x\n", + __func__, aw882xx->cali.cali_re); + + if (aw882xx->cali.cali_re != AW_ERRO_CALI_VALUE) { + ret = aw_write_data_to_dsp(INDEX_PARAMS_ID_RX_RE, + &aw882xx->cali.cali_re, + sizeof(int32_t), + aw882xx->chan_info.channel); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s : set cali re to dsp failed\n", + __func__); + } else { + aw_dev_info(aw882xx->dev, "%s : no set cali re to dsp re = %d\n", + __func__, aw882xx->cali.cali_re); + } + +} + +static void aw882xx_clear_sysint(struct aw882xx *aw882xx) +{ + uint16_t sysint = 0; + int ret; + + ret = aw882xx_get_sysint(aw882xx, &sysint); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s: get_sysint fail, ret=%d\n", + __func__, ret); + else + aw_dev_info(aw882xx->dev, "%s: get_sysint=0x%04x\n", + __func__, sysint); + + ret = aw882xx_get_sysint(aw882xx, &sysint); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s: get_sysint fail, ret=%d\n", + __func__, ret); + else + aw_dev_info(aw882xx->dev, "%s: get_sysint=0x%04x\n", + __func__, sysint); +} + +static int aw882xx_start(struct aw882xx *aw882xx) +{ + int ret; + + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_run_i2s_tx(aw882xx, true); + aw882xx_run_pwd(aw882xx, false); + msleep(2); + ret = aw882xx_sysst_check(aw882xx); + if (ret < 0) { + aw882xx_run_mute(aw882xx, true); + aw882xx_run_i2s_tx(aw882xx, false); + aw882xx_run_pwd(aw882xx, true); + } else { + aw882xx_clear_sysint(aw882xx); + aw882xx_set_intmask(aw882xx, true); + aw882xx_run_mute(aw882xx, false); + aw882xx_set_cali_re_to_dsp(aw882xx); + aw882xx_monitor_start(&aw882xx->monitor); + } + + return ret; +} + +static void aw882xx_stop(struct aw882xx *aw882xx) +{ + int ret; + uint16_t sysint = 0; + + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_monitor_stop(&aw882xx->monitor); + aw882xx->is_power_on = AW882XX_PA_CLOSEING_ST; + ret = aw882xx_get_sysint(aw882xx, &sysint); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s: get_sysint fail, ret=%d\n", + __func__, ret); + else + aw_dev_info(aw882xx->dev, "%s: get_sysint=0x%04x\n", + __func__, sysint); + + aw882xx_set_intmask(aw882xx, false); + aw882xx_run_mute(aw882xx, true); + aw882xx_run_i2s_tx(aw882xx, false); + aw882xx_run_pwd(aw882xx, true); + aw882xx->is_power_on = AW882XX_PA_CLOSE_ST; +} + +/****************************************************** + * + * aw882xx config + * + ******************************************************/ +static void aw882xx_set_dither_en(struct aw882xx *aw882xx, uint32_t reg_val) +{ + uint32_t read_val; + + aw882xx_i2c_read(aw882xx, AW882XX_TESTCTRL2_REG, &read_val); + read_val = read_val & AW882XX_DITHER_EN_MASK; + + read_val |= (reg_val & (~AW882XX_DITHER_EN_MASK)); + + aw882xx_i2c_write(aw882xx, AW882XX_TESTCTRL2_REG, read_val); + aw_dev_dbg(aw882xx->dev, "%s: set reg = 0x%04x, val = 0x%04x\n", + __func__, AW882XX_TESTCTRL2_REG, read_val); +} + +static int aw882xx_reg_container_update(struct aw882xx *aw882xx, + struct aw882xx_container *aw882xx_cont) +{ + int i = 0; + int reg_addr = 0; + int reg_val = 0; + int ret = -1; + unsigned int sysctrl_val = 0; + + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + for (i = 0; i < aw882xx_cont->len; i += 4) { + reg_addr = (aw882xx_cont->data[i+1]<<8) + + aw882xx_cont->data[i+0]; + reg_val = (aw882xx_cont->data[i+3]<<8) + + aw882xx_cont->data[i+2]; + aw_dev_dbg(aw882xx->dev, "%s: reg=0x%04x, val = 0x%04x\n", + __func__, reg_addr, reg_val); + if (reg_addr == AW882XX_SYSINTM_REG) { + aw882xx->intmask = reg_val; + reg_val = AW882XX_SYSINTM_DEFAULT; + } + + if (reg_addr == AW882XX_TESTCTRL2_REG) { + aw882xx_set_dither_en(aw882xx, (uint32_t)reg_val); + continue; + } + + ret = aw882xx_i2c_write(aw882xx, + (unsigned char)reg_addr, + (unsigned int)reg_val); + if (ret < 0) + break; + } + + aw882xx_i2c_read(aw882xx, AW882XX_SYSCTRL2_REG, &sysctrl_val); + aw882xx->hagce_val = (sysctrl_val & (~AW882XX_HAGCE_MASK)); + aw882xx->rmse_val = (sysctrl_val & (~AW882XX_RMSE_MASK)); + if (!aw882xx->hagce_enable) { + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_HAGCE_MASK, AW882XX_HAGCE_DISABLE_VALUE); + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_RMSE_MASK, AW882XX_RMSE_DISABLE_VALUE); + } + aw_dev_dbg(aw882xx->dev, "%s: hagce val is 0x%04x, rmse val is 0x%04x", + __func__, aw882xx->hagce_val, aw882xx->rmse_val); + + aw882xx_get_volume(aw882xx, &aw882xx->db_offset); + + aw_dev_dbg(aw882xx->dev, "%s: exit\n", __func__); + + return ret; +} + +static void aw882xx_reg_loaded(const struct firmware *cont, void *context) +{ + int ret; + struct aw882xx *aw882xx = context; + struct aw882xx_container *aw882xx_cfg = NULL; + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + + if (!cont) { + aw_dev_err(aw882xx->dev, "%s: failed to read %s\n", __func__, + chan_info->bin_cfg_name[aw882xx->cfg_num]); + release_firmware(cont); + goto error; + } + + aw_dev_info(aw882xx->dev, "%s: loaded %s - size: %zu\n", __func__, + chan_info->bin_cfg_name[aw882xx->cfg_num], + cont ? cont->size : 0); + + aw882xx_cfg = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!aw882xx_cfg) { + release_firmware(cont); + aw_dev_err(aw882xx->dev, + "%s: error allocating memory\n", __func__); + goto error; + } + aw882xx_cfg->len = cont->size; + memcpy(aw882xx_cfg->data, cont->data, cont->size); + release_firmware(cont); + + mutex_lock(&aw882xx->lock); + if (aw882xx->is_power_on != AW882XX_PA_OPENING_ST) { + kfree(aw882xx_cfg); + aw882xx_cfg = NULL; + mutex_unlock(&aw882xx->lock); + goto error; + } + + ret = aw882xx_reg_container_update(aw882xx, aw882xx_cfg); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: reg update fail\n", __func__); + kfree(aw882xx_cfg); + aw882xx_cfg = NULL; + mutex_unlock(&aw882xx->lock); + goto error; + } else { + aw_dev_info(aw882xx->dev, "%s: reg update sucess\n", __func__); + aw882xx_run_mute(aw882xx, true); + aw882xx_set_vcalb(aw882xx); + } + kfree(aw882xx_cfg); + aw882xx_cfg = NULL; + + ret = aw882xx_start(aw882xx); + if (ret < 0) { + mutex_unlock(&aw882xx->lock); + goto error; + } + aw882xx->init = AW882XX_INIT_OK; + aw882xx->is_power_on = AW882XX_PA_OPEN_ST; + mutex_unlock(&aw882xx->lock); + + return; + + +error: + aw882xx->init = AW882XX_INIT_NG; + aw882xx->is_power_on = AW882XX_PA_CLOSE_ST; +} + +static int aw882xx_load_reg(struct aw882xx *aw882xx) +{ + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw882xx->chan_info.bin_cfg_name[aw882xx->cfg_num], + aw882xx->dev, GFP_KERNEL, + aw882xx, aw882xx_reg_loaded); +} + +static void aw882xx_get_cfg_shift(struct aw882xx *aw882xx) +{ + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + + if (!chan_info->bin_cfg_name) { + chan_info->bin_cfg_name = devm_kzalloc(aw882xx->dev, + sizeof(aw882xx_cfg_name), GFP_KERNEL); + if (!chan_info->bin_cfg_name) { + aw_dev_err(aw882xx->dev, "%s: bin_cfg_name devm_kzalloc failed\n", + __func__); + return; + } + + if (!chan_info->name_suffix) { + snprintf(chan_info->bin_cfg_name[AW882XX_MODE_SPK_SHIFT], + AW882XX_CFG_NAME_MAX, "%s.bin", + aw882xx_cfg_name[AW882XX_MODE_SPK_SHIFT]); + + snprintf(chan_info->bin_cfg_name[AW882XX_MODE_RCV_SHIFT], + AW882XX_CFG_NAME_MAX, "%s.bin", + aw882xx_cfg_name[AW882XX_MODE_RCV_SHIFT]); + + snprintf(chan_info->bin_cfg_name[AW882XX_MODE_VOICE_SHIFT], + AW882XX_CFG_NAME_MAX, "%s.bin", + aw882xx_cfg_name[AW882XX_MODE_VOICE_SHIFT]); + } else { + snprintf(chan_info->bin_cfg_name[AW882XX_MODE_SPK_SHIFT], + AW882XX_CFG_NAME_MAX, "%s_%s.bin", + aw882xx_cfg_name[AW882XX_MODE_SPK_SHIFT], + chan_info->name_suffix); + + snprintf(chan_info->bin_cfg_name[AW882XX_MODE_RCV_SHIFT], + AW882XX_CFG_NAME_MAX, "%s_%s.bin", + aw882xx_cfg_name[AW882XX_MODE_RCV_SHIFT], + chan_info->name_suffix); + + snprintf(chan_info->bin_cfg_name[AW882XX_MODE_VOICE_SHIFT], + AW882XX_CFG_NAME_MAX, "%s_%s.bin", + aw882xx_cfg_name[AW882XX_MODE_VOICE_SHIFT], + chan_info->name_suffix); + } + } + + aw882xx->cfg_num = aw882xx_mode_cfg_shift[aw882xx->scene_mode]; + aw_dev_dbg(aw882xx->dev, "%s: cfg_num=%d\n", + __func__, aw882xx->cfg_num); +} + +static void aw882xx_cold_start(struct aw882xx *aw882xx) +{ + int ret = -1; + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_get_cfg_shift(aw882xx); + + ret = aw882xx_load_reg(aw882xx); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s: cfg loading requested failed: %d\n", + __func__, ret); +} + +void aw882xx_smartpa_cfg(struct aw882xx *aw882xx, bool flag) +{ + int ret; + + aw_dev_info(aw882xx->dev, "%s: flag = %d, power status = %d\n", + __func__, flag, aw882xx->is_power_on); + + mutex_lock(&aw882xx->lock); + if (flag == true && aw882xx->aw882xx_pa_switch == AW882XX_ON_PA) { + if (aw882xx->is_power_on == AW882XX_PA_CLOSE_ST) { + aw882xx->is_power_on = AW882XX_PA_OPENING_ST; + if ((aw882xx->init == AW882XX_INIT_ST) || + (aw882xx->init == AW882XX_INIT_NG)) { + aw_dev_info(aw882xx->dev, "%s: init = %d\n", + __func__, aw882xx->init); + aw882xx_load_cali_re(&aw882xx->cali); + aw882xx_cold_start(aw882xx); + } else { + ret = aw882xx_start(aw882xx); + if (ret < 0) { + aw882xx->is_power_on = AW882XX_PA_CLOSE_ST; + aw882xx->init = AW882XX_INIT_NG; + } else { + aw882xx->is_power_on = AW882XX_PA_OPEN_ST; + aw882xx->init = AW882XX_INIT_OK; + } + } + } + } else { + aw882xx_stop(aw882xx); + } + mutex_unlock(&aw882xx->lock); +} + +/****************************************************** + * + * kcontrol + * + ******************************************************/ +static const char *const mode_function[] = { "Spk", "Rcv", "Voice"}; +static const char *const pa_switch_function[] = { "On", "Off" }; +static const char *const awinic_algo[] = { "Disable", "Enable" }; +static const char *const hagc_status[] = {"Disable", "Reset"}; +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 50, 0); + +struct soc_mixer_control aw882xx_mixer = { + .reg = AW882XX_HAGCCFG4_REG, + .shift = AW882XX_VOL_START_BIT, + .max = AW882XX_VOLUME_MAX, + .min = AW882XX_VOLUME_MIN, +}; + +static int aw882xx_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + /* set kcontrol info */ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mc->max - mc->min; + return 0; +} + +static int aw882xx_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + /*unsigned int value = 0;*/ + struct soc_mixer_control *mc = + (struct soc_mixer_control *) kcontrol->private_value; + + aw882xx_i2c_read(aw882xx, AW882XX_HAGCCFG4_REG, ®_val); + ucontrol->value.integer.value[0] = (reg_val >> mc->shift) & + (AW882XX_VOL_MASK); + return 0; +} + +static int aw882xx_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *) kcontrol->private_value; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + unsigned int value = 0; + unsigned int reg_value = 0; + + /* value is right */ + value = ucontrol->value.integer.value[0]; + if (value > (mc->max-mc->min)) { + aw_dev_err(aw882xx->dev, "%s: value over range\n", __func__); + return -ERANGE; + } + + /* smartpa have clk */ + aw882xx_i2c_read(aw882xx, AW882XX_SYSST_REG, ®_value); + if (!(reg_value & AW882XX_PLLS_LOCKED_VALUE)) { + aw_dev_err(aw882xx->dev, "%s: NO I2S CLK ,cat not write reg\n", + __func__); + return 0; + } + + /* cal real value */ + value = (value << mc->shift) & (~AW882XX_VOL_MASK); + aw882xx_i2c_read(aw882xx, AW882XX_HAGCCFG4_REG, ®_value); + value = value | (reg_value & 0x00ff); + + /* write value */ + aw882xx_i2c_write(aw882xx, AW882XX_HAGCCFG4_REG, value); + + return 0; +} + +static struct snd_kcontrol_new aw882xx_volume = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "aw882xx_rx_volume", + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_READWRITE, + .tlv.p = (digital_gain), + .info = aw882xx_volume_info, + .get = aw882xx_volume_get, + .put = aw882xx_volume_put, + .private_value = (unsigned long)&aw882xx_mixer, +}; + +static int aw882xx_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "%s: aw882xx_scene_control=%d\n", + __func__, aw882xx->scene_mode); + + ucontrol->value.integer.value[0] = aw882xx->scene_mode; + + return 0; +} + +static int aw882xx_mode_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", + __func__, ucontrol->value.integer.value[0]); + + if (ucontrol->value.integer.value[0] == aw882xx->scene_mode) + return 1; + + aw882xx->scene_mode = ucontrol->value.integer.value[0]; + + aw882xx->init = AW882XX_INIT_ST; + + + return 0; +} + +static int aw882xx_rx_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + ret = aw_get_module_enable(&ctrl_value, AW_RX_MODULE); + if (ret) + aw_dev_err(aw882xx->dev, "%s: dsp_msg error, ret=%d\n", + __func__, ret); + + ucontrol->value.integer.value[0] = ctrl_value; + + aw_dev_dbg(aw882xx->dev, "%s: aw882xx_rx_enable %d\n", + __func__, ctrl_value); + return 0; +} + +static int aw882xx_rx_enable_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", + __func__, ucontrol->value.integer.value[0]); + + ctrl_value = ucontrol->value.integer.value[0]; + ret = aw_send_module_enable(&ctrl_value, AW_RX_MODULE); + if (ret) + aw_dev_err(aw882xx->dev, "%s: dsp_msg error, ret=%d\n", + __func__, ret); + + return 0; +} + +static int aw882xx_tx_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + ret = aw_get_module_enable(&ctrl_value, AW_TX_MODULE); + if (ret) + aw_dev_err(aw882xx->dev, "%s: dsp_msg error, ret=%d\n", + __func__, ret); + + ucontrol->value.integer.value[0] = ctrl_value; + + aw_dev_dbg(aw882xx->dev, "%s: aw882xx_tx_enable %d\n", + __func__, ctrl_value); + return 0; +} + +static int aw882xx_tx_enable_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + uint32_t ctrl_value = 0; + + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", + __func__, ucontrol->value.integer.value[0]); + + ctrl_value = ucontrol->value.integer.value[0]; + + ret = aw_send_module_enable(&ctrl_value, AW_TX_MODULE); + if (ret) + aw_dev_err(aw882xx->dev, "%s: dsp_msg error, ret=%d\n", + __func__, ret); + + return 0; +} + +static int aw882xx_pa_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + int *pa_switch_ptr = &aw882xx->aw882xx_pa_switch; + + aw_dev_dbg(aw882xx->dev, "%s: aw882xx_pa_switch=%d\n", + __func__, *pa_switch_ptr); + + ucontrol->value.integer.value[0] = *pa_switch_ptr; + + return 0; +} + +static int aw882xx_pa_switch_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + int *aw882xx_pa_switch = &aw882xx->aw882xx_pa_switch; + + aw_dev_dbg(aw882xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", + __func__, ucontrol->value.integer.value[0]); + + if (ucontrol->value.integer.value[0] == *aw882xx_pa_switch) + return 1; + + *aw882xx_pa_switch = ucontrol->value.integer.value[0]; + + mutex_lock(&aw882xx->lock); + if (aw882xx->audio_stream_st == AW882XX_AUDIO_START) { + if ((*aw882xx_pa_switch == AW882XX_OFF_PA) && + (aw882xx->is_power_on == AW882XX_PA_OPEN_ST)) + aw882xx_stop(aw882xx); + else if ((*aw882xx_pa_switch == AW882XX_ON_PA) && + (aw882xx->is_power_on == AW882XX_PA_CLOSE_ST)) { + aw882xx->is_power_on = AW882XX_PA_OPENING_ST; + ret = aw882xx_start(aw882xx); + if (ret < 0) { + aw882xx->is_power_on = AW882XX_PA_CLOSE_ST; + aw882xx->init = AW882XX_INIT_NG; + } else { + aw882xx->is_power_on = AW882XX_PA_OPEN_ST; + aw882xx->init = AW882XX_INIT_OK; + } + } + } + mutex_unlock(&aw882xx->lock); + + return 0; +} + +static int aw882xx_copp_en_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = -EINVAL; + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", + __func__, ucontrol->value.integer.value[0]); + + mutex_lock(&g_aw_copp_lock); + g_copp_en = ucontrol->value.integer.value[0]; + ret = aw_dsp_copp_module_en(g_copp_en); + if (ret) + aw_dev_err(aw882xx->dev, "%s: dsp_msg error, ret=%d\n", + __func__, ret); + + mutex_unlock(&g_aw_copp_lock); + + return 0; +} + +static int aw882xx_copp_en_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + mutex_lock(&g_aw_copp_lock); + ucontrol->value.integer.value[0] = g_copp_en; + mutex_unlock(&g_aw_copp_lock); + + aw_dev_dbg(aw882xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", + __func__, ucontrol->value.integer.value[0]); + return 0; +} + +static int aw882xx_hagc_en_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw882xx->hagce_enable; + return 0; +} + +static int aw882xx_hagc_en_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + aw_snd_soc_codec_t *codec = + aw_componet_codec_ops.aw_snd_soc_kcontrol_codec(kcontrol); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + if (aw882xx->hagce_enable == ucontrol->value.integer.value[0]) { + aw_dev_info(aw882xx->dev, "%s: hagce enable nochange", __func__); + return 0; + } + + aw882xx->hagce_enable = ucontrol->value.integer.value[0]; + if (aw882xx->hagce_enable) { + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_HAGCE_MASK, aw882xx->hagce_val); + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_RMSE_MASK, aw882xx->rmse_val); + } else { + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_HAGCE_MASK, AW882XX_HAGCE_DISABLE_VALUE); + aw882xx_i2c_write_bits(aw882xx, AW882XX_SYSCTRL2_REG, + AW882XX_RMSE_MASK, AW882XX_RMSE_DISABLE_VALUE); + } + + aw_dev_dbg(aw882xx->dev, "%s: ucontrol->value.integer.value[0]=%ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static const struct soc_enum aw882xx_snd_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mode_function), mode_function), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pa_switch_function), pa_switch_function), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(awinic_algo), awinic_algo), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(hagc_status), hagc_status), +}; + +static struct snd_kcontrol_new aw882xx_controls[] = { + SOC_ENUM_EXT("aw882xx_mode_switch", aw882xx_snd_enum[0], + aw882xx_mode_get, aw882xx_mode_set), + SOC_ENUM_EXT("aw882xx_pa_switch", aw882xx_snd_enum[1], + aw882xx_pa_switch_get, aw882xx_pa_switch_set), + SOC_ENUM_EXT("aw882xx_rx_switch", aw882xx_snd_enum[2], + aw882xx_rx_enable_get, aw882xx_rx_enable_set), + SOC_ENUM_EXT("aw882xx_tx_switch", aw882xx_snd_enum[2], + aw882xx_tx_enable_get, aw882xx_tx_enable_set), + SOC_ENUM_EXT("aw882xx_copp_switch", aw882xx_snd_enum[2], + aw882xx_copp_en_get, aw882xx_copp_en_set), + SOC_ENUM_EXT("aw882xx_hagc_switch", aw882xx_snd_enum[3], + aw882xx_hagc_en_get, aw882xx_hagc_en_set), +}; + +static void aw882xx_kcontrol_append_suffix(struct aw882xx *aw882xx, + struct snd_kcontrol_new *src_control, int num) +{ + int i = 0, ret; + struct snd_kcontrol_new *dst_control = NULL; + + dst_control = devm_kzalloc(aw882xx->dev, + num * sizeof(struct snd_kcontrol_new), GFP_KERNEL); + if (!dst_control) { + aw_dev_err(aw882xx->dev, "kcontrol kzalloc faild\n"); + return; + } + memcpy(dst_control, src_control, num * sizeof(struct snd_kcontrol_new)); + + for (i = 0; i < num; i++) { + ret = aw882xx_append_suffix("%s_%s", + (const char **)&dst_control[i].name, aw882xx); + if (ret < 0) + return; + } + aw_componet_codec_ops.aw_snd_soc_add_codec_controls(aw882xx->codec, + dst_control, num); +} + +void aw882xx_add_codec_controls(struct aw882xx *aw882xx) +{ + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_kcontrol_append_suffix(aw882xx, + aw882xx_controls, ARRAY_SIZE(aw882xx_controls)); + aw882xx_kcontrol_append_suffix(aw882xx, &aw882xx_volume, 1); +} + + +/****************************************************** + * + * Digital Audio Interface + * + ******************************************************/ +static int aw882xx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + aw_dev_info(aw882xx->dev, "%s: playback enter\n", __func__); + else + aw_dev_info(aw882xx->dev, "%s: capture enter\n", __func__); + + return 0; +} + +static int aw882xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + /*struct aw882xx *aw882xx = aw_snd_soc_codec_get_drvdata(dai->codec);*/ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + + aw_dev_info(codec->dev, "%s: fmt=0x%x\n", __func__, fmt); + + /* Supported mode: regular I2S, slave, or PDM */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != + SND_SOC_DAIFMT_CBS_CFS) { + aw_dev_err(codec->dev, "%s: invalid codec master mode\n", + __func__); + return -EINVAL; + } + break; + default: + aw_dev_err(codec->dev, "%s: unsupported DAI format %d\n", + __func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + return 0; +} + +static int aw882xx_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_info(aw882xx->dev, "%s: freq=%d\n", __func__, freq); + + aw882xx->sysclk = freq; + return 0; +} + +static int aw882xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + unsigned int rate = 0; + uint32_t cco_mux_value; + int reg_value = 0; + int width = 0; + + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + aw_dev_dbg(aw882xx->dev, "%s: requested rate: %d, sample size: %d\n", + __func__, rate, + snd_pcm_format_width(params_format(params))); + return 0; + } + /* get rate param */ + aw882xx->rate = rate = params_rate(params); + aw_dev_dbg(aw882xx->dev, "%s: requested rate: %d, sample size: %d\n", + __func__, rate, snd_pcm_format_width(params_format(params))); + + /* match rate */ + switch (rate) { + case 8000: + reg_value = AW882XX_I2SSR_8KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_8_16_32KHZ_VALUE; + break; + case 16000: + reg_value = AW882XX_I2SSR_16KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_8_16_32KHZ_VALUE; + break; + case 32000: + reg_value = AW882XX_I2SSR_32KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_8_16_32KHZ_VALUE; + break; + case 44100: + reg_value = AW882XX_I2SSR_44P1KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_EXC_8_16_32KHZ_VALUE; + break; + case 48000: + reg_value = AW882XX_I2SSR_48KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_EXC_8_16_32KHZ_VALUE; + break; + case 96000: + reg_value = AW882XX_I2SSR_96KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_EXC_8_16_32KHZ_VALUE; + break; + case 192000: + reg_value = AW882XX_I2SSR_192KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_EXC_8_16_32KHZ_VALUE; + break; + default: + reg_value = AW882XX_I2SSR_48KHZ_VALUE; + cco_mux_value = AW882XX_I2S_CCO_MUX_EXC_8_16_32KHZ_VALUE; + aw_dev_err(aw882xx->dev, "%s: rate can not support\n", + __func__); + break; + } + aw882xx_i2c_write_bits(aw882xx, AW882XX_PLLCTRL1_REG, + AW882XX_I2S_CCO_MUX_MASK, cco_mux_value); + + /* set chip rate */ + if (-1 != reg_value) { + aw882xx_i2c_write_bits(aw882xx, AW882XX_I2SCTRL_REG, + AW882XX_I2SSR_MASK, reg_value); + } + + + /* get bit width */ + width = params_width(params); + aw_dev_dbg(aw882xx->dev, "%s: width = %d\n", __func__, width); + switch (width) { + case 16: + reg_value = AW882XX_I2SFS_16_BITS_VALUE; + break; + case 20: + reg_value = AW882XX_I2SFS_20_BITS_VALUE; + break; + case 24: + reg_value = AW882XX_I2SFS_24_BITS_VALUE; + break; + case 32: + reg_value = AW882XX_I2SFS_32_BITS_VALUE; + break; + default: + reg_value = AW882XX_I2SFS_16_BITS_VALUE; + aw_dev_err(aw882xx->dev, + "%s: width can not support\n", __func__); + break; + } + + /* get width */ + if (-1 != reg_value) { + aw882xx_i2c_write_bits(aw882xx, AW882XX_I2SCTRL_REG, + AW882XX_I2SFS_MASK, reg_value); + } + + return 0; +} + +static int aw882xx_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_info(aw882xx->dev, "%s: mute state=%d\n", __func__, mute); + + if (!(aw882xx->flags & AW882XX_FLAG_START_ON_MUTE)) + return 0; + + if (mute) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw882xx_smartpa_cfg(aw882xx, false); + aw882xx->audio_stream_st = AW882XX_AUDIO_STOP; + } + } else { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + aw882xx_smartpa_cfg(aw882xx, true); + aw882xx->audio_stream_st = AW882XX_AUDIO_START; + } + } + + return 0; +} + +static void aw882xx_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + + aw_snd_soc_codec_t *codec = aw_get_codec(dai); + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + aw882xx->rate = 0; + +} + +static const struct snd_soc_dai_ops aw882xx_dai_ops = { + .startup = aw882xx_startup, + .set_fmt = aw882xx_set_fmt, + .set_sysclk = aw882xx_set_dai_sysclk, + .hw_params = aw882xx_hw_params, + .mute_stream = aw882xx_mute, + .shutdown = aw882xx_shutdown, +}; + +static struct snd_soc_dai_driver aw882xx_dai[] = { + { + .name = "aw882xx-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW882XX_RATES, + .formats = AW882XX_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW882XX_RATES, + .formats = AW882XX_FORMATS, + }, + .ops = &aw882xx_dai_ops, + .symmetric_rates = 1, + }, +}; + +/***************************************************** + * + * codec driver + * + *****************************************************/ +static int aw882xx_probe(aw_snd_soc_codec_t *codec) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx->codec = codec; + + aw882xx_add_codec_controls(aw882xx); + + if (codec->dev->of_node) { + if (chan_info->name_suffix) + dev_set_name(codec->dev, "%s_%s", "aw882xx_smartpa", + chan_info->name_suffix); + else + dev_set_name(codec->dev, "%s", "aw882xx_smartpa"); + } + + + schedule_delayed_work(&aw882xx->monitor.load_fw_work, + msecs_to_jiffies(AW_LOAD_MON_FW_DELAY_TIME)); + + aw_dev_info(aw882xx->dev, "%s: exit\n", __func__); + + return 0; +} + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static void aw882xx_remove(struct snd_soc_component *component) +{ + /*struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);*/ + aw_dev_info(component->dev, "%s: enter\n", __func__); +} +#else +static int aw882xx_remove(aw_snd_soc_codec_t *codec) +{ + /*struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec);*/ + aw_dev_info(codec->dev, "%s: enter\n", __func__); + + return 0; +} +#endif + +static unsigned int aw882xx_codec_read(aw_snd_soc_codec_t *codec, + unsigned int reg) +{ + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + unsigned int value = 0; + int ret = -1; + + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + if (aw882xx_reg_access[reg] & REG_RD_ACCESS) { + ret = aw882xx_i2c_read(aw882xx, reg, &value); + if (ret < 0) + aw_dev_dbg(aw882xx->dev, "%s: read register failed\n", + __func__); + } else { + aw_dev_dbg(aw882xx->dev, "%s: register 0x%x no read access\n", + __func__, reg); + } + return ret; +} + +static int aw882xx_codec_write(aw_snd_soc_codec_t *codec, + unsigned int reg, unsigned int value) +{ + int ret = -1; + struct aw882xx *aw882xx = + aw_componet_codec_ops.aw_snd_soc_codec_get_drvdata(codec); + + aw_dev_dbg(aw882xx->dev, "%s: enter ,reg is 0x%x value is 0x%x\n", + __func__, reg, value); + + if (aw882xx_reg_access[reg]®_WR_ACCESS) { + ret = aw882xx_i2c_write(aw882xx, reg, value); + } else { + aw_dev_dbg(aw882xx->dev, "%s: register 0x%x no write access\n", + __func__, reg); + } + + return ret; +} + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +static struct snd_soc_component_driver soc_codec_dev_aw882xx = { + .probe = aw882xx_probe, + .remove = aw882xx_remove, + .read = aw882xx_codec_read, + .write = aw882xx_codec_write, +}; +#else +static struct snd_soc_codec_driver soc_codec_dev_aw882xx = { + .probe = aw882xx_probe, + .remove = aw882xx_remove, + .read = aw882xx_codec_read, + .write = aw882xx_codec_write, + .reg_cache_size = AW882XX_REG_MAX, + .reg_word_size = 2, +}; +#endif + +/****************************************************** + * + * irq + * + ******************************************************/ +static void aw882xx_interrupt_setup(struct aw882xx *aw882xx) +{ + unsigned int reg_val; + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_i2c_read(aw882xx, AW882XX_SYSINTM_REG, ®_val); + reg_val &= (~AW882XX_UVLS_VDD_BELOW_2P8V_VALUE); + reg_val &= (~AW882XX_NOCLKS_TRIG_VALUE); + reg_val &= (~AW882XX_CLKS_TRIG_VALUE); + aw882xx_i2c_write(aw882xx, AW882XX_SYSINTM_REG, reg_val); +} + +static void aw882xx_interrupt_clear(struct aw882xx *aw882xx) +{ + unsigned int reg_val = 0; + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_i2c_read(aw882xx, AW882XX_SYSST_REG, ®_val); + aw_dev_info(aw882xx->dev, "%s: reg SYSST=0x%x\n", __func__, reg_val); + + aw882xx_i2c_read(aw882xx, AW882XX_SYSINT_REG, ®_val); + aw_dev_info(aw882xx->dev, "%s: reg SYSINT=0x%x\n", __func__, reg_val); + + aw882xx_i2c_read(aw882xx, AW882XX_SYSINTM_REG, ®_val); + aw_dev_info(aw882xx->dev, "%s: reg SYSINTM=0x%x\n", __func__, reg_val); +} + +static irqreturn_t aw882xx_irq(int irq, void *data) +{ + struct aw882xx *aw882xx = data; + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_interrupt_clear(aw882xx); + + aw_dev_info(aw882xx->dev, "%s: exit\n", __func__); + + return IRQ_HANDLED; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +static void aw882xx_parse_gpio_dt(struct aw882xx *aw882xx, + struct device_node *np) +{ + aw882xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw882xx->reset_gpio < 0) { + aw_dev_err(aw882xx->dev, + "%s: no reset gpio provided, will not HW reset device\n", + __func__); + } else { + aw_dev_info(aw882xx->dev, "%s: reset gpio provided ok\n", + __func__); + } + aw882xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw882xx->irq_gpio < 0) + aw_dev_err(aw882xx->dev, "%s: no irq gpio provided.\n", + __func__); + else + aw_dev_info(aw882xx->dev, "%s: irq gpio provided ok.\n", + __func__); +} + +static void aw882xx_parse_channel_dt(struct aw882xx *aw882xx, + struct device_node *np) +{ + int ret; + const char *channel_value = NULL; + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + + chan_info->channel = AW882XX_CHANNLE_LEFT_MONO; + chan_info->name_suffix = NULL; + ret = of_property_read_string(np, "sound-channel", &channel_value); + if (ret < 0) { + aw_dev_info(aw882xx->dev, + "%s:read sound-channel failed,use default\n", __func__); + return; + } + aw_dev_dbg(aw882xx->dev, + "%s: read sound-channel value is : %s\n", + __func__, channel_value); + + if (!strcmp(channel_value, "left")) { + chan_info->name_suffix = "l"; + } else if (!strcmp(channel_value, "right")) { + chan_info->channel = AW882XX_CHANNLE_RIGHT; + chan_info->name_suffix = "r"; + } else { + aw_dev_info(aw882xx->dev, "%s:not stereo channel,use default single track\n", + __func__); + } +} + +static void aw882xx_parse_dt(struct device *dev, struct aw882xx *aw882xx, + struct device_node *np) +{ + aw882xx_parse_gpio_dt(aw882xx, np); + aw882xx_parse_channel_dt(aw882xx, np); + aw882xx_parse_cali_mode_dt(&aw882xx->cali); + aw882xx_parse_cali_way_dt(&aw882xx->cali); + aw882xx_parse_monitor_dt(&aw882xx->monitor); +} + +void aw882xx_hw_reset(struct aw882xx *aw882xx) +{ + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + if (IS_ERR(aw882xx->aw_pinctrl)) { + if (gpio_is_valid(aw882xx->reset_gpio)) { + gpio_set_value_cansleep(aw882xx->reset_gpio, 0); + msleep(1); + gpio_set_value_cansleep(aw882xx->reset_gpio, 1); + msleep(2); + } else { + aw_dev_err(aw882xx->dev, "%s: failed\n", __func__); + } + }else + { + /* code */ + aw_select_pin_ctl(aw882xx, "aw_reset_low"); + msleep(1); + aw_select_pin_ctl(aw882xx, "aw_reset_high"); + msleep(2); + } +} + +/***************************************************** + * + * check chip id + * + *****************************************************/ +static int aw882xx_read_chipid(struct aw882xx *aw882xx) +{ + int ret = -1; + unsigned int cnt = 0; + unsigned int reg = 0; + + while (cnt < AW_READ_CHIPID_RETRIES) { + ret = aw882xx_i2c_read(aw882xx, AW882XX_ID_REG, ®); + if (ret < 0) { + aw_dev_err(aw882xx->dev, + "%s: failed to read REG_ID: %d\n", + __func__, ret); + return -EIO; + } + switch (reg) { + case AW882XX_ID: + aw_dev_info(aw882xx->dev, "%s: aw882xx detected\n", + __func__); + aw882xx->flags |= AW882XX_FLAG_SKIP_INTERRUPTS; + aw882xx->flags |= AW882XX_FLAG_START_ON_MUTE; + aw882xx->chipid = AW882XX_ID; + aw_dev_info(aw882xx->dev, "%s: aw882xx->flags=0x%x\n", + __func__, aw882xx->flags); + return 0; + default: + aw_dev_info(aw882xx->dev, "%s: unsupported device revision (0x%x)\n", + __func__, reg); + break; + } + cnt++; + + msleep(AW_READ_CHIPID_RETRY_DELAY); + } + + return -EINVAL; +} + +/****************************************************** + * + * sys group attribute: reg + * + ******************************************************/ +static ssize_t aw882xx_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int databuf[2] = {0}; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) + aw882xx_i2c_write(aw882xx, databuf[0], databuf[1]); + + return count; +} + +static ssize_t aw882xx_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned char i = 0; + unsigned int reg_val = 0; + + for (i = 0; i < AW882XX_REG_MAX; i++) { + if (aw882xx_reg_access[i]®_RD_ACCESS) { + aw882xx_i2c_read(aw882xx, i, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, + "reg:0x%02x=0x%04x\n", i, reg_val); + } + } + + return len; +} + +static ssize_t aw882xx_rw_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + unsigned int databuf[2] = {0}; + + if (2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw882xx->reg_addr = (unsigned char)databuf[0]; + aw882xx_i2c_write(aw882xx, databuf[0], databuf[1]); + } else if (1 == sscanf(buf, "%x", &databuf[0])) { + aw882xx->reg_addr = (unsigned char)databuf[0]; + } + + return count; +} + +static ssize_t aw882xx_rw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int reg_val = 0; + + if (aw882xx_reg_access[aw882xx->reg_addr] & REG_RD_ACCESS) { + aw882xx_i2c_read(aw882xx, aw882xx->reg_addr, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, + "reg:0x%02x=0x%04x\n", aw882xx->reg_addr, reg_val); + } + return len; +} + +static ssize_t aw882xx_driver_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "driver version:%s\n", AW882XX_DRIVER_VERSION); + + return len; +} + +static ssize_t aw882xx_fade_step_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0}; + + /*step 0 - 12*/ + if (1 == sscanf(buf, "%d", &databuf[0])) { + if (databuf[0] > (AW882XX_VOLUME_STEP_DB * 2)) { + aw_dev_info(aw882xx->dev, "%s: step overflow %d Db", + __func__, databuf[0]); + return count; + } + aw882xx->fade_step = databuf[0]; + } + aw_dev_info(aw882xx->dev, "%s: set step %d.%d DB Done", + __func__, GET_DB_INT(databuf[0]), GET_DB_DECIMAL(databuf[0])); + + return count; +} + +static ssize_t aw882xx_fade_step_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, + "step: %d\n", aw882xx->fade_step); + + return len; +} + + +static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, + aw882xx_reg_show, aw882xx_reg_store); +static DEVICE_ATTR(rw, S_IWUSR | S_IRUGO, + aw882xx_rw_show, aw882xx_rw_store); +static DEVICE_ATTR(driver_ver, S_IRUGO, + aw882xx_driver_ver_show, NULL); +static DEVICE_ATTR(fade_step, S_IWUSR | S_IRUGO, + aw882xx_fade_step_show, aw882xx_fade_step_store); + + +static struct attribute *aw882xx_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_rw.attr, + &dev_attr_driver_ver.attr, + &dev_attr_fade_step.attr, + NULL +}; + +static struct attribute_group aw882xx_attribute_group = { + .attrs = aw882xx_attributes, +}; + +static int aw_select_pin_ctl(struct aw882xx *aw882xx, const char *name) +{ + size_t i; + int rc; + + for (i = 0; i < ARRAY_SIZE(pctl_names); i++) { + const char *n = pctl_names[i]; + + if (!memcmp(n, name, strlen(n))) { + rc = pinctrl_select_state(aw882xx->aw_pinctrl, + aw882xx->pinctrl_state[i]); + if (rc) + aw_dev_err(aw882xx->dev, "cannot select '%s'\n", name); + else + aw_dev_dbg(aw882xx->dev, "Selected '%s'\n", name); + + return rc; + } + } + + aw_dev_err(aw882xx->dev, "%s:'%s' not found\n", __func__, name); + return -EINVAL; +} + +/****************************************************** + * + * i2c driver + * + ******************************************************/ +static int aw882xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_dai_driver *dai = NULL; + struct aw882xx *aw882xx = NULL; + struct device_node *np = i2c->dev.of_node; + struct aw882xx_chan_info *chan_info = NULL; + const char *aw882xx_rst = "aw882xx_rst"; + const char *aw882xx_int = "aw882xx_int"; + const char *aw882xx_irq_name = "aw882xx"; + int irq_flags = 0; + int ret; + int i; + + aw_dev_info(&i2c->dev, "%s: enter\n", __func__); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + aw_dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + aw882xx = devm_kzalloc(&i2c->dev, sizeof(struct aw882xx), GFP_KERNEL); + if (aw882xx == NULL) + return -ENOMEM; + + aw882xx->dev = &i2c->dev; + aw882xx->i2c = i2c; + chan_info = &aw882xx->chan_info; + i2c_set_clientdata(i2c, aw882xx); + mutex_init(&aw882xx->lock); + + /* aw882xx rst & int */ + if (np) { + aw882xx_parse_dt(&i2c->dev, aw882xx, np); + } else { + aw882xx->reset_gpio = -1; + aw882xx->irq_gpio = -1; + } + + aw882xx->aw_pinctrl = devm_pinctrl_get(aw882xx->dev); + if (IS_ERR(aw882xx->aw_pinctrl)) { + ret = PTR_ERR(aw882xx->aw_pinctrl); + aw_dev_err(aw882xx->dev, "Cannot get pinctrl\n", ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(pctl_names); i++) { + const char *n = pctl_names[i]; + struct pinctrl_state *state = + pinctrl_lookup_state(aw882xx->aw_pinctrl, n); + if (IS_ERR(state)) { + aw_dev_err(aw882xx->dev, "cannot find '%s'\n", n); + return PTR_ERR(state); + } + aw_dev_err(aw882xx->dev, "found pin control %s\n", n); + aw882xx->pinctrl_state[i] = state; + } + + aw_select_pin_ctl(aw882xx, "aw_reset_low"); + aw_select_pin_ctl(aw882xx, "aw_irq_active"); + + + if (gpio_is_valid(aw882xx->reset_gpio)) { + ret = aw882xx_append_suffix("%s_%s", &aw882xx_rst, aw882xx); + if (ret < 0) + return ret; + + ret = devm_gpio_request_one(&i2c->dev, aw882xx->reset_gpio, + GPIOF_OUT_INIT_LOW, aw882xx_rst); + if (ret) { + aw_dev_err(&i2c->dev, "%s: rst request failed\n", + __func__); + return ret; + } + } + + if (gpio_is_valid(aw882xx->irq_gpio)) { + ret = aw882xx_append_suffix("%s_%s", &aw882xx_int, aw882xx); + if (ret < 0) + return ret; + + ret = devm_gpio_request_one(&i2c->dev, aw882xx->irq_gpio, + GPIOF_DIR_IN, aw882xx_int); + if (ret) { + aw_dev_err(&i2c->dev, "%s: int request failed\n", + __func__); + return ret; + } + } + + /* hardware reset */ + aw882xx_hw_reset(aw882xx); + + /* aw882xx chip id */ + ret = aw882xx_read_chipid(aw882xx); + if (ret < 0) { + aw_dev_err(&i2c->dev, "%s: aw882xx_read_chipid failed ret=%d\n", + __func__, ret); + return ret; + } + + /* aw882xx device name */ + if (np) { + if (chan_info->name_suffix) + dev_set_name(&i2c->dev, "%s_%s", "aw882xx_smartpa", + chan_info->name_suffix); + else + dev_set_name(&i2c->dev, "%s", "aw882xx_smartpa"); + } else { + aw_dev_err(&i2c->dev, "%s failed to set device name: %d\n", + __func__, ret); + } + + /* register codec */ + dai = devm_kzalloc(&i2c->dev, sizeof(aw882xx_dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + memcpy(dai, aw882xx_dai, sizeof(aw882xx_dai)); + + /*Change the DAI name according to the channel*/ + ret = aw882xx_append_suffix("%s-%s", &dai->name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_suffix("%s_%s", + &dai->playback.stream_name, aw882xx); + if (ret < 0) + return ret; + ret = aw882xx_append_suffix("%s_%s", + &dai->capture.stream_name, aw882xx); + if (ret < 0) + return ret; + + aw_dev_info(aw882xx->dev, "%s: dai->name(%s)\n", __func__, dai->name); + ret = aw_componet_codec_ops.aw_snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_aw882xx, + dai, ARRAY_SIZE(aw882xx_dai)); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s failed to register aw882xx: %d\n", + __func__, ret); + return ret; + } + + /* aw882xx irq */ + if (gpio_is_valid(aw882xx->irq_gpio) && + !(aw882xx->flags & AW882XX_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + aw882xx_interrupt_setup(aw882xx); + + aw882xx_append_suffix("%s_%s", &aw882xx_irq_name, aw882xx); + + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(aw882xx->irq_gpio), + NULL, aw882xx_irq, irq_flags, + aw882xx_irq_name, aw882xx); + if (ret != 0) { + aw_dev_err(aw882xx->dev, "failed to request IRQ %d: %d\n", + gpio_to_irq(aw882xx->irq_gpio), ret); + goto err_irq; + } + } else { + aw_dev_info(aw882xx->dev, "%s skipping IRQ registration\n", + __func__); + /* disable feature support if gpio was invalid */ + aw882xx->flags |= AW882XX_FLAG_SKIP_INTERRUPTS; + } + + dev_set_drvdata(&i2c->dev, aw882xx); + ret = sysfs_create_group(&i2c->dev.kobj, &aw882xx_attribute_group); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s error creating sysfs attr files\n", + __func__); + goto err_sysfs; + } + + aw_cali_init(&aw882xx->cali); + + aw882xx_monitor_init(&aw882xx->monitor); + + aw882xx->fade_step = AW882XX_VOLUME_STEP_DB; + aw882xx->aw882xx_pa_switch = AW882XX_ON_PA; /*can open*/ + aw882xx->is_power_on = AW882XX_PA_CLOSE_ST; + aw_dev_dbg(aw882xx->dev, "%s: probe completed successfully!\n", + __func__); + if(!aw882xx_i2c_check) + { + i2c_check_status_create("audio_smpart_pa",1); + aw882xx_i2c_check = true; + } + return 0; + + +err_sysfs: +err_irq: + aw_componet_codec_ops.aw_snd_soc_unregister_codec(&i2c->dev); + + return ret; +} + +static int aw882xx_i2c_remove(struct i2c_client *i2c) +{ + struct aw882xx *aw882xx = i2c_get_clientdata(i2c); + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + + aw_cali_deinit(&aw882xx->cali); + aw882xx_monitor_deinit(&aw882xx->monitor); + + aw_componet_codec_ops.aw_snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static const struct i2c_device_id aw882xx_i2c_id[] = { + { AW882XX_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw882xx_i2c_id); + +static struct of_device_id aw882xx_dt_match[] = { + { .compatible = "awinic,aw882xx_smartpa" }, + { .compatible = "awinic,aw882xx_smartpa_l" }, + { .compatible = "awinic,aw882xx_smartpa_r" }, + { }, +}; + +static struct i2c_driver aw882xx_i2c_driver = { + .driver = { + .name = AW882XX_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw882xx_dt_match), + }, + .probe = aw882xx_i2c_probe, + .remove = aw882xx_i2c_remove, + .id_table = aw882xx_i2c_id, +}; + +static int __init aw882xx_i2c_init(void) +{ + int ret = -1; + + pr_info("%s: aw882xx driver version %s\n", + __func__, AW882XX_DRIVER_VERSION); + + ret = i2c_add_driver(&aw882xx_i2c_driver); + if (ret) + pr_err("%s: fail to add aw882xx device into i2c\n", __func__); + + return ret; +} +module_init(aw882xx_i2c_init); + + +static void __exit aw882xx_i2c_exit(void) +{ + i2c_del_driver(&aw882xx_i2c_driver); +} +module_exit(aw882xx_i2c_exit); + + +MODULE_DESCRIPTION("ASoC AW882XX Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw882xx/aw882xx.h b/sound/soc/codecs/aw882xx/aw882xx.h new file mode 100644 index 0000000000000000000000000000000000000000..92cac5997ab3b3c5915180756076357af67a4cd7 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx.h @@ -0,0 +1,194 @@ +#ifndef _AW882XX_H_ +#define _AW882XX_H_ + +#include +#include +#include +#include "awinic_cali.h" +#include "awinic_monitor.h" + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 1) +#define AW_KERNEL_VER_OVER_4_19_1 +#endif + +/* + * i2c transaction on Linux limited to 64k + * (See Linux kernel documentation: Documentation/i2c/writing-clients) +*/ +#define MAX_I2C_BUFFER_SIZE (65536) +#define AW882XX_I2C_READ_MSG_NUM (2) + + +#define AW882XX_FLAG_START_ON_MUTE (1 << 0) +#define AW882XX_FLAG_SKIP_INTERRUPTS (1 << 1) +#define AW882XX_FLAG_SAAM_AVAILABLE (1 << 2) +#define AW882XX_FLAG_STEREO_DEVICE (1 << 3) +#define AW882XX_FLAG_MULTI_MIC_INPUTS (1 << 4) + +#define AW882XX_NUM_RATES (9) +#define AW882XX_SYSST_CHECK_MAX (10) +#define AW882XX_MODE_SHIFT_MAX (3) + +#define AW882XX_CFG_NAME_MAX (64) +#define AW_FADE_OUT_TARGET_VOL (90 * 2) +#define AW882XX_VOLUME_STEP_DB (6 * 2) + + +enum aw882xx_pa_switch_st { + AW882XX_ON_PA = 0, + AW882XX_OFF_PA, +}; + +enum aw882xx_chip_st { + AW882XX_PA_CLOSE_ST = 0, + AW882XX_PA_CLOSEING_ST, + AW882XX_PA_OPEN_ST, + AW882XX_PA_OPENING_ST, +}; + +enum aw882xx_audio_stream_st { + AW882XX_AUDIO_STOP = 0, + AW882XX_AUDIO_START = 1, +}; + +enum aw882xx_channel_mode_dsp { + AW882XX_CHANNLE_LEFT_MONO = 0, + AW882XX_CHANNLE_RIGHT = 1, +}; + +enum aw882xx_init { + AW882XX_INIT_ST = 0, + AW882XX_INIT_OK = 1, + AW882XX_INIT_NG = 2, +}; + +enum aw882xx_chipid { + AW882XX_ID = 0x1852, +}; + +enum aw882xx_modeshift { + AW882XX_MODE_SPK_SHIFT = 0, + AW882XX_MODE_RCV_SHIFT = 1, + AW882XX_MODE_VOICE_SHIFT = 2, +}; + +enum aw882xx_mode_spk_rcv { + AW882XX_SPEAKER_MODE = 0, + AW882XX_RECEIVER_MODE = 1, + AW882XX_VOICE_MODE = 2, +}; + +struct aw882xx_container { + int len; + unsigned char data[]; +}; + +struct aw882xx_chan_info { + unsigned int channel; + char *name_suffix; + char (*bin_cfg_name)[AW882XX_CFG_NAME_MAX]; +}; + +#ifdef AW_KERNEL_VER_OVER_4_19_1 +typedef struct snd_soc_component aw_snd_soc_codec_t; +typedef struct snd_soc_component_driver aw_snd_soc_codec_driver_t; +#else +typedef struct snd_soc_codec aw_snd_soc_codec_t; +typedef struct snd_soc_codec_driver aw_snd_soc_codec_driver_t; +#endif + +struct aw_componet_codec_ops { + aw_snd_soc_codec_t *(*aw_snd_soc_kcontrol_codec)(struct snd_kcontrol *kcontrol); + void *(*aw_snd_soc_codec_get_drvdata)(aw_snd_soc_codec_t *codec); + int (*aw_snd_soc_add_codec_controls)(aw_snd_soc_codec_t *codec, + const struct snd_kcontrol_new *controls, + unsigned int num_controls); + void (*aw_snd_soc_unregister_codec)(struct device *dev); + int (*aw_snd_soc_register_codec)(struct device *dev, + const aw_snd_soc_codec_driver_t *codec_drv, + struct snd_soc_dai_driver *dai_drv, + int num_dai); +}; + +/*Pin ctr */ +static const char * const pctl_names[] = { + "aw_reset_low", + "aw_reset_high", + "aw_irq_active", +}; + +/******************************************** + * struct aw882xx + *******************************************/ +struct aw882xx { + int sysclk; + int rate; + int pstream; + int cstream; + int hagce_enable; + unsigned int hagce_val; + unsigned int rmse_val; + + int reset_gpio; + int irq_gpio; + int aw882xx_pa_switch; + int is_power_on; + int audio_stream_st; + uint16_t intmask; + uint32_t fade_step; + uint32_t fade_utime; + uint32_t db_offset; + + unsigned char reg_addr; + + unsigned int flags; + unsigned int chipid; + unsigned int init; + unsigned int cfg_num; + unsigned int scene_mode; + + aw_snd_soc_codec_t *codec; + struct regmap *regmap; + struct i2c_client *i2c; + struct device *dev; + struct mutex lock; + + struct aw882xx_chan_info chan_info; + struct aw_cali cali; + struct aw882xx_monitor monitor; + struct pinctrl *aw_pinctrl; + struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)]; +}; + +/******************************************** + * print information control + *******************************************/ +#define aw_dev_err(dev, format, ...) \ + pr_err("[%s]" format, dev_name(dev), ##__VA_ARGS__) + +#define aw_dev_info(dev, format, ...) \ + pr_info("[%s]" format, dev_name(dev), ##__VA_ARGS__) + +#define aw_dev_dbg(dev, format, ...) \ + pr_debug("[%s]" format, dev_name(dev), ##__VA_ARGS__) + + +/********************************************* +* aw882xx functions +**********************************************/ +int aw882xx_i2c_write(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int reg_data); +int aw882xx_i2c_read(struct aw882xx *aw882xx, + unsigned char reg_addr, unsigned int *reg_data); +void aw882xx_append_channel(char *format, const char **change_name, + struct aw882xx *aw882xx); +void aw882xx_smartpa_cfg(struct aw882xx *aw882xx, bool flag); +int aw882xx_set_volume(struct aw882xx *aw882xx, uint32_t value); +int aw882xx_get_volume(struct aw882xx *aw882xx, uint32_t *value); +uint32_t aw882xx_reg_val_to_db(uint32_t value); + + +int aw882xx_append_suffix(char *format, const char **change_name, + struct aw882xx *aw882xx); +#endif diff --git a/sound/soc/codecs/aw882xx/aw882xx_reg.h b/sound/soc/codecs/aw882xx/aw882xx_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..ae1c111a92cca5a56e795bdd3a655a044ac5f823 --- /dev/null +++ b/sound/soc/codecs/aw882xx/aw882xx_reg.h @@ -0,0 +1,1578 @@ +#ifndef __AW882XX_REG_H__ +#define __AW882XX_REG_H__ + +/* registers list */ +#define AW882XX_ID_REG (0x00) +#define AW882XX_SYSST_REG (0x01) +#define AW882XX_SYSINT_REG (0x02) +#define AW882XX_SYSINTM_REG (0x03) +#define AW882XX_SYSCTRL_REG (0x04) +#define AW882XX_SYSCTRL2_REG (0x05) +#define AW882XX_I2SCTRL_REG (0x06) +#define AW882XX_I2SCFG1_REG (0x07) +#define AW882XX_I2SCFG2_REG (0x08) +#define AW882XX_HAGCCFG1_REG (0x09) +#define AW882XX_HAGCCFG2_REG (0x0A) +#define AW882XX_HAGCCFG3_REG (0x0B) +#define AW882XX_HAGCCFG4_REG (0x0C) +#define AW882XX_HAGCCFG5_REG (0x0D) +#define AW882XX_HAGCCFG6_REG (0x0E) +#define AW882XX_HAGCCFG7_REG (0x0F) +#define AW882XX_HAGCST_REG (0x10) +#define AW882XX_PRODID_REG (0x11) +#define AW882XX_VBAT_REG (0x12) +#define AW882XX_TEMP_REG (0x13) +#define AW882XX_PVDD_REG (0x14) +#define AW882XX_DBGCTRL_REG (0x20) +#define AW882XX_I2SINT_REG (0x21) +#define AW882XX_I2SCAPCNT_REG (0x22) +#define AW882XX_CRCIN_REG (0x38) +#define AW882XX_CRCOUT_REG (0x39) +#define AW882XX_VSNCTRL1_REG (0x50) +#define AW882XX_ISNCTRL1_REG (0x52) +#define AW882XX_ISNCTRL2_REG (0x53) +#define AW882XX_VTMCTRL1_REG (0x54) +#define AW882XX_VTMCTRL2_REG (0x55) +#define AW882XX_VTMCTRL3_REG (0x56) +#define AW882XX_ISNDAT_REG (0x57) +#define AW882XX_VSNDAT_REG (0x58) +#define AW882XX_PWMCTRL_REG (0x59) +#define AW882XX_PWMCTRL2_REG (0x5A) +#define AW882XX_BSTCTRL1_REG (0x60) +#define AW882XX_BSTCTRL2_REG (0x61) +#define AW882XX_BSTCTRL3_REG (0x62) +#define AW882XX_BSTDBG1_REG (0x63) +#define AW882XX_BSTDBG2_REG (0x64) +#define AW882XX_BSTDBG3_REG (0x65) +#define AW882XX_PLLCTRL1_REG (0x66) +#define AW882XX_PLLCTRL2_REG (0x67) +#define AW882XX_PLLCTRL3_REG (0x68) +#define AW882XX_CDACTRL1_REG (0x69) +#define AW882XX_CDACTRL2_REG (0x6A) +#define AW882XX_SADCCTRL_REG (0x6B) +#define AW882XX_TESTCTRL1_REG (0x70) +#define AW882XX_TESTCTRL2_REG (0x71) +#define AW882XX_EFCTRL1_REG (0x72) +#define AW882XX_EFCTRL2_REG (0x73) +#define AW882XX_EFWH_REG (0x74) +#define AW882XX_EFWM2_REG (0x75) +#define AW882XX_EFWM1_REG (0x76) +#define AW882XX_EFWL_REG (0x77) +#define AW882XX_EFRH_REG (0x78) +#define AW882XX_EFRM2_REG (0x79) +#define AW882XX_EFRM1_REG (0x7A) +#define AW882XX_EFRL_REG (0x7B) +#define AW882XX_TESTDET_REG (0x7C) + +/******************************************** + * Register Access + *******************************************/ +#define AW882XX_REG_MAX (0x7D) + +#define REG_NONE_ACCESS (0) +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) + +static const unsigned char aw882xx_reg_access[AW882XX_REG_MAX] = { + [AW882XX_ID_REG] = (REG_RD_ACCESS), + [AW882XX_SYSST_REG] = (REG_RD_ACCESS), + [AW882XX_SYSINT_REG] = (REG_RD_ACCESS), + [AW882XX_SYSINTM_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_SYSCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_SYSCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_I2SCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_I2SCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_I2SCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCCFG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCCFG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCCFG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCCFG4_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCCFG5_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCCFG6_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCCFG7_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_HAGCST_REG] = (REG_RD_ACCESS), + [AW882XX_PRODID_REG] = (REG_RD_ACCESS), + [AW882XX_VBAT_REG] = (REG_RD_ACCESS), + [AW882XX_TEMP_REG] = (REG_RD_ACCESS), + [AW882XX_PVDD_REG] = (REG_RD_ACCESS), + [AW882XX_DBGCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_I2SINT_REG] = (REG_RD_ACCESS), + [AW882XX_I2SCAPCNT_REG] = (REG_RD_ACCESS), + [AW882XX_CRCIN_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_CRCOUT_REG] = (REG_RD_ACCESS), + [AW882XX_VSNCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_ISNCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_ISNCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_VTMCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_VTMCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_VTMCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_ISNDAT_REG] = (REG_RD_ACCESS), + [AW882XX_VSNDAT_REG] = (REG_RD_ACCESS), + [AW882XX_PWMCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_PWMCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_BSTCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_BSTCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_BSTCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_BSTDBG1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_BSTDBG2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_BSTDBG3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_PLLCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_PLLCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_PLLCTRL3_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_CDACTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_CDACTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_SADCCTRL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_TESTCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_TESTCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_EFCTRL1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_EFCTRL2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_EFWH_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_EFWM2_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_EFWM1_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_EFWL_REG] = (REG_RD_ACCESS | REG_WR_ACCESS), + [AW882XX_EFRH_REG] = (REG_RD_ACCESS), + [AW882XX_EFRM2_REG] = (REG_RD_ACCESS), + [AW882XX_EFRM1_REG] = (REG_RD_ACCESS), + [AW882XX_EFRL_REG] = (REG_RD_ACCESS), + [AW882XX_TESTDET_REG] = (REG_RD_ACCESS), +}; + +/******************************************** + * Register Detail + *******************************************/ +/* detail information of registers begin */ +/* ID (0x00) detail */ +/* IDCODE bit 15:0 (ID 0x00) */ +#define AW882XX_IDCODE_START_BIT (0) +#define AW882XX_IDCODE_BITS_LEN (16) +#define AW882XX_IDCODE_MASK \ + (~(((1< + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx.h" +#include "awinic_cali.h" +#include "awinic_monitor.h" +#include "awinic_dsp.h" + + +uint8_t g_cali_status; +static DEFINE_MUTEX(g_aw_dsp_msg_lock); + +#ifdef AW_CALI_STORE_EXAMPLE +/*write cali to persist file example*/ +#define AWINIC_CALI_FILE "/mnt/vendor/persist/factory/audio/aw_cali.bin" +#define AW_INT_DEC_DIGIT 10 +static int aw882xx_write_cali_re_to_file(int32_t cali_re, int channel) +{ + struct file *fp = NULL; + char buf[50] = {0}; + loff_t pos = 0; + mm_segment_t fs; + + fp = filp_open(AWINIC_CALI_FILE, O_RDWR | O_CREAT, 0664); + if (IS_ERR(fp)) { + pr_err("%s:channel:%d open %s failed!\n", + __func__, channel, AWINIC_CALI_FILE); + return -EINVAL; + } + if (channel == AW882XX_CHANNLE_RIGHT) + pos = AW_INT_DEC_DIGIT; + + cali_re = FIXED_RE_TO_MOHM(cali_re); + snprintf(buf, sizeof(buf), "%10d", cali_re); + + fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_write(fp, buf, strlen(buf), &pos); + + set_fs(fs); + + pr_info("%s: channel:%d buf:%s cali_re:%d\n", + __func__, channel, buf, cali_re); + + filp_close(fp, NULL); + return 0; +} + +static int aw882xx_get_cali_re_from_file(int32_t *cali_re, int channel) +{ + struct file *fp = NULL; + /*struct inode *node;*/ + int f_size; + char *buf = NULL; + int32_t int_cali_re = 0; + loff_t pos = 0; + mm_segment_t fs; + + fp = filp_open(AWINIC_CALI_FILE, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("%s:channel:%d open %s failed!\n", + __func__, channel, AWINIC_CALI_FILE); + return -EINVAL; + } + + if (channel == AW882XX_CHANNLE_RIGHT) + pos = AW_INT_DEC_DIGIT; + + /*node = fp->f_dentry->d_inode;*/ + /*f_size = node->i_size;*/ + f_size = AW_INT_DEC_DIGIT; + + buf = kzalloc(f_size + 1, GFP_ATOMIC); + if (!buf) { + pr_err("%s: channel:%d malloc mem %d failed!\n", + __func__, channel, f_size); + filp_close(fp, NULL); + return -EINVAL; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + + vfs_read(fp, buf, f_size, &pos); + + set_fs(fs); + + if (sscanf(buf, "%d", &int_cali_re) == 1) + *cali_re = MOHM_TO_FIXED_RE(int_cali_re); + else + *cali_re = AW_ERRO_CALI_VALUE; + + pr_info("%s: channel:%d buf:%s int_cali_re: %d\n", + __func__, channel, buf, int_cali_re); + + kfree(buf); + buf = NULL; + filp_close(fp, NULL); + + return 0; + +} +#endif + + /*custom need add to set/get cali_re form/to nv*/ +int aw882xx_set_cali_re_to_nvram(int32_t cali_re, int32_t channel) +{ + /*custom add, if success return value is 0, else -1*/ +#ifdef AW_CALI_STORE_EXAMPLE + return aw882xx_write_cali_re_to_file(cali_re, channel); +#else + return -EBUSY; +#endif +} +int aw882xx_get_cali_re_from_nvram(int32_t *cali_re, int32_t channel) +{ + /*custom add, if success return value is 0 , else -1*/ +#ifdef AW_CALI_STORE_EXAMPLE + return aw882xx_get_cali_re_from_file(cali_re, channel); +#else + return -EBUSY; +#endif +} + +static int aw882xx_store_cali_re(struct aw882xx *aw882xx, int32_t cali_re) +{ + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + + if (aw882xx == NULL) + return -EINVAL; + aw882xx->cali.cali_re = cali_re; + return aw882xx_set_cali_re_to_nvram(cali_re, chan_info->channel); +} + +void aw882xx_load_cali_re(struct aw_cali *cali) +{ + int32_t cali_re = 0; + int ret = 0; + struct aw882xx *aw882xx = + container_of(cali, struct aw882xx, cali); + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + + ret = aw882xx_get_cali_re_from_nvram(&cali_re, chan_info->channel); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: get cali re from nv failed: %d\n", + __func__, ret); + cali_re = AW_ERRO_CALI_VALUE; + } + aw882xx->cali.cali_re = cali_re; +} + + +static int aw_run_dsp_hmute(struct aw882xx *aw882xx, uint32_t hmute_st) +{ +#ifdef AWINIC_DSP_HMUTE + aw_dev_dbg(aw882xx->dev, "%s: hmute_st:%d\n", + __func__, hmute_st); + + return aw_write_msg_to_dsp(INLINE_PARAM_ID_ENABLE_HMUTE, + (void *)&hmute_st, sizeof(hmute_st), + aw882xx->chan_info.channel); +#endif + return 0; +} + +static int aw_run_cali_cfg_to_dsp(struct aw882xx *aw882xx, int cali_flag) +{ + int ret; + struct aw_cali *cali = &aw882xx->cali; + +#ifdef AWINIC_DSP_MSG + aw_dev_dbg(aw882xx->dev, "%s: cali_flag:%d\n", + __func__, cali_flag); + + ret = aw_write_msg_to_dsp(INLINE_PARAM_ID_ENABLE_CALI, + (void *)&cali_flag, sizeof(cali_flag), + aw882xx->chan_info.channel); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:start cali failed!\n", + __func__); + return ret; + } + + if (cali_flag) + msleep(cali->cali_re_time); + + return 0; +#else + struct cali_cfg set_cfg = { {0, 0, -1} }; + int i; + + aw_dev_dbg(aw882xx->dev, "%s: cali_flag:%d\n", + __func__, cali_flag); + + if (cali_flag) { + for (i = cali->first_cali_num; i <= cali->end_cali_num; i++) { + ret = aw_read_data_from_dsp(INDEX_PARAMS_ID_RX_CALI_CFG, + (void *)&aw882xx->cali.store_cfg[i], + sizeof(struct cali_cfg), i); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:dev[%d] read cali cfg data failed!\n", + __func__, i); + goto back_cfg; + } + + ret = aw_write_data_to_dsp(INDEX_PARAMS_ID_RX_CALI_CFG, + (void *)&set_cfg, + sizeof(struct cali_cfg), i); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: dev[%d]start cali failed !\n", + __func__, i); + goto back_cfg; + } + } + msleep(10 * 1000); + } else { + for (i = cali->first_cali_num; i <= cali->end_cali_num; i++) + aw_write_data_to_dsp(INDEX_PARAMS_ID_RX_CALI_CFG, + (void *)&aw882xx->cali.store_cfg[i], + sizeof(struct cali_cfg), i); + } + + return 0; + +back_cfg: + i--; + while (i >= cali->first_cali_num) { + aw_write_data_to_dsp(INDEX_PARAMS_ID_RX_CALI_CFG, + (void *)&aw882xx->cali.store_cfg[i], + sizeof(struct cali_cfg), i); + i--; + } + return ret; + +#endif +} + +static int aw_run_noise_to_dsp(struct aw882xx *aw882xx, + int32_t noise_enable) +{ + int i, ret; + struct aw_cali *cali = &aw882xx->cali; + + aw_dev_dbg(aw882xx->dev, "%s: noise_enable:%d\n", + __func__, noise_enable); + + for (i = cali->first_cali_num; i <= cali->end_cali_num; i++) { + ret = aw_write_data_to_dsp(INDEX_PARAMS_ID_RX_NOISE, + (void *)&noise_enable, sizeof(noise_enable), i); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:dev[%d] set noise:%d failed!\n", + __func__, i, noise_enable); + return ret; + } + } + return 0; +} + +static int aw_cali_get_re_from_dsp(struct aw882xx *aw882xx) +{ + struct cali_data cali_data; + int ret, i; + struct aw_cali *cali = &aw882xx->cali; + + /*get cali data*/ + for (i = cali->first_cali_num; i <= cali->end_cali_num; i++) { + ret = aw_read_data_from_dsp(INDEX_PARAMS_ID_RX_REAL_DATA, + (void *)&cali_data, + sizeof(struct cali_data), i); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:dev[%d] read cali data failed!\n", + __func__, i); + return ret; + } + + aw882xx->cali.re[i] = FIXED_RE_TO_MOHM(cali_data.data[0]); + aw_dev_dbg(aw882xx->dev, "%s:dev[%d]: re %d\n", + __func__, i, aw882xx->cali.re[i]); + } + + return 0; +} + +static int aw_cali_get_f0_from_dsp(struct aw882xx *aw882xx) +{ + int32_t read_f0; + int ret, i; + struct aw_cali *cali = &aw882xx->cali; + + for (i = cali->first_cali_num; i <= cali->end_cali_num; i++) { + ret = aw_read_data_from_dsp(INDEX_PARAMS_ID_RX_F0, + (void *)&read_f0, sizeof(int32_t), i); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:dev[%d] read f0 failed!\n", + __func__, i); + return -EBUSY; + } + aw882xx->cali.f0[i] = read_f0; + aw_dev_dbg(aw882xx->dev, "%s:dev[%d]: f0 %d\n", + __func__, i, aw882xx->cali.f0[i]); + } + + return 0; +} + +static int aw_cali_get_re(struct aw882xx *aw882xx) +{ + int ret; + + g_cali_status = true; + + ret = aw_run_dsp_hmute(aw882xx, true); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:set dsp hmute failed!\n", + __func__); + goto mute_failed; + } + + ret = aw_run_cali_cfg_to_dsp(aw882xx, true); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:set cali cfg failed !\n", + __func__); + goto set_cali_cfg_failed; + } + + /*get cali data*/ + ret = aw_cali_get_re_from_dsp(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: read re failed!\n", + __func__); + goto cali_data_failed; + } + +cali_data_failed: + aw_run_cali_cfg_to_dsp(aw882xx, false); +set_cali_cfg_failed: + aw_run_dsp_hmute(aw882xx, false); +mute_failed: + g_cali_status = false; + return ret; +} + +static int aw_cali_get_f0(struct aw882xx *aw882xx, bool noise_en) +{ + int ret; + + g_cali_status = true; + if (noise_en) { + ret = aw_run_cali_cfg_to_dsp(aw882xx, true); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:set cali cfg failed !\n", + __func__); + goto set_cali_cfg_failed; + } + + ret = aw_run_noise_to_dsp(aw882xx, true); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: set noise enable failed\n", + __func__); + goto set_noise_failed; + } + + /*keep 5 s, wait data stable*/ + msleep(5 * 1000); + } + + /*get cali data*/ + ret = aw_cali_get_f0_from_dsp(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:read f0 failed!\n", + __func__); + } + +set_noise_failed: + if (noise_en) { + aw_run_noise_to_dsp(aw882xx, false); + aw_run_cali_cfg_to_dsp(aw882xx, false); + } +set_cali_cfg_failed: + g_cali_status = false; + return ret; +} + +static int aw882xx_cali_start_up(struct aw882xx *aw882xx) +{ + int ret; + + g_cali_status = true; + ret = aw_run_dsp_hmute(aw882xx, true); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:set dsp hmute failed!\n", + __func__); + goto mute_failed; + } + + ret = aw_run_cali_cfg_to_dsp(aw882xx, true); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:set cali cfg failed !\n", + __func__); + aw_run_dsp_hmute(aw882xx, false); + goto set_cali_cfg_failed; + } + + /*get cali data*/ + ret = aw_cali_get_re_from_dsp(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: read re failed!\n", + __func__); + goto re_cali_failed; + } + + ret = aw_run_dsp_hmute(aw882xx, false); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:set dsp unhmute failed!\n", + __func__); + goto unhmute_failed; + } + + /*start white noise*/ + ret = aw_run_noise_to_dsp(aw882xx, true); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: set noise enable failed\n", + __func__); + goto set_noise_failed; + } + + /*keep 5 s, wait data stable*/ + msleep(5 * 1000); + + /*get f0 value*/ + ret = aw_cali_get_f0_from_dsp(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: read f0 failed !\n", __func__); + goto f0_cali_failed; + } + +f0_cali_failed: + aw_run_noise_to_dsp(aw882xx, false); +set_noise_failed: +unhmute_failed: +re_cali_failed: + aw_run_cali_cfg_to_dsp(aw882xx, false); +set_cali_cfg_failed: +mute_failed: + g_cali_status = false; + return ret; +} + +/***************cali debug fs***************/ +/*unit mOhms*/ +static int R0_MAX = 15000; +static int R0_MIN = 5000; + +int aw_cali_range_open(struct inode *inode, struct file *file) +{ + struct aw882xx *aw882xx = (struct aw882xx *)inode->i_private; + + file->private_data = (void *)aw882xx; + aw_dev_info(aw882xx->dev, "%s: open success", __func__); + return 0; +} + +ssize_t aw_cali_range_read(struct file *file, + char __user *buf, size_t len, loff_t *ppos) +{ + int ret; + char local_buf[50] = { 0 }; + struct aw882xx *aw882xx = (struct aw882xx *)file->private_data; + + if (*ppos) + return 0; + + memset(local_buf, 0, sizeof(local_buf)); + if (len < sizeof(local_buf)) { + aw_dev_err(aw882xx->dev, "%s: buf len not enough\n", __func__); + return -ENOSPC; + } + + ret = snprintf(local_buf, sizeof(local_buf) - 1, + " Min:%d mOhms, Max:%d mOhms\n", R0_MIN, R0_MAX); + + ret = simple_read_from_buffer(buf, len, ppos, local_buf, ret); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: copy failed!\n", __func__); + return -ENOMEM; + } + return ret; +} + +ssize_t aw_cali_range_write(struct file *file, + const char __user *buf, size_t len, loff_t *ppos) +{ + struct aw882xx *aw882xx = (struct aw882xx *)file->private_data; + uint32_t time; + int ret; + + if (*ppos) + return 0; + + ret = kstrtouint_from_user(buf, len, 0, &time); + if (ret) + return len; + + if (time < AW_CALI_RE_MIN_TIMER) { + aw_dev_err(aw882xx->dev, "%s:time:%d is too short, no set\n", + __func__, time); + return -EINVAL; + } + + aw882xx->cali.cali_re_time = time; + + return len; +} + +static const struct file_operations aw_cali_range_fops = { + .open = aw_cali_range_open, + .read = aw_cali_range_read, + .write = aw_cali_range_write, +}; + +int aw_cali_open(struct inode *inode, struct file *file) +{ + struct aw882xx *aw882xx = (struct aw882xx *)inode->i_private; + + file->private_data = (void *)aw882xx; + aw_dev_dbg(aw882xx->dev, "%s: open success\n", __func__); + return 0; +} + +ssize_t aw_cali_read(struct file *file, + char __user *buf, size_t len, loff_t *ppos) +{ + int ret; + char ret_value[64] = { 0 }; + struct aw882xx *aw882xx = (struct aw882xx *)file->private_data; + + if (*ppos) + return 0; + + memset(ret_value, 0, sizeof(ret_value)); + if (len < sizeof(ret_value)) { + aw_dev_err(aw882xx->dev, "%s:buf len no enough\n", __func__); + memset(aw882xx->cali.re, 0, sizeof(aw882xx->cali.re)); + return -ENOMEM; + } + + ret = aw_cali_get_re(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:cali failed\n", __func__); + memset(aw882xx->cali.re, 0, sizeof(aw882xx->cali.re)); + return ret; + } + + if (aw882xx->cali.end_cali_num - aw882xx->cali.first_cali_num) + ret = snprintf(ret_value, sizeof(ret_value) - 1, + "left:%d mOhms right:%d mOhms\n", + aw882xx->cali.re[0], aw882xx->cali.re[1]); + else + ret = snprintf(ret_value, sizeof(ret_value) - 1, + "%d\n", aw882xx->cali.re[aw882xx->chan_info.channel]); + + return simple_read_from_buffer(buf, len, ppos, ret_value, ret); +} + +ssize_t aw_cali_write(struct file *file, + const char __user *buf, size_t len, loff_t *ppos) +{ + + return 0; +} + +static const struct file_operations aw_cali_fops = { + .open = aw_cali_open, + .read = aw_cali_read, + .write = aw_cali_write, +}; + +int aw_f0_open(struct inode *inode, struct file *file) +{ + struct aw882xx *aw882xx = (struct aw882xx *)inode->i_private; + + file->private_data = (void *)aw882xx; + aw_dev_dbg(aw882xx->dev, "%s: open success\n", __func__); + return 0; +} + +ssize_t aw_f0_read(struct file *file, + char __user *buf, size_t len, loff_t *ppos) +{ + int ret; + char ret_value[64] = { 0 }; + struct aw882xx *aw882xx = (struct aw882xx *)file->private_data; + + if (*ppos) + return 0; + + memset(ret_value, 0, sizeof(ret_value)); + if (len < sizeof(ret_value)) { + aw_dev_err(aw882xx->dev, "%s:buf len no enough\n", __func__); + memset(aw882xx->cali.f0, 0, sizeof(aw882xx->cali.f0)); + return -ENOMEM; + } + + ret = aw_cali_get_f0(aw882xx, false); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:cali failed\n", __func__); + memset(aw882xx->cali.f0, 0, sizeof(aw882xx->cali.f0)); + return ret; + } + + if (aw882xx->cali.end_cali_num - aw882xx->cali.first_cali_num) + ret = snprintf(ret_value, sizeof(ret_value) - 1, + "left:%d right:%d\n", aw882xx->cali.f0[0], + aw882xx->cali.f0[1]); + else + ret = snprintf(ret_value, sizeof(ret_value) - 1, "%d\n", + aw882xx->cali.f0[aw882xx->chan_info.channel]); + + ret = simple_read_from_buffer(buf, len, ppos, ret_value, ret); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:copy failed!\n", __func__); + return -ENOMEM; + } + return ret; +} + +static const struct file_operations aw_f0_fops = { + .open = aw_f0_open, + .read = aw_f0_read, +}; +int aw_cali_status_open(struct inode *inode, struct file *file) +{ + struct aw882xx *aw882xx = (struct aw882xx *)inode->i_private; + + file->private_data = (void *)aw882xx; + aw_dev_dbg(aw882xx->dev, "%s: open success\n", __func__); + return 0; +} + +ssize_t aw_cali_status_read(struct file *file, + char __user *buf, size_t len, loff_t *ppos) +{ + int ret; + char status_value[20] = { 0 }; + struct cali_data cali_data; + struct aw_cali_st cali_st; + unsigned int algo_version; + int32_t real_r0; + struct aw882xx *aw882xx = (struct aw882xx *)file->private_data; + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + int channel = aw882xx->chan_info.channel; + + if (*ppos) + return 0; + + if (len < sizeof(status_value)) { + aw_dev_err(aw882xx->dev, "%s:buf len no enough\n", __func__); + return -ENOSPC; + } + + /*get cali data*/ + ret = aw_get_algo_version(&algo_version); + if (ret < 0) { + aw_dev_dbg(aw882xx->dev, "%s: failed to get algo version", __func__); + ret = aw_read_data_from_dsp(INDEX_PARAMS_ID_RX_REAL_DATA, + (void *)&cali_data, sizeof(struct cali_data), + chan_info->channel); + if (ret) { + aw_dev_err(aw882xx->dev, "%s:read speaker status failed!\n", + __func__); + return -EBUSY; + } + real_r0 = FIXED_RE_TO_MOHM(cali_data.data[0]); + ret = snprintf(status_value, sizeof(status_value) - 1, + "%d : %d\n", real_r0, cali_data.data[1]); + } else { + aw_dev_dbg(aw882xx->dev, "%s: algo version is 0x%08x", __func__, algo_version); + ret = aw_read_msg_from_dsp(INLINE_PARAMS_ID_SPK_STATUS, + (void *)&cali_st, sizeof(struct aw_cali_st), + chan_info->channel); + if (ret) { + aw_dev_err(aw882xx->dev, "%s:read speaker status failed!\n", + __func__); + return -EBUSY; + } + real_r0 = FIXED_RE_TO_MOHM(cali_st.data[4 * channel]); + ret = snprintf(status_value, sizeof(status_value) - 1, + "%d : %d\n", real_r0, cali_st.data[2 + 4 * channel]); + } + + ret = simple_read_from_buffer(buf, len, ppos, status_value, ret); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:copy failed!", __func__); + return -ENOMEM; + } + return ret; +} + +static const struct file_operations aw_cali_status_fops = { + .open = aw_cali_status_open, + .read = aw_cali_status_read, +}; + +static void aw_cali_debugfs_init(struct aw882xx *aw882xx) +{ + const char *debugfs_dir = "awinic_cali"; + struct aw_dbg_cali *dbg_fs = &aw882xx->cali.dbg_fs; + int ret; + + ret = aw882xx_append_suffix("%s_%s", &debugfs_dir, aw882xx); + if (ret < 0) + return; + + dbg_fs->dbg_dir = debugfs_create_dir(debugfs_dir, NULL); + if (dbg_fs->dbg_dir == NULL) { + aw_dev_err(aw882xx->dev, "create cali debugfs failed !\n"); + return; + } + dbg_fs->dbg_range = debugfs_create_file("range", S_IFREG|S_IRUGO, + dbg_fs->dbg_dir, aw882xx, &aw_cali_range_fops); + if (dbg_fs->dbg_range == NULL) { + aw_dev_err(aw882xx->dev, "create cali debugfs range failed !\n"); + return; + } + dbg_fs->dbg_cali = debugfs_create_file("cali", S_IFREG|S_IRUGO|S_IWUGO, + dbg_fs->dbg_dir, aw882xx, &aw_cali_fops); + if (dbg_fs->dbg_cali == NULL) { + aw_dev_err(aw882xx->dev, "create cali debugfs cali failed !\n"); + return; + } + dbg_fs->dbg_f0 = debugfs_create_file("f0", S_IFREG|S_IRUGO, + dbg_fs->dbg_dir, aw882xx, &aw_f0_fops); + if (dbg_fs->dbg_f0 == NULL) { + aw_dev_err(aw882xx->dev, "create cali debugfs cali failed !\n"); + return; + } + dbg_fs->dbg_status = debugfs_create_file("status", S_IFREG|S_IRUGO, + dbg_fs->dbg_dir, aw882xx, &aw_cali_status_fops); + if (dbg_fs->dbg_status == NULL) { + aw_dev_err(aw882xx->dev, "create cali debugfs status failed !\n"); + return; + } +} + +void aw_cali_debugfs_deinit(struct aw882xx *aw882xx) +{ + struct aw_dbg_cali *dbg_fs = &aw882xx->cali.dbg_fs; + + debugfs_remove(dbg_fs->dbg_range); + debugfs_remove(dbg_fs->dbg_cali); + debugfs_remove(dbg_fs->dbg_f0); + debugfs_remove(dbg_fs->dbg_status); + debugfs_remove(dbg_fs->dbg_dir); +} + +/***********************cali misc device*********************/ +static int aw882xx_file_open(struct inode *inode, struct file *file) +{ + struct miscdevice *device = NULL; + struct aw_misc_cali *misc_ptr = NULL; + struct aw_cali *cali_ptr = NULL; + struct aw882xx *aw882xx = NULL; + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + device = (struct miscdevice *)file->private_data; + + misc_ptr = container_of(device, struct aw_misc_cali, misc_device); + cali_ptr = container_of(misc_ptr, struct aw_cali, misc); + aw882xx = container_of(cali_ptr, struct aw882xx, cali); + + file->private_data = (void *)aw882xx; + + aw_dev_dbg(aw882xx->dev, "%s: misc open success\n", __func__); + return 0; +} + +static int aw882xx_file_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + pr_debug("misc release successi\n"); + return 0; +} + +static int aw882xx_file_get_index(unsigned int cmd, int32_t *index) +{ + switch (cmd) { + case AW882XX_IOCTL_GET_CALI_CFG: + case AW882XX_IOCTL_SET_CALI_CFG: + *index = INDEX_PARAMS_ID_RX_CALI_CFG; + break; + case AW882XX_IOCTL_GET_CALI_DATA: + *index = INDEX_PARAMS_ID_RX_REAL_DATA; + break; + case AW882XX_IOCTL_SET_NOISE: + *index = INDEX_PARAMS_ID_RX_NOISE; + break; + case AW882XX_IOCTL_GET_F0: + *index = INDEX_PARAMS_ID_RX_F0; + break; + case AW882XX_IOCTL_GET_CALI_RE: + case AW882XX_IOCTL_SET_CALI_RE: + *index = INDEX_PARAMS_ID_RX_RE; + break; + case AW882XX_IOCTL_GET_VMAX: + case AW882XX_IOCTL_SET_VMAX: + *index = INDEX_PARAMS_ID_RX_VMAX; + break; + case AW882XX_IOCTL_SET_PARAM: + case AW882XX_IOCTL_SET_PTR_PARAM_NUM: + *index = INDEX_PARAMS_ID_RX_PARAMS; + break; + case AW882XX_IOCTL_ENABLE_CALI: + break; + case AW882XX_IOCTL_GET_F0_Q: + case AW882XX_IOCTL_SET_DSP_HMUTE: + case AW882XX_IOCTL_SET_CALI_CFG_FLAG: + case AW882XX_IOCTL_MSG: + *index = INDEX_PARAMS_ID_AWDSP_RX_MSG; + break; + default: + pr_err("%s: unsupported cmd %d\n", __func__, cmd); + return -EINVAL; + } + + pr_info("%s: cmd is %d\n", __func__, cmd); + return 0; +} + +static int aw_misc_ops_read_dsp(struct aw882xx *aw882xx, aw_ioctl_msg_t *msg) +{ + char __user* user_data = (char __user*)msg->data_buf; + uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; + int data_len = msg->data_len; + int ret; + char *data_ptr; + + data_ptr = kmalloc(data_len, GFP_KERNEL); + if (!data_ptr) { + aw_dev_err(aw882xx->dev, "%s : malloc failed !\n", __func__); + return -ENOMEM; + } + + ret = aw_read_msg_from_dsp(dsp_msg_id, data_ptr, data_len, aw882xx->chan_info.channel); + if (ret) { + aw_dev_err(aw882xx->dev, "%s : write failed\n", __func__); + goto exit; + } + + if (copy_to_user((void __user *)user_data, + data_ptr, data_len)) { + ret = -EFAULT; + } +exit: + kfree(data_ptr); + return ret; +} + +static int aw_misc_ops_write_dsp(struct aw882xx *aw882xx, aw_ioctl_msg_t *msg) +{ + char __user* user_data = (char __user*)msg->data_buf; + uint32_t dsp_msg_id = (uint32_t)msg->opcode_id; + int data_len = msg->data_len; + int ret; + char *data_ptr; + + data_ptr = kmalloc(data_len, GFP_KERNEL); + if (!data_ptr) { + aw_dev_err(aw882xx->dev, "%s : malloc failed !\n", __func__); + return -ENOMEM; + } + + if (copy_from_user(data_ptr, (void __user *)user_data, data_len)) { + aw_dev_err(aw882xx->dev, "%s : copy data failed\n", __func__); + ret = -EFAULT; + goto exit; + } + + ret = aw_write_msg_to_dsp(dsp_msg_id, data_ptr, data_len, aw882xx->chan_info.channel); + if (ret) { + aw_dev_err(aw882xx->dev, "%s : write failed\n", __func__); + } +exit: + kfree(data_ptr); + return ret; +} + +static int aw_misc_ops_msg(struct aw882xx *aw882xx, unsigned long arg) +{ + aw_ioctl_msg_t ioctl_msg; + + if (copy_from_user(&ioctl_msg, (void __user *)arg, sizeof(aw_ioctl_msg_t))) { + return -EFAULT; + } + + if(ioctl_msg.version != AW_IOCTL_MSG_VERSION) { + aw_dev_err(aw882xx->dev, "unsupported msg version %d", ioctl_msg.version); + return -EINVAL; + } + + if (ioctl_msg.type == AW_IOCTL_MSG_RD_DSP) { + return aw_misc_ops_read_dsp(aw882xx, &ioctl_msg); + } else if (ioctl_msg.type == AW_IOCTL_MSG_WR_DSP) { + return aw_misc_ops_write_dsp(aw882xx, &ioctl_msg); + } else { + aw_dev_err(aw882xx->dev, "unsupported msg type %d", ioctl_msg.type); + return -EINVAL; + } +} + +static int aw882xx_cali_operation(struct aw882xx *aw882xx, + unsigned int cmd, unsigned long arg) +{ + int16_t data_len = _IOC_SIZE(cmd); + int ret = 0; + char *data_ptr = NULL; + uint32_t index = 0; + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + struct ptr_params_data *p_params = NULL; + int32_t *p_data = NULL; + + aw_dev_info(aw882xx->dev, "%s: cmd : %d, data_len%d\n", __func__, cmd , data_len); + + data_ptr = kmalloc(data_len, GFP_KERNEL); + if (!data_ptr) { + aw_dev_err(aw882xx->dev, "%s : malloc failed !\n", __func__); + return -ENOMEM; + } + + ret = aw882xx_file_get_index(cmd, &index); + if (ret < 0) + goto exit; + + switch (cmd) { + case AW882XX_IOCTL_ENABLE_CALI: + if (copy_from_user(data_ptr, + (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + g_cali_status = (int8_t)data_ptr[0]; + aw_dev_info(aw882xx->dev, "%s:set cali %s", __func__, + (g_cali_status == 0) ? ("disable") : ("enable")); + break; + case AW882XX_IOCTL_SET_CALI_CFG: + case AW882XX_IOCTL_SET_NOISE: + case AW882XX_IOCTL_SET_VMAX: + case AW882XX_IOCTL_SET_PARAM: + aw_dev_info(aw882xx->dev, "SET_PARAM : %d, data_len %d\n",cmd, data_len); + if (copy_from_user(data_ptr, + (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + ret = aw_write_data_to_dsp(index, data_ptr, + data_len, chan_info->channel); + if (ret) { + aw_dev_err(aw882xx->dev, "%s: dsp_msg_write error: %d\n", + __func__, index); + goto exit; + } + break; + case AW882XX_IOCTL_SET_PTR_PARAM_NUM: + aw_dev_info(aw882xx->dev, "SET_PTR_PARAM_NUM : %d, data_len %d\n",cmd, data_len); + if (copy_from_user(data_ptr, + (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + p_params = (struct ptr_params_data *)data_ptr; + if (p_params->data == NULL || (p_params->len <= 0)) { + aw_dev_err(aw882xx->dev, "%s: p_params error\n", + __func__); + ret = -EFAULT; + goto exit; + } + p_data = kzalloc(p_params->len, GFP_KERNEL); + if (!p_data) { + aw_dev_err(aw882xx->dev, + "%s: error allocating memory\n", __func__); + ret = -ENOMEM; + goto exit; + } + + if (copy_from_user(p_data, + (void __user *)p_params->data, + p_params->len)) { + kfree(p_data); + p_data = NULL; + ret = -EFAULT; + goto exit; + } + + ret = aw_write_data_to_dsp(index, p_data, + p_params->len, chan_info->channel); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: dsp_msg_write error: %d\n", + __func__, index); + kfree(p_data); + p_data = NULL; + goto exit; + } + kfree(p_data); + p_data = NULL; + break; + case AW882XX_IOCTL_SET_CALI_RE: + aw_dev_info(aw882xx->dev, "SET_CALI_RE : %d, data_len %d\n",cmd, data_len); + if (copy_from_user(data_ptr, + (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + + ret = aw882xx_store_cali_re(aw882xx, *((int32_t *)data_ptr)); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: store cali re error\n", + __func__); + goto exit; + } + + ret = aw_write_data_to_dsp(index, data_ptr, + data_len, chan_info->channel); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: dsp_msg_write error: %d\n", + __func__, index); + ret = 0; + } + break; + case AW882XX_IOCTL_SET_DSP_HMUTE: + if (copy_from_user(data_ptr, + (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + ret = aw_write_msg_to_dsp(INLINE_PARAM_ID_ENABLE_HMUTE, + data_ptr, data_len, aw882xx->chan_info.channel); + if (ret < 0) + goto exit; + break; + case AW882XX_IOCTL_SET_CALI_CFG_FLAG: + if (copy_from_user(data_ptr, + (void __user *)arg, data_len)) { + ret = -EFAULT; + goto exit; + } + ret = aw_write_msg_to_dsp(INLINE_PARAM_ID_ENABLE_CALI, + data_ptr, data_len, aw882xx->chan_info.channel); + if (ret < 0) + goto exit; + break; + case AW882XX_IOCTL_MSG: + ret = aw_misc_ops_msg(aw882xx, arg); + if (ret < 0) + goto exit; + break; + case AW882XX_IOCTL_GET_CALI_CFG: + case AW882XX_IOCTL_GET_CALI_DATA: + case AW882XX_IOCTL_GET_F0: + case AW882XX_IOCTL_GET_CALI_RE: + case AW882XX_IOCTL_GET_VMAX: + ret = aw_read_data_from_dsp(index, data_ptr, + data_len, chan_info->channel); + if (ret) { + aw_dev_err(aw882xx->dev, "%s: dsp_msg_read error: %d\n", + __func__, index); + ret = -EFAULT; + goto exit; + } + if (copy_to_user((void __user *)arg, + data_ptr, data_len)) { + ret = -EFAULT; + goto exit; + } + break; + case AW882XX_IOCTL_GET_F0_Q: + ret = aw_read_msg_from_dsp(INLINE_PARAM_ID_F0_Q, + data_ptr, data_len, chan_info->channel); + if (ret < 0) + goto exit; + if (copy_to_user((void __user *)arg, + data_ptr, data_len)) { + ret = -EFAULT; + goto exit; + } + break; + default: + aw_dev_err(aw882xx->dev, "%s : cmd %d\n", + __func__, cmd); + break; + } +exit: + kfree(data_ptr); + data_ptr = NULL; + return ret; +} + +static long aw882xx_file_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw882xx *aw882xx = NULL; + + if (((_IOC_TYPE(cmd)) != (AW882XX_IOCTL_MAGIC))) { + pr_err("%s: cmd magic err\n", __func__); + return -EINVAL; + } + aw882xx = (struct aw882xx *)file->private_data; + ret = aw882xx_cali_operation(aw882xx, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} + +#ifdef CONFIG_COMPAT +static long aw882xx_file_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct aw882xx *aw882xx = NULL; + + if (((_IOC_TYPE(cmd)) != (AW882XX_IOCTL_MAGIC))) { + pr_err("%s: cmd magic err\n", __func__); + return -EINVAL; + } + aw882xx = (struct aw882xx *)file->private_data; + ret = aw882xx_cali_operation(aw882xx, cmd, arg); + if (ret) + return -EINVAL; + + return 0; +} +#endif + +static const struct file_operations aw882xx_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = aw882xx_file_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = aw882xx_file_compat_ioctl, +#endif + .open = aw882xx_file_open, + .release = aw882xx_file_release, +}; + +static void aw_cali_misc_init(struct aw882xx *aw882xx) +{ + int ret; + struct miscdevice *device = &aw882xx->cali.misc.misc_device; + const char *aw_misc_name = "aw882xx_smartpa"; + + ret = aw882xx_append_suffix("%s_%s", &aw_misc_name, aw882xx); + if (ret < 0) + return; + + device->minor = MISC_DYNAMIC_MINOR; + device->name = aw_misc_name; + device->fops = &aw882xx_fops; + + ret = misc_register(device); + if (ret) { + aw_dev_err(aw882xx->dev, "%s: misc register fail: %d\n", + __func__, ret); + return; + } + aw_dev_dbg(aw882xx->dev, "%s: misc register success\n", __func__); +} + +static void aw_cali_misc_deinit(struct aw882xx *aw882xx) +{ + misc_deregister(&aw882xx->cali.misc.misc_device); + aw_dev_dbg(aw882xx->dev, "%s: misc unregister done\n", __func__); +} + +/*****************ATTR FOR Calibration**********************************/ +static ssize_t aw882xx_cali_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "%d ms\n", + aw882xx->cali.cali_re_time); + + return len; +} + +static ssize_t aw882xx_cali_time_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + uint32_t time; + + ret = kstrtoint(buf, 0, &time); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s, read buf %s failed\n", + __func__, buf); + return ret; + } + + if (time < AW_CALI_RE_MIN_TIMER) { + aw_dev_err(aw882xx->dev, "%s:time:%d is too short, no set\n", + __func__, time); + return -EINVAL; + } + + aw882xx->cali.cali_re_time = time; + aw_dev_info(aw882xx->dev, "%s:time:%d\n", + __func__, aw882xx->cali.cali_re_time); + + return count; +} + +static ssize_t aw882xx_cali_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + int ret; + + ret = aw882xx_cali_start_up(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: cali failed\n", __func__); + memset(aw882xx->cali.re, 0, sizeof(aw882xx->cali.re)); + memset(aw882xx->cali.f0, 0, sizeof(aw882xx->cali.f0)); + return ret; + } + + if (aw882xx->cali.end_cali_num - aw882xx->cali.first_cali_num) { + len += snprintf(buf+len, + PAGE_SIZE - len, "Re = left:%d mOhms right:%d mOhms\n", + aw882xx->cali.re[0], aw882xx->cali.re[1]); + len += snprintf(buf+len, + PAGE_SIZE - len, "F0 = left:%d right:%d\n", + aw882xx->cali.f0[0], aw882xx->cali.f0[1]); + } else { + len += snprintf(buf+len, + PAGE_SIZE - len, "Re = %d\n", + aw882xx->cali.re[aw882xx->chan_info.channel]); + len += snprintf(buf+len, + PAGE_SIZE - len, "F0 = %d\n", + aw882xx->cali.f0[aw882xx->chan_info.channel]); + } + + return len; +} + +static ssize_t aw882xx_cali_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + if (strncmp("start_cali", buf, strlen("start_cali"))) { + aw_dev_err(aw882xx->dev, "%s: not define cmd %s\n", + __func__, buf); + ret = -EINVAL; + goto cali_failed; + } + + ret = aw882xx_cali_start_up(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: cali failed\n", __func__); + goto cali_failed; + } + + return count; + +cali_failed: + memset(aw882xx->cali.re, 0, sizeof(aw882xx->cali.re)); + memset(aw882xx->cali.f0, 0, sizeof(aw882xx->cali.f0)); + return ret; +} + +static ssize_t aw882xx_cali_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + int ret; + + ret = aw_cali_get_re(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: cali failed\n", __func__); + memset(aw882xx->cali.re, 0, sizeof(aw882xx->cali.re)); + return ret; + } + + if (aw882xx->cali.end_cali_num - aw882xx->cali.first_cali_num) + len += snprintf(buf+len, + PAGE_SIZE - len, "left:%d mOhms right:%d mOhms\n", + aw882xx->cali.re[0], aw882xx->cali.re[1]); + else + len += snprintf(buf+len, + PAGE_SIZE - len, "%d\n", + aw882xx->cali.re[aw882xx->chan_info.channel]); + + return len; +} + +static ssize_t aw882xx_cali_re_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + if (strncmp("start_cali_re", buf, strlen("start_cali_re"))) { + aw_dev_err(aw882xx->dev, "%s: not define cmd %s\n", + __func__, buf); + ret = -EINVAL; + goto cali_re_failed; + } + + ret = aw_cali_get_re(aw882xx); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: cali failed\n", __func__); + goto cali_re_failed; + } + + return count; + +cali_re_failed: + memset(aw882xx->cali.re, 0, sizeof(aw882xx->cali.re)); + return ret; +} + +static ssize_t aw882xx_cali_f0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + int ret; + + ret = aw_cali_get_f0(aw882xx, false); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: cali failed\n", __func__); + memset(aw882xx->cali.f0, 0, sizeof(aw882xx->cali.f0)); + return ret; + } + + if (aw882xx->cali.end_cali_num - aw882xx->cali.first_cali_num) + len += snprintf(buf+len, + PAGE_SIZE - len, "left:%d right:%d\n", + aw882xx->cali.f0[0], aw882xx->cali.f0[1]); + else + len += snprintf(buf+len, + PAGE_SIZE - len, "%d\n", + aw882xx->cali.f0[aw882xx->chan_info.channel]); + + return len; +} + + +static ssize_t aw882xx_cali_f0_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + + if (strncmp("start_cali_f0", buf, strlen("start_cali_f0"))) { + aw_dev_err(aw882xx->dev, "%s: not define cmd %s\n", + __func__, buf); + ret = -EINVAL; + goto cali_f0_failed; + } + + ret = aw_cali_get_f0(aw882xx, false); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: cali failed\n", __func__); + goto cali_f0_failed; + } + + return count; + +cali_f0_failed: + memset(aw882xx->cali.f0, 0, sizeof(aw882xx->cali.f0)); + return ret; +} + +static ssize_t aw882xx_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + if (aw882xx->cali.end_cali_num - aw882xx->cali.first_cali_num) + len += snprintf(buf+len, + PAGE_SIZE - len, "left:%d mOhms right:%d mOhms\n", + aw882xx->cali.re[0], aw882xx->cali.re[1]); + else + len += snprintf(buf+len, + PAGE_SIZE - len, "%d\n", + aw882xx->cali.re[aw882xx->chan_info.channel]); + + return len; +} + +static ssize_t aw882xx_f0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + + if (aw882xx->cali.end_cali_num - aw882xx->cali.first_cali_num) + len += snprintf(buf+len, + PAGE_SIZE - len, "left:%d right:%d\n", + aw882xx->cali.f0[0], aw882xx->cali.f0[1]); + else + len += snprintf(buf+len, + PAGE_SIZE - len, "%d\n", + aw882xx->cali.f0[aw882xx->chan_info.channel]); + + return len; +} + +static ssize_t aw882xx_f0_q_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct f0_q_data data; + int ret = -1; + ssize_t len = 0; + + ret = aw_get_f0_q(&data, sizeof(struct f0_q_data), aw882xx->chan_info.channel); + if (ret < 0) + return ret; + + if (aw882xx->cali.first_cali_num == aw882xx->cali.end_cali_num) { + if (aw882xx->chan_info.channel == AW882XX_CHANNLE_LEFT_MONO) { + len += snprintf(buf+len, PAGE_SIZE - len, + "f0:%d q:%d\n", data.left_f0, data.left_q); + } else if (aw882xx->chan_info.channel == AW882XX_CHANNLE_RIGHT) { + len += snprintf(buf+len, PAGE_SIZE - len, + "f0:%d q:%d\n", data.right_f0, data.right_q); + } else { + aw_dev_err(aw882xx->dev, "%s: channel:%d unsupported\n", + __func__, aw882xx->chan_info.channel); + return -EINVAL; + } + } else { + len += snprintf(buf+len, PAGE_SIZE - len, "[left]f0:%d q:%d [right]f0:%d q:%d\n", + data.left_f0, data.left_q, data.right_f0, data.right_q); + } + + return len; +} + + +static ssize_t aw882xx_dsp_re_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + int ret = -1; + ssize_t len = 0; + uint32_t re = 0; + + ret = aw_read_data_from_dsp(INDEX_PARAMS_ID_RX_RE, + &re, sizeof(uint32_t), + aw882xx->chan_info.channel); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s : get dsp re failed\n", + __func__); + + re = FIXED_RE_TO_MOHM(re); + len += snprintf(buf+len, PAGE_SIZE-len, "dsp_re:%d\n", re); + + return len; +} + +static ssize_t aw882xx_dsp_re_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct aw882xx *aw882xx = dev_get_drvdata(dev); + int32_t data; + int32_t cali_re; + + ret = kstrtoint(buf, 0, &data); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s, read buf %s failed\n", + __func__, buf); + return ret; + } + + cali_re = MOHM_TO_FIXED_RE(data); + + ret = aw882xx_store_cali_re(aw882xx, cali_re); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: store cali re error\n", + __func__); + return -EPERM; + } + + ret = aw_write_data_to_dsp(INDEX_PARAMS_ID_RX_RE, (void *)&cali_re, + sizeof(uint32_t), aw882xx->chan_info.channel); + if (ret) { + aw_dev_err(aw882xx->dev, "%s: write cali_re to dsp failed\n", + __func__); + } + + aw_dev_dbg(aw882xx->dev, "%s: re:0x%x", + __func__, aw882xx->cali.cali_re); + + return count; +} + +static DEVICE_ATTR(cali_time, S_IRUGO | S_IWUSR, + aw882xx_cali_time_show, aw882xx_cali_time_store); +static DEVICE_ATTR(cali, S_IRUGO | S_IWUSR , + aw882xx_cali_show, aw882xx_cali_store); +static DEVICE_ATTR(cali_re, S_IRUGO | S_IWUSR, + aw882xx_cali_re_show, aw882xx_cali_re_store); +static DEVICE_ATTR(cali_f0, S_IRUGO | S_IWUSR, + aw882xx_cali_f0_show, aw882xx_cali_f0_store); +static DEVICE_ATTR(re_show, S_IRUGO, + aw882xx_re_show, NULL); +static DEVICE_ATTR(f0_show, S_IRUGO, + aw882xx_f0_show, NULL); +static DEVICE_ATTR(f0_q, S_IRUGO, + aw882xx_f0_q_show, NULL); +static DEVICE_ATTR(dsp_re, S_IWUSR | S_IRUGO, + aw882xx_dsp_re_show, aw882xx_dsp_re_store); + + +static struct attribute *aw882xx_cali_attr[] = { + &dev_attr_cali_time.attr, + &dev_attr_cali.attr, + &dev_attr_cali_re.attr, + &dev_attr_cali_f0.attr, + &dev_attr_re_show.attr, + &dev_attr_f0_show.attr, + &dev_attr_f0_q.attr, + &dev_attr_dsp_re.attr, + NULL +}; + +static struct attribute_group aw882xx_cali_attr_group = { + .attrs = aw882xx_cali_attr +}; + +static void aw_cali_attr_init(struct aw882xx *aw882xx) +{ + int ret; + + ret = sysfs_create_group(&aw882xx->dev->kobj, &aw882xx_cali_attr_group); + if (ret < 0) { + aw_dev_info(aw882xx->dev, "%s error creating sysfs cali attr files\n", + __func__); + } +} + +static void aw_cali_attr_deinit(struct aw882xx *aw882xx) +{ + aw_dev_info(aw882xx->dev, "%s attr files deinit\n", __func__); +} + +void aw_cali_init(struct aw_cali *cali) +{ + struct aw882xx *aw882xx = + container_of(cali, struct aw882xx, cali); + + aw_dev_info(aw882xx->dev, "%s enter\n", __func__); + + aw882xx->cali.cali_re_time = AW_CALI_RE_DEFAULT_TIMER; + if (cali->cali_mode == AW_CALI_MODE_DBGFS) + aw_cali_debugfs_init(aw882xx); + else if (cali->cali_mode == AW_CALI_MODE_MISC) + aw_cali_misc_init(aw882xx); + + aw_cali_attr_init(aw882xx); +} + +void aw_cali_deinit(struct aw_cali *cali) +{ + struct aw882xx *aw882xx = + container_of(cali, struct aw882xx, cali); + + aw_dev_info(aw882xx->dev, "%s enter\n", __func__); + if (cali->cali_mode == AW_CALI_MODE_DBGFS) + aw_cali_debugfs_deinit(aw882xx); + else if (cali->cali_mode == AW_CALI_MODE_MISC) + aw_cali_misc_deinit(aw882xx); + + aw_cali_attr_deinit(aw882xx); +} + +/***************************************************** + * + * device tree parse cali mode + * + *****************************************************/ +void aw882xx_parse_cali_mode_dt(struct aw_cali *cali) +{ + int ret = -1; + const char *cali_mode_str = NULL; + struct aw882xx *aw882xx = + container_of(cali, struct aw882xx, cali); + struct device_node *np = aw882xx->dev->of_node; + + ret = of_property_read_string(np, "aw-cali-mode", &cali_mode_str); + if (ret < 0) { + dev_info(aw882xx->dev, "%s: aw-cali-mode get failed ,user default attr way\n", + __func__); + cali->cali_mode = AW_CALI_MODE_NONE; + return; + } + + if (!strcmp(cali_mode_str, "aw_debugfs")) + cali->cali_mode = AW_CALI_MODE_DBGFS; + else if (!strcmp(cali_mode_str, "aw_misc")) + cali->cali_mode = AW_CALI_MODE_MISC; + else + cali->cali_mode = AW_CALI_MODE_NONE; + + aw_dev_info(aw882xx->dev, "%s:cali mode str:%s num:%d\n", + __func__, cali_mode_str, aw882xx->cali.cali_mode); +} + +static void aw882xx_dev_cali_init(struct aw882xx *aw882xx, bool stereo_cali_en) +{ + struct aw_cali *cali = &aw882xx->cali; + + if (stereo_cali_en && aw882xx->chan_info.name_suffix) { + cali->first_cali_num = AW882XX_CHANNLE_LEFT_MONO; + cali->end_cali_num = AW882XX_CHANNLE_RIGHT; + aw_dev_info(aw882xx->dev, "%s:use stereo channel cali\n", + __func__); + } else { + cali->first_cali_num = + cali->end_cali_num = aw882xx->chan_info.channel; + aw_dev_info(aw882xx->dev, "%s:use mono channel cali\n", + __func__); + } +} + +void aw882xx_parse_cali_way_dt(struct aw_cali *cali) +{ + bool aw_stereo_en; + struct aw882xx *aw882xx = + container_of(cali, struct aw882xx, cali); + struct device_node *np = aw882xx->dev->of_node; + + aw_stereo_en = of_property_read_bool(np, "aw-stereo-cali"); + + aw882xx_dev_cali_init(aw882xx, aw_stereo_en); +} diff --git a/sound/soc/codecs/aw882xx/awinic_cali.h b/sound/soc/codecs/aw882xx/awinic_cali.h new file mode 100644 index 0000000000000000000000000000000000000000..5b825c6adb71f12d7436826472cd8d520f785e75 --- /dev/null +++ b/sound/soc/codecs/aw882xx/awinic_cali.h @@ -0,0 +1,142 @@ +#ifndef __AWINIC_CALI_FS_H__ +#define __AWINIC_CALI_FS_H__ +#include +#include +#include "awinic_dsp.h" + +#define MOHM_TO_FIXED_RE(x) ((x << 12) / 1000) +#define FIXED_RE_TO_MOHM(x) ((x * 1000) >> 12) + +#define AW_IOCTL_MSG_VERSION (0) + +/********************************************* +* dsp +**********************************************/ +#define AW_CALI_STORE_EXAMPLE +/* ERRO CALI RE */ +#define AW_ERRO_CALI_VALUE (0) + +#define AWINIC_DSP_MSG +/*#define AWINIC_DSP_HMUTE*/ +#define AW_CALI_RE_DEFAULT_TIMER (3000) + +#define AW_CALI_RE_MIN_TIMER (1000) +#define AW_DEV_MAX (2) + + +/*********misc device ioctl fo cali**********/ +#define AW882XX_CALI_CFG_NUM (3) +#define AW882XX_CALI_DATA_NUM (6) +#define AW882XX_CALI_STATUS_DATA_NUM (8) +#define AW882XX_PARAMS_NUM (400) +#define AW882XX_KILO_PARAMS_NUM (1000) + + +struct cali_cfg { + int32_t data[AW882XX_CALI_CFG_NUM]; +}; +struct cali_data { + int32_t data[AW882XX_CALI_DATA_NUM]; +}; +struct aw_cali_st { + int32_t data[AW882XX_CALI_STATUS_DATA_NUM]; +}; +struct params_data { + int32_t data[AW882XX_PARAMS_NUM]; +}; +struct ptr_params_data { + int len; + int32_t *data; +}; + +typedef struct { + int32_t type; + int32_t opcode_id; + int32_t version; + int32_t data_len; + char *data_buf; + int32_t reseriver[2]; +}aw_ioctl_msg_t; + +#define AW882XX_IOCTL_MAGIC 'a' +#define AW882XX_IOCTL_SET_CALI_CFG _IOWR(AW882XX_IOCTL_MAGIC, 1, struct cali_cfg) +#define AW882XX_IOCTL_GET_CALI_CFG _IOWR(AW882XX_IOCTL_MAGIC, 2, struct cali_cfg) +#define AW882XX_IOCTL_GET_CALI_DATA _IOWR(AW882XX_IOCTL_MAGIC, 3, struct cali_data) +#define AW882XX_IOCTL_SET_NOISE _IOWR(AW882XX_IOCTL_MAGIC, 4, int32_t) +#define AW882XX_IOCTL_GET_F0 _IOWR(AW882XX_IOCTL_MAGIC, 5, int32_t) +#define AW882XX_IOCTL_SET_CALI_RE _IOWR(AW882XX_IOCTL_MAGIC, 6, int32_t) +#define AW882XX_IOCTL_GET_CALI_RE _IOWR(AW882XX_IOCTL_MAGIC, 7, int32_t) +#define AW882XX_IOCTL_SET_VMAX _IOWR(AW882XX_IOCTL_MAGIC, 8, int32_t) +#define AW882XX_IOCTL_GET_VMAX _IOWR(AW882XX_IOCTL_MAGIC, 9, int32_t) +#define AW882XX_IOCTL_SET_PARAM _IOWR(AW882XX_IOCTL_MAGIC, 10, struct params_data) +#define AW882XX_IOCTL_ENABLE_CALI _IOWR(AW882XX_IOCTL_MAGIC, 11, int8_t) +#define AW882XX_IOCTL_SET_PTR_PARAM_NUM _IOWR(AW882XX_IOCTL_MAGIC, 12, struct ptr_params_data) +#define AW882XX_IOCTL_GET_F0_Q _IOWR(AW882XX_IOCTL_MAGIC, 13, struct f0_q_data) +#define AW882XX_IOCTL_SET_DSP_HMUTE _IOWR(AW882XX_IOCTL_MAGIC, 14, int32_t) +#define AW882XX_IOCTL_SET_CALI_CFG_FLAG _IOWR(AW882XX_IOCTL_MAGIC, 15, int32_t) +#define AW882XX_IOCTL_MSG _IOWR(AW882XX_IOCTL_MAGIC, 16, aw_ioctl_msg_t) + +typedef struct { + int32_t type; + int32_t opcode_id; + int32_t version; + int32_t reseriver[3]; +}aw_dsp_msg_t; + +struct aw_misc_cali { + struct miscdevice misc_device; +}; + +struct aw_dbg_cali { + struct dentry *dbg_dir; + struct dentry *dbg_range; + struct dentry *dbg_cali; + struct dentry *dbg_status; + struct dentry *dbg_f0; +}; + +enum { + AW_IOCTL_MSG_IOCTL = 0, + AW_IOCTL_MSG_RD_DSP, + AW_IOCTL_MSG_WR_DSP +}; + +enum { + AW_CALI_MODE_NONE = 0, + AW_CALI_MODE_DBGFS, + AW_CALI_MODE_MISC, + AW_CALI_MODE_MAX +}; + +/********************************************* +* struct aw882xx cali +**********************************************/ +struct aw_cali { + unsigned char cali_mode; + uint8_t first_cali_num; + uint8_t end_cali_num; + int32_t cali_re; + int32_t cali_f0; + int32_t re[AW_DEV_MAX]; + int32_t f0[AW_DEV_MAX]; + struct cali_cfg store_cfg[AW_DEV_MAX]; + uint32_t cali_re_time; + + struct aw_dbg_cali dbg_fs; + struct aw_misc_cali misc; +}; + +/********************************************* +* aw882xx cali functions +**********************************************/ +void aw_cali_init(struct aw_cali *cali); +void aw_cali_deinit(struct aw_cali *cali); + +void aw882xx_load_cali_re(struct aw_cali *cali); +void aw882xx_parse_cali_mode_dt(struct aw_cali *cali); +void aw882xx_parse_cali_way_dt(struct aw_cali *cali); + + + + +#endif diff --git a/sound/soc/codecs/aw882xx/awinic_dsp.c b/sound/soc/codecs/aw882xx/awinic_dsp.c new file mode 100644 index 0000000000000000000000000000000000000000..2a18d521ae9659e356cbfce599bdbfa8a065b3c7 --- /dev/null +++ b/sound/soc/codecs/aw882xx/awinic_dsp.c @@ -0,0 +1,583 @@ +/* + * awinic_cali.c cali_module + * + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx.h" +#include "awinic_cali.h" +#include "awinic_monitor.h" +#include "awinic_dsp.h" + +static DEFINE_MUTEX(g_dsp_lock); +static DEFINE_MUTEX(g_msg_dsp_lock); + +static const uint32_t PARAM_ID_INDEX_TABLE[][INDEX_PARAMS_ID_MAX] = { + { + AFE_PARAM_ID_AWDSP_RX_PARAMS, + AFE_PARAM_ID_AWDSP_RX_SET_ENABLE, + AFE_PARAM_ID_AWDSP_TX_SET_ENABLE, + AFE_PARAM_ID_AWDSP_RX_VMAX_L, + AFE_PARAM_ID_AWDSP_RX_CALI_CFG_L, + AFE_PARAM_ID_AWDSP_RX_RE_L, + AFE_PARAM_ID_AWDSP_RX_NOISE_L, + AFE_PARAM_ID_AWDSP_RX_F0_L, + AFE_PARAM_ID_AWDSP_RX_REAL_DATA_L, + AFE_PARAM_ID_AWDSP_RX_MSG, + }, + { + AFE_PARAM_ID_AWDSP_RX_PARAMS, + AFE_PARAM_ID_AWDSP_RX_SET_ENABLE, + AFE_PARAM_ID_AWDSP_TX_SET_ENABLE, + AFE_PARAM_ID_AWDSP_RX_VMAX_R, + AFE_PARAM_ID_AWDSP_RX_CALI_CFG_R, + AFE_PARAM_ID_AWDSP_RX_RE_R, + AFE_PARAM_ID_AWDSP_RX_NOISE_R, + AFE_PARAM_ID_AWDSP_RX_F0_R, + AFE_PARAM_ID_AWDSP_RX_REAL_DATA_R, + AFE_PARAM_ID_AWDSP_RX_MSG, + }, +}; + + +static struct aw_afe_func *aw_afe_fn; +void aw_reg_fae_func(struct aw_afe_func *fn) +{ + aw_afe_fn = fn; +} +EXPORT_SYMBOL(aw_reg_fae_func); +/***************dsp communicate**************/ +#ifdef AW_MTK_PLATFORM +extern int mtk_spk_send_ipi_buf_to_dsp(void *data_buffer, uint32_t data_size); +extern int mtk_spk_recv_ipi_buf_from_dsp(int8_t *buffer, int16_t size, uint32_t *buf_len); +#elif defined AW_QCOM_PLATFORM +extern int afe_get_topology(int port_id); +extern int aw_send_afe_cal_apr(uint32_t param_id, + void *buf, int cmd_size, bool write); +extern int aw_send_afe_rx_module_enable(void *buf, int size); +extern int aw_send_afe_tx_module_enable(void *buf, int size); +#else +static int afe_get_topology(int port_id) +{ + return aw_afe_fn->afe_get_topology(port_id); +} +static int aw_send_afe_cal_apr(uint32_t param_id, + void *buf, int cmd_size, bool write) +{ + return aw_afe_fn->aw_send_afe_cal_apr(param_id,buf,cmd_size,write); +} +static int aw_send_afe_rx_module_enable(void *buf, int size) +{ + return aw_afe_fn->aw_send_afe_rx_module_enable(buf,size); +} +static int aw_send_afe_tx_module_enable(void *buf, int size) +{ + return aw_afe_fn->aw_send_afe_tx_module_enable(buf,size); +} +#endif + +#ifdef AW_QCOM_PLATFORM +extern int aw_adm_param_enable(int port_id, int module_id, int param_id, int enable); +#else +static int aw_adm_param_enable(int port_id, int module_id, int param_id, int enable) +{ +// return aw_afe_fn->aw_adm_param_enable(port_id, module_id, param_id, enable); + return 0; +} +#endif + +static int aw_get_params_id_by_index(int index, int32_t *params_id, int channel) +{ + if (index > INDEX_PARAMS_ID_MAX || channel > 1) { + pr_err("%s: error: index is %d, channel %d\n", + __func__, index, channel); + return -EINVAL; + } + *params_id = PARAM_ID_INDEX_TABLE[channel][index]; + return 0; +} + +#ifdef AW_MTK_PLATFORM +/*****************mtk dsp communication function start**********************/ +static int aw_mtk_write_data_to_dsp(int index, void *data, int data_size, int channel) +{ + int32_t param_id; + int32_t *dsp_data = NULL; + struct aw_dsp_msg_hdr *hdr = NULL; + int ret; + + ret = aw_get_params_id_by_index(index, ¶m_id, channel); + if (ret < 0) + return ret; + + pr_debug("%s: param id = 0x%x", __func__, param_id); + + dsp_data = kzalloc(sizeof(struct aw_dsp_msg_hdr) + data_size, + GFP_KERNEL); + if (!dsp_data) { + pr_err("%s: kzalloc dsp_msg error\n", __func__); + return -ENOMEM; + } + + hdr = (struct aw_dsp_msg_hdr *)dsp_data; + hdr->type = DSP_MSG_TYPE_DATA; + hdr->opcode_id = param_id; + hdr->version = AWINIC_DSP_MSG_HDR_VER; + + memcpy(((char *)dsp_data) + sizeof(struct aw_dsp_msg_hdr), + data, data_size); + + ret = mtk_spk_send_ipi_buf_to_dsp(dsp_data, + sizeof(struct aw_dsp_msg_hdr) + data_size); + if (ret < 0) { + pr_err("%s:write data failed\n", __func__); + kfree(dsp_data); + dsp_data = NULL; + return ret; + } + + kfree(dsp_data); + dsp_data = NULL; + return 0; +} + +static int aw_mtk_read_data_from_dsp(int index, void *data, int data_size, int channel) +{ + int ret; + int32_t param_id; + struct aw_dsp_msg_hdr hdr; + + ret = aw_get_params_id_by_index(index, ¶m_id, channel); + if (ret < 0) + return ret; + + pr_debug("%s: param id = 0x%x", __func__, param_id); + hdr.type = DSP_MSG_TYPE_CMD; + hdr.opcode_id = param_id; + hdr.version = AWINIC_DSP_MSG_HDR_VER; + + mutex_lock(&g_msg_dsp_lock); + ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, sizeof(struct aw_dsp_msg_hdr)); + if (ret < 0) { + pr_err("%s:send cmd failed\n", __func__); + goto dsp_msg_failed; + } + + ret = mtk_spk_recv_ipi_buf_from_dsp(data, data_size, &data_size); + if (ret < 0) { + pr_err("%s:get data failed\n", __func__); + goto dsp_msg_failed; + } + mutex_unlock(&g_msg_dsp_lock); + return 0; + +dsp_msg_failed: + mutex_unlock(&g_msg_dsp_lock); + return ret; +} + +static int aw_mtk_write_msg_to_dsp(int inline_id, + void *data, int data_size, int channel) +{ + int32_t *dsp_msg = NULL; + struct aw_dsp_msg_hdr *hdr = NULL; + int ret; + + dsp_msg = kzalloc(sizeof(struct aw_dsp_msg_hdr) + data_size, + GFP_KERNEL); + if (!dsp_msg) { + pr_err("%s: inline_id:0x%x kzalloc dsp_msg error\n", + __func__, inline_id); + return -ENOMEM; + } + hdr = (struct aw_dsp_msg_hdr *)dsp_msg; + hdr->type = DSP_MSG_TYPE_DATA; + hdr->opcode_id = inline_id; + hdr->version = AWINIC_DSP_MSG_HDR_VER; + + memcpy(((char *)dsp_msg) + sizeof(struct aw_dsp_msg_hdr), + data, data_size); + + ret = aw_mtk_write_data_to_dsp(INDEX_PARAMS_ID_AWDSP_RX_MSG, (void *)dsp_msg, + sizeof(struct aw_dsp_msg_hdr) + data_size, channel); + if (ret < 0) { + pr_err("%s:inline_id:0x%x, write data failed\n", + __func__, inline_id); + kfree(dsp_msg); + dsp_msg = NULL; + return ret; + } + + kfree(dsp_msg); + dsp_msg = NULL; + return 0; +} + +static int aw_mtk_read_msg_from_dsp(int inline_id, + char *data, int data_size, int channel) +{ + struct aw_dsp_msg_hdr hdr[2]; + int ret; + + hdr[0].type = DSP_MSG_TYPE_DATA; + hdr[0].opcode_id = AFE_PARAM_ID_AWDSP_RX_MSG; + hdr[0].version = AWINIC_DSP_MSG_HDR_VER; + hdr[1].type = DSP_MSG_TYPE_CMD; + hdr[1].opcode_id = inline_id; + hdr[1].version = AWINIC_DSP_MSG_HDR_VER; + + mutex_lock(&g_msg_dsp_lock); + ret = mtk_spk_send_ipi_buf_to_dsp(&hdr, 2 * sizeof(struct aw_dsp_msg_hdr)); + if (ret < 0) { + pr_err("%s:send cmd failed\n", __func__); + goto dsp_msg_failed; + } + + ret = mtk_spk_recv_ipi_buf_from_dsp(data, data_size, &data_size); + if (ret < 0) { + pr_err("%s:get data failed\n", __func__); + goto dsp_msg_failed; + } + mutex_unlock(&g_msg_dsp_lock); + return 0; + +dsp_msg_failed: + mutex_unlock(&g_msg_dsp_lock); + return ret; +} + +static int aw_mtk_send_module_enable(void *buf, uint8_t type) +{ + int ret; + + switch (type) { + case AW_RX_MODULE: + ret = aw_mtk_write_data_to_dsp(AFE_PARAM_ID_AWDSP_RX_SET_ENABLE, + buf, sizeof(uint32_t), 0); + break; + case AW_TX_MODULE: + ret = aw_mtk_write_data_to_dsp(AFE_PARAM_ID_AWDSP_TX_SET_ENABLE, + buf, sizeof(uint32_t), 0); + break; + default: + pr_err("%s: mtk unsupported type %d\n", __func__, type); + return -EINVAL; + } + + return ret; +} + +static int aw_mtk_get_module_enable(void *buf, uint8_t type) +{ + int ret; + + switch (type) { + case AW_RX_MODULE: + ret = aw_mtk_read_data_from_dsp(INDEX_PARAMS_ID_RX_ENBALE, + buf, sizeof(uint32_t), 0); + break; + case AW_TX_MODULE: + ret = aw_mtk_read_data_from_dsp(INDEX_PARAMS_ID_TX_ENABLE, + buf, sizeof(uint32_t), 0); + break; + default: + pr_err("%s: mtk unsupported type %d\n", __func__, type); + return -EINVAL; + } + + return ret; +} +/********************mtk dsp communication function end***********************/ +#else +/******************qcom dsp communication function start**********************/ +static int aw_check_dsp_ready(void) +{ + int topo_id; + + topo_id = afe_get_topology(AFE_PORT_ID_AWDSP_RX); + pr_debug("%s: topo_id 0x%x\n", __func__, topo_id); + + if (topo_id == AW_RX_TOPO_ID) + return true; + else + return false; +} + +static int aw_qcom_write_data_to_dsp(int index, void *data, int data_size, int channel) +{ + int ret; + int32_t param_id; + int try = 0; + + ret = aw_get_params_id_by_index(index, ¶m_id, channel); + if (ret < 0) + return ret; + + while (try < AW_DSP_TRY_TIME) { + if (aw_check_dsp_ready()) { + mutex_lock(&g_dsp_lock); + ret = aw_send_afe_cal_apr(param_id, data, + data_size, true); + mutex_unlock(&g_dsp_lock); + return ret; + } else { + try++; + msleep(AW_DSP_SLEEP_TIME); + pr_err("%s: afe not ready try again\n", __func__); + } + } + + return -EINVAL; +} + +static int aw_qcom_read_data_from_dsp(int index, void *data, int data_size, int channel) +{ + int ret; + int32_t param_id; + int try = 0; + + ret = aw_get_params_id_by_index(index, ¶m_id, channel); + if (ret < 0) + return ret; + + while (try < AW_DSP_TRY_TIME) { + if (aw_check_dsp_ready()) { + mutex_lock(&g_dsp_lock); + ret = aw_send_afe_cal_apr(param_id, data, + data_size, false); + mutex_unlock(&g_dsp_lock); + return ret; + } else { + try++; + msleep(AW_DSP_SLEEP_TIME); + pr_debug("[Awinic] %s: afe not ready try again\n", + __func__); + } + } + + return -EINVAL; +} + + +static int aw_qcom_write_msg_to_dsp(int inline_id, + char *data, int data_size, int channel) +{ + int32_t *dsp_msg = NULL; + struct aw_dsp_msg_hdr *hdr = NULL; + int ret; + + dsp_msg = kzalloc(sizeof(struct aw_dsp_msg_hdr) + data_size, + GFP_KERNEL); + if (!dsp_msg) { + pr_err("%s: inline_id:0x%x kzalloc dsp_msg error\n", + __func__, inline_id); + return -ENOMEM; + } + hdr = (struct aw_dsp_msg_hdr *)dsp_msg; + hdr->type = DSP_MSG_TYPE_DATA; + hdr->opcode_id = inline_id; + hdr->version = AWINIC_DSP_MSG_HDR_VER; + + memcpy(((char *)dsp_msg) + sizeof(struct aw_dsp_msg_hdr), + data, data_size); + + ret = aw_qcom_write_data_to_dsp(INDEX_PARAMS_ID_AWDSP_RX_MSG, + (void *)dsp_msg, + sizeof(struct aw_dsp_msg_hdr) + data_size, channel); + if (ret < 0) { + pr_err("%s:inline_id:0x%x, write data failed\n", + __func__, inline_id); + kfree(dsp_msg); + dsp_msg = NULL; + return ret; + } + + kfree(dsp_msg); + dsp_msg = NULL; + return 0; +} + +static int aw_qcom_read_msg_from_dsp(int inline_id, + char *data, int data_size, int channel) +{ + struct aw_dsp_msg_hdr dsp_msg; + int ret; + + dsp_msg.type = DSP_MSG_TYPE_CMD; + dsp_msg.opcode_id = inline_id; + dsp_msg.version = AWINIC_DSP_MSG_HDR_VER; + + mutex_lock(&g_msg_dsp_lock); + ret = aw_qcom_write_data_to_dsp(INDEX_PARAMS_ID_AWDSP_RX_MSG, + &dsp_msg, sizeof(struct aw_dsp_msg_hdr), channel); + if (ret < 0) { + pr_err("%s:inline_id:0x%x, write cmd to dsp failed\n", + __func__, inline_id); + goto dsp_msg_failed; + } + + ret = aw_qcom_read_data_from_dsp(INDEX_PARAMS_ID_AWDSP_RX_MSG, + data, data_size, channel); + if (ret < 0) { + pr_err("%s:inline_id:0x%x, read data from dsp failed\n", + __func__, inline_id); + goto dsp_msg_failed; + } + + mutex_unlock(&g_msg_dsp_lock); + return 0; + +dsp_msg_failed: + mutex_unlock(&g_msg_dsp_lock); + return ret; +} + +static int aw_qcom_send_module_enable(void *buf, int type) +{ + + if (type == AW_RX_MODULE) + return aw_send_afe_rx_module_enable(buf, sizeof(int32_t)); + else + return aw_send_afe_tx_module_enable(buf, sizeof(int32_t)); +} + +static int aw_qcom_get_module_enable(void *buf, int type) +{ + int ret; + + if (type == AW_RX_MODULE) { + ret = aw_qcom_read_data_from_dsp(INDEX_PARAMS_ID_RX_ENBALE, + buf, sizeof(int32_t), 0); + if (ret) { + pr_err("%s: read afe rx failed \n", __func__); + return ret; + } + } else { + ret = aw_qcom_read_data_from_dsp(INDEX_PARAMS_ID_TX_ENABLE, + buf, sizeof(int32_t), 0); + if (ret) { + pr_err("%s: read afe tx failed \n", __func__); + return ret; + } + } + return 0; +} + + +#endif +/*****************qcom dsp communication function end*********************/ +int aw_write_data_to_dsp(int index, void *data, int data_size, int channel) +{ +#ifdef AW_MTK_PLATFORM + return aw_mtk_write_data_to_dsp(index, data, data_size, channel); +#else + return aw_qcom_write_data_to_dsp(index, data, data_size, channel); +#endif +} + +int aw_read_data_from_dsp(int index, void *data, int data_size, int channel) +{ +#ifdef AW_MTK_PLATFORM + return aw_mtk_read_data_from_dsp(index, data, data_size, channel); +#else + return aw_qcom_read_data_from_dsp(index, data, data_size, channel); +#endif +} + +int aw_write_msg_to_dsp(int inline_id, void *data, int data_size, int channel) +{ +#ifdef AW_MTK_PLATFORM + return aw_mtk_write_msg_to_dsp(inline_id, data, data_size, channel); +#else + return aw_qcom_write_msg_to_dsp(inline_id, data, data_size, channel); +#endif +} + +int aw_read_msg_from_dsp(int inline_id, void *data, int data_size, int channel) +{ +#ifdef AW_MTK_PLATFORM + return aw_mtk_read_msg_from_dsp(inline_id, data, data_size, channel); +#else + return aw_qcom_read_msg_from_dsp(inline_id, data, data_size, channel); +#endif +} + +int aw_send_module_enable(void *buf, uint8_t type) +{ +#ifdef AW_MTK_PLATFORM + return aw_mtk_send_module_enable(buf, type); +#else + return aw_qcom_send_module_enable(buf, type); +#endif +} + +int aw_get_module_enable(void *buf, uint8_t type) +{ +#ifdef AW_MTK_PLATFORM + return aw_mtk_get_module_enable(buf, type); +#else + return aw_qcom_get_module_enable(buf, type); +#endif +} + +int aw_get_f0_q(struct f0_q_data *data, int data_size, int channel) +{ + int ret; + + ret = aw_read_msg_from_dsp(INLINE_PARAM_ID_F0_Q, + (void *)data, data_size, channel); + if (ret < 0) { + pr_err("%s : get f0_q failed\n", __func__); + return ret; + } + + return 0; +} + +int aw_get_algo_version(unsigned int *data) +{ + int ret; + + ret = aw_read_msg_from_dsp(INLINE_PARAMS_ID_VERSION, + (void *)data, sizeof(int), 0); + if (ret < 0) { + pr_err("%s : get version failed, ret is %d\n", __func__, ret); + return ret; + } + + pr_info("%s : algo version is 0x%08x", __func__, *data); + return 0; +} + +int aw_dsp_copp_module_en(bool enable) +{ + int ret; + int port_id = AFE_PORT_ID_AWDSP_RX; + int module_id = AW_COPP_MODULE_ID; + int param_id = AW_COPP_MODULE_PARAMS_ID_EN; + + ret = aw_adm_param_enable(port_id, module_id, param_id, enable); + if (ret) { + return -EINVAL; + } + + pr_info("%s: set skt %s", __func__, enable == 1 ? "enable" : "disable"); + return 0; +} + diff --git a/sound/soc/codecs/aw882xx/awinic_dsp.h b/sound/soc/codecs/aw882xx/awinic_dsp.h new file mode 100644 index 0000000000000000000000000000000000000000..a9737004085a72d26e250ea8b47fbe80d00bd2b3 --- /dev/null +++ b/sound/soc/codecs/aw882xx/awinic_dsp.h @@ -0,0 +1,107 @@ +#ifndef __AWINIC_DSP_H__ +#define __AWINIC_DSP_H__ + + + +/*#define AW_MTK_PLATFORM*/ +/*#define AW_QCOM_PLATFORM*/ + +#define AWINIC_DSP_MSG_HDR_VER (1) +#define AW_DSP_TRY_TIME (3) +#define AW_DSP_SLEEP_TIME (10) + +#define AFE_PORT_ID_AWDSP_RX (0x1016) /*plt fp4 AFE_PORT_ID_QUINARY_MI2S_RX*/ +#define AW_RX_TOPO_ID (0x1000FF01) /*RX topology id*/ + +#define AW_COPP_MODULE_ID (0X10013D02) /*SKT module id*/ +#define AW_COPP_MODULE_PARAMS_ID_EN (0X10013D14) /*SKT enable param id*/ + +#define INLINE_PARAM_ID_NULL (0x00000000) +#define INLINE_PARAM_ID_ENABLE_CALI (0x00000001) +#define INLINE_PARAM_ID_ENABLE_HMUTE (0x00000002) +#define INLINE_PARAM_ID_F0_Q (0x00000003) +#define INLINE_PARAM_ID_ACTIVE_FLAG (0x00000004) +#define INLINE_PARAM_ID_REAL_DATA (0x00000005) +#define INLINE_PARAM_ID_DIRECT_CURRENT_FLAG (0x00000006) +#define INLINE_PARAMS_ID_SPK_STATUS (0x00000007) +#define INLINE_PARAMS_ID_VERSION (0x00000008) + + +/*dsp params id*/ +#define AFE_PARAM_ID_AWDSP_RX_SET_ENABLE (0x10013D11) +#define AFE_PARAM_ID_AWDSP_RX_PARAMS (0x10013D12) +#define AFE_PARAM_ID_AWDSP_TX_SET_ENABLE (0x10013D13) +#define AFE_PARAM_ID_AWDSP_RX_VMAX_L (0X10013D17) +#define AFE_PARAM_ID_AWDSP_RX_VMAX_R (0X10013D18) +#define AFE_PARAM_ID_AWDSP_RX_CALI_CFG_L (0X10013D19) +#define AFE_PARAM_ID_AWDSP_RX_CALI_CFG_R (0x10013d1A) +#define AFE_PARAM_ID_AWDSP_RX_RE_L (0x10013d1B) +#define AFE_PARAM_ID_AWDSP_RX_RE_R (0X10013D1C) +#define AFE_PARAM_ID_AWDSP_RX_NOISE_L (0X10013D1D) +#define AFE_PARAM_ID_AWDSP_RX_NOISE_R (0X10013D1E) +#define AFE_PARAM_ID_AWDSP_RX_F0_L (0X10013D1F) +#define AFE_PARAM_ID_AWDSP_RX_F0_R (0X10013D20) +#define AFE_PARAM_ID_AWDSP_RX_REAL_DATA_L (0X10013D21) +#define AFE_PARAM_ID_AWDSP_RX_REAL_DATA_R (0X10013D22) +#define AFE_PARAM_ID_AWDSP_RX_MSG (0X10013D2A) + +enum aw882xx_dsp_msg_type { + DSP_MSG_TYPE_DATA = 0, + DSP_MSG_TYPE_CMD = 1, +}; + +enum aw882xx_dsp_hmute_st { + DSP_UNHMUTE = 0, + DSP_HMUTE = 1, +}; + +enum aw882xx_dsp_cali_st { + DSP_BACK_CALI_CFG = 0, + DSP_SET_CALI_CFG = 1, +}; + +enum aef_module_type { + AW_RX_MODULE = 0, + AW_TX_MODULE = 1, +}; + +enum afe_param_id_adsp { + INDEX_PARAMS_ID_RX_PARAMS = 0, + INDEX_PARAMS_ID_RX_ENBALE, + INDEX_PARAMS_ID_TX_ENABLE, + INDEX_PARAMS_ID_RX_VMAX, + INDEX_PARAMS_ID_RX_CALI_CFG, + INDEX_PARAMS_ID_RX_RE, + INDEX_PARAMS_ID_RX_NOISE, + INDEX_PARAMS_ID_RX_F0, + INDEX_PARAMS_ID_RX_REAL_DATA, + INDEX_PARAMS_ID_AWDSP_RX_MSG, + INDEX_PARAMS_ID_MAX +}; + +struct aw_dsp_msg_hdr { + int32_t type; + int32_t opcode_id; + int32_t version; + int32_t reserver[3]; +}; + +struct f0_q_data { + int32_t left_f0; + int32_t left_q; + int32_t right_f0; + int32_t right_q; +}; + + +int aw_write_data_to_dsp(int index, void *data, int data_size, int channel); +int aw_read_data_from_dsp(int index, void *data, int data_size, int channel); +int aw_write_msg_to_dsp(int inline_id, void *data, int data_size, int channel); +int aw_read_msg_from_dsp(int inline_id, void *data, int data_size, int channel); +int aw_send_module_enable(void *buf, uint8_t type); +int aw_get_module_enable(void *buf, uint8_t type); +int aw_get_f0_q(struct f0_q_data *data, int data_size, int channel); +int aw_get_algo_version(unsigned int *data); +int aw_dsp_copp_module_en(bool enable); + +#endif diff --git a/sound/soc/codecs/aw882xx/awinic_monitor.c b/sound/soc/codecs/aw882xx/awinic_monitor.c new file mode 100644 index 0000000000000000000000000000000000000000..8009323d413fd1f54e957cd2ab2c6bfdad620b55 --- /dev/null +++ b/sound/soc/codecs/aw882xx/awinic_monitor.c @@ -0,0 +1,1059 @@ +/* + * awinic_monitor.c monitor_module + * + * + * Copyright (c) 2019 AWINIC Technology CO., LTD + * + * Author: Nick Li + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw882xx.h" +#include "aw882xx_reg.h" +#include "awinic_cali.h" +#include "awinic_monitor.h" +#include "awinic_dsp.h" + + +static DEFINE_MUTEX(g_aw_monitor_lock); +static LIST_HEAD(g_aw_monitor_list); +uint8_t g_monitor_dev_num; +struct aw_monitor_cfg g_monitor_cfg; +#define AW_MONITOR_FILE "aw882xx_monitor.bin" + +extern unsigned char g_cali_status; + +static int aw882xx_monitor_get_voltage(struct aw882xx *aw882xx, + unsigned int *vol) +{ + int ret = -1; + uint16_t local_vol = 0; + + ret = aw882xx_i2c_read(aw882xx, AW882XX_VBAT_REG, vol); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: read voltage failed !\n", + __func__); + return ret; + } + local_vol = (*vol) * AW882XX_MONITOR_VBAT_RANGE / AW882XX_MONITOR_INT_10BIT; + + *vol = local_vol; + aw_dev_dbg(aw882xx->dev, "%s: chip voltage is %d\n", + __func__, local_vol); + return 0; +} + +static int aw882xx_monitor_get_temperature(struct aw882xx *aw882xx, int *temp) +{ + int ret = -1; + unsigned int reg_val = 0; + uint16_t local_temp; + + ret = aw882xx_i2c_read(aw882xx, AW882XX_TEMP_REG, ®_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: get temperature failed!\n", + __func__); + return ret; + } + + local_temp = reg_val; + if (local_temp & AW882XX_MONITOR_TEMP_SIGN_MASK) + local_temp = local_temp | AW882XX_MONITOR_TEMP_NEG_MASK; + + *temp = (int)local_temp; + + aw_dev_dbg(aw882xx->dev, "%s: chip temperature = %d\n", + __func__, *temp); + return 0; +} + +static int aw882xx_monitor_get_temp_and_vol(struct aw882xx *aw882xx) +{ + struct aw882xx_monitor *monitor = &aw882xx->monitor; + unsigned int voltage = 0; + int current_temp = 0; + int ret = -1; + +#ifdef AW_DEBUG + if (monitor->test_vol == 0) { + ret = aw882xx_monitor_get_voltage(aw882xx, &voltage); + if (ret < 0) + return ret; + } else { + voltage = monitor->test_vol; + } + + if (monitor->test_temp == 0) { + ret = aw882xx_monitor_get_temperature(aw882xx, ¤t_temp); + if (ret) + return ret; + } else { + current_temp = monitor->test_temp; + } +#else + ret = aw882xx_monitor_get_voltage(aw882xx, &voltage); + if (ret < 0) + return ret; + + ret = aw882xx_monitor_get_temperature(aw882xx, ¤t_temp); + if (ret < 0) + return ret; +#endif + + monitor->vol_trace.sum_val += voltage; + monitor->temp_trace.sum_val += current_temp; + monitor->samp_count++; + + return 0; +} + +static int aw882xx_monitor_trace_data_from_table(struct aw882xx *aw882xx, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace) +{ + int i; + + if (table_info.aw_table == NULL) { + aw_dev_err(aw882xx->dev, "%s: table_info.aw_table is null\n", + __func__); + return -EINVAL; + } + + for (i = 0; i < table_info.table_num; i++) { + if (data_trace->sum_val >= table_info.aw_table[i].min_val && + data_trace->sum_val <= table_info.aw_table[i].max_val) { + memcpy(&data_trace->aw_table, &table_info.aw_table[i], + sizeof(struct aw_table)); + break; + } + } + + data_trace->pre_val = data_trace->sum_val; + data_trace->sum_val = 0; + return 0; +} + +static int aw882xx_monitor_first_get_data_form_table(struct aw882xx *aw882xx, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace) +{ + int i; + + if (table_info.aw_table == NULL) { + aw_dev_err(aw882xx->dev, "%s: table_info.aw_table is null\n", + __func__); + return -EINVAL; + } + + for (i = 0; i < table_info.table_num; i++) { + if (data_trace->sum_val >= table_info.aw_table[i].min_val) { + memcpy(&data_trace->aw_table, &table_info.aw_table[i], + sizeof(struct aw_table)); + break; + } + } + data_trace->pre_val = data_trace->sum_val; + data_trace->sum_val = 0; + return 0; +} + +static int aw882xx_monitor_get_data_from_table(struct aw882xx *aw882xx, + struct aw_table_info table_info, + struct aw_monitor_trace *data_trace, + uint32_t aplha) +{ + struct aw882xx_monitor *monitor = &aw882xx->monitor; + + if (monitor->first_entry == AW_FIRST_ENTRY) { + return aw882xx_monitor_first_get_data_form_table(aw882xx, + table_info, data_trace); + } else { + data_trace->sum_val = data_trace->sum_val / monitor->samp_count; + data_trace->sum_val = ((int32_t)aplha * data_trace->sum_val + + (1000 - (int32_t)aplha) * data_trace->pre_val) / 1000; + return aw882xx_monitor_trace_data_from_table(aw882xx, + table_info, data_trace); + } + + return 0; +} + +static int aw882xx_monitor_get_data(struct aw882xx *aw882xx) +{ + struct aw882xx_monitor *monitor = &aw882xx->monitor; + struct aw_monitor_cfg *monitor_cfg = monitor->monitor_cfg; + struct aw_monitor_trace *vol_trace = &monitor->vol_trace; + struct aw_monitor_trace *temp_trace = &monitor->temp_trace; + int ret; + + if (monitor_cfg->vol_switch) { + ret = aw882xx_monitor_get_data_from_table(aw882xx, + monitor_cfg->vol_info, vol_trace, + monitor_cfg->vol_aplha); + if (ret < 0) + return ret; + } else { + vol_trace->aw_table.ipeak = IPEAK_NONE; + vol_trace->aw_table.gain = GAIN_NONE; + vol_trace->aw_table.vmax = VMAX_NONE; + } + + if (monitor_cfg->temp_switch) { + ret = aw882xx_monitor_get_data_from_table(aw882xx, + monitor_cfg->temp_info, temp_trace, + monitor_cfg->temp_aplha); + if (ret < 0) + return ret; + } else { + temp_trace->aw_table.ipeak = IPEAK_NONE; + temp_trace->aw_table.gain = GAIN_NONE; + temp_trace->aw_table.vmax = VMAX_NONE; + } + + aw_dev_info(aw882xx->dev, "%s: vol: ipeak = 0x%x, gain = 0x%x, vmax = 0x%x\n", + __func__, vol_trace->aw_table.ipeak, + vol_trace->aw_table.gain, + vol_trace->aw_table.vmax); + + aw_dev_info(aw882xx->dev, "%s: temp: ipeak = 0x%x, gain = 0x%x, vmax = 0x%x\n", + __func__, temp_trace->aw_table.ipeak, + temp_trace->aw_table.gain, + temp_trace->aw_table.vmax); + + return 0; +} + +static void aw882xx_monitor_get_cfg(struct aw882xx *aw882xx, + struct aw_table *set_table) +{ + struct aw882xx_monitor *monitor = &aw882xx->monitor; + struct aw_table *temp_data = &monitor->temp_trace.aw_table; + struct aw_table *vol_data = &monitor->vol_trace.aw_table; + + if (temp_data->ipeak == IPEAK_NONE && vol_data->ipeak == IPEAK_NONE) { + memcpy(set_table, temp_data, sizeof(struct aw_table)); + } else if (temp_data->ipeak == IPEAK_NONE) { + memcpy(set_table, vol_data, sizeof(struct aw_table)); + } else if (vol_data->ipeak == IPEAK_NONE) { + memcpy(set_table, temp_data, sizeof(struct aw_table)); + } else { + set_table->ipeak = (temp_data->ipeak < vol_data->ipeak ? + temp_data->ipeak : vol_data->ipeak); + set_table->gain = (temp_data->gain < vol_data->gain ? + vol_data->gain : temp_data->gain); + set_table->vmax = (temp_data->vmax < vol_data->vmax ? + vol_data->vmax : temp_data->vmax); + } +} + +static void aw882xx_monitor_set_ipeak(struct aw882xx *aw882xx, + uint8_t ipeak) +{ + struct aw_monitor_cfg *monitor_cfg = aw882xx->monitor.monitor_cfg; + unsigned int reg_val = 0; + unsigned int read_reg_val; + int ret; + + if (ipeak == IPEAK_NONE || (!monitor_cfg->ipeak_switch)) + return; + + ret = aw882xx_i2c_read(aw882xx, AW882XX_SYSCTRL2_REG, ®_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: read ipeak failed\n", __func__); + return; + } + + read_reg_val = reg_val; + read_reg_val &= AW882XX_BIT_SYSCTRL2_BST_IPEAK_MASK; + + if (read_reg_val == ipeak) { + aw_dev_info(aw882xx->dev, "%s: ipeak = 0x%x, no change\n", + __func__, read_reg_val); + return; + } + reg_val &= (~AW882XX_BIT_SYSCTRL2_BST_IPEAK_MASK); + read_reg_val = ipeak; + reg_val |= read_reg_val; + + ret = aw882xx_i2c_write(aw882xx, AW882XX_SYSCTRL2_REG, reg_val); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: write ipeak failed\n", __func__); + return; + } + aw_dev_info(aw882xx->dev, "%s: set reg val = 0x%x, ipeak = 0x%x\n", + __func__, reg_val, ipeak); +} + +static void aw882xx_monitor_set_gain(struct aw882xx *aw882xx, + uint16_t gain) +{ + struct aw_monitor_cfg *monitor_cfg = aw882xx->monitor.monitor_cfg; + uint32_t read_volume; + uint32_t set_volume; + uint32_t gain_db; + int ret; + + if (gain == GAIN_NONE || (!monitor_cfg->gain_switch)) + return; + + ret = aw882xx_get_volume(aw882xx, &read_volume); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: read volume failed\n", __func__); + return; + } + + gain_db = aw882xx_reg_val_to_db(gain); + + /*add offset*/ + set_volume = gain_db + aw882xx->db_offset; + + if (read_volume == set_volume) { + aw_dev_info(aw882xx->dev, "%s: set db = %d.%d dB, no change\n", + __func__, GET_DB_INT(read_volume), + GET_DB_DECIMAL(read_volume)); + return; + } + + ret = aw882xx_set_volume(aw882xx, set_volume); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s: set volume failed\n", __func__); + return; + } + + aw_dev_info(aw882xx->dev, "%s: set_volume = %d.%d dB\n", + __func__, GET_DB_INT(set_volume), + GET_DB_DECIMAL(set_volume)); +} + + +static void aw882xx_monitor_set_vmax(struct aw882xx *aw882xx, + uint32_t vmax) +{ + struct aw882xx_chan_info *chan_info = &aw882xx->chan_info; + struct aw_monitor_cfg *monitor_cfg = aw882xx->monitor.monitor_cfg; + uint32_t local_vmax = vmax; + int ret; + + if (vmax == VMAX_NONE || (!monitor_cfg->vmax_switch)) + return; + + if ((aw882xx->monitor.pre_vmax == vmax) && + (aw882xx->monitor.first_entry != AW_FIRST_ENTRY)) { + aw_dev_info(aw882xx->dev, "%s: vmax no change\n", + __func__); + return; + } + + ret = aw_write_data_to_dsp(INDEX_PARAMS_ID_RX_VMAX, + &local_vmax, sizeof(uint32_t), + chan_info->channel); + if (ret) + aw_dev_err(aw882xx->dev, "%s: dsp_msg_write error\n", + __func__); + + aw882xx->monitor.pre_vmax = vmax; + aw_dev_info(aw882xx->dev, "%s: set vmax = 0x%x\n", __func__, vmax); +} + +static int aw882xx_monitor_work(struct aw882xx *aw882xx) +{ + struct aw882xx_monitor *monitor = &aw882xx->monitor; + struct aw_monitor_cfg *monitor_cfg = monitor->monitor_cfg; + struct aw_table set_table; + int ret = -1; + + if (g_cali_status != 0) { + aw_dev_info(aw882xx->dev, "%s: done nothing while start cali", + __func__); + return 0; + } + + ret = aw882xx_monitor_get_temp_and_vol(aw882xx); + if (ret < 0) + return ret; + + if (monitor->samp_count < monitor_cfg->monitor_count && + (monitor->first_entry == AW_NOT_FIRST_ENTRY)) + return 0; + + ret = aw882xx_monitor_get_data(aw882xx); + if (ret < 0) + return ret; + + aw882xx_monitor_get_cfg(aw882xx, &set_table); + + aw_dev_dbg(aw882xx->dev, "%s: set_ipeak = 0x%x, set_gain = 0x%x, set_vmax = 0x%x\n", + __func__, set_table.ipeak, set_table.gain, set_table.vmax); + + aw882xx_monitor_set_ipeak(aw882xx, set_table.ipeak); + + aw882xx_monitor_set_gain(aw882xx, set_table.gain); + + aw882xx_monitor_set_vmax(aw882xx, set_table.vmax); + + monitor->samp_count = 0; + + if (monitor->first_entry == AW_FIRST_ENTRY) + monitor->first_entry = AW_NOT_FIRST_ENTRY; + + return 0; +} + +static int aw882xx_get_hmute(struct aw882xx *aw882xx) +{ + unsigned int reg_val = 0; + int ret; + + aw_dev_dbg(aw882xx->dev, "%s: enter\n", __func__); + + aw882xx_i2c_read(aw882xx, AW882XX_SYSCTRL2_REG, ®_val); + if ((~AW882XX_HMUTE_MASK) & reg_val) + ret = 1; + else + ret = 0; + + return ret; +} + +static void aw882xx_monitor_work_func(struct work_struct *work) +{ + struct aw882xx *aw882xx = container_of(work, + struct aw882xx, monitor.delay_work.work); + struct aw_monitor_cfg *monitor_cfg = aw882xx->monitor.monitor_cfg; + + aw_dev_dbg(aw882xx->dev, "%s: monitor is_enable %d,scene_mode %d,monitor_status:%d, monitor_switch:%d\n", + __func__, aw882xx->monitor.is_enable, aw882xx->scene_mode, + monitor_cfg->monitor_status, monitor_cfg->monitor_switch); + + if (aw882xx->monitor.is_enable && + (aw882xx->scene_mode == AW882XX_SPEAKER_MODE) && + (monitor_cfg->monitor_status == AW_MON_CFG_OK) && + monitor_cfg->monitor_switch) { + if (!aw882xx_get_hmute(aw882xx)) { + aw882xx_monitor_work(aw882xx); + schedule_delayed_work(&aw882xx->monitor.delay_work, + msecs_to_jiffies(monitor_cfg->monitor_time)); + } + } +} + +void aw882xx_monitor_start(struct aw882xx_monitor *monitor) +{ + struct aw882xx *aw882xx = container_of(monitor, + struct aw882xx, monitor); + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + monitor->first_entry = AW_FIRST_ENTRY; + monitor->samp_count = 0; + monitor->vol_trace.sum_val = 0; + monitor->temp_trace.sum_val = 0; + aw882xx->monitor.pre_vmax = 0; + + schedule_delayed_work(&aw882xx->monitor.delay_work, + msecs_to_jiffies(0)); +} + +void aw882xx_monitor_stop(struct aw882xx_monitor *monitor) +{ + struct aw882xx *aw882xx = container_of(monitor, + struct aw882xx, monitor); + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + cancel_delayed_work_sync(&aw882xx->monitor.delay_work); +} + + +/***************************************************** + * load monitor config + *****************************************************/ +static int aw_check_monitor_profile(struct aw882xx *aw882xx, + struct aw882xx_container *cont) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)cont->data; + int temp_size, vol_size; + + if (cont->len < sizeof(struct aw_monitor_hdr)) { + aw_dev_err(aw882xx->dev, + "%s:params size[%d] < struct aw_monitor_hdr size[%d]!\n", + __func__, cont->len, + (int)sizeof(struct aw_monitor_hdr)); + return -ENOMEM; + } + + if (monitor_hdr->temp_offset > cont->len) { + aw_dev_err(aw882xx->dev, + "%s:temp_offset[%d] overflow file size[%d]!\n", + __func__, monitor_hdr->temp_offset, cont->len); + return -ENOMEM; + } + + if (monitor_hdr->vol_offset > cont->len) { + aw_dev_err(aw882xx->dev, + "%s:vol_offset[%d] overflow file size[%d]!\n", + __func__, monitor_hdr->vol_offset, cont->len); + return -ENOMEM; + } + + temp_size = monitor_hdr->temp_num * monitor_hdr->single_temp_size; + if (temp_size > cont->len) { + aw_dev_err(aw882xx->dev, + "%s:temp_size:[%d] overflow file size[%d]!!\n", + __func__, temp_size, cont->len); + return -ENOMEM; + } + + vol_size = monitor_hdr->vol_num * monitor_hdr->single_vol_size; + if (vol_size > cont->len) { + aw_dev_err(aw882xx->dev, + "%s:vol_size:[%d] overflow file size[%d]!\n", + __func__, vol_size, cont->len); + return -ENOMEM; + } + + return 0; +} + +static void aw_parse_monitor_hdr(struct aw882xx *aw882xx, + struct aw882xx_container *cont) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)cont->data; + struct aw_monitor_cfg *monitor_cfg = aw882xx->monitor.monitor_cfg; + + monitor_cfg->monitor_switch = monitor_hdr->monitor_switch; + monitor_cfg->monitor_time = monitor_hdr->monitor_time; + monitor_cfg->monitor_count = monitor_hdr->monitor_count; + monitor_cfg->ipeak_switch = monitor_hdr->ipeak_switch; + monitor_cfg->gain_switch = monitor_hdr->gain_switch; + monitor_cfg->vmax_switch = monitor_hdr->vmax_switch; + monitor_cfg->temp_switch = monitor_hdr->temp_switch; + monitor_cfg->temp_aplha = monitor_hdr->temp_aplha; + monitor_cfg->vol_switch = monitor_hdr->vol_switch; + monitor_cfg->vol_aplha = monitor_hdr->vol_aplha; + + aw_dev_info(aw882xx->dev, "%s: chip name:%s\n", + __func__, monitor_hdr->chip_type); + aw_dev_info(aw882xx->dev, "%s: ui ver:0x%x\n", + __func__, monitor_hdr->ui_ver); + + aw_dev_info(aw882xx->dev, + "%s:monitor_switch:%d, monitor_time:%d (ms), monitor_count:%d\n", + __func__, monitor_cfg->monitor_switch, + monitor_cfg->monitor_time, monitor_cfg->monitor_count); + + aw_dev_info(aw882xx->dev, + "%s:ipeak_switch:%d, gain_switch:%d, vmax_switch:%d\n", + __func__, monitor_cfg->ipeak_switch, + monitor_cfg->gain_switch, monitor_cfg->vmax_switch); + + aw_dev_info(aw882xx->dev, + "%s:temp_switch:%d, temp_aplha:%d, vol_switch:%d, vol_aplha:%d\n", + __func__, monitor_cfg->temp_switch, + monitor_cfg->temp_aplha, monitor_cfg->vol_switch, + monitor_cfg->vol_aplha); +} + +static void aw_populate_data_to_table(struct aw882xx *aw882xx, + struct aw_table_info *table_info, const char *offset_ptr) +{ + int i; + + for (i = 0; i < table_info->table_num * AW_TABLE_SIZE; i += AW_TABLE_SIZE) { + table_info->aw_table[i / AW_TABLE_SIZE].min_val = + GET_16_DATA(offset_ptr[1 + i], offset_ptr[i]); + table_info->aw_table[i / AW_TABLE_SIZE].max_val = + GET_16_DATA(offset_ptr[3 + i], offset_ptr[2 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].ipeak = + GET_16_DATA(offset_ptr[5 + i], offset_ptr[4 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].gain = + GET_16_DATA(offset_ptr[7 + i], offset_ptr[6 + i]); + table_info->aw_table[i / AW_TABLE_SIZE].vmax = + GET_32_DATA(offset_ptr[11 + i], offset_ptr[10 + i], + offset_ptr[9 + i], offset_ptr[8 + i]); + } + + for (i = 0; i < table_info->table_num; i++) + aw_dev_info(aw882xx->dev, + "min_val:%d, max_val:%d, ipeak:0x%x, gain:0x%x, vmax:0x%x\n", + table_info->aw_table[i].min_val, + table_info->aw_table[i].max_val, + table_info->aw_table[i].ipeak, + table_info->aw_table[i].gain, + table_info->aw_table[i].vmax); + +} + +static int aw_parse_temp_data(struct aw882xx *aw882xx, + struct aw882xx_container *cont) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)cont->data; + struct aw_table_info *temp_info = + &aw882xx->monitor.monitor_cfg->temp_info; + + aw_dev_info(aw882xx->dev, "%s: ===parse temp start ===\n", + __func__); + + if (temp_info->aw_table != NULL) { + kfree(temp_info->aw_table); + temp_info->aw_table = NULL; + } + + temp_info->aw_table = kzalloc((monitor_hdr->temp_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (!temp_info->aw_table) + return -ENOMEM; + + temp_info->table_num = monitor_hdr->temp_num; + aw_populate_data_to_table(aw882xx, temp_info, + &cont->data[monitor_hdr->temp_offset]); + aw_dev_info(aw882xx->dev, "%s: ===parse temp end ===\n", + __func__); + return 0; +} + +static int aw_parse_vol_data(struct aw882xx *aw882xx, + struct aw882xx_container *cont) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)cont->data; + struct aw_table_info *vol_info = + &aw882xx->monitor.monitor_cfg->vol_info; + + aw_dev_info(aw882xx->dev, "%s: ===parse vol start ===\n", + __func__); + + if (vol_info->aw_table != NULL) { + kfree(vol_info->aw_table); + vol_info->aw_table = NULL; + } + + vol_info->aw_table = kzalloc((monitor_hdr->vol_num * AW_TABLE_SIZE), + GFP_KERNEL); + if (!vol_info->aw_table) + return -ENOMEM; + + vol_info->table_num = monitor_hdr->vol_num; + aw_populate_data_to_table(aw882xx, vol_info, + &cont->data[monitor_hdr->vol_offset]); + aw_dev_info(aw882xx->dev, "%s: ===parse vol end ===\n", + __func__); + return 0; +} + +static int aw_parse_monitor_data(struct aw882xx *aw882xx, + struct aw882xx_container *cont) +{ + int ret; + struct aw_monitor_cfg *monitor_cfg = aw882xx->monitor.monitor_cfg; + + ret = aw_check_monitor_profile(aw882xx, cont); + if (ret < 0) { + aw_dev_err(aw882xx->dev, "%s:check %s failed\n", + __func__, AW_MONITOR_FILE); + return ret; + } + + aw_parse_monitor_hdr(aw882xx, cont); + + ret = aw_parse_temp_data(aw882xx, cont); + if (ret < 0) + return ret; + + ret = aw_parse_vol_data(aw882xx, cont); + if (ret < 0) { + if (monitor_cfg->temp_info.aw_table != NULL) { + kfree(monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + monitor_cfg->temp_info.table_num = 0; + } + return ret; + } + + monitor_cfg->monitor_status = AW_MON_CFG_OK; + return 0; +} + +static int aw_monitor_param_check_sum(struct aw882xx *aw882xx, + struct aw882xx_container *cont) +{ + int i, check_sum = 0; + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)cont->data; + + for (i = 4; i < cont->len; i++) + check_sum += (uint8_t)cont->data[i]; + + if (monitor_hdr->check_sum != check_sum) { + aw_dev_err(aw882xx->dev, "%s:check_sum[%d] is not equal to actual check_sum[%d]\n", + __func__, monitor_hdr->check_sum, check_sum); + return -ENOMEM; + } + + return 0; +} + +static int aw_parse_monitor_profile(struct aw882xx *aw882xx, + struct aw882xx_container *cont) +{ + struct aw_monitor_hdr *monitor_hdr = + (struct aw_monitor_hdr *)cont->data; + int ret; + + ret = aw_monitor_param_check_sum(aw882xx, cont); + if (ret < 0) + return ret; + + switch (monitor_hdr->monitor_ver) { + case AW_MONITOR_HDR_VER_0_1_0: + return aw_parse_monitor_data(aw882xx, cont); + default: + aw_dev_err(aw882xx->dev, "%s:cfg version:0x%x unsupported\n", + __func__, monitor_hdr->monitor_ver); + return -EINVAL; + } +} + +static void aw_monitor_profile_loaded(const struct firmware *cont, + void *context) +{ + struct aw882xx *aw882xx = context; + struct aw882xx_container *monitor_cfg = NULL; + int ret; + + mutex_lock(&g_aw_monitor_lock); + if (aw882xx->monitor.monitor_cfg->monitor_status == AW_MON_CFG_ST) { + if (!cont) { + aw_dev_err(aw882xx->dev, "%s:failed to read %s\n", + __func__, AW_MONITOR_FILE); + goto exit; + } + + aw_dev_info(aw882xx->dev, "%s: loaded %s - size: %zu\n", + __func__, AW_MONITOR_FILE, cont ? cont->size : 0); + + monitor_cfg = kzalloc(cont->size + sizeof(int), GFP_KERNEL); + if (!monitor_cfg) { + aw_dev_err(aw882xx->dev, "%s: error allocating memory\n", __func__); + goto exit; + } + monitor_cfg->len = cont->size; + memcpy(monitor_cfg->data, cont->data, cont->size); + ret = aw_parse_monitor_profile(aw882xx, monitor_cfg); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s:parse monitor cfg failed\n", + __func__); + kfree(monitor_cfg); + monitor_cfg = NULL; + } + +exit: + release_firmware(cont); + mutex_unlock(&g_aw_monitor_lock); +} + +int aw882xx_load_monitor_profile(struct aw882xx_monitor *monitor) +{ + int ret; + struct aw882xx *aw882xx = container_of(monitor, + struct aw882xx, monitor); + + if (!monitor->is_enable) { + aw_dev_info(aw882xx->dev, "%s: monitor flag:%d, monitor bin noload\n", + __func__, monitor->is_enable); + ret = 0; + } else { + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + AW_MONITOR_FILE, + aw882xx->dev, GFP_KERNEL, aw882xx, + aw_monitor_profile_loaded); + } + + return ret; +} + +static void aw882xx_monitor_load_fw_work_func(struct work_struct *work) +{ + struct aw882xx_monitor *monitor = container_of(work, + struct aw882xx_monitor, load_fw_work.work); + + aw882xx_load_monitor_profile(monitor); +} + +void aw882xx_deinit_monitor_profile(struct aw882xx_monitor *monitor) +{ + struct aw_monitor_cfg *monitor_cfg = monitor->monitor_cfg; + + monitor_cfg->monitor_status = AW_MON_CFG_ST; + + if (monitor_cfg->temp_info.aw_table != NULL) { + kfree(monitor_cfg->temp_info.aw_table); + monitor_cfg->temp_info.aw_table = NULL; + } + + if (monitor_cfg->vol_info.aw_table != NULL) { + kfree(monitor_cfg->vol_info.aw_table); + monitor_cfg->vol_info.aw_table = NULL; + } + memset(monitor_cfg, 0, sizeof(struct aw_monitor_cfg)); +} + +#ifdef AW_DEBUG +static ssize_t aw882xx_vol_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + uint32_t vol = 0; + int ret = -1; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &vol); + if (ret < 0) + return ret; + + aw_dev_info(aw882xx->dev, "%s: vol set =%d\n", __func__, vol); + aw882xx->monitor.test_vol = vol; + + return count; +} + +static ssize_t aw882xx_vol_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + uint32_t local_vol = aw882xx->monitor.test_vol; + + len += snprintf(buf+len, PAGE_SIZE-len, + "aw882xx vol: %d\n", local_vol); + return len; +} + +static ssize_t aw882xx_temp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + int32_t temp = 0; + int ret = -1; + + if (count == 0) + return 0; + + ret = kstrtoint(buf, 0, &temp); + if (ret < 0) + return ret; + + aw_dev_info(aw882xx->dev, "%s: temp set =%d\n", __func__, temp); + aw882xx->monitor.test_temp = temp; + + return count; +} + +static ssize_t aw882xx_temp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + int32_t local_temp = aw882xx->monitor.test_temp; + + len += snprintf(buf+len, PAGE_SIZE-len, + "aw882xx temp: %d\n", local_temp); + return len; +} + +static DEVICE_ATTR(vol, S_IWUSR | S_IRUGO, + aw882xx_vol_show, aw882xx_vol_store); +static DEVICE_ATTR(temp, S_IWUSR | S_IRUGO, + aw882xx_temp_show, aw882xx_temp_store); +#endif + +static ssize_t aw882xx_monitor_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + uint32_t enable = 0; + int ret = -1; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &enable); + if (ret < 0) + return ret; + + aw_dev_info(aw882xx->dev, "%s:monitor enable set =%d\n", + __func__, enable); + aw882xx->monitor.is_enable = enable; + if (enable) + schedule_delayed_work(&aw882xx->monitor.delay_work, + msecs_to_jiffies(0)); + + return count; +} + +static ssize_t aw882xx_monitor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + ssize_t len = 0; + uint32_t local_enable; + + local_enable = aw882xx->monitor.is_enable; + len += snprintf(buf+len, PAGE_SIZE-len, + "aw882xx monitor enable: %d\n", local_enable); + return len; +} + +static ssize_t aw_monitor_update_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw882xx *aw882xx = dev_get_drvdata(dev); + struct list_head *list; + struct aw882xx_monitor *aw_monitor = NULL; + uint32_t update = 0; + int ret = -1; + + if (count == 0) + return 0; + + ret = kstrtouint(buf, 0, &update); + if (ret < 0) + return ret; + + aw_dev_info(aw882xx->dev, "%s:monitor update = %d\n", + __func__, update); + + if (update) { + /*stop all monitor*/ + list_for_each(list, &g_aw_monitor_list) { + aw_monitor = container_of(list, + struct aw882xx_monitor, list); + aw882xx_monitor_stop(aw_monitor); + } + + aw882xx_deinit_monitor_profile(&aw882xx->monitor); + aw882xx_load_monitor_profile(&aw882xx->monitor); + msleep(50); + /*start all monitor*/ + list_for_each(list, &g_aw_monitor_list) { + aw_monitor = container_of(list, + struct aw882xx_monitor, list); + aw882xx_monitor_start(aw_monitor); + } + } + + return count; +} + +static DEVICE_ATTR(monitor, S_IWUSR | S_IRUGO, + aw882xx_monitor_show, aw882xx_monitor_store); +static DEVICE_ATTR(monitor_update, S_IWUSR, + NULL, aw_monitor_update_store); + + +static struct attribute *aw882xx_monitor_attr[] = { + &dev_attr_monitor.attr, + &dev_attr_monitor_update.attr, +#ifdef AW_DEBUG + &dev_attr_vol.attr, + &dev_attr_temp.attr, +#endif + NULL +}; + +static struct attribute_group aw882xx_monitor_attr_group = { + .attrs = aw882xx_monitor_attr, +}; + +void aw882xx_monitor_init(struct aw882xx_monitor *monitor) +{ + int ret; + struct aw882xx *aw882xx = container_of(monitor, + struct aw882xx, monitor); + + aw_dev_info(aw882xx->dev, "%s: enter\n", __func__); + +#ifdef AW_DEBUG + monitor->test_vol = 0; + monitor->test_temp = 0; +#endif + + mutex_lock(&g_aw_monitor_lock); + if (g_monitor_dev_num == 0) + memset(&g_monitor_cfg, 0, sizeof(struct aw_monitor_cfg)); + monitor->monitor_cfg = &g_monitor_cfg; + g_monitor_dev_num++; + mutex_unlock(&g_aw_monitor_lock); + + INIT_LIST_HEAD(&monitor->list); + list_add(&monitor->list, &g_aw_monitor_list); + + INIT_DELAYED_WORK(&monitor->delay_work, aw882xx_monitor_work_func); + INIT_DELAYED_WORK(&monitor->load_fw_work, aw882xx_monitor_load_fw_work_func); + + + ret = sysfs_create_group(&aw882xx->dev->kobj, + &aw882xx_monitor_attr_group); + if (ret < 0) + aw_dev_err(aw882xx->dev, "%s error creating sysfs attr files\n", + __func__); +} + +void aw882xx_monitor_deinit(struct aw882xx_monitor *monitor) +{ + struct aw882xx *aw882xx = container_of(monitor, + struct aw882xx, monitor); + + mutex_lock(&g_aw_monitor_lock); + aw882xx_monitor_stop(monitor); + g_monitor_dev_num--; + if (g_monitor_dev_num == 0) + aw882xx_deinit_monitor_profile(monitor); + mutex_unlock(&g_aw_monitor_lock); + + sysfs_remove_group(&aw882xx->dev->kobj, &aw882xx_monitor_attr_group); +} + +/***************************************************** + * device tree parse monitor param + *****************************************************/ +void aw882xx_parse_monitor_dt(struct aw882xx_monitor *monitor) +{ + int ret; + struct aw882xx *aw882xx = container_of(monitor, + struct aw882xx, monitor); + struct device_node *np = aw882xx->dev->of_node; + + ret = of_property_read_u32(np, "monitor-flag", &monitor->is_enable); + if (ret) { + monitor->is_enable = AW882XX_MONITOR_DEFAULT_FLAG; + aw_dev_info(aw882xx->dev, + "%s: monitor-flag get failed ,user default value!\n", + __func__); + } else { + aw_dev_info(aw882xx->dev, "%s: monitor-flag = %d\n", + __func__, monitor->is_enable); + } +} diff --git a/sound/soc/codecs/aw882xx/awinic_monitor.h b/sound/soc/codecs/aw882xx/awinic_monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..09fc1d3a37bd78886f10b5362c3056b33dec40fc --- /dev/null +++ b/sound/soc/codecs/aw882xx/awinic_monitor.h @@ -0,0 +1,136 @@ +#ifndef __AWINIC_MONITOR_H__ +#define __AWINIC_MONITOR_H__ + +/*#define AW_DEBUG*/ + +struct aw_table; + +#define AW_TABLE_SIZE sizeof(struct aw_table) +#define AW882XX_MONITOR_DEFAULT_FLAG (0) +#define AW882XX_MONITOR_VBAT_RANGE (6025) +#define AW882XX_MONITOR_INT_10BIT (1023) +#define AW882XX_MONITOR_TEMP_SIGN_MASK (1<<9) +#define AW882XX_MONITOR_TEMP_NEG_MASK (0XFC00) +#define AW882XX_BIT_SYSCTRL2_BST_IPEAK_MASK (15<<0) +#define AW882XX_BIT_HAGCCFG4_GAIN_SHIFT (8) +#define AW882XX_BIT_HAGCCFG4_GAIN_MASK (0x00ff) +#define IPEAK_NONE (0xFF) +#define GAIN_NONE (0xFF) +#define VMAX_NONE (0xFFFFFFFF) +#define GET_DB_INT(x) (x / 2) +#define GET_DB_DECIMAL(x) ((x % 2) * 5) +#define AW_LOAD_MON_FW_DELAY_TIME (3000) + + +#define GET_32_DATA(w, x, y, z) \ + ((uint32_t)((((uint8_t)w) << 24) | (((uint8_t)x) << 16) | (((uint8_t)y) << 8) | ((uint8_t)z))) +#define GET_16_DATA(x, y) \ + ((uint16_t)((((uint8_t)x) << 8) | (uint8_t)y)) + + +enum aw_monitor_hdr_ver { + AW_MONITOR_HDR_VER_0_1_0 = 0x00010000, +}; + +enum { + AW_FIRST_ENTRY = 0, + AW_NOT_FIRST_ENTRY = 1, +}; + +struct aw_table { + int16_t min_val; + int16_t max_val; + uint16_t ipeak; + uint16_t gain; + uint32_t vmax; +}; + +struct aw_table_info { + uint8_t table_num; + struct aw_table *aw_table; +}; + + +enum aw_monitor_init { + AW_MON_CFG_ST = 0, + AW_MON_CFG_OK = 1, +}; + +struct aw_monitor_cfg { + uint8_t monitor_status; + uint32_t monitor_switch; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t temp_switch; + uint32_t temp_aplha; + uint32_t vol_switch; + uint32_t vol_aplha; + uint32_t ipeak_switch; + uint32_t gain_switch; + uint32_t vmax_switch; + struct aw_table_info temp_info; + struct aw_table_info vol_info; +}; + +struct aw_monitor_hdr { + uint32_t check_sum; + uint32_t monitor_ver; + char chip_type[8]; + uint32_t ui_ver; + uint32_t monitor_switch; + uint32_t monitor_time; + uint32_t monitor_count; + uint32_t ipeak_switch; + uint32_t gain_switch; + uint32_t vmax_switch; + uint32_t temp_switch; + uint32_t temp_aplha; + uint32_t temp_num; + uint32_t single_temp_size; + uint32_t temp_offset; + uint32_t vol_switch; + uint32_t vol_aplha; + uint32_t vol_num; + uint32_t single_vol_size; + uint32_t vol_offset; +}; + +struct aw_monitor_trace { + int32_t pre_val; + int32_t sum_val; + struct aw_table aw_table; +}; + +/****************************************************************** +* struct aw882xx monitor +*******************************************************************/ +struct aw882xx_monitor { + struct delayed_work delay_work; + struct delayed_work load_fw_work; + struct aw_monitor_cfg *monitor_cfg; + struct list_head list; + uint32_t is_enable; + uint8_t first_entry; + uint8_t samp_count; + uint32_t pre_vmax; + + struct aw_monitor_trace temp_trace; + struct aw_monitor_trace vol_trace; +#ifdef AW_DEBUG + uint16_t test_vol; + int16_t test_temp; +#endif +}; + +/****************************************************************** +* aw882xx monitor functions +*******************************************************************/ +void aw882xx_monitor_start(struct aw882xx_monitor *monitor); +void aw882xx_monitor_stop(struct aw882xx_monitor *monitor); +void aw882xx_parse_monitor_dt(struct aw882xx_monitor *monitor); +void aw882xx_monitor_init(struct aw882xx_monitor *monitor); +void aw882xx_monitor_deinit(struct aw882xx_monitor *monitor); + + + +#endif