1 /*
2  * Copyright (c) 2021 ITE Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ite_it8xxx2_tach
8 
9 /**
10  * @file
11  * @brief ITE it8xxx2 tachometer sensor module driver
12  *
13  * This file contains a driver for the tachometer sensor module which contains
14  * two independent counters (F1TL/MRR and F2TL/MRR). 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 or T1B 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  *                            |------>| F1TL/MRR  |<-+-|  | |_| |_ |<--+
25  *                            |       +-----------+    +-----------+   |
26  *                            |       capture pulses                  T0B (GPJ2)
27  *                            |       in sample rate
28  *                            |       period
29  *           +-----------+    |
30  * Crystal-->| Prescaler |--->|        Tachometer 1                   T1A (GPD7)
31  * 32.768k   +-----------+    |             |          +-----------+   |
32  *                            |       +-----+-----+    |   _   _   |<--+
33  *                            |------>| F2TL/MRR  |<-+-|  | |_| |_ |<--+
34  *                            |       +-----------+    +-----------+   |
35  *                            |       capture pulses                  T1B (GPJ3)
36  *                            |       in one second
37  *                            |       period
38  *                            |
39  *
40  * Based on the counter value, we can compute the current RPM of external signal
41  * from encoders.
42  */
43 
44 #include <zephyr/device.h>
45 #include <zephyr/drivers/pinctrl.h>
46 #include <zephyr/drivers/sensor.h>
47 #include <zephyr/dt-bindings/sensor/it8xxx2_tach.h>
48 #include <errno.h>
49 #include <soc.h>
50 #include <soc_dt.h>
51 
52 #include <zephyr/logging/log.h>
53 LOG_MODULE_REGISTER(tach_ite_it8xxx2, CONFIG_SENSOR_LOG_LEVEL);
54 
55 /*
56  * NOTE: The PWM output maximum is 324Hz in EC LPM, so if we need fan to work
57  *       then don't let EC enter LPM.
58  */
59 #define TACH_FREQ		EC_FREQ
60 
61 struct tach_it8xxx2_config {
62 	/* Fan x tachometer LSB reading register */
63 	uintptr_t reg_fxtlrr;
64 	/* Fan x tachometer MSB reading register */
65 	uintptr_t reg_fxtmrr;
66 	/* Tachometer switch control register */
67 	uintptr_t reg_tswctlr;
68 	/* Tachometer data valid bit of tswctlr register */
69 	int dvs_bit;
70 	/* Tachometer data valid status bit of tswctlr register */
71 	int chsel_bit;
72 	/* Tachometer alternate configuration */
73 	const struct pinctrl_dev_config *pcfg;
74 	/* Select channel of tachometer */
75 	int channel;
76 	/* Number of pulses per round of tachometer's input */
77 	int pulses_per_round;
78 };
79 
80 /* Driver data */
81 struct tach_it8xxx2_data {
82 	/* Captured counts of tachometer */
83 	uint32_t capture;
84 };
85 
tach_ch_is_valid(const struct device * dev,int tach_ch)86 static bool tach_ch_is_valid(const struct device *dev, int tach_ch)
87 {
88 	const struct tach_it8xxx2_config *const config = dev->config;
89 	volatile uint8_t *reg_tswctlr = (uint8_t *)config->reg_tswctlr;
90 	int dvs_bit = config->dvs_bit;
91 	int chsel_bit = config->chsel_bit;
92 	int mask = (dvs_bit | chsel_bit);
93 	bool valid = false;
94 
95 	switch (tach_ch) {
96 	case IT8XXX2_TACH_CHANNEL_A:
97 		if ((*reg_tswctlr & mask) == dvs_bit) {
98 			valid = true;
99 		}
100 		break;
101 	case IT8XXX2_TACH_CHANNEL_B:
102 		if ((*reg_tswctlr & mask) == mask) {
103 			valid = true;
104 		}
105 		break;
106 	default:
107 		break;
108 	}
109 
110 	return valid;
111 }
112 
tach_it8xxx2_sample_fetch(const struct device * dev,enum sensor_channel chan)113 static int tach_it8xxx2_sample_fetch(const struct device *dev,
114 				     enum sensor_channel chan)
115 {
116 	const struct tach_it8xxx2_config *const config = dev->config;
117 	volatile uint8_t *reg_fxtlrr = (uint8_t *)config->reg_fxtlrr;
118 	volatile uint8_t *reg_fxtmrr = (uint8_t *)config->reg_fxtmrr;
119 	volatile uint8_t *reg_tswctlr = (uint8_t *)config->reg_tswctlr;
120 	int tach_ch = config->channel;
121 	struct tach_it8xxx2_data *const data = dev->data;
122 
123 	if ((chan != SENSOR_CHAN_RPM) && (chan != SENSOR_CHAN_ALL)) {
124 		return -ENOTSUP;
125 	}
126 
127 	if (tach_ch_is_valid(dev, tach_ch)) {
128 		/* If channel data of tachometer is valid, then save it */
129 		data->capture = ((*reg_fxtmrr) << 8) | (*reg_fxtlrr);
130 		/* Clear tachometer data valid status */
131 		*reg_tswctlr |= config->dvs_bit;
132 	} else {
133 		/* If channel data of tachometer isn't valid, then clear it */
134 		data->capture = 0;
135 	}
136 
137 	return 0;
138 }
139 
tach_it8xxx2_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)140 static int tach_it8xxx2_channel_get(const struct device *dev,
141 				    enum sensor_channel chan,
142 				    struct sensor_value *val)
143 {
144 	const struct tach_it8xxx2_config *const config = dev->config;
145 	int tachx = ((config->dvs_bit) == IT8XXX2_PWM_T0DVS) ? 0 : 1;
146 	int p = config->pulses_per_round;
147 	struct tach_it8xxx2_data *const data = dev->data;
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 		if (tachx == 0) {
157 			/*
158 			 * Fan Speed (RPM) = 60 / (1/fs * {F1TMRR, F1TLRR} * P)
159 			 * - P denotes the numbers of pulses per round
160 			 * - {F1TMRR, F1TLRR} = 0000h denotes Fan Speed is zero
161 			 * - The sampling rate (fs) is TACH_FREQ / 128
162 			 */
163 			val->val1 = (60 * TACH_FREQ / 128 / p / (data->capture));
164 		} else {
165 			/*
166 			 * Fan Speed (RPM) = {F2TMRR, F2TLRR} * 60 / P
167 			 * - P denotes the numbers of pulses per round
168 			 * - {F2TMRR, F2TLRR} = 0000h denotes Fan Speed is zero
169 			 */
170 			val->val1 = ((data->capture) * 120 / (p * 2));
171 		}
172 	} else {
173 		val->val1 = 0U;
174 	}
175 
176 	val->val2 = 0U;
177 
178 	return 0;
179 }
180 
tach_it8xxx2_init(const struct device * dev)181 static int tach_it8xxx2_init(const struct device *dev)
182 {
183 	const struct tach_it8xxx2_config *const config = dev->config;
184 	volatile uint8_t *reg_tswctlr = (uint8_t *)config->reg_tswctlr;
185 	int tach_ch = config->channel;
186 	int status;
187 
188 	if (tach_ch > IT8XXX2_TACH_CHANNEL_B) {
189 		LOG_ERR("Tach channel %d, only support 0 or 1", tach_ch);
190 		return -EINVAL;
191 	}
192 
193 	/* Select pin to alternate mode for tachometer */
194 	status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
195 	if (status < 0) {
196 		LOG_ERR("Failed to configure TACH pins");
197 		return status;
198 	}
199 
200 	if (tach_ch == IT8XXX2_TACH_CHANNEL_A) {
201 		/* Select IT8XXX2_TACH_CHANNEL_A output to tachometer */
202 		*reg_tswctlr &= ~(config->chsel_bit);
203 		/* Clear tachometer data valid status */
204 		*reg_tswctlr |= config->dvs_bit;
205 	} else {
206 		/* Select IT8XXX2_TACH_CHANNEL_B output to tachometer */
207 		*reg_tswctlr |= config->chsel_bit;
208 		/* Clear tachometer data valid status */
209 		*reg_tswctlr |= config->dvs_bit;
210 	}
211 
212 	/* Tachometer sensor already start */
213 	return 0;
214 }
215 
216 static DEVICE_API(sensor, tach_it8xxx2_driver_api) = {
217 	.sample_fetch = tach_it8xxx2_sample_fetch,
218 	.channel_get = tach_it8xxx2_channel_get,
219 };
220 
221 #define TACH_IT8XXX2_INIT(inst)						       \
222 	PINCTRL_DT_INST_DEFINE(inst);					       \
223 									       \
224 	static const struct tach_it8xxx2_config tach_it8xxx2_cfg_##inst = {    \
225 		.reg_fxtlrr = DT_INST_REG_ADDR_BY_IDX(inst, 0),		       \
226 		.reg_fxtmrr = DT_INST_REG_ADDR_BY_IDX(inst, 1),		       \
227 		.reg_tswctlr = DT_INST_REG_ADDR_BY_IDX(inst, 2),	       \
228 		.dvs_bit = DT_INST_PROP(inst, dvs_bit),			       \
229 		.chsel_bit = DT_INST_PROP(inst, chsel_bit),		       \
230 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),		       \
231 		.channel = DT_INST_PROP(inst, channel),			       \
232 		.pulses_per_round = DT_INST_PROP(inst, pulses_per_round),      \
233 	};								       \
234 									       \
235 	static struct tach_it8xxx2_data tach_it8xxx2_data_##inst;	       \
236 									       \
237 	SENSOR_DEVICE_DT_INST_DEFINE(inst,				       \
238 			      tach_it8xxx2_init,			       \
239 			      NULL,					       \
240 			      &tach_it8xxx2_data_##inst,		       \
241 			      &tach_it8xxx2_cfg_##inst,			       \
242 			      POST_KERNEL,				       \
243 			      CONFIG_SENSOR_INIT_PRIORITY,		       \
244 			      &tach_it8xxx2_driver_api);
245 
246 DT_INST_FOREACH_STATUS_OKAY(TACH_IT8XXX2_INIT)
247