From 482d17f235ecbb013abc8cc6622b2aa35b625c34 Mon Sep 17 00:00:00 2001 From: Jhan BoChao Date: Tue, 11 Mar 2025 15:57:50 +0800 Subject: [PATCH] driver: sensor: add tachometer driver for rts5912 Add tachometer driver for Realtek rts5912. Signed-off-by: Jhan BoChao --- boards/realtek/rts5912_evb/rts5912_evb.dts | 7 + drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/realtek/CMakeLists.txt | 4 + drivers/sensor/realtek/Kconfig | 4 + drivers/sensor/realtek/rts5912/CMakeLists.txt | 6 + drivers/sensor/realtek/rts5912/Kconfig | 9 ++ drivers/sensor/realtek/rts5912/rts5912.c | 150 ++++++++++++++++++ dts/arm/realtek/ec/rts5912.dtsi | 9 ++ dts/bindings/tach/realtek,rts5912-tach.yaml | 28 ++++ soc/realtek/ec/rts5912/reg/reg_tacho.h | 42 +++++ 11 files changed, 261 insertions(+) create mode 100644 drivers/sensor/realtek/CMakeLists.txt create mode 100644 drivers/sensor/realtek/Kconfig create mode 100644 drivers/sensor/realtek/rts5912/CMakeLists.txt create mode 100644 drivers/sensor/realtek/rts5912/Kconfig create mode 100644 drivers/sensor/realtek/rts5912/rts5912.c create mode 100644 dts/bindings/tach/realtek,rts5912-tach.yaml create mode 100644 soc/realtek/ec/rts5912/reg/reg_tacho.h diff --git a/boards/realtek/rts5912_evb/rts5912_evb.dts b/boards/realtek/rts5912_evb/rts5912_evb.dts index 7f40c19b219..15d3b5357f1 100644 --- a/boards/realtek/rts5912_evb/rts5912_evb.dts +++ b/boards/realtek/rts5912_evb/rts5912_evb.dts @@ -53,3 +53,10 @@ &swj_port { status = "okay"; }; + +&tach0 { + status = "okay"; + pinctrl-0 = <&tacho0_gpio052>; + pinctrl-names = "default"; + pulses-per-round = <2>; +}; diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index c05b37c5971..7b26ff5d2fa 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(nordic) add_subdirectory(nuvoton) add_subdirectory(nxp) add_subdirectory(pixart) +add_subdirectory(realtek) add_subdirectory(renesas) add_subdirectory(rohm) add_subdirectory(seeed) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index da03d104454..8cda03acc08 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -108,6 +108,7 @@ source "drivers/sensor/nordic/Kconfig" source "drivers/sensor/nuvoton/Kconfig" source "drivers/sensor/nxp/Kconfig" source "drivers/sensor/pixart/Kconfig" +source "drivers/sensor/realtek/Kconfig" source "drivers/sensor/renesas/Kconfig" source "drivers/sensor/rohm/Kconfig" source "drivers/sensor/seeed/Kconfig" diff --git a/drivers/sensor/realtek/CMakeLists.txt b/drivers/sensor/realtek/CMakeLists.txt new file mode 100644 index 00000000000..c69984afe4a --- /dev/null +++ b/drivers/sensor/realtek/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2025, Realtek, SIBG-SD7 +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_TACH_RTS5912 rts5912) diff --git a/drivers/sensor/realtek/Kconfig b/drivers/sensor/realtek/Kconfig new file mode 100644 index 00000000000..bca4a9dcc89 --- /dev/null +++ b/drivers/sensor/realtek/Kconfig @@ -0,0 +1,4 @@ +# Copyright (c) 2025, Realtek, SIBG-SD7 +# SPDX-License-Identifier: Apache-2.0 + +source "drivers/sensor/realtek/rts5912/Kconfig" diff --git a/drivers/sensor/realtek/rts5912/CMakeLists.txt b/drivers/sensor/realtek/rts5912/CMakeLists.txt new file mode 100644 index 00000000000..bc870db466b --- /dev/null +++ b/drivers/sensor/realtek/rts5912/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2025, Realtek, SIBG-SD7 +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(rts5912.c) diff --git a/drivers/sensor/realtek/rts5912/Kconfig b/drivers/sensor/realtek/rts5912/Kconfig new file mode 100644 index 00000000000..649567dfab1 --- /dev/null +++ b/drivers/sensor/realtek/rts5912/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Realtek, SIBG-SD7 +# SPDX-License-Identifier: Apache-2.0 + +config TACH_RTS5912 + bool "RTS5912 Tachometer sensor" + default y + depends on DT_HAS_REALTEK_RTS5912_TACH_ENABLED + help + Enable the Realtek RTS5912 tachometer sensor. diff --git a/drivers/sensor/realtek/rts5912/rts5912.c b/drivers/sensor/realtek/rts5912/rts5912.c new file mode 100644 index 00000000000..5b6fcf740d2 --- /dev/null +++ b/drivers/sensor/realtek/rts5912/rts5912.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2025 Realtek, SIBG-SD7 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT realtek_rts5912_tach + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "reg/reg_tacho.h" + +LOG_MODULE_REGISTER(tach_rts5912, CONFIG_SENSOR_LOG_LEVEL); + +struct tach_rts5912_config { + volatile struct tacho_regs *regs; + uint32_t clk_grp; + uint32_t clk_idx; + uint32_t clk_src; + uint32_t clk_div; + const struct device *clk_dev; + const struct pinctrl_dev_config *pcfg; + int pulses_per_round; +}; + +struct tach_rts5912_data { + uint16_t count; +}; + +#define COUNT_100KHZ_SEC 100000U +#define SEC_TO_MINUTE 60U +#define PIN_STUCK_TIMEOUT (100U * USEC_PER_MSEC) + +int tach_rts5912_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct tach_rts5912_config *const cfg = dev->config; + struct tach_rts5912_data *const data = dev->data; + volatile struct tacho_regs *const tach = cfg->regs; + + if (chan != SENSOR_CHAN_RPM && chan != SENSOR_CHAN_ALL) { + return -ENOTSUP; + } + + tach->status = TACHO_STS_CNTRDY; + + if (WAIT_FOR(tach->status & TACHO_STS_CNTRDY, PIN_STUCK_TIMEOUT, k_msleep(1))) { + /* See whether internal counter is already latched */ + if (tach->status & TACHO_STS_CNTRDY) { + tach->status = TACHO_STS_CNTRDY; + data->count = (tach->ctrl & TACHO_CTRL_CNT_Msk) >> TACHO_CTRL_CNT_Pos; + } + } else { + data->count = 0; + } + + return 0; +} + +static int tach_rts5912_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + const struct tach_rts5912_config *const cfg = dev->config; + struct tach_rts5912_data *const data = dev->data; + + if (chan != SENSOR_CHAN_RPM) { + return -ENOTSUP; + } + + /* Convert the count per 100khz cycles to rpm */ + if (data->count != 0U) { + val->val1 = + (SEC_TO_MINUTE * COUNT_100KHZ_SEC) / (cfg->pulses_per_round * data->count); + } else { + val->val1 = 0U; + } + + val->val2 = 0U; + + return 0; +} + +static int tach_rts5912_init(const struct device *dev) +{ + const struct tach_rts5912_config *const cfg = dev->config; + volatile struct tacho_regs *const tach = cfg->regs; + int ret; + + struct rts5912_sccon_subsys sccon_subsys = { + .clk_grp = cfg->clk_grp, + .clk_idx = cfg->clk_idx, + }; + + if (!device_is_ready(cfg->clk_dev)) { + return -ENODEV; + } + + ret = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&sccon_subsys); + if (ret != 0) { + LOG_ERR("RTS5912 Tachometer clock control failed (%d)", ret); + return ret; + } + +#ifdef CONFIG_PINCTRL + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + + if (ret != 0) { + LOG_ERR("RTS5912 pinctrl failed (%d)", ret); + return ret; + } +#endif + + /* write one clear the status */ + tach->status = TACHO_STS_LIMIT | TACHO_STS_CHG | TACHO_STS_CNTRDY; + tach->ctrl &= ~TACHO_CTRL_SELEDGE_Msk; + tach->ctrl = ((0x01ul << TACHO_CTRL_SELEDGE_Pos) | TACHO_CTRL_READMODE | TACHO_CTRL_EN); + + return 0; +} + +static DEVICE_API(sensor, tach_rts5912_driver_api) = { + .sample_fetch = tach_rts5912_sample_fetch, + .channel_get = tach_rts5912_channel_get, +}; + +#define REALTEK_TACH_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + \ + static const struct tach_rts5912_config tach_cfg_##inst = { \ + .regs = (struct tacho_regs *const)DT_INST_REG_ADDR(inst), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .clk_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \ + .clk_grp = DT_INST_CLOCKS_CELL_BY_NAME(inst, tacho, clk_grp), \ + .clk_idx = DT_INST_CLOCKS_CELL_BY_NAME(inst, tacho, clk_idx), \ + .pulses_per_round = DT_INST_PROP(inst, pulses_per_round), \ + }; \ + \ + static struct tach_rts5912_data tach_data_##inst; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, tach_rts5912_init, NULL, &tach_data_##inst, \ + &tach_cfg_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ + &tach_rts5912_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(REALTEK_TACH_INIT) diff --git a/dts/arm/realtek/ec/rts5912.dtsi b/dts/arm/realtek/ec/rts5912.dtsi index 28419a1f1d0..bb022acbf72 100644 --- a/dts/arm/realtek/ec/rts5912.dtsi +++ b/dts/arm/realtek/ec/rts5912.dtsi @@ -267,6 +267,15 @@ interrupt-parent = <&nvic>; status = "disabled"; }; + + tach0: tach@4000fd00 { + compatible = "realtek,rts5912-tach"; + reg = <0x4000fd00 0x40>; + clocks = <&sccon RTS5912_SCCON_PERIPH_GRP0 PERIPH_GRP0_TACH0_CLKPWR>; + clock-names = "tacho"; + interrupts = <192 0>; + status = "disabled"; + }; }; swj_port: swj-port { diff --git a/dts/bindings/tach/realtek,rts5912-tach.yaml b/dts/bindings/tach/realtek,rts5912-tach.yaml new file mode 100644 index 00000000000..1d72ce8bb0b --- /dev/null +++ b/dts/bindings/tach/realtek,rts5912-tach.yaml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2025 Realtek Semiconductor Corporation, SIBG-SD7 +# + +description: Realtek rts5912 tachometer controller + +compatible: "realtek,rts5912-tach" + +include: [tach.yaml, pinctrl-device.yaml, sensor-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + pulses-per-round: + type: int + required: true + description: number of pulses per round of tachometer's input diff --git a/soc/realtek/ec/rts5912/reg/reg_tacho.h b/soc/realtek/ec/rts5912/reg/reg_tacho.h new file mode 100644 index 00000000000..4e7b9d0851f --- /dev/null +++ b/soc/realtek/ec/rts5912/reg/reg_tacho.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 Realtek, SIBG-SD7 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SOC_REALTEK_RTS5912_REG_TACHO_H +#define ZEPHYR_SOC_REALTEK_RTS5912_REG_TACHO_H + +struct tacho_regs { + uint32_t ctrl; + uint32_t status; + uint32_t limit_high; + uint32_t limit_low; + uint32_t int_en; +}; + +/* CTRL */ +#define TACHO_CTRL_EN BIT(0UL) +#define TACHO_CTRL_FILTEREN BIT(1UL) +#define TACHO_CTRL_SELEDGE_Pos (2UL) +#define TACHO_CTRL_SELEDGE_Msk GENMASK(3, TACHO_CTRL_SELEDGE_Pos) +#define TACHO_CTRL_READMODE BIT(4UL) +#define TACHO_CTRL_CNT_Pos (16UL) +#define TACHO_CTRL_CNT_Msk GENMASK(31, TACHO_CTRL_CNT_Pos) +/* STS */ +#define TACHO_STS_LIMIT BIT(0UL) +#define TACHO_STS_PIN BIT(1UL) +#define TACHO_STS_CHG BIT(2UL) +#define TACHO_STS_CNTRDY BIT(3UL) +/* LIMITH */ +#define TACHO_LIMITH_VAL_Pos (0UL) +#define TACHO_LIMITH_VAL_Msk GENMASK(15, TACHO_LIMITH_VAL_Pos) +/* LIMITL */ +#define TACHO_LIMITL_VAL_Pos (0UL) +#define TACHO_LIMITL_VAL_Msk GENMASK(15, TACHO_LIMITL_VAL_Pos) +/* INTEN */ +#define TACHO_INTEN_LIMITEN BIT(0UL) +#define TACHO_INTEN_CNTRDYEN BIT(1UL) +#define TACHO_INTEN_CHGEN BIT(2UL) + +#endif /* ZEPHYR_SOC_REALTEK_RTS5912_REG_TACHO_H */