.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2014 MediaTek Inc. |
---|
3 | 4 | * Author: James Liao <jamesjj.liao@mediatek.com> |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License version 2 as |
---|
7 | | - * published by the Free Software Foundation. |
---|
8 | | - * |
---|
9 | | - * This program is distributed in the hope that it will be useful, |
---|
10 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
12 | | - * GNU General Public License for more details. |
---|
13 | 5 | */ |
---|
14 | 6 | |
---|
15 | 7 | #include <linux/of.h> |
---|
.. | .. |
---|
27 | 19 | #define CON0_BASE_EN BIT(0) |
---|
28 | 20 | #define CON0_PWR_ON BIT(0) |
---|
29 | 21 | #define CON0_ISO_EN BIT(1) |
---|
30 | | -#define CON0_PCW_CHG BIT(31) |
---|
| 22 | +#define PCW_CHG_MASK BIT(31) |
---|
31 | 23 | |
---|
32 | 24 | #define AUDPLL_TUNER_EN BIT(31) |
---|
33 | 25 | |
---|
34 | 26 | #define POSTDIV_MASK 0x7 |
---|
| 27 | + |
---|
| 28 | +/* default 7 bits integer, can be overridden with pcwibits. */ |
---|
35 | 29 | #define INTEGER_BITS 7 |
---|
36 | 30 | |
---|
37 | 31 | /* |
---|
.. | .. |
---|
49 | 43 | void __iomem *tuner_addr; |
---|
50 | 44 | void __iomem *tuner_en_addr; |
---|
51 | 45 | void __iomem *pcw_addr; |
---|
| 46 | + void __iomem *pcw_chg_addr; |
---|
52 | 47 | const struct mtk_pll_data *data; |
---|
53 | 48 | }; |
---|
54 | 49 | |
---|
.. | .. |
---|
68 | 63 | u32 pcw, int postdiv) |
---|
69 | 64 | { |
---|
70 | 65 | int pcwbits = pll->data->pcwbits; |
---|
71 | | - int pcwfbits; |
---|
| 66 | + int pcwfbits = 0; |
---|
| 67 | + int ibits; |
---|
72 | 68 | u64 vco; |
---|
73 | 69 | u8 c = 0; |
---|
74 | 70 | |
---|
75 | 71 | /* The fractional part of the PLL divider. */ |
---|
76 | | - pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0; |
---|
| 72 | + ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS; |
---|
| 73 | + if (pcwbits > ibits) |
---|
| 74 | + pcwfbits = pcwbits - ibits; |
---|
77 | 75 | |
---|
78 | 76 | vco = (u64)fin * pcw; |
---|
79 | 77 | |
---|
.. | .. |
---|
117 | 115 | static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, |
---|
118 | 116 | int postdiv) |
---|
119 | 117 | { |
---|
120 | | - u32 con1, val; |
---|
121 | | - int pll_en; |
---|
122 | | - |
---|
123 | | - pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN; |
---|
| 118 | + u32 chg, val; |
---|
124 | 119 | |
---|
125 | 120 | /* disable tuner */ |
---|
126 | 121 | __mtk_pll_tuner_disable(pll); |
---|
.. | .. |
---|
141 | 136 | pll->data->pcw_shift); |
---|
142 | 137 | val |= pcw << pll->data->pcw_shift; |
---|
143 | 138 | writel(val, pll->pcw_addr); |
---|
144 | | - |
---|
145 | | - con1 = readl(pll->base_addr + REG_CON1); |
---|
146 | | - |
---|
147 | | - if (pll_en) |
---|
148 | | - con1 |= CON0_PCW_CHG; |
---|
149 | | - |
---|
150 | | - writel(con1, pll->base_addr + REG_CON1); |
---|
| 139 | + chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK; |
---|
| 140 | + writel(chg, pll->pcw_chg_addr); |
---|
151 | 141 | if (pll->tuner_addr) |
---|
152 | | - writel(con1 + 1, pll->tuner_addr); |
---|
| 142 | + writel(val + 1, pll->tuner_addr); |
---|
153 | 143 | |
---|
154 | 144 | /* restore tuner_en */ |
---|
155 | 145 | __mtk_pll_tuner_enable(pll); |
---|
156 | 146 | |
---|
157 | | - if (pll_en) |
---|
158 | | - udelay(20); |
---|
| 147 | + udelay(20); |
---|
159 | 148 | } |
---|
160 | 149 | |
---|
161 | 150 | /* |
---|
.. | .. |
---|
170 | 159 | static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, |
---|
171 | 160 | u32 freq, u32 fin) |
---|
172 | 161 | { |
---|
173 | | - unsigned long fmin = 1000 * MHZ; |
---|
| 162 | + unsigned long fmin = pll->data->fmin ? pll->data->fmin : (1000 * MHZ); |
---|
174 | 163 | const struct mtk_pll_div_table *div_table = pll->data->div_table; |
---|
175 | 164 | u64 _pcw; |
---|
| 165 | + int ibits; |
---|
176 | 166 | u32 val; |
---|
177 | 167 | |
---|
178 | 168 | if (freq > pll->data->fmax) |
---|
.. | .. |
---|
196 | 186 | } |
---|
197 | 187 | |
---|
198 | 188 | /* _pcw = freq * postdiv / fin * 2^pcwfbits */ |
---|
199 | | - _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS); |
---|
| 189 | + ibits = pll->data->pcwibits ? pll->data->pcwibits : INTEGER_BITS; |
---|
| 190 | + _pcw = ((u64)freq << val) << (pll->data->pcwbits - ibits); |
---|
200 | 191 | do_div(_pcw, fin); |
---|
201 | 192 | |
---|
202 | 193 | *pcw = (u32)_pcw; |
---|
.. | .. |
---|
322 | 313 | pll->pwr_addr = base + data->pwr_reg; |
---|
323 | 314 | pll->pd_addr = base + data->pd_reg; |
---|
324 | 315 | pll->pcw_addr = base + data->pcw_reg; |
---|
| 316 | + if (data->pcw_chg_reg) |
---|
| 317 | + pll->pcw_chg_addr = base + data->pcw_chg_reg; |
---|
| 318 | + else |
---|
| 319 | + pll->pcw_chg_addr = pll->base_addr + REG_CON1; |
---|
325 | 320 | if (data->tuner_reg) |
---|
326 | 321 | pll->tuner_addr = base + data->tuner_reg; |
---|
327 | 322 | if (data->tuner_en_reg) |
---|