Skip to content

Commit eb99158

Browse files
RuibinChangkartben
authored andcommitted
drivers/sensor/ite/tach/it51xxx: implement tachometer driver
Implement tachometer driver for ITE it51xxx series chip. Signed-off-by: Ruibin Chang <[email protected]>
1 parent e6bb7fc commit eb99158

File tree

10 files changed

+329
-0
lines changed

10 files changed

+329
-0
lines changed

boards/ite/it515xx_evb/it515xx_evb.dts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,12 @@
110110
pinctrl-0 = <&adc0_ch3_gpi3_default>;
111111
pinctrl-names = "default";
112112
};
113+
114+
/* test fan tachometer sensor */
115+
&tach0 {
116+
status = "okay";
117+
input-pin = <IT51XXX_TACH_INPUT_PIN_A>;
118+
pulses-per-round = <2>;
119+
pinctrl-0 = <&tach0a_gpd6_default>;
120+
pinctrl-names = "default";
121+
};

drivers/sensor/ite/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
# zephyr-keep-sorted-start
5+
add_subdirectory_ifdef(CONFIG_TACH_IT51XXX ite_tach_it51xxx)
56
add_subdirectory_ifdef(CONFIG_TACH_IT8XXX2 ite_tach_it8xxx2)
67
add_subdirectory_ifdef(CONFIG_VCMP_IT8XXX2 ite_vcmp_it8xxx2)
78
# zephyr-keep-sorted-stop

