linux/arch/mips/lantiq/clk.c
<<
>>
Prefs
   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
 161static inline u32 get_counter_resolution(void)
 162{
 163        u32 res;
 164
 165        __asm__ __volatile__(
 166                ".set   push\n"
 167                ".set   mips32r2\n"
 168                "rdhwr  %0, $3\n"
 169                ".set pop\n"
 170                : "=&r" (res)
 171                : /* no input */
 172                : "memory");
 173
 174        return res;
 175}
 176
 177void __init plat_time_init(void)
 178{
 179        struct clk *clk;
 180
 181        ltq_soc_init();
 182
 183        clk = clk_get_cpu();
 184        mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution();
 185        write_c0_compare(read_c0_count());
 186        pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
 187        clk_put(clk);
 188}
 189