Blame view

drivers/clk/renesas/clk-r8a7778.c 3.41 KB
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
1
2
3
4
5
6
7
8
9
10
11
  /*
   * r8a7778 Core CPG Clocks
   *
   * Copyright (C) 2014  Ulrich Hecht
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; version 2 of the License.
   */
  
  #include <linux/clk-provider.h>
09c32427c   Simon Horman   clk: renesas: Ren...
12
  #include <linux/clk/renesas.h>
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
13
  #include <linux/of_address.h>
5a1cfafae   Geert Uytterhoeven   clk: shmobile: Re...
14
  #include <linux/slab.h>
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
15
16
17
18
19
20
21
22
  
  struct r8a7778_cpg {
  	struct clk_onecell_data data;
  	spinlock_t lock;
  	void __iomem *reg;
  };
  
  /* PLL multipliers per bits 11, 12, and 18 of MODEMR */
7371a20b9   Geert Uytterhoeven   clk: shmobile: r8...
23
  static const struct {
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
24
25
  	unsigned long plla_mult;
  	unsigned long pllb_mult;
7371a20b9   Geert Uytterhoeven   clk: shmobile: r8...
26
  } r8a7778_rates[] __initconst = {
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
27
28
29
30
31
32
33
34
35
36
  	[0] = { 21, 21 },
  	[1] = { 24, 24 },
  	[2] = { 28, 28 },
  	[3] = { 32, 32 },
  	[5] = { 24, 21 },
  	[6] = { 28, 21 },
  	[7] = { 32, 24 },
  };
  
  /* Clock dividers per bits 1 and 2 of MODEMR */
7371a20b9   Geert Uytterhoeven   clk: shmobile: r8...
37
  static const struct {
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
38
39
  	const char *name;
  	unsigned int div[4];
7371a20b9   Geert Uytterhoeven   clk: shmobile: r8...
40
  } r8a7778_divs[6] __initconst = {
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  	{ "b",   { 12, 12, 16, 18 } },
  	{ "out", { 12, 12, 16, 18 } },
  	{ "p",   { 16, 12, 16, 12 } },
  	{ "s",   { 4,  3,  4,  3  } },
  	{ "s1",  { 8,  6,  8,  6  } },
  };
  
  static u32 cpg_mode_rates __initdata;
  static u32 cpg_mode_divs __initdata;
  
  static struct clk * __init
  r8a7778_cpg_register_clock(struct device_node *np, struct r8a7778_cpg *cpg,
  			     const char *name)
  {
  	if (!strcmp(name, "plla")) {
  		return clk_register_fixed_factor(NULL, "plla",
  			of_clk_get_parent_name(np, 0), 0,
  			r8a7778_rates[cpg_mode_rates].plla_mult, 1);
  	} else if (!strcmp(name, "pllb")) {
  		return clk_register_fixed_factor(NULL, "pllb",
  			of_clk_get_parent_name(np, 0), 0,
  			r8a7778_rates[cpg_mode_rates].pllb_mult, 1);
  	} else {
  		unsigned int i;
  
  		for (i = 0; i < ARRAY_SIZE(r8a7778_divs); i++) {
  			if (!strcmp(name, r8a7778_divs[i].name)) {
  				return clk_register_fixed_factor(NULL,
  					r8a7778_divs[i].name,
  					"plla", 0, 1,
  					r8a7778_divs[i].div[cpg_mode_divs]);
  			}
  		}
  	}
  
  	return ERR_PTR(-EINVAL);
  }
  
  
  static void __init r8a7778_cpg_clocks_init(struct device_node *np)
  {
  	struct r8a7778_cpg *cpg;
  	struct clk **clks;
  	unsigned int i;
  	int num_clks;
  
  	num_clks = of_property_count_strings(np, "clock-output-names");
  	if (num_clks < 0) {
  		pr_err("%s: failed to count clocks
  ", __func__);
  		return;
  	}
  
  	cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
  	clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
  	if (cpg == NULL || clks == NULL) {
  		/* We're leaking memory on purpose, there's no point in cleaning
  		 * up as the system won't boot anyway.
  		 */
  		return;
  	}
  
  	spin_lock_init(&cpg->lock);
  
  	cpg->data.clks = clks;
  	cpg->data.clk_num = num_clks;
  
  	cpg->reg = of_iomap(np, 0);
  	if (WARN_ON(cpg->reg == NULL))
  		return;
  
  	for (i = 0; i < num_clks; ++i) {
  		const char *name;
  		struct clk *clk;
  
  		of_property_read_string_index(np, "clock-output-names", i,
  					      &name);
  
  		clk = r8a7778_cpg_register_clock(np, cpg, name);
  		if (IS_ERR(clk))
  			pr_err("%s: failed to register %s %s clock (%ld)
  ",
  			       __func__, np->name, name, PTR_ERR(clk));
  		else
  			cpg->data.clks[i] = clk;
  	}
  
  	of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
8bc964aa2   Geert Uytterhoeven   clk: shmobile: r8...
129
130
  
  	cpg_mstp_add_clk_domain(np);
6232c51cb   Ulrich Hecht   ARM: shmobile: r8...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  }
  
  CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks",
  	       r8a7778_cpg_clocks_init);
  
  void __init r8a7778_clocks_init(u32 mode)
  {
  	BUG_ON(!(mode & BIT(19)));
  
  	cpg_mode_rates = (!!(mode & BIT(18)) << 2) |
  			 (!!(mode & BIT(12)) << 1) |
  			 (!!(mode & BIT(11)));
  	cpg_mode_divs = (!!(mode & BIT(2)) << 1) |
  			(!!(mode & BIT(1)));
  
  	of_clk_init(NULL);
  }