diff options
Diffstat (limited to 'drivers/video/xilinxfb.c')
-rw-r--r-- | drivers/video/xilinxfb.c | 353 |
1 files changed, 252 insertions, 101 deletions
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 6ef9733a18d4..6ef99b2d13ca 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c | |||
@@ -6,9 +6,12 @@ | |||
6 | * Author: MontaVista Software, Inc. | 6 | * Author: MontaVista Software, Inc. |
7 | * source@mvista.com | 7 | * source@mvista.com |
8 | * | 8 | * |
9 | * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the | 9 | * 2002-2007 (c) MontaVista Software, Inc. |
10 | * terms of the GNU General Public License version 2. This program is licensed | 10 | * 2007 (c) Secret Lab Technologies, Ltd. |
11 | * "as is" without any warranty of any kind, whether express or implied. | 11 | * |
12 | * This file is licensed under the terms of the GNU General Public License | ||
13 | * version 2. This program is licensed "as is" without any warranty of any | ||
14 | * kind, whether express or implied. | ||
12 | */ | 15 | */ |
13 | 16 | ||
14 | /* | 17 | /* |
@@ -18,6 +21,7 @@ | |||
18 | * Geert Uytterhoeven. | 21 | * Geert Uytterhoeven. |
19 | */ | 22 | */ |
20 | 23 | ||
24 | #include <linux/device.h> | ||
21 | #include <linux/module.h> | 25 | #include <linux/module.h> |
22 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
23 | #include <linux/version.h> | 27 | #include <linux/version.h> |
@@ -28,9 +32,12 @@ | |||
28 | #include <linux/init.h> | 32 | #include <linux/init.h> |
29 | #include <linux/dma-mapping.h> | 33 | #include <linux/dma-mapping.h> |
30 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
31 | 35 | #if defined(CONFIG_OF) | |
36 | #include <linux/of_device.h> | ||
37 | #include <linux/of_platform.h> | ||
38 | #endif | ||
32 | #include <asm/io.h> | 39 | #include <asm/io.h> |
33 | #include <syslib/virtex_devices.h> | 40 | #include <linux/xilinxfb.h> |
34 | 41 | ||
35 | #define DRIVER_NAME "xilinxfb" | 42 | #define DRIVER_NAME "xilinxfb" |
36 | #define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" | 43 | #define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver" |
@@ -63,12 +70,6 @@ | |||
63 | */ | 70 | */ |
64 | #define BYTES_PER_PIXEL 4 | 71 | #define BYTES_PER_PIXEL 4 |
65 | #define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8) | 72 | #define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8) |
66 | #define XRES 640 | ||
67 | #define YRES 480 | ||
68 | #define XRES_VIRTUAL 1024 | ||
69 | #define YRES_VIRTUAL YRES | ||
70 | #define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL) | ||
71 | #define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH) | ||
72 | 73 | ||
73 | #define RED_SHIFT 16 | 74 | #define RED_SHIFT 16 |
74 | #define GREEN_SHIFT 8 | 75 | #define GREEN_SHIFT 8 |
@@ -77,23 +78,26 @@ | |||
77 | #define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ | 78 | #define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */ |
78 | 79 | ||
79 | /* | 80 | /* |
81 | * Default xilinxfb configuration | ||
82 | */ | ||
83 | static struct xilinxfb_platform_data xilinx_fb_default_pdata = { | ||
84 | .xres = 640, | ||
85 | .yres = 480, | ||
86 | .xvirt = 1024, | ||
87 | .yvirt = 480; | ||
88 | }; | ||
89 | |||
90 | /* | ||
80 | * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures | 91 | * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures |
81 | */ | 92 | */ |
82 | static struct fb_fix_screeninfo xilinx_fb_fix = { | 93 | static struct fb_fix_screeninfo xilinx_fb_fix = { |
83 | .id = "Xilinx", | 94 | .id = "Xilinx", |
84 | .type = FB_TYPE_PACKED_PIXELS, | 95 | .type = FB_TYPE_PACKED_PIXELS, |
85 | .visual = FB_VISUAL_TRUECOLOR, | 96 | .visual = FB_VISUAL_TRUECOLOR, |
86 | .smem_len = FB_SIZE, | ||
87 | .line_length = LINE_LENGTH, | ||
88 | .accel = FB_ACCEL_NONE | 97 | .accel = FB_ACCEL_NONE |
89 | }; | 98 | }; |
90 | 99 | ||
91 | static struct fb_var_screeninfo xilinx_fb_var = { | 100 | static struct fb_var_screeninfo xilinx_fb_var = { |
92 | .xres = XRES, | ||
93 | .yres = YRES, | ||
94 | .xres_virtual = XRES_VIRTUAL, | ||
95 | .yres_virtual = YRES_VIRTUAL, | ||
96 | |||
97 | .bits_per_pixel = BITS_PER_PIXEL, | 101 | .bits_per_pixel = BITS_PER_PIXEL, |
98 | 102 | ||
99 | .red = { RED_SHIFT, 8, 0 }, | 103 | .red = { RED_SHIFT, 8, 0 }, |
@@ -111,8 +115,9 @@ struct xilinxfb_drvdata { | |||
111 | u32 regs_phys; /* phys. address of the control registers */ | 115 | u32 regs_phys; /* phys. address of the control registers */ |
112 | u32 __iomem *regs; /* virt. address of the control registers */ | 116 | u32 __iomem *regs; /* virt. address of the control registers */ |
113 | 117 | ||
114 | unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */ | 118 | void *fb_virt; /* virt. address of the frame buffer */ |
115 | dma_addr_t fb_phys; /* phys. address of the frame buffer */ | 119 | dma_addr_t fb_phys; /* phys. address of the frame buffer */ |
120 | int fb_alloced; /* Flag, was the fb memory alloced? */ | ||
116 | 121 | ||
117 | u32 reg_ctrl_default; | 122 | u32 reg_ctrl_default; |
118 | 123 | ||
@@ -195,130 +200,136 @@ static struct fb_ops xilinxfb_ops = | |||
195 | .fb_imageblit = cfb_imageblit, | 200 | .fb_imageblit = cfb_imageblit, |
196 | }; | 201 | }; |
197 | 202 | ||
198 | /* === The device driver === */ | 203 | /* --------------------------------------------------------------------- |
204 | * Bus independent setup/teardown | ||
205 | */ | ||
199 | 206 | ||
200 | static int | 207 | static int xilinxfb_assign(struct device *dev, unsigned long physaddr, |
201 | xilinxfb_drv_probe(struct device *dev) | 208 | struct xilinxfb_platform_data *pdata) |
202 | { | 209 | { |
203 | struct platform_device *pdev; | ||
204 | struct xilinxfb_platform_data *pdata; | ||
205 | struct xilinxfb_drvdata *drvdata; | 210 | struct xilinxfb_drvdata *drvdata; |
206 | struct resource *regs_res; | 211 | int rc; |
207 | int retval; | 212 | int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL; |
208 | |||
209 | if (!dev) | ||
210 | return -EINVAL; | ||
211 | |||
212 | pdev = to_platform_device(dev); | ||
213 | pdata = pdev->dev.platform_data; | ||
214 | 213 | ||
214 | /* Allocate the driver data region */ | ||
215 | drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); | 215 | drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); |
216 | if (!drvdata) { | 216 | if (!drvdata) { |
217 | printk(KERN_ERR "Couldn't allocate device private record\n"); | 217 | dev_err(dev, "Couldn't allocate device private record\n"); |
218 | return -ENOMEM; | 218 | return -ENOMEM; |
219 | } | 219 | } |
220 | dev_set_drvdata(dev, drvdata); | 220 | dev_set_drvdata(dev, drvdata); |
221 | 221 | ||
222 | /* Map the control registers in */ | 222 | /* Map the control registers in */ |
223 | regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 223 | if (!request_mem_region(physaddr, 8, DRIVER_NAME)) { |
224 | if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) { | 224 | dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", |
225 | printk(KERN_ERR "Couldn't get registers resource\n"); | 225 | physaddr); |
226 | retval = -EFAULT; | 226 | rc = -ENODEV; |
227 | goto failed1; | 227 | goto err_region; |
228 | } | 228 | } |
229 | 229 | drvdata->regs_phys = physaddr; | |
230 | if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) { | 230 | drvdata->regs = ioremap(physaddr, 8); |
231 | printk(KERN_ERR | 231 | if (!drvdata->regs) { |
232 | "Couldn't lock memory region at 0x%08X\n", | 232 | dev_err(dev, "Couldn't lock memory region at 0x%08lX\n", |
233 | regs_res->start); | 233 | physaddr); |
234 | retval = -EBUSY; | 234 | rc = -ENODEV; |
235 | goto failed1; | 235 | goto err_map; |
236 | } | 236 | } |
237 | drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8); | ||
238 | drvdata->regs_phys = regs_res->start; | ||
239 | 237 | ||
240 | /* Allocate the framebuffer memory */ | 238 | /* Allocate the framebuffer memory */ |
241 | drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE), | 239 | if (pdata->fb_phys) { |
242 | &drvdata->fb_phys, GFP_KERNEL); | 240 | drvdata->fb_phys = pdata->fb_phys; |
241 | drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize); | ||
242 | } else { | ||
243 | drvdata->fb_alloced = 1; | ||
244 | drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize), | ||
245 | &drvdata->fb_phys, GFP_KERNEL); | ||
246 | } | ||
247 | |||
243 | if (!drvdata->fb_virt) { | 248 | if (!drvdata->fb_virt) { |
244 | printk(KERN_ERR "Could not allocate frame buffer memory\n"); | 249 | dev_err(dev, "Could not allocate frame buffer memory\n"); |
245 | retval = -ENOMEM; | 250 | rc = -ENOMEM; |
246 | goto failed2; | 251 | goto err_fbmem; |
247 | } | 252 | } |
248 | 253 | ||
249 | /* Clear (turn to black) the framebuffer */ | 254 | /* Clear (turn to black) the framebuffer */ |
250 | memset_io((void *) drvdata->fb_virt, 0, FB_SIZE); | 255 | memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize); |
251 | 256 | ||
252 | /* Tell the hardware where the frame buffer is */ | 257 | /* Tell the hardware where the frame buffer is */ |
253 | xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); | 258 | xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys); |
254 | 259 | ||
255 | /* Turn on the display */ | 260 | /* Turn on the display */ |
256 | drvdata->reg_ctrl_default = REG_CTRL_ENABLE; | 261 | drvdata->reg_ctrl_default = REG_CTRL_ENABLE; |
257 | if (pdata && pdata->rotate_screen) | 262 | if (pdata->rotate_screen) |
258 | drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; | 263 | drvdata->reg_ctrl_default |= REG_CTRL_ROTATE; |
259 | xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); | 264 | xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default); |
260 | 265 | ||
261 | /* Fill struct fb_info */ | 266 | /* Fill struct fb_info */ |
262 | drvdata->info.device = dev; | 267 | drvdata->info.device = dev; |
263 | drvdata->info.screen_base = drvdata->fb_virt; | 268 | drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt; |
264 | drvdata->info.fbops = &xilinxfb_ops; | 269 | drvdata->info.fbops = &xilinxfb_ops; |
265 | drvdata->info.fix = xilinx_fb_fix; | 270 | drvdata->info.fix = xilinx_fb_fix; |
266 | drvdata->info.fix.smem_start = drvdata->fb_phys; | 271 | drvdata->info.fix.smem_start = drvdata->fb_phys; |
267 | drvdata->info.pseudo_palette = drvdata->pseudo_palette; | 272 | drvdata->info.fix.smem_len = fbsize; |
268 | 273 | drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL; | |
269 | if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) { | ||
270 | printk(KERN_ERR "Fail to allocate colormap (%d entries)\n", | ||
271 | PALETTE_ENTRIES_NO); | ||
272 | retval = -EFAULT; | ||
273 | goto failed3; | ||
274 | } | ||
275 | 274 | ||
275 | drvdata->info.pseudo_palette = drvdata->pseudo_palette; | ||
276 | drvdata->info.flags = FBINFO_DEFAULT; | 276 | drvdata->info.flags = FBINFO_DEFAULT; |
277 | if (pdata) { | ||
278 | xilinx_fb_var.height = pdata->screen_height_mm; | ||
279 | xilinx_fb_var.width = pdata->screen_width_mm; | ||
280 | } | ||
281 | drvdata->info.var = xilinx_fb_var; | 277 | drvdata->info.var = xilinx_fb_var; |
278 | drvdata->info.var.height = pdata->screen_height_mm; | ||
279 | drvdata->info.var.width = pdata->screen_width_mm; | ||
280 | drvdata->info.var.xres = pdata->xres; | ||
281 | drvdata->info.var.yres = pdata->yres; | ||
282 | drvdata->info.var.xres_virtual = pdata->xvirt; | ||
283 | drvdata->info.var.yres_virtual = pdata->yvirt; | ||
284 | |||
285 | /* Allocate a colour map */ | ||
286 | rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0); | ||
287 | if (rc) { | ||
288 | dev_err(dev, "Fail to allocate colormap (%d entries)\n", | ||
289 | PALETTE_ENTRIES_NO); | ||
290 | goto err_cmap; | ||
291 | } | ||
282 | 292 | ||
283 | /* Register new frame buffer */ | 293 | /* Register new frame buffer */ |
284 | if (register_framebuffer(&drvdata->info) < 0) { | 294 | rc = register_framebuffer(&drvdata->info); |
285 | printk(KERN_ERR "Could not register frame buffer\n"); | 295 | if (rc) { |
286 | retval = -EINVAL; | 296 | dev_err(dev, "Could not register frame buffer\n"); |
287 | goto failed4; | 297 | goto err_regfb; |
288 | } | 298 | } |
289 | 299 | ||
300 | /* Put a banner in the log (for DEBUG) */ | ||
301 | dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs); | ||
302 | dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n", | ||
303 | (void*)drvdata->fb_phys, drvdata->fb_virt, fbsize); | ||
304 | |||
290 | return 0; /* success */ | 305 | return 0; /* success */ |
291 | 306 | ||
292 | failed4: | 307 | err_regfb: |
293 | fb_dealloc_cmap(&drvdata->info.cmap); | 308 | fb_dealloc_cmap(&drvdata->info.cmap); |
294 | 309 | ||
295 | failed3: | 310 | err_cmap: |
296 | dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, | 311 | if (drvdata->fb_alloced) |
297 | drvdata->fb_phys); | 312 | dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt, |
298 | 313 | drvdata->fb_phys); | |
299 | /* Turn off the display */ | 314 | /* Turn off the display */ |
300 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); | 315 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); |
316 | |||
317 | err_fbmem: | ||
301 | iounmap(drvdata->regs); | 318 | iounmap(drvdata->regs); |
302 | 319 | ||
303 | failed2: | 320 | err_map: |
304 | release_mem_region(regs_res->start, 8); | 321 | release_mem_region(physaddr, 8); |
305 | 322 | ||
306 | failed1: | 323 | err_region: |
307 | kfree(drvdata); | 324 | kfree(drvdata); |
308 | dev_set_drvdata(dev, NULL); | 325 | dev_set_drvdata(dev, NULL); |
309 | 326 | ||
310 | return retval; | 327 | return rc; |
311 | } | 328 | } |
312 | 329 | ||
313 | static int | 330 | static int xilinxfb_release(struct device *dev) |
314 | xilinxfb_drv_remove(struct device *dev) | ||
315 | { | 331 | { |
316 | struct xilinxfb_drvdata *drvdata; | 332 | struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev); |
317 | |||
318 | if (!dev) | ||
319 | return -ENODEV; | ||
320 | |||
321 | drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev); | ||
322 | 333 | ||
323 | #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) | 334 | #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) |
324 | xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); | 335 | xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info); |
@@ -328,8 +339,9 @@ xilinxfb_drv_remove(struct device *dev) | |||
328 | 339 | ||
329 | fb_dealloc_cmap(&drvdata->info.cmap); | 340 | fb_dealloc_cmap(&drvdata->info.cmap); |
330 | 341 | ||
331 | dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt, | 342 | if (drvdata->fb_alloced) |
332 | drvdata->fb_phys); | 343 | dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len), |
344 | drvdata->fb_virt, drvdata->fb_phys); | ||
333 | 345 | ||
334 | /* Turn off the display */ | 346 | /* Turn off the display */ |
335 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); | 347 | xilinx_fb_out_be32(drvdata, REG_CTRL, 0); |
@@ -343,29 +355,168 @@ xilinxfb_drv_remove(struct device *dev) | |||
343 | return 0; | 355 | return 0; |
344 | } | 356 | } |
345 | 357 | ||
358 | /* --------------------------------------------------------------------- | ||
359 | * Platform bus binding | ||
360 | */ | ||
361 | |||
362 | static int | ||
363 | xilinxfb_platform_probe(struct platform_device *pdev) | ||
364 | { | ||
365 | struct xilinxfb_platform_data *pdata; | ||
366 | struct resource *res; | ||
346 | 367 | ||
347 | static struct device_driver xilinxfb_driver = { | 368 | /* Find the registers address */ |
348 | .name = DRIVER_NAME, | 369 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
349 | .bus = &platform_bus_type, | 370 | if (!res) { |
371 | dev_err(&pdev->dev, "Couldn't get registers resource\n"); | ||
372 | return -ENODEV; | ||
373 | } | ||
350 | 374 | ||
351 | .probe = xilinxfb_drv_probe, | 375 | /* If a pdata structure is provided, then extract the parameters */ |
352 | .remove = xilinxfb_drv_remove | 376 | pdata = &xilinx_fb_default_pdata; |
377 | if (pdev->dev.platform_data) { | ||
378 | pdata = pdev->dev.platform_data; | ||
379 | if (!pdata->xres) | ||
380 | pdata->xres = xilinx_fb_default_pdata.xres; | ||
381 | if (!pdata->yres) | ||
382 | pdata->yres = xilinx_fb_default_pdata.yres; | ||
383 | if (!pdata->xvirt) | ||
384 | pdata->xvirt = xilinx_fb_default_pdata.xvirt; | ||
385 | if (!pdata->yvirt) | ||
386 | pdata->yvirt = xilinx_fb_default_pdata.yvirt; | ||
387 | } | ||
388 | |||
389 | return xilinxfb_assign(&pdev->dev, res->start, pdata); | ||
390 | } | ||
391 | |||
392 | static int | ||
393 | xilinxfb_platform_remove(struct platform_device *pdev) | ||
394 | { | ||
395 | return xilinxfb_release(&pdev->dev); | ||
396 | } | ||
397 | |||
398 | |||
399 | static struct platform_driver xilinxfb_platform_driver = { | ||
400 | .probe = xilinxfb_platform_probe, | ||
401 | .remove = xilinxfb_platform_remove, | ||
402 | .driver = { | ||
403 | .owner = THIS_MODULE, | ||
404 | .name = DRIVER_NAME, | ||
405 | }, | ||
406 | }; | ||
407 | |||
408 | /* --------------------------------------------------------------------- | ||
409 | * OF bus binding | ||
410 | */ | ||
411 | |||
412 | #if defined(CONFIG_OF) | ||
413 | static int __devinit | ||
414 | xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match) | ||
415 | { | ||
416 | struct resource res; | ||
417 | const u32 *prop; | ||
418 | struct xilinxfb_platform_data pdata; | ||
419 | int size, rc; | ||
420 | |||
421 | /* Copy with the default pdata (not a ptr reference!) */ | ||
422 | pdata = xilinx_fb_default_pdata; | ||
423 | |||
424 | dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match); | ||
425 | |||
426 | rc = of_address_to_resource(op->node, 0, &res); | ||
427 | if (rc) { | ||
428 | dev_err(&op->dev, "invalid address\n"); | ||
429 | return rc; | ||
430 | } | ||
431 | |||
432 | prop = of_get_property(op->node, "phys-size", &size); | ||
433 | if ((prop) && (size >= sizeof(u32)*2)) { | ||
434 | pdata.screen_width_mm = prop[0]; | ||
435 | pdata.screen_height_mm = prop[1]; | ||
436 | } | ||
437 | |||
438 | prop = of_get_property(op->node, "resolution", &size); | ||
439 | if ((prop) && (size >= sizeof(u32)*2)) { | ||
440 | pdata.xres = prop[0]; | ||
441 | pdata.yres = prop[1]; | ||
442 | } | ||
443 | |||
444 | prop = of_get_property(op->node, "virtual-resolution", &size); | ||
445 | if ((prop) && (size >= sizeof(u32)*2)) { | ||
446 | pdata.xvirt = prop[0]; | ||
447 | pdata.yvirt = prop[1]; | ||
448 | } | ||
449 | |||
450 | if (of_find_property(op->node, "rotate-display", NULL)) | ||
451 | pdata.rotate_screen = 1; | ||
452 | |||
453 | return xilinxfb_assign(&op->dev, res.start, &pdata); | ||
454 | } | ||
455 | |||
456 | static int __devexit xilinxfb_of_remove(struct of_device *op) | ||
457 | { | ||
458 | return xilinxfb_release(&op->dev); | ||
459 | } | ||
460 | |||
461 | /* Match table for of_platform binding */ | ||
462 | static struct of_device_id __devinit xilinxfb_of_match[] = { | ||
463 | { .compatible = "xilinx,ml300-fb", }, | ||
464 | {}, | ||
353 | }; | 465 | }; |
466 | MODULE_DEVICE_TABLE(of, xilinxfb_of_match); | ||
467 | |||
468 | static struct of_platform_driver xilinxfb_of_driver = { | ||
469 | .owner = THIS_MODULE, | ||
470 | .name = DRIVER_NAME, | ||
471 | .match_table = xilinxfb_of_match, | ||
472 | .probe = xilinxfb_of_probe, | ||
473 | .remove = __devexit_p(xilinxfb_of_remove), | ||
474 | .driver = { | ||
475 | .name = DRIVER_NAME, | ||
476 | }, | ||
477 | }; | ||
478 | |||
479 | /* Registration helpers to keep the number of #ifdefs to a minimum */ | ||
480 | static inline int __init xilinxfb_of_register(void) | ||
481 | { | ||
482 | pr_debug("xilinxfb: calling of_register_platform_driver()\n"); | ||
483 | return of_register_platform_driver(&xilinxfb_of_driver); | ||
484 | } | ||
485 | |||
486 | static inline void __exit xilinxfb_of_unregister(void) | ||
487 | { | ||
488 | of_unregister_platform_driver(&xilinxfb_of_driver); | ||
489 | } | ||
490 | #else /* CONFIG_OF */ | ||
491 | /* CONFIG_OF not enabled; do nothing helpers */ | ||
492 | static inline int __init xilinxfb_of_register(void) { return 0; } | ||
493 | static inline void __exit xilinxfb_of_unregister(void) { } | ||
494 | #endif /* CONFIG_OF */ | ||
495 | |||
496 | /* --------------------------------------------------------------------- | ||
497 | * Module setup and teardown | ||
498 | */ | ||
354 | 499 | ||
355 | static int __init | 500 | static int __init |
356 | xilinxfb_init(void) | 501 | xilinxfb_init(void) |
357 | { | 502 | { |
358 | /* | 503 | int rc; |
359 | * No kernel boot options used, | 504 | rc = xilinxfb_of_register(); |
360 | * so we just need to register the driver | 505 | if (rc) |
361 | */ | 506 | return rc; |
362 | return driver_register(&xilinxfb_driver); | 507 | |
508 | rc = platform_driver_register(&xilinxfb_platform_driver); | ||
509 | if (rc) | ||
510 | xilinxfb_of_unregister(); | ||
511 | |||
512 | return rc; | ||
363 | } | 513 | } |
364 | 514 | ||
365 | static void __exit | 515 | static void __exit |
366 | xilinxfb_cleanup(void) | 516 | xilinxfb_cleanup(void) |
367 | { | 517 | { |
368 | driver_unregister(&xilinxfb_driver); | 518 | platform_driver_unregister(&xilinxfb_platform_driver); |
519 | xilinxfb_of_unregister(); | ||
369 | } | 520 | } |
370 | 521 | ||
371 | module_init(xilinxfb_init); | 522 | module_init(xilinxfb_init); |