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