From 97faaa82e2c85d4fd7ee2e84f0a2566857abdc26 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Fri, 19 Sep 2025 09:47:45 +0800 Subject: [PATCH] iio: proximity: add nds03 tof sensor Change-Id: I263bc2a7cc302ded8c940a10f73e050abdefa1de Signed-off-by: Jianwei Fan --- drivers/iio/proximity/Kconfig | 2 + drivers/iio/proximity/Makefile | 1 + drivers/iio/proximity/nds03/Kconfig | 7 + drivers/iio/proximity/nds03/Makefile | 9 + drivers/iio/proximity/nds03/nds03.h | 104 +++ drivers/iio/proximity/nds03/nds03_calib.c | 275 +++++++ drivers/iio/proximity/nds03/nds03_calib.h | 42 + drivers/iio/proximity/nds03/nds03_comm.c | 385 +++++++++ drivers/iio/proximity/nds03/nds03_comm.h | 71 ++ drivers/iio/proximity/nds03/nds03_data.c | 238 ++++++ drivers/iio/proximity/nds03/nds03_data.h | 46 ++ drivers/iio/proximity/nds03/nds03_def.h | 308 ++++++++ drivers/iio/proximity/nds03/nds03_dev.c | 743 ++++++++++++++++++ drivers/iio/proximity/nds03/nds03_dev.h | 94 +++ drivers/iio/proximity/nds03/nds03_iio.c | 235 ++++++ drivers/iio/proximity/nds03/nds03_iio.h | 31 + drivers/iio/proximity/nds03/nds03_module.c | 674 ++++++++++++++++ .../iio/proximity/nds03/nds03_module_i2c.c | 99 +++ drivers/iio/proximity/nds03/nds03_platform.c | 117 +++ drivers/iio/proximity/nds03/nds03_platform.h | 137 ++++ drivers/iio/proximity/nds03/nds03_stdint.h | 95 +++ 21 files changed, 3713 insertions(+) create mode 100644 drivers/iio/proximity/nds03/Kconfig create mode 100644 drivers/iio/proximity/nds03/Makefile create mode 100644 drivers/iio/proximity/nds03/nds03.h create mode 100644 drivers/iio/proximity/nds03/nds03_calib.c create mode 100644 drivers/iio/proximity/nds03/nds03_calib.h create mode 100644 drivers/iio/proximity/nds03/nds03_comm.c create mode 100644 drivers/iio/proximity/nds03/nds03_comm.h create mode 100644 drivers/iio/proximity/nds03/nds03_data.c create mode 100644 drivers/iio/proximity/nds03/nds03_data.h create mode 100644 drivers/iio/proximity/nds03/nds03_def.h create mode 100644 drivers/iio/proximity/nds03/nds03_dev.c create mode 100644 drivers/iio/proximity/nds03/nds03_dev.h create mode 100644 drivers/iio/proximity/nds03/nds03_iio.c create mode 100644 drivers/iio/proximity/nds03/nds03_iio.h create mode 100644 drivers/iio/proximity/nds03/nds03_module.c create mode 100644 drivers/iio/proximity/nds03/nds03_module_i2c.c create mode 100644 drivers/iio/proximity/nds03/nds03_platform.c create mode 100644 drivers/iio/proximity/nds03/nds03_platform.h create mode 100644 drivers/iio/proximity/nds03/nds03_stdint.h diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index e5d8fbdcc254..f2fb15eeaf7e 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -32,6 +32,8 @@ config CROS_EC_MKBP_PROXIMITY To compile this driver as a module, choose M here: the module will be called cros_ec_mkbp_proximity. +source "drivers/iio/proximity/nds03/Kconfig" + config ISL29501 tristate "Intersil ISL29501 Time Of Flight sensor" depends on I2C diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index cc838bb5408a..ae0028d6729a 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_AS3935) += as3935.o obj-$(CONFIG_CROS_EC_MKBP_PROXIMITY) += cros_ec_mkbp_proximity.o +obj-$(CONFIG_DTOF_NDS03) += nds03/ obj-$(CONFIG_ISL29501) += isl29501.o obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o obj-$(CONFIG_MB1232) += mb1232.o diff --git a/drivers/iio/proximity/nds03/Kconfig b/drivers/iio/proximity/nds03/Kconfig new file mode 100644 index 000000000000..da8d3c8c258c --- /dev/null +++ b/drivers/iio/proximity/nds03/Kconfig @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config DTOF_NDS03 + tristate "NDS03 I2C DEVICE" + depends on I2C && SYSFS + help + Using I2C diff --git a/drivers/iio/proximity/nds03/Makefile b/drivers/iio/proximity/nds03/Makefile new file mode 100644 index 000000000000..5f23d3d56d41 --- /dev/null +++ b/drivers/iio/proximity/nds03/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for the nds03 drivers. +# + +obj-$(CONFIG_DTOF_NDS03) += nds03.o +nds03-y += nds03_module.o nds03_platform.o nds03_module_i2c.o nds03_iio.o \ + nds03_dev.o nds03_data.o \ + nds03_comm.o nds03_calib.o diff --git a/drivers/iio/proximity/nds03/nds03.h b/drivers/iio/proximity/nds03/nds03.h new file mode 100644 index 000000000000..ef789ed72047 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03.h @@ -0,0 +1,104 @@ +/*! + @file nds03.h + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#ifndef __NDS03_H +#define __NDS03_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* nds03 sdk */ +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" +#include "nds03_calib.h" +#include "nds03_def.h" + +#define TOF_NDS03_DRV_NAME "tof_nds03" +#define DRIVER_VERSION "1.0.4" +#define TOF_NDS03_MAJOR 255 +#define MAX_POS_BITS 32 + +/*! use debug */ +extern int nds03_enable_debug; + +#define nds03_dbgmsg(str, ...) \ + do { \ + if (nds03_enable_debug > 0) \ + printk("%s: " str, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + + +#define nds03_info(str, ...) \ + pr_info("%s: " str , __FUNCTION__, ##__VA_ARGS__) + +#define nds03_errmsg(str, ...) \ + pr_err("%s: " str, __FUNCTION__, ##__VA_ARGS__) + +#define nds03_warnmsg(str, ...) \ + pr_warn("%s: " str,__FUNCTION__, ##__VA_ARGS__) + +struct nds03_context { + + /*!< multiple device id 0 based*/ + int id; + + /*!< misc device name */ + char name[64]; + + struct i2c_client * client; + + /*!< nds03 device info */ + NDS03_Dev_t g_nds03_device; + + /*!< main dev mutex/lock */ + struct mutex work_mutex; + + // /*!< work for pseudo irq polling check */ + struct delayed_work dwork; + struct work_struct irq_work; + // /*!< input device used for sending event */ + struct input_dev *idev; + + /*!< intr gpio number */ + int irq; + + bool remove_flag; + /// /* user control configuration parameter */ + /*!< measure mode irq or poll*/ + atomic_t meas_mode; + /*!< rescheduled time use in poll mode */ + atomic_t poll_delay_ms; + /*!< use ctrl measure state */ + atomic_t is_meas; + /*!< calibtion result of the deivce */ + int calib_result; + /*!< open input file descriptor count*/ + int fd_open_count; + struct iio_dev *indio_dev; + struct nds03_iio_dev *iio; +}; + +int nds03_common_probe(struct nds03_context * ctx); +int nds03_common_remove(struct nds03_context * ctx); +int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open); +int nds03_sensor_init(struct nds03_context *ctx); + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_calib.c b/drivers/iio/proximity/nds03/nds03_calib.c new file mode 100644 index 000000000000..ea47934653af --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_calib.c @@ -0,0 +1,275 @@ +/** + * @file nds03_calib.c + * @author tongsheng.tang + * @brief NDS03 Calibration functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" +#include "nds03_calib.h" + +/** + * @brief NDS03 Get Offset Calib Depth MM + * 获取offset标定距离 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm)); + + return ret; +} + +/** + * @brief NDS03 Set Offset Calib Depth MM + * 设置offset标定距离 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (calib_depth_mm == 0) + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, &calib_depth_mm)); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_OFFSET_MM, calib_depth_mm)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Offset Calibration Check + * Offset 标定检查 + * @param pNxDevice + * @param calib_depth_mm + * @return NDS03_Error + */ +static NDS03_Error NDS03_OffsetCalibrationCheck(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ref_histo_max, depth[2]; + uint8_t depth_flag; + + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max)); + if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) { + ret = NDS03_ERROR_VCSEL_ERROR; + NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max); + return ret; + } + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DEPTH_FLAG, &depth_flag)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 1)); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + depth[0] = pNxDevice->ranging_data[0].depth; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, 2)); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + depth[1] = pNxDevice->ranging_data[0].depth; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEPTH_FLAG, depth_flag)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + if (ret == NDS03_ERROR_NONE && ((depth[0] + NDS03_OFFSET_DEPTH_ERROR_TH < depth[1]) || + (depth[0] > depth[1] + NDS03_OFFSET_DEPTH_ERROR_TH) || + depth[0] == NDS03_DEPTH_INVALID_VALUE || depth[1] == NDS03_DEPTH_INVALID_VALUE)) { + ret = NDS03_ERROR_OFFSET_ERROR; + NX_PRINTF("depth[0]:%d depth[1]:%d\r\n", depth[0], depth[1]); + } + return ret; +} + +/** + * @brief ToF Offset 标定 + * @details 不可以指定标定距离,使用默认距离,如果没有修改,那值默认是500mm + * + * @param pNxDevice 设备模组 + * @return int8_t + * @retval 0: 成功 + * @retval !0: Offset标定失败 + */ +NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ambient_bg; + + NX_PRINTF("%s Start!\r\n", __func__); + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + if (ambient_bg > NDS03_AMBIENT_TH) { + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient_bg:%d\r\n", ambient_bg); + return ret; + } + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret)); + CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice)); + + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief ToF Offset 标定 + * @details 可以指定标定距离 + * + * @param pNxDevice 设备模组 + * @param calib_depth_mm 标定距离 + * @return int8_t + * @retval 0: 成功 + * @retval !0: Offset标定失败 + */ +NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t ambient_bg; + + NX_PRINTF("%s Start!\r\n", __func__); + + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + if (ambient_bg > NDS03_AMBIENT_TH){ + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient:%d \r\n", ambient_bg); + return ret; + } + CHECK_RET(NDS03_SetOffsetCalibDepthMM(pNxDevice, calib_depth_mm)); + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_OFFSET_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_OFFSET_CALIB, 10000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&ret)); + CHECK_RET(NDS03_OffsetCalibrationCheck(pNxDevice)); + + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Read Xtalk Data + * 读取NDS03串扰数据 + * @param pNxDevice 模组设备 + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +static NDS03_Error NDS03_ReadXtalkData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + uint16_t addr; + uint16_t rbuf[240]; + uint8_t *rbuf_ptr = (uint8_t *)rbuf; + uint32_t size = 240 * 2; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, 0xEC, &addr)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, rbuf_ptr, + ((size-rsize)>_size) ? _size:(size-rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf_ptr += _size; + addr += _size; + rsize += _size; + } + for (int i = 80; i < 240; i++) { + if (rbuf[i] > 10000) + return -14; + } + + return ret; +} + +/** + * @brief NDS03 Xtalk Calibration + * NDS03串扰/盖板标定 + * @param pNxDevice 设备模组 + * @return int8_t + * @retval 0: 成功 + * @retval !0: xtalk标定失败 + */ +NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE, calib_state = NDS03_ERROR_NONE; + uint16_t ambient_bg,ref_histo_max; + uint8_t cnt = 2; + int8_t check_xtalk_state = 0; + + NX_PRINTF("%s Start!\r\n", __func__); + do { + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_AMBIENT, &ambient_bg)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_REF_HISTO_MAX, &ref_histo_max)); + if (ambient_bg > NDS03_AMBIENT_TH) { + ret = NDS03_ERROR_AMBIENT_HIGH; + NX_PRINTF("ambient:%d\r\n", ambient_bg); + return ret; + } + if (ret == NDS03_ERROR_NONE && ref_histo_max < NDS03_OFFSET_REF_MAX_COUNT_TH) { + ret = NDS03_ERROR_VCSEL_ERROR; + NX_PRINTF("ref_histo_max:%d\r\n", ref_histo_max); + return ret; + } + // 打开使能 + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, NDS03_CMD_XTALK_CALIB)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_XTALK_CALIB, 5000)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice)); + if (pNxDevice->chip_info.fw_version == 0x10203) { + CHECK_RET(NDS03_GetSingleRangingData(pNxDevice)); + check_xtalk_state = NDS03_ReadXtalkData(pNxDevice); + } + + } while (cnt-- && check_xtalk_state != 0); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CALIB_STATE, (uint8_t*)&calib_state)); + ret = check_xtalk_state ? check_xtalk_state : (ret | calib_state) & + (NDS03_CALIB_ERROR_XTALK_OVERFLOW | NDS03_CALIB_ERROR_XTALK_EXCESSIVE); + NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Get Xtalk Value + * 获取标定串扰值 + * @param pNxDevice + * @return NDS03_Error + */ +NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_XTALK, xtalk_value)); + + return ret; +} diff --git a/drivers/iio/proximity/nds03/nds03_calib.h b/drivers/iio/proximity/nds03/nds03_calib.h new file mode 100644 index 000000000000..453047f36124 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_calib.h @@ -0,0 +1,42 @@ +/** + * @file nds03_calib.h + * @author tongsheng.tang + * @brief NDS03 Calibration functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ + +#ifndef __NDS03_CALIB_H__ +#define __NDS03_CALIB_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Calibration_Group NDS03 Calibration Functions + * @brief NDS03 Calibration Functions + * @{ + */ + +/** 获取offset标定距离 */ +NDS03_Error NDS03_GetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t *calib_depth_mm); +/** 设置offset标定距离 */ +NDS03_Error NDS03_SetOffsetCalibDepthMM(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm); +/** Offset标定函数(无标定距离设置) */ +NDS03_Error NDS03_OffsetCalibration(NDS03_Dev_t *pNxDevice); +/** Offset标定函数(有标定距离设置) */ +NDS03_Error NDS03_OffsetCalibrationAtDepth(NDS03_Dev_t *pNxDevice, uint16_t calib_depth_mm); +/** XTalk标定 */ +NDS03_Error NDS03_XtalkCalibration(NDS03_Dev_t *pNxDevice); +/** 获取标定串扰值 */ +NDS03_Error NDS03_GetXTalkValue(NDS03_Dev_t *pNxDevice, uint16_t* xtalk_value); + +/** @} NDS03_Calibration_Group */ + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_comm.c b/drivers/iio/proximity/nds03/nds03_comm.c new file mode 100644 index 000000000000..1b94a4d77c19 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_comm.c @@ -0,0 +1,385 @@ +/** + * @file nds03_comm.c + * @author tongsheng.tang + * @brief NDS03 communication functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_stdint.h" +#if NDS03_PLATFORM != PLATFORM_LINUX_DRIVER +#include +#include +#else +#include +#endif +#include "nds03_dev.h" +#include "nds03_comm.h" +#include "nds03_def.h" +#include "nds03_platform.h" + +/** + * @brief NDS03 Delay 1ms + * @param ms 延时时间 + * @return void + */ +NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms) +{ + return nds03_delay_1ms(&pNxDevice->platform, ms); +} + +/** + * @brief NDS03 Delay 10us + * @param us 延时时间 + * @return void + */ +NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us) +{ + return nds03_delay_10us(&pNxDevice->platform, us); +} + +/** + * @brief NDS03 Get System Clk Ms +* @param pNxDevice 模组设备 + * @param time_ms 获取时间(ms) + * @return void + */ +NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_get_system_clk_ms(&pNxDevice->platform, time_ms); + + return ret; +} + +/** + * @brief NDS03 Set XShut Pin Level + * 设置xshut引脚的电平 + * @param pNxDevice 模组设备 + * @param level xshut引脚电平,0为低电平,1为高电平 + * @return void + */ +NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level) +{ + return nds03_set_xshut_pin_level(&pNxDevice->platform, level); +} + +/** + * @brief 获取当前i2c时钟频率 + * + * @param pNxDevice 模组设备 + * @param freq 获取的频率 + * @return + */ +NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq) +{ + return nds03_i2c_get_clock_frequency(&pNxDevice->platform, freq); +} + +/** + * @brief 设置当前i2c时钟频率 + * + * @param pNxDevice 模组设备 + * @param freq 设置的频率 + * @return + */ +NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq) +{ + return nds03_i2c_set_clock_frequency(&pNxDevice->platform, freq); +} + +/** + * @brief 半字,即2个字节,调换数据格式 + * 小端无影响,大端会调换数据格式 + * @param buf 数据缓冲区 + * @param buf_num 数据个数 + */ +static void NDS03_HalfWordDataFmtChange(uint16_t *buf, uint16_t buf_num) +{ + uint16_t tmp; + uint8_t *pu8buf = (uint8_t*)buf; + uint16_t i; + + for (i = 0; i < buf_num; i++) { + tmp = buf[i]; + *pu8buf++ = (tmp >> 0); + *pu8buf++ = (tmp >> 8); + } +} + +/** + * @brief 1字,即4个字节,调换数据格式 + * 小端无影响,大端会调换数据格式 + * @param buf 数据缓冲区 + * @param buf_num 数据个数 + */ +static void NDS03_WordDataFmtChange(uint32_t *buf, uint16_t buf_num) +{ + uint32_t tmp; + uint8_t *pu8buf = (uint8_t*)buf; + uint16_t i; + + for (i = 0; i < buf_num; i++) { + tmp = buf[i]; + *pu8buf++ = (tmp >> 0); + *pu8buf++ = (tmp >> 8); + *pu8buf++ = (tmp >> 16); + *pu8buf++ = (tmp >> 24); + } +} + +/** + * @brief Write n Words to NDS03 + * 对NDS03的寄存器写N个字 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 存放寄存器值的指针 + * @param len: 写数据的长度,按字个数计算 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + + return ret; +} + +/** + * @brief Read n Words from NDS03 + * 对NDS03的寄存器读N个字 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 存放寄存器值的指针 + * @param len: 读数据的长度,按字个数计算 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + + return ret; +} + +/** + * @brief Write 1 Byte to NDS03 + * 对NDS03的寄存器写1个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, &wdata, 1); + + return ret; +} + +/** + * @brief Read 1 Byte from NDS03 + * 对NDS03的寄存器读1个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, rdata, 1); + + return ret; +} + +/** + * @brief Write N bytes By Half-Word to NDS03 + * 对NDS03的寄存器写N个字节,使用半字写的方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @param size: 写数据的长度,按字节个数计算 + * 注意:size必须是2的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x01) == 0) { + NDS03_HalfWordDataFmtChange(wdata, size / 2); + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + NDS03_HalfWordDataFmtChange(wdata, size / 2); + } + + return ret; +} + +/** + * @brief Read N Bytes By Half-World from NDS03 + * 对NDS03的寄存器读N个字节,使用半字读的方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @param size: 读数据的长度,按字节个数计算 + * 注意:size必须是2的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x01) == 0 && rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + NDS03_HalfWordDataFmtChange(rdata, size / 2); + } + + return ret; +} + +/** + * @brief Write 2 Byte to NDS03 + * 对NDS03的寄存器写2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[2]; + + tmp[0] = (wdata >> 0) & 0xFF; + tmp[1] = (wdata >> 8) & 0xFF; + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + + return ret; +} + +/** + * @brief Read 2 Byte from NDS03 + * 对NDS03的寄存器读2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[2]; + + if (rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + *rdata = (uint16_t)tmp[0] | ((uint16_t)tmp[1] << 8); + } + + return ret; +} + +/** + * @brief Write N Bytes By Word to NDS03 + * 对NDS03的寄存器写N个字节,使用字方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @param size: 写数据的长度,按字节个数计算 + * 注意:size必须是4的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr, + uint32_t *wdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x03) == 0) { + NDS03_WordDataFmtChange(wdata, size / 4); + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, (uint8_t*)wdata, size); + NDS03_WordDataFmtChange(wdata, size / 4); + } + + return ret; +} + +/** + * @brief Read N Bytes By Word from NDS03 + * 对NDS03的寄存器读N个字节,使用字方式 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @param size: 读数据的长度,按字节个数计算 + * 注意:size必须是4的倍数 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata, uint16_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if ((size & 0x03) == 0 && rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, (uint8_t*)rdata, size); + NDS03_WordDataFmtChange(rdata, size / 4); + } + + return ret; +} + +/** + * @brief Write 4 Byte to NDS03 + * 对NDS03的寄存器写2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param wdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[4]; + + tmp[0] = (wdata >> 0) & 0xFF; + tmp[1] = (wdata >> 8) & 0xFF; + tmp[2] = (wdata >> 16) & 0xFF; + tmp[3] = (wdata >> 24) & 0xFF; + ret = nds03_i2c_write_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + + return ret; +} + +/** + * @brief Read 4 Byte from NDS03 + * 对NDS03的寄存器读2个字节 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param addr: 寄存器地址 + * @param rdata: 寄存器的值 + * @return NDS03_Error +*/ +NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t tmp[4]; + + if (rdata != NULL) { + ret = nds03_i2c_read_nbytes(&pNxDevice->platform, addr, tmp, sizeof(tmp)); + *rdata = (uint32_t)tmp[0] | ((uint32_t)tmp[1] << 8) | + ((uint32_t)tmp[2] << 16) | ((uint32_t)tmp[3] << 24); + } + + return ret; +} + diff --git a/drivers/iio/proximity/nds03/nds03_comm.h b/drivers/iio/proximity/nds03/nds03_comm.h new file mode 100644 index 000000000000..43630b61e436 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_comm.h @@ -0,0 +1,71 @@ +/** + * @file nds03_comm.h + * @author tongsheng.tang + * @brief NDS03 communication functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ +#ifndef __NDS03_COMM_H__ +#define __NDS03_COMM_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Communication_Group NDS03 Communication Functions + * @brief NDS03 Communication Functions + * @{ + */ + +/** 延时时间(ms) */ +NDS03_Error NDS03_Delay1ms(NDS03_Dev_t *pNxDevice, uint32_t ms); + +/** 延时时间(10us) */ +NDS03_Error NDS03_Delay10us(NDS03_Dev_t *pNxDevice, uint32_t us); + +/** 设置xshut引脚的电平 */ +NDS03_Error NDS03_SetXShutPinLevel(NDS03_Dev_t *pNxDevice, int8_t level); + +/** NDS03设置i2c频率 */ +NDS03_Error NDS03_SetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t freq); +/** NDS03获取i2c频率 */ +NDS03_Error NDS03_GetI2cFreq(NDS03_Dev_t *pNxDevice, uint32_t *freq); +/** 对NDS03寄存器写N个字节 */ +NDS03_Error NDS03_WriteNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节 */ +NDS03_Error NDS03_ReadNBytes(NDS03_Dev_t *pNxDevice, uint8_t addr, void *rdata, uint16_t size); +/** 对NDS03寄存器写1个字节 */ +NDS03_Error NDS03_WriteByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t wdata); +/** 对NDS03寄存器写1个字节 */ +NDS03_Error NDS03_ReadByte(NDS03_Dev_t *pNxDevice, uint8_t addr, uint8_t *rdata); +/** 对NDS03寄存器写N个字节,使用半字方式 */ +NDS03_Error NDS03_WriteNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节,使用半字方式 */ +NDS03_Error NDS03_ReadNBytesByHalfWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint16_t *rdata, uint16_t size); +/** 对NDS03寄存器写1个字 */ +NDS03_Error NDS03_WriteHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t wdata); +/** 对NDS03寄存器读1个字 */ +NDS03_Error NDS03_ReadHalfWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint16_t *rdata); +/** 对NDS03寄存器写N个字节,使用字方式 */ +NDS03_Error NDS03_WriteNBytesByWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint32_t *wdata, uint16_t size); +/** 对NDS03寄存器读N个字节,使用字方式 */ +NDS03_Error NDS03_ReadNBytesByWord(NDS03_Dev_t *pNxDevice, + uint8_t addr, uint32_t *rdata, uint16_t size); +/** 对NDS03寄存器写1个字 */ +NDS03_Error NDS03_WriteWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t wdata); +/** 对NDS03寄存器读1个字 */ +NDS03_Error NDS03_ReadWord(NDS03_Dev_t *pNxDevice, uint8_t addr, uint32_t *rdata); +/** 获取系统时钟时间(ms) */ +NDS03_Error NDS03_GetSystemClkMs(NDS03_Dev_t *pNxDevice,int32_t *time_ms); + +/** @} NDS03_Communication_Group */ + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_data.c b/drivers/iio/proximity/nds03/nds03_data.c new file mode 100644 index 000000000000..dbc2f1824d3c --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_data.c @@ -0,0 +1,238 @@ + +/** + * @file nds03_data.c + * @author tongsheng.tang + * @brief NDS03 get depth data functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + */ + +#include "nds03_def.h" +#include "nds03_comm.h" +#include "nds03_dev.h" +#include "nds03_data.h" + +/** + * @brief NDS03 Get Ranging Data Ready + * 检测NDS03测距是否完成 + * @param pNxDevice 模组设备 + * @return int8_t + * @retval 函数执行结果 + * - 0:未完成 + * 1: 完成 + * - ::NDS03_ERROR_I2C:IIC通讯错误/数据异常 + */ +NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t buf_valid_flag = 0x00; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &buf_valid_flag)); + + if (buf_valid_flag == NDS03_DEPTH_DATA_FLAG) + return 1; + + return ret; +} + +/** + * @brief NDS03 Start Single Measurement + * 发送开始单次测量信号 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG)); + + return ret; +} + +/** + * @brief NDS03 Start Continuous Measurement + * 发送开始连续测量信号 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (pNxDevice->config.continuous_flag == 0) { + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, + NDS03_REG_DAT_REQ, NDS03_DEPTH_CONTINUOUS_FLAG)); + pNxDevice->config.continuous_flag = 1; + } + + return ret; +} + +/** + * @brief NDS03 Stop Continuous Measurement + * 发送结束连续测量信号,用于连续模式 + * @param pNxDevice 模组设备 + * @return int8_t + */ +NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + if (pNxDevice->config.continuous_flag != 0) { + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DATA_REQ_IDLE)); + /* 等待测量完成 */ + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_CONTINUOUS_FLAG, 200)); + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + pNxDevice->config.continuous_flag = 0; + } + + return ret; +} + +/** + * @brief NDS03 Clear Data Valid Flag + * 清除NDS03测量数据的有效位,取完一次数 + * 据做的操作,通知NDS03数据已读取 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + + return ret; +} + +/** + * @brief NDS03 Read Ranging Data + * 读取NDS03寄存器获取测量数据,数据更新于一次测距完成后 + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + +#if NDS03_TARGET_MAX_NUM == 1 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM == 2 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 2 * sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM == 3 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 3 * sizeof(pNxDevice->ranging_data[0]))); +#endif + +#if NDS03_TARGET_MAX_NUM >= 4 + CHECK_RET(NDS03_ReadNBytesByHalfWord(pNxDevice, + NDS03_REG_DEPTH, (uint16_t*)&pNxDevice->ranging_data[0], + 4 * sizeof(pNxDevice->ranging_data[0]))); +#endif + + return ret; +} + +/** + * @brief NDS03 Get Continuous Ranging Data + * 连续模式下,从NDS03中获取一次深度数据, + * 需要与NDS03_StartContinuousMeasurement函数搭配 + * @param pNxDevice 模组设备 + * @param pData 获取到的深度和幅度数据 + * @return int32_t + */ +NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t data_cnt; + uint32_t retry_cnt = 20000; + + /* 等待测量完成 */ + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &data_cnt)); + CHECK_RET(NDS03_Delay10us(pNxDevice, 10)); + } while (data_cnt == pNxDevice->data_cnt && --retry_cnt); + pNxDevice->data_cnt = data_cnt; + if (retry_cnt != 0) { + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + } else { + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Get Single Ranging Data + * NDS03中获取一次深度数据 + * + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t timeout_ms = pNxDevice->config.range_frame_time_us / 1000; + + /* 清除标志位 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + /* 发送触发信号 */ + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_DEPTH_DATA_FLAG)); + /* 等待测量完成 */ + timeout_ms = (timeout_ms < 200) ? 200 : timeout_ms; + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_DEPTH_DATA_FLAG, timeout_ms)); + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + + return ret; +} + +/** + * @brief NDS03 Get Interrupt Ranging Data + * NDS03中获取一次中断深度数据 + * + * @param pNxDevice 模组设备 + * @return int32_t + */ +NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + /* 读取测量数据 */ + CHECK_RET(NDS03_ReadRangingData(pNxDevice)); + /* 清除数据有效标志位 */ + CHECK_RET(NDS03_ClearDataValidFlag(pNxDevice)); + + return ret; +} + diff --git a/drivers/iio/proximity/nds03/nds03_data.h b/drivers/iio/proximity/nds03/nds03_data.h new file mode 100644 index 000000000000..4475e4c4dbd3 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_data.h @@ -0,0 +1,46 @@ +/** + * @file nds03_data.h + * @author tongsheng.tang + * @brief NDS03 communication and data handling functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ +#ifndef __NDS03_DATA_H__ +#define __NDS03_DATA_H__ + +#include "nds03_def.h" +/** @defgroup NDS03_Data_Group NDS03 Data Functions + * @brief NDS03 Data Functions + * @{ + */ + +/** 检测NDS03测距是否完成 */ +NDS03_Error NDS03_GetRangingDataReady(NDS03_Dev_t *pNxDevice); +/** 发送开始单次测量信号 */ +NDS03_Error NDS03_StartSingleMeasurement(NDS03_Dev_t *pNxDevice); +/** 发送开始连续测量信号 */ +NDS03_Error NDS03_StartContinuousMeasurement(NDS03_Dev_t *pNxDevice); +/** 发送结束连续测量信号 */ +NDS03_Error NDS03_StopContinuousMeasurement(NDS03_Dev_t *pNxDevice); +/** 清除数据有效位 */ +NDS03_Error NDS03_ClearDataValidFlag(NDS03_Dev_t *pNxDevice); +/** 读取深度和幅度值 */ +NDS03_Error NDS03_ReadRangingData(NDS03_Dev_t *pNxDevice); +/** 获取连续测量深度和幅度值 */ +NDS03_Error NDS03_GetContinuousRangingData(NDS03_Dev_t *pNxDevice); +/** 获取一次测量深度和幅度值 */ +NDS03_Error NDS03_GetSingleRangingData(NDS03_Dev_t *pNxDevice); +/** 获取一次中断数据 */ +NDS03_Error NDS03_GetInterruptRangingData(NDS03_Dev_t *pNxDevice); + +/** @} NDS03_Data_Group */ + +#endif // __NDS03_DATA_H__ diff --git a/drivers/iio/proximity/nds03/nds03_def.h b/drivers/iio/proximity/nds03/nds03_def.h new file mode 100644 index 000000000000..047c75ba7929 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_def.h @@ -0,0 +1,308 @@ +/** + * @file nds03_def.h + * @author tongsheng.tang + * @brief NDS03's Macro definition and data structure + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ +#ifndef __NDS03_DEF_H__ +#define __NDS03_DEF_H__ + +#include "nds03_stdint.h" +#if NDS03_PLATFORM == PLATFORM_LINUX_DRIVER +#include +#else +#include +#endif +#include "nds03_platform.h" + +#ifndef DEBUG_INFO +#define DEBUG_INFO 0 /** 调试信息打印开关 */ +#endif + +#if NDS03_PLATFORM == PLATFORM_NOT_C51 +#include +#define NX_PRINTF(fmt, ...) do { if (DEBUG_INFO) printf(fmt, ##__VA_ARGS__); } while(0) + +#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER +#include +#define NX_PRINTF(fmt, args...) do { if (DEBUG_INFO) printk(fmt, ##args); } while(0) + +#elif NDS03_PLATFORM == PLATFORM_C51 +#define NX_PRINTF(fmt, ...) + +#else +#define NX_PRINTF(fmt, ...) +#endif + +/** @defgroup NDS03_Global_Define_Group NDS03 Defines + * @brief NDS03 Defines + * @{ + */ + +/** @defgroup NDS03_Reg_Group NDS03 Register Defines + * @brief NDS03 Register Defines + * @{ + */ +#define NDS03_REG_DEV_ADDR (0x1E) /** 模组的设备地址 */ + +#define NDS03_REG_STATE (0x20) /** 模组运行状态寄存器 */ +#define NDS03_REG_DATA_CNT (0x21) /** 模组测距次数计数值 */ +#define NDS03_REG_FW_VER (0x24) /** 模组固件版本号寄存器 */ + +#define NDS03_REG_RANGE_STATE (0x28) /** 测距状态码 */ +#define NDS03_REG_CALIB_STATE (0x29) /** 标定状态码 */ +#define NDS03_REG_THERM (0x2A) /** 温度值 */ +#define NDS03_REG_AMBIENT (0x2C) /** 环境光值 */ + +#define NDS03_REG_DEPTH (0x30) /** 深度值 */ +#define NDS03_REG_CONFI (0x32) /** 置信度 */ +#define NDS03_REG_COUNT (0x34) /** 计数值 */ +#define NDS03_REG_CRATE (0x36) /** 计数率 */ +#define NDS03_REG_DEPTH2 (0x38) /** 深度值 */ +#define NDS03_REG_CONFI2 (0x3A) /** 置信度 */ +#define NDS03_REG_COUNT2 (0x3C) /** 计数值 */ +#define NDS03_REG_CRATE2 (0x3E) /** 计数率 */ +#define NDS03_REG_DEPTH3 (0x40) /** 深度值 */ +#define NDS03_REG_CONFI3 (0x42) /** 置信度 */ +#define NDS03_REG_COUNT3 (0x44) /** 计数值 */ +#define NDS03_REG_CRATE3 (0x46) /** 计数率 */ +#define NDS03_REG_DEPTH4 (0x48) /** 深度值 */ +#define NDS03_REG_CONFI4 (0x4A) /** 置信度 */ +#define NDS03_REG_COUNT4 (0x4C) /** 计数值 */ +#define NDS03_REG_CRATE4 (0x4E) /** 计数率 */ + +#define NDS03_REG_DAT_REQ (0x50) /** 获取深度请求寄存器 */ +#define NDS03_REG_DAT_VAL (0x51) /** 获取数据命令有效寄存器 */ +#define NDS03_REG_CMD_REQ (0x52) /** 命令请求寄存器 */ +#define NDS03_REG_CMD_VAL (0x53) /** 命令完成寄存器 */ +#define NDS03_REG_CMD_ENA (0x54) /** 命令使能寄存器 */ +#define NDS03_REG_CFG_ENA (0x55) /** 配置使能,该值为0xA5才能访问其他寄存器 */ +#define NDS03_REG_REF_HISTO_MAX (0x56) /** 参考直方图最大值 */ + +#define NDS03_REG_DEPTH_FLAG (0x64) /** 测距结果标志位 */ +#define NDS03_REG_SLEEP_TIME (0x66) /** 睡眠时间(ms) */ +#define NDS03_REG_PULSE_NUM (0x6C) /** 发光次数 */ + +#define NDS03_REG_DEPTH_TH_L (0x70) /** 深度低阈值 */ +#define NDS03_REG_DEPTH_TH_H (0x72) /** 深度高阈值 */ +#define NDS03_REG_GPIO1_FUNC (0x74) /** 中断功能/方式 */ +#define NDS03_REG_SLEEP_MODE (0x75) /** 睡眠方式 */ +#define NDS03_REG_CONFI_TH (0x76) /** 置信度阈值 */ +#define NDS03_REG_TARGET_NUM (0x77) /** 目标个数 */ +#define NDS03_REG_INV_TIME (0x7C) /** 测量间隔时间 */ +#define NDS03_REG_OFFSET_MM (0x90) /** offset 标定位置 */ + +#define NDS03_REG_XTALK_TH (0xB0) /** 串扰阈值 */ +#define NDS03_REG_XTALK (0xB2) /** 串扰值 */ + +#define NDS03_REG_DATA_SIZE (0x5C) /** 数据大小 */ +#define NDS03_REG_CACHE_SIZE (0x5D) /** 缓存大小 */ +#define NDS03_REG_CACHE_ADDR (0x5E) /** 缓存地址 */ +#define NDS03_REG_CACHE_DATA (0xC0) /** 缓存数据 */ + +/** @} NDS03_Reg_Group */ + +/** @defgroup NDS03_State_Group NDS03 Data Request Index + * @brief NDS03 State (NDS03_REG_STATE) + * @{ + */ + +#define NDS03_STATE_IDLE 0x00 /** 空闲状态 */ +#define NDS03_STATE_SOFT_READY 0xA5 /** 软件就绪状态 */ +#define NDS03_STATE_GOT_DEPTH 0xA6 /** 已获取深度状态 */ + +/** @} NDS03_State_Group */ + +/** @defgroup NDS03_Data_Val_Req_Idx_Group NDS03 Data Request Index + * @brief NDS03 Data Request Mask (NDS03_REG_DAT_VAL_REQ) + * @{ + */ +/** DATA REQ */ +#define NDS03_DATA_REQ_IDLE 0x00 /** 无效数据命令标志位 */ +#define NDS03_DEPTH_DATA_FLAG 0x10 /** 获取深度数据标志 */ +#define NDS03_DEPTH_CONTINUOUS_FLAG 0x13 /** 连续获取深度数据标志 */ +#define NDS03_USER_DATA_FLAG 0x50 /** 读用户数据标志位 */ +#define NDS03_GET_MODEL_FLAG 0x51 /** 获取模组型号标志位 */ +#define NDS03_CMD_READ_HGM_DATA 0xC0 /** 读直方图数据标志位 */ +#define NDS03_CMD_READ_HGM_DATA_ENA 0x05 /** 读直方图数据使能标志位 */ + +/** DATA VAL */ +#define NDS03_DATA_VAL_IDLE 0x00 /** 无效数据标志位 */ + +/** CMD REQ */ +#define NDS03_CMD_OFFSET_CALIB 0x20 /** offset标定命令 */ +#define NDS03_CMD_XTALK_CALIB 0x24 /** xtalk标定 */ +#define NDS03_CMD_WRITE_USER_DATA 0x50 /** 写用户数据区域标志位 */ + + +/** CMD VAL */ +#define NDS03_CMD_VAL_IDLE 0x00 /** 无效命令标志位 */ + +/** CMD ENA */ +#define NDS03_CMD_WRITE_USER_DATA_ENA 0xAA /** 用户数据使能标志位 */ +#define NDS03_CMD_ENA_ENABLE 0xA5 /** 配置开启标志位 */ +#define NDS03_CMD_ENA_DISABLE 0x00 /** 配置关闭标志位 */ + +/** @} NDS03_Data_Val_Req_Idx_Group */ + +/** @defgroup NDS03_Sleep_Group NDS03 Sleep Group + * @brief NDS03 Sleep (NDS03_REG_SLEEP_MODE) + * @{ + */ + +#define NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP 0xA5 /* 手动进入软件睡眠标志位,超时唤醒 */ +#define NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP 0xA4 /* 手动进入软件睡眠标志位,手动唤醒 */ +// #define NDS03_AUTO_SLEEP_MANUAL_WEAK_UP 0xA3 /* 测量结束自动进入软件睡眠标志位,手动唤醒 */ +// #define NDS03_AUTO_SLEEP_TIME_OUT_WEAK_UP 0xA2 /* 测量结束自动进入软件睡眠标志位,超时唤醒 */ + +/** @} NDS03_Sleep_Group */ + +/** @enum NDS03_Status_e + * @brief 定义NDS03状态宏 + */ +typedef int8_t NDS03_Error; + +/** @defgroup NDS03_Error_Group NDS03 Error Group + * @brief NDS03 Error Group (NDS03_REG_ERROR_FLAG) + * @{ + */ +#define NDS03_ERROR_NONE 0 /** 成功 */ +#define NDS03_ERROR_API -1 /** api接口注册失败 */ +#define NDS03_ERROR_TIMEOUT -2 /** 超时错误 */ +#define NDS03_ERROR_I2C -3 /** IIC通讯错误 */ +#define NDS03_ERROR_BOOT -4 /** 模组启动错误 */ +#define NDS03_ERROR_CALIB -5 /** 标定失败错误 */ +#define NDS03_ERROR_INIT -6 /** 初始化失败 */ +#define NDS03_ERROR_RANGING -7 /** 测距出错 */ +#define NDS03_ERROR_UPGRADE_VER -8 /** 升级版本不对 */ +#define NDS03_ERROR_UPGRADE -9 /** 升级失败 */ +#define NDS03_ERROR_AMBIENT_HIGH -10 /** 标定时环境光强过大 */ +#define NDS03_ERROR_NO_NDS03 -11 /** 不是NDS03模组 */ +#define NDS03_ERROR_VCSEL_ERROR -12 /** VCSEL不亮 */ +#define NDS03_ERROR_OFFSET_ERROR -13 /** OFFSET 标定失败 */ + +/** @} NDS03_Error_Group */ + +/** @defgroup NDS03_Calib_State_Group NDS03 Calib State Group + * @brief NDS03 Calib State Group (NDS03_REG_CALIB_STATE) + * @{ + */ +#define NDS03_CALIB_ERROR_NONE 0x00 /** 成功 */ +#define NDS03_CALIB_ERROR_XTALK_OVERFLOW 0x02 /** 串扰溢出 */ +#define NDS03_CALIB_ERROR_XTALK_EXCESSIVE 0x10 /** 串扰过大 */ +#define NDS03_CALIB_ERROR_OFFSET 0x20 /** offset标定后测距误差过大 */ +/** @} NDS03_Calib_State_Group */ + +/** @defgroup NDS03_GPIO1_Func_Group NDS03 GPIO1 Functions Define + * @brief NDS03 GPIO1 Functions Define Group (NDS03_REG_GPIO1_FUNC) + * @{ + */ + +/** REG_GPIO1_SETTING Mask */ +#define NDS03_GPIO1_FUNCTIONALITY_MASK 0x07 /** GPIO1功能配置掩码 */ +#define NDS03_GPIO1_POLARITY_MASK 0x08 /** 极性配置掩码 */ + +/** GPIO1 Functionality */ +typedef uint8_t NDS03_Gpio1Func_t; +#define NDS03_GPIO1_FUNCTIONALITY_OFF ((NDS03_Gpio1Func_t)0x00) /** 无触发中断 */ +#define NDS03_GPIO1_THRESHOLD_LOW ((NDS03_Gpio1Func_t)0x01) /** 低深度触发中断 (value < NDS03_REG_DEPTH_TH_L) */ +#define NDS03_GPIO1_THRESHOLD_HIGH ((NDS03_Gpio1Func_t)0x02) /** 高深度触发中断 (value > NDS03_REG_DEPTH_TH_H) */ +#define NDS03_GPIO1_THRESHOLD_DOMAIN_OUT ((NDS03_Gpio1Func_t)0x03) /** 低深度或高深度触发中断 (value < NDS03_REG_DEPTH_TH_L 或 value > NDS03_REG_DEPTH_TH_H) */ +#define NDS03_GPIO1_NEW_MEASURE_READY ((NDS03_Gpio1Func_t)0x04) /** 新深度数据就绪中断 */ + +/** GPIO1 polarity */ +typedef uint8_t NDS03_Gpio1Polar_t; +#define NDS03_GPIO1_POLARITY_LOW ((NDS03_Gpio1Polar_t)0x00) /** 负极性, 低电平有效 */ +#define NDS03_GPIO1_POLARITY_HIGH ((NDS03_Gpio1Polar_t)0x01) /** 正极性, 高电平有效 */ + +/** @} NDS03_GPIO1_Func_Group */ + +#define NDS03_TARGET_MAX_NUM 4 +#define NDS03_AMBIENT_TH 1000 /** 标定时环境光强阈值 */ +#define NDS03_OFFSET_DEPTH_ERROR_TH 10 /** OFFSET 标定深度误差阈值 */ +#define NDS03_OFFSET_REF_MAX_COUNT_TH 500 /** OFFSET 标定深度误差阈值 */ +#define NDS03_DEPTH_INVALID_VALUE 65300 /** 深度无效值 */ + +/** @enum NDS03_Status_e + * @brief 定义NDS03状态宏 + */ +typedef enum{ + NDS03_DISABLE = 0, ///< 关闭状态 + NDS03_ENABLE = 1 ///< 使能状态 +} NDS03_Status_e; + +/** + * @struct NDS03_RangingData_t + * + * @brief NDS03测量结果结构体 \n + * 定义存储NDS03的深度、置信度信息 + */ +typedef struct{ + uint16_t depth; ///< 测量距离 + uint16_t confi; ///< 测量置信度 + uint16_t count; ///< 计数值 + uint16_t crate; ///< 计数率 +} NDS03_RangingData_t; + + +/** + * @struct NDS03_ChipInfo_t + * + * @brief NDS03模组生产信息\n + */ +typedef struct { + uint32_t fw_version; ///< NDS03固件版本 +} NDS03_ChipInfo_t; + +/** + * @struct NDS03_DevConfig_t + * + * @brief NDS03模组配置数据\n + */ +typedef struct { + uint32_t range_frame_time_us; //< 模组取图帧间隔时间配置 + uint8_t continuous_flag; ///< 连续模式标志位 + uint8_t target_num; ///< 目标个数 +} NDS03_DevConfig_t; + +/** + * @struct NDS03_Dev_t + * + * @brief 设备类型结构体\n + */ +typedef struct { + uint8_t dev_pwr_state; ///< 设备的当前状态, 就绪模式或者休眠模式 + NDS03_DevConfig_t config; ///< 模组配置信息 + NDS03_ChipInfo_t chip_info; ///< 模组设备信息 + uint8_t data_cnt; ///< 数据获取次数 + NDS03_RangingData_t ranging_data[NDS03_TARGET_MAX_NUM]; ///< 测距数据结果 + NDS03_Platform_t platform; +} NDS03_Dev_t; + +#define NDS03_DEFAULT_SLAVE_ADDR 0x5C + +#if NDS03_PLATFORM == PLATFORM_C51 +#define CHECK_RET(func) \ + ret = func; \ + if(ret != NDS03_ERROR_NONE) \ + return ret; +#else +#define CHECK_RET(func) do { \ + ret = func; \ + if(ret != NDS03_ERROR_NONE) { \ + NX_PRINTF("%s I2c Error, ret: %d\r\n", #func, ret); \ + return ret; \ + } \ +} while (0) +#endif + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_dev.c b/drivers/iio/proximity/nds03/nds03_dev.c new file mode 100644 index 000000000000..09cd9a5f2d53 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_dev.c @@ -0,0 +1,743 @@ +/** + * @file nds03_dev.c + * @author tongsheng.tang + * @brief NDS03 device setting functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, + * in the file named LICENSE. + * + */ + +#include "nds03_dev.h" +#include "nds03_def.h" +#include "nds03_comm.h" + +/** SDK主版本 */ +static uint8_t sdk_version_major = 2; +/** SDK次版本 */ +static uint8_t sdk_version_minor = 0; +/** SDK小版本 */ +static uint8_t sdk_version_patch = 3; + +/** + * @brief NDS03 Get SDK Version + * 获取当前SDK的软件版本号 + * @return uint32_t + * @retval 软件版本号 + */ +uint32_t NDS03_GetSdkVersion(void) +{ + return ((uint32_t)sdk_version_major << 16) + + ((uint32_t)sdk_version_minor << 8) + (uint32_t)sdk_version_patch; +} + +/** + * @brief NDS03 Get Firmware Version + * 获取NDS03模组固件版本号 + * @param pNxDevice + * @return NDS03_Error + */ +NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_FW_VER, &pNxDevice->chip_info.fw_version)); + return ret; +} + +/** + * @brief NDS03 Get Therm + * 获取NDS03的温度 + * @param pNxDevice + * @param therm 温度,单位为0.1度 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_THERM, (uint16_t*)therm)); + return ret; +} + +/** + * @brief NDS03 Set Pulse Num + * 设置发光次数 + * @param pNxDevice + * @param pulse_num 发光次数 + * @return NDS03_Error + */ +NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} +/** + * @brief NDS03 Get Pulse Num + * 获取发光次数 + * @param pNxDevice + * @param pulse_num 发光次数 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_PULSE_NUM, pulse_num)); + + return ret; +} + +/** + * @brief NDS03 Set Frame Time + * 设置测量帧间隔时间(us) + * @param pNxDevice + * @param inv_time 测量帧间隔时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteWord(pNxDevice, NDS03_REG_INV_TIME, frame_time_us)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME, + &pNxDevice->config.range_frame_time_us)); + + return ret; +} +/** + * @brief NDS03 Get Frame Time + * 获取帧测量间隔时间(us) + * @param pNxDevice + * @param inv_time 测量间隔时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadWord(pNxDevice, NDS03_REG_INV_TIME, + &pNxDevice->config.range_frame_time_us)); + *frame_time_us = pNxDevice->config.range_frame_time_us; + + return ret; +} + +/** + * @brief NDS03 Set Confidence threshold + * 配置置信度阈值 + * @param pNxDevice + * @param confi_th + * @return NDS03_Error + */ +NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Confidence threshold + * 获取置信度阈值 + * @param pNxDevice + * @param confi_th 置信度阈值 + * @return NDS03_Error + */ +NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CONFI_TH, confi_th)); + + return ret; +} + +/** + * @brief NDS03 Set Target Num + * 配置目标个数 + * @param pNxDevice + * @param num + * @return NDS03_Error + */ +NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + num = (num > NDS03_TARGET_MAX_NUM) ? NDS03_TARGET_MAX_NUM : num; + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_TARGET_NUM, num)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + pNxDevice->config.target_num = num; + + return ret; +} + +/** + * @brief NDS03 Get Target Num + * 获取目标个数 + * @param pNxDevice + * @param num + * @return NDS03_Error + */ +NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_TARGET_NUM, num)); + pNxDevice->config.target_num = *num; + + return ret; +} + +/** + * @brief NDS03 Set Gpio1 Configuration + * 设置中断引脚的功能配置 + * @param pNxDevice: NDS03模组设备信息结构体 + * @param functionality: 中断功能设置 + * NDS03_GPIO1_FUNCTIONALITY_OFF: 无功能(默认) + * NDS03_GPIO1_THRESHOLD_LOW:比较功能,当深度小于低阈值时,GPIO输出有效电平 + * NDS03_GPIO1_THRESHOLD_HIGH:比较功能,当深度大于高阈值时,GPIO输出有效电平 + * NDS03_GPIO1_THRESHOLD_DOMAIN_OUT:比较功能,当深度小于低阈值或者大于高阈值时,GPIO输出有效电平 + * NDS03_GPIO1_NEW_MEASURE_READY:深度数据有效功能,当深度数据有效时,GPIO输出有效电平 + * @param polarity: INT引脚有效电平 + * NDS03_GPIO1_POLARITY_LOW:低电平有效 + * NDS03_GPIO1_POLARITY_HIGH:高电平有效 + * @return NDS03_Error +*/ +NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t rbuf; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf)); + /** 设置中断功能 */ + rbuf = rbuf & (~NDS03_GPIO1_FUNCTIONALITY_MASK); + rbuf = rbuf | (functionality & NDS03_GPIO1_FUNCTIONALITY_MASK); + /** 设置中断引脚极性 */ + if (polarity == NDS03_GPIO1_POLARITY_HIGH) + rbuf = rbuf | NDS03_GPIO1_POLARITY_MASK; + else + rbuf = rbuf & (~NDS03_GPIO1_POLARITY_MASK); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_GPIO1_FUNC, rbuf)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Gpio1 Config + * 获取中断引脚的功能配置 + * @param pNxDevice: NDS03模组设备信息结构体指针 + * @param functionality: 获取到的中断功能变量指针 + * @param polarity: 获取到的中断引脚极性变量指针 + * @return NDS03_Error +*/ +NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t rbuf; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_GPIO1_FUNC, &rbuf)); + // Polarity + *polarity = ((rbuf & NDS03_GPIO1_POLARITY_MASK) == NDS03_GPIO1_POLARITY_MASK) ? + NDS03_GPIO1_POLARITY_HIGH : NDS03_GPIO1_POLARITY_LOW; + // Functionality + *functionality = rbuf & NDS03_GPIO1_FUNCTIONALITY_MASK; + + return ret; +} + +/** + * @brief NDS03 Set Depth Threshold + * 设置深度阈值 + * 该功能仅用于GPIO功能为 + * NDS03_GPIO1_THRESHOLD_LOW + * 或NDS03_GPIO1_THRESHOLD_HIGH + * 或NDS03_GPIO1_THRESHOLD_DOMAIN_OUT + * @param pNxDevice: NDS03模组设备信息结构体 + * @param depth_low: 低深度阈值 / mm + * @param depth_high: 高深度阈值 / mm + * @return NDS03_Error +*/ +NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t depth_low, uint16_t depth_high) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_DISABLE)); + + return ret; +} + +/** + * @brief NDS03 Get Depth Threshold + * 获取深度阈值 + * @param pNxDevice: NDS03模组设备信息结构体 + * @param depth_low: 低深度阈值 / mm + * @param depth_high: 高深度阈值 / mm + * @return NDS03_Error +*/ +NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t *depth_low, uint16_t *depth_high) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_L, depth_low)); + CHECK_RET(NDS03_ReadHalfWord(pNxDevice, NDS03_REG_DEPTH_TH_H, depth_high)); + + return ret; +} + +/** + * @brief NDS03 Waitfor Data Val + * 等待数据完成 + * @param pNxDevice 模组设备 + * @param flag 读命令标志位 + * @return NDS03_Error + */ +NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t dat_valid_flag = 0x00; + int32_t retry_cnt; + + retry_cnt = timeout_ms * 2; + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DAT_VAL, &dat_valid_flag)); + if (dat_valid_flag == flag) + break; + NDS03_Delay10us(pNxDevice, 50); + } while (--retry_cnt); + + if (retry_cnt == 0) { + NX_PRINTF("data_valid_flag: %d\r\n", dat_valid_flag); + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Waitfor Cmd Val + * 等待命令完成 + * @param pNxDevice 模组设备 + * @param cmd 命令 + * @param timeout_ms 超时时间 + * @return NDS03_Error + */ +NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t retry_cnt; + uint8_t val; + + retry_cnt = timeout_ms * 2; + do { + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CMD_VAL, &val)); + if (val == cmd) + break; + + NDS03_Delay10us(pNxDevice, 50); + } while (--retry_cnt); + + if (retry_cnt == 0) { + NX_PRINTF("Timeout!!, val: 0x%02x\r\n", val); + ret = NDS03_ERROR_TIMEOUT; + } + + return ret; +} + +/** + * @brief NDS03 Read Hgm Data + * 读取NDS03直方图数据 + * @param pNxDevice 模组设备 + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice, uint8_t *rbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + uint16_t addr = 0xe000; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, 0x05)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, 0xC0)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, 0xC0, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, + NDS03_REG_CACHE_DATA, rbuf, + ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf += _size; + addr += _size; + rsize += _size; + } + + return ret; +} + +/** + * @brief NDS03 Read User Data + * 读取NDS03中用户数据区域,支持任意地址循环读取,比如从0xFFF0开始读取32个字节, + * 则前16个字节数据是0xFFF0~0xFFFF的数据,后16个字节是0x0000~0x000F的数据 + * @param pNxDevice 模组设备 + * @param addr 数据地址,0x0000~0xFFFF + * @param rbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *rbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_USER_DATA_FLAG)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_USER_DATA_FLAG, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, + rbuf, ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + rbuf += _size; + addr += _size; + rsize += _size; + } + + return ret; +} + +/** + * @brief NDS03 Read User Data + * 写入NDS03中用户数据区域, 支持任意地址循环写入,比如从0xFFF0开始写入32个字节, + * 则前16个字节数据是0xFFF0~0xFFFF的数据,后16个字节是0x0000~0x000F的数据 + * @param pNxDevice 模组设备 + * @param addr 数据地址,0x0000~0xFFFF + * @param wbuf 数据指针 + * @param size 数据大小 + * @return NDS03_Error + */ +NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *wbuf, uint32_t size) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t rsize, _size; + uint8_t one_size; + + // NX_PRINTF("%s Start\r\n", __func__); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_CACHE_SIZE, &one_size)); + _size = (uint32_t)one_size; + rsize = 0; + while ((rsize < size) && (ret == NDS03_ERROR_NONE)) { + CHECK_RET(NDS03_WriteNBytes(pNxDevice, NDS03_REG_CACHE_DATA, + wbuf, ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DATA_SIZE, + ((size - rsize) > _size) ? _size : (size - rsize))); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_CACHE_ADDR, addr)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_ENA, + NDS03_CMD_WRITE_USER_DATA_ENA)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_REQ, + NDS03_CMD_WRITE_USER_DATA)); + CHECK_RET(NDS03_WaitforCmdVal(pNxDevice, NDS03_CMD_WRITE_USER_DATA, 500)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CMD_VAL, NDS03_CMD_VAL_IDLE)); + wbuf += _size; + addr += _size; + rsize += _size; + } + // NX_PRINTF("%s End\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03软件休眠,定时自动唤醒 + * + * @param pNxDevice 模组设备 + * @param sleep_time_ms 软件睡眠时间,达到时间后自动唤醒 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, + NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP)); + + return ret; +} + +/** + * @brief NDS03软件休眠,需要手动唤醒 + * + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, + NDS03_REG_SLEEP_MODE, NDS03_MANUAL_SLEEP_MANUAL_WEAK_UP)); + + return ret; +} + +/** + * @brief NDS03 Sleep + * NDS03进入休眠 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 0)); + return ret; +} + +/** + * @brief NDS03 Wakeup + * NDS03从软件睡眠中唤醒 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint32_t freq; + + CHECK_RET(NDS03_GetI2cFreq(pNxDevice,&freq)); + CHECK_RET(NDS03_SetI2cFreq(pNxDevice,1000)); + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, 0)); + + CHECK_RET(NDS03_SetI2cFreq(pNxDevice,freq)); + + return ret; +} + +/** + * @brief NDS03 Software Sleep + * 软件睡眠 + * @param pNxDevice 模组设备 + * @param sleep_time_ms 软件睡眠时间,达到时间后自动唤醒 + * @return NDS03_Error + * @deprecated 在以后的版本会弃用,请使用NDS03_SoftSleepWithAutoWakeup() + */ +static __maybe_unused NDS03_Error NDS03_SoftSleep(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_CFG_ENA, NDS03_CMD_ENA_ENABLE); + ret |= NDS03_WriteHalfWord(pNxDevice, NDS03_REG_SLEEP_TIME, sleep_time_ms); + ret |= NDS03_WriteByte(pNxDevice, NDS03_REG_SLEEP_MODE, + NDS03_MANUAL_SLEEP_TIME_OUT_WEAK_UP); + + return ret; +} + +/** + * @brief NDS03 Wakeup + * NDS03从睡眠中唤醒 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_SetXShutPinLevel(pNxDevice, 1)); + return ret; +} + +/** + * @brief 判断是否为NDS03 + * + * @param pNxDevice + * @return NDS03_Error + * @arg 0: 是NDS03 + * @arg NDS03_ERROR_NO_NDS03: 不是NDS03 + * @arg others: 不确定是否为该模组,需要进一步排查,可能是I2C通信异常。 + * 如果排除I2C通信异常,则认为不是NDS03,可能是其他设备。 + */ +NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint8_t buf[4] = {0}; + + NDS03_SetXShutPinLevel(pNxDevice, 1); + CHECK_RET(NDS03_Delay1ms(pNxDevice, 10)); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_REQ, NDS03_GET_MODEL_FLAG)); + CHECK_RET(NDS03_WaitforDataVal(pNxDevice, NDS03_GET_MODEL_FLAG, 200)); + CHECK_RET(NDS03_ReadNBytes(pNxDevice, NDS03_REG_CACHE_DATA, buf, sizeof(buf))); + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DAT_VAL, NDS03_DATA_VAL_IDLE)); + if ((buf[0] != 0x31) || (buf[1] != 0x53) || (buf[2] != 0x30) || (buf[3] != 0x33)) + ret = NDS03_ERROR_NO_NDS03; + + return ret; +} + +/** + * @brief NDS03 Set Device Address + * 设置模组设备地址 + * @param pNxDevice 模组设备 + * @param dev_addr + * @return NDS03_Error + */ +NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + CHECK_RET(NDS03_WriteByte(pNxDevice, NDS03_REG_DEV_ADDR, dev_addr)); + pNxDevice->platform.i2c_dev_addr = dev_addr; + + return ret; +} + +/** + * @brief NDS03 InitDevice + * 初始化设备 + * @param pNxDevice 模组设备 + * @return NDS03_Error + */ +NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + + // NX_PRINTF("%s Start!\r\n", __func__); + + CHECK_RET(NDS03_GetFirmwareVersion(pNxDevice)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_DATA_CNT, &pNxDevice->data_cnt)); + CHECK_RET(NDS03_GetFrameTime(pNxDevice, &pNxDevice->config.range_frame_time_us)); + pNxDevice->config.continuous_flag = 0; + + // NX_PRINTF("%s End!\r\n", __func__); + + return ret; +} + +/** + * @brief NDS03 Wait for Device Boot Up + * 等待NDS03模组启动 + * @param pNxDevice 模组设备 + * @return NDS03_ERROR_NONE:成功 + * NDS03_ERROR_BOOT:启动失败--请检测模组是否焊接好,还有i2c地址与读写函数是否错误。 + * NDS03_ERROR_FW:固件不兼容--请与FAE联系,是否模组的固件与SDK不兼容。 + */ +NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + int32_t try_times = 200; + uint8_t slave_addr = pNxDevice->platform.i2c_dev_addr; + + NDS03_SetXShutPinLevel(pNxDevice, 0); + CHECK_RET(NDS03_Delay10us(pNxDevice, 20)); + NDS03_SetXShutPinLevel(pNxDevice, 1); + CHECK_RET(NDS03_Delay1ms(pNxDevice, 2)); + ret = NDS03_SetXShutPinLevel(pNxDevice, 1); + pNxDevice->platform.i2c_dev_addr = (ret == NDS03_ERROR_NONE) ? + NDS03_DEFAULT_SLAVE_ADDR : pNxDevice->platform.i2c_dev_addr; + + pNxDevice->data_cnt = 0; + pNxDevice->config.continuous_flag = 0; + + do { + CHECK_RET(NDS03_Delay10us(pNxDevice, 10)); + CHECK_RET(NDS03_ReadByte(pNxDevice, NDS03_REG_STATE, &pNxDevice->dev_pwr_state)); + } while ((pNxDevice->dev_pwr_state != NDS03_STATE_SOFT_READY) && + (pNxDevice->dev_pwr_state != NDS03_STATE_GOT_DEPTH) && --try_times); + + if (0 == try_times) { + NX_PRINTF("state: 0x%02x\r\n", pNxDevice->dev_pwr_state); + NX_PRINTF("NDS03 boot error\r\n"); + return NDS03_ERROR_BOOT; + } + + if (slave_addr != pNxDevice->platform.i2c_dev_addr) + CHECK_RET(NDS03_SetDevAddr(pNxDevice, slave_addr)); + + return ret; +} + +/** + * @brief NDS03 Dirty Warning + * 脏污预警 + * @param pNxDevice 模组设备 + * @param flag 脏污预警标志位 1:脏污预警,0:正常 + * @param time_th 近距离时间阈值,单位ms + * @return NDS03_ERROR_NONE:成功 + */ +NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th) +{ + NDS03_Error ret = NDS03_ERROR_NONE; + uint16_t depth_low_th = 30; + static int32_t depth_low_count = 0, depth_low_time_sta = 0, depth_low_time_end = 0; + + if (time_th == 0) + time_th = 10 * 1000; + + if (pNxDevice->ranging_data[0].depth < depth_low_th) { + depth_low_count ++; + if (depth_low_count == 1) + NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_sta); + + NDS03_GetSystemClkMs(pNxDevice, &depth_low_time_end); + if (depth_low_time_end < depth_low_time_sta) { + depth_low_time_sta = 0; + depth_low_time_end = 0; + } + } else { + depth_low_count = 0; + depth_low_time_sta = 0; + depth_low_time_end = 0; + } + + if (depth_low_count > 10 && pNxDevice->ranging_data[1].depth != NDS03_DEPTH_INVALID_VALUE) + *flag = 1; + + if ((depth_low_time_end - depth_low_time_sta) > time_th) + *flag = 1; + + return ret; +} diff --git a/drivers/iio/proximity/nds03/nds03_dev.h b/drivers/iio/proximity/nds03/nds03_dev.h new file mode 100644 index 000000000000..99780128875c --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_dev.h @@ -0,0 +1,94 @@ +/** + * @file nds03_dev.h + * @author tongsheng.tang + * @brief NDS03 device setting functions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ +#ifndef __NDS03_DEV_H__ +#define __NDS03_DEV_H__ + +#include "nds03_def.h" + +/** @defgroup NDS03_Dev_Group NDS03 Device Functions + * @brief NDS03 Device Functions + * @{ + */ + +/** 获取SDK版本号 */ +uint32_t NDS03_GetSdkVersion(void); +/** 获取NDS03模组固件版本号 */ +NDS03_Error NDS03_GetFirmwareVersion(NDS03_Dev_t *pNxDevice); +/** 获取温度 */ +NDS03_Error NDS03_GetTherm(NDS03_Dev_t *pNxDevice, int16_t* therm); +/** 设置发光次数 */ +NDS03_Error NDS03_SetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t pulse_num); +/** 获取发光次数 */ +NDS03_Error NDS03_GetPulseNum(NDS03_Dev_t *pNxDevice, uint32_t *pulse_num); +/** 设置测量间隔时间 */ +NDS03_Error NDS03_SetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t frame_time_us); +/** 获取测量间隔时间 */ +NDS03_Error NDS03_GetFrameTime(NDS03_Dev_t *pNxDevice, uint32_t *frame_time_us); +/** 设置置信度阈值 */ +NDS03_Error NDS03_SetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t confi_th); +/** 获取置信度阈值 */ +NDS03_Error NDS03_GetConfiTh(NDS03_Dev_t *pNxDevice, uint8_t *confi_th); +/** 设置目标个数 */ +NDS03_Error NDS03_SetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t num); +/** 获取目标个数 */ +NDS03_Error NDS03_GetTargetNum(NDS03_Dev_t *pNxDevice, uint8_t *num); +/** 设置中断引脚功能 */ +NDS03_Error NDS03_SetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t functionality, NDS03_Gpio1Polar_t polarity); +/** 获取中断引脚功能 */ +NDS03_Error NDS03_GetGpio1Config(NDS03_Dev_t *pNxDevice, + NDS03_Gpio1Func_t *functionality, NDS03_Gpio1Polar_t *polarity); +/** 设置深度阈值 */ +NDS03_Error NDS03_SetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t depth_low, uint16_t depth_high); +/** 获取深度阈值 */ +NDS03_Error NDS03_GetDepthThreshold(NDS03_Dev_t *pNxDevice, + uint16_t *depth_low, uint16_t *depth_high); +/** 等待获取数据结束 */ +NDS03_Error NDS03_WaitforDataVal(NDS03_Dev_t *pNxDevice, uint8_t flag, int32_t timeout_ms); +/** 等待命令结束 */ +NDS03_Error NDS03_WaitforCmdVal(NDS03_Dev_t *pNxDevice, uint8_t cmd, int32_t timeout_ms); +/** 从NDS03中读取直方图数据 */ +NDS03_Error NDS03_ReadHgmData(NDS03_Dev_t *pNxDevice,uint8_t *rbuf, uint32_t size); +/** 从NDS03中读取用户数据 */ +NDS03_Error NDS03_ReadUserData(NDS03_Dev_t *pNxDevice, uint16_t addr, uint8_t *rbuf, uint32_t size); +/** 从NDS03中写入用户数据 */ +NDS03_Error NDS03_WriteUserData(NDS03_Dev_t *pNxDevice, + uint16_t addr, uint8_t *wbuf, uint32_t size); +/** NDS03进入软件睡眠,手动唤醒 */ +NDS03_Error NDS03_SoftSleepWithManualWakeup(NDS03_Dev_t *pNxDevice); +/** NDS03进入软件睡眠,自动唤醒 */ +NDS03_Error NDS03_SoftSleepWithAutoWakeup(NDS03_Dev_t *pNxDevice, uint16_t sleep_time_ms); +/** NDS03从软件睡眠中唤醒 */ +NDS03_Error NDS03_SoftWakeup(NDS03_Dev_t *pNxDevice); +/** NDS03进入睡眠 */ +NDS03_Error NDS03_Sleep(NDS03_Dev_t *pNxDevice); +/** NDS03从睡眠中唤醒 */ +NDS03_Error NDS03_Wakeup(NDS03_Dev_t *pNxDevice); +/** 判断是否为NDS03设备,返回值为0表示是NDS03设备 */ +NDS03_Error NDS03_IsNDS03(NDS03_Dev_t *pNxDevice); +/** 设置模组设备地址 */ +NDS03_Error NDS03_SetDevAddr(NDS03_Dev_t *pNxDevice, uint8_t dev_addr); +/** 初始化设备 */ +NDS03_Error NDS03_InitDevice(NDS03_Dev_t *pNxDevice); +/** 等待设备启动 */ +NDS03_Error NDS03_WaitDeviceBootUp(NDS03_Dev_t *pNxDevice); +/** 脏污预警 */ +NDS03_Error NDS03_DirtyWarning(NDS03_Dev_t *pNxDevice,uint8_t *flag,uint32_t time_th); + +/** @} NDS03_Dev_Group */ + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_iio.c b/drivers/iio/proximity/nds03/nds03_iio.c new file mode 100644 index 000000000000..a683cc292616 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_iio.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include "nds03_iio.h" +#include "nds03.h" + +#define NDS03_DISTANCE_CHANNEL { \ + .type = IIO_DISTANCE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_ENABLE), \ + .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE),\ + .scan_index = NDS03_IIO_CHAN_DISTANCE, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ +} + +static const int nds03_scales[] = { 1 }; + +static const struct iio_chan_spec nds03_channels[] = { + NDS03_DISTANCE_CHANNEL, + IIO_CHAN_SOFT_TIMESTAMP(NDS03_IIO_CHAN_TIMESTAMP), +}; + +static int nds03_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *type = IIO_VAL_INT; + *vals = nds03_scales; + *length = ARRAY_SIZE(nds03_scales); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +/* === read_raw === */ +static int nds03_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->scan_index == NDS03_IIO_CHAN_DISTANCE) { + *val = iio->ctx->g_nds03_device.ranging_data[0].depth; + return IIO_VAL_INT; + } + break; + case IIO_CHAN_INFO_SCALE: + *val = nds03_scales[0]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_ENABLE: + *val = iio->enabled; + return IIO_VAL_INT; + + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int nds03_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_RAW: + return -EINVAL; + case IIO_CHAN_INFO_SCALE: + /* NOTE: Default to 1 */ + return 0; + case IIO_CHAN_INFO_ENABLE: + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct iio_info nds03_iio_info = { + .read_raw = nds03_read_raw, + .write_raw = nds03_write_raw, + .read_avail= nds03_read_avail, +}; + +/* === buffer setup === */ +static void nds03_enable_work(struct work_struct *work) +{ + struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, enable_work); + struct nds03_context *ctx = iio->ctx; + NDS03_Dev_t *dev = &ctx->g_nds03_device; + int ret; + + mutex_lock(&ctx->work_mutex); + if (iio->enabled) + goto out; + + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + atomic_set(&ctx->is_meas, 1); + ret = nds03_sensor_init(ctx); + if(ret != 0) { + dev_err(&ctx->client->dev, "nds03 sensor init failed %d\n", ret); + goto out; + } + ret = NDS03_StartContinuousMeasurement(dev); + if (ret) { + dev_err(&ctx->client->dev, "StartContinuous fail %d\n", ret); + goto out; + } + iio->enabled = true; + dev_info(&ctx->client->dev, "NDS03 sensor started\n"); + goto out; + +out: + mutex_unlock(&ctx->work_mutex); +} + +static void nds03_disable_work(struct work_struct *work) +{ + struct nds03_iio_dev *iio = container_of(work, struct nds03_iio_dev, disable_work); + struct nds03_context *ctx = iio->ctx; + NDS03_Dev_t *dev = &ctx->g_nds03_device; + + mutex_lock(&ctx->work_mutex); + if (!iio->enabled) + goto out; + + atomic_set(&ctx->is_meas, 0); + NDS03_StopContinuousMeasurement(dev); + iio->enabled = false; + dev_info(&ctx->client->dev, "NDS03 sensor stopped\n"); +out: + mutex_unlock(&ctx->work_mutex); +} + +static int nds03_buffer_preenable(struct iio_dev *indio_dev) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + schedule_work(&iio->enable_work); + return 0; +} + +static int nds03_buffer_predisable(struct iio_dev *indio_dev) +{ + struct nds03_iio_dev *iio = iio_device_get_drvdata(indio_dev); + + schedule_work(&iio->disable_work); + return 0; +} + +static const struct iio_buffer_setup_ops nds03_buffer_setup_ops = { + .preenable = nds03_buffer_preenable, + .predisable = nds03_buffer_predisable, +}; + +int nds03_iio_init(struct nds03_context *ctx) +{ + struct device *dev = &ctx->client->dev; + struct nds03_iio_dev *iio; + int ret; + + iio = devm_kzalloc(dev, sizeof(*iio), GFP_KERNEL); + if (!iio) { + nds03_errmsg("devm_kzalloc error\n"); + return -ENOMEM; + } + + iio->indio_dev = devm_iio_device_alloc(dev, 0); + if (!iio->indio_dev) { + nds03_errmsg("devm_iio_device_alloc error\n"); + return -ENOMEM; + } + + iio->ctx = ctx; + iio->enabled = false; + INIT_WORK(&iio->enable_work, nds03_enable_work); + INIT_WORK(&iio->disable_work, nds03_disable_work); + + iio->indio_dev->name = "nds03"; + iio->indio_dev->channels = nds03_channels; + iio->indio_dev->num_channels = ARRAY_SIZE(nds03_channels); + iio->indio_dev->info = &nds03_iio_info; + iio->indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; + iio_device_set_drvdata(iio->indio_dev, iio); + + /* kfifo buffer + setup_ops */ + ret = devm_iio_kfifo_buffer_setup(dev, iio->indio_dev, &nds03_buffer_setup_ops); + if (ret) + return ret; + + ret = devm_iio_device_register(dev, iio->indio_dev); + if (ret) + return ret; + + ctx->iio = iio; + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_iio_init); + +void nds03_iio_remove(struct nds03_context *ctx) +{ + return; +} +EXPORT_SYMBOL_GPL(nds03_iio_remove); + +void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm) +{ + struct nds03_iio_dev *iio = ctx->iio; + struct nds03_scan scan; + + if (!iio || !iio->enabled) + return; + + scan.distance = distance_mm; + if (iio_buffer_enabled(iio->indio_dev)) + iio_push_to_buffers_with_timestamp(iio->indio_dev, &scan, + ktime_get_boottime_ns()); +} +EXPORT_SYMBOL_GPL(nds03_iio_push_data); diff --git a/drivers/iio/proximity/nds03/nds03_iio.h b/drivers/iio/proximity/nds03/nds03_iio.h new file mode 100644 index 000000000000..9f17533d68a2 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_iio.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __NDS03_IIO_H +#define __NDS03_IIO_H + +#include +#include +#include + +struct nds03_iio_dev { + struct iio_dev *indio_dev; + struct nds03_context *ctx; + bool enabled; + struct work_struct enable_work; + struct work_struct disable_work; +}; + +enum nds03_iio_chan { + NDS03_IIO_CHAN_DISTANCE, + NDS03_IIO_CHAN_TIMESTAMP, +}; + +struct nds03_scan { + __le16 distance; + s64 ts; +}; + +int nds03_iio_init(struct nds03_context *ctx); +void nds03_iio_remove(struct nds03_context *ctx); +void nds03_iio_push_data(struct nds03_context *ctx, uint16_t distance_mm); + +#endif diff --git a/drivers/iio/proximity/nds03/nds03_module.c b/drivers/iio/proximity/nds03/nds03_module.c new file mode 100644 index 000000000000..4025ca087922 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_module.c @@ -0,0 +1,674 @@ + +/*! + @file nds03_module.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03.h" +#include "nds03_iio.h" + +/* Set default value to 1 to allow to see module insertion debug messages */ +int nds03_enable_debug = 0; + +static inline NDS03_Platform_t *to_nds03_platform(struct nds03_context *ctx) +{ + return &ctx->g_nds03_device.platform; +} +static inline NDS03_Dev_t * to_nds03_dev(struct nds03_context *ctx) +{ + return &ctx->g_nds03_device; +} + +int nds03_interrupt_config(NDS03_Dev_t *pNxDevice, uint8_t is_open) +{ + int8_t retval = 0; + + if (is_open) { + retval |= NDS03_SetGpio1Config(pNxDevice, + NDS03_GPIO1_NEW_MEASURE_READY, NDS03_GPIO1_POLARITY_LOW); + /* 连续模式开启测量 */ + retval |= NDS03_StartContinuousMeasurement(pNxDevice); + } else { + /* 连续模式关闭测量 */ + retval |= NDS03_StopContinuousMeasurement(pNxDevice); + /* 关闭测距中断 */ + retval |= NDS03_SetGpio1Config(pNxDevice, + NDS03_GPIO1_FUNCTIONALITY_OFF, NDS03_GPIO1_POLARITY_LOW); + } + return retval; +} +EXPORT_SYMBOL_GPL(nds03_interrupt_config); + +int nds03_sensor_init(struct nds03_context *ctx) +{ + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + + NDS03_Platform_t *pdev = to_nds03_platform(ctx); + /* 函数指针结构体 */ + + if (NDS03_ERROR_NONE != nds03_platform_init(pdev, ctx->client)) { + nds03_errmsg("nds03_platform init error\n"); + return -1; + } + /* 循环等待设备启动, 若模组或者IIC读写函数有问题则会报错 */ + if (NDS03_ERROR_NONE != NDS03_WaitDeviceBootUp(pNxDevice)) { + nds03_errmsg("NDS03_WaitDeviceBootUp error\r\n"); + return -1; + } + /** 判断是否为NDS03设备 */ + if (NDS03_ERROR_NONE != NDS03_IsNDS03(pNxDevice)) { + nds03_errmsg("The device is not NDS03, please change the device!\n"); + return -2; + } + /* 初始化模组设备 */ + if (NDS03_ERROR_NONE != NDS03_InitDevice(pNxDevice)) { + nds03_errmsg("NDS03_InitDevice error!!\r\n"); + return -3; + } + if (atomic_read(&ctx->meas_mode) == 0) + nds03_interrupt_config(pNxDevice, 1); + else + nds03_interrupt_config(pNxDevice, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_sensor_init); + +static void printf_ranging_data(NDS03_Dev_t *pNxDevice) +{ + nds03_info("ranging data start:\r\n"); + + nds03_info("dist start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].depth, pNxDevice->ranging_data[1].depth, + pNxDevice->ranging_data[2].depth, pNxDevice->ranging_data[3].depth); + nds03_info("dist end\r\n"); + + nds03_info("confi start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].confi, pNxDevice->ranging_data[1].confi, + pNxDevice->ranging_data[2].confi, pNxDevice->ranging_data[3].confi); + nds03_info("confi end\r\n"); + + nds03_info("count start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].count, pNxDevice->ranging_data[1].count, + pNxDevice->ranging_data[2].count, pNxDevice->ranging_data[3].count); + nds03_info("count end\r\n"); + + nds03_info("crate start:\r\n"); + nds03_info( + "%d %d %d %d\r\n", + pNxDevice->ranging_data[0].crate, pNxDevice->ranging_data[1].crate, + pNxDevice->ranging_data[2].crate, pNxDevice->ranging_data[3].crate); + nds03_info("crate end\r\n"); + + nds03_info("ranging data end\r\n"); +} + +static int32_t nds03_make_measure(struct nds03_context *ctx) +{ + int32_t ret = 0; + NDS03_Dev_t *pNxDevice = &ctx->g_nds03_device; + + mutex_lock(&ctx->work_mutex); + /* 获取测量数据 */ + if (atomic_read(&ctx->meas_mode)) + ret = NDS03_GetSingleRangingData(pNxDevice); + else + ret = NDS03_GetInterruptRangingData(pNxDevice); + + if (ret >= 0 && nds03_enable_debug) + printf_ranging_data(pNxDevice); + + mutex_unlock(&ctx->work_mutex); + + return ret; +} + +static int __ctrl_tof_start(struct nds03_context * ctx) +{ + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + atomic_set(&ctx->is_meas, 1); + + return 0; +} + +static int __ctrl_tof_stop(struct nds03_context * ctx) +{ + atomic_set(&ctx->is_meas, 0); + return 0; +} + +static int __ctrl_tof_reset(struct nds03_context * ctx) +{ + int ret = 0; + + __ctrl_tof_stop(ctx); + mutex_lock(&ctx->work_mutex); + ret = nds03_sensor_init(ctx); + if (ret != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + return ret; +} + +static int32_t tof_offset_calib(struct nds03_context *ctx, uint16_t calib_dist) +{ + int32_t i, cnt = 20; + int32_t depth_sum, depth_aver; + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + /* 将设备处于500mm处 */ + NDS03_StopContinuousMeasurement(pNxDevice); + msleep(100); + /* 串扰标定 */ + ctx->calib_result = NDS03_XtalkCalibration(pNxDevice); + if (NDS03_ERROR_NONE != ctx->calib_result) { + nds03_info("Xtalk calib error: %d\n", ctx->calib_result); + return -1; + } + /* Offset标定 */ + ctx->calib_result = NDS03_OffsetCalibrationAtDepth(pNxDevice, calib_dist); + if(NDS03_ERROR_NONE != ctx->calib_result) { + nds03_info("Offset calib error: %d\n", ctx->calib_result); + return -1; + } + /* 获取平均值 */ + NDS03_GetSingleRangingData(pNxDevice); + NDS03_GetSingleRangingData(pNxDevice); + depth_sum = 0; + for (i = 0; i < cnt; i++) { + if (NDS03_ERROR_NONE != NDS03_GetSingleRangingData(pNxDevice)) { + nds03_info("NDS03_GetSingleRangingData error!!\r\n"); + return -1; + } + depth_sum = depth_sum + (int32_t)(uint32_t)pNxDevice->ranging_data[0].depth; + } + depth_aver = depth_sum / cnt; + if (depth_aver < (calib_dist - 20) || depth_aver > (calib_dist + 20)) { + ctx->calib_result = NDS03_ERROR_RANGING; + nds03_info("NDS03 calibration fail!!\r\n"); + return -1; + } + nds03_info("NDS03 calibration success\r\n"); + return 0; +} + +static void report_meas_event(struct nds03_context * ctx) +{ + int retval = 0; + + retval = nds03_make_measure(ctx); + if (retval < 0) + return; + + uint16_t distance = ctx->g_nds03_device.ranging_data[0].depth; + nds03_iio_push_data(ctx, distance); +} + +static irqreturn_t tof_irq_handler_i2c(int vec, void *info) +{ + struct nds03_context *ctx = (struct nds03_context *)info; + bool is_meas = atomic_read(&ctx->is_meas); + + if (ctx->irq == vec && is_meas) + schedule_work(&ctx->irq_work); + + return IRQ_HANDLED; +} + +static void nds03_work_handler(struct work_struct *work) +{ + struct nds03_context *ctx = container_of(work, struct nds03_context, dwork.work); + + if (atomic_read(&ctx->meas_mode) && atomic_read(&ctx->is_meas)) { + nds03_make_measure(ctx); + schedule_delayed_work(&ctx->dwork, + msecs_to_jiffies(atomic_read(&ctx->poll_delay_ms))); + report_meas_event(ctx); + } +} + +static void nds03_measure_irq_work(struct work_struct *work) +{ + struct nds03_context *ctx = container_of(work, struct nds03_context, irq_work); + + report_meas_event(ctx); +} + +static ssize_t nds03_show_is_meas(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + return snprintf(buf, 10, "%d\n", atomic_read(&ctx->is_meas)); +} + +static ssize_t nds03_store_is_meas(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret = count; + + switch (buf[0]) { + case '0': + __ctrl_tof_stop(ctx); + break; + case '1': + __ctrl_tof_start(ctx); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + return ret ; +} + +static DEVICE_ATTR(is_meas, 0660, nds03_show_is_meas, nds03_store_is_meas); + +static ssize_t nds03_show_poll_delay_ms(struct device *dev, + struct device_attribute *attr, char *buf) +{ + uint32_t poll_ms; + struct nds03_context *ctx = dev_get_drvdata(dev); + + poll_ms = atomic_read(&ctx->poll_delay_ms); + return snprintf(buf, 10, "%d\n", poll_ms); +} + +static ssize_t nds03_store_poll_delay_ms(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret; + unsigned long delay_ms; + + ret = kstrtoul(buf, 10, &delay_ms); + if(ret < 0) { + nds03_warnmsg("Invalid input ctx\n"); + goto store_err; + } + atomic_set(&ctx->poll_delay_ms, delay_ms); + nds03_dbgmsg("Poll delay %lu ms\n", delay_ms); +store_err: + return ret < 0 ? -EINVAL : count; +} + +static DEVICE_ATTR(meas_delay_ms, 0660, nds03_show_poll_delay_ms, nds03_store_poll_delay_ms); + +static ssize_t nds03_show_meas_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n",atomic_read(&ctx->meas_mode)); +} + +static ssize_t nds03_store_meas_mode(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pNxDevice = to_nds03_dev(ctx); + int ret = count; + + mutex_lock(&ctx->work_mutex); + switch (buf[0]) { + case '0': + if(ctx->irq < 0){ + nds03_warnmsg("No support Interrupt\n"); + ret = -EINVAL; + } else { + atomic_set(&ctx->meas_mode, 0); + nds03_interrupt_config(pNxDevice, 1); + nds03_dbgmsg("Enter Interrupt Mode\n"); + } + break; + case '1': + atomic_set(&ctx->meas_mode, 1); + nds03_interrupt_config(pNxDevice, 0); + nds03_dbgmsg("Enter Poll Mode\n"); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + mutex_unlock(&ctx->work_mutex); + return ret ; +} +static DEVICE_ATTR(meas_mode, 0660, nds03_show_meas_mode, nds03_store_meas_mode); + +static ssize_t nds03_store_tof_reset(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret = 0; + + if(buf[0] == '1') + ret = __ctrl_tof_reset(ctx); + + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_reset, 0660, NULL, nds03_store_tof_reset); + +static ssize_t nds03_show_tof_calib(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n",ctx->calib_result); +} + +static ssize_t nds03_store_tof_calib(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int ret; + unsigned long calib_dis; + + mutex_lock(&ctx->work_mutex); + ret = kstrtoul(buf, 10, &calib_dis); + if(ret < 0) { + nds03_warnmsg("Invalid input ctx\n"); + ret = -EPERM; + goto store_err; + } + nds03_info("offset calib distance: %ld mm\n", calib_dis); + ret = tof_offset_calib(ctx, calib_dis); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + +store_err: + mutex_unlock(&ctx->work_mutex); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_calib, 0660, nds03_show_tof_calib, nds03_store_tof_calib); + +static ssize_t nds03_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 10, "%d\n", nds03_enable_debug); +} + +static ssize_t nds03_store_enable_debug(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + struct nds03_context *ctx = dev_get_drvdata(dev); + int32_t ret = 0; + + mutex_lock(&ctx->work_mutex); + switch (buf[0]) { + case '0': + nds03_enable_debug = 0; + nds03_info("close nds03 debug\n"); + break; + case '1': + nds03_enable_debug = 1; + nds03_info("open nds03 debug\n"); + break; + default: + nds03_warnmsg("Invalid value\n"); + ret = -EINVAL; + break; + } + mutex_unlock(&ctx->work_mutex); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(enable_debug, 0660, nds03_show_enable_debug, nds03_store_enable_debug); + +static ssize_t nds03_store_tof_pulsenum(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int ret; + unsigned long pulsenum; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + ret = kstrtoul(buf, 10, &pulsenum); + if (ret < 0) { + nds03_errmsg("Invalid input ctx\n"); + return -EPERM; + } + mutex_lock(&ctx->work_mutex); + ret = NDS03_SetPulseNum(pdev, pulsenum); + mutex_unlock(&ctx->work_mutex); + nds03_info("set tof pulsenum: %ld, ret: %d\n", pulsenum, ret); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_pulsenum, 0660, NULL, nds03_store_tof_pulsenum); + +static ssize_t nds03_show_tof_xtalk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret, count; + uint16_t xtalk_value; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + mutex_lock(&ctx->work_mutex); + ret = NDS03_GetXTalkValue(pdev, &xtalk_value); + if (ret < 0) + nds03_errmsg("get tof xtalk_value error\n"); + mutex_unlock(&ctx->work_mutex); + count = snprintf(buf, 10, "%d\n",xtalk_value); + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR(tof_xtalk, 0660, nds03_show_tof_xtalk, NULL); + +static ssize_t nds03_store_xtalk_calibration(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int32_t ret = 0; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + + if (sysfs_streq(buf, "1") || sysfs_streq(buf, "on") || + sysfs_streq(buf, "start")) { + mutex_lock(&ctx->work_mutex); + NDS03_StopContinuousMeasurement(pdev); + ret = NDS03_XtalkCalibration(pdev); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + if(ret < 0) { + nds03_errmsg("NDS03_XtalkCalibration error, ret = %d\n", ret); + return -EIO; + } + return count; + } else { + return -EINVAL; + } +} + +static DEVICE_ATTR(xtalk_calibration, 0660, NULL, nds03_store_xtalk_calibration); + +static ssize_t nds03_store_offset_calibration(struct device *dev, + struct device_attribute *attr, const char *buf,size_t count) +{ + int ret; + struct nds03_context *ctx = dev_get_drvdata(dev); + NDS03_Dev_t *pdev = to_nds03_dev(ctx); + int32_t calib_depth_mm_tmp = 0; + + ret = kstrtoint(buf, 10, &calib_depth_mm_tmp); + if (ret) + return -EINVAL; + + mutex_lock(&ctx->work_mutex); + NDS03_StopContinuousMeasurement(pdev); + ret = NDS03_OffsetCalibrationAtDepth(pdev, calib_depth_mm_tmp); + if (nds03_sensor_init(ctx) != 0) + nds03_errmsg("nds03 sensor init failed\n"); + + mutex_unlock(&ctx->work_mutex); + if (ret < 0) { + nds03_errmsg("NDS03_OffsetCalibrationAtDepth error, ret = %d\n", ret); + return -EIO; + } + + return count; +} + +static DEVICE_ATTR(offset_calibration, 0660, NULL, nds03_store_offset_calibration); + +static struct attribute *nds03_attributes[] = { + &dev_attr_is_meas.attr, + &dev_attr_meas_delay_ms.attr, + &dev_attr_meas_mode.attr, + &dev_attr_enable_debug.attr, + &dev_attr_tof_reset.attr, + &dev_attr_tof_calib.attr, + &dev_attr_tof_pulsenum.attr, + &dev_attr_tof_xtalk.attr, + &dev_attr_xtalk_calibration.attr, + &dev_attr_offset_calibration.attr, + NULL +}; + +static const struct attribute_group nds03_sysfs_groups = { + .attrs = nds03_attributes, +}; + +static void nds03_parse_device_tree(struct nds03_context *ctx) +{ + int32_t ret; + NDS03_Platform_t *pdev = to_nds03_platform(ctx); + + /* Initialize xshut gpio */ + pdev->xshut_gpio = devm_gpiod_get_optional(&ctx->client->dev, "xshut", GPIOD_OUT_HIGH); + if (IS_ERR(pdev->xshut_gpio)) { + ret = PTR_ERR(pdev->xshut_gpio); + nds03_warnmsg( "no xshut pin available, error = %d\n", ret); + return; + } else { + nds03_dbgmsg("get xshut pin success\n"); + } + + /* Initialize irq gpio*/ + atomic_set(&ctx->meas_mode, 1); //Default to polling mode + ctx->irq = -1; + pdev->intr_gpio = devm_gpiod_get_optional(&ctx->client->dev, "intr", GPIOD_IN); + if (IS_ERR(pdev->intr_gpio)) { + ret = PTR_ERR(pdev->intr_gpio); + nds03_warnmsg( "no intr pin available, error = %d\n", ret); + return; + } + nds03_dbgmsg("get intr pin success\n"); + ctx->irq = ctx->client->irq; + if (ctx->irq) { + unsigned long default_trigger = irqd_get_trigger_type(irq_get_irq_data(ctx->irq)); + ret = devm_request_threaded_irq(&ctx->client->dev, + ctx->irq, NULL, + tof_irq_handler_i2c, + default_trigger|IRQF_ONESHOT, + "nds03_interrupt", + (void *)ctx); + if (ret) { + nds03_errmsg("fail to req threaded irq rc=%d\n", ret); + } else { + nds03_info( + "request irq success, irq mode use, irq num: %d, type: %lu", + ctx->irq, default_trigger); + atomic_set(&ctx->meas_mode, 0); //Configure in interrupt mode + } + } else { + void *poll_interval_dt = NULL; + uint32_t delay_ms; + nds03_info("no irq number specified, polling mode is used\n"); + poll_interval_dt = (void *)of_get_property(ctx->client->dev.of_node, + "nds03_poll_interval", + NULL); + delay_ms = poll_interval_dt ? be32_to_cpup(poll_interval_dt) : 0; + + nds03_dbgmsg("poll delay ms:%d\n", delay_ms); + + atomic_set(&ctx->poll_delay_ms, delay_ms); + } +} + +int nds03_common_probe(struct nds03_context * ctx) +{ + int ret = 0; + u32 i2c_freq = 0; + // struct input_dev *input; + + /* Initialize mutex */ + mutex_init(&ctx->work_mutex); + + /* init work handler */ + INIT_DELAYED_WORK(&ctx->dwork, nds03_work_handler); + + INIT_WORK(&ctx->irq_work, nds03_measure_irq_work); + + atomic_set(&ctx->is_meas, 0); + + /* Parse the device tree for NDS03 sensor configuration. */ + nds03_parse_device_tree(ctx); + of_property_read_u32(ctx->client->adapter->dev.of_node, "clock-frequency", &i2c_freq); + pr_info("I2C bus number is %d, bus speed: %u Hz\n", ctx->client->adapter->nr, i2c_freq); + + ret = nds03_iio_init(ctx); + if (ret) { + nds03_errmsg("IIO init failed: %d\n", ret); + goto err_iio; + } + ctx->fd_open_count = 0; + + nds03_dbgmsg("create sysfs group successfully\n"); + + /* Initialize nds03 sensor */ + ret = nds03_sensor_init(ctx); + if (ret != 0 ) { + nds03_errmsg("Failed to init nds03 sensor error:%d\n", ret); + goto err_iio; + } + nds03_dbgmsg("init nds03 sensor successfully\n"); + + ret = sysfs_create_group(&ctx->client->dev.kobj, &nds03_sysfs_groups); + if (ret) { + nds03_errmsg("Failed to create sysfs group error:%d\n", ret); + goto exit_err; + } + ctx->remove_flag = false; + nds03_dbgmsg("register chardev successfully\n"); + + nds03_info("nds03 module registered successfully\n"); + nds03_info( "NDS03 Driver version: %s \n", DRIVER_VERSION); + return 0; + +err_iio: + nds03_iio_remove(ctx); + +exit_err: + return ret; +} +EXPORT_SYMBOL_GPL(nds03_common_probe); + +int nds03_common_remove(struct nds03_context * ctx) +{ + nds03_dbgmsg("Enter %s \n", __FUNCTION__); + cancel_delayed_work(&ctx->dwork); + ctx->remove_flag = true; + sysfs_remove_group(&ctx->client->dev.kobj, &nds03_sysfs_groups); + nds03_iio_remove(ctx); + + return 0; +} +EXPORT_SYMBOL_GPL(nds03_common_remove); diff --git a/drivers/iio/proximity/nds03/nds03_module_i2c.c b/drivers/iio/proximity/nds03/nds03_module_i2c.c new file mode 100644 index 000000000000..7ec4288479ca --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_module_i2c.c @@ -0,0 +1,99 @@ +/*! + @file nds03_module_i2c.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03.h" +#include "nds03_platform.h" + +struct nds03_context *nds03_context_obj = NULL; + +// int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int nds03_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct device *dev = &client->dev; + struct nds03_context * ctx = NULL; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if(IS_ERR(ctx)) { + nds03_errmsg("nds03_data memory allocation failed\n"); + ret = -ENOMEM; + goto module_reg_err; + } + + nds03_context_obj = ctx; + ctx->client = client; + + ret = nds03_common_probe(ctx); + if(ret != 0) { + nds03_errmsg("Failed to register nds03 module: %d\n", ret); + goto module_reg_err; + } + i2c_set_clientdata(client, ctx); + return 0; + +module_reg_err: + return ret; +} + +static void nds03_i2c_remove(struct i2c_client *client) +{ + struct nds03_context * ctx = i2c_get_clientdata(client); + nds03_common_remove(ctx); + // return 0; +} + +static const struct i2c_device_id tof_nds03_id[] = { + {TOF_NDS03_DRV_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tof_nds03_id); + +static const struct of_device_id tof_nds03_dt_match[] = { + { .compatible = "nx,"TOF_NDS03_DRV_NAME, }, + { } +}; +MODULE_DEVICE_TABLE(of, tof_nds03_dt_match); + +static struct i2c_driver tof_nds03_driver = { + .driver = { + .name = TOF_NDS03_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tof_nds03_dt_match, + }, + .probe = nds03_i2c_probe, + .remove = nds03_i2c_remove, + .id_table = tof_nds03_id, + +}; + +static int __init tof_nds03_init_i2c(void) +{ + int ret = 0; + + nds03_dbgmsg("Enter\n"); + ret = i2c_add_driver(&tof_nds03_driver); + if (ret) + nds03_errmsg("%d erro ret:%d\n", __LINE__, ret); + return ret; +} + +static void __exit tof_nds03_exit_i2c(void ) +{ + nds03_dbgmsg("Exit\n"); + i2c_del_driver(&tof_nds03_driver); +} + +module_init(tof_nds03_init_i2c); +module_exit(tof_nds03_exit_i2c); + +MODULE_DESCRIPTION("Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/iio/proximity/nds03/nds03_platform.c b/drivers/iio/proximity/nds03/nds03_platform.c new file mode 100644 index 000000000000..e3552fe7e7e0 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_platform.c @@ -0,0 +1,117 @@ +/*! + @file nds03_platform.c + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#include "nds03_platform.h" + +int8_t nds03_platform_init(NDS03_Platform_t *pdev, void * client) +{ + pdev->client = (struct i2c_client *)client; + pdev->i2c_dev_addr = 0X5C; + + return 0; +} + +int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void * param) +{ + return 0; +} + +int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len) +{ + int8_t ret; + struct i2c_msg i2c_message[2]; + uint8_t i2c_buf[256]; + + i2c_buf[0] = i2c_raddr; + i2c_message[0].addr = pDev->i2c_dev_addr; + i2c_message[0].buf = i2c_buf; + i2c_message[0].len = 1; + i2c_message[0].flags = 0 ; //| I2C_M_STOP;//I2C_M_STOP; + + i2c_message[1].addr = pDev->i2c_dev_addr; + i2c_message[1].buf = i2c_rdata; + i2c_message[1].len = len; + i2c_message[1].flags = I2C_M_RD; + ret = i2c_transfer(pDev->client->adapter, i2c_message, 2); + if (ret != 2) { + pr_err("NDS03: i2c read error, i2c_raddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_raddr, ret); + return -EIO; + } + return 0; + +} + +int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len) +{ + int32_t ret; + struct i2c_msg i2c_message; + //For user implement + uint8_t i2c_buf[256]; + + memcpy(&i2c_buf[1], i2c_wdata, len); + i2c_buf[0] = i2c_waddr; + + i2c_message.addr = pDev->i2c_dev_addr; + i2c_message.buf = i2c_buf; + i2c_message.len = len + 1; + i2c_message.flags = 0; + ret = i2c_transfer(pDev->client->adapter, &i2c_message, 1); + if (ret != 1) { + pr_err("NDS03: i2c write error, i2c_waddr: 0x%x, reg: 0x%x, ret: %d", pDev->i2c_dev_addr, i2c_waddr, ret); + return -EIO; + } + return 0; + +} + +int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us) +{ + wait_10us *= 10; + if (wait_10us < 10) + udelay(wait_10us); + else if (wait_10us < 20000) + usleep_range(wait_10us, wait_10us + 1); + else + msleep(wait_10us / 1000); + return 0; +} + +int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms) +{ + nds03_delay_10us(pDev, wait_ms * 100); + return 0; +} + +int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level) +{ + if (pDev->xshut_gpio == NULL) { + pr_err("xshut_gpiod is not init , not setting xshut\n"); + return -1; + } + gpiod_set_value(pDev->xshut_gpio, level); + // pr_info("xshut set to %d\n", level); + return 0; +} + +int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency) +{ + return 0; +} + +int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency) +{ + return 0; +} + +int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms) +{ + return 0; +} diff --git a/drivers/iio/proximity/nds03/nds03_platform.h b/drivers/iio/proximity/nds03/nds03_platform.h new file mode 100644 index 000000000000..56d68d1ff057 --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_platform.h @@ -0,0 +1,137 @@ +/*! + @file nds03_platform.h + @brief + @author lull + @date 2025-06 + @copyright Copyright (c) 2025 Shenzhen Nephotonics Semiconductor Technology Co., Ltd. + @license BSD 3-Clause License + This file is part of the Nephotonics sensor SDK. + It is licensed under the BSD 3-Clause License. + A copy of the license can be found in the project root directory, in the file named LICENSE. + */ +#ifndef __NDS03_PLATFORM__H__ +#define __NDS03_PLATFORM__H__ + +#include "nds03_stdint.h" +#include +#include +#include +#include +/** + * @struct NDS03_Platform_t + * + * @brief NDS03平台相关定义 \n + * 定义i2c地址等,注意必须定义i2c地址 + */ +typedef struct{ + //文件描述符 + int fd; + /** 用户不可更改以下变量 @{ */ + uint8_t i2c_dev_addr; // i2c设备地址 + /** @} */ + /** 用户可根据需要添加变量 */ + struct i2c_client *client; + ////// /* nds03 device io */ + struct gpio_desc *intr_gpio; + /*!< xsdn reset (low active) gpio number to device */ + struct gpio_desc *xshut_gpio; + +} NDS03_Platform_t; + +/** + * @brief NDS03平台初始化 + * + * @param pDev 平台设备指针 + * @param void* 拓展指针 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_platform_init(NDS03_Platform_t *pdev, void *); + +/** + * @brief NDS03平台释放 + * + * @param pDev 平台设备指针 + * @param void* 拓展指针 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_platform_uninit(NDS03_Platform_t *pdev, void *); + +/** + * @brief I2C读一个字节 + * + * @param pDev 平台设备指针 + * @param i2c_raddr 读寄存器地址 + * @param i2c_rdata 读数据 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_i2c_read_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_raddr, uint8_t *i2c_rdata, uint16_t len); + +/** + * @brief I2C写一个字节 + * + * @param pDev 平台设备指针 + * @param i2c_waddr 写寄存器地址 + * @param i2c_wdata 写数据 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_i2c_write_nbytes(NDS03_Platform_t *pDev, uint8_t i2c_waddr, uint8_t *i2c_wdata, uint16_t len); + +/** + * @brief 延时wait_ms毫秒 + * + * @param pDev 平台设备指针 + * @param wait_ms 输入需要延时时长 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_delay_1ms(NDS03_Platform_t *pDev, uint32_t wait_ms); + +/** + * @brief 延时10*wait_10us微秒 + * + * @param pDev 平台设备指针 + * @param wait_10us 输入需要延时时长 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_delay_10us(NDS03_Platform_t *pDev, uint32_t wait_10us); + +/** + * @brief 设置nds03 xshut引脚电平 + * + * @param pDev 平台设备指针 + * @param level 引脚电平,0为低电平,1为高电平 + * @return int8_t + * @retval 0:成功, 其他:失败 + */ +int8_t nds03_set_xshut_pin_level(NDS03_Platform_t *pDev, int8_t level); + +/*! + @brief NDS03获取当前i2c时钟频率 + @param pDev 平台设备指针 + @param clock_frequency 时钟频率指针 + @return int8_t + */ +int8_t nds03_i2c_get_clock_frequency(NDS03_Platform_t *pDev, uint32_t *clock_frequency); + +/*! + @brief NDS03设置当前i2c时钟频率 + @param pDev 平台设备指针 + @param clock_frequency 时钟频率指针 + @return int8_t + */ +int8_t nds03_i2c_set_clock_frequency(NDS03_Platform_t *pDev, uint32_t clock_frequency); +/*! + @brief 获取当前系统时间,单位ms + @param pDev + @param time_ms + @return int8_t + */ +int8_t nds03_get_system_clk_ms(NDS03_Platform_t *pDev, int32_t *time_ms); + +#endif + diff --git a/drivers/iio/proximity/nds03/nds03_stdint.h b/drivers/iio/proximity/nds03/nds03_stdint.h new file mode 100644 index 000000000000..c4657b0e98cd --- /dev/null +++ b/drivers/iio/proximity/nds03/nds03_stdint.h @@ -0,0 +1,95 @@ + +/** + * @file nds03_stdint.h + * @author tongsheng.tang + * @brief NDS03 platform-specific integer type definitions + * @version 2.x.x + * @date 2025-06 + * + * @copyright Copyright (c) 2025, Nephotonics Information Technology (Hefei) Co., Ltd. + * + * @license BSD 3-Clause License + * This file is part of the NDS03 SDK and is licensed under the BSD 3-Clause License. + * You may obtain a copy of the license in the project root directory, in the file named LICENSE. + * + */ +#ifndef __NDS03_STDINT_H__ +#define __NDS03_STDINT_H__ + +#define PLATFORM_C51 0 +#define PLATFORM_NOT_C51 1 +#define PLATFORM_LINUX_DRIVER 2 +#ifndef NDS03_PLATFORM +#define NDS03_PLATFORM PLATFORM_LINUX_DRIVER +#endif + +#if NDS03_PLATFORM == PLATFORM_NOT_C51 +#include + +#elif NDS03_PLATFORM == PLATFORM_C51 + /* exact-width signed integer types */ + typedef signed char int8_t; + typedef signed int int16_t; + typedef signed long int32_t; + + /* exact-width unsigned integer types */ + typedef unsigned char uint8_t; + typedef unsigned int uint16_t; + typedef unsigned long uint32_t; + + #define __func__ __FILE__ + + /* minimum values of exact-width signed integer types */ + #define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ + + /* maximum values of exact-width signed integer types */ + #define INT32_MAX 2147483647 + + /* maximum values of exact-width unsigned integer types */ + #define UINT32_MAX 4294967295u + + /* 7.18.2.2 */ + + /* minimum values of minimum-width signed integer types */ + #define INT_LEAST32_MIN (~0x7fffffff) + + /* maximum values of minimum-width signed integer types */ + #define INT_LEAST32_MAX 2147483647 + + /* maximum values of minimum-width unsigned integer types */ + #define UINT_LEAST32_MAX 4294967295u + + /* 7.18.2.3 */ + + /* minimum values of fastest minimum-width signed integer types */ + #define INT_FAST32_MIN (~0x7fffffff) + + /* maximum values of fastest minimum-width signed integer types */ + #define INT_FAST32_MAX 2147483647 + + /* maximum values of fastest minimum-width unsigned integer types */ + #define UINT_FAST32_MAX 4294967295u +#elif NDS03_PLATFORM == PLATFORM_LINUX_DRIVER + /* exact-width signed integer types */ +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +/* exact-width unsigned integer types */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#define __func__ __FILE__ + +/* minimum values of exact-width signed integer types */ +#define INT32_MIN (~0x7fffffff) /* -2147483648 is unsigned */ +/* maximum values of exact-width signed integer types */ +#define INT32_MAX 2147483647 + +/* maximum values of exact-width unsigned integer types */ +#define UINT32_MAX 4294967295u +#endif + +#endif /** __NDS03_STDINT_H__ */ +