diff options
-rw-r--r-- | drivers/clk/tegra/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-dfll.c | 1095 | ||||
-rw-r--r-- | drivers/clk/tegra/clk-dfll.h | 54 |
3 files changed, 1150 insertions, 0 deletions
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index aec862ba7a17..ec2e5163e1ae 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-y += clk.o | 1 | obj-y += clk.o |
2 | obj-y += clk-audio-sync.o | 2 | obj-y += clk-audio-sync.o |
3 | obj-y += clk-dfll.o | ||
3 | obj-y += clk-divider.o | 4 | obj-y += clk-divider.o |
4 | obj-y += clk-periph.o | 5 | obj-y += clk-periph.o |
5 | obj-y += clk-periph-gate.o | 6 | obj-y += clk-periph-gate.o |
diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c new file mode 100644 index 000000000000..fb138bfa0af2 --- /dev/null +++ b/drivers/clk/tegra/clk-dfll.c | |||
@@ -0,0 +1,1095 @@ | |||
1 | /* | ||
2 | * clk-dfll.c - Tegra DFLL clock source common code | ||
3 | * | ||
4 | * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved. | ||
5 | * | ||
6 | * Aleksandr Frid <afrid@nvidia.com> | ||
7 | * Paul Walmsley <pwalmsley@nvidia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * This library is for the DVCO and DFLL IP blocks on the Tegra124 | ||
19 | * SoC. These IP blocks together are also known at NVIDIA as | ||
20 | * "CL-DVFS". To try to avoid confusion, this code refers to them | ||
21 | * collectively as the "DFLL." | ||
22 | * | ||
23 | * The DFLL is a root clocksource which tolerates some amount of | ||
24 | * supply voltage noise. Tegra124 uses it to clock the fast CPU | ||
25 | * complex when the target CPU speed is above a particular rate. The | ||
26 | * DFLL can be operated in either open-loop mode or closed-loop mode. | ||
27 | * In open-loop mode, the DFLL generates an output clock appropriate | ||
28 | * to the supply voltage. In closed-loop mode, when configured with a | ||
29 | * target frequency, the DFLL minimizes supply voltage while | ||
30 | * delivering an average frequency equal to the target. | ||
31 | * | ||
32 | * Devices clocked by the DFLL must be able to tolerate frequency | ||
33 | * variation. In the case of the CPU, it's important to note that the | ||
34 | * CPU cycle time will vary. This has implications for | ||
35 | * performance-measurement code and any code that relies on the CPU | ||
36 | * cycle time to delay for a certain length of time. | ||
37 | * | ||
38 | */ | ||
39 | |||
40 | #include <linux/clk.h> | ||
41 | #include <linux/clk-provider.h> | ||
42 | #include <linux/debugfs.h> | ||
43 | #include <linux/device.h> | ||
44 | #include <linux/err.h> | ||
45 | #include <linux/i2c.h> | ||
46 | #include <linux/io.h> | ||
47 | #include <linux/kernel.h> | ||
48 | #include <linux/module.h> | ||
49 | #include <linux/of.h> | ||
50 | #include <linux/pm_opp.h> | ||
51 | #include <linux/pm_runtime.h> | ||
52 | #include <linux/regmap.h> | ||
53 | #include <linux/regulator/consumer.h> | ||
54 | #include <linux/reset.h> | ||
55 | #include <linux/seq_file.h> | ||
56 | |||
57 | #include "clk-dfll.h" | ||
58 | |||
59 | /* | ||
60 | * DFLL control registers - access via dfll_{readl,writel} | ||
61 | */ | ||
62 | |||
63 | /* DFLL_CTRL: DFLL control register */ | ||
64 | #define DFLL_CTRL 0x00 | ||
65 | #define DFLL_CTRL_MODE_MASK 0x03 | ||
66 | |||
67 | /* DFLL_CONFIG: DFLL sample rate control */ | ||
68 | #define DFLL_CONFIG 0x04 | ||
69 | #define DFLL_CONFIG_DIV_MASK 0xff | ||
70 | #define DFLL_CONFIG_DIV_PRESCALE 32 | ||
71 | |||
72 | /* DFLL_PARAMS: tuning coefficients for closed loop integrator */ | ||
73 | #define DFLL_PARAMS 0x08 | ||
74 | #define DFLL_PARAMS_CG_SCALE (0x1 << 24) | ||
75 | #define DFLL_PARAMS_FORCE_MODE_SHIFT 22 | ||
76 | #define DFLL_PARAMS_FORCE_MODE_MASK (0x3 << DFLL_PARAMS_FORCE_MODE_SHIFT) | ||
77 | #define DFLL_PARAMS_CF_PARAM_SHIFT 16 | ||
78 | #define DFLL_PARAMS_CF_PARAM_MASK (0x3f << DFLL_PARAMS_CF_PARAM_SHIFT) | ||
79 | #define DFLL_PARAMS_CI_PARAM_SHIFT 8 | ||
80 | #define DFLL_PARAMS_CI_PARAM_MASK (0x7 << DFLL_PARAMS_CI_PARAM_SHIFT) | ||
81 | #define DFLL_PARAMS_CG_PARAM_SHIFT 0 | ||
82 | #define DFLL_PARAMS_CG_PARAM_MASK (0xff << DFLL_PARAMS_CG_PARAM_SHIFT) | ||
83 | |||
84 | /* DFLL_TUNE0: delay line configuration register 0 */ | ||
85 | #define DFLL_TUNE0 0x0c | ||
86 | |||
87 | /* DFLL_TUNE1: delay line configuration register 1 */ | ||
88 | #define DFLL_TUNE1 0x10 | ||
89 | |||
90 | /* DFLL_FREQ_REQ: target DFLL frequency control */ | ||
91 | #define DFLL_FREQ_REQ 0x14 | ||
92 | #define DFLL_FREQ_REQ_FORCE_ENABLE (0x1 << 28) | ||
93 | #define DFLL_FREQ_REQ_FORCE_SHIFT 16 | ||
94 | #define DFLL_FREQ_REQ_FORCE_MASK (0xfff << DFLL_FREQ_REQ_FORCE_SHIFT) | ||
95 | #define FORCE_MAX 2047 | ||
96 | #define FORCE_MIN -2048 | ||
97 | #define DFLL_FREQ_REQ_SCALE_SHIFT 8 | ||
98 | #define DFLL_FREQ_REQ_SCALE_MASK (0xff << DFLL_FREQ_REQ_SCALE_SHIFT) | ||
99 | #define DFLL_FREQ_REQ_SCALE_MAX 256 | ||
100 | #define DFLL_FREQ_REQ_FREQ_VALID (0x1 << 7) | ||
101 | #define DFLL_FREQ_REQ_MULT_SHIFT 0 | ||
102 | #define DFLL_FREQ_REG_MULT_MASK (0x7f << DFLL_FREQ_REQ_MULT_SHIFT) | ||
103 | #define FREQ_MAX 127 | ||
104 | |||
105 | /* DFLL_DROOP_CTRL: droop prevention control */ | ||
106 | #define DFLL_DROOP_CTRL 0x1c | ||
107 | |||
108 | /* DFLL_OUTPUT_CFG: closed loop mode control registers */ | ||
109 | /* NOTE: access via dfll_i2c_{readl,writel} */ | ||
110 | #define DFLL_OUTPUT_CFG 0x20 | ||
111 | #define DFLL_OUTPUT_CFG_I2C_ENABLE (0x1 << 30) | ||
112 | #define OUT_MASK 0x3f | ||
113 | #define DFLL_OUTPUT_CFG_SAFE_SHIFT 24 | ||
114 | #define DFLL_OUTPUT_CFG_SAFE_MASK \ | ||
115 | (OUT_MASK << DFLL_OUTPUT_CFG_SAFE_SHIFT) | ||
116 | #define DFLL_OUTPUT_CFG_MAX_SHIFT 16 | ||
117 | #define DFLL_OUTPUT_CFG_MAX_MASK \ | ||
118 | (OUT_MASK << DFLL_OUTPUT_CFG_MAX_SHIFT) | ||
119 | #define DFLL_OUTPUT_CFG_MIN_SHIFT 8 | ||
120 | #define DFLL_OUTPUT_CFG_MIN_MASK \ | ||
121 | (OUT_MASK << DFLL_OUTPUT_CFG_MIN_SHIFT) | ||
122 | #define DFLL_OUTPUT_CFG_PWM_DELTA (0x1 << 7) | ||
123 | #define DFLL_OUTPUT_CFG_PWM_ENABLE (0x1 << 6) | ||
124 | #define DFLL_OUTPUT_CFG_PWM_DIV_SHIFT 0 | ||
125 | #define DFLL_OUTPUT_CFG_PWM_DIV_MASK \ | ||
126 | (OUT_MASK << DFLL_OUTPUT_CFG_PWM_DIV_SHIFT) | ||
127 | |||
128 | /* DFLL_OUTPUT_FORCE: closed loop mode voltage forcing control */ | ||
129 | #define DFLL_OUTPUT_FORCE 0x24 | ||
130 | #define DFLL_OUTPUT_FORCE_ENABLE (0x1 << 6) | ||
131 | #define DFLL_OUTPUT_FORCE_VALUE_SHIFT 0 | ||
132 | #define DFLL_OUTPUT_FORCE_VALUE_MASK \ | ||
133 | (OUT_MASK << DFLL_OUTPUT_FORCE_VALUE_SHIFT) | ||
134 | |||
135 | /* DFLL_MONITOR_CTRL: internal monitor data source control */ | ||
136 | #define DFLL_MONITOR_CTRL 0x28 | ||
137 | #define DFLL_MONITOR_CTRL_FREQ 6 | ||
138 | |||
139 | /* DFLL_MONITOR_DATA: internal monitor data output */ | ||
140 | #define DFLL_MONITOR_DATA 0x2c | ||
141 | #define DFLL_MONITOR_DATA_NEW_MASK (0x1 << 16) | ||
142 | #define DFLL_MONITOR_DATA_VAL_SHIFT 0 | ||
143 | #define DFLL_MONITOR_DATA_VAL_MASK (0xFFFF << DFLL_MONITOR_DATA_VAL_SHIFT) | ||
144 | |||
145 | /* | ||
146 | * I2C output control registers - access via dfll_i2c_{readl,writel} | ||
147 | */ | ||
148 | |||
149 | /* DFLL_I2C_CFG: I2C controller configuration register */ | ||
150 | #define DFLL_I2C_CFG 0x40 | ||
151 | #define DFLL_I2C_CFG_ARB_ENABLE (0x1 << 20) | ||
152 | #define DFLL_I2C_CFG_HS_CODE_SHIFT 16 | ||
153 | #define DFLL_I2C_CFG_HS_CODE_MASK (0x7 << DFLL_I2C_CFG_HS_CODE_SHIFT) | ||
154 | #define DFLL_I2C_CFG_PACKET_ENABLE (0x1 << 15) | ||
155 | #define DFLL_I2C_CFG_SIZE_SHIFT 12 | ||
156 | #define DFLL_I2C_CFG_SIZE_MASK (0x7 << DFLL_I2C_CFG_SIZE_SHIFT) | ||
157 | #define DFLL_I2C_CFG_SLAVE_ADDR_10 (0x1 << 10) | ||
158 | #define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_7BIT 1 | ||
159 | #define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_10BIT 0 | ||
160 | |||
161 | /* DFLL_I2C_VDD_REG_ADDR: PMIC I2C address for closed loop mode */ | ||
162 | #define DFLL_I2C_VDD_REG_ADDR 0x44 | ||
163 | |||
164 | /* DFLL_I2C_STS: I2C controller status */ | ||
165 | #define DFLL_I2C_STS 0x48 | ||
166 | #define DFLL_I2C_STS_I2C_LAST_SHIFT 1 | ||
167 | #define DFLL_I2C_STS_I2C_REQ_PENDING 0x1 | ||
168 | |||
169 | /* DFLL_INTR_STS: DFLL interrupt status register */ | ||
170 | #define DFLL_INTR_STS 0x5c | ||
171 | |||
172 | /* DFLL_INTR_EN: DFLL interrupt enable register */ | ||
173 | #define DFLL_INTR_EN 0x60 | ||
174 | #define DFLL_INTR_MIN_MASK 0x1 | ||
175 | #define DFLL_INTR_MAX_MASK 0x2 | ||
176 | |||
177 | /* | ||
178 | * Integrated I2C controller registers - relative to td->i2c_controller_base | ||
179 | */ | ||
180 | |||
181 | /* DFLL_I2C_CLK_DIVISOR: I2C controller clock divisor */ | ||
182 | #define DFLL_I2C_CLK_DIVISOR 0x6c | ||
183 | #define DFLL_I2C_CLK_DIVISOR_MASK 0xffff | ||
184 | #define DFLL_I2C_CLK_DIVISOR_FS_SHIFT 16 | ||
185 | #define DFLL_I2C_CLK_DIVISOR_HS_SHIFT 0 | ||
186 | #define DFLL_I2C_CLK_DIVISOR_PREDIV 8 | ||
187 | #define DFLL_I2C_CLK_DIVISOR_HSMODE_PREDIV 12 | ||
188 | |||
189 | /* | ||
190 | * Other constants | ||
191 | */ | ||
192 | |||
193 | /* MAX_DFLL_VOLTAGES: number of LUT entries in the DFLL IP block */ | ||
194 | #define MAX_DFLL_VOLTAGES 33 | ||
195 | |||
196 | /* | ||
197 | * REF_CLK_CYC_PER_DVCO_SAMPLE: the number of ref_clk cycles that the hardware | ||
198 | * integrates the DVCO counter over - used for debug rate monitoring and | ||
199 | * droop control | ||
200 | */ | ||
201 | #define REF_CLK_CYC_PER_DVCO_SAMPLE 4 | ||
202 | |||
203 | /* | ||
204 | * REF_CLOCK_RATE: the DFLL reference clock rate currently supported by this | ||
205 | * driver, in Hz | ||
206 | */ | ||
207 | #define REF_CLOCK_RATE 51000000UL | ||
208 | |||
209 | |||
210 | /** | ||
211 | * enum dfll_ctrl_mode - DFLL hardware operating mode | ||
212 | * @DFLL_UNINITIALIZED: (uninitialized state - not in hardware bitfield) | ||
213 | * @DFLL_DISABLED: DFLL not generating an output clock | ||
214 | * @DFLL_OPEN_LOOP: DVCO running, but DFLL not adjusting voltage | ||
215 | * | ||
216 | * The integer corresponding to the last two states, minus one, is | ||
217 | * written to the DFLL hardware to change operating modes. | ||
218 | */ | ||
219 | enum dfll_ctrl_mode { | ||
220 | DFLL_UNINITIALIZED = 0, | ||
221 | DFLL_DISABLED = 1, | ||
222 | DFLL_OPEN_LOOP = 2, | ||
223 | }; | ||
224 | |||
225 | /** | ||
226 | * enum dfll_tune_range - voltage range that the driver believes it's in | ||
227 | * @DFLL_TUNE_UNINITIALIZED: DFLL tuning not yet programmed | ||
228 | * @DFLL_TUNE_LOW: DFLL in the low-voltage range (or open-loop mode) | ||
229 | * | ||
230 | * Some DFLL tuning parameters may need to change depending on the | ||
231 | * DVCO's voltage; these states represent the ranges that the driver | ||
232 | * supports. These are software states; these values are never | ||
233 | * written into registers. | ||
234 | */ | ||
235 | enum dfll_tune_range { | ||
236 | DFLL_TUNE_UNINITIALIZED = 0, | ||
237 | DFLL_TUNE_LOW = 1, | ||
238 | }; | ||
239 | |||
240 | struct tegra_dfll { | ||
241 | struct device *dev; | ||
242 | struct tegra_dfll_soc_data *soc; | ||
243 | |||
244 | void __iomem *base; | ||
245 | void __iomem *i2c_base; | ||
246 | void __iomem *i2c_controller_base; | ||
247 | void __iomem *lut_base; | ||
248 | |||
249 | struct regulator *vdd_reg; | ||
250 | struct clk *soc_clk; | ||
251 | struct clk *ref_clk; | ||
252 | struct clk *i2c_clk; | ||
253 | struct clk *dfll_clk; | ||
254 | struct reset_control *dvco_rst; | ||
255 | unsigned long ref_rate; | ||
256 | unsigned long i2c_clk_rate; | ||
257 | unsigned long dvco_rate_min; | ||
258 | |||
259 | enum dfll_ctrl_mode mode; | ||
260 | enum dfll_tune_range tune_range; | ||
261 | struct dentry *debugfs_dir; | ||
262 | struct clk_hw dfll_clk_hw; | ||
263 | const char *output_clock_name; | ||
264 | |||
265 | /* Parameters from DT */ | ||
266 | u32 droop_ctrl; | ||
267 | }; | ||
268 | |||
269 | #define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw) | ||
270 | |||
271 | /* mode_name: map numeric DFLL modes to names for friendly console messages */ | ||
272 | static const char * const mode_name[] = { | ||
273 | [DFLL_UNINITIALIZED] = "uninitialized", | ||
274 | [DFLL_DISABLED] = "disabled", | ||
275 | [DFLL_OPEN_LOOP] = "open_loop", | ||
276 | }; | ||
277 | |||
278 | /* | ||
279 | * Register accessors | ||
280 | */ | ||
281 | |||
282 | static inline u32 dfll_readl(struct tegra_dfll *td, u32 offs) | ||
283 | { | ||
284 | return __raw_readl(td->base + offs); | ||
285 | } | ||
286 | |||
287 | static inline void dfll_writel(struct tegra_dfll *td, u32 val, u32 offs) | ||
288 | { | ||
289 | WARN_ON(offs >= DFLL_I2C_CFG); | ||
290 | __raw_writel(val, td->base + offs); | ||
291 | } | ||
292 | |||
293 | static inline void dfll_wmb(struct tegra_dfll *td) | ||
294 | { | ||
295 | dfll_readl(td, DFLL_CTRL); | ||
296 | } | ||
297 | |||
298 | /* I2C output control registers - for addresses above DFLL_I2C_CFG */ | ||
299 | |||
300 | static inline u32 dfll_i2c_readl(struct tegra_dfll *td, u32 offs) | ||
301 | { | ||
302 | return __raw_readl(td->i2c_base + offs); | ||
303 | } | ||
304 | |||
305 | static inline void dfll_i2c_writel(struct tegra_dfll *td, u32 val, u32 offs) | ||
306 | { | ||
307 | __raw_writel(val, td->i2c_base + offs); | ||
308 | } | ||
309 | |||
310 | static inline void dfll_i2c_wmb(struct tegra_dfll *td) | ||
311 | { | ||
312 | dfll_i2c_readl(td, DFLL_I2C_CFG); | ||
313 | } | ||
314 | |||
315 | /** | ||
316 | * dfll_is_running - is the DFLL currently generating a clock? | ||
317 | * @td: DFLL instance | ||
318 | * | ||
319 | * If the DFLL is currently generating an output clock signal, return | ||
320 | * true; otherwise return false. | ||
321 | */ | ||
322 | static bool dfll_is_running(struct tegra_dfll *td) | ||
323 | { | ||
324 | return td->mode >= DFLL_OPEN_LOOP; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * Runtime PM suspend/resume callbacks | ||
329 | */ | ||
330 | |||
331 | /** | ||
332 | * tegra_dfll_runtime_resume - enable all clocks needed by the DFLL | ||
333 | * @dev: DFLL device * | ||
334 | * | ||
335 | * Enable all clocks needed by the DFLL. Assumes that clk_prepare() | ||
336 | * has already been called on all the clocks. | ||
337 | * | ||
338 | * XXX Should also handle context restore when returning from off. | ||
339 | */ | ||
340 | int tegra_dfll_runtime_resume(struct device *dev) | ||
341 | { | ||
342 | struct tegra_dfll *td = dev_get_drvdata(dev); | ||
343 | int ret; | ||
344 | |||
345 | ret = clk_enable(td->ref_clk); | ||
346 | if (ret) { | ||
347 | dev_err(dev, "could not enable ref clock: %d\n", ret); | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | ret = clk_enable(td->soc_clk); | ||
352 | if (ret) { | ||
353 | dev_err(dev, "could not enable register clock: %d\n", ret); | ||
354 | clk_disable(td->ref_clk); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | ret = clk_enable(td->i2c_clk); | ||
359 | if (ret) { | ||
360 | dev_err(dev, "could not enable i2c clock: %d\n", ret); | ||
361 | clk_disable(td->soc_clk); | ||
362 | clk_disable(td->ref_clk); | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | EXPORT_SYMBOL(tegra_dfll_runtime_resume); | ||
369 | |||
370 | /** | ||
371 | * tegra_dfll_runtime_suspend - disable all clocks needed by the DFLL | ||
372 | * @dev: DFLL device * | ||
373 | * | ||
374 | * Disable all clocks needed by the DFLL. Assumes that other code | ||
375 | * will later call clk_unprepare(). | ||
376 | */ | ||
377 | int tegra_dfll_runtime_suspend(struct device *dev) | ||
378 | { | ||
379 | struct tegra_dfll *td = dev_get_drvdata(dev); | ||
380 | |||
381 | clk_disable(td->ref_clk); | ||
382 | clk_disable(td->soc_clk); | ||
383 | clk_disable(td->i2c_clk); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | EXPORT_SYMBOL(tegra_dfll_runtime_suspend); | ||
388 | |||
389 | /* | ||
390 | * DFLL tuning operations (per-voltage-range tuning settings) | ||
391 | */ | ||
392 | |||
393 | /** | ||
394 | * dfll_tune_low - tune to DFLL and CPU settings valid for any voltage | ||
395 | * @td: DFLL instance | ||
396 | * | ||
397 | * Tune the DFLL oscillator parameters and the CPU clock shaper for | ||
398 | * the low-voltage range. These settings are valid for any voltage, | ||
399 | * but may not be optimal. | ||
400 | */ | ||
401 | static void dfll_tune_low(struct tegra_dfll *td) | ||
402 | { | ||
403 | td->tune_range = DFLL_TUNE_LOW; | ||
404 | |||
405 | dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0); | ||
406 | dfll_writel(td, td->soc->tune1, DFLL_TUNE1); | ||
407 | dfll_wmb(td); | ||
408 | |||
409 | if (td->soc->set_clock_trimmers_low) | ||
410 | td->soc->set_clock_trimmers_low(); | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * Output clock scaler helpers | ||
415 | */ | ||
416 | |||
417 | /** | ||
418 | * dfll_scale_dvco_rate - calculate scaled rate from the DVCO rate | ||
419 | * @scale_bits: clock scaler value (bits in the DFLL_FREQ_REQ_SCALE field) | ||
420 | * @dvco_rate: the DVCO rate | ||
421 | * | ||
422 | * Apply the same scaling formula that the DFLL hardware uses to scale | ||
423 | * the DVCO rate. | ||
424 | */ | ||
425 | static unsigned long dfll_scale_dvco_rate(int scale_bits, | ||
426 | unsigned long dvco_rate) | ||
427 | { | ||
428 | return (u64)dvco_rate * (scale_bits + 1) / DFLL_FREQ_REQ_SCALE_MAX; | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | * Monitor control | ||
433 | */ | ||
434 | |||
435 | /** | ||
436 | * dfll_calc_monitored_rate - convert DFLL_MONITOR_DATA_VAL rate into real freq | ||
437 | * @monitor_data: value read from the DFLL_MONITOR_DATA_VAL bitfield | ||
438 | * @ref_rate: DFLL reference clock rate | ||
439 | * | ||
440 | * Convert @monitor_data from DFLL_MONITOR_DATA_VAL units into cycles | ||
441 | * per second. Returns the converted value. | ||
442 | */ | ||
443 | static u64 dfll_calc_monitored_rate(u32 monitor_data, | ||
444 | unsigned long ref_rate) | ||
445 | { | ||
446 | return monitor_data * (ref_rate / REF_CLK_CYC_PER_DVCO_SAMPLE); | ||
447 | } | ||
448 | |||
449 | /** | ||
450 | * dfll_read_monitor_rate - return the DFLL's output rate from internal monitor | ||
451 | * @td: DFLL instance | ||
452 | * | ||
453 | * If the DFLL is enabled, return the last rate reported by the DFLL's | ||
454 | * internal monitoring hardware. This works in both open-loop and | ||
455 | * closed-loop mode, and takes the output scaler setting into account. | ||
456 | * Assumes that the monitor was programmed to monitor frequency before | ||
457 | * the sample period started. If the driver believes that the DFLL is | ||
458 | * currently uninitialized or disabled, it will return 0, since | ||
459 | * otherwise the DFLL monitor data register will return the last | ||
460 | * measured rate from when the DFLL was active. | ||
461 | */ | ||
462 | static u64 dfll_read_monitor_rate(struct tegra_dfll *td) | ||
463 | { | ||
464 | u32 v, s; | ||
465 | u64 pre_scaler_rate, post_scaler_rate; | ||
466 | |||
467 | if (!dfll_is_running(td)) | ||
468 | return 0; | ||
469 | |||
470 | v = dfll_readl(td, DFLL_MONITOR_DATA); | ||
471 | v = (v & DFLL_MONITOR_DATA_VAL_MASK) >> DFLL_MONITOR_DATA_VAL_SHIFT; | ||
472 | pre_scaler_rate = dfll_calc_monitored_rate(v, td->ref_rate); | ||
473 | |||
474 | s = dfll_readl(td, DFLL_FREQ_REQ); | ||
475 | s = (s & DFLL_FREQ_REQ_SCALE_MASK) >> DFLL_FREQ_REQ_SCALE_SHIFT; | ||
476 | post_scaler_rate = dfll_scale_dvco_rate(s, pre_scaler_rate); | ||
477 | |||
478 | return post_scaler_rate; | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * DFLL mode switching | ||
483 | */ | ||
484 | |||
485 | /** | ||
486 | * dfll_set_mode - change the DFLL control mode | ||
487 | * @td: DFLL instance | ||
488 | * @mode: DFLL control mode (see enum dfll_ctrl_mode) | ||
489 | * | ||
490 | * Change the DFLL's operating mode between disabled, open-loop mode, | ||
491 | * and closed-loop mode, or vice versa. | ||
492 | */ | ||
493 | static void dfll_set_mode(struct tegra_dfll *td, | ||
494 | enum dfll_ctrl_mode mode) | ||
495 | { | ||
496 | td->mode = mode; | ||
497 | dfll_writel(td, mode - 1, DFLL_CTRL); | ||
498 | dfll_wmb(td); | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | * DFLL enable/disable & open-loop <-> closed-loop transitions | ||
503 | */ | ||
504 | |||
505 | /** | ||
506 | * dfll_disable - switch from open-loop mode to disabled mode | ||
507 | * @td: DFLL instance | ||
508 | * | ||
509 | * Switch from OPEN_LOOP state to DISABLED state. Returns 0 upon success | ||
510 | * or -EPERM if the DFLL is not currently in open-loop mode. | ||
511 | */ | ||
512 | static int dfll_disable(struct tegra_dfll *td) | ||
513 | { | ||
514 | if (td->mode != DFLL_OPEN_LOOP) { | ||
515 | dev_err(td->dev, "cannot disable DFLL in %s mode\n", | ||
516 | mode_name[td->mode]); | ||
517 | return -EINVAL; | ||
518 | } | ||
519 | |||
520 | dfll_set_mode(td, DFLL_DISABLED); | ||
521 | pm_runtime_put_sync(td->dev); | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * dfll_enable - switch a disabled DFLL to open-loop mode | ||
528 | * @td: DFLL instance | ||
529 | * | ||
530 | * Switch from DISABLED state to OPEN_LOOP state. Returns 0 upon success | ||
531 | * or -EPERM if the DFLL is not currently disabled. | ||
532 | */ | ||
533 | static int dfll_enable(struct tegra_dfll *td) | ||
534 | { | ||
535 | if (td->mode != DFLL_DISABLED) { | ||
536 | dev_err(td->dev, "cannot enable DFLL in %s mode\n", | ||
537 | mode_name[td->mode]); | ||
538 | return -EPERM; | ||
539 | } | ||
540 | |||
541 | pm_runtime_get_sync(td->dev); | ||
542 | dfll_set_mode(td, DFLL_OPEN_LOOP); | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | /** | ||
548 | * dfll_set_open_loop_config - prepare to switch to open-loop mode | ||
549 | * @td: DFLL instance | ||
550 | * | ||
551 | * Prepare to switch the DFLL to open-loop mode. This switches the | ||
552 | * DFLL to the low-voltage tuning range, ensures that I2C output | ||
553 | * forcing is disabled, and disables the output clock rate scaler. | ||
554 | * The DFLL's low-voltage tuning range parameters must be | ||
555 | * characterized to keep the downstream device stable at any DVCO | ||
556 | * input voltage. No return value. | ||
557 | */ | ||
558 | static void dfll_set_open_loop_config(struct tegra_dfll *td) | ||
559 | { | ||
560 | u32 val; | ||
561 | |||
562 | /* always tune low (safe) in open loop */ | ||
563 | if (td->tune_range != DFLL_TUNE_LOW) | ||
564 | dfll_tune_low(td); | ||
565 | |||
566 | val = dfll_readl(td, DFLL_FREQ_REQ); | ||
567 | val |= DFLL_FREQ_REQ_SCALE_MASK; | ||
568 | val &= ~DFLL_FREQ_REQ_FORCE_ENABLE; | ||
569 | dfll_writel(td, val, DFLL_FREQ_REQ); | ||
570 | dfll_wmb(td); | ||
571 | } | ||
572 | |||
573 | /* | ||
574 | * Clock framework integration | ||
575 | */ | ||
576 | |||
577 | static int dfll_clk_is_enabled(struct clk_hw *hw) | ||
578 | { | ||
579 | struct tegra_dfll *td = clk_hw_to_dfll(hw); | ||
580 | |||
581 | return dfll_is_running(td); | ||
582 | } | ||
583 | |||
584 | static int dfll_clk_enable(struct clk_hw *hw) | ||
585 | { | ||
586 | struct tegra_dfll *td = clk_hw_to_dfll(hw); | ||
587 | |||
588 | return dfll_enable(td); | ||
589 | } | ||
590 | |||
591 | static void dfll_clk_disable(struct clk_hw *hw) | ||
592 | { | ||
593 | struct tegra_dfll *td = clk_hw_to_dfll(hw); | ||
594 | |||
595 | dfll_disable(td); | ||
596 | } | ||
597 | |||
598 | static const struct clk_ops dfll_clk_ops = { | ||
599 | .is_enabled = dfll_clk_is_enabled, | ||
600 | .enable = dfll_clk_enable, | ||
601 | .disable = dfll_clk_disable, | ||
602 | }; | ||
603 | |||
604 | static struct clk_init_data dfll_clk_init_data = { | ||
605 | .flags = CLK_IS_ROOT, | ||
606 | .ops = &dfll_clk_ops, | ||
607 | .num_parents = 0, | ||
608 | }; | ||
609 | |||
610 | /** | ||
611 | * dfll_register_clk - register the DFLL output clock with the clock framework | ||
612 | * @td: DFLL instance | ||
613 | * | ||
614 | * Register the DFLL's output clock with the Linux clock framework and register | ||
615 | * the DFLL driver as an OF clock provider. Returns 0 upon success or -EINVAL | ||
616 | * or -ENOMEM upon failure. | ||
617 | */ | ||
618 | static int dfll_register_clk(struct tegra_dfll *td) | ||
619 | { | ||
620 | int ret; | ||
621 | |||
622 | dfll_clk_init_data.name = td->output_clock_name; | ||
623 | td->dfll_clk_hw.init = &dfll_clk_init_data; | ||
624 | |||
625 | td->dfll_clk = clk_register(td->dev, &td->dfll_clk_hw); | ||
626 | if (IS_ERR(td->dfll_clk)) { | ||
627 | dev_err(td->dev, "DFLL clock registration error\n"); | ||
628 | return -EINVAL; | ||
629 | } | ||
630 | |||
631 | ret = of_clk_add_provider(td->dev->of_node, of_clk_src_simple_get, | ||
632 | td->dfll_clk); | ||
633 | if (ret) { | ||
634 | dev_err(td->dev, "of_clk_add_provider() failed\n"); | ||
635 | |||
636 | clk_unregister(td->dfll_clk); | ||
637 | return ret; | ||
638 | } | ||
639 | |||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | /** | ||
644 | * dfll_unregister_clk - unregister the DFLL output clock | ||
645 | * @td: DFLL instance | ||
646 | * | ||
647 | * Unregister the DFLL's output clock from the Linux clock framework | ||
648 | * and from clkdev. No return value. | ||
649 | */ | ||
650 | static void dfll_unregister_clk(struct tegra_dfll *td) | ||
651 | { | ||
652 | of_clk_del_provider(td->dev->of_node); | ||
653 | clk_unregister(td->dfll_clk); | ||
654 | td->dfll_clk = NULL; | ||
655 | } | ||
656 | |||
657 | /* | ||
658 | * Debugfs interface | ||
659 | */ | ||
660 | |||
661 | #ifdef CONFIG_DEBUG_FS | ||
662 | |||
663 | static int attr_enable_get(void *data, u64 *val) | ||
664 | { | ||
665 | struct tegra_dfll *td = data; | ||
666 | |||
667 | *val = dfll_is_running(td); | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | static int attr_enable_set(void *data, u64 val) | ||
672 | { | ||
673 | struct tegra_dfll *td = data; | ||
674 | |||
675 | return val ? dfll_enable(td) : dfll_disable(td); | ||
676 | } | ||
677 | DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, | ||
678 | "%llu\n"); | ||
679 | |||
680 | static int attr_rate_get(void *data, u64 *val) | ||
681 | { | ||
682 | struct tegra_dfll *td = data; | ||
683 | |||
684 | *val = dfll_read_monitor_rate(td); | ||
685 | |||
686 | return 0; | ||
687 | } | ||
688 | DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, NULL, "%llu\n"); | ||
689 | |||
690 | static int attr_registers_show(struct seq_file *s, void *data) | ||
691 | { | ||
692 | u32 val, offs; | ||
693 | struct tegra_dfll *td = s->private; | ||
694 | |||
695 | seq_puts(s, "CONTROL REGISTERS:\n"); | ||
696 | for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) { | ||
697 | if (offs == DFLL_OUTPUT_CFG) | ||
698 | val = dfll_i2c_readl(td, offs); | ||
699 | else | ||
700 | val = dfll_readl(td, offs); | ||
701 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, val); | ||
702 | } | ||
703 | |||
704 | seq_puts(s, "\nI2C and INTR REGISTERS:\n"); | ||
705 | for (offs = DFLL_I2C_CFG; offs <= DFLL_I2C_STS; offs += 4) | ||
706 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, | ||
707 | dfll_i2c_readl(td, offs)); | ||
708 | for (offs = DFLL_INTR_STS; offs <= DFLL_INTR_EN; offs += 4) | ||
709 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, | ||
710 | dfll_i2c_readl(td, offs)); | ||
711 | |||
712 | seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n"); | ||
713 | offs = DFLL_I2C_CLK_DIVISOR; | ||
714 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, | ||
715 | __raw_readl(td->i2c_controller_base + offs)); | ||
716 | |||
717 | seq_puts(s, "\nLUT:\n"); | ||
718 | for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4) | ||
719 | seq_printf(s, "[0x%02x] = 0x%08x\n", offs, | ||
720 | __raw_readl(td->lut_base + offs)); | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static int attr_registers_open(struct inode *inode, struct file *file) | ||
726 | { | ||
727 | return single_open(file, attr_registers_show, inode->i_private); | ||
728 | } | ||
729 | |||
730 | static const struct file_operations attr_registers_fops = { | ||
731 | .open = attr_registers_open, | ||
732 | .read = seq_read, | ||
733 | .llseek = seq_lseek, | ||
734 | .release = single_release, | ||
735 | }; | ||
736 | |||
737 | static int dfll_debug_init(struct tegra_dfll *td) | ||
738 | { | ||
739 | int ret; | ||
740 | |||
741 | if (!td || (td->mode == DFLL_UNINITIALIZED)) | ||
742 | return 0; | ||
743 | |||
744 | td->debugfs_dir = debugfs_create_dir("tegra_dfll_fcpu", NULL); | ||
745 | if (!td->debugfs_dir) | ||
746 | return -ENOMEM; | ||
747 | |||
748 | ret = -ENOMEM; | ||
749 | |||
750 | if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR, | ||
751 | td->debugfs_dir, td, &enable_fops)) | ||
752 | goto err_out; | ||
753 | |||
754 | if (!debugfs_create_file("rate", S_IRUGO, | ||
755 | td->debugfs_dir, td, &rate_fops)) | ||
756 | goto err_out; | ||
757 | |||
758 | if (!debugfs_create_file("registers", S_IRUGO, | ||
759 | td->debugfs_dir, td, &attr_registers_fops)) | ||
760 | goto err_out; | ||
761 | |||
762 | return 0; | ||
763 | |||
764 | err_out: | ||
765 | debugfs_remove_recursive(td->debugfs_dir); | ||
766 | return ret; | ||
767 | } | ||
768 | |||
769 | #endif /* CONFIG_DEBUG_FS */ | ||
770 | |||
771 | /* | ||
772 | * DFLL initialization | ||
773 | */ | ||
774 | |||
775 | /** | ||
776 | * dfll_set_default_params - program non-output related DFLL parameters | ||
777 | * @td: DFLL instance | ||
778 | * | ||
779 | * During DFLL driver initialization or resume from context loss, | ||
780 | * program parameters for the closed loop integrator, DVCO tuning, | ||
781 | * voltage droop control and monitor control. | ||
782 | */ | ||
783 | static void dfll_set_default_params(struct tegra_dfll *td) | ||
784 | { | ||
785 | dfll_tune_low(td); | ||
786 | dfll_writel(td, td->droop_ctrl, DFLL_DROOP_CTRL); | ||
787 | dfll_writel(td, DFLL_MONITOR_CTRL_FREQ, DFLL_MONITOR_CTRL); | ||
788 | } | ||
789 | |||
790 | /** | ||
791 | * dfll_init_clks - clk_get() the DFLL source clocks | ||
792 | * @td: DFLL instance | ||
793 | * | ||
794 | * Call clk_get() on the DFLL source clocks and save the pointers for later | ||
795 | * use. Returns 0 upon success or error (see devm_clk_get) if one or more | ||
796 | * of the clocks couldn't be looked up. | ||
797 | */ | ||
798 | static int dfll_init_clks(struct tegra_dfll *td) | ||
799 | { | ||
800 | td->ref_clk = devm_clk_get(td->dev, "ref"); | ||
801 | if (IS_ERR(td->ref_clk)) { | ||
802 | dev_err(td->dev, "missing ref clock\n"); | ||
803 | return PTR_ERR(td->ref_clk); | ||
804 | } | ||
805 | |||
806 | td->soc_clk = devm_clk_get(td->dev, "soc"); | ||
807 | if (IS_ERR(td->soc_clk)) { | ||
808 | dev_err(td->dev, "missing soc clock\n"); | ||
809 | return PTR_ERR(td->soc_clk); | ||
810 | } | ||
811 | |||
812 | td->i2c_clk = devm_clk_get(td->dev, "i2c"); | ||
813 | if (IS_ERR(td->i2c_clk)) { | ||
814 | dev_err(td->dev, "missing i2c clock\n"); | ||
815 | return PTR_ERR(td->i2c_clk); | ||
816 | } | ||
817 | td->i2c_clk_rate = clk_get_rate(td->i2c_clk); | ||
818 | |||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * dfll_init - Prepare the DFLL IP block for use | ||
824 | * @td: DFLL instance | ||
825 | * | ||
826 | * Do everything necessary to prepare the DFLL IP block for use. The | ||
827 | * DFLL will be left in DISABLED state. Called by dfll_probe(). | ||
828 | * Returns 0 upon success, or passes along the error from whatever | ||
829 | * function returned it. | ||
830 | */ | ||
831 | static int dfll_init(struct tegra_dfll *td) | ||
832 | { | ||
833 | int ret; | ||
834 | |||
835 | td->ref_rate = clk_get_rate(td->ref_clk); | ||
836 | if (td->ref_rate != REF_CLOCK_RATE) { | ||
837 | dev_err(td->dev, "unexpected ref clk rate %lu, expecting %lu", | ||
838 | td->ref_rate, REF_CLOCK_RATE); | ||
839 | return -EINVAL; | ||
840 | } | ||
841 | |||
842 | reset_control_deassert(td->dvco_rst); | ||
843 | |||
844 | ret = clk_prepare(td->ref_clk); | ||
845 | if (ret) { | ||
846 | dev_err(td->dev, "failed to prepare ref_clk\n"); | ||
847 | return ret; | ||
848 | } | ||
849 | |||
850 | ret = clk_prepare(td->soc_clk); | ||
851 | if (ret) { | ||
852 | dev_err(td->dev, "failed to prepare soc_clk\n"); | ||
853 | goto di_err1; | ||
854 | } | ||
855 | |||
856 | ret = clk_prepare(td->i2c_clk); | ||
857 | if (ret) { | ||
858 | dev_err(td->dev, "failed to prepare i2c_clk\n"); | ||
859 | goto di_err2; | ||
860 | } | ||
861 | |||
862 | pm_runtime_enable(td->dev); | ||
863 | pm_runtime_get_sync(td->dev); | ||
864 | |||
865 | dfll_set_mode(td, DFLL_DISABLED); | ||
866 | dfll_set_default_params(td); | ||
867 | |||
868 | if (td->soc->init_clock_trimmers) | ||
869 | td->soc->init_clock_trimmers(); | ||
870 | |||
871 | dfll_set_open_loop_config(td); | ||
872 | |||
873 | pm_runtime_put_sync(td->dev); | ||
874 | |||
875 | return 0; | ||
876 | |||
877 | di_err2: | ||
878 | clk_unprepare(td->soc_clk); | ||
879 | di_err1: | ||
880 | clk_unprepare(td->ref_clk); | ||
881 | |||
882 | reset_control_assert(td->dvco_rst); | ||
883 | |||
884 | return ret; | ||
885 | } | ||
886 | |||
887 | /* | ||
888 | * DT data fetch | ||
889 | */ | ||
890 | |||
891 | /** | ||
892 | * read_dt_param - helper function for reading required parameters from the DT | ||
893 | * @td: DFLL instance | ||
894 | * @param: DT property name | ||
895 | * @dest: output pointer for the value read | ||
896 | * | ||
897 | * Read a required numeric parameter from the DFLL device node, or complain | ||
898 | * if the property doesn't exist. Returns a boolean indicating success for | ||
899 | * easy chaining of multiple calls to this function. | ||
900 | */ | ||
901 | static bool read_dt_param(struct tegra_dfll *td, const char *param, u32 *dest) | ||
902 | { | ||
903 | int err = of_property_read_u32(td->dev->of_node, param, dest); | ||
904 | |||
905 | if (err < 0) { | ||
906 | dev_err(td->dev, "failed to read DT parameter %s: %d\n", | ||
907 | param, err); | ||
908 | return false; | ||
909 | } | ||
910 | |||
911 | return true; | ||
912 | } | ||
913 | |||
914 | /** | ||
915 | * dfll_fetch_common_params - read DFLL parameters from the device tree | ||
916 | * @td: DFLL instance | ||
917 | * | ||
918 | * Read all the DT parameters that are common to both I2C and PWM operation. | ||
919 | * Returns 0 on success or -EINVAL on any failure. | ||
920 | */ | ||
921 | static int dfll_fetch_common_params(struct tegra_dfll *td) | ||
922 | { | ||
923 | bool ok = true; | ||
924 | |||
925 | ok &= read_dt_param(td, "nvidia,droop-ctrl", &td->droop_ctrl); | ||
926 | |||
927 | if (of_property_read_string(td->dev->of_node, "clock-output-names", | ||
928 | &td->output_clock_name)) { | ||
929 | dev_err(td->dev, "missing clock-output-names property\n"); | ||
930 | ok = false; | ||
931 | } | ||
932 | |||
933 | return ok ? 0 : -EINVAL; | ||
934 | } | ||
935 | |||
936 | /* | ||
937 | * API exported to per-SoC platform drivers | ||
938 | */ | ||
939 | |||
940 | /** | ||
941 | * tegra_dfll_register - probe a Tegra DFLL device | ||
942 | * @pdev: DFLL platform_device * | ||
943 | * @soc: Per-SoC integration and characterization data for this DFLL instance | ||
944 | * | ||
945 | * Probe and initialize a DFLL device instance. Intended to be called | ||
946 | * by a SoC-specific shim driver that passes in per-SoC integration | ||
947 | * and configuration data via @soc. Returns 0 on success or -err on failure. | ||
948 | */ | ||
949 | int tegra_dfll_register(struct platform_device *pdev, | ||
950 | struct tegra_dfll_soc_data *soc) | ||
951 | { | ||
952 | struct resource *mem; | ||
953 | struct tegra_dfll *td; | ||
954 | int ret; | ||
955 | |||
956 | if (!soc) { | ||
957 | dev_err(&pdev->dev, "no tegra_dfll_soc_data provided\n"); | ||
958 | return -EINVAL; | ||
959 | } | ||
960 | |||
961 | td = devm_kzalloc(&pdev->dev, sizeof(*td), GFP_KERNEL); | ||
962 | if (!td) | ||
963 | return -ENOMEM; | ||
964 | td->dev = &pdev->dev; | ||
965 | platform_set_drvdata(pdev, td); | ||
966 | |||
967 | td->soc = soc; | ||
968 | |||
969 | td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu"); | ||
970 | if (IS_ERR(td->vdd_reg)) { | ||
971 | dev_err(td->dev, "couldn't get vdd_cpu regulator\n"); | ||
972 | return PTR_ERR(td->vdd_reg); | ||
973 | } | ||
974 | |||
975 | td->dvco_rst = devm_reset_control_get(td->dev, "dvco"); | ||
976 | if (IS_ERR(td->dvco_rst)) { | ||
977 | dev_err(td->dev, "couldn't get dvco reset\n"); | ||
978 | return PTR_ERR(td->dvco_rst); | ||
979 | } | ||
980 | |||
981 | ret = dfll_fetch_common_params(td); | ||
982 | if (ret) { | ||
983 | dev_err(td->dev, "couldn't parse device tree parameters\n"); | ||
984 | return ret; | ||
985 | } | ||
986 | |||
987 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
988 | if (!mem) { | ||
989 | dev_err(td->dev, "no control register resource\n"); | ||
990 | return -ENODEV; | ||
991 | } | ||
992 | |||
993 | td->base = devm_ioremap(td->dev, mem->start, resource_size(mem)); | ||
994 | if (!td->base) { | ||
995 | dev_err(td->dev, "couldn't ioremap DFLL control registers\n"); | ||
996 | return -ENODEV; | ||
997 | } | ||
998 | |||
999 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1000 | if (!mem) { | ||
1001 | dev_err(td->dev, "no i2c_base resource\n"); | ||
1002 | return -ENODEV; | ||
1003 | } | ||
1004 | |||
1005 | td->i2c_base = devm_ioremap(td->dev, mem->start, resource_size(mem)); | ||
1006 | if (!td->i2c_base) { | ||
1007 | dev_err(td->dev, "couldn't ioremap i2c_base resource\n"); | ||
1008 | return -ENODEV; | ||
1009 | } | ||
1010 | |||
1011 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 2); | ||
1012 | if (!mem) { | ||
1013 | dev_err(td->dev, "no i2c_controller_base resource\n"); | ||
1014 | return -ENODEV; | ||
1015 | } | ||
1016 | |||
1017 | td->i2c_controller_base = devm_ioremap(td->dev, mem->start, | ||
1018 | resource_size(mem)); | ||
1019 | if (!td->i2c_controller_base) { | ||
1020 | dev_err(td->dev, | ||
1021 | "couldn't ioremap i2c_controller_base resource\n"); | ||
1022 | return -ENODEV; | ||
1023 | } | ||
1024 | |||
1025 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 3); | ||
1026 | if (!mem) { | ||
1027 | dev_err(td->dev, "no lut_base resource\n"); | ||
1028 | return -ENODEV; | ||
1029 | } | ||
1030 | |||
1031 | td->lut_base = devm_ioremap(td->dev, mem->start, resource_size(mem)); | ||
1032 | if (!td->lut_base) { | ||
1033 | dev_err(td->dev, | ||
1034 | "couldn't ioremap lut_base resource\n"); | ||
1035 | return -ENODEV; | ||
1036 | } | ||
1037 | |||
1038 | ret = dfll_init_clks(td); | ||
1039 | if (ret) { | ||
1040 | dev_err(&pdev->dev, "DFLL clock init error\n"); | ||
1041 | return ret; | ||
1042 | } | ||
1043 | |||
1044 | /* Enable the clocks and set the device up */ | ||
1045 | ret = dfll_init(td); | ||
1046 | if (ret) | ||
1047 | return ret; | ||
1048 | |||
1049 | ret = dfll_register_clk(td); | ||
1050 | if (ret) { | ||
1051 | dev_err(&pdev->dev, "DFLL clk registration failed\n"); | ||
1052 | return ret; | ||
1053 | } | ||
1054 | |||
1055 | #ifdef CONFIG_DEBUG_FS | ||
1056 | dfll_debug_init(td); | ||
1057 | #endif | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | EXPORT_SYMBOL(tegra_dfll_register); | ||
1062 | |||
1063 | /** | ||
1064 | * tegra_dfll_unregister - release all of the DFLL driver resources for a device | ||
1065 | * @pdev: DFLL platform_device * | ||
1066 | * | ||
1067 | * Unbind this driver from the DFLL hardware device represented by | ||
1068 | * @pdev. The DFLL must be disabled for this to succeed. Returns 0 | ||
1069 | * upon success or -EBUSY if the DFLL is still active. | ||
1070 | */ | ||
1071 | int tegra_dfll_unregister(struct platform_device *pdev) | ||
1072 | { | ||
1073 | struct tegra_dfll *td = platform_get_drvdata(pdev); | ||
1074 | |||
1075 | /* Try to prevent removal while the DFLL is active */ | ||
1076 | if (td->mode != DFLL_DISABLED) { | ||
1077 | dev_err(&pdev->dev, | ||
1078 | "must disable DFLL before removing driver\n"); | ||
1079 | return -EBUSY; | ||
1080 | } | ||
1081 | |||
1082 | debugfs_remove_recursive(td->debugfs_dir); | ||
1083 | |||
1084 | dfll_unregister_clk(td); | ||
1085 | pm_runtime_disable(&pdev->dev); | ||
1086 | |||
1087 | clk_unprepare(td->ref_clk); | ||
1088 | clk_unprepare(td->soc_clk); | ||
1089 | clk_unprepare(td->i2c_clk); | ||
1090 | |||
1091 | reset_control_assert(td->dvco_rst); | ||
1092 | |||
1093 | return 0; | ||
1094 | } | ||
1095 | EXPORT_SYMBOL(tegra_dfll_unregister); | ||
diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h new file mode 100644 index 000000000000..b5d1fd47684e --- /dev/null +++ b/drivers/clk/tegra/clk-dfll.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * clk-dfll.h - prototypes and macros for the Tegra DFLL clocksource driver | ||
3 | * Copyright (C) 2013 NVIDIA Corporation. All rights reserved. | ||
4 | * | ||
5 | * Aleksandr Frid <afrid@nvidia.com> | ||
6 | * Paul Walmsley <pwalmsley@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | */ | ||
17 | |||
18 | #ifndef __DRIVERS_CLK_TEGRA_CLK_DFLL_H | ||
19 | #define __DRIVERS_CLK_TEGRA_CLK_DFLL_H | ||
20 | |||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/reset.h> | ||
23 | #include <linux/types.h> | ||
24 | |||
25 | /** | ||
26 | * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver | ||
27 | * @opp_dev: struct device * that holds the OPP table for the DFLL | ||
28 | * @min_millivolts: minimum voltage (in mV) that the DFLL can operate | ||
29 | * @tune0_low: DFLL tuning register 0 (low voltage range) | ||
30 | * @tune0_high: DFLL tuning register 0 (high voltage range) | ||
31 | * @tune1: DFLL tuning register 1 | ||
32 | * @assert_dvco_reset: fn ptr to place the DVCO in reset | ||
33 | * @deassert_dvco_reset: fn ptr to release the DVCO reset | ||
34 | * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage | ||
35 | * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage | ||
36 | */ | ||
37 | struct tegra_dfll_soc_data { | ||
38 | struct device *opp_dev; | ||
39 | unsigned int min_millivolts; | ||
40 | u32 tune0_low; | ||
41 | u32 tune0_high; | ||
42 | u32 tune1; | ||
43 | void (*init_clock_trimmers)(void); | ||
44 | void (*set_clock_trimmers_high)(void); | ||
45 | void (*set_clock_trimmers_low)(void); | ||
46 | }; | ||
47 | |||
48 | int tegra_dfll_register(struct platform_device *pdev, | ||
49 | struct tegra_dfll_soc_data *soc); | ||
50 | int tegra_dfll_unregister(struct platform_device *pdev); | ||
51 | int tegra_dfll_runtime_suspend(struct device *dev); | ||
52 | int tegra_dfll_runtime_resume(struct device *dev); | ||
53 | |||
54 | #endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */ | ||