aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/atmel_lcdfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/atmel_lcdfb.c')
-rw-r--r--drivers/video/atmel_lcdfb.c115
1 files changed, 111 insertions, 4 deletions
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 5d22ea532e42..fc65c02306dd 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -16,6 +16,7 @@
16#include <linux/fb.h> 16#include <linux/fb.h>
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/delay.h> 18#include <linux/delay.h>
19#include <linux/backlight.h>
19 20
20#include <asm/arch/board.h> 21#include <asm/arch/board.h>
21#include <asm/arch/cpu.h> 22#include <asm/arch/cpu.h>
@@ -69,6 +70,107 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
69} 70}
70#endif 71#endif
71 72
73static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
74 | ATMEL_LCDC_POL_POSITIVE
75 | ATMEL_LCDC_ENA_PWMENABLE;
76
77#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
78
79/* some bl->props field just changed */
80static int atmel_bl_update_status(struct backlight_device *bl)
81{
82 struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
83 int power = sinfo->bl_power;
84 int brightness = bl->props.brightness;
85
86 /* REVISIT there may be a meaningful difference between
87 * fb_blank and power ... there seem to be some cases
88 * this doesn't handle correctly.
89 */
90 if (bl->props.fb_blank != sinfo->bl_power)
91 power = bl->props.fb_blank;
92 else if (bl->props.power != sinfo->bl_power)
93 power = bl->props.power;
94
95 if (brightness < 0 && power == FB_BLANK_UNBLANK)
96 brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
97 else if (power != FB_BLANK_UNBLANK)
98 brightness = 0;
99
100 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
101 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
102 brightness ? contrast_ctr : 0);
103
104 bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
105
106 return 0;
107}
108
109static int atmel_bl_get_brightness(struct backlight_device *bl)
110{
111 struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
112
113 return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
114}
115
116static struct backlight_ops atmel_lcdc_bl_ops = {
117 .update_status = atmel_bl_update_status,
118 .get_brightness = atmel_bl_get_brightness,
119};
120
121static void init_backlight(struct atmel_lcdfb_info *sinfo)
122{
123 struct backlight_device *bl;
124
125 sinfo->bl_power = FB_BLANK_UNBLANK;
126
127 if (sinfo->backlight)
128 return;
129
130 bl = backlight_device_register("backlight", &sinfo->pdev->dev,
131 sinfo, &atmel_lcdc_bl_ops);
132 if (IS_ERR(sinfo->backlight)) {
133 dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
134 PTR_ERR(bl));
135 return;
136 }
137 sinfo->backlight = bl;
138
139 bl->props.power = FB_BLANK_UNBLANK;
140 bl->props.fb_blank = FB_BLANK_UNBLANK;
141 bl->props.max_brightness = 0xff;
142 bl->props.brightness = atmel_bl_get_brightness(bl);
143}
144
145static void exit_backlight(struct atmel_lcdfb_info *sinfo)
146{
147 if (sinfo->backlight)
148 backlight_device_unregister(sinfo->backlight);
149}
150
151#else
152
153static void init_backlight(struct atmel_lcdfb_info *sinfo)
154{
155 dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
156}
157
158static void exit_backlight(struct atmel_lcdfb_info *sinfo)
159{
160}
161
162#endif
163
164static void init_contrast(struct atmel_lcdfb_info *sinfo)
165{
166 /* have some default contrast/backlight settings */
167 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
168 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
169
170 if (sinfo->lcdcon_is_backlight)
171 init_backlight(sinfo);
172}
173
72 174
73static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { 175static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
74 .type = FB_TYPE_PACKED_PIXELS, 176 .type = FB_TYPE_PACKED_PIXELS,
@@ -390,10 +492,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
390 /* Disable all interrupts */ 492 /* Disable all interrupts */
391 lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); 493 lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
392 494
393 /* Set contrast */
394 value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
395 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
396 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
397 /* ...wait for DMA engine to become idle... */ 495 /* ...wait for DMA engine to become idle... */
398 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) 496 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
399 msleep(10); 497 msleep(10);
@@ -597,6 +695,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
597 sinfo->default_monspecs = pdata_sinfo->default_monspecs; 695 sinfo->default_monspecs = pdata_sinfo->default_monspecs;
598 sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; 696 sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
599 sinfo->guard_time = pdata_sinfo->guard_time; 697 sinfo->guard_time = pdata_sinfo->guard_time;
698 sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
600 } else { 699 } else {
601 dev_err(dev, "cannot get default configuration\n"); 700 dev_err(dev, "cannot get default configuration\n");
602 goto free_info; 701 goto free_info;
@@ -690,6 +789,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
690 goto release_mem; 789 goto release_mem;
691 } 790 }
692 791
792 /* Initialize PWM for contrast or backlight ("off") */
793 init_contrast(sinfo);
794
693 /* interrupt */ 795 /* interrupt */
694 ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); 796 ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
695 if (ret) { 797 if (ret) {
@@ -741,6 +843,7 @@ free_cmap:
741unregister_irqs: 843unregister_irqs:
742 free_irq(sinfo->irq_base, info); 844 free_irq(sinfo->irq_base, info);
743unmap_mmio: 845unmap_mmio:
846 exit_backlight(sinfo);
744 iounmap(sinfo->mmio); 847 iounmap(sinfo->mmio);
745release_mem: 848release_mem:
746 release_mem_region(info->fix.mmio_start, info->fix.mmio_len); 849 release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
@@ -775,6 +878,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
775 if (!sinfo) 878 if (!sinfo)
776 return 0; 879 return 0;
777 880
881 exit_backlight(sinfo);
778 if (sinfo->atmel_lcdfb_power_control) 882 if (sinfo->atmel_lcdfb_power_control)
779 sinfo->atmel_lcdfb_power_control(0); 883 sinfo->atmel_lcdfb_power_control(0);
780 unregister_framebuffer(info); 884 unregister_framebuffer(info);
@@ -801,6 +905,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
801 905
802static struct platform_driver atmel_lcdfb_driver = { 906static struct platform_driver atmel_lcdfb_driver = {
803 .remove = __exit_p(atmel_lcdfb_remove), 907 .remove = __exit_p(atmel_lcdfb_remove),
908
909// FIXME need suspend, resume
910
804 .driver = { 911 .driver = {
805 .name = "atmel_lcdfb", 912 .name = "atmel_lcdfb",
806 .owner = THIS_MODULE, 913 .owner = THIS_MODULE,