| .. | .. |
|---|
| 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) |
|---|