1 /*
2  * Copyright 2023-2024 NXP
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT nxp_vref
7 
8 #include <errno.h>
9 
10 #include <zephyr/drivers/regulator.h>
11 #include <zephyr/dt-bindings/regulator/nxp_vref.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys/linear_range.h>
14 #include <zephyr/sys/util.h>
15 
16 #include <fsl_device_registers.h>
17 
18 static const struct linear_range utrim_range = LINEAR_RANGE_INIT(1000000, 100000U, 0x0U, 0xBU);
19 
20 struct regulator_nxp_vref_data {
21 	struct regulator_common_data common;
22 };
23 
24 struct regulator_nxp_vref_config {
25 	struct regulator_common_config common;
26 	VREF_Type *base;
27 	uint16_t buf_start_delay;
28 	uint16_t bg_start_time;
29 	bool current_compensation_en;
30 };
31 
regulator_nxp_vref_enable(const struct device * dev)32 static int regulator_nxp_vref_enable(const struct device *dev)
33 {
34 	const struct regulator_nxp_vref_config *config = dev->config;
35 	VREF_Type *const base = config->base;
36 
37 	volatile uint32_t *const csr = &base->CSR;
38 
39 	*csr |= VREF_CSR_LPBGEN_MASK | VREF_CSR_LPBG_BUF_EN_MASK;
40 	/* Wait for bandgap startup */
41 	k_busy_wait(config->bg_start_time);
42 
43 	/* Enable high accuracy bandgap */
44 	*csr |= VREF_CSR_HCBGEN_MASK;
45 
46 	/* Monitor until stable */
47 	while (!(*csr & VREF_CSR_VREFST_MASK)) {
48 		;
49 	}
50 
51 	/* Enable output buffer */
52 	*csr |= VREF_CSR_BUF21EN_MASK;
53 
54 	return 0;
55 }
56 
regulator_nxp_vref_disable(const struct device * dev)57 static int regulator_nxp_vref_disable(const struct device *dev)
58 {
59 	const struct regulator_nxp_vref_config *config = dev->config;
60 	VREF_Type *const base = config->base;
61 
62 	/*
63 	 * Disable HC Bandgap, LP Bandgap, and Buf21
64 	 * to achieve "Off" mode of VREF
65 	 */
66 	base->CSR &= ~(VREF_CSR_BUF21EN_MASK | VREF_CSR_HCBGEN_MASK | VREF_CSR_LPBGEN_MASK);
67 
68 	return 0;
69 }
70 
regulator_nxp_vref_set_mode(const struct device * dev,regulator_mode_t mode)71 static int regulator_nxp_vref_set_mode(const struct device *dev, regulator_mode_t mode)
72 {
73 	const struct regulator_nxp_vref_config *config = dev->config;
74 	VREF_Type *const base = config->base;
75 	uint32_t csr = base->CSR;
76 
77 	if (mode == NXP_VREF_MODE_STANDBY) {
78 		csr &= ~VREF_CSR_REGEN_MASK &
79 			~VREF_CSR_CHOPEN_MASK &
80 			~VREF_CSR_HI_PWR_LV_MASK &
81 			~VREF_CSR_BUF21EN_MASK;
82 	} else if (mode == NXP_VREF_MODE_LOW_POWER) {
83 		csr &= ~VREF_CSR_REGEN_MASK &
84 			~VREF_CSR_CHOPEN_MASK &
85 			~VREF_CSR_HI_PWR_LV_MASK;
86 		csr |= VREF_CSR_BUF21EN_MASK;
87 	} else if (mode == NXP_VREF_MODE_HIGH_POWER) {
88 		csr &= ~VREF_CSR_REGEN_MASK &
89 			~VREF_CSR_CHOPEN_MASK;
90 		csr |= VREF_CSR_HI_PWR_LV_MASK &
91 			VREF_CSR_BUF21EN_MASK;
92 	} else if (mode == NXP_VREF_MODE_INTERNAL_REGULATOR) {
93 		csr |= VREF_CSR_REGEN_MASK &
94 			VREF_CSR_CHOPEN_MASK &
95 			VREF_CSR_HI_PWR_LV_MASK &
96 			VREF_CSR_BUF21EN_MASK;
97 	} else {
98 		return -EINVAL;
99 	}
100 
101 	base->CSR = csr;
102 
103 	k_busy_wait(config->buf_start_delay);
104 
105 	return 0;
106 }
107 
regulator_nxp_vref_get_mode(const struct device * dev,regulator_mode_t * mode)108 static int regulator_nxp_vref_get_mode(const struct device *dev, regulator_mode_t *mode)
109 {
110 	const struct regulator_nxp_vref_config *config = dev->config;
111 	VREF_Type *const base = config->base;
112 	uint32_t csr = base->CSR;
113 
114 	/* Check bits to determine mode */
115 	if (csr & VREF_CSR_REGEN_MASK) {
116 		*mode = NXP_VREF_MODE_INTERNAL_REGULATOR;
117 	} else if (csr & VREF_CSR_HI_PWR_LV_MASK) {
118 		*mode = NXP_VREF_MODE_HIGH_POWER;
119 	} else if (csr & VREF_CSR_BUF21EN_MASK) {
120 		*mode = NXP_VREF_MODE_LOW_POWER;
121 	} else {
122 		*mode = NXP_VREF_MODE_STANDBY;
123 	}
124 
125 	return 0;
126 }
127 
regulator_nxp_vref_count_voltages(const struct device * dev)128 static inline unsigned int regulator_nxp_vref_count_voltages(const struct device *dev)
129 {
130 	return linear_range_values_count(&utrim_range);
131 }
132 
regulator_nxp_vref_list_voltage(const struct device * dev,unsigned int idx,int32_t * volt_uv)133 static int regulator_nxp_vref_list_voltage(const struct device *dev,
134 						unsigned int idx, int32_t *volt_uv)
135 {
136 	return linear_range_get_value(&utrim_range, idx, volt_uv);
137 }
138 
regulator_nxp_vref_set_voltage(const struct device * dev,int32_t min_uv,int32_t max_uv)139 static int regulator_nxp_vref_set_voltage(const struct device *dev,
140 					int32_t min_uv, int32_t max_uv)
141 {
142 	const struct regulator_nxp_vref_config *config = dev->config;
143 	VREF_Type *const base = config->base;
144 	uint16_t idx;
145 	int ret;
146 
147 	ret = linear_range_get_win_index(&utrim_range, min_uv, max_uv, &idx);
148 	if (ret < 0) {
149 		return ret;
150 	}
151 
152 	base->UTRIM &= ~VREF_UTRIM_TRIM2V1_MASK;
153 	base->UTRIM |= VREF_UTRIM_TRIM2V1_MASK & idx;
154 
155 	return 0;
156 }
157 
regulator_nxp_vref_get_voltage(const struct device * dev,int32_t * volt_uv)158 static int regulator_nxp_vref_get_voltage(const struct device *dev,
159 						int32_t *volt_uv)
160 {
161 	const struct regulator_nxp_vref_config *config = dev->config;
162 	VREF_Type *const base = config->base;
163 	uint16_t idx;
164 	int ret;
165 
166 	/* Linear range index is the register value */
167 	idx = (base->UTRIM & VREF_UTRIM_TRIM2V1_MASK) >> VREF_UTRIM_TRIM2V1_SHIFT;
168 
169 	ret = linear_range_get_value(&utrim_range, idx, volt_uv);
170 
171 	return ret;
172 }
173 
174 static DEVICE_API(regulator, api) = {
175 	.enable = regulator_nxp_vref_enable,
176 	.disable = regulator_nxp_vref_disable,
177 	.set_mode = regulator_nxp_vref_set_mode,
178 	.get_mode = regulator_nxp_vref_get_mode,
179 	.set_voltage = regulator_nxp_vref_set_voltage,
180 	.get_voltage = regulator_nxp_vref_get_voltage,
181 	.list_voltage = regulator_nxp_vref_list_voltage,
182 	.count_voltages = regulator_nxp_vref_count_voltages,
183 };
184 
regulator_nxp_vref_init(const struct device * dev)185 static int regulator_nxp_vref_init(const struct device *dev)
186 {
187 	const struct regulator_nxp_vref_config *config = dev->config;
188 	VREF_Type *const base = config->base;
189 	int ret;
190 
191 	regulator_common_data_init(dev);
192 
193 	ret = regulator_nxp_vref_disable(dev);
194 	if (ret < 0) {
195 		return ret;
196 	}
197 
198 	if (config->current_compensation_en) {
199 		base->CSR |= VREF_CSR_ICOMPEN_MASK;
200 	}
201 
202 	/* Workaround some chips not resetting the value correctly on reset */
203 	base->UTRIM = 0;
204 
205 	return regulator_common_init(dev, false);
206 }
207 
208 #define REGULATOR_NXP_VREF_DEFINE(inst)						\
209 	static struct regulator_nxp_vref_data data_##inst;			\
210 										\
211 	static const struct regulator_nxp_vref_config config_##inst = {		\
212 		.common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst),		\
213 		.base = (VREF_Type *) DT_INST_REG_ADDR(inst),			\
214 		.buf_start_delay = DT_INST_PROP(inst,				\
215 				nxp_buffer_startup_delay_us),			\
216 		.bg_start_time = DT_INST_PROP(inst,				\
217 				nxp_bandgap_startup_time_us),			\
218 		.current_compensation_en = DT_INST_PROP(inst,			\
219 				nxp_current_compensation_en),			\
220 	};									\
221 										\
222 	DEVICE_DT_INST_DEFINE(inst, regulator_nxp_vref_init, NULL, &data_##inst,\
223 				&config_##inst, POST_KERNEL,			\
224 				CONFIG_REGULATOR_NXP_VREF_INIT_PRIORITY, &api);	\
225 
226 DT_INST_FOREACH_STATUS_OKAY(REGULATOR_NXP_VREF_DEFINE)
227