clk-loongson1c.c (2885B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2016 Yang Ling <gnaygnil@gmail.com> 4 */ 5 6#include <linux/clkdev.h> 7#include <linux/clk-provider.h> 8#include <linux/io.h> 9 10#include <loongson1.h> 11#include "clk.h" 12 13#define OSC (24 * 1000000) 14#define DIV_APB 1 15 16static DEFINE_SPINLOCK(_lock); 17 18static unsigned long ls1x_pll_recalc_rate(struct clk_hw *hw, 19 unsigned long parent_rate) 20{ 21 u32 pll, rate; 22 23 pll = __raw_readl(LS1X_CLK_PLL_FREQ); 24 rate = ((pll >> 8) & 0xff) + ((pll >> 16) & 0xff); 25 rate *= OSC; 26 rate >>= 2; 27 28 return rate; 29} 30 31static const struct clk_ops ls1x_pll_clk_ops = { 32 .recalc_rate = ls1x_pll_recalc_rate, 33}; 34 35static const struct clk_div_table ahb_div_table[] = { 36 [0] = { .val = 0, .div = 2 }, 37 [1] = { .val = 1, .div = 4 }, 38 [2] = { .val = 2, .div = 3 }, 39 [3] = { .val = 3, .div = 3 }, 40 [4] = { /* sentinel */ } 41}; 42 43void __init ls1x_clk_init(void) 44{ 45 struct clk_hw *hw; 46 47 hw = clk_hw_register_fixed_rate(NULL, "osc_clk", NULL, 0, OSC); 48 clk_hw_register_clkdev(hw, "osc_clk", NULL); 49 50 /* clock derived from 24 MHz OSC clk */ 51 hw = clk_hw_register_pll(NULL, "pll_clk", "osc_clk", 52 &ls1x_pll_clk_ops, 0); 53 clk_hw_register_clkdev(hw, "pll_clk", NULL); 54 55 hw = clk_hw_register_divider(NULL, "cpu_clk_div", "pll_clk", 56 CLK_GET_RATE_NOCACHE, LS1X_CLK_PLL_DIV, 57 DIV_CPU_SHIFT, DIV_CPU_WIDTH, 58 CLK_DIVIDER_ONE_BASED | 59 CLK_DIVIDER_ROUND_CLOSEST, &_lock); 60 clk_hw_register_clkdev(hw, "cpu_clk_div", NULL); 61 hw = clk_hw_register_fixed_factor(NULL, "cpu_clk", "cpu_clk_div", 62 0, 1, 1); 63 clk_hw_register_clkdev(hw, "cpu_clk", NULL); 64 65 hw = clk_hw_register_divider(NULL, "dc_clk_div", "pll_clk", 66 0, LS1X_CLK_PLL_DIV, DIV_DC_SHIFT, 67 DIV_DC_WIDTH, CLK_DIVIDER_ONE_BASED, &_lock); 68 clk_hw_register_clkdev(hw, "dc_clk_div", NULL); 69 hw = clk_hw_register_fixed_factor(NULL, "dc_clk", "dc_clk_div", 70 0, 1, 1); 71 clk_hw_register_clkdev(hw, "dc_clk", NULL); 72 73 hw = clk_hw_register_divider_table(NULL, "ahb_clk_div", "cpu_clk_div", 74 0, LS1X_CLK_PLL_FREQ, DIV_DDR_SHIFT, 75 DIV_DDR_WIDTH, CLK_DIVIDER_ALLOW_ZERO, 76 ahb_div_table, &_lock); 77 clk_hw_register_clkdev(hw, "ahb_clk_div", NULL); 78 hw = clk_hw_register_fixed_factor(NULL, "ahb_clk", "ahb_clk_div", 79 0, 1, 1); 80 clk_hw_register_clkdev(hw, "ahb_clk", NULL); 81 clk_hw_register_clkdev(hw, "ls1x-dma", NULL); 82 clk_hw_register_clkdev(hw, "stmmaceth", NULL); 83 84 /* clock derived from AHB clk */ 85 hw = clk_hw_register_fixed_factor(NULL, "apb_clk", "ahb_clk", 0, 1, 86 DIV_APB); 87 clk_hw_register_clkdev(hw, "apb_clk", NULL); 88 clk_hw_register_clkdev(hw, "ls1x-ac97", NULL); 89 clk_hw_register_clkdev(hw, "ls1x-i2c", NULL); 90 clk_hw_register_clkdev(hw, "ls1x-nand", NULL); 91 clk_hw_register_clkdev(hw, "ls1x-pwmtimer", NULL); 92 clk_hw_register_clkdev(hw, "ls1x-spi", NULL); 93 clk_hw_register_clkdev(hw, "ls1x-wdt", NULL); 94 clk_hw_register_clkdev(hw, "serial8250", NULL); 95}