| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2016 Maxime Ripard. All rights reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This software is licensed under the terms of the GNU General Public |
|---|
| 5 | | - * License version 2, as published by the Free Software Foundation, and |
|---|
| 6 | | - * may be copied, distributed, and modified under those terms. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | | - * GNU General Public License for more details. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | |
|---|
| 14 | 6 | #include <linux/clk-provider.h> |
|---|
| 7 | +#include <linux/io.h> |
|---|
| 15 | 8 | #include <linux/of_address.h> |
|---|
| 16 | 9 | |
|---|
| 17 | 10 | #include "ccu_common.h" |
|---|
| .. | .. |
|---|
| 51 | 44 | * the base (2x, 4x and 8x), and one variable divider (the one true |
|---|
| 52 | 45 | * pll audio). |
|---|
| 53 | 46 | * |
|---|
| 54 | | - * We don't have any need for the variable divider for now, so we just |
|---|
| 55 | | - * hardcode it to match with the clock names |
|---|
| 47 | + * With sigma-delta modulation for fractional-N on the audio PLL, |
|---|
| 48 | + * we have to use specific dividers. This means the variable divider |
|---|
| 49 | + * can no longer be used, as the audio codec requests the exact clock |
|---|
| 50 | + * rates we support through this mechanism. So we now hard code the |
|---|
| 51 | + * variable divider to 1. This means the clock rates will no longer |
|---|
| 52 | + * match the clock names. |
|---|
| 56 | 53 | */ |
|---|
| 57 | 54 | #define SUN8I_A33_PLL_AUDIO_REG 0x008 |
|---|
| 58 | 55 | |
|---|
| 59 | | -static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", |
|---|
| 60 | | - "osc24M", 0x008, |
|---|
| 61 | | - 8, 7, /* N */ |
|---|
| 62 | | - 0, 5, /* M */ |
|---|
| 63 | | - BIT(31), /* gate */ |
|---|
| 64 | | - BIT(28), /* lock */ |
|---|
| 65 | | - CLK_SET_RATE_UNGATE); |
|---|
| 56 | +static struct ccu_sdm_setting pll_audio_sdm_table[] = { |
|---|
| 57 | + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, |
|---|
| 58 | + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, |
|---|
| 59 | +}; |
|---|
| 60 | + |
|---|
| 61 | +static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", |
|---|
| 62 | + "osc24M", 0x008, |
|---|
| 63 | + 8, 7, /* N */ |
|---|
| 64 | + 0, 5, /* M */ |
|---|
| 65 | + pll_audio_sdm_table, BIT(24), |
|---|
| 66 | + 0x284, BIT(31), |
|---|
| 67 | + BIT(31), /* gate */ |
|---|
| 68 | + BIT(28), /* lock */ |
|---|
| 69 | + CLK_SET_RATE_UNGATE); |
|---|
| 66 | 70 | |
|---|
| 67 | 71 | static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video", |
|---|
| 68 | 72 | "osc24M", 0x010, |
|---|
| .. | .. |
|---|
| 576 | 580 | &ats_clk.common, |
|---|
| 577 | 581 | }; |
|---|
| 578 | 582 | |
|---|
| 579 | | -/* We hardcode the divider to 4 for now */ |
|---|
| 580 | | -static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", |
|---|
| 581 | | - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); |
|---|
| 582 | | -static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", |
|---|
| 583 | | - "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); |
|---|
| 584 | | -static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", |
|---|
| 585 | | - "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); |
|---|
| 586 | | -static CLK_FIXED_FACTOR(pll_audio_8x_clk, "pll-audio-8x", |
|---|
| 587 | | - "pll-audio-base", 1, 2, CLK_SET_RATE_PARENT); |
|---|
| 588 | | -static CLK_FIXED_FACTOR(pll_periph_2x_clk, "pll-periph-2x", |
|---|
| 589 | | - "pll-periph", 1, 2, 0); |
|---|
| 590 | | -static CLK_FIXED_FACTOR(pll_video_2x_clk, "pll-video-2x", |
|---|
| 591 | | - "pll-video", 1, 2, 0); |
|---|
| 583 | +static const struct clk_hw *clk_parent_pll_audio[] = { |
|---|
| 584 | + &pll_audio_base_clk.common.hw |
|---|
| 585 | +}; |
|---|
| 586 | + |
|---|
| 587 | +/* We hardcode the divider to 1 for now */ |
|---|
| 588 | +static CLK_FIXED_FACTOR_HWS(pll_audio_clk, "pll-audio", |
|---|
| 589 | + clk_parent_pll_audio, |
|---|
| 590 | + 1, 1, CLK_SET_RATE_PARENT); |
|---|
| 591 | +static CLK_FIXED_FACTOR_HWS(pll_audio_2x_clk, "pll-audio-2x", |
|---|
| 592 | + clk_parent_pll_audio, |
|---|
| 593 | + 2, 1, CLK_SET_RATE_PARENT); |
|---|
| 594 | +static CLK_FIXED_FACTOR_HWS(pll_audio_4x_clk, "pll-audio-4x", |
|---|
| 595 | + clk_parent_pll_audio, |
|---|
| 596 | + 1, 1, CLK_SET_RATE_PARENT); |
|---|
| 597 | +static CLK_FIXED_FACTOR_HWS(pll_audio_8x_clk, "pll-audio-8x", |
|---|
| 598 | + clk_parent_pll_audio, |
|---|
| 599 | + 1, 2, CLK_SET_RATE_PARENT); |
|---|
| 600 | +static CLK_FIXED_FACTOR_HW(pll_periph_2x_clk, "pll-periph-2x", |
|---|
| 601 | + &pll_periph_clk.common.hw, |
|---|
| 602 | + 1, 2, 0); |
|---|
| 603 | +static CLK_FIXED_FACTOR_HW(pll_video_2x_clk, "pll-video-2x", |
|---|
| 604 | + &pll_video_clk.common.hw, |
|---|
| 605 | + 1, 2, 0); |
|---|
| 592 | 606 | |
|---|
| 593 | 607 | static struct clk_hw_onecell_data sun8i_a33_hw_clks = { |
|---|
| 594 | 608 | .hws = { |
|---|
| .. | .. |
|---|
| 781 | 795 | return; |
|---|
| 782 | 796 | } |
|---|
| 783 | 797 | |
|---|
| 784 | | - /* Force the PLL-Audio-1x divider to 4 */ |
|---|
| 798 | + /* Force the PLL-Audio-1x divider to 1 */ |
|---|
| 785 | 799 | val = readl(reg + SUN8I_A33_PLL_AUDIO_REG); |
|---|
| 786 | 800 | val &= ~GENMASK(19, 16); |
|---|
| 787 | | - writel(val | (3 << 16), reg + SUN8I_A33_PLL_AUDIO_REG); |
|---|
| 801 | + writel(val | (0 << 16), reg + SUN8I_A33_PLL_AUDIO_REG); |
|---|
| 788 | 802 | |
|---|
| 789 | 803 | /* Force PLL-MIPI to MIPI mode */ |
|---|
| 790 | 804 | val = readl(reg + SUN8I_A33_PLL_MIPI_REG); |
|---|