linux/drivers/clk/imx/clk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/clk.h>
   3#include <linux/clk-provider.h>
   4#include <linux/err.h>
   5#include <linux/io.h>
   6#include <linux/of.h>
   7#include <linux/slab.h>
   8#include <linux/spinlock.h>
   9#include "clk.h"
  10
  11#define CCM_CCDR                        0x4
  12#define CCDR_MMDC_CH0_MASK              BIT(17)
  13#define CCDR_MMDC_CH1_MASK              BIT(16)
  14
  15DEFINE_SPINLOCK(imx_ccm_lock);
  16
  17void imx_unregister_clocks(struct clk *clks[], unsigned int count)
  18{
  19        unsigned int i;
  20
  21        for (i = 0; i < count; i++)
  22                clk_unregister(clks[i]);
  23}
  24
  25void imx_unregister_hw_clocks(struct clk_hw *hws[], unsigned int count)
  26{
  27        unsigned int i;
  28
  29        for (i = 0; i < count; i++)
  30                clk_hw_unregister(hws[i]);
  31}
  32
  33void __init imx_mmdc_mask_handshake(void __iomem *ccm_base,
  34                                    unsigned int chn)
  35{
  36        unsigned int reg;
  37
  38        reg = readl_relaxed(ccm_base + CCM_CCDR);
  39        reg |= chn == 0 ? CCDR_MMDC_CH0_MASK : CCDR_MMDC_CH1_MASK;
  40        writel_relaxed(reg, ccm_base + CCM_CCDR);
  41}
  42
  43void imx_check_clocks(struct clk *clks[], unsigned int count)
  44{
  45        unsigned i;
  46
  47        for (i = 0; i < count; i++)
  48                if (IS_ERR(clks[i]))
  49                        pr_err("i.MX clk %u: register failed with %ld\n",
  50                               i, PTR_ERR(clks[i]));
  51}
  52
  53void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
  54{
  55        unsigned int i;
  56
  57        for (i = 0; i < count; i++)
  58                if (IS_ERR(clks[i]))
  59                        pr_err("i.MX clk %u: register failed with %ld\n",
  60                               i, PTR_ERR(clks[i]));
  61}
  62
  63static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name)
  64{
  65        struct of_phandle_args phandle;
  66        struct clk *clk = ERR_PTR(-ENODEV);
  67        char *path;
  68
  69        path = kasprintf(GFP_KERNEL, "/clocks/%s", name);
  70        if (!path)
  71                return ERR_PTR(-ENOMEM);
  72
  73        phandle.np = of_find_node_by_path(path);
  74        kfree(path);
  75
  76        if (phandle.np) {
  77                clk = of_clk_get_from_provider(&phandle);
  78                of_node_put(phandle.np);
  79        }
  80        return clk;
  81}
  82
  83struct clk * __init imx_obtain_fixed_clock(
  84                        const char *name, unsigned long rate)
  85{
  86        struct clk *clk;
  87
  88        clk = imx_obtain_fixed_clock_from_dt(name);
  89        if (IS_ERR(clk))
  90                clk = imx_clk_fixed(name, rate);
  91        return clk;
  92}
  93
  94struct clk_hw * __init imx_obtain_fixed_clock_hw(
  95                        const char *name, unsigned long rate)
  96{
  97        struct clk *clk;
  98
  99        clk = imx_obtain_fixed_clock_from_dt(name);
 100        if (IS_ERR(clk))
 101                clk = imx_clk_fixed(name, rate);
 102        return __clk_get_hw(clk);
 103}
 104
 105struct clk_hw * imx_obtain_fixed_clk_hw(struct device_node *np,
 106                                        const char *name)
 107{
 108        struct clk *clk;
 109
 110        clk = of_clk_get_by_name(np, name);
 111        if (IS_ERR(clk))
 112                return ERR_PTR(-ENOENT);
 113
 114        return __clk_get_hw(clk);
 115}
 116
 117/*
 118 * This fixups the register CCM_CSCMR1 write value.
 119 * The write/read/divider values of the aclk_podf field
 120 * of that register have the relationship described by
 121 * the following table:
 122 *
 123 * write value       read value        divider
 124 * 3b'000            3b'110            7
 125 * 3b'001            3b'111            8
 126 * 3b'010            3b'100            5
 127 * 3b'011            3b'101            6
 128 * 3b'100            3b'010            3
 129 * 3b'101            3b'011            4
 130 * 3b'110            3b'000            1
 131 * 3b'111            3b'001            2(default)
 132 *
 133 * That's why we do the xor operation below.
 134 */
 135#define CSCMR1_FIXUP    0x00600000
 136
 137void imx_cscmr1_fixup(u32 *val)
 138{
 139        *val ^= CSCMR1_FIXUP;
 140        return;
 141}
 142
 143static int imx_keep_uart_clocks;
 144static struct clk ** const *imx_uart_clocks;
 145
 146static int __init imx_keep_uart_clocks_param(char *str)
 147{
 148        imx_keep_uart_clocks = 1;
 149
 150        return 0;
 151}
 152__setup_param("earlycon", imx_keep_uart_earlycon,
 153              imx_keep_uart_clocks_param, 0);
 154__setup_param("earlyprintk", imx_keep_uart_earlyprintk,
 155              imx_keep_uart_clocks_param, 0);
 156
 157void imx_register_uart_clocks(struct clk ** const clks[])
 158{
 159        if (imx_keep_uart_clocks) {
 160                int i;
 161
 162                imx_uart_clocks = clks;
 163                for (i = 0; imx_uart_clocks[i]; i++)
 164                        clk_prepare_enable(*imx_uart_clocks[i]);
 165        }
 166}
 167
 168static int __init imx_clk_disable_uart(void)
 169{
 170        if (imx_keep_uart_clocks && imx_uart_clocks) {
 171                int i;
 172
 173                for (i = 0; imx_uart_clocks[i]; i++)
 174                        clk_disable_unprepare(*imx_uart_clocks[i]);
 175        }
 176
 177        return 0;
 178}
 179late_initcall_sync(imx_clk_disable_uart);
 180