diff options
-rw-r--r-- | drivers/clk/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clk/clk-max77686.c | 176 |
2 files changed, 9 insertions, 168 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 726d72aad49f..d68b14b3c0e6 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -38,6 +38,7 @@ config COMMON_CLK_MAX_GEN | |||
38 | config COMMON_CLK_MAX77686 | 38 | config COMMON_CLK_MAX77686 |
39 | tristate "Clock driver for Maxim 77686 MFD" | 39 | tristate "Clock driver for Maxim 77686 MFD" |
40 | depends on MFD_MAX77686 | 40 | depends on MFD_MAX77686 |
41 | select COMMON_CLK_MAX_GEN | ||
41 | ---help--- | 42 | ---help--- |
42 | This driver supports Maxim 77686 crystal oscillator clock. | 43 | This driver supports Maxim 77686 crystal oscillator clock. |
43 | 44 | ||
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index 185b611c957e..ed0beb4cb39b 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c | |||
@@ -31,187 +31,37 @@ | |||
31 | #include <linux/clkdev.h> | 31 | #include <linux/clkdev.h> |
32 | 32 | ||
33 | #include <dt-bindings/clock/maxim,max77686.h> | 33 | #include <dt-bindings/clock/maxim,max77686.h> |
34 | 34 | #include "clk-max-gen.h" | |
35 | struct max77686_clk { | ||
36 | struct max77686_dev *iodev; | ||
37 | u32 mask; | ||
38 | struct clk_hw hw; | ||
39 | struct clk_lookup *lookup; | ||
40 | }; | ||
41 | |||
42 | static struct max77686_clk *to_max77686_clk(struct clk_hw *hw) | ||
43 | { | ||
44 | return container_of(hw, struct max77686_clk, hw); | ||
45 | } | ||
46 | |||
47 | static int max77686_clk_prepare(struct clk_hw *hw) | ||
48 | { | ||
49 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
50 | |||
51 | return regmap_update_bits(max77686->iodev->regmap, | ||
52 | MAX77686_REG_32KHZ, max77686->mask, | ||
53 | max77686->mask); | ||
54 | } | ||
55 | |||
56 | static void max77686_clk_unprepare(struct clk_hw *hw) | ||
57 | { | ||
58 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
59 | |||
60 | regmap_update_bits(max77686->iodev->regmap, | ||
61 | MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask); | ||
62 | } | ||
63 | |||
64 | static int max77686_clk_is_prepared(struct clk_hw *hw) | ||
65 | { | ||
66 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
67 | int ret; | ||
68 | u32 val; | ||
69 | |||
70 | ret = regmap_read(max77686->iodev->regmap, | ||
71 | MAX77686_REG_32KHZ, &val); | ||
72 | |||
73 | if (ret < 0) | ||
74 | return -EINVAL; | ||
75 | |||
76 | return val & max77686->mask; | ||
77 | } | ||
78 | |||
79 | static unsigned long max77686_recalc_rate(struct clk_hw *hw, | ||
80 | unsigned long parent_rate) | ||
81 | { | ||
82 | return 32768; | ||
83 | } | ||
84 | |||
85 | static struct clk_ops max77686_clk_ops = { | ||
86 | .prepare = max77686_clk_prepare, | ||
87 | .unprepare = max77686_clk_unprepare, | ||
88 | .is_prepared = max77686_clk_is_prepared, | ||
89 | .recalc_rate = max77686_recalc_rate, | ||
90 | }; | ||
91 | 35 | ||
92 | static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { | 36 | static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = { |
93 | [MAX77686_CLK_AP] = { | 37 | [MAX77686_CLK_AP] = { |
94 | .name = "32khz_ap", | 38 | .name = "32khz_ap", |
95 | .ops = &max77686_clk_ops, | 39 | .ops = &max_gen_clk_ops, |
96 | .flags = CLK_IS_ROOT, | 40 | .flags = CLK_IS_ROOT, |
97 | }, | 41 | }, |
98 | [MAX77686_CLK_CP] = { | 42 | [MAX77686_CLK_CP] = { |
99 | .name = "32khz_cp", | 43 | .name = "32khz_cp", |
100 | .ops = &max77686_clk_ops, | 44 | .ops = &max_gen_clk_ops, |
101 | .flags = CLK_IS_ROOT, | 45 | .flags = CLK_IS_ROOT, |
102 | }, | 46 | }, |
103 | [MAX77686_CLK_PMIC] = { | 47 | [MAX77686_CLK_PMIC] = { |
104 | .name = "32khz_pmic", | 48 | .name = "32khz_pmic", |
105 | .ops = &max77686_clk_ops, | 49 | .ops = &max_gen_clk_ops, |
106 | .flags = CLK_IS_ROOT, | 50 | .flags = CLK_IS_ROOT, |
107 | }, | 51 | }, |
108 | }; | 52 | }; |
109 | 53 | ||
110 | static struct clk *max77686_clk_register(struct device *dev, | ||
111 | struct max77686_clk *max77686) | ||
112 | { | ||
113 | struct clk *clk; | ||
114 | struct clk_hw *hw = &max77686->hw; | ||
115 | |||
116 | clk = clk_register(dev, hw); | ||
117 | if (IS_ERR(clk)) | ||
118 | return clk; | ||
119 | |||
120 | max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL); | ||
121 | if (!max77686->lookup) | ||
122 | return ERR_PTR(-ENOMEM); | ||
123 | |||
124 | max77686->lookup->con_id = hw->init->name; | ||
125 | max77686->lookup->clk = clk; | ||
126 | |||
127 | clkdev_add(max77686->lookup); | ||
128 | |||
129 | return clk; | ||
130 | } | ||
131 | |||
132 | static int max77686_clk_probe(struct platform_device *pdev) | 54 | static int max77686_clk_probe(struct platform_device *pdev) |
133 | { | 55 | { |
134 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 56 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); |
135 | struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM]; | ||
136 | struct clk **clocks; | ||
137 | int i, ret; | ||
138 | |||
139 | clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *) | ||
140 | * MAX77686_CLKS_NUM, GFP_KERNEL); | ||
141 | if (!clocks) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
145 | max77686_clks[i] = devm_kzalloc(&pdev->dev, | ||
146 | sizeof(struct max77686_clk), GFP_KERNEL); | ||
147 | if (!max77686_clks[i]) | ||
148 | return -ENOMEM; | ||
149 | } | ||
150 | |||
151 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
152 | max77686_clks[i]->iodev = iodev; | ||
153 | max77686_clks[i]->mask = 1 << i; | ||
154 | max77686_clks[i]->hw.init = &max77686_clks_init[i]; | ||
155 | |||
156 | clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]); | ||
157 | if (IS_ERR(clocks[i])) { | ||
158 | ret = PTR_ERR(clocks[i]); | ||
159 | dev_err(&pdev->dev, "failed to register %s\n", | ||
160 | max77686_clks[i]->hw.init->name); | ||
161 | goto err_clocks; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | platform_set_drvdata(pdev, clocks); | ||
166 | |||
167 | if (iodev->dev->of_node) { | ||
168 | struct clk_onecell_data *of_data; | ||
169 | |||
170 | of_data = devm_kzalloc(&pdev->dev, | ||
171 | sizeof(*of_data), GFP_KERNEL); | ||
172 | if (!of_data) { | ||
173 | ret = -ENOMEM; | ||
174 | goto err_clocks; | ||
175 | } | ||
176 | 57 | ||
177 | of_data->clks = clocks; | 58 | return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ, |
178 | of_data->clk_num = MAX77686_CLKS_NUM; | 59 | max77686_clks_init, MAX77686_CLKS_NUM); |
179 | ret = of_clk_add_provider(iodev->dev->of_node, | ||
180 | of_clk_src_onecell_get, of_data); | ||
181 | if (ret) { | ||
182 | dev_err(&pdev->dev, "failed to register OF clock provider\n"); | ||
183 | goto err_clocks; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | |||
189 | err_clocks: | ||
190 | for (--i; i >= 0; --i) { | ||
191 | clkdev_drop(max77686_clks[i]->lookup); | ||
192 | clk_unregister(max77686_clks[i]->hw.clk); | ||
193 | } | ||
194 | |||
195 | return ret; | ||
196 | } | 60 | } |
197 | 61 | ||
198 | static int max77686_clk_remove(struct platform_device *pdev) | 62 | static int max77686_clk_remove(struct platform_device *pdev) |
199 | { | 63 | { |
200 | struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 64 | return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM); |
201 | struct clk **clocks = platform_get_drvdata(pdev); | ||
202 | int i; | ||
203 | |||
204 | if (iodev->dev->of_node) | ||
205 | of_clk_del_provider(iodev->dev->of_node); | ||
206 | |||
207 | for (i = 0; i < MAX77686_CLKS_NUM; i++) { | ||
208 | struct clk_hw *hw = __clk_get_hw(clocks[i]); | ||
209 | struct max77686_clk *max77686 = to_max77686_clk(hw); | ||
210 | |||
211 | clkdev_drop(max77686->lookup); | ||
212 | clk_unregister(clocks[i]); | ||
213 | } | ||
214 | return 0; | ||
215 | } | 65 | } |
216 | 66 | ||
217 | static const struct platform_device_id max77686_clk_id[] = { | 67 | static const struct platform_device_id max77686_clk_id[] = { |
@@ -230,17 +80,7 @@ static struct platform_driver max77686_clk_driver = { | |||
230 | .id_table = max77686_clk_id, | 80 | .id_table = max77686_clk_id, |
231 | }; | 81 | }; |
232 | 82 | ||
233 | static int __init max77686_clk_init(void) | 83 | module_platform_driver(max77686_clk_driver); |
234 | { | ||
235 | return platform_driver_register(&max77686_clk_driver); | ||
236 | } | ||
237 | subsys_initcall(max77686_clk_init); | ||
238 | |||
239 | static void __init max77686_clk_cleanup(void) | ||
240 | { | ||
241 | platform_driver_unregister(&max77686_clk_driver); | ||
242 | } | ||
243 | module_exit(max77686_clk_cleanup); | ||
244 | 84 | ||
245 | MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); | 85 | MODULE_DESCRIPTION("MAXIM 77686 Clock Driver"); |
246 | MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); | 86 | MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>"); |