1 /*
2 * Copyright (c) 2024 ENE Technology Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ene_kb1200_tach
8
9 #include <zephyr/drivers/pinctrl.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <reg/tacho.h>
12
13 /* Device config */
14 struct tach_kb1200_config {
15 /* tachometer controller base address */
16 struct tacho_regs *tacho;
17 /* number of pulses (holes) per round of tachometer's input (encoder) */
18 int pulses_per_round;
19 /* sampling clock timing of tachometer (us) */
20 int sample_time_us;
21 const struct pinctrl_dev_config *pcfg;
22 };
23
24 /* Driver data */
25 struct tach_kb1200_data {
26 /* Captured counts of tachometer */
27 uint32_t capture;
28 };
29
30 /* TACH local functions */
tach_kb1200_configure(const struct device * dev)31 static int tach_kb1200_configure(const struct device *dev)
32 {
33 const struct tach_kb1200_config *const config = dev->config;
34 uint8_t sample_us = 0;
35
36 /* Configure clock module and its frequency of tachometer */
37 switch (config->sample_time_us) {
38 case 2:
39 sample_us = TACHO_MONITOR_CLK_2US;
40 break;
41 case 8:
42 sample_us = TACHO_MONITOR_CLK_8US;
43 break;
44 case 16:
45 sample_us = TACHO_MONITOR_CLK_16US;
46 break;
47 case 64:
48 sample_us = TACHO_MONITOR_CLK_64US;
49 break;
50 default:
51 return -ENOTSUP;
52 }
53 config->tacho->TACHOCFG = (sample_us << 4) | TACHO_FUNCTION_ENABLE;
54
55 return 0;
56 }
57
58 /* TACH api functions */
tach_kb1200_sample_fetch(const struct device * dev,enum sensor_channel chan)59 int tach_kb1200_sample_fetch(const struct device *dev, enum sensor_channel chan)
60 {
61 ARG_UNUSED(chan);
62 struct tach_kb1200_data *const data = dev->data;
63 const struct tach_kb1200_config *const config = dev->config;
64
65 /* Check tachometer timeout flag*/
66 if (config->tacho->TACHOPF & TACHO_TIMEOUT_EVENT) {
67 /* Clear timeout flags and update flag */
68 config->tacho->TACHOPF = (TACHO_TIMEOUT_EVENT | TACHO_UPDATE_EVENT);
69 data->capture = 0;
70 return 0;
71 }
72
73 /* Check tachometer update flag is set */
74 if (config->tacho->TACHOPF & TACHO_UPDATE_EVENT) {
75 /* Clear pending flags */
76 config->tacho->TACHOPF = TACHO_UPDATE_EVENT;
77 /* Save captured count */
78 data->capture = config->tacho->TACHOCV & TACHO_CNT_MAX_VALUE;
79 }
80 return 0;
81 }
82
tach_kb1200_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)83 static int tach_kb1200_channel_get(const struct device *dev, enum sensor_channel chan,
84 struct sensor_value *val)
85 {
86 struct tach_kb1200_data *const data = dev->data;
87 const struct tach_kb1200_config *const config = dev->config;
88
89 if (chan != SENSOR_CHAN_RPM) {
90 return -ENOTSUP;
91 }
92
93 if (data->capture > 0) {
94 /*
95 * RPM = (60000000/t) / n
96 * t: One Pulses length(us) = sample_time_us * cnt
97 * n: One Round pulses Number
98 */
99 val->val1 = (60000000 / (config->sample_time_us * data->capture)) /
100 config->pulses_per_round;
101 } else {
102 val->val1 = 0U;
103 }
104 val->val2 = 0U;
105
106 return 0;
107 }
108
109 /* TACH driver registration */
tach_kb1200_init(const struct device * dev)110 static int tach_kb1200_init(const struct device *dev)
111 {
112 int ret;
113 const struct tach_kb1200_config *config = dev->config;
114
115 ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
116 if (ret != 0) {
117 return ret;
118 }
119
120 tach_kb1200_configure(dev);
121
122 return 0;
123 }
124
125 static DEVICE_API(sensor, tach_kb1200_driver_api) = {
126 .sample_fetch = tach_kb1200_sample_fetch,
127 .channel_get = tach_kb1200_channel_get,
128 };
129
130 #define KB1200_TACH_INIT(inst) \
131 PINCTRL_DT_INST_DEFINE(inst); \
132 static const struct tach_kb1200_config tach_cfg_##inst = { \
133 .tacho = (struct tacho_regs *)DT_INST_REG_ADDR(inst), \
134 .pulses_per_round = DT_INST_PROP(inst, pulses_per_round), \
135 .sample_time_us = DT_INST_PROP(inst, sample_time_us), \
136 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
137 }; \
138 static struct tach_kb1200_data tach_data_##inst; \
139 SENSOR_DEVICE_DT_INST_DEFINE(inst, tach_kb1200_init, NULL, &tach_data_##inst, \
140 &tach_cfg_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
141 &tach_kb1200_driver_api);
142
143 DT_INST_FOREACH_STATUS_OKAY(KB1200_TACH_INIT)
144