root/drivers/clk/samsung/clk-exynos-clkout.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exynos_clkout_suspend
  2. exynos_clkout_resume
  3. exynos_clkout_init
  4. exynos4_clkout_init
  5. exynos5_clkout_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
   4  * Author: Tomasz Figa <t.figa@samsung.com>
   5  *
   6  * Clock driver for Exynos clock output
   7  */
   8 
   9 #include <linux/slab.h>
  10 #include <linux/clk.h>
  11 #include <linux/clk-provider.h>
  12 #include <linux/io.h>
  13 #include <linux/of.h>
  14 #include <linux/of_address.h>
  15 #include <linux/syscore_ops.h>
  16 
  17 #define EXYNOS_CLKOUT_NR_CLKS           1
  18 #define EXYNOS_CLKOUT_PARENTS           32
  19 
  20 #define EXYNOS_PMU_DEBUG_REG            0xa00
  21 #define EXYNOS_CLKOUT_DISABLE_SHIFT     0
  22 #define EXYNOS_CLKOUT_MUX_SHIFT         8
  23 #define EXYNOS4_CLKOUT_MUX_MASK         0xf
  24 #define EXYNOS5_CLKOUT_MUX_MASK         0x1f
  25 
  26 struct exynos_clkout {
  27         struct clk_gate gate;
  28         struct clk_mux mux;
  29         spinlock_t slock;
  30         void __iomem *reg;
  31         u32 pmu_debug_save;
  32         struct clk_hw_onecell_data data;
  33 };
  34 
  35 static struct exynos_clkout *clkout;
  36 
  37 static int exynos_clkout_suspend(void)
  38 {
  39         clkout->pmu_debug_save = readl(clkout->reg + EXYNOS_PMU_DEBUG_REG);
  40 
  41         return 0;
  42 }
  43 
  44 static void exynos_clkout_resume(void)
  45 {
  46         writel(clkout->pmu_debug_save, clkout->reg + EXYNOS_PMU_DEBUG_REG);
  47 }
  48 
  49 static struct syscore_ops exynos_clkout_syscore_ops = {
  50         .suspend = exynos_clkout_suspend,
  51         .resume = exynos_clkout_resume,
  52 };
  53 
  54 static void __init exynos_clkout_init(struct device_node *node, u32 mux_mask)
  55 {
  56         const char *parent_names[EXYNOS_CLKOUT_PARENTS];
  57         struct clk *parents[EXYNOS_CLKOUT_PARENTS];
  58         int parent_count;
  59         int ret;
  60         int i;
  61 
  62         clkout = kzalloc(struct_size(clkout, data.hws, EXYNOS_CLKOUT_NR_CLKS),
  63                          GFP_KERNEL);
  64         if (!clkout)
  65                 return;
  66 
  67         spin_lock_init(&clkout->slock);
  68 
  69         parent_count = 0;
  70         for (i = 0; i < EXYNOS_CLKOUT_PARENTS; ++i) {
  71                 char name[] = "clkoutXX";
  72 
  73                 snprintf(name, sizeof(name), "clkout%d", i);
  74                 parents[i] = of_clk_get_by_name(node, name);
  75                 if (IS_ERR(parents[i])) {
  76                         parent_names[i] = "none";
  77                         continue;
  78                 }
  79 
  80                 parent_names[i] = __clk_get_name(parents[i]);
  81                 parent_count = i + 1;
  82         }
  83 
  84         if (!parent_count)
  85                 goto free_clkout;
  86 
  87         clkout->reg = of_iomap(node, 0);
  88         if (!clkout->reg)
  89                 goto clks_put;
  90 
  91         clkout->gate.reg = clkout->reg + EXYNOS_PMU_DEBUG_REG;
  92         clkout->gate.bit_idx = EXYNOS_CLKOUT_DISABLE_SHIFT;
  93         clkout->gate.flags = CLK_GATE_SET_TO_DISABLE;
  94         clkout->gate.lock = &clkout->slock;
  95 
  96         clkout->mux.reg = clkout->reg + EXYNOS_PMU_DEBUG_REG;
  97         clkout->mux.mask = mux_mask;
  98         clkout->mux.shift = EXYNOS_CLKOUT_MUX_SHIFT;
  99         clkout->mux.lock = &clkout->slock;
 100 
 101         clkout->data.hws[0] = clk_hw_register_composite(NULL, "clkout",
 102                                 parent_names, parent_count, &clkout->mux.hw,
 103                                 &clk_mux_ops, NULL, NULL, &clkout->gate.hw,
 104                                 &clk_gate_ops, CLK_SET_RATE_PARENT
 105                                 | CLK_SET_RATE_NO_REPARENT);
 106         if (IS_ERR(clkout->data.hws[0]))
 107                 goto err_unmap;
 108 
 109         clkout->data.num = EXYNOS_CLKOUT_NR_CLKS;
 110         ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, &clkout->data);
 111         if (ret)
 112                 goto err_clk_unreg;
 113 
 114         register_syscore_ops(&exynos_clkout_syscore_ops);
 115 
 116         return;
 117 
 118 err_clk_unreg:
 119         clk_hw_unregister(clkout->data.hws[0]);
 120 err_unmap:
 121         iounmap(clkout->reg);
 122 clks_put:
 123         for (i = 0; i < EXYNOS_CLKOUT_PARENTS; ++i)
 124                 if (!IS_ERR(parents[i]))
 125                         clk_put(parents[i]);
 126 free_clkout:
 127         kfree(clkout);
 128 
 129         pr_err("%s: failed to register clkout clock\n", __func__);
 130 }
 131 
 132 /*
 133  * We use CLK_OF_DECLARE_DRIVER initialization method to avoid setting
 134  * the OF_POPULATED flag on the pmu device tree node, so later the
 135  * Exynos PMU platform device can be properly probed with PMU driver.
 136  */
 137 
 138 static void __init exynos4_clkout_init(struct device_node *node)
 139 {
 140         exynos_clkout_init(node, EXYNOS4_CLKOUT_MUX_MASK);
 141 }
 142 CLK_OF_DECLARE_DRIVER(exynos4210_clkout, "samsung,exynos4210-pmu",
 143                 exynos4_clkout_init);
 144 CLK_OF_DECLARE_DRIVER(exynos4412_clkout, "samsung,exynos4412-pmu",
 145                 exynos4_clkout_init);
 146 CLK_OF_DECLARE_DRIVER(exynos3250_clkout, "samsung,exynos3250-pmu",
 147                 exynos4_clkout_init);
 148 
 149 static void __init exynos5_clkout_init(struct device_node *node)
 150 {
 151         exynos_clkout_init(node, EXYNOS5_CLKOUT_MUX_MASK);
 152 }
 153 CLK_OF_DECLARE_DRIVER(exynos5250_clkout, "samsung,exynos5250-pmu",
 154                 exynos5_clkout_init);
 155 CLK_OF_DECLARE_DRIVER(exynos5410_clkout, "samsung,exynos5410-pmu",
 156                 exynos5_clkout_init);
 157 CLK_OF_DECLARE_DRIVER(exynos5420_clkout, "samsung,exynos5420-pmu",
 158                 exynos5_clkout_init);
 159 CLK_OF_DECLARE_DRIVER(exynos5433_clkout, "samsung,exynos5433-pmu",
 160                 exynos5_clkout_init);

/* [<][>][^][v][top][bottom][index][help] */