linux/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * arch/sh/kernel/cpu/sh4a/clock-sh7780.c
   4 *
   5 * SH7780 support for the clock framework
   6 *
   7 *  Copyright (C) 2005  Paul Mundt
   8 */
   9#include <linux/init.h>
  10#include <linux/kernel.h>
  11#include <linux/io.h>
  12#include <linux/clkdev.h>
  13#include <asm/clock.h>
  14#include <asm/freq.h>
  15#include <asm/io.h>
  16
  17static int ifc_divisors[] = { 2, 4 };
  18static int bfc_divisors[] = { 1, 1, 1, 8, 12, 16, 24, 1 };
  19static int pfc_divisors[] = { 1, 24, 24, 1 };
  20static int cfc_divisors[] = { 1, 1, 4, 1, 6, 1, 1, 1 };
  21
  22static void master_clk_init(struct clk *clk)
  23{
  24        clk->rate *= pfc_divisors[__raw_readl(FRQCR) & 0x0003];
  25}
  26
  27static struct sh_clk_ops sh7780_master_clk_ops = {
  28        .init           = master_clk_init,
  29};
  30
  31static unsigned long module_clk_recalc(struct clk *clk)
  32{
  33        int idx = (__raw_readl(FRQCR) & 0x0003);
  34        return clk->parent->rate / pfc_divisors[idx];
  35}
  36
  37static struct sh_clk_ops sh7780_module_clk_ops = {
  38        .recalc         = module_clk_recalc,
  39};
  40
  41static unsigned long bus_clk_recalc(struct clk *clk)
  42{
  43        int idx = ((__raw_readl(FRQCR) >> 16) & 0x0007);
  44        return clk->parent->rate / bfc_divisors[idx];
  45}
  46
  47static struct sh_clk_ops sh7780_bus_clk_ops = {
  48        .recalc         = bus_clk_recalc,
  49};
  50
  51static unsigned long cpu_clk_recalc(struct clk *clk)
  52{
  53        int idx = ((__raw_readl(FRQCR) >> 24) & 0x0001);
  54        return clk->parent->rate / ifc_divisors[idx];
  55}
  56
  57static struct sh_clk_ops sh7780_cpu_clk_ops = {
  58        .recalc         = cpu_clk_recalc,
  59};
  60
  61static struct sh_clk_ops *sh7780_clk_ops[] = {
  62        &sh7780_master_clk_ops,
  63        &sh7780_module_clk_ops,
  64        &sh7780_bus_clk_ops,
  65        &sh7780_cpu_clk_ops,
  66};
  67
  68void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
  69{
  70        if (idx < ARRAY_SIZE(sh7780_clk_ops))
  71                *ops = sh7780_clk_ops[idx];
  72}
  73
  74static unsigned long shyway_clk_recalc(struct clk *clk)
  75{
  76        int idx = ((__raw_readl(FRQCR) >> 20) & 0x0007);
  77        return clk->parent->rate / cfc_divisors[idx];
  78}
  79
  80static struct sh_clk_ops sh7780_shyway_clk_ops = {
  81        .recalc         = shyway_clk_recalc,
  82};
  83
  84static struct clk sh7780_shyway_clk = {
  85        .flags          = CLK_ENABLE_ON_INIT,
  86        .ops            = &sh7780_shyway_clk_ops,
  87};
  88
  89/*
  90 * Additional SH7780-specific on-chip clocks that aren't already part of the
  91 * clock framework
  92 */
  93static struct clk *sh7780_onchip_clocks[] = {
  94        &sh7780_shyway_clk,
  95};
  96
  97static struct clk_lookup lookups[] = {
  98        /* main clocks */
  99        CLKDEV_CON_ID("shyway_clk", &sh7780_shyway_clk),
 100};
 101
 102int __init arch_clk_init(void)
 103{
 104        struct clk *clk;
 105        int i, ret = 0;
 106
 107        cpg_clk_init();
 108
 109        clk = clk_get(NULL, "master_clk");
 110        for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) {
 111                struct clk *clkp = sh7780_onchip_clocks[i];
 112
 113                clkp->parent = clk;
 114                ret |= clk_register(clkp);
 115        }
 116
 117        clk_put(clk);
 118
 119        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 120
 121        return ret;
 122}
 123