clk.c (3496B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * 4 * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 5 * Copyright (C) 2010 John Crispin <john@phrozen.org> 6 */ 7#include <linux/io.h> 8#include <linux/export.h> 9#include <linux/init.h> 10#include <linux/kernel.h> 11#include <linux/types.h> 12#include <linux/clk.h> 13#include <linux/clkdev.h> 14#include <linux/err.h> 15#include <linux/list.h> 16 17#include <asm/time.h> 18#include <asm/irq.h> 19#include <asm/div64.h> 20 21#include <lantiq_soc.h> 22 23#include "clk.h" 24#include "prom.h" 25 26/* lantiq socs have 3 static clocks */ 27static struct clk cpu_clk_generic[4]; 28 29void clkdev_add_static(unsigned long cpu, unsigned long fpi, 30 unsigned long io, unsigned long ppe) 31{ 32 cpu_clk_generic[0].rate = cpu; 33 cpu_clk_generic[1].rate = fpi; 34 cpu_clk_generic[2].rate = io; 35 cpu_clk_generic[3].rate = ppe; 36} 37 38struct clk *clk_get_cpu(void) 39{ 40 return &cpu_clk_generic[0]; 41} 42 43struct clk *clk_get_fpi(void) 44{ 45 return &cpu_clk_generic[1]; 46} 47EXPORT_SYMBOL_GPL(clk_get_fpi); 48 49struct clk *clk_get_io(void) 50{ 51 return &cpu_clk_generic[2]; 52} 53 54struct clk *clk_get_ppe(void) 55{ 56 return &cpu_clk_generic[3]; 57} 58EXPORT_SYMBOL_GPL(clk_get_ppe); 59 60static inline int clk_good(struct clk *clk) 61{ 62 return clk && !IS_ERR(clk); 63} 64 65unsigned long clk_get_rate(struct clk *clk) 66{ 67 if (unlikely(!clk_good(clk))) 68 return 0; 69 70 if (clk->rate != 0) 71 return clk->rate; 72 73 if (clk->get_rate != NULL) 74 return clk->get_rate(); 75 76 return 0; 77} 78EXPORT_SYMBOL(clk_get_rate); 79 80int clk_set_rate(struct clk *clk, unsigned long rate) 81{ 82 if (unlikely(!clk_good(clk))) 83 return 0; 84 if (clk->rates && *clk->rates) { 85 unsigned long *r = clk->rates; 86 87 while (*r && (*r != rate)) 88 r++; 89 if (!*r) { 90 pr_err("clk %s.%s: trying to set invalid rate %ld\n", 91 clk->cl.dev_id, clk->cl.con_id, rate); 92 return -1; 93 } 94 } 95 clk->rate = rate; 96 return 0; 97} 98EXPORT_SYMBOL(clk_set_rate); 99 100long clk_round_rate(struct clk *clk, unsigned long rate) 101{ 102 if (unlikely(!clk_good(clk))) 103 return 0; 104 if (clk->rates && *clk->rates) { 105 unsigned long *r = clk->rates; 106 107 while (*r && (*r != rate)) 108 r++; 109 if (!*r) { 110 return clk->rate; 111 } 112 } 113 return rate; 114} 115EXPORT_SYMBOL(clk_round_rate); 116 117int clk_enable(struct clk *clk) 118{ 119 if (unlikely(!clk_good(clk))) 120 return -1; 121 122 if (clk->enable) 123 return clk->enable(clk); 124 125 return -1; 126} 127EXPORT_SYMBOL(clk_enable); 128 129void clk_disable(struct clk *clk) 130{ 131 if (unlikely(!clk_good(clk))) 132 return; 133 134 if (clk->disable) 135 clk->disable(clk); 136} 137EXPORT_SYMBOL(clk_disable); 138 139int clk_activate(struct clk *clk) 140{ 141 if (unlikely(!clk_good(clk))) 142 return -1; 143 144 if (clk->activate) 145 return clk->activate(clk); 146 147 return -1; 148} 149EXPORT_SYMBOL(clk_activate); 150 151void clk_deactivate(struct clk *clk) 152{ 153 if (unlikely(!clk_good(clk))) 154 return; 155 156 if (clk->deactivate) 157 clk->deactivate(clk); 158} 159EXPORT_SYMBOL(clk_deactivate); 160 161struct clk *clk_get_parent(struct clk *clk) 162{ 163 return NULL; 164} 165EXPORT_SYMBOL(clk_get_parent); 166 167int clk_set_parent(struct clk *clk, struct clk *parent) 168{ 169 return 0; 170} 171EXPORT_SYMBOL(clk_set_parent); 172 173static inline u32 get_counter_resolution(void) 174{ 175 u32 res; 176 177 __asm__ __volatile__( 178 ".set push\n" 179 ".set mips32r2\n" 180 "rdhwr %0, $3\n" 181 ".set pop\n" 182 : "=&r" (res) 183 : /* no input */ 184 : "memory"); 185 186 return res; 187} 188 189void __init plat_time_init(void) 190{ 191 struct clk *clk; 192 193 ltq_soc_init(); 194 195 clk = clk_get_cpu(); 196 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); 197 write_c0_compare(read_c0_count()); 198 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); 199 clk_put(clk); 200}