aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuc Verhaegen <libv@skynet.be>2014-11-14 07:26:50 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2014-11-14 08:28:45 -0500
commitfc219bfd5b2e488e3c246990869cfde5ca235c89 (patch)
tree56944f60afbd96f4812cb5040395ede02a14cf56
parentbf2fda157a9ab50f65da60a365ede3a5b529d025 (diff)
simplefb: add clock handling code
This claims and enables clocks listed in the simple framebuffer dt node. This is needed so that the display engine, in case the required clocks are known by the kernel code and are described in the dt, will remain properly enabled. Signed-off-by: Luc Verhaegen <libv@skynet.be> [hdegoede@redhat.com: Change clks from list to dynamic array] Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Geert Uytterhoeven <geert@linux-m68k.org> Reviewed-by: Maxime Ripard <maxime.ripard@free-electrons.com> Reviewed-by: David Herrmann <dh.herrmann@gmail.com> Acked-by: Grant Likely <grant.likely@linaro.org> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-rw-r--r--drivers/video/fbdev/simplefb.c108
1 files changed, 107 insertions, 1 deletions
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index cdcf1fe46eae..d19294635a42 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -26,6 +26,7 @@
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/platform_data/simplefb.h> 27#include <linux/platform_data/simplefb.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/clk-provider.h>
29 30
30static struct fb_fix_screeninfo simplefb_fix = { 31static struct fb_fix_screeninfo simplefb_fix = {
31 .id = "simple", 32 .id = "simple",
@@ -167,8 +168,105 @@ static int simplefb_parse_pd(struct platform_device *pdev,
167 168
168struct simplefb_par { 169struct simplefb_par {
169 u32 palette[PSEUDO_PALETTE_SIZE]; 170 u32 palette[PSEUDO_PALETTE_SIZE];
171#ifdef CONFIG_OF
172 int clk_count;
173 struct clk **clks;
174#endif
170}; 175};
171 176
177#ifdef CONFIG_OF
178/*
179 * Clock handling code.
180 *
181 * Here we handle the clocks property of our "simple-framebuffer" dt node.
182 * This is necessary so that we can make sure that any clocks needed by
183 * the display engine that the bootloader set up for us (and for which it
184 * provided a simplefb dt node), stay up, for the life of the simplefb
185 * driver.
186 *
187 * When the driver unloads, we cleanly disable, and then release the clocks.
188 *
189 * We only complain about errors here, no action is taken as the most likely
190 * error can only happen due to a mismatch between the bootloader which set
191 * up simplefb, and the clock definitions in the device tree. Chances are
192 * that there are no adverse effects, and if there are, a clean teardown of
193 * the fb probe will not help us much either. So just complain and carry on,
194 * and hope that the user actually gets a working fb at the end of things.
195 */
196static int simplefb_clocks_init(struct simplefb_par *par,
197 struct platform_device *pdev)
198{
199 struct device_node *np = pdev->dev.of_node;
200 struct clk *clock;
201 int i, ret;
202
203 if (dev_get_platdata(&pdev->dev) || !np)
204 return 0;
205
206 par->clk_count = of_clk_get_parent_count(np);
207 if (par->clk_count <= 0)
208 return 0;
209
210 par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL);
211 if (!par->clks)
212 return -ENOMEM;
213
214 for (i = 0; i < par->clk_count; i++) {
215 clock = of_clk_get(np, i);
216 if (IS_ERR(clock)) {
217 if (PTR_ERR(clock) == -EPROBE_DEFER) {
218 while (--i >= 0) {
219 if (par->clks[i])
220 clk_put(par->clks[i]);
221 }
222 kfree(par->clks);
223 return -EPROBE_DEFER;
224 }
225 dev_err(&pdev->dev, "%s: clock %d not found: %ld\n",
226 __func__, i, PTR_ERR(clock));
227 continue;
228 }
229 par->clks[i] = clock;
230 }
231
232 for (i = 0; i < par->clk_count; i++) {
233 if (par->clks[i]) {
234 ret = clk_prepare_enable(par->clks[i]);
235 if (ret) {
236 dev_err(&pdev->dev,
237 "%s: failed to enable clock %d: %d\n",
238 __func__, i, ret);
239 clk_put(par->clks[i]);
240 par->clks[i] = NULL;
241 }
242 }
243 }
244
245 return 0;
246}
247
248static void simplefb_clocks_destroy(struct simplefb_par *par)
249{
250 int i;
251
252 if (!par->clks)
253 return;
254
255 for (i = 0; i < par->clk_count; i++) {
256 if (par->clks[i]) {
257 clk_disable_unprepare(par->clks[i]);
258 clk_put(par->clks[i]);
259 }
260 }
261
262 kfree(par->clks);
263}
264#else
265static int simplefb_clocks_init(struct simplefb_par *par,
266 struct platform_device *pdev) { return 0; }
267static void simplefb_clocks_destroy(struct simplefb_par *par) { }
268#endif
269
172static int simplefb_probe(struct platform_device *pdev) 270static int simplefb_probe(struct platform_device *pdev)
173{ 271{
174 int ret; 272 int ret;
@@ -236,6 +334,10 @@ static int simplefb_probe(struct platform_device *pdev)
236 } 334 }
237 info->pseudo_palette = par->palette; 335 info->pseudo_palette = par->palette;
238 336
337 ret = simplefb_clocks_init(par, pdev);
338 if (ret < 0)
339 goto error_unmap;
340
239 dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n", 341 dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
240 info->fix.smem_start, info->fix.smem_len, 342 info->fix.smem_start, info->fix.smem_len,
241 info->screen_base); 343 info->screen_base);
@@ -247,13 +349,15 @@ static int simplefb_probe(struct platform_device *pdev)
247 ret = register_framebuffer(info); 349 ret = register_framebuffer(info);
248 if (ret < 0) { 350 if (ret < 0) {
249 dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); 351 dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
250 goto error_unmap; 352 goto error_clocks;
251 } 353 }
252 354
253 dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node); 355 dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
254 356
255 return 0; 357 return 0;
256 358
359error_clocks:
360 simplefb_clocks_destroy(par);
257error_unmap: 361error_unmap:
258 iounmap(info->screen_base); 362 iounmap(info->screen_base);
259error_fb_release: 363error_fb_release:
@@ -264,8 +368,10 @@ error_fb_release:
264static int simplefb_remove(struct platform_device *pdev) 368static int simplefb_remove(struct platform_device *pdev)
265{ 369{
266 struct fb_info *info = platform_get_drvdata(pdev); 370 struct fb_info *info = platform_get_drvdata(pdev);
371 struct simplefb_par *par = info->par;
267 372
268 unregister_framebuffer(info); 373 unregister_framebuffer(info);
374 simplefb_clocks_destroy(par);
269 framebuffer_release(info); 375 framebuffer_release(info);
270 376
271 return 0; 377 return 0;