diff options
Diffstat (limited to 'drivers/video/wm8505fb.c')
-rw-r--r-- | drivers/video/wm8505fb.c | 145 |
1 files changed, 45 insertions, 100 deletions
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index 4dd0580f96fd..01f9ace068e2 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c | |||
@@ -14,25 +14,25 @@ | |||
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/dma-mapping.h> | ||
24 | #include <linux/fb.h> | 19 | #include <linux/fb.h> |
20 | #include <linux/errno.h> | ||
21 | #include <linux/err.h> | ||
25 | #include <linux/init.h> | 22 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
27 | #include <linux/io.h> | 24 | #include <linux/io.h> |
28 | #include <linux/dma-mapping.h> | 25 | #include <linux/kernel.h> |
29 | #include <linux/platform_device.h> | 26 | #include <linux/memblock.h> |
30 | #include <linux/wait.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/module.h> | ||
31 | #include <linux/of.h> | 29 | #include <linux/of.h> |
32 | #include <linux/of_fdt.h> | 30 | #include <linux/of_fdt.h> |
33 | #include <linux/memblock.h> | 31 | #include <linux/platform_device.h> |
34 | 32 | #include <linux/slab.h> | |
35 | #include <linux/platform_data/video-vt8500lcdfb.h> | 33 | #include <linux/string.h> |
34 | #include <linux/wait.h> | ||
35 | #include <video/of_display_timing.h> | ||
36 | 36 | ||
37 | #include "wm8505fb_regs.h" | 37 | #include "wm8505fb_regs.h" |
38 | #include "wmt_ge_rops.h" | 38 | #include "wmt_ge_rops.h" |
@@ -263,26 +263,22 @@ static struct fb_ops wm8505fb_ops = { | |||
263 | static int wm8505fb_probe(struct platform_device *pdev) | 263 | static int wm8505fb_probe(struct platform_device *pdev) |
264 | { | 264 | { |
265 | struct wm8505fb_info *fbi; | 265 | struct wm8505fb_info *fbi; |
266 | struct resource *res; | 266 | struct resource *res; |
267 | struct display_timings *disp_timing; | ||
267 | void *addr; | 268 | void *addr; |
268 | int ret; | 269 | int ret; |
269 | 270 | ||
270 | struct fb_videomode of_mode; | 271 | struct fb_videomode mode; |
271 | struct device_node *np; | ||
272 | u32 bpp; | 272 | u32 bpp; |
273 | dma_addr_t fb_mem_phys; | 273 | dma_addr_t fb_mem_phys; |
274 | unsigned long fb_mem_len; | 274 | unsigned long fb_mem_len; |
275 | void *fb_mem_virt; | 275 | void *fb_mem_virt; |
276 | 276 | ||
277 | ret = -ENOMEM; | ||
278 | fbi = NULL; | ||
279 | |||
280 | fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) + | 277 | fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) + |
281 | sizeof(u32) * 16, GFP_KERNEL); | 278 | sizeof(u32) * 16, GFP_KERNEL); |
282 | if (!fbi) { | 279 | if (!fbi) { |
283 | dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); | 280 | dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); |
284 | ret = -ENOMEM; | 281 | return -ENOMEM; |
285 | goto failed; | ||
286 | } | 282 | } |
287 | 283 | ||
288 | strcpy(fbi->fb.fix.id, DRIVER_NAME); | 284 | strcpy(fbi->fb.fix.id, DRIVER_NAME); |
@@ -308,54 +304,23 @@ static int wm8505fb_probe(struct platform_device *pdev) | |||
308 | fbi->fb.pseudo_palette = addr; | 304 | fbi->fb.pseudo_palette = addr; |
309 | 305 | ||
310 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 306 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
311 | if (res == NULL) { | 307 | fbi->regbase = devm_ioremap_resource(&pdev->dev, res); |
312 | dev_err(&pdev->dev, "no I/O memory resource defined\n"); | 308 | if (IS_ERR(fbi->regbase)) |
313 | ret = -ENODEV; | 309 | return PTR_ERR(fbi->regbase); |
314 | goto failed_fbi; | ||
315 | } | ||
316 | 310 | ||
317 | res = request_mem_region(res->start, resource_size(res), DRIVER_NAME); | 311 | disp_timing = of_get_display_timings(pdev->dev.of_node); |
318 | if (res == NULL) { | 312 | if (!disp_timing) |
319 | dev_err(&pdev->dev, "failed to request I/O memory\n"); | 313 | return -EINVAL; |
320 | ret = -EBUSY; | ||
321 | goto failed_fbi; | ||
322 | } | ||
323 | |||
324 | fbi->regbase = ioremap(res->start, resource_size(res)); | ||
325 | if (fbi->regbase == NULL) { | ||
326 | dev_err(&pdev->dev, "failed to map I/O memory\n"); | ||
327 | ret = -EBUSY; | ||
328 | goto failed_free_res; | ||
329 | } | ||
330 | 314 | ||
331 | np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0); | 315 | ret = of_get_fb_videomode(pdev->dev.of_node, &mode, OF_USE_NATIVE_MODE); |
332 | if (!np) { | 316 | if (ret) |
333 | pr_err("%s: No display description in Device Tree\n", __func__); | 317 | return ret; |
334 | ret = -EINVAL; | ||
335 | goto failed_free_res; | ||
336 | } | ||
337 | 318 | ||
338 | /* | 319 | ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp); |
339 | * This code is copied from Sascha Hauer's of_videomode helper | 320 | if (ret) |
340 | * and can be replaced with a call to the helper once mainlined | 321 | return ret; |
341 | */ | ||
342 | ret = 0; | ||
343 | ret |= of_property_read_u32(np, "hactive", &of_mode.xres); | ||
344 | ret |= of_property_read_u32(np, "vactive", &of_mode.yres); | ||
345 | ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin); | ||
346 | ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin); | ||
347 | ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len); | ||
348 | ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin); | ||
349 | ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin); | ||
350 | ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len); | ||
351 | ret |= of_property_read_u32(np, "bpp", &bpp); | ||
352 | if (ret) { | ||
353 | pr_err("%s: Unable to read display properties\n", __func__); | ||
354 | goto failed_free_res; | ||
355 | } | ||
356 | 322 | ||
357 | of_mode.vmode = FB_VMODE_NONINTERLACED; | 323 | fb_videomode_to_var(&fbi->fb.var, &mode); |
358 | fb_videomode_to_var(&fbi->fb.var, &of_mode); | ||
359 | 324 | ||
360 | fbi->fb.var.nonstd = 0; | 325 | fbi->fb.var.nonstd = 0; |
361 | fbi->fb.var.activate = FB_ACTIVATE_NOW; | 326 | fbi->fb.var.activate = FB_ACTIVATE_NOW; |
@@ -364,16 +329,16 @@ static int wm8505fb_probe(struct platform_device *pdev) | |||
364 | fbi->fb.var.width = -1; | 329 | fbi->fb.var.width = -1; |
365 | 330 | ||
366 | /* try allocating the framebuffer */ | 331 | /* try allocating the framebuffer */ |
367 | fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8); | 332 | fb_mem_len = mode.xres * mode.yres * 2 * (bpp / 8); |
368 | fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, | 333 | fb_mem_virt = dmam_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys, |
369 | GFP_KERNEL); | 334 | GFP_KERNEL); |
370 | if (!fb_mem_virt) { | 335 | if (!fb_mem_virt) { |
371 | pr_err("%s: Failed to allocate framebuffer\n", __func__); | 336 | pr_err("%s: Failed to allocate framebuffer\n", __func__); |
372 | return -ENOMEM; | 337 | return -ENOMEM; |
373 | }; | 338 | } |
374 | 339 | ||
375 | fbi->fb.var.xres_virtual = of_mode.xres; | 340 | fbi->fb.var.xres_virtual = mode.xres; |
376 | fbi->fb.var.yres_virtual = of_mode.yres * 2; | 341 | fbi->fb.var.yres_virtual = mode.yres * 2; |
377 | fbi->fb.var.bits_per_pixel = bpp; | 342 | fbi->fb.var.bits_per_pixel = bpp; |
378 | 343 | ||
379 | fbi->fb.fix.smem_start = fb_mem_phys; | 344 | fbi->fb.fix.smem_start = fb_mem_phys; |
@@ -381,28 +346,29 @@ static int wm8505fb_probe(struct platform_device *pdev) | |||
381 | fbi->fb.screen_base = fb_mem_virt; | 346 | fbi->fb.screen_base = fb_mem_virt; |
382 | fbi->fb.screen_size = fb_mem_len; | 347 | fbi->fb.screen_size = fb_mem_len; |
383 | 348 | ||
349 | fbi->contrast = 0x10; | ||
350 | ret = wm8505fb_set_par(&fbi->fb); | ||
351 | if (ret) { | ||
352 | dev_err(&pdev->dev, "Failed to set parameters\n"); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
384 | if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { | 356 | if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { |
385 | dev_err(&pdev->dev, "Failed to allocate color map\n"); | 357 | dev_err(&pdev->dev, "Failed to allocate color map\n"); |
386 | ret = -ENOMEM; | 358 | return -ENOMEM; |
387 | goto failed_free_io; | ||
388 | } | 359 | } |
389 | 360 | ||
390 | wm8505fb_init_hw(&fbi->fb); | 361 | wm8505fb_init_hw(&fbi->fb); |
391 | 362 | ||
392 | fbi->contrast = 0x80; | ||
393 | ret = wm8505fb_set_par(&fbi->fb); | ||
394 | if (ret) { | ||
395 | dev_err(&pdev->dev, "Failed to set parameters\n"); | ||
396 | goto failed_free_cmap; | ||
397 | } | ||
398 | |||
399 | platform_set_drvdata(pdev, fbi); | 363 | platform_set_drvdata(pdev, fbi); |
400 | 364 | ||
401 | ret = register_framebuffer(&fbi->fb); | 365 | ret = register_framebuffer(&fbi->fb); |
402 | if (ret < 0) { | 366 | if (ret < 0) { |
403 | dev_err(&pdev->dev, | 367 | dev_err(&pdev->dev, |
404 | "Failed to register framebuffer device: %d\n", ret); | 368 | "Failed to register framebuffer device: %d\n", ret); |
405 | goto failed_free_cmap; | 369 | if (fbi->fb.cmap.len) |
370 | fb_dealloc_cmap(&fbi->fb.cmap); | ||
371 | return ret; | ||
406 | } | 372 | } |
407 | 373 | ||
408 | ret = device_create_file(&pdev->dev, &dev_attr_contrast); | 374 | ret = device_create_file(&pdev->dev, &dev_attr_contrast); |
@@ -416,25 +382,11 @@ static int wm8505fb_probe(struct platform_device *pdev) | |||
416 | fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1); | 382 | fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1); |
417 | 383 | ||
418 | return 0; | 384 | return 0; |
419 | |||
420 | failed_free_cmap: | ||
421 | if (fbi->fb.cmap.len) | ||
422 | fb_dealloc_cmap(&fbi->fb.cmap); | ||
423 | failed_free_io: | ||
424 | iounmap(fbi->regbase); | ||
425 | failed_free_res: | ||
426 | release_mem_region(res->start, resource_size(res)); | ||
427 | failed_fbi: | ||
428 | platform_set_drvdata(pdev, NULL); | ||
429 | kfree(fbi); | ||
430 | failed: | ||
431 | return ret; | ||
432 | } | 385 | } |
433 | 386 | ||
434 | static int wm8505fb_remove(struct platform_device *pdev) | 387 | static int wm8505fb_remove(struct platform_device *pdev) |
435 | { | 388 | { |
436 | struct wm8505fb_info *fbi = platform_get_drvdata(pdev); | 389 | struct wm8505fb_info *fbi = platform_get_drvdata(pdev); |
437 | struct resource *res; | ||
438 | 390 | ||
439 | device_remove_file(&pdev->dev, &dev_attr_contrast); | 391 | device_remove_file(&pdev->dev, &dev_attr_contrast); |
440 | 392 | ||
@@ -445,13 +397,6 @@ static int wm8505fb_remove(struct platform_device *pdev) | |||
445 | if (fbi->fb.cmap.len) | 397 | if (fbi->fb.cmap.len) |
446 | fb_dealloc_cmap(&fbi->fb.cmap); | 398 | fb_dealloc_cmap(&fbi->fb.cmap); |
447 | 399 | ||
448 | iounmap(fbi->regbase); | ||
449 | |||
450 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
451 | release_mem_region(res->start, resource_size(res)); | ||
452 | |||
453 | kfree(fbi); | ||
454 | |||
455 | return 0; | 400 | return 0; |
456 | } | 401 | } |
457 | 402 | ||