xref: /openbmc/linux/drivers/clk/at91/clk-utmi.c (revision ae213c44)
1 /*
2  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  */
10 
11 #include <linux/clk-provider.h>
12 #include <linux/clkdev.h>
13 #include <linux/clk/at91_pmc.h>
14 #include <linux/of.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/regmap.h>
17 #include <soc/at91/atmel-sfr.h>
18 
19 #include "pmc.h"
20 
21 /*
22  * The purpose of this clock is to generate a 480 MHz signal. A different
23  * rate can't be configured.
24  */
25 #define UTMI_RATE	480000000
26 
27 struct clk_utmi {
28 	struct clk_hw hw;
29 	struct regmap *regmap_pmc;
30 	struct regmap *regmap_sfr;
31 };
32 
33 #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
34 
35 static inline bool clk_utmi_ready(struct regmap *regmap)
36 {
37 	unsigned int status;
38 
39 	regmap_read(regmap, AT91_PMC_SR, &status);
40 
41 	return status & AT91_PMC_LOCKU;
42 }
43 
44 static int clk_utmi_prepare(struct clk_hw *hw)
45 {
46 	struct clk_hw *hw_parent;
47 	struct clk_utmi *utmi = to_clk_utmi(hw);
48 	unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
49 			    AT91_PMC_BIASEN;
50 	unsigned int utmi_ref_clk_freq;
51 	unsigned long parent_rate;
52 
53 	/*
54 	 * If mainck rate is different from 12 MHz, we have to configure the
55 	 * FREQ field of the SFR_UTMICKTRIM register to generate properly
56 	 * the utmi clock.
57 	 */
58 	hw_parent = clk_hw_get_parent(hw);
59 	parent_rate = clk_hw_get_rate(hw_parent);
60 
61 	switch (parent_rate) {
62 	case 12000000:
63 		utmi_ref_clk_freq = 0;
64 		break;
65 	case 16000000:
66 		utmi_ref_clk_freq = 1;
67 		break;
68 	case 24000000:
69 		utmi_ref_clk_freq = 2;
70 		break;
71 	/*
72 	 * Not supported on SAMA5D2 but it's not an issue since MAINCK
73 	 * maximum value is 24 MHz.
74 	 */
75 	case 48000000:
76 		utmi_ref_clk_freq = 3;
77 		break;
78 	default:
79 		pr_err("UTMICK: unsupported mainck rate\n");
80 		return -EINVAL;
81 	}
82 
83 	if (utmi->regmap_sfr) {
84 		regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
85 				   AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
86 	} else if (utmi_ref_clk_freq) {
87 		pr_err("UTMICK: sfr node required\n");
88 		return -EINVAL;
89 	}
90 
91 	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, uckr, uckr);
92 
93 	while (!clk_utmi_ready(utmi->regmap_pmc))
94 		cpu_relax();
95 
96 	return 0;
97 }
98 
99 static int clk_utmi_is_prepared(struct clk_hw *hw)
100 {
101 	struct clk_utmi *utmi = to_clk_utmi(hw);
102 
103 	return clk_utmi_ready(utmi->regmap_pmc);
104 }
105 
106 static void clk_utmi_unprepare(struct clk_hw *hw)
107 {
108 	struct clk_utmi *utmi = to_clk_utmi(hw);
109 
110 	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR,
111 			   AT91_PMC_UPLLEN, 0);
112 }
113 
114 static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
115 					  unsigned long parent_rate)
116 {
117 	/* UTMI clk rate is fixed. */
118 	return UTMI_RATE;
119 }
120 
121 static const struct clk_ops utmi_ops = {
122 	.prepare = clk_utmi_prepare,
123 	.unprepare = clk_utmi_unprepare,
124 	.is_prepared = clk_utmi_is_prepared,
125 	.recalc_rate = clk_utmi_recalc_rate,
126 };
127 
128 struct clk_hw * __init
129 at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
130 		       const char *name, const char *parent_name)
131 {
132 	struct clk_utmi *utmi;
133 	struct clk_hw *hw;
134 	struct clk_init_data init;
135 	int ret;
136 
137 	utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
138 	if (!utmi)
139 		return ERR_PTR(-ENOMEM);
140 
141 	init.name = name;
142 	init.ops = &utmi_ops;
143 	init.parent_names = parent_name ? &parent_name : NULL;
144 	init.num_parents = parent_name ? 1 : 0;
145 	init.flags = CLK_SET_RATE_GATE;
146 
147 	utmi->hw.init = &init;
148 	utmi->regmap_pmc = regmap_pmc;
149 	utmi->regmap_sfr = regmap_sfr;
150 
151 	hw = &utmi->hw;
152 	ret = clk_hw_register(NULL, &utmi->hw);
153 	if (ret) {
154 		kfree(utmi);
155 		hw = ERR_PTR(ret);
156 	}
157 
158 	return hw;
159 }
160