drivers/sensor/ite/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
# zephyr-keep-sorted-start
5+
source "drivers/sensor/ite/ite_tach_it51xxx/Kconfig"
56
source "drivers/sensor/ite/ite_tach_it8xxx2/Kconfig"
67
source "drivers/sensor/ite/ite_vcmp_it8xxx2/Kconfig"
78
# zephyr-keep-sorted-stop
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources(tach_ite_it51xxx.c)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2025 ITE Technology Corporation.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config TACH_IT51XXX
5+
bool "ITE it51xxx Tachometer sensor"
6+
default y
7+
depends on DT_HAS_ITE_IT51XXX_TACH_ENABLED
8+
depends on SOC_IT51XXX
9+
select PINCTRL
10+
help
11+
Enable the ITE it51xxx tachometer sensor,
12+
it51xxx supports three 16-bit tachometer sensor, each sensor has two
13+
input pin, and we need to select one input from them.
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* Copyright (c) 2025 ITE Technology Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ite_it51xxx_tach
8+
9+
/**
10+
* @file
11+
* @brief ITE it51xxx tachometer sensor module driver
12+
*
13+
* This file contains a driver for the tachometer sensor module which contains
14+
* three independent counters (T0L/MR, T1L/MR and T2L/MR). The content of the
15+
* Tachometer Reading Register is still update based on the sampling counter
16+
* that samples the tachometer input (T0A, T0B, T1A, T1B, T2A or T2B pins).
17+
* The following is block diagram of this module:
18+
*
19+
* Sample Rate = TACH_FREQ / 128
20+
* |
21+
* | Tachometer 0 | T0A (GPD6)
22+
* | | | +-----------+ |
23+
* | +-----+-----+ | | _ _ |<--+
24+
* |------>| T0L/MR |<-+-| | |_| |_ |<--+
25+
* | +-----------+ +-----------+ |
26+
* | capture pulses T0B (GPC6)
27+
* | in sample rate
28+
* | period
29+
* |
30+
* | Sample Rate = TACH_FREQ / 128
31+
* +-----------+ | |
32+
* Crystal-->| Prescaler |--->| Tachometer 1 | T1A (GPD7)
33+
* 32.768k +-----------+ | | | +-----------+ |
34+
* | +-----+-----+ | | _ _ |<--+
35+
* |------>| T1L/MR |<-+-| | |_| |_ |<--+
36+
* | +-----------+ +-----------+ |
37+
* | capture pulses T1B (GPJ6)
38+
* | in sample rate
39+
* | period
40+
* |
41+
* | Sample Rate = TACH_FREQ / 128
42+
* | |
43+
* | Tachometer 2 | T2A (GPJ0)
44+
* | | | +-----------+ |
45+
* | +-----+-----+ | | _ _ |<--+
46+
* |------>| T2L/MR |<-+-| | |_| |_ |<--+
47+
* | +-----------+ +-----------+ |
48+
* | capture pulses T2B (GPJ1)
49+
* | in sample rate
50+
* | period
51+
* |
52+
*
53+
*
54+
* Based on the counter value, we can compute the current RPM of external signal
55+
* from encoders.
56+
*/
57+
58+
#include <zephyr/device.h>
59+
#include <zephyr/drivers/pinctrl.h>
60+
#include <zephyr/drivers/sensor.h>
61+
#include <zephyr/dt-bindings/sensor/it51xxx_tach.h>
62+
#include <errno.h>
63+
#include <soc.h>
64+
#include <soc_dt.h>
65+
66+
#include <zephyr/logging/log.h>
67+
LOG_MODULE_REGISTER(tach_ite_it51xxx, CONFIG_SENSOR_LOG_LEVEL);
68+
69+
#define TACH_FREQ IT51XXX_EC_FREQ
70+
71+
/* 0xC0/0xD0/0xE0: Tach channel 0~2 tachometer speed (2 bytes value) */
72+
#define REG_TACH_CH 0x00
73+
/* 0xC6/0xD6/0xE6: Tach channel 0~2 control 1 */
74+
#define REG_TACH_CH_CTRL1 0x06
75+
#define TACH_CH_DVS BIT(1)
76+
#define TACH_CH_SEL BIT(0)
77+
78+
struct tach_it51xxx_config {
79+
/* Tach channel register base address */
80+
uintptr_t base;
81+
/* Tachometer alternate configuration */
82+
const struct pinctrl_dev_config *pcfg;
83+
/* Select input pin to tachometer */
84+
int input_pin;
85+
/* Number of pulses per round of tachometer's input */
86+
int pulses_per_round;
87+
};
88+
89+
struct tach_it51xxx_data {
90+
/* Captured counts of tachometer */
91+
uint16_t capture;
92+
};
93+
94+
static bool tach_ch_is_valid(const struct device *dev, int input_pin)
95+
{
96+
const struct tach_it51xxx_config *const config = dev->config;
97+
const uintptr_t base = config->base;
98+
uint8_t reg_val;
99+
100+
if (input_pin > IT51XXX_TACH_INPUT_PIN_B) {
101+
LOG_ERR("Tach input pin %d invalid, only support 0(A) or 1(B)", input_pin);
102+
return false;
103+
}
104+
105+
reg_val = sys_read8(base + REG_TACH_CH_CTRL1);
106+
if (((reg_val & TACH_CH_SEL) == input_pin) && (reg_val & TACH_CH_DVS)) {
107+
/* Input pin match register setting and tachometer data valid */
108+
return true;
109+
}
110+
111+
return false;
112+
}
113+
114+
static int tach_it51xxx_sample_fetch(const struct device *dev, enum sensor_channel chan)
115+
{
116+
const struct tach_it51xxx_config *const config = dev->config;
117+
const uintptr_t base = config->base;
118+
int input_pin = config->input_pin;
119+
struct tach_it51xxx_data *const data = dev->data;
120+
uint8_t reg_val;
121+
122+
if ((chan != SENSOR_CHAN_RPM) && (chan != SENSOR_CHAN_ALL)) {
123+
return -ENOTSUP;
124+
}
125+
126+
if (tach_ch_is_valid(dev, input_pin)) {
127+
/* If tachometer data is valid, then save it */
128+
data->capture = sys_read16(base + REG_TACH_CH);
129+
/* Clear tachometer data valid status */
130+
reg_val = sys_read8(base + REG_TACH_CH_CTRL1);
131+
sys_write8(reg_val | TACH_CH_DVS, base + REG_TACH_CH_CTRL1);
132+
} else {
133+
/* If tachometer data isn't valid, then clear it */
134+
data->capture = 0;
135+
}
136+
137+
return 0;
138+
}
139+
140+
static int tach_it51xxx_channel_get(const struct device *dev, enum sensor_channel chan,
141+
struct sensor_value *val)
142+
{
143+
const struct tach_it51xxx_config *const config = dev->config;
144+
int p = config->pulses_per_round;
145+
struct tach_it51xxx_data *const data = dev->data;
146+
147+
__ASSERT(p > 0, "pulses_per_round must be bigger than 0");
148+
149+
if (chan != SENSOR_CHAN_RPM) {
150+
LOG_ERR("Sensor chan %d, only support SENSOR_CHAN_RPM", chan);
151+
return -ENOTSUP;
152+
}
153+
154+
/* Transform count unit to RPM */
155+
if (data->capture > 0) {
156+
/*
157+
* Fan Speed (RPM) = 60 / (1/fs * {TACH_CH_(H & L)} * P)
158+
* - P denotes the numbers of pulses per round
159+
* - {TACH_CH_(H & L)} = 0000h denotes Fan Speed is zero
160+
* - The sampling rate (fs) is TACH_FREQ / 128
161+
*/
162+
val->val1 = (60 * TACH_FREQ / 128 / p / (data->capture));
163+
} else {
164+
val->val1 = 0U;
165+
}
166+
167+
val->val2 = 0U;
168+
169+
return 0;
170+
}
171+
172+
static int tach_it51xxx_init(const struct device *dev)
173+
{
174+
const struct tach_it51xxx_config *const config = dev->config;
175+
const uintptr_t base = config->base;
176+
int input_pin = config->input_pin;
177+
int status;
178+
uint8_t reg_val;
179+
180+
if (input_pin > IT51XXX_TACH_INPUT_PIN_B) {
181+
LOG_ERR("Tach input pin %d invalid, only support 0(A) or 1(B)", input_pin);
182+
return -EINVAL;
183+
}
184+
185+
/* Select input pin to tachometer alternate mode */
186+
status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
187+
if (status < 0) {
188+
LOG_ERR("Failed to configure TACH pins");
189+
return status;
190+
}
191+
192+
reg_val = sys_read8(base + REG_TACH_CH_CTRL1);
193+
if (input_pin == IT51XXX_TACH_INPUT_PIN_A) {
194+
/* Select TACH_INPUT_PIN_A to tachometer */
195+
reg_val &= ~TACH_CH_SEL;
196+
} else {
197+
/* Select TACH_INPUT_PIN_B to tachometer */
198+
reg_val |= TACH_CH_SEL;
199+
}
200+
/* Clear tachometer data valid status */
201+
sys_write8(reg_val | TACH_CH_DVS, base + REG_TACH_CH_CTRL1);
202+
203+
/* Tachometer sensor already start */
204+
return 0;
205+
}
206+
207+
static DEVICE_API(sensor, tach_it51xxx_driver_api) = {
208+
.sample_fetch = tach_it51xxx_sample_fetch,
209+
.channel_get = tach_it51xxx_channel_get,
210+
};
211+
212+
#define TACH_IT51XXX_INIT(inst) \
213+
PINCTRL_DT_INST_DEFINE(inst); \
214+
\
215+
static const struct tach_it51xxx_config tach_it51xxx_cfg_##inst = { \
216+
.base = DT_INST_REG_ADDR(inst), \
217+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
218+
.input_pin = DT_INST_PROP(inst, input_pin), \
219+
.pulses_per_round = DT_INST_PROP(inst, pulses_per_round), \
220+
}; \
221+
\
222+
static struct tach_it51xxx_data tach_it51xxx_data_##inst; \
223+
\
224+
SENSOR_DEVICE_DT_INST_DEFINE(inst, tach_it51xxx_init, NULL, &tach_it51xxx_data_##inst, \
225+
&tach_it51xxx_cfg_##inst, POST_KERNEL, \
226+
CONFIG_SENSOR_INIT_PRIORITY, &tach_it51xxx_driver_api);
227+
228+
DT_INST_FOREACH_STATUS_OKAY(TACH_IT51XXX_INIT)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright (c) 2025 ITE Technology Corporation.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ITE, it51xxx Tachometer node
5+
6+
compatible: "ite,it51xxx-tach"
7+
8+
include: [tach.yaml, pinctrl-device.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
input-pin:
15+
type: int
16+
required: true
17+
enum:
18+
- 0
19+
- 1
20+
description: 0 = TACH_INPUT_PIN_A, 1 = TACH_INPUT_PIN_B
21+
22+
pulses-per-round:
23+
type: int
24+
required: true
25+
description: number of pulses per round of tachometer's input
26+
27+
pinctrl-0:
28+
required: true
29+
30+
pinctrl-names:
31+
required: true

dts/riscv/ite/it51xxx.dtsi

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <zephyr/dt-bindings/interrupt-controller/ite-it51xxx-intc.h>
1414
#include <zephyr/dt-bindings/interrupt-controller/ite-it51xxx-wuc.h>
1515
#include <zephyr/dt-bindings/pinctrl/it8xxx2-pinctrl.h>
16+
#include <zephyr/dt-bindings/sensor/it51xxx_tach.h>
1617

1718
/ {
1819
#address-cells = <1>;
@@ -1023,5 +1024,23 @@
10231024
interrupts = <IT51XXX_IRQ_TIMER1_DW IRQ_TYPE_EDGE_RISING>; /* Warn timer */
10241025
interrupt-parent = <&intc>;
10251026
};
1027+
1028+
tach0: tach@f046c0 {
1029+
compatible = "ite,it51xxx-tach";
1030+
reg = <0x00f046c0 0xf>;
1031+
status = "disabled";
1032+
};
1033+
1034+
tach1: tach@f046d0 {
1035+
compatible = "ite,it51xxx-tach";
1036+
reg = <0x00f046d0 0xf>;
1037+
status = "disabled";
1038+
};
1039+
1040+
tach2: tach@f046e0 {
1041+
compatible = "ite,it51xxx-tach";
1042+
reg = <0x00f046e0 0xf>;
1043+
status = "disabled";
1044+
};
10261045
};
10271046
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2025 ITE Technology Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_ITE_TACH_H_
7+
#define ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_ITE_TACH_H_
8+
9+
/**
10+
* @name Tachometer input pin
11+
* @{
12+
*/
13+
14+
/** Tachometer input from pin A */
15+
#define IT51XXX_TACH_INPUT_PIN_A 0
16+
/** Tachometer input from pin B */
17+
#define IT51XXX_TACH_INPUT_PIN_B 1
18+
19+
/** @} */
20+
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_ITE_TACH_H_ */

soc/ite/ec/it51xxx/chip_chipregs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#include <zephyr/sys/util.h>
1111

12+
#define IT51XXX_EC_FREQ KHZ(9200)
13+
1214
#ifdef _ASMLANGUAGE
1315
#define ECREG(x) x
1416
#else

0 commit comments

Comments
 (0)