linux/drivers/clk/clk-nspire.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *
   4 *  Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
   5 */
   6
   7#include <linux/clk-provider.h>
   8#include <linux/err.h>
   9#include <linux/io.h>
  10#include <linux/of.h>
  11#include <linux/of_address.h>
  12
  13#define MHZ (1000 * 1000)
  14
  15#define BASE_CPU_SHIFT          1
  16#define BASE_CPU_MASK           0x7F
  17
  18#define CPU_AHB_SHIFT           12
  19#define CPU_AHB_MASK            0x07
  20
  21#define FIXED_BASE_SHIFT        8
  22#define FIXED_BASE_MASK         0x01
  23
  24#define CLASSIC_BASE_SHIFT      16
  25#define CLASSIC_BASE_MASK       0x1F
  26
  27#define CX_BASE_SHIFT           15
  28#define CX_BASE_MASK            0x3F
  29
  30#define CX_UNKNOWN_SHIFT        21
  31#define CX_UNKNOWN_MASK         0x03
  32
  33struct nspire_clk_info {
  34        u32 base_clock;
  35        u16 base_cpu_ratio;
  36        u16 base_ahb_ratio;
  37};
  38
  39
  40#define EXTRACT(var, prop) (((var)>>prop##_SHIFT) & prop##_MASK)
  41static void nspire_clkinfo_cx(u32 val, struct nspire_clk_info *clk)
  42{
  43        if (EXTRACT(val, FIXED_BASE))
  44                clk->base_clock = 48 * MHZ;
  45        else
  46                clk->base_clock = 6 * EXTRACT(val, CX_BASE) * MHZ;
  47
  48        clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * EXTRACT(val, CX_UNKNOWN);
  49        clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
  50}
  51
  52static void nspire_clkinfo_classic(u32 val, struct nspire_clk_info *clk)
  53{
  54        if (EXTRACT(val, FIXED_BASE))
  55                clk->base_clock = 27 * MHZ;
  56        else
  57                clk->base_clock = (300 - 6 * EXTRACT(val, CLASSIC_BASE)) * MHZ;
  58
  59        clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * 2;
  60        clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
  61}
  62
  63static void __init nspire_ahbdiv_setup(struct device_node *node,
  64                void (*get_clkinfo)(u32, struct nspire_clk_info *))
  65{
  66        u32 val;
  67        void __iomem *io;
  68        struct clk_hw *hw;
  69        const char *clk_name = node->name;
  70        const char *parent_name;
  71        struct nspire_clk_info info;
  72
  73        io = of_iomap(node, 0);
  74        if (!io)
  75                return;
  76        val = readl(io);
  77        iounmap(io);
  78
  79        get_clkinfo(val, &info);
  80
  81        of_property_read_string(node, "clock-output-names", &clk_name);
  82        parent_name = of_clk_get_parent_name(node, 0);
  83
  84        hw = clk_hw_register_fixed_factor(NULL, clk_name, parent_name, 0,
  85                                          1, info.base_ahb_ratio);
  86        if (!IS_ERR(hw))
  87                of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
  88}
  89
  90static void __init nspire_ahbdiv_setup_cx(struct device_node *node)
  91{
  92        nspire_ahbdiv_setup(node, nspire_clkinfo_cx);
  93}
  94
  95static void __init nspire_ahbdiv_setup_classic(struct device_node *node)
  96{
  97        nspire_ahbdiv_setup(node, nspire_clkinfo_classic);
  98}
  99
 100CLK_OF_DECLARE(nspire_ahbdiv_cx, "lsi,nspire-cx-ahb-divider",
 101                nspire_ahbdiv_setup_cx);
 102CLK_OF_DECLARE(nspire_ahbdiv_classic, "lsi,nspire-classic-ahb-divider",
 103                nspire_ahbdiv_setup_classic);
 104
 105static void __init nspire_clk_setup(struct device_node *node,
 106                void (*get_clkinfo)(u32, struct nspire_clk_info *))
 107{
 108        u32 val;
 109        void __iomem *io;
 110        struct clk_hw *hw;
 111        const char *clk_name = node->name;
 112        struct nspire_clk_info info;
 113
 114        io = of_iomap(node, 0);
 115        if (!io)
 116                return;
 117        val = readl(io);
 118        iounmap(io);
 119
 120        get_clkinfo(val, &info);
 121
 122        of_property_read_string(node, "clock-output-names", &clk_name);
 123
 124        hw = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0,
 125                                        info.base_clock);
 126        if (!IS_ERR(hw))
 127                of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
 128        else
 129                return;
 130
 131        pr_info("TI-NSPIRE Base: %uMHz CPU: %uMHz AHB: %uMHz\n",
 132                info.base_clock / MHZ,
 133                info.base_clock / info.base_cpu_ratio / MHZ,
 134                info.base_clock / info.base_ahb_ratio / MHZ);
 135}
 136
 137static void __init nspire_clk_setup_cx(struct device_node *node)
 138{
 139        nspire_clk_setup(node, nspire_clkinfo_cx);
 140}
 141
 142static void __init nspire_clk_setup_classic(struct device_node *node)
 143{
 144        nspire_clk_setup(node, nspire_clkinfo_classic);
 145}
 146
 147CLK_OF_DECLARE(nspire_clk_cx, "lsi,nspire-cx-clock", nspire_clk_setup_cx);
 148CLK_OF_DECLARE(nspire_clk_classic, "lsi,nspire-classic-clock",
 149                nspire_clk_setup_classic);
 150