1 /*
2 * Copyright (c) 2020 Intel Corporation
3 * Copyright (c) 2022 Microchip Technology Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT microchip_xec_tach
9
10 #include <errno.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <zephyr/arch/cpu.h>
14 #ifdef CONFIG_SOC_SERIES_MEC172X
15 #include <zephyr/drivers/clock_control/mchp_xec_clock_control.h>
16 #include <zephyr/drivers/interrupt_controller/intc_mchp_xec_ecia.h>
17 #endif
18 #include <zephyr/drivers/pinctrl.h>
19 #include <zephyr/drivers/sensor.h>
20 #include <soc.h>
21 #include <zephyr/sys/sys_io.h>
22 #include <zephyr/logging/log.h>
23
24 #include <zephyr/pm/device.h>
25 #include <zephyr/pm/policy.h>
26
27 LOG_MODULE_REGISTER(tach_xec, CONFIG_SENSOR_LOG_LEVEL);
28
29 struct tach_xec_config {
30 struct tach_regs * const regs;
31 uint8_t girq;
32 uint8_t girq_pos;
33 uint8_t pcr_idx;
34 uint8_t pcr_pos;
35 const struct pinctrl_dev_config *pcfg;
36 };
37
38 struct tach_xec_data {
39 uint32_t control;
40 uint16_t count;
41 };
42
43 #define FAN_STOPPED 0xFFFFU
44 #define COUNT_100KHZ_SEC 100000U
45 #define SEC_TO_MINUTE 60U
46 #define PIN_STS_TIMEOUT 20U
47 #define TACH_CTRL_EDGES (CONFIG_TACH_XEC_EDGES << \
48 MCHP_TACH_CTRL_NUM_EDGES_POS)
49
tach_xec_sample_fetch(const struct device * dev,enum sensor_channel chan)50 int tach_xec_sample_fetch(const struct device *dev, enum sensor_channel chan)
51 {
52 ARG_UNUSED(chan);
53
54 const struct tach_xec_config * const cfg = dev->config;
55 struct tach_xec_data * const data = dev->data;
56 struct tach_regs * const tach = cfg->regs;
57 uint8_t poll_count = 0;
58
59 pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
60
61 while (poll_count < PIN_STS_TIMEOUT) {
62 /* See whether internal counter is already latched */
63 if (tach->STATUS & MCHP_TACH_STS_CNT_RDY) {
64 data->count =
65 tach->CONTROL >> MCHP_TACH_CTRL_COUNTER_POS;
66 break;
67 }
68
69 poll_count++;
70
71 /* Allow other threads to run while we sleep */
72 k_usleep(USEC_PER_MSEC);
73 }
74
75 pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
76
77 if (poll_count == PIN_STS_TIMEOUT) {
78 return -EINVAL;
79 }
80
81 /* We interpret a fan stopped or jammed as 0 */
82 if (data->count == FAN_STOPPED) {
83 data->count = 0U;
84 }
85
86 return 0;
87 }
88
tach_xec_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)89 static int tach_xec_channel_get(const struct device *dev,
90 enum sensor_channel chan,
91 struct sensor_value *val)
92 {
93 struct tach_xec_data * const data = dev->data;
94
95 if (chan != SENSOR_CHAN_RPM) {
96 return -ENOTSUP;
97 }
98
99 /* Convert the count per 100khz cycles to rpm */
100 if (data->count != FAN_STOPPED && data->count != 0U) {
101 val->val1 = (SEC_TO_MINUTE * COUNT_100KHZ_SEC)/data->count;
102 val->val2 = 0U;
103 } else {
104 val->val1 = 0U;
105 }
106
107 val->val2 = 0U;
108
109 return 0;
110 }
111
tach_xec_sleep_clr(const struct device * dev)112 static void tach_xec_sleep_clr(const struct device *dev)
113 {
114 const struct tach_xec_config * const cfg = dev->config;
115 struct pcr_regs * const pcr = (struct pcr_regs * const)(
116 DT_REG_ADDR_BY_IDX(DT_NODELABEL(pcr), 0));
117
118 #ifdef CONFIG_SOC_SERIES_MEC172X
119 pcr->SLP_EN[cfg->pcr_idx] &= ~BIT(cfg->pcr_pos);
120 #else
121 uintptr_t addr = (uintptr_t)&pcr->SLP_EN0 + (4u * cfg->pcr_idx);
122 uint32_t pcr_val = sys_read32(addr) & ~BIT(cfg->pcr_pos);
123
124 sys_write32(pcr_val, addr);
125 #endif
126 }
127
128 #ifdef CONFIG_PM_DEVICE
tach_xec_pm_action(const struct device * dev,enum pm_device_action action)129 static int tach_xec_pm_action(const struct device *dev, enum pm_device_action action)
130 {
131 const struct tach_xec_config * const cfg = dev->config;
132 struct tach_xec_data * const data = dev->data;
133 struct tach_regs * const tach = cfg->regs;
134 int ret = 0;
135
136 switch (action) {
137 case PM_DEVICE_ACTION_RESUME:
138 if (data->control & MCHP_TACH_CTRL_EN) {
139 tach->CONTROL |= MCHP_TACH_CTRL_EN;
140 data->control &= (~MCHP_TACH_CTRL_EN);
141 }
142 break;
143 case PM_DEVICE_ACTION_SUSPEND:
144 if (tach->CONTROL & MCHP_TACH_CTRL_EN) {
145 /* Take a backup */
146 data->control = tach->CONTROL;
147 tach->CONTROL &= (~MCHP_TACH_CTRL_EN);
148 }
149 break;
150 default:
151 ret = -ENOTSUP;
152 }
153
154 return ret;
155 }
156 #endif /* CONFIG_PM_DEVICE */
157
tach_xec_init(const struct device * dev)158 static int tach_xec_init(const struct device *dev)
159 {
160 const struct tach_xec_config * const cfg = dev->config;
161 struct tach_regs * const tach = cfg->regs;
162
163 int ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
164
165 if (ret != 0) {
166 LOG_ERR("XEC TACH pinctrl init failed (%d)", ret);
167 return ret;
168 }
169
170 tach_xec_sleep_clr(dev);
171
172 tach->CONTROL = MCHP_TACH_CTRL_READ_MODE_100K_CLOCK |
173 TACH_CTRL_EDGES |
174 MCHP_TACH_CTRL_FILTER_EN |
175 MCHP_TACH_CTRL_EN;
176
177 return 0;
178 }
179
180 static DEVICE_API(sensor, tach_xec_driver_api) = {
181 .sample_fetch = tach_xec_sample_fetch,
182 .channel_get = tach_xec_channel_get,
183 };
184
185 #define XEC_TACH_CONFIG(inst) \
186 static const struct tach_xec_config tach_xec_config_##inst = { \
187 .regs = (struct tach_regs * const)DT_INST_REG_ADDR(inst), \
188 .girq = DT_INST_PROP_BY_IDX(inst, girqs, 0), \
189 .girq_pos = DT_INST_PROP_BY_IDX(inst, girqs, 1), \
190 .pcr_idx = DT_INST_PROP_BY_IDX(inst, pcrs, 0), \
191 .pcr_pos = DT_INST_PROP_BY_IDX(inst, pcrs, 1), \
192 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
193 }
194
195 #define TACH_XEC_DEVICE(id) \
196 static struct tach_xec_data tach_xec_data_##id; \
197 \
198 PINCTRL_DT_INST_DEFINE(id); \
199 \
200 XEC_TACH_CONFIG(id); \
201 \
202 PM_DEVICE_DT_INST_DEFINE(id, tach_xec_pm_action); \
203 \
204 SENSOR_DEVICE_DT_INST_DEFINE(id, \
205 tach_xec_init, \
206 PM_DEVICE_DT_INST_GET(id), \
207 &tach_xec_data_##id, \
208 &tach_xec_config_##id, \
209 POST_KERNEL, \
210 CONFIG_SENSOR_INIT_PRIORITY, \
211 &tach_xec_driver_api);
212
213 DT_INST_FOREACH_STATUS_OKAY(TACH_XEC_DEVICE)
214