diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-05-30 23:59:19 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-05-30 23:59:19 -0400 |
commit | 8fa76f7e61ef4e5bc97207143ea4e198b22487bc (patch) | |
tree | 266c42b6687e68e4febb72d8c031e5facd899a1c /drivers/video | |
parent | a41a7b91772da2c77ac0da74285fd8ebd86a85ba (diff) | |
parent | 67a3e12b05e055c0415c556a315a3d3eb637e29e (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/video')
31 files changed, 3048 insertions, 314 deletions
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c index 8d406fb689c1..f3d7440f0072 100644 --- a/drivers/video/arcfb.c +++ b/drivers/video/arcfb.c | |||
@@ -80,7 +80,7 @@ struct arcfb_par { | |||
80 | spinlock_t lock; | 80 | spinlock_t lock; |
81 | }; | 81 | }; |
82 | 82 | ||
83 | static struct fb_fix_screeninfo arcfb_fix __initdata = { | 83 | static struct fb_fix_screeninfo arcfb_fix __devinitdata = { |
84 | .id = "arcfb", | 84 | .id = "arcfb", |
85 | .type = FB_TYPE_PACKED_PIXELS, | 85 | .type = FB_TYPE_PACKED_PIXELS, |
86 | .visual = FB_VISUAL_MONO01, | 86 | .visual = FB_VISUAL_MONO01, |
@@ -90,7 +90,7 @@ static struct fb_fix_screeninfo arcfb_fix __initdata = { | |||
90 | .accel = FB_ACCEL_NONE, | 90 | .accel = FB_ACCEL_NONE, |
91 | }; | 91 | }; |
92 | 92 | ||
93 | static struct fb_var_screeninfo arcfb_var __initdata = { | 93 | static struct fb_var_screeninfo arcfb_var __devinitdata = { |
94 | .xres = 128, | 94 | .xres = 128, |
95 | .yres = 64, | 95 | .yres = 64, |
96 | .xres_virtual = 128, | 96 | .xres_virtual = 128, |
@@ -588,7 +588,7 @@ err: | |||
588 | return retval; | 588 | return retval; |
589 | } | 589 | } |
590 | 590 | ||
591 | static int arcfb_remove(struct platform_device *dev) | 591 | static int __devexit arcfb_remove(struct platform_device *dev) |
592 | { | 592 | { |
593 | struct fb_info *info = platform_get_drvdata(dev); | 593 | struct fb_info *info = platform_get_drvdata(dev); |
594 | 594 | ||
@@ -602,7 +602,7 @@ static int arcfb_remove(struct platform_device *dev) | |||
602 | 602 | ||
603 | static struct platform_driver arcfb_driver = { | 603 | static struct platform_driver arcfb_driver = { |
604 | .probe = arcfb_probe, | 604 | .probe = arcfb_probe, |
605 | .remove = arcfb_remove, | 605 | .remove = __devexit_p(arcfb_remove), |
606 | .driver = { | 606 | .driver = { |
607 | .name = "arcfb", | 607 | .name = "arcfb", |
608 | }, | 608 | }, |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 29d72851f85b..f8d69ad36830 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -1820,10 +1820,6 @@ struct atyclk { | |||
1820 | #define ATYIO_FEATW 0x41545903 /* ATY\03 */ | 1820 | #define ATYIO_FEATW 0x41545903 /* ATY\03 */ |
1821 | #endif | 1821 | #endif |
1822 | 1822 | ||
1823 | #ifndef FBIO_WAITFORVSYNC | ||
1824 | #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) | ||
1825 | #endif | ||
1826 | |||
1827 | static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) | 1823 | static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg) |
1828 | { | 1824 | { |
1829 | struct atyfb_par *par = (struct atyfb_par *) info->par; | 1825 | struct atyfb_par *par = (struct atyfb_par *) info->par; |
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 68d2518fadaa..38ffc3fbcbe4 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c | |||
@@ -222,6 +222,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) | |||
222 | data->port = __check_device(pdata, name); | 222 | data->port = __check_device(pdata, name); |
223 | if (data->port < 0) { | 223 | if (data->port < 0) { |
224 | dev_err(&pdev->dev, "wrong platform data is assigned"); | 224 | dev_err(&pdev->dev, "wrong platform data is assigned"); |
225 | kfree(data); | ||
225 | return -EINVAL; | 226 | return -EINVAL; |
226 | } | 227 | } |
227 | 228 | ||
@@ -266,6 +267,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) | |||
266 | backlight_update_status(bl); | 267 | backlight_update_status(bl); |
267 | return 0; | 268 | return 0; |
268 | out: | 269 | out: |
270 | backlight_device_unregister(bl); | ||
269 | kfree(data); | 271 | kfree(data); |
270 | return ret; | 272 | return ret; |
271 | } | 273 | } |
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index c025c84601b0..e54a337227ea 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig | |||
@@ -8,12 +8,13 @@ menuconfig BACKLIGHT_LCD_SUPPORT | |||
8 | Enable this to be able to choose the drivers for controlling the | 8 | Enable this to be able to choose the drivers for controlling the |
9 | backlight and the LCD panel on some platforms, for example on PDAs. | 9 | backlight and the LCD panel on some platforms, for example on PDAs. |
10 | 10 | ||
11 | if BACKLIGHT_LCD_SUPPORT | ||
12 | |||
11 | # | 13 | # |
12 | # LCD | 14 | # LCD |
13 | # | 15 | # |
14 | config LCD_CLASS_DEVICE | 16 | config LCD_CLASS_DEVICE |
15 | tristate "Lowlevel LCD controls" | 17 | tristate "Lowlevel LCD controls" |
16 | depends on BACKLIGHT_LCD_SUPPORT | ||
17 | default m | 18 | default m |
18 | help | 19 | help |
19 | This framework adds support for low-level control of LCD. | 20 | This framework adds support for low-level control of LCD. |
@@ -24,31 +25,32 @@ config LCD_CLASS_DEVICE | |||
24 | To have support for your specific LCD panel you will have to | 25 | To have support for your specific LCD panel you will have to |
25 | select the proper drivers which depend on this option. | 26 | select the proper drivers which depend on this option. |
26 | 27 | ||
28 | if LCD_CLASS_DEVICE | ||
29 | |||
27 | config LCD_CORGI | 30 | config LCD_CORGI |
28 | tristate "LCD Panel support for SHARP corgi/spitz model" | 31 | tristate "LCD Panel support for SHARP corgi/spitz model" |
29 | depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL | 32 | depends on SPI_MASTER && PXA_SHARPSL |
30 | help | 33 | help |
31 | Say y here to support the LCD panels usually found on SHARP | 34 | Say y here to support the LCD panels usually found on SHARP |
32 | corgi (C7x0) and spitz (Cxx00) models. | 35 | corgi (C7x0) and spitz (Cxx00) models. |
33 | 36 | ||
34 | config LCD_L4F00242T03 | 37 | config LCD_L4F00242T03 |
35 | tristate "Epson L4F00242T03 LCD" | 38 | tristate "Epson L4F00242T03 LCD" |
36 | depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO | 39 | depends on SPI_MASTER && GENERIC_GPIO |
37 | help | 40 | help |
38 | SPI driver for Epson L4F00242T03. This provides basic support | 41 | SPI driver for Epson L4F00242T03. This provides basic support |
39 | for init and powering the LCD up/down through a sysfs interface. | 42 | for init and powering the LCD up/down through a sysfs interface. |
40 | 43 | ||
41 | config LCD_LMS283GF05 | 44 | config LCD_LMS283GF05 |
42 | tristate "Samsung LMS283GF05 LCD" | 45 | tristate "Samsung LMS283GF05 LCD" |
43 | depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO | 46 | depends on SPI_MASTER && GENERIC_GPIO |
44 | help | 47 | help |
45 | SPI driver for Samsung LMS283GF05. This provides basic support | 48 | SPI driver for Samsung LMS283GF05. This provides basic support |
46 | for powering the LCD up/down through a sysfs interface. | 49 | for powering the LCD up/down through a sysfs interface. |
47 | 50 | ||
48 | config LCD_LTV350QV | 51 | config LCD_LTV350QV |
49 | tristate "Samsung LTV350QV LCD Panel" | 52 | tristate "Samsung LTV350QV LCD Panel" |
50 | depends on LCD_CLASS_DEVICE && SPI_MASTER | 53 | depends on SPI_MASTER |
51 | default n | ||
52 | help | 54 | help |
53 | If you have a Samsung LTV350QV LCD panel, say y to include a | 55 | If you have a Samsung LTV350QV LCD panel, say y to include a |
54 | power control driver for it. The panel starts up in power | 56 | power control driver for it. The panel starts up in power |
@@ -59,60 +61,61 @@ config LCD_LTV350QV | |||
59 | 61 | ||
60 | config LCD_ILI9320 | 62 | config LCD_ILI9320 |
61 | tristate | 63 | tristate |
62 | depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT | ||
63 | default n | ||
64 | help | 64 | help |
65 | If you have a panel based on the ILI9320 controller chip | 65 | If you have a panel based on the ILI9320 controller chip |
66 | then say y to include a power driver for it. | 66 | then say y to include a power driver for it. |
67 | 67 | ||
68 | config LCD_TDO24M | 68 | config LCD_TDO24M |
69 | tristate "Toppoly TDO24M and TDO35S LCD Panels support" | 69 | tristate "Toppoly TDO24M and TDO35S LCD Panels support" |
70 | depends on LCD_CLASS_DEVICE && SPI_MASTER | 70 | depends on SPI_MASTER |
71 | default n | ||
72 | help | 71 | help |
73 | If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to | 72 | If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to |
74 | include the support for it. | 73 | include the support for it. |
75 | 74 | ||
76 | config LCD_VGG2432A4 | 75 | config LCD_VGG2432A4 |
77 | tristate "VGG2432A4 LCM device support" | 76 | tristate "VGG2432A4 LCM device support" |
78 | depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER | 77 | depends on SPI_MASTER |
79 | select LCD_ILI9320 | 78 | select LCD_ILI9320 |
80 | default n | ||
81 | help | 79 | help |
82 | If you have a VGG2432A4 panel based on the ILI9320 controller chip | 80 | If you have a VGG2432A4 panel based on the ILI9320 controller chip |
83 | then say y to include a power driver for it. | 81 | then say y to include a power driver for it. |
84 | 82 | ||
85 | config LCD_PLATFORM | 83 | config LCD_PLATFORM |
86 | tristate "Platform LCD controls" | 84 | tristate "Platform LCD controls" |
87 | depends on LCD_CLASS_DEVICE | ||
88 | help | 85 | help |
89 | This driver provides a platform-device registered LCD power | 86 | This driver provides a platform-device registered LCD power |
90 | control interface. | 87 | control interface. |
91 | 88 | ||
92 | config LCD_TOSA | 89 | config LCD_TOSA |
93 | tristate "Sharp SL-6000 LCD Driver" | 90 | tristate "Sharp SL-6000 LCD Driver" |
94 | depends on LCD_CLASS_DEVICE && SPI | 91 | depends on SPI && MACH_TOSA |
95 | depends on MACH_TOSA | ||
96 | default n | ||
97 | help | 92 | help |
98 | If you have an Sharp SL-6000 Zaurus say Y to enable a driver | 93 | If you have an Sharp SL-6000 Zaurus say Y to enable a driver |
99 | for its LCD. | 94 | for its LCD. |
100 | 95 | ||
101 | config LCD_HP700 | 96 | config LCD_HP700 |
102 | tristate "HP Jornada 700 series LCD Driver" | 97 | tristate "HP Jornada 700 series LCD Driver" |
103 | depends on LCD_CLASS_DEVICE | ||
104 | depends on SA1100_JORNADA720_SSP && !PREEMPT | 98 | depends on SA1100_JORNADA720_SSP && !PREEMPT |
105 | default y | 99 | default y |
106 | help | 100 | help |
107 | If you have an HP Jornada 700 series handheld (710/720/728) | 101 | If you have an HP Jornada 700 series handheld (710/720/728) |
108 | say Y to enable LCD control driver. | 102 | say Y to enable LCD control driver. |
109 | 103 | ||
104 | config LCD_S6E63M0 | ||
105 | tristate "S6E63M0 AMOLED LCD Driver" | ||
106 | depends on SPI && BACKLIGHT_CLASS_DEVICE | ||
107 | default n | ||
108 | help | ||
109 | If you have an S6E63M0 LCD Panel, say Y to enable its | ||
110 | LCD control driver. | ||
111 | |||
112 | endif # LCD_CLASS_DEVICE | ||
113 | |||
110 | # | 114 | # |
111 | # Backlight | 115 | # Backlight |
112 | # | 116 | # |
113 | config BACKLIGHT_CLASS_DEVICE | 117 | config BACKLIGHT_CLASS_DEVICE |
114 | tristate "Lowlevel Backlight controls" | 118 | tristate "Lowlevel Backlight controls" |
115 | depends on BACKLIGHT_LCD_SUPPORT | ||
116 | default m | 119 | default m |
117 | help | 120 | help |
118 | This framework adds support for low-level control of the LCD | 121 | This framework adds support for low-level control of the LCD |
@@ -121,9 +124,11 @@ config BACKLIGHT_CLASS_DEVICE | |||
121 | To have support for your specific LCD panel you will have to | 124 | To have support for your specific LCD panel you will have to |
122 | select the proper drivers which depend on this option. | 125 | select the proper drivers which depend on this option. |
123 | 126 | ||
127 | if BACKLIGHT_CLASS_DEVICE | ||
128 | |||
124 | config BACKLIGHT_ATMEL_LCDC | 129 | config BACKLIGHT_ATMEL_LCDC |
125 | bool "Atmel LCDC Contrast-as-Backlight control" | 130 | bool "Atmel LCDC Contrast-as-Backlight control" |
126 | depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL | 131 | depends on FB_ATMEL |
127 | default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK | 132 | default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK |
128 | help | 133 | help |
129 | This provides a backlight control internal to the Atmel LCDC | 134 | This provides a backlight control internal to the Atmel LCDC |
@@ -136,8 +141,7 @@ config BACKLIGHT_ATMEL_LCDC | |||
136 | 141 | ||
137 | config BACKLIGHT_ATMEL_PWM | 142 | config BACKLIGHT_ATMEL_PWM |
138 | tristate "Atmel PWM backlight control" | 143 | tristate "Atmel PWM backlight control" |
139 | depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM | 144 | depends on ATMEL_PWM |
140 | default n | ||
141 | help | 145 | help |
142 | Say Y here if you want to use the PWM peripheral in Atmel AT91 and | 146 | Say Y here if you want to use the PWM peripheral in Atmel AT91 and |
143 | AVR32 devices. This driver will need additional platform data to know | 147 | AVR32 devices. This driver will need additional platform data to know |
@@ -146,9 +150,18 @@ config BACKLIGHT_ATMEL_PWM | |||
146 | To compile this driver as a module, choose M here: the module will be | 150 | To compile this driver as a module, choose M here: the module will be |
147 | called atmel-pwm-bl. | 151 | called atmel-pwm-bl. |
148 | 152 | ||
153 | config BACKLIGHT_EP93XX | ||
154 | tristate "Cirrus EP93xx Backlight Driver" | ||
155 | depends on FB_EP93XX | ||
156 | help | ||
157 | If you have a LCD backlight connected to the BRIGHT output of | ||
158 | the EP93xx, say Y here to enable this driver. | ||
159 | |||
160 | To compile this driver as a module, choose M here: the module will | ||
161 | be called ep93xx_bl. | ||
162 | |||
149 | config BACKLIGHT_GENERIC | 163 | config BACKLIGHT_GENERIC |
150 | tristate "Generic (aka Sharp Corgi) Backlight Driver" | 164 | tristate "Generic (aka Sharp Corgi) Backlight Driver" |
151 | depends on BACKLIGHT_CLASS_DEVICE | ||
152 | default y | 165 | default y |
153 | help | 166 | help |
154 | Say y to enable the generic platform backlight driver previously | 167 | Say y to enable the generic platform backlight driver previously |
@@ -157,7 +170,7 @@ config BACKLIGHT_GENERIC | |||
157 | 170 | ||
158 | config BACKLIGHT_LOCOMO | 171 | config BACKLIGHT_LOCOMO |
159 | tristate "Sharp LOCOMO LCD/Backlight Driver" | 172 | tristate "Sharp LOCOMO LCD/Backlight Driver" |
160 | depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO | 173 | depends on SHARP_LOCOMO |
161 | default y | 174 | default y |
162 | help | 175 | help |
163 | If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to | 176 | If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to |
@@ -165,7 +178,7 @@ config BACKLIGHT_LOCOMO | |||
165 | 178 | ||
166 | config BACKLIGHT_OMAP1 | 179 | config BACKLIGHT_OMAP1 |
167 | tristate "OMAP1 PWL-based LCD Backlight" | 180 | tristate "OMAP1 PWL-based LCD Backlight" |
168 | depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1 | 181 | depends on ARCH_OMAP1 |
169 | default y | 182 | default y |
170 | help | 183 | help |
171 | This driver controls the LCD backlight level and power for | 184 | This driver controls the LCD backlight level and power for |
@@ -174,7 +187,7 @@ config BACKLIGHT_OMAP1 | |||
174 | 187 | ||
175 | config BACKLIGHT_HP680 | 188 | config BACKLIGHT_HP680 |
176 | tristate "HP Jornada 680 Backlight Driver" | 189 | tristate "HP Jornada 680 Backlight Driver" |
177 | depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX | 190 | depends on SH_HP6XX |
178 | default y | 191 | default y |
179 | help | 192 | help |
180 | If you have a HP Jornada 680, say y to enable the | 193 | If you have a HP Jornada 680, say y to enable the |
@@ -182,7 +195,6 @@ config BACKLIGHT_HP680 | |||
182 | 195 | ||
183 | config BACKLIGHT_HP700 | 196 | config BACKLIGHT_HP700 |
184 | tristate "HP Jornada 700 series Backlight Driver" | 197 | tristate "HP Jornada 700 series Backlight Driver" |
185 | depends on BACKLIGHT_CLASS_DEVICE | ||
186 | depends on SA1100_JORNADA720_SSP && !PREEMPT | 198 | depends on SA1100_JORNADA720_SSP && !PREEMPT |
187 | default y | 199 | default y |
188 | help | 200 | help |
@@ -191,76 +203,70 @@ config BACKLIGHT_HP700 | |||
191 | 203 | ||
192 | config BACKLIGHT_PROGEAR | 204 | config BACKLIGHT_PROGEAR |
193 | tristate "Frontpath ProGear Backlight Driver" | 205 | tristate "Frontpath ProGear Backlight Driver" |
194 | depends on BACKLIGHT_CLASS_DEVICE && PCI && X86 | 206 | depends on PCI && X86 |
195 | default n | ||
196 | help | 207 | help |
197 | If you have a Frontpath ProGear say Y to enable the | 208 | If you have a Frontpath ProGear say Y to enable the |
198 | backlight driver. | 209 | backlight driver. |
199 | 210 | ||
200 | config BACKLIGHT_CARILLO_RANCH | 211 | config BACKLIGHT_CARILLO_RANCH |
201 | tristate "Intel Carillo Ranch Backlight Driver" | 212 | tristate "Intel Carillo Ranch Backlight Driver" |
202 | depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 | 213 | depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 |
203 | default n | ||
204 | help | 214 | help |
205 | If you have a Intel LE80578 (Carillo Ranch) say Y to enable the | 215 | If you have a Intel LE80578 (Carillo Ranch) say Y to enable the |
206 | backlight driver. | 216 | backlight driver. |
207 | 217 | ||
208 | config BACKLIGHT_PWM | 218 | config BACKLIGHT_PWM |
209 | tristate "Generic PWM based Backlight Driver" | 219 | tristate "Generic PWM based Backlight Driver" |
210 | depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM | 220 | depends on HAVE_PWM |
211 | help | 221 | help |
212 | If you have a LCD backlight adjustable by PWM, say Y to enable | 222 | If you have a LCD backlight adjustable by PWM, say Y to enable |
213 | this driver. | 223 | this driver. |
214 | 224 | ||
215 | config BACKLIGHT_DA903X | 225 | config BACKLIGHT_DA903X |
216 | tristate "Backlight Driver for DA9030/DA9034 using WLED" | 226 | tristate "Backlight Driver for DA9030/DA9034 using WLED" |
217 | depends on BACKLIGHT_CLASS_DEVICE && PMIC_DA903X | 227 | depends on PMIC_DA903X |
218 | help | 228 | help |
219 | If you have a LCD backlight connected to the WLED output of DA9030 | 229 | If you have a LCD backlight connected to the WLED output of DA9030 |
220 | or DA9034 WLED output, say Y here to enable this driver. | 230 | or DA9034 WLED output, say Y here to enable this driver. |
221 | 231 | ||
222 | config BACKLIGHT_MAX8925 | 232 | config BACKLIGHT_MAX8925 |
223 | tristate "Backlight driver for MAX8925" | 233 | tristate "Backlight driver for MAX8925" |
224 | depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925 | 234 | depends on MFD_MAX8925 |
225 | help | 235 | help |
226 | If you have a LCD backlight connected to the WLED output of MAX8925 | 236 | If you have a LCD backlight connected to the WLED output of MAX8925 |
227 | WLED output, say Y here to enable this driver. | 237 | WLED output, say Y here to enable this driver. |
228 | 238 | ||
229 | config BACKLIGHT_MBP_NVIDIA | 239 | config BACKLIGHT_MBP_NVIDIA |
230 | tristate "MacBook Pro Nvidia Backlight Driver" | 240 | tristate "MacBook Pro Nvidia Backlight Driver" |
231 | depends on BACKLIGHT_CLASS_DEVICE && X86 | 241 | depends on X86 |
232 | default n | ||
233 | help | 242 | help |
234 | If you have an Apple Macbook Pro with Nvidia graphics hardware say Y | 243 | If you have an Apple Macbook Pro with Nvidia graphics hardware say Y |
235 | to enable a driver for its backlight | 244 | to enable a driver for its backlight |
236 | 245 | ||
237 | config BACKLIGHT_TOSA | 246 | config BACKLIGHT_TOSA |
238 | tristate "Sharp SL-6000 Backlight Driver" | 247 | tristate "Sharp SL-6000 Backlight Driver" |
239 | depends on BACKLIGHT_CLASS_DEVICE && I2C | 248 | depends on I2C && MACH_TOSA && LCD_TOSA |
240 | depends on MACH_TOSA && LCD_TOSA | ||
241 | default n | ||
242 | help | 249 | help |
243 | If you have an Sharp SL-6000 Zaurus say Y to enable a driver | 250 | If you have an Sharp SL-6000 Zaurus say Y to enable a driver |
244 | for its backlight | 251 | for its backlight |
245 | 252 | ||
246 | config BACKLIGHT_SAHARA | 253 | config BACKLIGHT_SAHARA |
247 | tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" | 254 | tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" |
248 | depends on BACKLIGHT_CLASS_DEVICE && X86 | 255 | depends on X86 |
249 | default n | ||
250 | help | 256 | help |
251 | If you have a Tabletkiosk Sahara Touch-iT, say y to enable the | 257 | If you have a Tabletkiosk Sahara Touch-iT, say y to enable the |
252 | backlight driver. | 258 | backlight driver. |
253 | 259 | ||
254 | config BACKLIGHT_WM831X | 260 | config BACKLIGHT_WM831X |
255 | tristate "WM831x PMIC Backlight Driver" | 261 | tristate "WM831x PMIC Backlight Driver" |
256 | depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X | 262 | depends on MFD_WM831X |
257 | help | 263 | help |
258 | If you have a backlight driven by the ISINK and DCDC of a | 264 | If you have a backlight driven by the ISINK and DCDC of a |
259 | WM831x PMIC say y to enable the backlight driver for it. | 265 | WM831x PMIC say y to enable the backlight driver for it. |
260 | 266 | ||
261 | config BACKLIGHT_ADX | 267 | config BACKLIGHT_ADX |
262 | tristate "Avionic Design Xanthos Backlight Driver" | 268 | tristate "Avionic Design Xanthos Backlight Driver" |
263 | depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX | 269 | depends on ARCH_PXA_ADX |
264 | default y | 270 | default y |
265 | help | 271 | help |
266 | Say Y to enable the backlight driver on Avionic Design Xanthos-based | 272 | Say Y to enable the backlight driver on Avionic Design Xanthos-based |
@@ -268,7 +274,7 @@ config BACKLIGHT_ADX | |||
268 | 274 | ||
269 | config BACKLIGHT_ADP5520 | 275 | config BACKLIGHT_ADP5520 |
270 | tristate "Backlight Driver for ADP5520/ADP5501 using WLED" | 276 | tristate "Backlight Driver for ADP5520/ADP5501 using WLED" |
271 | depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520 | 277 | depends on PMIC_ADP5520 |
272 | help | 278 | help |
273 | If you have a LCD backlight connected to the BST/BL_SNK output of | 279 | If you have a LCD backlight connected to the BST/BL_SNK output of |
274 | ADP5520 or ADP5501, say Y here to enable this driver. | 280 | ADP5520 or ADP5501, say Y here to enable this driver. |
@@ -276,9 +282,31 @@ config BACKLIGHT_ADP5520 | |||
276 | To compile this driver as a module, choose M here: the module will | 282 | To compile this driver as a module, choose M here: the module will |
277 | be called adp5520_bl. | 283 | be called adp5520_bl. |
278 | 284 | ||
285 | config BACKLIGHT_ADP8860 | ||
286 | tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED" | ||
287 | depends on BACKLIGHT_CLASS_DEVICE && I2C | ||
288 | select NEW_LEDS | ||
289 | select LEDS_CLASS | ||
290 | help | ||
291 | If you have a LCD backlight connected to the ADP8860, ADP8861 or | ||
292 | ADP8863 say Y here to enable this driver. | ||
293 | |||
294 | To compile this driver as a module, choose M here: the module will | ||
295 | be called adp8860_bl. | ||
296 | |||
279 | config BACKLIGHT_88PM860X | 297 | config BACKLIGHT_88PM860X |
280 | tristate "Backlight Driver for 88PM8606 using WLED" | 298 | tristate "Backlight Driver for 88PM8606 using WLED" |
281 | depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X | 299 | depends on MFD_88PM860X |
282 | help | 300 | help |
283 | Say Y to enable the backlight driver for Marvell 88PM8606. | 301 | Say Y to enable the backlight driver for Marvell 88PM8606. |
284 | 302 | ||
303 | config BACKLIGHT_PCF50633 | ||
304 | tristate "Backlight driver for NXP PCF50633 MFD" | ||
305 | depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633 | ||
306 | help | ||
307 | If you have a backlight driven by a NXP PCF50633 MFD, say Y here to | ||
308 | enable its driver. | ||
309 | |||
310 | endif # BACKLIGHT_CLASS_DEVICE | ||
311 | |||
312 | endif # BACKLIGHT_LCD_SUPPORT | ||
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 09d1f14d6257..44c0f81ad85d 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile | |||
@@ -11,9 +11,11 @@ obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o | |||
11 | obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o | 11 | obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o |
12 | obj-$(CONFIG_LCD_TDO24M) += tdo24m.o | 12 | obj-$(CONFIG_LCD_TDO24M) += tdo24m.o |
13 | obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o | 13 | obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o |
14 | obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o | ||
14 | 15 | ||
15 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | 16 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o |
16 | obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o | 17 | obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o |
18 | obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o | ||
17 | obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o | 19 | obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o |
18 | obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o | 20 | obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o |
19 | obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o | 21 | obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o |
@@ -30,5 +32,7 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o | |||
30 | obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o | 32 | obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o |
31 | obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o | 33 | obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o |
32 | obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o | 34 | obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o |
35 | obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o | ||
33 | obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o | 36 | obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o |
37 | obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o | ||
34 | 38 | ||
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c new file mode 100644 index 000000000000..921ca37398f3 --- /dev/null +++ b/drivers/video/backlight/adp8860_bl.c | |||
@@ -0,0 +1,838 @@ | |||
1 | /* | ||
2 | * Backlight driver for Analog Devices ADP8860 Backlight Devices | ||
3 | * | ||
4 | * Copyright 2009-2010 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/version.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/pm.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/fb.h> | ||
17 | #include <linux/backlight.h> | ||
18 | #include <linux/leds.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | |||
22 | #include <linux/i2c/adp8860.h> | ||
23 | #define ADP8860_EXT_FEATURES | ||
24 | #define ADP8860_USE_LEDS | ||
25 | |||
26 | #define ADP8860_MFDVID 0x00 /* Manufacturer and device ID */ | ||
27 | #define ADP8860_MDCR 0x01 /* Device mode and status */ | ||
28 | #define ADP8860_MDCR2 0x02 /* Device mode and Status Register 2 */ | ||
29 | #define ADP8860_INTR_EN 0x03 /* Interrupts enable */ | ||
30 | #define ADP8860_CFGR 0x04 /* Configuration register */ | ||
31 | #define ADP8860_BLSEN 0x05 /* Sink enable backlight or independent */ | ||
32 | #define ADP8860_BLOFF 0x06 /* Backlight off timeout */ | ||
33 | #define ADP8860_BLDIM 0x07 /* Backlight dim timeout */ | ||
34 | #define ADP8860_BLFR 0x08 /* Backlight fade in and out rates */ | ||
35 | #define ADP8860_BLMX1 0x09 /* Backlight (Brightness Level 1-daylight) maximum current */ | ||
36 | #define ADP8860_BLDM1 0x0A /* Backlight (Brightness Level 1-daylight) dim current */ | ||
37 | #define ADP8860_BLMX2 0x0B /* Backlight (Brightness Level 2-office) maximum current */ | ||
38 | #define ADP8860_BLDM2 0x0C /* Backlight (Brightness Level 2-office) dim current */ | ||
39 | #define ADP8860_BLMX3 0x0D /* Backlight (Brightness Level 3-dark) maximum current */ | ||
40 | #define ADP8860_BLDM3 0x0E /* Backlight (Brightness Level 3-dark) dim current */ | ||
41 | #define ADP8860_ISCFR 0x0F /* Independent sink current fade control register */ | ||
42 | #define ADP8860_ISCC 0x10 /* Independent sink current control register */ | ||
43 | #define ADP8860_ISCT1 0x11 /* Independent Sink Current Timer Register LED[7:5] */ | ||
44 | #define ADP8860_ISCT2 0x12 /* Independent Sink Current Timer Register LED[4:1] */ | ||
45 | #define ADP8860_ISCF 0x13 /* Independent sink current fade register */ | ||
46 | #define ADP8860_ISC7 0x14 /* Independent Sink Current LED7 */ | ||
47 | #define ADP8860_ISC6 0x15 /* Independent Sink Current LED6 */ | ||
48 | #define ADP8860_ISC5 0x16 /* Independent Sink Current LED5 */ | ||
49 | #define ADP8860_ISC4 0x17 /* Independent Sink Current LED4 */ | ||
50 | #define ADP8860_ISC3 0x18 /* Independent Sink Current LED3 */ | ||
51 | #define ADP8860_ISC2 0x19 /* Independent Sink Current LED2 */ | ||
52 | #define ADP8860_ISC1 0x1A /* Independent Sink Current LED1 */ | ||
53 | #define ADP8860_CCFG 0x1B /* Comparator configuration */ | ||
54 | #define ADP8860_CCFG2 0x1C /* Second comparator configuration */ | ||
55 | #define ADP8860_L2_TRP 0x1D /* L2 comparator reference */ | ||
56 | #define ADP8860_L2_HYS 0x1E /* L2 hysteresis */ | ||
57 | #define ADP8860_L3_TRP 0x1F /* L3 comparator reference */ | ||
58 | #define ADP8860_L3_HYS 0x20 /* L3 hysteresis */ | ||
59 | #define ADP8860_PH1LEVL 0x21 /* First phototransistor ambient light level-low byte register */ | ||
60 | #define ADP8860_PH1LEVH 0x22 /* First phototransistor ambient light level-high byte register */ | ||
61 | #define ADP8860_PH2LEVL 0x23 /* Second phototransistor ambient light level-low byte register */ | ||
62 | #define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */ | ||
63 | |||
64 | #define ADP8860_MANUFID 0x0 /* Analog Devices ADP8860 Manufacturer ID */ | ||
65 | #define ADP8861_MANUFID 0x4 /* Analog Devices ADP8861 Manufacturer ID */ | ||
66 | #define ADP8863_MANUFID 0x2 /* Analog Devices ADP8863 Manufacturer ID */ | ||
67 | |||
68 | #define ADP8860_DEVID(x) ((x) & 0xF) | ||
69 | #define ADP8860_MANID(x) ((x) >> 4) | ||
70 | |||
71 | /* MDCR Device mode and status */ | ||
72 | #define INT_CFG (1 << 6) | ||
73 | #define NSTBY (1 << 5) | ||
74 | #define DIM_EN (1 << 4) | ||
75 | #define GDWN_DIS (1 << 3) | ||
76 | #define SIS_EN (1 << 2) | ||
77 | #define CMP_AUTOEN (1 << 1) | ||
78 | #define BLEN (1 << 0) | ||
79 | |||
80 | /* ADP8860_CCFG Main ALS comparator level enable */ | ||
81 | #define L3_EN (1 << 1) | ||
82 | #define L2_EN (1 << 0) | ||
83 | |||
84 | #define CFGR_BLV_SHIFT 3 | ||
85 | #define CFGR_BLV_MASK 0x3 | ||
86 | #define ADP8860_FLAG_LED_MASK 0xFF | ||
87 | |||
88 | #define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4)) | ||
89 | #define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1)) | ||
90 | #define ALS_CCFG_VAL(filt) ((0x7 & filt) << 5) | ||
91 | |||
92 | enum { | ||
93 | adp8860, | ||
94 | adp8861, | ||
95 | adp8863 | ||
96 | }; | ||
97 | |||
98 | struct adp8860_led { | ||
99 | struct led_classdev cdev; | ||
100 | struct work_struct work; | ||
101 | struct i2c_client *client; | ||
102 | enum led_brightness new_brightness; | ||
103 | int id; | ||
104 | int flags; | ||
105 | }; | ||
106 | |||
107 | struct adp8860_bl { | ||
108 | struct i2c_client *client; | ||
109 | struct backlight_device *bl; | ||
110 | struct adp8860_led *led; | ||
111 | struct adp8860_backlight_platform_data *pdata; | ||
112 | struct mutex lock; | ||
113 | unsigned long cached_daylight_max; | ||
114 | int id; | ||
115 | int revid; | ||
116 | int current_brightness; | ||
117 | unsigned en_ambl_sens:1; | ||
118 | unsigned gdwn_dis:1; | ||
119 | }; | ||
120 | |||
121 | static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val) | ||
122 | { | ||
123 | int ret; | ||
124 | |||
125 | ret = i2c_smbus_read_byte_data(client, reg); | ||
126 | if (ret < 0) { | ||
127 | dev_err(&client->dev, "failed reading at 0x%02x\n", reg); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | *val = (uint8_t)ret; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int adp8860_write(struct i2c_client *client, u8 reg, u8 val) | ||
136 | { | ||
137 | return i2c_smbus_write_byte_data(client, reg, val); | ||
138 | } | ||
139 | |||
140 | static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask) | ||
141 | { | ||
142 | struct adp8860_bl *data = i2c_get_clientdata(client); | ||
143 | uint8_t reg_val; | ||
144 | int ret; | ||
145 | |||
146 | mutex_lock(&data->lock); | ||
147 | |||
148 | ret = adp8860_read(client, reg, ®_val); | ||
149 | |||
150 | if (!ret && ((reg_val & bit_mask) == 0)) { | ||
151 | reg_val |= bit_mask; | ||
152 | ret = adp8860_write(client, reg, reg_val); | ||
153 | } | ||
154 | |||
155 | mutex_unlock(&data->lock); | ||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask) | ||
160 | { | ||
161 | struct adp8860_bl *data = i2c_get_clientdata(client); | ||
162 | uint8_t reg_val; | ||
163 | int ret; | ||
164 | |||
165 | mutex_lock(&data->lock); | ||
166 | |||
167 | ret = adp8860_read(client, reg, ®_val); | ||
168 | |||
169 | if (!ret && (reg_val & bit_mask)) { | ||
170 | reg_val &= ~bit_mask; | ||
171 | ret = adp8860_write(client, reg, reg_val); | ||
172 | } | ||
173 | |||
174 | mutex_unlock(&data->lock); | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * Independent sink / LED | ||
180 | */ | ||
181 | #if defined(ADP8860_USE_LEDS) | ||
182 | static void adp8860_led_work(struct work_struct *work) | ||
183 | { | ||
184 | struct adp8860_led *led = container_of(work, struct adp8860_led, work); | ||
185 | adp8860_write(led->client, ADP8860_ISC1 - led->id + 1, | ||
186 | led->new_brightness >> 1); | ||
187 | } | ||
188 | |||
189 | static void adp8860_led_set(struct led_classdev *led_cdev, | ||
190 | enum led_brightness value) | ||
191 | { | ||
192 | struct adp8860_led *led; | ||
193 | |||
194 | led = container_of(led_cdev, struct adp8860_led, cdev); | ||
195 | led->new_brightness = value; | ||
196 | schedule_work(&led->work); | ||
197 | } | ||
198 | |||
199 | static int adp8860_led_setup(struct adp8860_led *led) | ||
200 | { | ||
201 | struct i2c_client *client = led->client; | ||
202 | int ret = 0; | ||
203 | |||
204 | ret = adp8860_write(client, ADP8860_ISC1 - led->id + 1, 0); | ||
205 | ret |= adp8860_set_bits(client, ADP8860_ISCC, 1 << (led->id - 1)); | ||
206 | |||
207 | if (led->id > 4) | ||
208 | ret |= adp8860_set_bits(client, ADP8860_ISCT1, | ||
209 | (led->flags & 0x3) << ((led->id - 5) * 2)); | ||
210 | else | ||
211 | ret |= adp8860_set_bits(client, ADP8860_ISCT2, | ||
212 | (led->flags & 0x3) << ((led->id - 1) * 2)); | ||
213 | |||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static int __devinit adp8860_led_probe(struct i2c_client *client) | ||
218 | { | ||
219 | struct adp8860_backlight_platform_data *pdata = | ||
220 | client->dev.platform_data; | ||
221 | struct adp8860_bl *data = i2c_get_clientdata(client); | ||
222 | struct adp8860_led *led, *led_dat; | ||
223 | struct led_info *cur_led; | ||
224 | int ret, i; | ||
225 | |||
226 | led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL); | ||
227 | if (led == NULL) { | ||
228 | dev_err(&client->dev, "failed to alloc memory\n"); | ||
229 | return -ENOMEM; | ||
230 | } | ||
231 | |||
232 | ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law); | ||
233 | ret = adp8860_write(client, ADP8860_ISCT1, | ||
234 | (pdata->led_on_time & 0x3) << 6); | ||
235 | ret |= adp8860_write(client, ADP8860_ISCF, | ||
236 | FADE_VAL(pdata->led_fade_in, pdata->led_fade_out)); | ||
237 | |||
238 | if (ret) { | ||
239 | dev_err(&client->dev, "failed to write\n"); | ||
240 | goto err_free; | ||
241 | } | ||
242 | |||
243 | for (i = 0; i < pdata->num_leds; ++i) { | ||
244 | cur_led = &pdata->leds[i]; | ||
245 | led_dat = &led[i]; | ||
246 | |||
247 | led_dat->id = cur_led->flags & ADP8860_FLAG_LED_MASK; | ||
248 | |||
249 | if (led_dat->id > 7 || led_dat->id < 1) { | ||
250 | dev_err(&client->dev, "Invalid LED ID %d\n", | ||
251 | led_dat->id); | ||
252 | goto err; | ||
253 | } | ||
254 | |||
255 | if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { | ||
256 | dev_err(&client->dev, "LED %d used by Backlight\n", | ||
257 | led_dat->id); | ||
258 | goto err; | ||
259 | } | ||
260 | |||
261 | led_dat->cdev.name = cur_led->name; | ||
262 | led_dat->cdev.default_trigger = cur_led->default_trigger; | ||
263 | led_dat->cdev.brightness_set = adp8860_led_set; | ||
264 | led_dat->cdev.brightness = LED_OFF; | ||
265 | led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT; | ||
266 | led_dat->client = client; | ||
267 | led_dat->new_brightness = LED_OFF; | ||
268 | INIT_WORK(&led_dat->work, adp8860_led_work); | ||
269 | |||
270 | ret = led_classdev_register(&client->dev, &led_dat->cdev); | ||
271 | if (ret) { | ||
272 | dev_err(&client->dev, "failed to register LED %d\n", | ||
273 | led_dat->id); | ||
274 | goto err; | ||
275 | } | ||
276 | |||
277 | ret = adp8860_led_setup(led_dat); | ||
278 | if (ret) { | ||
279 | dev_err(&client->dev, "failed to write\n"); | ||
280 | i++; | ||
281 | goto err; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | data->led = led; | ||
286 | |||
287 | return 0; | ||
288 | |||
289 | err: | ||
290 | for (i = i - 1; i >= 0; --i) { | ||
291 | led_classdev_unregister(&led[i].cdev); | ||
292 | cancel_work_sync(&led[i].work); | ||
293 | } | ||
294 | |||
295 | err_free: | ||
296 | kfree(led); | ||
297 | |||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static int __devexit adp8860_led_remove(struct i2c_client *client) | ||
302 | { | ||
303 | struct adp8860_backlight_platform_data *pdata = | ||
304 | client->dev.platform_data; | ||
305 | struct adp8860_bl *data = i2c_get_clientdata(client); | ||
306 | int i; | ||
307 | |||
308 | for (i = 0; i < pdata->num_leds; i++) { | ||
309 | led_classdev_unregister(&data->led[i].cdev); | ||
310 | cancel_work_sync(&data->led[i].work); | ||
311 | } | ||
312 | |||
313 | kfree(data->led); | ||
314 | return 0; | ||
315 | } | ||
316 | #else | ||
317 | static int __devinit adp8860_led_probe(struct i2c_client *client) | ||
318 | { | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int __devexit adp8860_led_remove(struct i2c_client *client) | ||
323 | { | ||
324 | return 0; | ||
325 | } | ||
326 | #endif | ||
327 | |||
328 | static int adp8860_bl_set(struct backlight_device *bl, int brightness) | ||
329 | { | ||
330 | struct adp8860_bl *data = bl_get_data(bl); | ||
331 | struct i2c_client *client = data->client; | ||
332 | int ret = 0; | ||
333 | |||
334 | if (data->en_ambl_sens) { | ||
335 | if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) { | ||
336 | /* Disable Ambient Light auto adjust */ | ||
337 | ret |= adp8860_clr_bits(client, ADP8860_MDCR, | ||
338 | CMP_AUTOEN); | ||
339 | ret |= adp8860_write(client, ADP8860_BLMX1, brightness); | ||
340 | } else { | ||
341 | /* | ||
342 | * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust | ||
343 | * restore daylight l1 sysfs brightness | ||
344 | */ | ||
345 | ret |= adp8860_write(client, ADP8860_BLMX1, | ||
346 | data->cached_daylight_max); | ||
347 | ret |= adp8860_set_bits(client, ADP8860_MDCR, | ||
348 | CMP_AUTOEN); | ||
349 | } | ||
350 | } else | ||
351 | ret |= adp8860_write(client, ADP8860_BLMX1, brightness); | ||
352 | |||
353 | if (data->current_brightness && brightness == 0) | ||
354 | ret |= adp8860_set_bits(client, | ||
355 | ADP8860_MDCR, DIM_EN); | ||
356 | else if (data->current_brightness == 0 && brightness) | ||
357 | ret |= adp8860_clr_bits(client, | ||
358 | ADP8860_MDCR, DIM_EN); | ||
359 | |||
360 | if (!ret) | ||
361 | data->current_brightness = brightness; | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | static int adp8860_bl_update_status(struct backlight_device *bl) | ||
367 | { | ||
368 | int brightness = bl->props.brightness; | ||
369 | if (bl->props.power != FB_BLANK_UNBLANK) | ||
370 | brightness = 0; | ||
371 | |||
372 | if (bl->props.fb_blank != FB_BLANK_UNBLANK) | ||
373 | brightness = 0; | ||
374 | |||
375 | return adp8860_bl_set(bl, brightness); | ||
376 | } | ||
377 | |||
378 | static int adp8860_bl_get_brightness(struct backlight_device *bl) | ||
379 | { | ||
380 | struct adp8860_bl *data = bl_get_data(bl); | ||
381 | |||
382 | return data->current_brightness; | ||
383 | } | ||
384 | |||
385 | static const struct backlight_ops adp8860_bl_ops = { | ||
386 | .update_status = adp8860_bl_update_status, | ||
387 | .get_brightness = adp8860_bl_get_brightness, | ||
388 | }; | ||
389 | |||
390 | static int adp8860_bl_setup(struct backlight_device *bl) | ||
391 | { | ||
392 | struct adp8860_bl *data = bl_get_data(bl); | ||
393 | struct i2c_client *client = data->client; | ||
394 | struct adp8860_backlight_platform_data *pdata = data->pdata; | ||
395 | int ret = 0; | ||
396 | |||
397 | ret |= adp8860_write(client, ADP8860_BLSEN, ~pdata->bl_led_assign); | ||
398 | ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max); | ||
399 | ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim); | ||
400 | |||
401 | if (data->en_ambl_sens) { | ||
402 | data->cached_daylight_max = pdata->l1_daylight_max; | ||
403 | ret |= adp8860_write(client, ADP8860_BLMX2, | ||
404 | pdata->l2_office_max); | ||
405 | ret |= adp8860_write(client, ADP8860_BLDM2, | ||
406 | pdata->l2_office_dim); | ||
407 | ret |= adp8860_write(client, ADP8860_BLMX3, | ||
408 | pdata->l3_dark_max); | ||
409 | ret |= adp8860_write(client, ADP8860_BLDM3, | ||
410 | pdata->l3_dark_dim); | ||
411 | |||
412 | ret |= adp8860_write(client, ADP8860_L2_TRP, pdata->l2_trip); | ||
413 | ret |= adp8860_write(client, ADP8860_L2_HYS, pdata->l2_hyst); | ||
414 | ret |= adp8860_write(client, ADP8860_L3_TRP, pdata->l3_trip); | ||
415 | ret |= adp8860_write(client, ADP8860_L3_HYS, pdata->l3_hyst); | ||
416 | ret |= adp8860_write(client, ADP8860_CCFG, L2_EN | L3_EN | | ||
417 | ALS_CCFG_VAL(pdata->abml_filt)); | ||
418 | } | ||
419 | |||
420 | ret |= adp8860_write(client, ADP8860_CFGR, | ||
421 | BL_CFGR_VAL(pdata->bl_fade_law, 0)); | ||
422 | |||
423 | ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in, | ||
424 | pdata->bl_fade_out)); | ||
425 | |||
426 | ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY | | ||
427 | (data->gdwn_dis ? GDWN_DIS : 0)); | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | static ssize_t adp8860_show(struct device *dev, char *buf, int reg) | ||
433 | { | ||
434 | struct adp8860_bl *data = dev_get_drvdata(dev); | ||
435 | int error; | ||
436 | uint8_t reg_val; | ||
437 | |||
438 | mutex_lock(&data->lock); | ||
439 | error = adp8860_read(data->client, reg, ®_val); | ||
440 | mutex_unlock(&data->lock); | ||
441 | |||
442 | if (error < 0) | ||
443 | return error; | ||
444 | |||
445 | return sprintf(buf, "%u\n", reg_val); | ||
446 | } | ||
447 | |||
448 | static ssize_t adp8860_store(struct device *dev, const char *buf, | ||
449 | size_t count, int reg) | ||
450 | { | ||
451 | struct adp8860_bl *data = dev_get_drvdata(dev); | ||
452 | unsigned long val; | ||
453 | int ret; | ||
454 | |||
455 | ret = strict_strtoul(buf, 10, &val); | ||
456 | if (ret) | ||
457 | return ret; | ||
458 | |||
459 | mutex_lock(&data->lock); | ||
460 | adp8860_write(data->client, reg, val); | ||
461 | mutex_unlock(&data->lock); | ||
462 | |||
463 | return count; | ||
464 | } | ||
465 | |||
466 | static ssize_t adp8860_bl_l3_dark_max_show(struct device *dev, | ||
467 | struct device_attribute *attr, char *buf) | ||
468 | { | ||
469 | return adp8860_show(dev, buf, ADP8860_BLMX3); | ||
470 | } | ||
471 | |||
472 | static ssize_t adp8860_bl_l3_dark_max_store(struct device *dev, | ||
473 | struct device_attribute *attr, const char *buf, size_t count) | ||
474 | { | ||
475 | return adp8860_store(dev, buf, count, ADP8860_BLMX3); | ||
476 | } | ||
477 | |||
478 | static DEVICE_ATTR(l3_dark_max, 0664, adp8860_bl_l3_dark_max_show, | ||
479 | adp8860_bl_l3_dark_max_store); | ||
480 | |||
481 | static ssize_t adp8860_bl_l2_office_max_show(struct device *dev, | ||
482 | struct device_attribute *attr, char *buf) | ||
483 | { | ||
484 | return adp8860_show(dev, buf, ADP8860_BLMX2); | ||
485 | } | ||
486 | |||
487 | static ssize_t adp8860_bl_l2_office_max_store(struct device *dev, | ||
488 | struct device_attribute *attr, const char *buf, size_t count) | ||
489 | { | ||
490 | return adp8860_store(dev, buf, count, ADP8860_BLMX2); | ||
491 | } | ||
492 | static DEVICE_ATTR(l2_office_max, 0664, adp8860_bl_l2_office_max_show, | ||
493 | adp8860_bl_l2_office_max_store); | ||
494 | |||
495 | static ssize_t adp8860_bl_l1_daylight_max_show(struct device *dev, | ||
496 | struct device_attribute *attr, char *buf) | ||
497 | { | ||
498 | return adp8860_show(dev, buf, ADP8860_BLMX1); | ||
499 | } | ||
500 | |||
501 | static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev, | ||
502 | struct device_attribute *attr, const char *buf, size_t count) | ||
503 | { | ||
504 | struct adp8860_bl *data = dev_get_drvdata(dev); | ||
505 | |||
506 | strict_strtoul(buf, 10, &data->cached_daylight_max); | ||
507 | return adp8860_store(dev, buf, count, ADP8860_BLMX1); | ||
508 | } | ||
509 | static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show, | ||
510 | adp8860_bl_l1_daylight_max_store); | ||
511 | |||
512 | static ssize_t adp8860_bl_l3_dark_dim_show(struct device *dev, | ||
513 | struct device_attribute *attr, char *buf) | ||
514 | { | ||
515 | return adp8860_show(dev, buf, ADP8860_BLDM3); | ||
516 | } | ||
517 | |||
518 | static ssize_t adp8860_bl_l3_dark_dim_store(struct device *dev, | ||
519 | struct device_attribute *attr, | ||
520 | const char *buf, size_t count) | ||
521 | { | ||
522 | return adp8860_store(dev, buf, count, ADP8860_BLDM3); | ||
523 | } | ||
524 | static DEVICE_ATTR(l3_dark_dim, 0664, adp8860_bl_l3_dark_dim_show, | ||
525 | adp8860_bl_l3_dark_dim_store); | ||
526 | |||
527 | static ssize_t adp8860_bl_l2_office_dim_show(struct device *dev, | ||
528 | struct device_attribute *attr, char *buf) | ||
529 | { | ||
530 | return adp8860_show(dev, buf, ADP8860_BLDM2); | ||
531 | } | ||
532 | |||
533 | static ssize_t adp8860_bl_l2_office_dim_store(struct device *dev, | ||
534 | struct device_attribute *attr, | ||
535 | const char *buf, size_t count) | ||
536 | { | ||
537 | return adp8860_store(dev, buf, count, ADP8860_BLDM2); | ||
538 | } | ||
539 | static DEVICE_ATTR(l2_office_dim, 0664, adp8860_bl_l2_office_dim_show, | ||
540 | adp8860_bl_l2_office_dim_store); | ||
541 | |||
542 | static ssize_t adp8860_bl_l1_daylight_dim_show(struct device *dev, | ||
543 | struct device_attribute *attr, char *buf) | ||
544 | { | ||
545 | return adp8860_show(dev, buf, ADP8860_BLDM1); | ||
546 | } | ||
547 | |||
548 | static ssize_t adp8860_bl_l1_daylight_dim_store(struct device *dev, | ||
549 | struct device_attribute *attr, | ||
550 | const char *buf, size_t count) | ||
551 | { | ||
552 | return adp8860_store(dev, buf, count, ADP8860_BLDM1); | ||
553 | } | ||
554 | static DEVICE_ATTR(l1_daylight_dim, 0664, adp8860_bl_l1_daylight_dim_show, | ||
555 | adp8860_bl_l1_daylight_dim_store); | ||
556 | |||
557 | #ifdef ADP8860_EXT_FEATURES | ||
558 | static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev, | ||
559 | struct device_attribute *attr, char *buf) | ||
560 | { | ||
561 | struct adp8860_bl *data = dev_get_drvdata(dev); | ||
562 | int error; | ||
563 | uint8_t reg_val; | ||
564 | uint16_t ret_val; | ||
565 | |||
566 | mutex_lock(&data->lock); | ||
567 | error = adp8860_read(data->client, ADP8860_PH1LEVL, ®_val); | ||
568 | ret_val = reg_val; | ||
569 | error |= adp8860_read(data->client, ADP8860_PH1LEVH, ®_val); | ||
570 | mutex_unlock(&data->lock); | ||
571 | |||
572 | if (error < 0) | ||
573 | return error; | ||
574 | |||
575 | /* Return 13-bit conversion value for the first light sensor */ | ||
576 | ret_val += (reg_val & 0x1F) << 8; | ||
577 | |||
578 | return sprintf(buf, "%u\n", ret_val); | ||
579 | } | ||
580 | static DEVICE_ATTR(ambient_light_level, 0444, | ||
581 | adp8860_bl_ambient_light_level_show, NULL); | ||
582 | |||
583 | static ssize_t adp8860_bl_ambient_light_zone_show(struct device *dev, | ||
584 | struct device_attribute *attr, char *buf) | ||
585 | { | ||
586 | struct adp8860_bl *data = dev_get_drvdata(dev); | ||
587 | int error; | ||
588 | uint8_t reg_val; | ||
589 | |||
590 | mutex_lock(&data->lock); | ||
591 | error = adp8860_read(data->client, ADP8860_CFGR, ®_val); | ||
592 | mutex_unlock(&data->lock); | ||
593 | |||
594 | if (error < 0) | ||
595 | return error; | ||
596 | |||
597 | return sprintf(buf, "%u\n", | ||
598 | ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1); | ||
599 | } | ||
600 | |||
601 | static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, | ||
602 | struct device_attribute *attr, | ||
603 | const char *buf, size_t count) | ||
604 | { | ||
605 | struct adp8860_bl *data = dev_get_drvdata(dev); | ||
606 | unsigned long val; | ||
607 | uint8_t reg_val; | ||
608 | int ret; | ||
609 | |||
610 | ret = strict_strtoul(buf, 10, &val); | ||
611 | if (ret) | ||
612 | return ret; | ||
613 | |||
614 | if (val == 0) { | ||
615 | /* Enable automatic ambient light sensing */ | ||
616 | adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); | ||
617 | } else if ((val > 0) && (val < 6)) { | ||
618 | /* Disable automatic ambient light sensing */ | ||
619 | adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); | ||
620 | |||
621 | /* Set user supplied ambient light zone */ | ||
622 | mutex_lock(&data->lock); | ||
623 | adp8860_read(data->client, ADP8860_CFGR, ®_val); | ||
624 | reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); | ||
625 | reg_val |= val << CFGR_BLV_SHIFT; | ||
626 | adp8860_write(data->client, ADP8860_CFGR, reg_val); | ||
627 | mutex_unlock(&data->lock); | ||
628 | } | ||
629 | |||
630 | return count; | ||
631 | } | ||
632 | static DEVICE_ATTR(ambient_light_zone, 0664, | ||
633 | adp8860_bl_ambient_light_zone_show, | ||
634 | adp8860_bl_ambient_light_zone_store); | ||
635 | #endif | ||
636 | |||
637 | static struct attribute *adp8860_bl_attributes[] = { | ||
638 | &dev_attr_l3_dark_max.attr, | ||
639 | &dev_attr_l3_dark_dim.attr, | ||
640 | &dev_attr_l2_office_max.attr, | ||
641 | &dev_attr_l2_office_dim.attr, | ||
642 | &dev_attr_l1_daylight_max.attr, | ||
643 | &dev_attr_l1_daylight_dim.attr, | ||
644 | #ifdef ADP8860_EXT_FEATURES | ||
645 | &dev_attr_ambient_light_level.attr, | ||
646 | &dev_attr_ambient_light_zone.attr, | ||
647 | #endif | ||
648 | NULL | ||
649 | }; | ||
650 | |||
651 | static const struct attribute_group adp8860_bl_attr_group = { | ||
652 | .attrs = adp8860_bl_attributes, | ||
653 | }; | ||
654 | |||
655 | static int __devinit adp8860_probe(struct i2c_client *client, | ||
656 | const struct i2c_device_id *id) | ||
657 | { | ||
658 | struct backlight_device *bl; | ||
659 | struct adp8860_bl *data; | ||
660 | struct adp8860_backlight_platform_data *pdata = | ||
661 | client->dev.platform_data; | ||
662 | struct backlight_properties props; | ||
663 | uint8_t reg_val; | ||
664 | int ret; | ||
665 | |||
666 | if (!i2c_check_functionality(client->adapter, | ||
667 | I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
668 | dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); | ||
669 | return -EIO; | ||
670 | } | ||
671 | |||
672 | if (!pdata) { | ||
673 | dev_err(&client->dev, "no platform data?\n"); | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | |||
677 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
678 | if (data == NULL) | ||
679 | return -ENOMEM; | ||
680 | |||
681 | ret = adp8860_read(client, ADP8860_MFDVID, ®_val); | ||
682 | if (ret < 0) | ||
683 | goto out2; | ||
684 | |||
685 | switch (ADP8860_MANID(reg_val)) { | ||
686 | case ADP8863_MANUFID: | ||
687 | data->gdwn_dis = !!pdata->gdwn_dis; | ||
688 | case ADP8860_MANUFID: | ||
689 | data->en_ambl_sens = !!pdata->en_ambl_sens; | ||
690 | break; | ||
691 | case ADP8861_MANUFID: | ||
692 | data->gdwn_dis = !!pdata->gdwn_dis; | ||
693 | break; | ||
694 | default: | ||
695 | dev_err(&client->dev, "failed to probe\n"); | ||
696 | ret = -ENODEV; | ||
697 | goto out2; | ||
698 | } | ||
699 | |||
700 | /* It's confirmed that the DEVID field is actually a REVID */ | ||
701 | |||
702 | data->revid = ADP8860_DEVID(reg_val); | ||
703 | data->client = client; | ||
704 | data->pdata = pdata; | ||
705 | data->id = id->driver_data; | ||
706 | data->current_brightness = 0; | ||
707 | i2c_set_clientdata(client, data); | ||
708 | |||
709 | memset(&props, 0, sizeof(props)); | ||
710 | props.max_brightness = ADP8860_MAX_BRIGHTNESS; | ||
711 | |||
712 | mutex_init(&data->lock); | ||
713 | |||
714 | bl = backlight_device_register(dev_driver_string(&client->dev), | ||
715 | &client->dev, data, &adp8860_bl_ops, &props); | ||
716 | if (IS_ERR(bl)) { | ||
717 | dev_err(&client->dev, "failed to register backlight\n"); | ||
718 | ret = PTR_ERR(bl); | ||
719 | goto out2; | ||
720 | } | ||
721 | |||
722 | bl->props.max_brightness = | ||
723 | bl->props.brightness = ADP8860_MAX_BRIGHTNESS; | ||
724 | |||
725 | data->bl = bl; | ||
726 | |||
727 | if (data->en_ambl_sens) | ||
728 | ret = sysfs_create_group(&bl->dev.kobj, | ||
729 | &adp8860_bl_attr_group); | ||
730 | |||
731 | if (ret) { | ||
732 | dev_err(&client->dev, "failed to register sysfs\n"); | ||
733 | goto out1; | ||
734 | } | ||
735 | |||
736 | ret = adp8860_bl_setup(bl); | ||
737 | if (ret) { | ||
738 | ret = -EIO; | ||
739 | goto out; | ||
740 | } | ||
741 | |||
742 | backlight_update_status(bl); | ||
743 | |||
744 | dev_info(&client->dev, "%s Rev.%d Backlight\n", | ||
745 | client->name, data->revid); | ||
746 | |||
747 | if (pdata->num_leds) | ||
748 | adp8860_led_probe(client); | ||
749 | |||
750 | return 0; | ||
751 | |||
752 | out: | ||
753 | if (data->en_ambl_sens) | ||
754 | sysfs_remove_group(&data->bl->dev.kobj, | ||
755 | &adp8860_bl_attr_group); | ||
756 | out1: | ||
757 | backlight_device_unregister(bl); | ||
758 | out2: | ||
759 | i2c_set_clientdata(client, NULL); | ||
760 | kfree(data); | ||
761 | |||
762 | return ret; | ||
763 | } | ||
764 | |||
765 | static int __devexit adp8860_remove(struct i2c_client *client) | ||
766 | { | ||
767 | struct adp8860_bl *data = i2c_get_clientdata(client); | ||
768 | |||
769 | adp8860_clr_bits(client, ADP8860_MDCR, NSTBY); | ||
770 | |||
771 | if (data->led) | ||
772 | adp8860_led_remove(client); | ||
773 | |||
774 | if (data->en_ambl_sens) | ||
775 | sysfs_remove_group(&data->bl->dev.kobj, | ||
776 | &adp8860_bl_attr_group); | ||
777 | |||
778 | backlight_device_unregister(data->bl); | ||
779 | i2c_set_clientdata(client, NULL); | ||
780 | kfree(data); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | #ifdef CONFIG_PM | ||
786 | static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message) | ||
787 | { | ||
788 | adp8860_clr_bits(client, ADP8860_MDCR, NSTBY); | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int adp8860_i2c_resume(struct i2c_client *client) | ||
794 | { | ||
795 | adp8860_set_bits(client, ADP8860_MDCR, NSTBY); | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | #else | ||
800 | #define adp8860_i2c_suspend NULL | ||
801 | #define adp8860_i2c_resume NULL | ||
802 | #endif | ||
803 | |||
804 | static const struct i2c_device_id adp8860_id[] = { | ||
805 | { "adp8860", adp8860 }, | ||
806 | { "adp8861", adp8861 }, | ||
807 | { "adp8863", adp8863 }, | ||
808 | { } | ||
809 | }; | ||
810 | MODULE_DEVICE_TABLE(i2c, adp8860_id); | ||
811 | |||
812 | static struct i2c_driver adp8860_driver = { | ||
813 | .driver = { | ||
814 | .name = KBUILD_MODNAME, | ||
815 | }, | ||
816 | .probe = adp8860_probe, | ||
817 | .remove = __devexit_p(adp8860_remove), | ||
818 | .suspend = adp8860_i2c_suspend, | ||
819 | .resume = adp8860_i2c_resume, | ||
820 | .id_table = adp8860_id, | ||
821 | }; | ||
822 | |||
823 | static int __init adp8860_init(void) | ||
824 | { | ||
825 | return i2c_add_driver(&adp8860_driver); | ||
826 | } | ||
827 | module_init(adp8860_init); | ||
828 | |||
829 | static void __exit adp8860_exit(void) | ||
830 | { | ||
831 | i2c_del_driver(&adp8860_driver); | ||
832 | } | ||
833 | module_exit(adp8860_exit); | ||
834 | |||
835 | MODULE_LICENSE("GPL v2"); | ||
836 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
837 | MODULE_DESCRIPTION("ADP8860 Backlight driver"); | ||
838 | MODULE_ALIAS("i2c:adp8860-backlight"); | ||
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c index 7f4a7c30a98b..fe9af129c5dd 100644 --- a/drivers/video/backlight/adx_bl.c +++ b/drivers/video/backlight/adx_bl.c | |||
@@ -107,8 +107,8 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev) | |||
107 | props.max_brightness = 0xff; | 107 | props.max_brightness = 0xff; |
108 | bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, | 108 | bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, |
109 | bl, &adx_backlight_ops, &props); | 109 | bl, &adx_backlight_ops, &props); |
110 | if (!bldev) { | 110 | if (IS_ERR(bldev)) { |
111 | ret = -ENOMEM; | 111 | ret = PTR_ERR(bldev); |
112 | goto out; | 112 | goto out; |
113 | } | 113 | } |
114 | 114 | ||
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c new file mode 100644 index 000000000000..b0cc49184803 --- /dev/null +++ b/drivers/video/backlight/ep93xx_bl.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Driver for the Cirrus EP93xx lcd backlight | ||
3 | * | ||
4 | * Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This driver controls the pulse width modulated brightness control output, | ||
11 | * BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors. | ||
12 | */ | ||
13 | |||
14 | |||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/fb.h> | ||
18 | #include <linux/backlight.h> | ||
19 | |||
20 | #include <mach/hardware.h> | ||
21 | |||
22 | #define EP93XX_RASTER_REG(x) (EP93XX_RASTER_BASE + (x)) | ||
23 | #define EP93XX_RASTER_BRIGHTNESS EP93XX_RASTER_REG(0x20) | ||
24 | |||
25 | #define EP93XX_MAX_COUNT 255 | ||
26 | #define EP93XX_MAX_BRIGHT 255 | ||
27 | #define EP93XX_DEF_BRIGHT 128 | ||
28 | |||
29 | struct ep93xxbl { | ||
30 | void __iomem *mmio; | ||
31 | int brightness; | ||
32 | }; | ||
33 | |||
34 | static int ep93xxbl_set(struct backlight_device *bl, int brightness) | ||
35 | { | ||
36 | struct ep93xxbl *ep93xxbl = bl_get_data(bl); | ||
37 | |||
38 | __raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio); | ||
39 | |||
40 | ep93xxbl->brightness = brightness; | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static int ep93xxbl_update_status(struct backlight_device *bl) | ||
46 | { | ||
47 | int brightness = bl->props.brightness; | ||
48 | |||
49 | if (bl->props.power != FB_BLANK_UNBLANK || | ||
50 | bl->props.fb_blank != FB_BLANK_UNBLANK) | ||
51 | brightness = 0; | ||
52 | |||
53 | return ep93xxbl_set(bl, brightness); | ||
54 | } | ||
55 | |||
56 | static int ep93xxbl_get_brightness(struct backlight_device *bl) | ||
57 | { | ||
58 | struct ep93xxbl *ep93xxbl = bl_get_data(bl); | ||
59 | |||
60 | return ep93xxbl->brightness; | ||
61 | } | ||
62 | |||
63 | static const struct backlight_ops ep93xxbl_ops = { | ||
64 | .update_status = ep93xxbl_update_status, | ||
65 | .get_brightness = ep93xxbl_get_brightness, | ||
66 | }; | ||
67 | |||
68 | static int __init ep93xxbl_probe(struct platform_device *dev) | ||
69 | { | ||
70 | struct ep93xxbl *ep93xxbl; | ||
71 | struct backlight_device *bl; | ||
72 | struct backlight_properties props; | ||
73 | |||
74 | ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL); | ||
75 | if (!ep93xxbl) | ||
76 | return -ENOMEM; | ||
77 | |||
78 | /* | ||
79 | * This register is located in the range already ioremap'ed by | ||
80 | * the framebuffer driver. A MFD driver seems a bit of overkill | ||
81 | * to handle this so use the static I/O mapping; this address | ||
82 | * is already virtual. | ||
83 | * | ||
84 | * NOTE: No locking is required; the framebuffer does not touch | ||
85 | * this register. | ||
86 | */ | ||
87 | ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS; | ||
88 | |||
89 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
90 | props.max_brightness = EP93XX_MAX_BRIGHT; | ||
91 | bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl, | ||
92 | &ep93xxbl_ops, &props); | ||
93 | if (IS_ERR(bl)) | ||
94 | return PTR_ERR(bl); | ||
95 | |||
96 | bl->props.brightness = EP93XX_DEF_BRIGHT; | ||
97 | |||
98 | platform_set_drvdata(dev, bl); | ||
99 | |||
100 | ep93xxbl_update_status(bl); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int ep93xxbl_remove(struct platform_device *dev) | ||
106 | { | ||
107 | struct backlight_device *bl = platform_get_drvdata(dev); | ||
108 | |||
109 | backlight_device_unregister(bl); | ||
110 | platform_set_drvdata(dev, NULL); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | #ifdef CONFIG_PM | ||
115 | static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state) | ||
116 | { | ||
117 | struct backlight_device *bl = platform_get_drvdata(dev); | ||
118 | |||
119 | return ep93xxbl_set(bl, 0); | ||
120 | } | ||
121 | |||
122 | static int ep93xxbl_resume(struct platform_device *dev) | ||
123 | { | ||
124 | struct backlight_device *bl = platform_get_drvdata(dev); | ||
125 | |||
126 | backlight_update_status(bl); | ||
127 | return 0; | ||
128 | } | ||
129 | #else | ||
130 | #define ep93xxbl_suspend NULL | ||
131 | #define ep93xxbl_resume NULL | ||
132 | #endif | ||
133 | |||
134 | static struct platform_driver ep93xxbl_driver = { | ||
135 | .driver = { | ||
136 | .name = "ep93xx-bl", | ||
137 | .owner = THIS_MODULE, | ||
138 | }, | ||
139 | .probe = ep93xxbl_probe, | ||
140 | .remove = __devexit_p(ep93xxbl_remove), | ||
141 | .suspend = ep93xxbl_suspend, | ||
142 | .resume = ep93xxbl_resume, | ||
143 | }; | ||
144 | |||
145 | static int __init ep93xxbl_init(void) | ||
146 | { | ||
147 | return platform_driver_register(&ep93xxbl_driver); | ||
148 | } | ||
149 | module_init(ep93xxbl_init); | ||
150 | |||
151 | static void __exit ep93xxbl_exit(void) | ||
152 | { | ||
153 | platform_driver_unregister(&ep93xxbl_driver); | ||
154 | } | ||
155 | module_exit(ep93xxbl_exit); | ||
156 | |||
157 | MODULE_DESCRIPTION("EP93xx Backlight Driver"); | ||
158 | MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); | ||
159 | MODULE_LICENSE("GPL"); | ||
160 | MODULE_ALIAS("platform:ep93xx-bl"); | ||
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index bcdb12c93efd..9093ef0fa869 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c | |||
@@ -125,8 +125,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) | |||
125 | 125 | ||
126 | if (priv == NULL) { | 126 | if (priv == NULL) { |
127 | dev_err(&spi->dev, "No memory for this device.\n"); | 127 | dev_err(&spi->dev, "No memory for this device.\n"); |
128 | ret = -ENOMEM; | 128 | return -ENOMEM; |
129 | goto err; | ||
130 | } | 129 | } |
131 | 130 | ||
132 | dev_set_drvdata(&spi->dev, priv); | 131 | dev_set_drvdata(&spi->dev, priv); |
@@ -139,7 +138,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) | |||
139 | if (ret) { | 138 | if (ret) { |
140 | dev_err(&spi->dev, | 139 | dev_err(&spi->dev, |
141 | "Unable to get the lcd l4f00242t03 reset gpio.\n"); | 140 | "Unable to get the lcd l4f00242t03 reset gpio.\n"); |
142 | return ret; | 141 | goto err; |
143 | } | 142 | } |
144 | 143 | ||
145 | ret = gpio_direction_output(pdata->reset_gpio, 1); | 144 | ret = gpio_direction_output(pdata->reset_gpio, 1); |
@@ -151,7 +150,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi) | |||
151 | if (ret) { | 150 | if (ret) { |
152 | dev_err(&spi->dev, | 151 | dev_err(&spi->dev, |
153 | "Unable to get the lcd l4f00242t03 data en gpio.\n"); | 152 | "Unable to get the lcd l4f00242t03 data en gpio.\n"); |
154 | return ret; | 153 | goto err2; |
155 | } | 154 | } |
156 | 155 | ||
157 | ret = gpio_direction_output(pdata->data_enable_gpio, 0); | 156 | ret = gpio_direction_output(pdata->data_enable_gpio, 0); |
@@ -222,9 +221,9 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi) | |||
222 | gpio_free(pdata->reset_gpio); | 221 | gpio_free(pdata->reset_gpio); |
223 | 222 | ||
224 | if (priv->io_reg) | 223 | if (priv->io_reg) |
225 | regulator_put(priv->core_reg); | ||
226 | if (priv->core_reg) | ||
227 | regulator_put(priv->io_reg); | 224 | regulator_put(priv->io_reg); |
225 | if (priv->core_reg) | ||
226 | regulator_put(priv->core_reg); | ||
228 | 227 | ||
229 | kfree(priv); | 228 | kfree(priv); |
230 | 229 | ||
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index b5accc957ad3..b2b2c7ba1f63 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c | |||
@@ -162,6 +162,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) | |||
162 | backlight_update_status(bl); | 162 | backlight_update_status(bl); |
163 | return 0; | 163 | return 0; |
164 | out: | 164 | out: |
165 | backlight_device_unregister(bl); | ||
165 | kfree(data); | 166 | kfree(data); |
166 | return ret; | 167 | return ret; |
167 | } | 168 | } |
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 1b5d3fe6bbbc..9fb533f6373e 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c | |||
@@ -141,7 +141,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { | |||
141 | .callback = mbp_dmi_match, | 141 | .callback = mbp_dmi_match, |
142 | .ident = "MacBook 1,1", | 142 | .ident = "MacBook 1,1", |
143 | .matches = { | 143 | .matches = { |
144 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | 144 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), |
145 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), | 145 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), |
146 | }, | 146 | }, |
147 | .driver_data = (void *)&intel_chipset_data, | 147 | .driver_data = (void *)&intel_chipset_data, |
@@ -184,6 +184,42 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { | |||
184 | }, | 184 | }, |
185 | { | 185 | { |
186 | .callback = mbp_dmi_match, | 186 | .callback = mbp_dmi_match, |
187 | .ident = "MacBookPro 1,1", | ||
188 | .matches = { | ||
189 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
190 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), | ||
191 | }, | ||
192 | .driver_data = (void *)&intel_chipset_data, | ||
193 | }, | ||
194 | { | ||
195 | .callback = mbp_dmi_match, | ||
196 | .ident = "MacBookPro 1,2", | ||
197 | .matches = { | ||
198 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
199 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"), | ||
200 | }, | ||
201 | .driver_data = (void *)&intel_chipset_data, | ||
202 | }, | ||
203 | { | ||
204 | .callback = mbp_dmi_match, | ||
205 | .ident = "MacBookPro 2,1", | ||
206 | .matches = { | ||
207 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
208 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"), | ||
209 | }, | ||
210 | .driver_data = (void *)&intel_chipset_data, | ||
211 | }, | ||
212 | { | ||
213 | .callback = mbp_dmi_match, | ||
214 | .ident = "MacBookPro 2,2", | ||
215 | .matches = { | ||
216 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
217 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), | ||
218 | }, | ||
219 | .driver_data = (void *)&intel_chipset_data, | ||
220 | }, | ||
221 | { | ||
222 | .callback = mbp_dmi_match, | ||
187 | .ident = "MacBookPro 3,1", | 223 | .ident = "MacBookPro 3,1", |
188 | .matches = { | 224 | .matches = { |
189 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | 225 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
@@ -238,6 +274,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { | |||
238 | }, | 274 | }, |
239 | { | 275 | { |
240 | .callback = mbp_dmi_match, | 276 | .callback = mbp_dmi_match, |
277 | .ident = "MacBook 6,1", | ||
278 | .matches = { | ||
279 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | ||
280 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"), | ||
281 | }, | ||
282 | .driver_data = (void *)&nvidia_chipset_data, | ||
283 | }, | ||
284 | { | ||
285 | .callback = mbp_dmi_match, | ||
241 | .ident = "MacBookAir 2,1", | 286 | .ident = "MacBookAir 2,1", |
242 | .matches = { | 287 | .matches = { |
243 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | 288 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), |
diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c new file mode 100644 index 000000000000..3c424f7efdcc --- /dev/null +++ b/drivers/video/backlight/pcf50633-backlight.c | |||
@@ -0,0 +1,190 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> | ||
3 | * PCF50633 backlight device driver | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | * You should have received a copy of the GNU General Public License along | ||
11 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
12 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | |||
21 | #include <linux/backlight.h> | ||
22 | #include <linux/fb.h> | ||
23 | |||
24 | #include <linux/mfd/pcf50633/core.h> | ||
25 | #include <linux/mfd/pcf50633/backlight.h> | ||
26 | |||
27 | struct pcf50633_bl { | ||
28 | struct pcf50633 *pcf; | ||
29 | struct backlight_device *bl; | ||
30 | |||
31 | unsigned int brightness; | ||
32 | unsigned int brightness_limit; | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * pcf50633_bl_set_brightness_limit | ||
37 | * | ||
38 | * Update the brightness limit for the pc50633 backlight. The actual brightness | ||
39 | * will not go above the limit. This is useful to limit power drain for example | ||
40 | * on low battery. | ||
41 | * | ||
42 | * @dev: Pointer to a pcf50633 device | ||
43 | * @limit: The brightness limit. Valid values are 0-63 | ||
44 | */ | ||
45 | int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit) | ||
46 | { | ||
47 | struct pcf50633_bl *pcf_bl = platform_get_drvdata(pcf->bl_pdev); | ||
48 | |||
49 | if (!pcf_bl) | ||
50 | return -ENODEV; | ||
51 | |||
52 | pcf_bl->brightness_limit = limit & 0x3f; | ||
53 | backlight_update_status(pcf_bl->bl); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int pcf50633_bl_update_status(struct backlight_device *bl) | ||
59 | { | ||
60 | struct pcf50633_bl *pcf_bl = bl_get_data(bl); | ||
61 | unsigned int new_brightness; | ||
62 | |||
63 | |||
64 | if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK) || | ||
65 | bl->props.power != FB_BLANK_UNBLANK) | ||
66 | new_brightness = 0; | ||
67 | else if (bl->props.brightness < pcf_bl->brightness_limit) | ||
68 | new_brightness = bl->props.brightness; | ||
69 | else | ||
70 | new_brightness = pcf_bl->brightness_limit; | ||
71 | |||
72 | |||
73 | if (pcf_bl->brightness == new_brightness) | ||
74 | return 0; | ||
75 | |||
76 | if (new_brightness) { | ||
77 | pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDOUT, | ||
78 | new_brightness); | ||
79 | if (!pcf_bl->brightness) | ||
80 | pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 1); | ||
81 | } else { | ||
82 | pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 0); | ||
83 | } | ||
84 | |||
85 | pcf_bl->brightness = new_brightness; | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int pcf50633_bl_get_brightness(struct backlight_device *bl) | ||
91 | { | ||
92 | struct pcf50633_bl *pcf_bl = bl_get_data(bl); | ||
93 | return pcf_bl->brightness; | ||
94 | } | ||
95 | |||
96 | static const struct backlight_ops pcf50633_bl_ops = { | ||
97 | .get_brightness = pcf50633_bl_get_brightness, | ||
98 | .update_status = pcf50633_bl_update_status, | ||
99 | .options = BL_CORE_SUSPENDRESUME, | ||
100 | }; | ||
101 | |||
102 | static int __devinit pcf50633_bl_probe(struct platform_device *pdev) | ||
103 | { | ||
104 | int ret; | ||
105 | struct pcf50633_bl *pcf_bl; | ||
106 | struct device *parent = pdev->dev.parent; | ||
107 | struct pcf50633_platform_data *pcf50633_data = parent->platform_data; | ||
108 | struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data; | ||
109 | struct backlight_properties bl_props; | ||
110 | |||
111 | pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL); | ||
112 | if (!pcf_bl) | ||
113 | return -ENOMEM; | ||
114 | |||
115 | bl_props.max_brightness = 0x3f; | ||
116 | bl_props.power = FB_BLANK_UNBLANK; | ||
117 | |||
118 | if (pdata) { | ||
119 | bl_props.brightness = pdata->default_brightness; | ||
120 | pcf_bl->brightness_limit = pdata->default_brightness_limit; | ||
121 | } else { | ||
122 | bl_props.brightness = 0x3f; | ||
123 | pcf_bl->brightness_limit = 0x3f; | ||
124 | } | ||
125 | |||
126 | pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent); | ||
127 | |||
128 | pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl, | ||
129 | &pcf50633_bl_ops, &bl_props); | ||
130 | |||
131 | if (IS_ERR(pcf_bl->bl)) { | ||
132 | ret = PTR_ERR(pcf_bl->bl); | ||
133 | goto err_free; | ||
134 | } | ||
135 | |||
136 | platform_set_drvdata(pdev, pcf_bl); | ||
137 | |||
138 | pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time); | ||
139 | |||
140 | /* Should be different from bl_props.brightness, so we do not exit | ||
141 | * update_status early the first time it's called */ | ||
142 | pcf_bl->brightness = pcf_bl->bl->props.brightness + 1; | ||
143 | |||
144 | backlight_update_status(pcf_bl->bl); | ||
145 | |||
146 | return 0; | ||
147 | |||
148 | err_free: | ||
149 | kfree(pcf_bl); | ||
150 | |||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int __devexit pcf50633_bl_remove(struct platform_device *pdev) | ||
155 | { | ||
156 | struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev); | ||
157 | |||
158 | backlight_device_unregister(pcf_bl->bl); | ||
159 | |||
160 | platform_set_drvdata(pdev, NULL); | ||
161 | |||
162 | kfree(pcf_bl); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct platform_driver pcf50633_bl_driver = { | ||
168 | .probe = pcf50633_bl_probe, | ||
169 | .remove = __devexit_p(pcf50633_bl_remove), | ||
170 | .driver = { | ||
171 | .name = "pcf50633-backlight", | ||
172 | }, | ||
173 | }; | ||
174 | |||
175 | static int __init pcf50633_bl_init(void) | ||
176 | { | ||
177 | return platform_driver_register(&pcf50633_bl_driver); | ||
178 | } | ||
179 | module_init(pcf50633_bl_init); | ||
180 | |||
181 | static void __exit pcf50633_bl_exit(void) | ||
182 | { | ||
183 | platform_driver_unregister(&pcf50633_bl_driver); | ||
184 | } | ||
185 | module_exit(pcf50633_bl_exit); | ||
186 | |||
187 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
188 | MODULE_DESCRIPTION("PCF50633 backlight driver"); | ||
189 | MODULE_LICENSE("GPL"); | ||
190 | MODULE_ALIAS("platform:pcf50633-backlight"); | ||
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c new file mode 100644 index 000000000000..a3128c9cb7ad --- /dev/null +++ b/drivers/video/backlight/s6e63m0.c | |||
@@ -0,0 +1,920 @@ | |||
1 | /* | ||
2 | * S6E63M0 AMOLED LCD panel driver. | ||
3 | * | ||
4 | * Author: InKi Dae <inki.dae@samsung.com> | ||
5 | * | ||
6 | * Derived from drivers/video/omap/lcd-apollon.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/wait.h> | ||
24 | #include <linux/fb.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/gpio.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/lcd.h> | ||
32 | #include <linux/backlight.h> | ||
33 | |||
34 | #include "s6e63m0_gamma.h" | ||
35 | |||
36 | #define SLEEPMSEC 0x1000 | ||
37 | #define ENDDEF 0x2000 | ||
38 | #define DEFMASK 0xFF00 | ||
39 | #define COMMAND_ONLY 0xFE | ||
40 | #define DATA_ONLY 0xFF | ||
41 | |||
42 | #define MIN_BRIGHTNESS 0 | ||
43 | #define MAX_BRIGHTNESS 10 | ||
44 | |||
45 | #define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) | ||
46 | |||
47 | struct s6e63m0 { | ||
48 | struct device *dev; | ||
49 | struct spi_device *spi; | ||
50 | unsigned int power; | ||
51 | unsigned int current_brightness; | ||
52 | unsigned int gamma_mode; | ||
53 | unsigned int gamma_table_count; | ||
54 | struct lcd_device *ld; | ||
55 | struct backlight_device *bd; | ||
56 | struct lcd_platform_data *lcd_pd; | ||
57 | }; | ||
58 | |||
59 | static const unsigned short SEQ_PANEL_CONDITION_SET[] = { | ||
60 | 0xF8, 0x01, | ||
61 | DATA_ONLY, 0x27, | ||
62 | DATA_ONLY, 0x27, | ||
63 | DATA_ONLY, 0x07, | ||
64 | DATA_ONLY, 0x07, | ||
65 | DATA_ONLY, 0x54, | ||
66 | DATA_ONLY, 0x9f, | ||
67 | DATA_ONLY, 0x63, | ||
68 | DATA_ONLY, 0x86, | ||
69 | DATA_ONLY, 0x1a, | ||
70 | DATA_ONLY, 0x33, | ||
71 | DATA_ONLY, 0x0d, | ||
72 | DATA_ONLY, 0x00, | ||
73 | DATA_ONLY, 0x00, | ||
74 | |||
75 | ENDDEF, 0x0000 | ||
76 | }; | ||
77 | |||
78 | static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = { | ||
79 | 0xf2, 0x02, | ||
80 | DATA_ONLY, 0x03, | ||
81 | DATA_ONLY, 0x1c, | ||
82 | DATA_ONLY, 0x10, | ||
83 | DATA_ONLY, 0x10, | ||
84 | |||
85 | 0xf7, 0x03, | ||
86 | DATA_ONLY, 0x00, | ||
87 | DATA_ONLY, 0x00, | ||
88 | |||
89 | ENDDEF, 0x0000 | ||
90 | }; | ||
91 | |||
92 | static const unsigned short SEQ_GAMMA_SETTING[] = { | ||
93 | 0xfa, 0x00, | ||
94 | DATA_ONLY, 0x18, | ||
95 | DATA_ONLY, 0x08, | ||
96 | DATA_ONLY, 0x24, | ||
97 | DATA_ONLY, 0x64, | ||
98 | DATA_ONLY, 0x56, | ||
99 | DATA_ONLY, 0x33, | ||
100 | DATA_ONLY, 0xb6, | ||
101 | DATA_ONLY, 0xba, | ||
102 | DATA_ONLY, 0xa8, | ||
103 | DATA_ONLY, 0xac, | ||
104 | DATA_ONLY, 0xb1, | ||
105 | DATA_ONLY, 0x9d, | ||
106 | DATA_ONLY, 0xc1, | ||
107 | DATA_ONLY, 0xc1, | ||
108 | DATA_ONLY, 0xb7, | ||
109 | DATA_ONLY, 0x00, | ||
110 | DATA_ONLY, 0x9c, | ||
111 | DATA_ONLY, 0x00, | ||
112 | DATA_ONLY, 0x9f, | ||
113 | DATA_ONLY, 0x00, | ||
114 | DATA_ONLY, 0xd6, | ||
115 | |||
116 | 0xfa, 0x01, | ||
117 | |||
118 | ENDDEF, 0x0000 | ||
119 | }; | ||
120 | |||
121 | static const unsigned short SEQ_ETC_CONDITION_SET[] = { | ||
122 | 0xf6, 0x00, | ||
123 | DATA_ONLY, 0x8c, | ||
124 | DATA_ONLY, 0x07, | ||
125 | |||
126 | 0xb3, 0xc, | ||
127 | |||
128 | 0xb5, 0x2c, | ||
129 | DATA_ONLY, 0x12, | ||
130 | DATA_ONLY, 0x0c, | ||
131 | DATA_ONLY, 0x0a, | ||
132 | DATA_ONLY, 0x10, | ||
133 | DATA_ONLY, 0x0e, | ||
134 | DATA_ONLY, 0x17, | ||
135 | DATA_ONLY, 0x13, | ||
136 | DATA_ONLY, 0x1f, | ||
137 | DATA_ONLY, 0x1a, | ||
138 | DATA_ONLY, 0x2a, | ||
139 | DATA_ONLY, 0x24, | ||
140 | DATA_ONLY, 0x1f, | ||
141 | DATA_ONLY, 0x1b, | ||
142 | DATA_ONLY, 0x1a, | ||
143 | DATA_ONLY, 0x17, | ||
144 | |||
145 | DATA_ONLY, 0x2b, | ||
146 | DATA_ONLY, 0x26, | ||
147 | DATA_ONLY, 0x22, | ||
148 | DATA_ONLY, 0x20, | ||
149 | DATA_ONLY, 0x3a, | ||
150 | DATA_ONLY, 0x34, | ||
151 | DATA_ONLY, 0x30, | ||
152 | DATA_ONLY, 0x2c, | ||
153 | DATA_ONLY, 0x29, | ||
154 | DATA_ONLY, 0x26, | ||
155 | DATA_ONLY, 0x25, | ||
156 | DATA_ONLY, 0x23, | ||
157 | DATA_ONLY, 0x21, | ||
158 | DATA_ONLY, 0x20, | ||
159 | DATA_ONLY, 0x1e, | ||
160 | DATA_ONLY, 0x1e, | ||
161 | |||
162 | 0xb6, 0x00, | ||
163 | DATA_ONLY, 0x00, | ||
164 | DATA_ONLY, 0x11, | ||
165 | DATA_ONLY, 0x22, | ||
166 | DATA_ONLY, 0x33, | ||
167 | DATA_ONLY, 0x44, | ||
168 | DATA_ONLY, 0x44, | ||
169 | DATA_ONLY, 0x44, | ||
170 | |||
171 | DATA_ONLY, 0x55, | ||
172 | DATA_ONLY, 0x55, | ||
173 | DATA_ONLY, 0x66, | ||
174 | DATA_ONLY, 0x66, | ||
175 | DATA_ONLY, 0x66, | ||
176 | DATA_ONLY, 0x66, | ||
177 | DATA_ONLY, 0x66, | ||
178 | DATA_ONLY, 0x66, | ||
179 | |||
180 | 0xb7, 0x2c, | ||
181 | DATA_ONLY, 0x12, | ||
182 | DATA_ONLY, 0x0c, | ||
183 | DATA_ONLY, 0x0a, | ||
184 | DATA_ONLY, 0x10, | ||
185 | DATA_ONLY, 0x0e, | ||
186 | DATA_ONLY, 0x17, | ||
187 | DATA_ONLY, 0x13, | ||
188 | DATA_ONLY, 0x1f, | ||
189 | DATA_ONLY, 0x1a, | ||
190 | DATA_ONLY, 0x2a, | ||
191 | DATA_ONLY, 0x24, | ||
192 | DATA_ONLY, 0x1f, | ||
193 | DATA_ONLY, 0x1b, | ||
194 | DATA_ONLY, 0x1a, | ||
195 | DATA_ONLY, 0x17, | ||
196 | |||
197 | DATA_ONLY, 0x2b, | ||
198 | DATA_ONLY, 0x26, | ||
199 | DATA_ONLY, 0x22, | ||
200 | DATA_ONLY, 0x20, | ||
201 | DATA_ONLY, 0x3a, | ||
202 | DATA_ONLY, 0x34, | ||
203 | DATA_ONLY, 0x30, | ||
204 | DATA_ONLY, 0x2c, | ||
205 | DATA_ONLY, 0x29, | ||
206 | DATA_ONLY, 0x26, | ||
207 | DATA_ONLY, 0x25, | ||
208 | DATA_ONLY, 0x23, | ||
209 | DATA_ONLY, 0x21, | ||
210 | DATA_ONLY, 0x20, | ||
211 | DATA_ONLY, 0x1e, | ||
212 | DATA_ONLY, 0x1e, | ||
213 | |||
214 | 0xb8, 0x00, | ||
215 | DATA_ONLY, 0x00, | ||
216 | DATA_ONLY, 0x11, | ||
217 | DATA_ONLY, 0x22, | ||
218 | DATA_ONLY, 0x33, | ||
219 | DATA_ONLY, 0x44, | ||
220 | DATA_ONLY, 0x44, | ||
221 | DATA_ONLY, 0x44, | ||
222 | |||
223 | DATA_ONLY, 0x55, | ||
224 | DATA_ONLY, 0x55, | ||
225 | DATA_ONLY, 0x66, | ||
226 | DATA_ONLY, 0x66, | ||
227 | DATA_ONLY, 0x66, | ||
228 | DATA_ONLY, 0x66, | ||
229 | DATA_ONLY, 0x66, | ||
230 | DATA_ONLY, 0x66, | ||
231 | |||
232 | 0xb9, 0x2c, | ||
233 | DATA_ONLY, 0x12, | ||
234 | DATA_ONLY, 0x0c, | ||
235 | DATA_ONLY, 0x0a, | ||
236 | DATA_ONLY, 0x10, | ||
237 | DATA_ONLY, 0x0e, | ||
238 | DATA_ONLY, 0x17, | ||
239 | DATA_ONLY, 0x13, | ||
240 | DATA_ONLY, 0x1f, | ||
241 | DATA_ONLY, 0x1a, | ||
242 | DATA_ONLY, 0x2a, | ||
243 | DATA_ONLY, 0x24, | ||
244 | DATA_ONLY, 0x1f, | ||
245 | DATA_ONLY, 0x1b, | ||
246 | DATA_ONLY, 0x1a, | ||
247 | DATA_ONLY, 0x17, | ||
248 | |||
249 | DATA_ONLY, 0x2b, | ||
250 | DATA_ONLY, 0x26, | ||
251 | DATA_ONLY, 0x22, | ||
252 | DATA_ONLY, 0x20, | ||
253 | DATA_ONLY, 0x3a, | ||
254 | DATA_ONLY, 0x34, | ||
255 | DATA_ONLY, 0x30, | ||
256 | DATA_ONLY, 0x2c, | ||
257 | DATA_ONLY, 0x29, | ||
258 | DATA_ONLY, 0x26, | ||
259 | DATA_ONLY, 0x25, | ||
260 | DATA_ONLY, 0x23, | ||
261 | DATA_ONLY, 0x21, | ||
262 | DATA_ONLY, 0x20, | ||
263 | DATA_ONLY, 0x1e, | ||
264 | DATA_ONLY, 0x1e, | ||
265 | |||
266 | 0xba, 0x00, | ||
267 | DATA_ONLY, 0x00, | ||
268 | DATA_ONLY, 0x11, | ||
269 | DATA_ONLY, 0x22, | ||
270 | DATA_ONLY, 0x33, | ||
271 | DATA_ONLY, 0x44, | ||
272 | DATA_ONLY, 0x44, | ||
273 | DATA_ONLY, 0x44, | ||
274 | |||
275 | DATA_ONLY, 0x55, | ||
276 | DATA_ONLY, 0x55, | ||
277 | DATA_ONLY, 0x66, | ||
278 | DATA_ONLY, 0x66, | ||
279 | DATA_ONLY, 0x66, | ||
280 | DATA_ONLY, 0x66, | ||
281 | DATA_ONLY, 0x66, | ||
282 | DATA_ONLY, 0x66, | ||
283 | |||
284 | 0xc1, 0x4d, | ||
285 | DATA_ONLY, 0x96, | ||
286 | DATA_ONLY, 0x1d, | ||
287 | DATA_ONLY, 0x00, | ||
288 | DATA_ONLY, 0x00, | ||
289 | DATA_ONLY, 0x01, | ||
290 | DATA_ONLY, 0xdf, | ||
291 | DATA_ONLY, 0x00, | ||
292 | DATA_ONLY, 0x00, | ||
293 | DATA_ONLY, 0x03, | ||
294 | DATA_ONLY, 0x1f, | ||
295 | DATA_ONLY, 0x00, | ||
296 | DATA_ONLY, 0x00, | ||
297 | DATA_ONLY, 0x00, | ||
298 | DATA_ONLY, 0x00, | ||
299 | DATA_ONLY, 0x00, | ||
300 | DATA_ONLY, 0x00, | ||
301 | DATA_ONLY, 0x00, | ||
302 | DATA_ONLY, 0x00, | ||
303 | DATA_ONLY, 0x03, | ||
304 | DATA_ONLY, 0x06, | ||
305 | DATA_ONLY, 0x09, | ||
306 | DATA_ONLY, 0x0d, | ||
307 | DATA_ONLY, 0x0f, | ||
308 | DATA_ONLY, 0x12, | ||
309 | DATA_ONLY, 0x15, | ||
310 | DATA_ONLY, 0x18, | ||
311 | |||
312 | 0xb2, 0x10, | ||
313 | DATA_ONLY, 0x10, | ||
314 | DATA_ONLY, 0x0b, | ||
315 | DATA_ONLY, 0x05, | ||
316 | |||
317 | ENDDEF, 0x0000 | ||
318 | }; | ||
319 | |||
320 | static const unsigned short SEQ_ACL_ON[] = { | ||
321 | /* ACL on */ | ||
322 | 0xc0, 0x01, | ||
323 | |||
324 | ENDDEF, 0x0000 | ||
325 | }; | ||
326 | |||
327 | static const unsigned short SEQ_ACL_OFF[] = { | ||
328 | /* ACL off */ | ||
329 | 0xc0, 0x00, | ||
330 | |||
331 | ENDDEF, 0x0000 | ||
332 | }; | ||
333 | |||
334 | static const unsigned short SEQ_ELVSS_ON[] = { | ||
335 | /* ELVSS on */ | ||
336 | 0xb1, 0x0b, | ||
337 | |||
338 | ENDDEF, 0x0000 | ||
339 | }; | ||
340 | |||
341 | static const unsigned short SEQ_ELVSS_OFF[] = { | ||
342 | /* ELVSS off */ | ||
343 | 0xb1, 0x0a, | ||
344 | |||
345 | ENDDEF, 0x0000 | ||
346 | }; | ||
347 | |||
348 | static const unsigned short SEQ_STAND_BY_OFF[] = { | ||
349 | 0x11, COMMAND_ONLY, | ||
350 | |||
351 | ENDDEF, 0x0000 | ||
352 | }; | ||
353 | |||
354 | static const unsigned short SEQ_STAND_BY_ON[] = { | ||
355 | 0x10, COMMAND_ONLY, | ||
356 | |||
357 | ENDDEF, 0x0000 | ||
358 | }; | ||
359 | |||
360 | static const unsigned short SEQ_DISPLAY_ON[] = { | ||
361 | 0x29, COMMAND_ONLY, | ||
362 | |||
363 | ENDDEF, 0x0000 | ||
364 | }; | ||
365 | |||
366 | |||
367 | static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data) | ||
368 | { | ||
369 | u16 buf[1]; | ||
370 | struct spi_message msg; | ||
371 | |||
372 | struct spi_transfer xfer = { | ||
373 | .len = 2, | ||
374 | .tx_buf = buf, | ||
375 | }; | ||
376 | |||
377 | buf[0] = (addr << 8) | data; | ||
378 | |||
379 | spi_message_init(&msg); | ||
380 | spi_message_add_tail(&xfer, &msg); | ||
381 | |||
382 | return spi_sync(lcd->spi, &msg); | ||
383 | } | ||
384 | |||
385 | static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address, | ||
386 | unsigned char command) | ||
387 | { | ||
388 | int ret = 0; | ||
389 | |||
390 | if (address != DATA_ONLY) | ||
391 | ret = s6e63m0_spi_write_byte(lcd, 0x0, address); | ||
392 | if (command != COMMAND_ONLY) | ||
393 | ret = s6e63m0_spi_write_byte(lcd, 0x1, command); | ||
394 | |||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd, | ||
399 | const unsigned short *wbuf) | ||
400 | { | ||
401 | int ret = 0, i = 0; | ||
402 | |||
403 | while ((wbuf[i] & DEFMASK) != ENDDEF) { | ||
404 | if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { | ||
405 | ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]); | ||
406 | if (ret) | ||
407 | break; | ||
408 | } else | ||
409 | udelay(wbuf[i+1]*1000); | ||
410 | i += 2; | ||
411 | } | ||
412 | |||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma) | ||
417 | { | ||
418 | unsigned int i = 0; | ||
419 | int ret = 0; | ||
420 | |||
421 | /* disable gamma table updating. */ | ||
422 | ret = s6e63m0_spi_write(lcd, 0xfa, 0x00); | ||
423 | if (ret) { | ||
424 | dev_err(lcd->dev, "failed to disable gamma table updating.\n"); | ||
425 | goto gamma_err; | ||
426 | } | ||
427 | |||
428 | for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) { | ||
429 | ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]); | ||
430 | if (ret) { | ||
431 | dev_err(lcd->dev, "failed to set gamma table.\n"); | ||
432 | goto gamma_err; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | /* update gamma table. */ | ||
437 | ret = s6e63m0_spi_write(lcd, 0xfa, 0x01); | ||
438 | if (ret) | ||
439 | dev_err(lcd->dev, "failed to update gamma table.\n"); | ||
440 | |||
441 | gamma_err: | ||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma) | ||
446 | { | ||
447 | int ret = 0; | ||
448 | |||
449 | ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); | ||
450 | |||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | |||
455 | static int s6e63m0_ldi_init(struct s6e63m0 *lcd) | ||
456 | { | ||
457 | int ret, i; | ||
458 | const unsigned short *init_seq[] = { | ||
459 | SEQ_PANEL_CONDITION_SET, | ||
460 | SEQ_DISPLAY_CONDITION_SET, | ||
461 | SEQ_GAMMA_SETTING, | ||
462 | SEQ_ETC_CONDITION_SET, | ||
463 | SEQ_ACL_ON, | ||
464 | SEQ_ELVSS_ON, | ||
465 | }; | ||
466 | |||
467 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { | ||
468 | ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]); | ||
469 | if (ret) | ||
470 | break; | ||
471 | } | ||
472 | |||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | static int s6e63m0_ldi_enable(struct s6e63m0 *lcd) | ||
477 | { | ||
478 | int ret = 0, i; | ||
479 | const unsigned short *enable_seq[] = { | ||
480 | SEQ_STAND_BY_OFF, | ||
481 | SEQ_DISPLAY_ON, | ||
482 | }; | ||
483 | |||
484 | for (i = 0; i < ARRAY_SIZE(enable_seq); i++) { | ||
485 | ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]); | ||
486 | if (ret) | ||
487 | break; | ||
488 | } | ||
489 | |||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | static int s6e63m0_ldi_disable(struct s6e63m0 *lcd) | ||
494 | { | ||
495 | int ret; | ||
496 | |||
497 | ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON); | ||
498 | |||
499 | return ret; | ||
500 | } | ||
501 | |||
502 | static int s6e63m0_power_on(struct s6e63m0 *lcd) | ||
503 | { | ||
504 | int ret = 0; | ||
505 | struct lcd_platform_data *pd = NULL; | ||
506 | struct backlight_device *bd = NULL; | ||
507 | |||
508 | pd = lcd->lcd_pd; | ||
509 | if (!pd) { | ||
510 | dev_err(lcd->dev, "platform data is NULL.\n"); | ||
511 | return -EFAULT; | ||
512 | } | ||
513 | |||
514 | bd = lcd->bd; | ||
515 | if (!bd) { | ||
516 | dev_err(lcd->dev, "backlight device is NULL.\n"); | ||
517 | return -EFAULT; | ||
518 | } | ||
519 | |||
520 | if (!pd->power_on) { | ||
521 | dev_err(lcd->dev, "power_on is NULL.\n"); | ||
522 | return -EFAULT; | ||
523 | } else { | ||
524 | pd->power_on(lcd->ld, 1); | ||
525 | mdelay(pd->power_on_delay); | ||
526 | } | ||
527 | |||
528 | if (!pd->reset) { | ||
529 | dev_err(lcd->dev, "reset is NULL.\n"); | ||
530 | return -EFAULT; | ||
531 | } else { | ||
532 | pd->reset(lcd->ld); | ||
533 | mdelay(pd->reset_delay); | ||
534 | } | ||
535 | |||
536 | ret = s6e63m0_ldi_init(lcd); | ||
537 | if (ret) { | ||
538 | dev_err(lcd->dev, "failed to initialize ldi.\n"); | ||
539 | return ret; | ||
540 | } | ||
541 | |||
542 | ret = s6e63m0_ldi_enable(lcd); | ||
543 | if (ret) { | ||
544 | dev_err(lcd->dev, "failed to enable ldi.\n"); | ||
545 | return ret; | ||
546 | } | ||
547 | |||
548 | /* set brightness to current value after power on or resume. */ | ||
549 | ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); | ||
550 | if (ret) { | ||
551 | dev_err(lcd->dev, "lcd gamma setting failed.\n"); | ||
552 | return ret; | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int s6e63m0_power_off(struct s6e63m0 *lcd) | ||
559 | { | ||
560 | int ret = 0; | ||
561 | struct lcd_platform_data *pd = NULL; | ||
562 | |||
563 | pd = lcd->lcd_pd; | ||
564 | if (!pd) { | ||
565 | dev_err(lcd->dev, "platform data is NULL.\n"); | ||
566 | return -EFAULT; | ||
567 | } | ||
568 | |||
569 | ret = s6e63m0_ldi_disable(lcd); | ||
570 | if (ret) { | ||
571 | dev_err(lcd->dev, "lcd setting failed.\n"); | ||
572 | return -EIO; | ||
573 | } | ||
574 | |||
575 | mdelay(pd->power_off_delay); | ||
576 | |||
577 | if (!pd->power_on) { | ||
578 | dev_err(lcd->dev, "power_on is NULL.\n"); | ||
579 | return -EFAULT; | ||
580 | } else | ||
581 | pd->power_on(lcd->ld, 0); | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static int s6e63m0_power(struct s6e63m0 *lcd, int power) | ||
587 | { | ||
588 | int ret = 0; | ||
589 | |||
590 | if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) | ||
591 | ret = s6e63m0_power_on(lcd); | ||
592 | else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) | ||
593 | ret = s6e63m0_power_off(lcd); | ||
594 | |||
595 | if (!ret) | ||
596 | lcd->power = power; | ||
597 | |||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | static int s6e63m0_set_power(struct lcd_device *ld, int power) | ||
602 | { | ||
603 | struct s6e63m0 *lcd = lcd_get_data(ld); | ||
604 | |||
605 | if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && | ||
606 | power != FB_BLANK_NORMAL) { | ||
607 | dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); | ||
608 | return -EINVAL; | ||
609 | } | ||
610 | |||
611 | return s6e63m0_power(lcd, power); | ||
612 | } | ||
613 | |||
614 | static int s6e63m0_get_power(struct lcd_device *ld) | ||
615 | { | ||
616 | struct s6e63m0 *lcd = lcd_get_data(ld); | ||
617 | |||
618 | return lcd->power; | ||
619 | } | ||
620 | |||
621 | static int s6e63m0_get_brightness(struct backlight_device *bd) | ||
622 | { | ||
623 | return bd->props.brightness; | ||
624 | } | ||
625 | |||
626 | static int s6e63m0_set_brightness(struct backlight_device *bd) | ||
627 | { | ||
628 | int ret = 0, brightness = bd->props.brightness; | ||
629 | struct s6e63m0 *lcd = bl_get_data(bd); | ||
630 | |||
631 | if (brightness < MIN_BRIGHTNESS || | ||
632 | brightness > bd->props.max_brightness) { | ||
633 | dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", | ||
634 | MIN_BRIGHTNESS, MAX_BRIGHTNESS); | ||
635 | return -EINVAL; | ||
636 | } | ||
637 | |||
638 | ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness); | ||
639 | if (ret) { | ||
640 | dev_err(&bd->dev, "lcd brightness setting failed.\n"); | ||
641 | return -EIO; | ||
642 | } | ||
643 | |||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | static struct lcd_ops s6e63m0_lcd_ops = { | ||
648 | .set_power = s6e63m0_set_power, | ||
649 | .get_power = s6e63m0_get_power, | ||
650 | }; | ||
651 | |||
652 | static const struct backlight_ops s6e63m0_backlight_ops = { | ||
653 | .get_brightness = s6e63m0_get_brightness, | ||
654 | .update_status = s6e63m0_set_brightness, | ||
655 | }; | ||
656 | |||
657 | static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev, | ||
658 | struct device_attribute *attr, char *buf) | ||
659 | { | ||
660 | struct s6e63m0 *lcd = dev_get_drvdata(dev); | ||
661 | char temp[10]; | ||
662 | |||
663 | switch (lcd->gamma_mode) { | ||
664 | case 0: | ||
665 | sprintf(temp, "2.2 mode\n"); | ||
666 | strcat(buf, temp); | ||
667 | break; | ||
668 | case 1: | ||
669 | sprintf(temp, "1.9 mode\n"); | ||
670 | strcat(buf, temp); | ||
671 | break; | ||
672 | case 2: | ||
673 | sprintf(temp, "1.7 mode\n"); | ||
674 | strcat(buf, temp); | ||
675 | break; | ||
676 | default: | ||
677 | dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n"); | ||
678 | break; | ||
679 | } | ||
680 | |||
681 | return strlen(buf); | ||
682 | } | ||
683 | |||
684 | static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev, | ||
685 | struct device_attribute *attr, | ||
686 | const char *buf, size_t len) | ||
687 | { | ||
688 | struct s6e63m0 *lcd = dev_get_drvdata(dev); | ||
689 | struct backlight_device *bd = NULL; | ||
690 | int brightness, rc; | ||
691 | |||
692 | rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode); | ||
693 | if (rc < 0) | ||
694 | return rc; | ||
695 | |||
696 | bd = lcd->bd; | ||
697 | |||
698 | brightness = bd->props.brightness; | ||
699 | |||
700 | switch (lcd->gamma_mode) { | ||
701 | case 0: | ||
702 | _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); | ||
703 | break; | ||
704 | case 1: | ||
705 | _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]); | ||
706 | break; | ||
707 | case 2: | ||
708 | _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]); | ||
709 | break; | ||
710 | default: | ||
711 | dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n"); | ||
712 | _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]); | ||
713 | break; | ||
714 | } | ||
715 | return len; | ||
716 | } | ||
717 | |||
718 | static DEVICE_ATTR(gamma_mode, 0644, | ||
719 | s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode); | ||
720 | |||
721 | static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, | ||
722 | struct device_attribute *attr, char *buf) | ||
723 | { | ||
724 | struct s6e63m0 *lcd = dev_get_drvdata(dev); | ||
725 | char temp[3]; | ||
726 | |||
727 | sprintf(temp, "%d\n", lcd->gamma_table_count); | ||
728 | strcpy(buf, temp); | ||
729 | |||
730 | return strlen(buf); | ||
731 | } | ||
732 | static DEVICE_ATTR(gamma_table, 0644, | ||
733 | s6e63m0_sysfs_show_gamma_table, NULL); | ||
734 | |||
735 | static int __init s6e63m0_probe(struct spi_device *spi) | ||
736 | { | ||
737 | int ret = 0; | ||
738 | struct s6e63m0 *lcd = NULL; | ||
739 | struct lcd_device *ld = NULL; | ||
740 | struct backlight_device *bd = NULL; | ||
741 | |||
742 | lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL); | ||
743 | if (!lcd) | ||
744 | return -ENOMEM; | ||
745 | |||
746 | /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */ | ||
747 | spi->bits_per_word = 9; | ||
748 | |||
749 | ret = spi_setup(spi); | ||
750 | if (ret < 0) { | ||
751 | dev_err(&spi->dev, "spi setup failed.\n"); | ||
752 | goto out_free_lcd; | ||
753 | } | ||
754 | |||
755 | lcd->spi = spi; | ||
756 | lcd->dev = &spi->dev; | ||
757 | |||
758 | lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data; | ||
759 | if (!lcd->lcd_pd) { | ||
760 | dev_err(&spi->dev, "platform data is NULL.\n"); | ||
761 | goto out_free_lcd; | ||
762 | } | ||
763 | |||
764 | ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops); | ||
765 | if (IS_ERR(ld)) { | ||
766 | ret = PTR_ERR(ld); | ||
767 | goto out_free_lcd; | ||
768 | } | ||
769 | |||
770 | lcd->ld = ld; | ||
771 | |||
772 | bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd, | ||
773 | &s6e63m0_backlight_ops, NULL); | ||
774 | if (IS_ERR(bd)) { | ||
775 | ret = PTR_ERR(bd); | ||
776 | goto out_lcd_unregister; | ||
777 | } | ||
778 | |||
779 | bd->props.max_brightness = MAX_BRIGHTNESS; | ||
780 | bd->props.brightness = MAX_BRIGHTNESS; | ||
781 | lcd->bd = bd; | ||
782 | |||
783 | /* | ||
784 | * it gets gamma table count available so it gets user | ||
785 | * know that. | ||
786 | */ | ||
787 | lcd->gamma_table_count = | ||
788 | sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int)); | ||
789 | |||
790 | ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode); | ||
791 | if (ret < 0) | ||
792 | dev_err(&(spi->dev), "failed to add sysfs entries\n"); | ||
793 | |||
794 | ret = device_create_file(&(spi->dev), &dev_attr_gamma_table); | ||
795 | if (ret < 0) | ||
796 | dev_err(&(spi->dev), "failed to add sysfs entries\n"); | ||
797 | |||
798 | /* | ||
799 | * if lcd panel was on from bootloader like u-boot then | ||
800 | * do not lcd on. | ||
801 | */ | ||
802 | if (!lcd->lcd_pd->lcd_enabled) { | ||
803 | /* | ||
804 | * if lcd panel was off from bootloader then | ||
805 | * current lcd status is powerdown and then | ||
806 | * it enables lcd panel. | ||
807 | */ | ||
808 | lcd->power = FB_BLANK_POWERDOWN; | ||
809 | |||
810 | s6e63m0_power(lcd, FB_BLANK_UNBLANK); | ||
811 | } else | ||
812 | lcd->power = FB_BLANK_UNBLANK; | ||
813 | |||
814 | dev_set_drvdata(&spi->dev, lcd); | ||
815 | |||
816 | dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n"); | ||
817 | |||
818 | return 0; | ||
819 | |||
820 | out_lcd_unregister: | ||
821 | lcd_device_unregister(ld); | ||
822 | out_free_lcd: | ||
823 | kfree(lcd); | ||
824 | return ret; | ||
825 | } | ||
826 | |||
827 | static int __devexit s6e63m0_remove(struct spi_device *spi) | ||
828 | { | ||
829 | struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | ||
830 | |||
831 | s6e63m0_power(lcd, FB_BLANK_POWERDOWN); | ||
832 | lcd_device_unregister(lcd->ld); | ||
833 | kfree(lcd); | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | #if defined(CONFIG_PM) | ||
839 | unsigned int before_power; | ||
840 | |||
841 | static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg) | ||
842 | { | ||
843 | int ret = 0; | ||
844 | struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | ||
845 | |||
846 | dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); | ||
847 | |||
848 | before_power = lcd->power; | ||
849 | |||
850 | /* | ||
851 | * when lcd panel is suspend, lcd panel becomes off | ||
852 | * regardless of status. | ||
853 | */ | ||
854 | ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN); | ||
855 | |||
856 | return ret; | ||
857 | } | ||
858 | |||
859 | static int s6e63m0_resume(struct spi_device *spi) | ||
860 | { | ||
861 | int ret = 0; | ||
862 | struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | ||
863 | |||
864 | /* | ||
865 | * after suspended, if lcd panel status is FB_BLANK_UNBLANK | ||
866 | * (at that time, before_power is FB_BLANK_UNBLANK) then | ||
867 | * it changes that status to FB_BLANK_POWERDOWN to get lcd on. | ||
868 | */ | ||
869 | if (before_power == FB_BLANK_UNBLANK) | ||
870 | lcd->power = FB_BLANK_POWERDOWN; | ||
871 | |||
872 | dev_dbg(&spi->dev, "before_power = %d\n", before_power); | ||
873 | |||
874 | ret = s6e63m0_power(lcd, before_power); | ||
875 | |||
876 | return ret; | ||
877 | } | ||
878 | #else | ||
879 | #define s6e63m0_suspend NULL | ||
880 | #define s6e63m0_resume NULL | ||
881 | #endif | ||
882 | |||
883 | /* Power down all displays on reboot, poweroff or halt. */ | ||
884 | static void s6e63m0_shutdown(struct spi_device *spi) | ||
885 | { | ||
886 | struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); | ||
887 | |||
888 | s6e63m0_power(lcd, FB_BLANK_POWERDOWN); | ||
889 | } | ||
890 | |||
891 | static struct spi_driver s6e63m0_driver = { | ||
892 | .driver = { | ||
893 | .name = "s6e63m0", | ||
894 | .bus = &spi_bus_type, | ||
895 | .owner = THIS_MODULE, | ||
896 | }, | ||
897 | .probe = s6e63m0_probe, | ||
898 | .remove = __devexit_p(s6e63m0_remove), | ||
899 | .shutdown = s6e63m0_shutdown, | ||
900 | .suspend = s6e63m0_suspend, | ||
901 | .resume = s6e63m0_resume, | ||
902 | }; | ||
903 | |||
904 | static int __init s6e63m0_init(void) | ||
905 | { | ||
906 | return spi_register_driver(&s6e63m0_driver); | ||
907 | } | ||
908 | |||
909 | static void __exit s6e63m0_exit(void) | ||
910 | { | ||
911 | spi_unregister_driver(&s6e63m0_driver); | ||
912 | } | ||
913 | |||
914 | module_init(s6e63m0_init); | ||
915 | module_exit(s6e63m0_exit); | ||
916 | |||
917 | MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>"); | ||
918 | MODULE_DESCRIPTION("S6E63M0 LCD Driver"); | ||
919 | MODULE_LICENSE("GPL"); | ||
920 | |||
diff --git a/drivers/video/backlight/s6e63m0_gamma.h b/drivers/video/backlight/s6e63m0_gamma.h new file mode 100644 index 000000000000..2c44bdb0696b --- /dev/null +++ b/drivers/video/backlight/s6e63m0_gamma.h | |||
@@ -0,0 +1,266 @@ | |||
1 | /* linux/drivers/video/samsung/s6e63m0_brightness.h | ||
2 | * | ||
3 | * Gamma level definitions. | ||
4 | * | ||
5 | * Copyright (c) 2009 Samsung Electronics | ||
6 | * InKi Dae <inki.dae@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _S6E63M0_BRIGHTNESS_H | ||
14 | #define _S6E63M0_BRIGHTNESS_H | ||
15 | |||
16 | #define MAX_GAMMA_LEVEL 11 | ||
17 | #define GAMMA_TABLE_COUNT 21 | ||
18 | |||
19 | /* gamma value: 2.2 */ | ||
20 | static const unsigned int s6e63m0_22_300[] = { | ||
21 | 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6, | ||
22 | 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0, | ||
23 | 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb | ||
24 | }; | ||
25 | |||
26 | static const unsigned int s6e63m0_22_280[] = { | ||
27 | 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6, | ||
28 | 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1, | ||
29 | 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 | ||
30 | }; | ||
31 | |||
32 | static const unsigned int s6e63m0_22_260[] = { | ||
33 | 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6, | ||
34 | 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2, | ||
35 | 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 | ||
36 | |||
37 | }; | ||
38 | |||
39 | static const unsigned int s6e63m0_22_240[] = { | ||
40 | 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9, | ||
41 | 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3, | ||
42 | 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA | ||
43 | |||
44 | }; | ||
45 | static const unsigned int s6e63m0_22_220[] = { | ||
46 | 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8, | ||
47 | 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4, | ||
48 | 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 | ||
49 | }; | ||
50 | |||
51 | static const unsigned int s6e63m0_22_200[] = { | ||
52 | 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA, | ||
53 | 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6, | ||
54 | 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA | ||
55 | }; | ||
56 | |||
57 | static const unsigned int s6e63m0_22_170[] = { | ||
58 | 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB, | ||
59 | 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8, | ||
60 | 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB | ||
61 | }; | ||
62 | |||
63 | static const unsigned int s6e63m0_22_140[] = { | ||
64 | 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC, | ||
65 | 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9, | ||
66 | 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E | ||
67 | }; | ||
68 | |||
69 | static const unsigned int s6e63m0_22_110[] = { | ||
70 | 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF, | ||
71 | 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC, | ||
72 | 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D | ||
73 | }; | ||
74 | |||
75 | static const unsigned int s6e63m0_22_90[] = { | ||
76 | 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0, | ||
77 | 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF, | ||
78 | 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 | ||
79 | }; | ||
80 | |||
81 | static const unsigned int s6e63m0_22_30[] = { | ||
82 | 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8, | ||
83 | 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7, | ||
84 | 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 | ||
85 | }; | ||
86 | |||
87 | /* gamma value: 1.9 */ | ||
88 | static const unsigned int s6e63m0_19_300[] = { | ||
89 | 0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA, | ||
90 | 0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5, | ||
91 | 0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB | ||
92 | }; | ||
93 | |||
94 | static const unsigned int s6e63m0_19_280[] = { | ||
95 | 0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB, | ||
96 | 0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7, | ||
97 | 0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5 | ||
98 | }; | ||
99 | |||
100 | static const unsigned int s6e63m0_19_260[] = { | ||
101 | 0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA, | ||
102 | 0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8, | ||
103 | 0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF | ||
104 | }; | ||
105 | |||
106 | static const unsigned int s6e63m0_19_240[] = { | ||
107 | 0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB, | ||
108 | 0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9, | ||
109 | 0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8 | ||
110 | }; | ||
111 | |||
112 | static const unsigned int s6e63m0_19_220[] = { | ||
113 | 0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC, | ||
114 | 0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA, | ||
115 | 0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0 | ||
116 | }; | ||
117 | |||
118 | static const unsigned int s6e63m0_19_200[] = { | ||
119 | 0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE, | ||
120 | 0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB, | ||
121 | 0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8 | ||
122 | }; | ||
123 | |||
124 | static const unsigned int s6e63m0_19_170[] = { | ||
125 | 0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF, | ||
126 | 0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD, | ||
127 | 0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA | ||
128 | }; | ||
129 | |||
130 | static const unsigned int s6e63m0_19_140[] = { | ||
131 | 0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0, | ||
132 | 0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0, | ||
133 | 0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C | ||
134 | }; | ||
135 | |||
136 | static const unsigned int s6e63m0_19_110[] = { | ||
137 | 0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2, | ||
138 | 0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1, | ||
139 | 0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D | ||
140 | }; | ||
141 | |||
142 | static const unsigned int s6e63m0_19_90[] = { | ||
143 | 0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3, | ||
144 | 0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3, | ||
145 | 0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81 | ||
146 | }; | ||
147 | |||
148 | static const unsigned int s6e63m0_19_30[] = { | ||
149 | 0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA, | ||
150 | 0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA, | ||
151 | 0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E | ||
152 | }; | ||
153 | |||
154 | /* gamma value: 1.7 */ | ||
155 | static const unsigned int s6e63m0_17_300[] = { | ||
156 | 0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF, | ||
157 | 0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD, | ||
158 | 0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB | ||
159 | }; | ||
160 | |||
161 | static const unsigned int s6e63m0_17_280[] = { | ||
162 | 0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF, | ||
163 | 0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD, | ||
164 | 0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 | ||
165 | }; | ||
166 | |||
167 | static const unsigned int s6e63m0_17_260[] = { | ||
168 | 0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0, | ||
169 | 0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF, | ||
170 | 0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 | ||
171 | }; | ||
172 | |||
173 | static const unsigned int s6e63m0_17_240[] = { | ||
174 | 0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2, | ||
175 | 0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF, | ||
176 | 0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA | ||
177 | }; | ||
178 | |||
179 | static const unsigned int s6e63m0_17_220[] = { | ||
180 | 0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2, | ||
181 | 0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1, | ||
182 | 0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 | ||
183 | }; | ||
184 | |||
185 | static const unsigned int s6e63m0_17_200[] = { | ||
186 | 0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2, | ||
187 | 0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1, | ||
188 | 0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA | ||
189 | }; | ||
190 | |||
191 | static const unsigned int s6e63m0_17_170[] = { | ||
192 | 0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3, | ||
193 | 0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3, | ||
194 | 0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB | ||
195 | }; | ||
196 | |||
197 | static const unsigned int s6e63m0_17_140[] = { | ||
198 | 0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3, | ||
199 | 0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4, | ||
200 | 0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E | ||
201 | }; | ||
202 | |||
203 | static const unsigned int s6e63m0_17_110[] = { | ||
204 | 0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6, | ||
205 | 0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8, | ||
206 | 0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D | ||
207 | }; | ||
208 | |||
209 | static const unsigned int s6e63m0_17_90[] = { | ||
210 | 0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8, | ||
211 | 0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8, | ||
212 | 0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 | ||
213 | }; | ||
214 | |||
215 | static const unsigned int s6e63m0_17_30[] = { | ||
216 | 0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1, | ||
217 | 0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0, | ||
218 | 0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 | ||
219 | }; | ||
220 | |||
221 | struct s6e63m0_gamma { | ||
222 | unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; | ||
223 | unsigned int *gamma_19_table[MAX_GAMMA_LEVEL]; | ||
224 | unsigned int *gamma_17_table[MAX_GAMMA_LEVEL]; | ||
225 | }; | ||
226 | |||
227 | static struct s6e63m0_gamma gamma_table = { | ||
228 | .gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30, | ||
229 | .gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90, | ||
230 | .gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110, | ||
231 | .gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140, | ||
232 | .gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170, | ||
233 | .gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200, | ||
234 | .gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220, | ||
235 | .gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240, | ||
236 | .gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260, | ||
237 | .gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280, | ||
238 | .gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300, | ||
239 | |||
240 | .gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30, | ||
241 | .gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90, | ||
242 | .gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110, | ||
243 | .gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140, | ||
244 | .gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170, | ||
245 | .gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200, | ||
246 | .gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220, | ||
247 | .gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240, | ||
248 | .gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260, | ||
249 | .gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280, | ||
250 | .gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300, | ||
251 | |||
252 | .gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30, | ||
253 | .gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90, | ||
254 | .gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110, | ||
255 | .gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140, | ||
256 | .gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170, | ||
257 | .gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200, | ||
258 | .gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220, | ||
259 | .gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240, | ||
260 | .gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260, | ||
261 | .gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280, | ||
262 | .gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300, | ||
263 | }; | ||
264 | |||
265 | #endif | ||
266 | |||
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 23b2a8c0dbfc..b020ba7f1cf2 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c | |||
@@ -501,7 +501,9 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) | |||
501 | 501 | ||
502 | static int __devinit bfin_bf54x_probe(struct platform_device *pdev) | 502 | static int __devinit bfin_bf54x_probe(struct platform_device *pdev) |
503 | { | 503 | { |
504 | #ifndef NO_BL_SUPPORT | ||
504 | struct backlight_properties props; | 505 | struct backlight_properties props; |
506 | #endif | ||
505 | struct bfin_bf54xfb_info *info; | 507 | struct bfin_bf54xfb_info *info; |
506 | struct fb_info *fbinfo; | 508 | struct fb_info *fbinfo; |
507 | int ret; | 509 | int ret; |
@@ -654,7 +656,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) | |||
654 | printk(KERN_ERR DRIVER_NAME | 656 | printk(KERN_ERR DRIVER_NAME |
655 | ": unable to register backlight.\n"); | 657 | ": unable to register backlight.\n"); |
656 | ret = -EINVAL; | 658 | ret = -EINVAL; |
657 | goto out9; | 659 | unregister_framebuffer(fbinfo); |
660 | goto out8; | ||
658 | } | 661 | } |
659 | 662 | ||
660 | lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops); | 663 | lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops); |
@@ -663,8 +666,6 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) | |||
663 | 666 | ||
664 | return 0; | 667 | return 0; |
665 | 668 | ||
666 | out9: | ||
667 | unregister_framebuffer(fbinfo); | ||
668 | out8: | 669 | out8: |
669 | free_irq(info->irq, info); | 670 | free_irq(info->irq, info); |
670 | out7: | 671 | out7: |
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index 2baac7cc1425..c8e1f04941bd 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c | |||
@@ -61,47 +61,13 @@ | |||
61 | #define LCD_X_RES 320 /* Horizontal Resolution */ | 61 | #define LCD_X_RES 320 /* Horizontal Resolution */ |
62 | #define LCD_Y_RES 240 /* Vertical Resolution */ | 62 | #define LCD_Y_RES 240 /* Vertical Resolution */ |
63 | #define DMA_BUS_SIZE 16 | 63 | #define DMA_BUS_SIZE 16 |
64 | #define U_LINE 4 /* Blanking Lines */ | ||
64 | 65 | ||
65 | #define USE_RGB565_16_BIT_PPI | ||
66 | |||
67 | #ifdef USE_RGB565_16_BIT_PPI | ||
68 | #define LCD_BPP 16 /* Bit Per Pixel */ | ||
69 | #define CLOCKS_PER_PIX 1 | ||
70 | #define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ | ||
71 | #endif | ||
72 | 66 | ||
73 | /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) | 67 | /* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) |
74 | * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 | 68 | * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 |
75 | */ | 69 | */ |
76 | 70 | ||
77 | #ifdef USE_RGB565_8_BIT_PPI | ||
78 | #define LCD_BPP 16 /* Bit Per Pixel */ | ||
79 | #define CLOCKS_PER_PIX 2 | ||
80 | #define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ | ||
81 | #endif | ||
82 | |||
83 | #ifdef USE_RGB888_8_BIT_PPI | ||
84 | #define LCD_BPP 24 /* Bit Per Pixel */ | ||
85 | #define CLOCKS_PER_PIX 3 | ||
86 | #define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ | ||
87 | #endif | ||
88 | |||
89 | /* | ||
90 | * HS and VS timing parameters (all in number of PPI clk ticks) | ||
91 | */ | ||
92 | |||
93 | #define U_LINE 4 /* Blanking Lines */ | ||
94 | |||
95 | #define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ | ||
96 | #define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ | ||
97 | #define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ | ||
98 | #define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ | ||
99 | |||
100 | #define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ | ||
101 | #define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ | ||
102 | #define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ | ||
103 | |||
104 | #define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) | ||
105 | 71 | ||
106 | #define BFIN_LCD_NBR_PALETTE_ENTRIES 256 | 72 | #define BFIN_LCD_NBR_PALETTE_ENTRIES 256 |
107 | 73 | ||
@@ -110,12 +76,6 @@ | |||
110 | #define PPI_PORT_CFG_01 0x10 | 76 | #define PPI_PORT_CFG_01 0x10 |
111 | #define PPI_POLS_1 0x8000 | 77 | #define PPI_POLS_1 0x8000 |
112 | 78 | ||
113 | #if (CLOCKS_PER_PIX > 1) | ||
114 | #define PPI_PMODE (DLEN_8 | PACK_EN) | ||
115 | #else | ||
116 | #define PPI_PMODE (DLEN_16) | ||
117 | #endif | ||
118 | |||
119 | #define LQ035_INDEX 0x74 | 79 | #define LQ035_INDEX 0x74 |
120 | #define LQ035_DATA 0x76 | 80 | #define LQ035_DATA 0x76 |
121 | 81 | ||
@@ -139,6 +99,15 @@ struct bfin_lq035q1fb_info { | |||
139 | int irq; | 99 | int irq; |
140 | spinlock_t lock; /* lock */ | 100 | spinlock_t lock; /* lock */ |
141 | u32 pseudo_pal[16]; | 101 | u32 pseudo_pal[16]; |
102 | |||
103 | u32 lcd_bpp; | ||
104 | u32 h_actpix; | ||
105 | u32 h_period; | ||
106 | u32 h_pulse; | ||
107 | u32 h_start; | ||
108 | u32 v_lines; | ||
109 | u32 v_pulse; | ||
110 | u32 v_period; | ||
142 | }; | 111 | }; |
143 | 112 | ||
144 | static int nocursor; | 113 | static int nocursor; |
@@ -234,16 +203,69 @@ static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) | |||
234 | return 0; | 203 | return 0; |
235 | } | 204 | } |
236 | 205 | ||
206 | static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info *fbi) | ||
207 | { | ||
208 | unsigned long clocks_per_pix, cpld_pipeline_delay_cor; | ||
209 | |||
210 | /* | ||
211 | * Interface 16/18-bit TFT over an 8-bit wide PPI using a small | ||
212 | * Programmable Logic Device (CPLD) | ||
213 | * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 | ||
214 | */ | ||
215 | |||
216 | switch (fbi->disp_info->ppi_mode) { | ||
217 | case USE_RGB565_16_BIT_PPI: | ||
218 | fbi->lcd_bpp = 16; | ||
219 | clocks_per_pix = 1; | ||
220 | cpld_pipeline_delay_cor = 0; | ||
221 | break; | ||
222 | case USE_RGB565_8_BIT_PPI: | ||
223 | fbi->lcd_bpp = 16; | ||
224 | clocks_per_pix = 2; | ||
225 | cpld_pipeline_delay_cor = 3; | ||
226 | break; | ||
227 | case USE_RGB888_8_BIT_PPI: | ||
228 | fbi->lcd_bpp = 24; | ||
229 | clocks_per_pix = 3; | ||
230 | cpld_pipeline_delay_cor = 5; | ||
231 | break; | ||
232 | default: | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * HS and VS timing parameters (all in number of PPI clk ticks) | ||
238 | */ | ||
239 | |||
240 | fbi->h_actpix = (LCD_X_RES * clocks_per_pix); /* active horizontal pixel */ | ||
241 | fbi->h_period = (336 * clocks_per_pix); /* HS period */ | ||
242 | fbi->h_pulse = (2 * clocks_per_pix); /* HS pulse width */ | ||
243 | fbi->h_start = (7 * clocks_per_pix + cpld_pipeline_delay_cor); /* first valid pixel */ | ||
244 | |||
245 | fbi->v_lines = (LCD_Y_RES + U_LINE); /* total vertical lines */ | ||
246 | fbi->v_pulse = (2 * clocks_per_pix); /* VS pulse width (1-5 H_PERIODs) */ | ||
247 | fbi->v_period = (fbi->h_period * fbi->v_lines); /* VS period */ | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
237 | static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) | 252 | static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) |
238 | { | 253 | { |
239 | bfin_write_PPI_DELAY(H_START); | 254 | unsigned ppi_pmode; |
240 | bfin_write_PPI_COUNT(H_ACTPIX - 1); | 255 | |
241 | bfin_write_PPI_FRAME(V_LINES); | 256 | if (fbi->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI) |
257 | ppi_pmode = DLEN_16; | ||
258 | else | ||
259 | ppi_pmode = (DLEN_8 | PACK_EN); | ||
260 | |||
261 | bfin_write_PPI_DELAY(fbi->h_start); | ||
262 | bfin_write_PPI_COUNT(fbi->h_actpix - 1); | ||
263 | bfin_write_PPI_FRAME(fbi->v_lines); | ||
242 | 264 | ||
243 | bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ | 265 | bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ |
244 | PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ | 266 | PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ |
245 | PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ | 267 | PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ |
246 | PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ | 268 | ppi_pmode | /* 8/16 bit data length / PACK_EN? */ |
247 | PPI_POLS_1); /* faling edge syncs POLS */ | 269 | PPI_POLS_1); /* faling edge syncs POLS */ |
248 | } | 270 | } |
249 | 271 | ||
@@ -272,19 +294,19 @@ static void bfin_lq035q1_stop_timers(void) | |||
272 | 294 | ||
273 | } | 295 | } |
274 | 296 | ||
275 | static void bfin_lq035q1_init_timers(void) | 297 | static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info *fbi) |
276 | { | 298 | { |
277 | 299 | ||
278 | bfin_lq035q1_stop_timers(); | 300 | bfin_lq035q1_stop_timers(); |
279 | 301 | ||
280 | set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); | 302 | set_gptimer_period(TIMER_HSYNC_id, fbi->h_period); |
281 | set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); | 303 | set_gptimer_pwidth(TIMER_HSYNC_id, fbi->h_pulse); |
282 | set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | | 304 | set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | |
283 | TIMER_TIN_SEL | TIMER_CLK_SEL| | 305 | TIMER_TIN_SEL | TIMER_CLK_SEL| |
284 | TIMER_EMU_RUN); | 306 | TIMER_EMU_RUN); |
285 | 307 | ||
286 | set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); | 308 | set_gptimer_period(TIMER_VSYNC_id, fbi->v_period); |
287 | set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); | 309 | set_gptimer_pwidth(TIMER_VSYNC_id, fbi->v_pulse); |
288 | set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | | 310 | set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | |
289 | TIMER_TIN_SEL | TIMER_CLK_SEL | | 311 | TIMER_TIN_SEL | TIMER_CLK_SEL | |
290 | TIMER_EMU_RUN); | 312 | TIMER_EMU_RUN); |
@@ -294,21 +316,21 @@ static void bfin_lq035q1_init_timers(void) | |||
294 | static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) | 316 | static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) |
295 | { | 317 | { |
296 | 318 | ||
319 | |||
297 | set_dma_config(CH_PPI, | 320 | set_dma_config(CH_PPI, |
298 | set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, | 321 | set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, |
299 | INTR_DISABLE, DIMENSION_2D, | 322 | INTR_DISABLE, DIMENSION_2D, |
300 | DATA_SIZE_16, | 323 | DATA_SIZE_16, |
301 | DMA_NOSYNC_KEEP_DMA_BUF)); | 324 | DMA_NOSYNC_KEEP_DMA_BUF)); |
302 | set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); | 325 | set_dma_x_count(CH_PPI, (LCD_X_RES * fbi->lcd_bpp) / DMA_BUS_SIZE); |
303 | set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); | 326 | set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); |
304 | set_dma_y_count(CH_PPI, V_LINES); | 327 | set_dma_y_count(CH_PPI, fbi->v_lines); |
305 | 328 | ||
306 | set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); | 329 | set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); |
307 | set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); | 330 | set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); |
308 | 331 | ||
309 | } | 332 | } |
310 | 333 | ||
311 | #if (CLOCKS_PER_PIX == 1) | ||
312 | static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, | 334 | static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, |
313 | P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, | 335 | P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, |
314 | P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, | 336 | P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, |
@@ -316,22 +338,27 @@ static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, | |||
316 | P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, | 338 | P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, |
317 | P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, | 339 | P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, |
318 | P_PPI0_D15, 0}; | 340 | P_PPI0_D15, 0}; |
319 | #else | 341 | |
320 | static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, | 342 | static const u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, |
321 | P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, | 343 | P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, |
322 | P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, | 344 | P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, |
323 | P_PPI0_D6, P_PPI0_D7, 0}; | 345 | P_PPI0_D6, P_PPI0_D7, 0}; |
324 | #endif | ||
325 | 346 | ||
326 | static inline void bfin_lq035q1_free_ports(void) | 347 | static inline void bfin_lq035q1_free_ports(unsigned ppi16) |
327 | { | 348 | { |
328 | peripheral_free_list(ppi0_req_16); | 349 | if (ppi16) |
350 | peripheral_free_list(ppi0_req_16); | ||
351 | else | ||
352 | peripheral_free_list(ppi0_req_8); | ||
353 | |||
329 | if (ANOMALY_05000400) | 354 | if (ANOMALY_05000400) |
330 | gpio_free(P_IDENT(P_PPI0_FS3)); | 355 | gpio_free(P_IDENT(P_PPI0_FS3)); |
331 | } | 356 | } |
332 | 357 | ||
333 | static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) | 358 | static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev, |
359 | unsigned ppi16) | ||
334 | { | 360 | { |
361 | int ret; | ||
335 | /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: | 362 | /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: |
336 | * Drive PPI_FS3 Low | 363 | * Drive PPI_FS3 Low |
337 | */ | 364 | */ |
@@ -342,7 +369,12 @@ static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) | |||
342 | gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); | 369 | gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); |
343 | } | 370 | } |
344 | 371 | ||
345 | if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { | 372 | if (ppi16) |
373 | ret = peripheral_request_list(ppi0_req_16, DRIVER_NAME); | ||
374 | else | ||
375 | ret = peripheral_request_list(ppi0_req_8, DRIVER_NAME); | ||
376 | |||
377 | if (ret) { | ||
346 | dev_err(&pdev->dev, "requesting peripherals failed\n"); | 378 | dev_err(&pdev->dev, "requesting peripherals failed\n"); |
347 | return -EFAULT; | 379 | return -EFAULT; |
348 | } | 380 | } |
@@ -364,7 +396,7 @@ static int bfin_lq035q1_fb_open(struct fb_info *info, int user) | |||
364 | 396 | ||
365 | bfin_lq035q1_config_dma(fbi); | 397 | bfin_lq035q1_config_dma(fbi); |
366 | bfin_lq035q1_config_ppi(fbi); | 398 | bfin_lq035q1_config_ppi(fbi); |
367 | bfin_lq035q1_init_timers(); | 399 | bfin_lq035q1_init_timers(fbi); |
368 | 400 | ||
369 | /* start dma */ | 401 | /* start dma */ |
370 | enable_dma(CH_PPI); | 402 | enable_dma(CH_PPI); |
@@ -402,12 +434,9 @@ static int bfin_lq035q1_fb_release(struct fb_info *info, int user) | |||
402 | static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, | 434 | static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, |
403 | struct fb_info *info) | 435 | struct fb_info *info) |
404 | { | 436 | { |
405 | switch (var->bits_per_pixel) { | 437 | struct bfin_lq035q1fb_info *fbi = info->par; |
406 | #if (LCD_BPP == 24) | 438 | |
407 | case 24:/* TRUECOLOUR, 16m */ | 439 | if (var->bits_per_pixel == fbi->lcd_bpp) { |
408 | #else | ||
409 | case 16:/* DIRECTCOLOUR, 64k */ | ||
410 | #endif | ||
411 | var->red.offset = info->var.red.offset; | 440 | var->red.offset = info->var.red.offset; |
412 | var->green.offset = info->var.green.offset; | 441 | var->green.offset = info->var.green.offset; |
413 | var->blue.offset = info->var.blue.offset; | 442 | var->blue.offset = info->var.blue.offset; |
@@ -420,8 +449,7 @@ static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, | |||
420 | var->red.msb_right = 0; | 449 | var->red.msb_right = 0; |
421 | var->green.msb_right = 0; | 450 | var->green.msb_right = 0; |
422 | var->blue.msb_right = 0; | 451 | var->blue.msb_right = 0; |
423 | break; | 452 | } else { |
424 | default: | ||
425 | pr_debug("%s: depth not supported: %u BPP\n", __func__, | 453 | pr_debug("%s: depth not supported: %u BPP\n", __func__, |
426 | var->bits_per_pixel); | 454 | var->bits_per_pixel); |
427 | return -EINVAL; | 455 | return -EINVAL; |
@@ -528,6 +556,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
528 | { | 556 | { |
529 | struct bfin_lq035q1fb_info *info; | 557 | struct bfin_lq035q1fb_info *info; |
530 | struct fb_info *fbinfo; | 558 | struct fb_info *fbinfo; |
559 | u32 active_video_mem_offset; | ||
531 | int ret; | 560 | int ret; |
532 | 561 | ||
533 | ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); | 562 | ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); |
@@ -550,6 +579,12 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
550 | 579 | ||
551 | platform_set_drvdata(pdev, fbinfo); | 580 | platform_set_drvdata(pdev, fbinfo); |
552 | 581 | ||
582 | ret = bfin_lq035q1_calc_timing(info); | ||
583 | if (ret < 0) { | ||
584 | dev_err(&pdev->dev, "Failed PPI Mode\n"); | ||
585 | goto out3; | ||
586 | } | ||
587 | |||
553 | strcpy(fbinfo->fix.id, DRIVER_NAME); | 588 | strcpy(fbinfo->fix.id, DRIVER_NAME); |
554 | 589 | ||
555 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; | 590 | fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; |
@@ -571,46 +606,48 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
571 | fbinfo->var.xres_virtual = LCD_X_RES; | 606 | fbinfo->var.xres_virtual = LCD_X_RES; |
572 | fbinfo->var.yres = LCD_Y_RES; | 607 | fbinfo->var.yres = LCD_Y_RES; |
573 | fbinfo->var.yres_virtual = LCD_Y_RES; | 608 | fbinfo->var.yres_virtual = LCD_Y_RES; |
574 | fbinfo->var.bits_per_pixel = LCD_BPP; | 609 | fbinfo->var.bits_per_pixel = info->lcd_bpp; |
575 | 610 | ||
576 | if (info->disp_info->mode & LQ035_BGR) { | 611 | if (info->disp_info->mode & LQ035_BGR) { |
577 | #if (LCD_BPP == 24) | 612 | if (info->lcd_bpp == 24) { |
578 | fbinfo->var.red.offset = 0; | 613 | fbinfo->var.red.offset = 0; |
579 | fbinfo->var.green.offset = 8; | 614 | fbinfo->var.green.offset = 8; |
580 | fbinfo->var.blue.offset = 16; | 615 | fbinfo->var.blue.offset = 16; |
581 | #else | 616 | } else { |
582 | fbinfo->var.red.offset = 0; | 617 | fbinfo->var.red.offset = 0; |
583 | fbinfo->var.green.offset = 5; | 618 | fbinfo->var.green.offset = 5; |
584 | fbinfo->var.blue.offset = 11; | 619 | fbinfo->var.blue.offset = 11; |
585 | #endif | 620 | } |
586 | } else { | 621 | } else { |
587 | #if (LCD_BPP == 24) | 622 | if (info->lcd_bpp == 24) { |
588 | fbinfo->var.red.offset = 16; | 623 | fbinfo->var.red.offset = 16; |
589 | fbinfo->var.green.offset = 8; | 624 | fbinfo->var.green.offset = 8; |
590 | fbinfo->var.blue.offset = 0; | 625 | fbinfo->var.blue.offset = 0; |
591 | #else | 626 | } else { |
592 | fbinfo->var.red.offset = 11; | 627 | fbinfo->var.red.offset = 11; |
593 | fbinfo->var.green.offset = 5; | 628 | fbinfo->var.green.offset = 5; |
594 | fbinfo->var.blue.offset = 0; | 629 | fbinfo->var.blue.offset = 0; |
595 | #endif | 630 | } |
596 | } | 631 | } |
597 | 632 | ||
598 | fbinfo->var.transp.offset = 0; | 633 | fbinfo->var.transp.offset = 0; |
599 | 634 | ||
600 | #if (LCD_BPP == 24) | 635 | if (info->lcd_bpp == 24) { |
601 | fbinfo->var.red.length = 8; | 636 | fbinfo->var.red.length = 8; |
602 | fbinfo->var.green.length = 8; | 637 | fbinfo->var.green.length = 8; |
603 | fbinfo->var.blue.length = 8; | 638 | fbinfo->var.blue.length = 8; |
604 | #else | 639 | } else { |
605 | fbinfo->var.red.length = 5; | 640 | fbinfo->var.red.length = 5; |
606 | fbinfo->var.green.length = 6; | 641 | fbinfo->var.green.length = 6; |
607 | fbinfo->var.blue.length = 5; | 642 | fbinfo->var.blue.length = 5; |
608 | #endif | 643 | } |
609 | 644 | ||
610 | fbinfo->var.transp.length = 0; | 645 | fbinfo->var.transp.length = 0; |
611 | 646 | ||
612 | fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 | 647 | active_video_mem_offset = ((U_LINE / 2) * LCD_X_RES * (info->lcd_bpp / 8)); |
613 | + ACTIVE_VIDEO_MEM_OFFSET; | 648 | |
649 | fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * info->lcd_bpp / 8 | ||
650 | + active_video_mem_offset; | ||
614 | 651 | ||
615 | fbinfo->fix.line_length = fbinfo->var.xres_virtual * | 652 | fbinfo->fix.line_length = fbinfo->var.xres_virtual * |
616 | fbinfo->var.bits_per_pixel / 8; | 653 | fbinfo->var.bits_per_pixel / 8; |
@@ -629,8 +666,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
629 | goto out3; | 666 | goto out3; |
630 | } | 667 | } |
631 | 668 | ||
632 | fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; | 669 | fbinfo->screen_base = (void *)info->fb_buffer + active_video_mem_offset; |
633 | fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; | 670 | fbinfo->fix.smem_start = (int)info->fb_buffer + active_video_mem_offset; |
634 | 671 | ||
635 | fbinfo->fbops = &bfin_lq035q1_fb_ops; | 672 | fbinfo->fbops = &bfin_lq035q1_fb_ops; |
636 | 673 | ||
@@ -643,7 +680,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
643 | goto out4; | 680 | goto out4; |
644 | } | 681 | } |
645 | 682 | ||
646 | ret = bfin_lq035q1_request_ports(pdev); | 683 | ret = bfin_lq035q1_request_ports(pdev, |
684 | info->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI); | ||
647 | if (ret) { | 685 | if (ret) { |
648 | dev_err(&pdev->dev, "couldn't request gpio port\n"); | 686 | dev_err(&pdev->dev, "couldn't request gpio port\n"); |
649 | goto out6; | 687 | goto out6; |
@@ -693,7 +731,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
693 | } | 731 | } |
694 | 732 | ||
695 | dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", | 733 | dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", |
696 | LCD_X_RES, LCD_Y_RES, LCD_BPP); | 734 | LCD_X_RES, LCD_Y_RES, info->lcd_bpp); |
697 | 735 | ||
698 | return 0; | 736 | return 0; |
699 | 737 | ||
@@ -705,7 +743,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) | |||
705 | out8: | 743 | out8: |
706 | free_irq(info->irq, info); | 744 | free_irq(info->irq, info); |
707 | out7: | 745 | out7: |
708 | bfin_lq035q1_free_ports(); | 746 | bfin_lq035q1_free_ports(info->disp_info->ppi_mode == |
747 | USE_RGB565_16_BIT_PPI); | ||
709 | out6: | 748 | out6: |
710 | fb_dealloc_cmap(&fbinfo->cmap); | 749 | fb_dealloc_cmap(&fbinfo->cmap); |
711 | out4: | 750 | out4: |
@@ -742,7 +781,8 @@ static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) | |||
742 | 781 | ||
743 | fb_dealloc_cmap(&fbinfo->cmap); | 782 | fb_dealloc_cmap(&fbinfo->cmap); |
744 | 783 | ||
745 | bfin_lq035q1_free_ports(); | 784 | bfin_lq035q1_free_ports(info->disp_info->ppi_mode == |
785 | USE_RGB565_16_BIT_PPI); | ||
746 | 786 | ||
747 | platform_set_drvdata(pdev, NULL); | 787 | platform_set_drvdata(pdev, NULL); |
748 | framebuffer_release(fbinfo); | 788 | framebuffer_release(fbinfo); |
@@ -781,7 +821,7 @@ static int bfin_lq035q1_resume(struct device *dev) | |||
781 | 821 | ||
782 | bfin_lq035q1_config_dma(info); | 822 | bfin_lq035q1_config_dma(info); |
783 | bfin_lq035q1_config_ppi(info); | 823 | bfin_lq035q1_config_ppi(info); |
784 | bfin_lq035q1_init_timers(); | 824 | bfin_lq035q1_init_timers(info); |
785 | 825 | ||
786 | /* start dma */ | 826 | /* start dma */ |
787 | enable_dma(CH_PPI); | 827 | enable_dma(CH_PPI); |
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index c2ec3dcd4e91..7a50272eaab9 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c | |||
@@ -420,7 +420,9 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id) | |||
420 | 420 | ||
421 | static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) | 421 | static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) |
422 | { | 422 | { |
423 | #ifndef NO_BL_SUPPORT | ||
423 | struct backlight_properties props; | 424 | struct backlight_properties props; |
425 | #endif | ||
424 | struct bfin_t350mcqbfb_info *info; | 426 | struct bfin_t350mcqbfb_info *info; |
425 | struct fb_info *fbinfo; | 427 | struct fb_info *fbinfo; |
426 | int ret; | 428 | int ret; |
@@ -550,7 +552,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) | |||
550 | printk(KERN_ERR DRIVER_NAME | 552 | printk(KERN_ERR DRIVER_NAME |
551 | ": unable to register backlight.\n"); | 553 | ": unable to register backlight.\n"); |
552 | ret = -EINVAL; | 554 | ret = -EINVAL; |
553 | goto out9; | 555 | unregister_framebuffer(fbinfo); |
556 | goto out8; | ||
554 | } | 557 | } |
555 | 558 | ||
556 | lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); | 559 | lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops); |
@@ -559,8 +562,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) | |||
559 | 562 | ||
560 | return 0; | 563 | return 0; |
561 | 564 | ||
562 | out9: | ||
563 | unregister_framebuffer(fbinfo); | ||
564 | out8: | 565 | out8: |
565 | free_irq(info->irq, info); | 566 | free_irq(info->irq, info); |
566 | out7: | 567 | out7: |
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 8d244ba0f601..cad7d45c8bac 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c | |||
@@ -36,7 +36,9 @@ | |||
36 | #define DRIVER_NAME "da8xx_lcdc" | 36 | #define DRIVER_NAME "da8xx_lcdc" |
37 | 37 | ||
38 | /* LCD Status Register */ | 38 | /* LCD Status Register */ |
39 | #define LCD_END_OF_FRAME1 BIT(9) | ||
39 | #define LCD_END_OF_FRAME0 BIT(8) | 40 | #define LCD_END_OF_FRAME0 BIT(8) |
41 | #define LCD_PL_LOAD_DONE BIT(6) | ||
40 | #define LCD_FIFO_UNDERFLOW BIT(5) | 42 | #define LCD_FIFO_UNDERFLOW BIT(5) |
41 | #define LCD_SYNC_LOST BIT(2) | 43 | #define LCD_SYNC_LOST BIT(2) |
42 | 44 | ||
@@ -58,11 +60,13 @@ | |||
58 | #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) | 60 | #define LCD_PALETTE_LOAD_MODE(x) ((x) << 20) |
59 | #define PALETTE_AND_DATA 0x00 | 61 | #define PALETTE_AND_DATA 0x00 |
60 | #define PALETTE_ONLY 0x01 | 62 | #define PALETTE_ONLY 0x01 |
63 | #define DATA_ONLY 0x02 | ||
61 | 64 | ||
62 | #define LCD_MONO_8BIT_MODE BIT(9) | 65 | #define LCD_MONO_8BIT_MODE BIT(9) |
63 | #define LCD_RASTER_ORDER BIT(8) | 66 | #define LCD_RASTER_ORDER BIT(8) |
64 | #define LCD_TFT_MODE BIT(7) | 67 | #define LCD_TFT_MODE BIT(7) |
65 | #define LCD_UNDERFLOW_INT_ENA BIT(6) | 68 | #define LCD_UNDERFLOW_INT_ENA BIT(6) |
69 | #define LCD_PL_ENABLE BIT(4) | ||
66 | #define LCD_MONOCHROME_MODE BIT(1) | 70 | #define LCD_MONOCHROME_MODE BIT(1) |
67 | #define LCD_RASTER_ENABLE BIT(0) | 71 | #define LCD_RASTER_ENABLE BIT(0) |
68 | #define LCD_TFT_ALT_ENABLE BIT(23) | 72 | #define LCD_TFT_ALT_ENABLE BIT(23) |
@@ -87,6 +91,10 @@ | |||
87 | #define LCD_DMA_CTRL_REG 0x40 | 91 | #define LCD_DMA_CTRL_REG 0x40 |
88 | #define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 | 92 | #define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44 |
89 | #define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 | 93 | #define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48 |
94 | #define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C | ||
95 | #define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 | ||
96 | |||
97 | #define LCD_NUM_BUFFERS 2 | ||
90 | 98 | ||
91 | #define WSI_TIMEOUT 50 | 99 | #define WSI_TIMEOUT 50 |
92 | #define PALETTE_SIZE 256 | 100 | #define PALETTE_SIZE 256 |
@@ -111,13 +119,20 @@ static inline void lcdc_write(unsigned int val, unsigned int addr) | |||
111 | struct da8xx_fb_par { | 119 | struct da8xx_fb_par { |
112 | resource_size_t p_palette_base; | 120 | resource_size_t p_palette_base; |
113 | unsigned char *v_palette_base; | 121 | unsigned char *v_palette_base; |
122 | dma_addr_t vram_phys; | ||
123 | unsigned long vram_size; | ||
124 | void *vram_virt; | ||
125 | unsigned int dma_start; | ||
126 | unsigned int dma_end; | ||
114 | struct clk *lcdc_clk; | 127 | struct clk *lcdc_clk; |
115 | int irq; | 128 | int irq; |
116 | unsigned short pseudo_palette[16]; | 129 | unsigned short pseudo_palette[16]; |
117 | unsigned int databuf_sz; | ||
118 | unsigned int palette_sz; | 130 | unsigned int palette_sz; |
119 | unsigned int pxl_clk; | 131 | unsigned int pxl_clk; |
120 | int blank; | 132 | int blank; |
133 | wait_queue_head_t vsync_wait; | ||
134 | int vsync_flag; | ||
135 | int vsync_timeout; | ||
121 | #ifdef CONFIG_CPU_FREQ | 136 | #ifdef CONFIG_CPU_FREQ |
122 | struct notifier_block freq_transition; | 137 | struct notifier_block freq_transition; |
123 | #endif | 138 | #endif |
@@ -148,9 +163,9 @@ static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = { | |||
148 | .type = FB_TYPE_PACKED_PIXELS, | 163 | .type = FB_TYPE_PACKED_PIXELS, |
149 | .type_aux = 0, | 164 | .type_aux = 0, |
150 | .visual = FB_VISUAL_PSEUDOCOLOR, | 165 | .visual = FB_VISUAL_PSEUDOCOLOR, |
151 | .xpanstep = 1, | 166 | .xpanstep = 0, |
152 | .ypanstep = 1, | 167 | .ypanstep = 1, |
153 | .ywrapstep = 1, | 168 | .ywrapstep = 0, |
154 | .accel = FB_ACCEL_NONE | 169 | .accel = FB_ACCEL_NONE |
155 | }; | 170 | }; |
156 | 171 | ||
@@ -221,22 +236,48 @@ static inline void lcd_disable_raster(void) | |||
221 | 236 | ||
222 | static void lcd_blit(int load_mode, struct da8xx_fb_par *par) | 237 | static void lcd_blit(int load_mode, struct da8xx_fb_par *par) |
223 | { | 238 | { |
224 | u32 tmp = par->p_palette_base + par->databuf_sz - 4; | 239 | u32 start; |
225 | u32 reg; | 240 | u32 end; |
241 | u32 reg_ras; | ||
242 | u32 reg_dma; | ||
243 | |||
244 | /* init reg to clear PLM (loading mode) fields */ | ||
245 | reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); | ||
246 | reg_ras &= ~(3 << 20); | ||
247 | |||
248 | reg_dma = lcdc_read(LCD_DMA_CTRL_REG); | ||
249 | |||
250 | if (load_mode == LOAD_DATA) { | ||
251 | start = par->dma_start; | ||
252 | end = par->dma_end; | ||
253 | |||
254 | reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); | ||
255 | reg_dma |= LCD_END_OF_FRAME_INT_ENA; | ||
256 | reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; | ||
257 | |||
258 | lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
259 | lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
260 | lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
261 | lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
262 | } else if (load_mode == LOAD_PALETTE) { | ||
263 | start = par->p_palette_base; | ||
264 | end = start + par->palette_sz - 1; | ||
265 | |||
266 | reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); | ||
267 | reg_ras |= LCD_PL_ENABLE; | ||
268 | |||
269 | lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
270 | lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
271 | } | ||
226 | 272 | ||
227 | /* Update the databuf in the hw. */ | 273 | lcdc_write(reg_dma, LCD_DMA_CTRL_REG); |
228 | lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | 274 | lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); |
229 | lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
230 | 275 | ||
231 | /* Start the DMA. */ | 276 | /* |
232 | reg = lcdc_read(LCD_RASTER_CTRL_REG); | 277 | * The Raster enable bit must be set after all other control fields are |
233 | reg &= ~(3 << 20); | 278 | * set. |
234 | if (load_mode == LOAD_DATA) | 279 | */ |
235 | reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA); | 280 | lcd_enable_raster(); |
236 | else if (load_mode == LOAD_PALETTE) | ||
237 | reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); | ||
238 | |||
239 | lcdc_write(reg, LCD_RASTER_CTRL_REG); | ||
240 | } | 281 | } |
241 | 282 | ||
242 | /* Configure the Burst Size of DMA */ | 283 | /* Configure the Burst Size of DMA */ |
@@ -368,12 +409,8 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) | |||
368 | static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, | 409 | static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, |
369 | u32 bpp, u32 raster_order) | 410 | u32 bpp, u32 raster_order) |
370 | { | 411 | { |
371 | u32 bpl, reg; | 412 | u32 reg; |
372 | 413 | ||
373 | /* Disable Dual Frame Buffer. */ | ||
374 | reg = lcdc_read(LCD_DMA_CTRL_REG); | ||
375 | lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE, | ||
376 | LCD_DMA_CTRL_REG); | ||
377 | /* Set the Panel Width */ | 414 | /* Set the Panel Width */ |
378 | /* Pixels per line = (PPL + 1)*16 */ | 415 | /* Pixels per line = (PPL + 1)*16 */ |
379 | /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ | 416 | /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/ |
@@ -410,9 +447,6 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, | |||
410 | return -EINVAL; | 447 | return -EINVAL; |
411 | } | 448 | } |
412 | 449 | ||
413 | bpl = width * bpp / 8; | ||
414 | par->databuf_sz = height * bpl + par->palette_sz; | ||
415 | |||
416 | return 0; | 450 | return 0; |
417 | } | 451 | } |
418 | 452 | ||
@@ -421,8 +455,9 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
421 | struct fb_info *info) | 455 | struct fb_info *info) |
422 | { | 456 | { |
423 | struct da8xx_fb_par *par = info->par; | 457 | struct da8xx_fb_par *par = info->par; |
424 | unsigned short *palette = (unsigned short *)par->v_palette_base; | 458 | unsigned short *palette = (unsigned short *) par->v_palette_base; |
425 | u_short pal; | 459 | u_short pal; |
460 | int update_hw = 0; | ||
426 | 461 | ||
427 | if (regno > 255) | 462 | if (regno > 255) |
428 | return 1; | 463 | return 1; |
@@ -439,8 +474,10 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
439 | pal |= (green & 0x00f0); | 474 | pal |= (green & 0x00f0); |
440 | pal |= (blue & 0x000f); | 475 | pal |= (blue & 0x000f); |
441 | 476 | ||
442 | palette[regno] = pal; | 477 | if (palette[regno] != pal) { |
443 | 478 | update_hw = 1; | |
479 | palette[regno] = pal; | ||
480 | } | ||
444 | } else if ((info->var.bits_per_pixel == 16) && regno < 16) { | 481 | } else if ((info->var.bits_per_pixel == 16) && regno < 16) { |
445 | red >>= (16 - info->var.red.length); | 482 | red >>= (16 - info->var.red.length); |
446 | red <<= info->var.red.offset; | 483 | red <<= info->var.red.offset; |
@@ -453,9 +490,16 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
453 | 490 | ||
454 | par->pseudo_palette[regno] = red | green | blue; | 491 | par->pseudo_palette[regno] = red | green | blue; |
455 | 492 | ||
456 | palette[0] = 0x4000; | 493 | if (palette[0] != 0x4000) { |
494 | update_hw = 1; | ||
495 | palette[0] = 0x4000; | ||
496 | } | ||
457 | } | 497 | } |
458 | 498 | ||
499 | /* Update the palette in the h/w as needed. */ | ||
500 | if (update_hw) | ||
501 | lcd_blit(LOAD_PALETTE, par); | ||
502 | |||
459 | return 0; | 503 | return 0; |
460 | } | 504 | } |
461 | 505 | ||
@@ -541,15 +585,54 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | |||
541 | 585 | ||
542 | static irqreturn_t lcdc_irq_handler(int irq, void *arg) | 586 | static irqreturn_t lcdc_irq_handler(int irq, void *arg) |
543 | { | 587 | { |
588 | struct da8xx_fb_par *par = arg; | ||
544 | u32 stat = lcdc_read(LCD_STAT_REG); | 589 | u32 stat = lcdc_read(LCD_STAT_REG); |
590 | u32 reg_ras; | ||
545 | 591 | ||
546 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | 592 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { |
547 | lcd_disable_raster(); | 593 | lcd_disable_raster(); |
548 | lcdc_write(stat, LCD_STAT_REG); | 594 | lcdc_write(stat, LCD_STAT_REG); |
549 | lcd_enable_raster(); | 595 | lcd_enable_raster(); |
550 | } else | 596 | } else if (stat & LCD_PL_LOAD_DONE) { |
597 | /* | ||
598 | * Must disable raster before changing state of any control bit. | ||
599 | * And also must be disabled before clearing the PL loading | ||
600 | * interrupt via the following write to the status register. If | ||
601 | * this is done after then one gets multiple PL done interrupts. | ||
602 | */ | ||
603 | lcd_disable_raster(); | ||
604 | |||
551 | lcdc_write(stat, LCD_STAT_REG); | 605 | lcdc_write(stat, LCD_STAT_REG); |
552 | 606 | ||
607 | /* Disable PL completion inerrupt */ | ||
608 | reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); | ||
609 | reg_ras &= ~LCD_PL_ENABLE; | ||
610 | lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); | ||
611 | |||
612 | /* Setup and start data loading mode */ | ||
613 | lcd_blit(LOAD_DATA, par); | ||
614 | } else { | ||
615 | lcdc_write(stat, LCD_STAT_REG); | ||
616 | |||
617 | if (stat & LCD_END_OF_FRAME0) { | ||
618 | lcdc_write(par->dma_start, | ||
619 | LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
620 | lcdc_write(par->dma_end, | ||
621 | LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
622 | par->vsync_flag = 1; | ||
623 | wake_up_interruptible(&par->vsync_wait); | ||
624 | } | ||
625 | |||
626 | if (stat & LCD_END_OF_FRAME1) { | ||
627 | lcdc_write(par->dma_start, | ||
628 | LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
629 | lcdc_write(par->dma_end, | ||
630 | LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
631 | par->vsync_flag = 1; | ||
632 | wake_up_interruptible(&par->vsync_wait); | ||
633 | } | ||
634 | } | ||
635 | |||
553 | return IRQ_HANDLED; | 636 | return IRQ_HANDLED; |
554 | } | 637 | } |
555 | 638 | ||
@@ -654,9 +737,10 @@ static int __devexit fb_remove(struct platform_device *dev) | |||
654 | 737 | ||
655 | unregister_framebuffer(info); | 738 | unregister_framebuffer(info); |
656 | fb_dealloc_cmap(&info->cmap); | 739 | fb_dealloc_cmap(&info->cmap); |
657 | dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, | 740 | dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, |
658 | info->screen_base - PAGE_SIZE, | 741 | par->p_palette_base); |
659 | info->fix.smem_start); | 742 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, |
743 | par->vram_phys); | ||
660 | free_irq(par->irq, par); | 744 | free_irq(par->irq, par); |
661 | clk_disable(par->lcdc_clk); | 745 | clk_disable(par->lcdc_clk); |
662 | clk_put(par->lcdc_clk); | 746 | clk_put(par->lcdc_clk); |
@@ -668,6 +752,39 @@ static int __devexit fb_remove(struct platform_device *dev) | |||
668 | return 0; | 752 | return 0; |
669 | } | 753 | } |
670 | 754 | ||
755 | /* | ||
756 | * Function to wait for vertical sync which for this LCD peripheral | ||
757 | * translates into waiting for the current raster frame to complete. | ||
758 | */ | ||
759 | static int fb_wait_for_vsync(struct fb_info *info) | ||
760 | { | ||
761 | struct da8xx_fb_par *par = info->par; | ||
762 | int ret; | ||
763 | |||
764 | /* | ||
765 | * Set flag to 0 and wait for isr to set to 1. It would seem there is a | ||
766 | * race condition here where the ISR could have occured just before or | ||
767 | * just after this set. But since we are just coarsely waiting for | ||
768 | * a frame to complete then that's OK. i.e. if the frame completed | ||
769 | * just before this code executed then we have to wait another full | ||
770 | * frame time but there is no way to avoid such a situation. On the | ||
771 | * other hand if the frame completed just after then we don't need | ||
772 | * to wait long at all. Either way we are guaranteed to return to the | ||
773 | * user immediately after a frame completion which is all that is | ||
774 | * required. | ||
775 | */ | ||
776 | par->vsync_flag = 0; | ||
777 | ret = wait_event_interruptible_timeout(par->vsync_wait, | ||
778 | par->vsync_flag != 0, | ||
779 | par->vsync_timeout); | ||
780 | if (ret < 0) | ||
781 | return ret; | ||
782 | if (ret == 0) | ||
783 | return -ETIMEDOUT; | ||
784 | |||
785 | return 0; | ||
786 | } | ||
787 | |||
671 | static int fb_ioctl(struct fb_info *info, unsigned int cmd, | 788 | static int fb_ioctl(struct fb_info *info, unsigned int cmd, |
672 | unsigned long arg) | 789 | unsigned long arg) |
673 | { | 790 | { |
@@ -697,6 +814,8 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
697 | sync_arg.pulse_width, | 814 | sync_arg.pulse_width, |
698 | sync_arg.front_porch); | 815 | sync_arg.front_porch); |
699 | break; | 816 | break; |
817 | case FBIO_WAITFORVSYNC: | ||
818 | return fb_wait_for_vsync(info); | ||
700 | default: | 819 | default: |
701 | return -EINVAL; | 820 | return -EINVAL; |
702 | } | 821 | } |
@@ -732,10 +851,47 @@ static int cfb_blank(int blank, struct fb_info *info) | |||
732 | return ret; | 851 | return ret; |
733 | } | 852 | } |
734 | 853 | ||
854 | /* | ||
855 | * Set new x,y offsets in the virtual display for the visible area and switch | ||
856 | * to the new mode. | ||
857 | */ | ||
858 | static int da8xx_pan_display(struct fb_var_screeninfo *var, | ||
859 | struct fb_info *fbi) | ||
860 | { | ||
861 | int ret = 0; | ||
862 | struct fb_var_screeninfo new_var; | ||
863 | struct da8xx_fb_par *par = fbi->par; | ||
864 | struct fb_fix_screeninfo *fix = &fbi->fix; | ||
865 | unsigned int end; | ||
866 | unsigned int start; | ||
867 | |||
868 | if (var->xoffset != fbi->var.xoffset || | ||
869 | var->yoffset != fbi->var.yoffset) { | ||
870 | memcpy(&new_var, &fbi->var, sizeof(new_var)); | ||
871 | new_var.xoffset = var->xoffset; | ||
872 | new_var.yoffset = var->yoffset; | ||
873 | if (fb_check_var(&new_var, fbi)) | ||
874 | ret = -EINVAL; | ||
875 | else { | ||
876 | memcpy(&fbi->var, &new_var, sizeof(new_var)); | ||
877 | |||
878 | start = fix->smem_start + | ||
879 | new_var.yoffset * fix->line_length + | ||
880 | new_var.xoffset * var->bits_per_pixel / 8; | ||
881 | end = start + var->yres * fix->line_length - 1; | ||
882 | par->dma_start = start; | ||
883 | par->dma_end = end; | ||
884 | } | ||
885 | } | ||
886 | |||
887 | return ret; | ||
888 | } | ||
889 | |||
735 | static struct fb_ops da8xx_fb_ops = { | 890 | static struct fb_ops da8xx_fb_ops = { |
736 | .owner = THIS_MODULE, | 891 | .owner = THIS_MODULE, |
737 | .fb_check_var = fb_check_var, | 892 | .fb_check_var = fb_check_var, |
738 | .fb_setcolreg = fb_setcolreg, | 893 | .fb_setcolreg = fb_setcolreg, |
894 | .fb_pan_display = da8xx_pan_display, | ||
739 | .fb_ioctl = fb_ioctl, | 895 | .fb_ioctl = fb_ioctl, |
740 | .fb_fillrect = cfb_fillrect, | 896 | .fb_fillrect = cfb_fillrect, |
741 | .fb_copyarea = cfb_copyarea, | 897 | .fb_copyarea = cfb_copyarea, |
@@ -829,40 +985,53 @@ static int __init fb_probe(struct platform_device *device) | |||
829 | } | 985 | } |
830 | 986 | ||
831 | /* allocate frame buffer */ | 987 | /* allocate frame buffer */ |
832 | da8xx_fb_info->screen_base = dma_alloc_coherent(NULL, | 988 | par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp; |
833 | par->databuf_sz + PAGE_SIZE, | 989 | par->vram_size = PAGE_ALIGN(par->vram_size/8); |
834 | (resource_size_t *) | 990 | par->vram_size = par->vram_size * LCD_NUM_BUFFERS; |
835 | &da8xx_fb_info->fix.smem_start, | 991 | |
836 | GFP_KERNEL | GFP_DMA); | 992 | par->vram_virt = dma_alloc_coherent(NULL, |
837 | 993 | par->vram_size, | |
838 | if (!da8xx_fb_info->screen_base) { | 994 | (resource_size_t *) &par->vram_phys, |
995 | GFP_KERNEL | GFP_DMA); | ||
996 | if (!par->vram_virt) { | ||
839 | dev_err(&device->dev, | 997 | dev_err(&device->dev, |
840 | "GLCD: kmalloc for frame buffer failed\n"); | 998 | "GLCD: kmalloc for frame buffer failed\n"); |
841 | ret = -EINVAL; | 999 | ret = -EINVAL; |
842 | goto err_release_fb; | 1000 | goto err_release_fb; |
843 | } | 1001 | } |
844 | 1002 | ||
845 | /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */ | 1003 | da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt; |
846 | par->v_palette_base = da8xx_fb_info->screen_base + | 1004 | da8xx_fb_fix.smem_start = par->vram_phys; |
847 | (PAGE_SIZE - par->palette_sz); | 1005 | da8xx_fb_fix.smem_len = par->vram_size; |
848 | par->p_palette_base = da8xx_fb_info->fix.smem_start + | 1006 | da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; |
849 | (PAGE_SIZE - par->palette_sz); | 1007 | |
850 | 1008 | par->dma_start = par->vram_phys; | |
851 | /* the rest of the frame buffer is pixel data */ | 1009 | par->dma_end = par->dma_start + lcdc_info->height * |
852 | da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz; | 1010 | da8xx_fb_fix.line_length - 1; |
853 | da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz; | 1011 | |
854 | da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; | 1012 | /* allocate palette buffer */ |
855 | da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; | 1013 | par->v_palette_base = dma_alloc_coherent(NULL, |
1014 | PALETTE_SIZE, | ||
1015 | (resource_size_t *) | ||
1016 | &par->p_palette_base, | ||
1017 | GFP_KERNEL | GFP_DMA); | ||
1018 | if (!par->v_palette_base) { | ||
1019 | dev_err(&device->dev, | ||
1020 | "GLCD: kmalloc for palette buffer failed\n"); | ||
1021 | ret = -EINVAL; | ||
1022 | goto err_release_fb_mem; | ||
1023 | } | ||
1024 | memset(par->v_palette_base, 0, PALETTE_SIZE); | ||
856 | 1025 | ||
857 | par->irq = platform_get_irq(device, 0); | 1026 | par->irq = platform_get_irq(device, 0); |
858 | if (par->irq < 0) { | 1027 | if (par->irq < 0) { |
859 | ret = -ENOENT; | 1028 | ret = -ENOENT; |
860 | goto err_release_fb_mem; | 1029 | goto err_release_pl_mem; |
861 | } | 1030 | } |
862 | 1031 | ||
863 | ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); | 1032 | ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); |
864 | if (ret) | 1033 | if (ret) |
865 | goto err_release_fb_mem; | 1034 | goto err_release_pl_mem; |
866 | 1035 | ||
867 | /* Initialize par */ | 1036 | /* Initialize par */ |
868 | da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; | 1037 | da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; |
@@ -870,8 +1039,8 @@ static int __init fb_probe(struct platform_device *device) | |||
870 | da8xx_fb_var.xres = lcdc_info->width; | 1039 | da8xx_fb_var.xres = lcdc_info->width; |
871 | da8xx_fb_var.xres_virtual = lcdc_info->width; | 1040 | da8xx_fb_var.xres_virtual = lcdc_info->width; |
872 | 1041 | ||
873 | da8xx_fb_var.yres = lcdc_info->height; | 1042 | da8xx_fb_var.yres = lcdc_info->height; |
874 | da8xx_fb_var.yres_virtual = lcdc_info->height; | 1043 | da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS; |
875 | 1044 | ||
876 | da8xx_fb_var.grayscale = | 1045 | da8xx_fb_var.grayscale = |
877 | lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; | 1046 | lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; |
@@ -892,18 +1061,18 @@ static int __init fb_probe(struct platform_device *device) | |||
892 | ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); | 1061 | ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); |
893 | if (ret) | 1062 | if (ret) |
894 | goto err_free_irq; | 1063 | goto err_free_irq; |
895 | |||
896 | /* First palette_sz byte of the frame buffer is the palette */ | ||
897 | da8xx_fb_info->cmap.len = par->palette_sz; | 1064 | da8xx_fb_info->cmap.len = par->palette_sz; |
898 | 1065 | ||
899 | /* Flush the buffer to the screen. */ | ||
900 | lcd_blit(LOAD_DATA, par); | ||
901 | |||
902 | /* initialize var_screeninfo */ | 1066 | /* initialize var_screeninfo */ |
903 | da8xx_fb_var.activate = FB_ACTIVATE_FORCE; | 1067 | da8xx_fb_var.activate = FB_ACTIVATE_FORCE; |
904 | fb_set_var(da8xx_fb_info, &da8xx_fb_var); | 1068 | fb_set_var(da8xx_fb_info, &da8xx_fb_var); |
905 | 1069 | ||
906 | dev_set_drvdata(&device->dev, da8xx_fb_info); | 1070 | dev_set_drvdata(&device->dev, da8xx_fb_info); |
1071 | |||
1072 | /* initialize the vsync wait queue */ | ||
1073 | init_waitqueue_head(&par->vsync_wait); | ||
1074 | par->vsync_timeout = HZ / 5; | ||
1075 | |||
907 | /* Register the Frame Buffer */ | 1076 | /* Register the Frame Buffer */ |
908 | if (register_framebuffer(da8xx_fb_info) < 0) { | 1077 | if (register_framebuffer(da8xx_fb_info) < 0) { |
909 | dev_err(&device->dev, | 1078 | dev_err(&device->dev, |
@@ -919,10 +1088,6 @@ static int __init fb_probe(struct platform_device *device) | |||
919 | goto err_cpu_freq; | 1088 | goto err_cpu_freq; |
920 | } | 1089 | } |
921 | #endif | 1090 | #endif |
922 | |||
923 | /* enable raster engine */ | ||
924 | lcd_enable_raster(); | ||
925 | |||
926 | return 0; | 1091 | return 0; |
927 | 1092 | ||
928 | #ifdef CONFIG_CPU_FREQ | 1093 | #ifdef CONFIG_CPU_FREQ |
@@ -936,10 +1101,12 @@ err_dealloc_cmap: | |||
936 | err_free_irq: | 1101 | err_free_irq: |
937 | free_irq(par->irq, par); | 1102 | free_irq(par->irq, par); |
938 | 1103 | ||
1104 | err_release_pl_mem: | ||
1105 | dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base, | ||
1106 | par->p_palette_base); | ||
1107 | |||
939 | err_release_fb_mem: | 1108 | err_release_fb_mem: |
940 | dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, | 1109 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys); |
941 | da8xx_fb_info->screen_base - PAGE_SIZE, | ||
942 | da8xx_fb_info->fix.smem_start); | ||
943 | 1110 | ||
944 | err_release_fb: | 1111 | err_release_fb: |
945 | framebuffer_release(da8xx_fb_info); | 1112 | framebuffer_release(da8xx_fb_info); |
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 6113c47e095a..073c9b408cf7 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c | |||
@@ -66,7 +66,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma, | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync) | 69 | int fb_deferred_io_fsync(struct file *file, int datasync) |
70 | { | 70 | { |
71 | struct fb_info *info = file->private_data; | 71 | struct fb_info *info = file->private_data; |
72 | 72 | ||
@@ -155,25 +155,41 @@ static void fb_deferred_io_work(struct work_struct *work) | |||
155 | { | 155 | { |
156 | struct fb_info *info = container_of(work, struct fb_info, | 156 | struct fb_info *info = container_of(work, struct fb_info, |
157 | deferred_work.work); | 157 | deferred_work.work); |
158 | struct list_head *node, *next; | ||
159 | struct page *cur; | ||
160 | struct fb_deferred_io *fbdefio = info->fbdefio; | 158 | struct fb_deferred_io *fbdefio = info->fbdefio; |
159 | struct page *page, *tmp_page; | ||
160 | struct list_head *node, *tmp_node; | ||
161 | struct list_head non_dirty; | ||
162 | |||
163 | INIT_LIST_HEAD(&non_dirty); | ||
161 | 164 | ||
162 | /* here we mkclean the pages, then do all deferred IO */ | 165 | /* here we mkclean the pages, then do all deferred IO */ |
163 | mutex_lock(&fbdefio->lock); | 166 | mutex_lock(&fbdefio->lock); |
164 | list_for_each_entry(cur, &fbdefio->pagelist, lru) { | 167 | list_for_each_entry_safe(page, tmp_page, &fbdefio->pagelist, lru) { |
165 | lock_page(cur); | 168 | lock_page(page); |
166 | page_mkclean(cur); | 169 | /* |
167 | unlock_page(cur); | 170 | * The workqueue callback can be triggered after a |
171 | * ->page_mkwrite() call but before the PTE has been marked | ||
172 | * dirty. In this case page_mkclean() won't "rearm" the page. | ||
173 | * | ||
174 | * To avoid this, remove those "non-dirty" pages from the | ||
175 | * pagelist before calling the driver's callback, then add | ||
176 | * them back to get processed on the next work iteration. | ||
177 | * At that time, their PTEs will hopefully be dirty for real. | ||
178 | */ | ||
179 | if (!page_mkclean(page)) | ||
180 | list_move_tail(&page->lru, &non_dirty); | ||
181 | unlock_page(page); | ||
168 | } | 182 | } |
169 | 183 | ||
170 | /* driver's callback with pagelist */ | 184 | /* driver's callback with pagelist */ |
171 | fbdefio->deferred_io(info, &fbdefio->pagelist); | 185 | fbdefio->deferred_io(info, &fbdefio->pagelist); |
172 | 186 | ||
173 | /* clear the list */ | 187 | /* clear the list... */ |
174 | list_for_each_safe(node, next, &fbdefio->pagelist) { | 188 | list_for_each_safe(node, tmp_node, &fbdefio->pagelist) { |
175 | list_del(node); | 189 | list_del(node); |
176 | } | 190 | } |
191 | /* ... and add back the "non-dirty" pages to the list */ | ||
192 | list_splice_tail(&non_dirty, &fbdefio->pagelist); | ||
177 | mutex_unlock(&fbdefio->lock); | 193 | mutex_unlock(&fbdefio->lock); |
178 | } | 194 | } |
179 | 195 | ||
@@ -202,6 +218,7 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_open); | |||
202 | void fb_deferred_io_cleanup(struct fb_info *info) | 218 | void fb_deferred_io_cleanup(struct fb_info *info) |
203 | { | 219 | { |
204 | struct fb_deferred_io *fbdefio = info->fbdefio; | 220 | struct fb_deferred_io *fbdefio = info->fbdefio; |
221 | struct list_head *node, *tmp_node; | ||
205 | struct page *page; | 222 | struct page *page; |
206 | int i; | 223 | int i; |
207 | 224 | ||
@@ -209,6 +226,13 @@ void fb_deferred_io_cleanup(struct fb_info *info) | |||
209 | cancel_delayed_work(&info->deferred_work); | 226 | cancel_delayed_work(&info->deferred_work); |
210 | flush_scheduled_work(); | 227 | flush_scheduled_work(); |
211 | 228 | ||
229 | /* the list may have still some non-dirty pages at this point */ | ||
230 | mutex_lock(&fbdefio->lock); | ||
231 | list_for_each_safe(node, tmp_node, &fbdefio->pagelist) { | ||
232 | list_del(node); | ||
233 | } | ||
234 | mutex_unlock(&fbdefio->lock); | ||
235 | |||
212 | /* clear out the mapping that we setup */ | 236 | /* clear out the mapping that we setup */ |
213 | for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { | 237 | for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { |
214 | page = fb_deferred_io_page(info, i); | 238 | page = fb_deferred_io_page(info, i); |
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 8bbf251f83d9..af8f0f2cc782 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c | |||
@@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(hga_reg_lock); | |||
106 | 106 | ||
107 | /* Framebuffer driver structures */ | 107 | /* Framebuffer driver structures */ |
108 | 108 | ||
109 | static struct fb_var_screeninfo __initdata hga_default_var = { | 109 | static struct fb_var_screeninfo hga_default_var __devinitdata = { |
110 | .xres = 720, | 110 | .xres = 720, |
111 | .yres = 348, | 111 | .yres = 348, |
112 | .xres_virtual = 720, | 112 | .xres_virtual = 720, |
@@ -120,7 +120,7 @@ static struct fb_var_screeninfo __initdata hga_default_var = { | |||
120 | .width = -1, | 120 | .width = -1, |
121 | }; | 121 | }; |
122 | 122 | ||
123 | static struct fb_fix_screeninfo __initdata hga_fix = { | 123 | static struct fb_fix_screeninfo hga_fix __devinitdata = { |
124 | .id = "HGA", | 124 | .id = "HGA", |
125 | .type = FB_TYPE_PACKED_PIXELS, /* (not sure) */ | 125 | .type = FB_TYPE_PACKED_PIXELS, /* (not sure) */ |
126 | .visual = FB_VISUAL_MONO10, | 126 | .visual = FB_VISUAL_MONO10, |
@@ -276,7 +276,7 @@ static void hga_blank(int blank_mode) | |||
276 | spin_unlock_irqrestore(&hga_reg_lock, flags); | 276 | spin_unlock_irqrestore(&hga_reg_lock, flags); |
277 | } | 277 | } |
278 | 278 | ||
279 | static int __init hga_card_detect(void) | 279 | static int __devinit hga_card_detect(void) |
280 | { | 280 | { |
281 | int count = 0; | 281 | int count = 0; |
282 | void __iomem *p, *q; | 282 | void __iomem *p, *q; |
@@ -596,7 +596,7 @@ static int __devinit hgafb_probe(struct platform_device *pdev) | |||
596 | return 0; | 596 | return 0; |
597 | } | 597 | } |
598 | 598 | ||
599 | static int hgafb_remove(struct platform_device *pdev) | 599 | static int __devexit hgafb_remove(struct platform_device *pdev) |
600 | { | 600 | { |
601 | struct fb_info *info = platform_get_drvdata(pdev); | 601 | struct fb_info *info = platform_get_drvdata(pdev); |
602 | 602 | ||
@@ -621,7 +621,7 @@ static int hgafb_remove(struct platform_device *pdev) | |||
621 | 621 | ||
622 | static struct platform_driver hgafb_driver = { | 622 | static struct platform_driver hgafb_driver = { |
623 | .probe = hgafb_probe, | 623 | .probe = hgafb_probe, |
624 | .remove = hgafb_remove, | 624 | .remove = __devexit_p(hgafb_remove), |
625 | .driver = { | 625 | .driver = { |
626 | .name = "hgafb", | 626 | .name = "hgafb", |
627 | }, | 627 | }, |
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c index 393f3f3d3dfe..cfb8d6451014 100644 --- a/drivers/video/hitfb.c +++ b/drivers/video/hitfb.c | |||
@@ -30,14 +30,14 @@ | |||
30 | 30 | ||
31 | #define WIDTH 640 | 31 | #define WIDTH 640 |
32 | 32 | ||
33 | static struct fb_var_screeninfo hitfb_var __initdata = { | 33 | static struct fb_var_screeninfo hitfb_var __devinitdata = { |
34 | .activate = FB_ACTIVATE_NOW, | 34 | .activate = FB_ACTIVATE_NOW, |
35 | .height = -1, | 35 | .height = -1, |
36 | .width = -1, | 36 | .width = -1, |
37 | .vmode = FB_VMODE_NONINTERLACED, | 37 | .vmode = FB_VMODE_NONINTERLACED, |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static struct fb_fix_screeninfo hitfb_fix __initdata = { | 40 | static struct fb_fix_screeninfo hitfb_fix __devinitdata = { |
41 | .id = "Hitachi HD64461", | 41 | .id = "Hitachi HD64461", |
42 | .type = FB_TYPE_PACKED_PIXELS, | 42 | .type = FB_TYPE_PACKED_PIXELS, |
43 | .accel = FB_ACCEL_NONE, | 43 | .accel = FB_ACCEL_NONE, |
@@ -417,7 +417,7 @@ err_fb: | |||
417 | return ret; | 417 | return ret; |
418 | } | 418 | } |
419 | 419 | ||
420 | static int __exit hitfb_remove(struct platform_device *dev) | 420 | static int __devexit hitfb_remove(struct platform_device *dev) |
421 | { | 421 | { |
422 | struct fb_info *info = platform_get_drvdata(dev); | 422 | struct fb_info *info = platform_get_drvdata(dev); |
423 | 423 | ||
@@ -462,7 +462,7 @@ static const struct dev_pm_ops hitfb_dev_pm_ops = { | |||
462 | 462 | ||
463 | static struct platform_driver hitfb_driver = { | 463 | static struct platform_driver hitfb_driver = { |
464 | .probe = hitfb_probe, | 464 | .probe = hitfb_probe, |
465 | .remove = __exit_p(hitfb_remove), | 465 | .remove = __devexit_p(hitfb_remove), |
466 | .driver = { | 466 | .driver = { |
467 | .name = "hitfb", | 467 | .name = "hitfb", |
468 | .owner = THIS_MODULE, | 468 | .owner = THIS_MODULE, |
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h index 40984551c927..6b51175629c7 100644 --- a/drivers/video/intelfb/intelfb.h +++ b/drivers/video/intelfb/intelfb.h | |||
@@ -371,10 +371,6 @@ struct intelfb_info { | |||
371 | ((dinfo)->chipset == INTEL_965G) || \ | 371 | ((dinfo)->chipset == INTEL_965G) || \ |
372 | ((dinfo)->chipset == INTEL_965GM)) | 372 | ((dinfo)->chipset == INTEL_965GM)) |
373 | 373 | ||
374 | #ifndef FBIO_WAITFORVSYNC | ||
375 | #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) | ||
376 | #endif | ||
377 | |||
378 | /*** function prototypes ***/ | 374 | /*** function prototypes ***/ |
379 | 375 | ||
380 | extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); | 376 | extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var); |
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index 6bf0d460a738..d4cde79ea15e 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c | |||
@@ -667,7 +667,7 @@ release_irq: | |||
667 | release_regs: | 667 | release_regs: |
668 | iounmap(fbi->io); | 668 | iounmap(fbi->io); |
669 | release_mem_region: | 669 | release_mem_region: |
670 | release_mem_region((unsigned long)fbi->mem, size); | 670 | release_mem_region(res->start, size); |
671 | free_fb: | 671 | free_fb: |
672 | framebuffer_release(fbinfo); | 672 | framebuffer_release(fbinfo); |
673 | return ret; | 673 | return ret; |
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 2b094dec4a56..46b430978bcc 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -631,7 +631,7 @@ static struct fb_ops s3c2410fb_ops = { | |||
631 | * cache. Once this area is remapped, all virtual memory | 631 | * cache. Once this area is remapped, all virtual memory |
632 | * access to the video memory should occur at the new region. | 632 | * access to the video memory should occur at the new region. |
633 | */ | 633 | */ |
634 | static int __init s3c2410fb_map_video_memory(struct fb_info *info) | 634 | static int __devinit s3c2410fb_map_video_memory(struct fb_info *info) |
635 | { | 635 | { |
636 | struct s3c2410fb_info *fbi = info->par; | 636 | struct s3c2410fb_info *fbi = info->par; |
637 | dma_addr_t map_dma; | 637 | dma_addr_t map_dma; |
@@ -814,7 +814,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) | |||
814 | 814 | ||
815 | static char driver_name[] = "s3c2410fb"; | 815 | static char driver_name[] = "s3c2410fb"; |
816 | 816 | ||
817 | static int __init s3c24xxfb_probe(struct platform_device *pdev, | 817 | static int __devinit s3c24xxfb_probe(struct platform_device *pdev, |
818 | enum s3c_drv_type drv_type) | 818 | enum s3c_drv_type drv_type) |
819 | { | 819 | { |
820 | struct s3c2410fb_info *info; | 820 | struct s3c2410fb_info *info; |
@@ -1018,7 +1018,7 @@ static int __devinit s3c2412fb_probe(struct platform_device *pdev) | |||
1018 | /* | 1018 | /* |
1019 | * Cleanup | 1019 | * Cleanup |
1020 | */ | 1020 | */ |
1021 | static int s3c2410fb_remove(struct platform_device *pdev) | 1021 | static int __devexit s3c2410fb_remove(struct platform_device *pdev) |
1022 | { | 1022 | { |
1023 | struct fb_info *fbinfo = platform_get_drvdata(pdev); | 1023 | struct fb_info *fbinfo = platform_get_drvdata(pdev); |
1024 | struct s3c2410fb_info *info = fbinfo->par; | 1024 | struct s3c2410fb_info *info = fbinfo->par; |
@@ -1096,7 +1096,7 @@ static int s3c2410fb_resume(struct platform_device *dev) | |||
1096 | 1096 | ||
1097 | static struct platform_driver s3c2410fb_driver = { | 1097 | static struct platform_driver s3c2410fb_driver = { |
1098 | .probe = s3c2410fb_probe, | 1098 | .probe = s3c2410fb_probe, |
1099 | .remove = s3c2410fb_remove, | 1099 | .remove = __devexit_p(s3c2410fb_remove), |
1100 | .suspend = s3c2410fb_suspend, | 1100 | .suspend = s3c2410fb_suspend, |
1101 | .resume = s3c2410fb_resume, | 1101 | .resume = s3c2410fb_resume, |
1102 | .driver = { | 1102 | .driver = { |
@@ -1107,7 +1107,7 @@ static struct platform_driver s3c2410fb_driver = { | |||
1107 | 1107 | ||
1108 | static struct platform_driver s3c2412fb_driver = { | 1108 | static struct platform_driver s3c2412fb_driver = { |
1109 | .probe = s3c2412fb_probe, | 1109 | .probe = s3c2412fb_probe, |
1110 | .remove = s3c2410fb_remove, | 1110 | .remove = __devexit_p(s3c2410fb_remove), |
1111 | .suspend = s3c2410fb_suspend, | 1111 | .suspend = s3c2410fb_suspend, |
1112 | .resume = s3c2410fb_resume, | 1112 | .resume = s3c2410fb_resume, |
1113 | .driver = { | 1113 | .driver = { |
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index d4471b4c0374..dce8c97b4333 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c | |||
@@ -71,7 +71,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", | |||
71 | "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX", | 71 | "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX", |
72 | "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge", | 72 | "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge", |
73 | "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX", | 73 | "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX", |
74 | "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P"}; | 74 | "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P", |
75 | "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"}; | ||
75 | 76 | ||
76 | #define CHIP_UNKNOWN 0x00 | 77 | #define CHIP_UNKNOWN 0x00 |
77 | #define CHIP_732_TRIO32 0x01 | 78 | #define CHIP_732_TRIO32 0x01 |
@@ -89,10 +90,14 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", | |||
89 | #define CHIP_356_VIRGE_GX2 0x0D | 90 | #define CHIP_356_VIRGE_GX2 0x0D |
90 | #define CHIP_357_VIRGE_GX2P 0x0E | 91 | #define CHIP_357_VIRGE_GX2P 0x0E |
91 | #define CHIP_359_VIRGE_GX2P 0x0F | 92 | #define CHIP_359_VIRGE_GX2P 0x0F |
93 | #define CHIP_360_TRIO3D_1X 0x10 | ||
94 | #define CHIP_362_TRIO3D_2X 0x11 | ||
95 | #define CHIP_368_TRIO3D_2X 0x12 | ||
92 | 96 | ||
93 | #define CHIP_XXX_TRIO 0x80 | 97 | #define CHIP_XXX_TRIO 0x80 |
94 | #define CHIP_XXX_TRIO64V2_DXGX 0x81 | 98 | #define CHIP_XXX_TRIO64V2_DXGX 0x81 |
95 | #define CHIP_XXX_VIRGE_DXGX 0x82 | 99 | #define CHIP_XXX_VIRGE_DXGX 0x82 |
100 | #define CHIP_36X_TRIO3D_1X_2X 0x83 | ||
96 | 101 | ||
97 | #define CHIP_UNDECIDED_FLAG 0x80 | 102 | #define CHIP_UNDECIDED_FLAG 0x80 |
98 | #define CHIP_MASK 0xFF | 103 | #define CHIP_MASK 0xFF |
@@ -324,6 +329,7 @@ static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | |||
324 | 329 | ||
325 | static void s3_set_pixclock(struct fb_info *info, u32 pixclock) | 330 | static void s3_set_pixclock(struct fb_info *info, u32 pixclock) |
326 | { | 331 | { |
332 | struct s3fb_info *par = info->par; | ||
327 | u16 m, n, r; | 333 | u16 m, n, r; |
328 | u8 regval; | 334 | u8 regval; |
329 | int rv; | 335 | int rv; |
@@ -339,7 +345,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) | |||
339 | vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); | 345 | vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); |
340 | 346 | ||
341 | /* Set S3 clock registers */ | 347 | /* Set S3 clock registers */ |
342 | vga_wseq(NULL, 0x12, ((n - 2) | (r << 5))); | 348 | if (par->chip == CHIP_360_TRIO3D_1X || |
349 | par->chip == CHIP_362_TRIO3D_2X || | ||
350 | par->chip == CHIP_368_TRIO3D_2X) { | ||
351 | vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ | ||
352 | vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */ | ||
353 | } else | ||
354 | vga_wseq(NULL, 0x12, (n - 2) | (r << 5)); | ||
343 | vga_wseq(NULL, 0x13, m - 2); | 355 | vga_wseq(NULL, 0x13, m - 2); |
344 | 356 | ||
345 | udelay(1000); | 357 | udelay(1000); |
@@ -456,7 +468,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
456 | static int s3fb_set_par(struct fb_info *info) | 468 | static int s3fb_set_par(struct fb_info *info) |
457 | { | 469 | { |
458 | struct s3fb_info *par = info->par; | 470 | struct s3fb_info *par = info->par; |
459 | u32 value, mode, hmul, offset_value, screen_size, multiplex; | 471 | u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes; |
460 | u32 bpp = info->var.bits_per_pixel; | 472 | u32 bpp = info->var.bits_per_pixel; |
461 | 473 | ||
462 | if (bpp != 0) { | 474 | if (bpp != 0) { |
@@ -518,7 +530,7 @@ static int s3fb_set_par(struct fb_info *info) | |||
518 | svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */ | 530 | svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */ |
519 | svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */ | 531 | svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */ |
520 | 532 | ||
521 | svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits | 533 | svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */ |
522 | 534 | ||
523 | /* svga_wcrt_mask(0x58, 0x03, 0x03); */ | 535 | /* svga_wcrt_mask(0x58, 0x03, 0x03); */ |
524 | 536 | ||
@@ -530,10 +542,14 @@ static int s3fb_set_par(struct fb_info *info) | |||
530 | pr_debug("fb%d: offset register : %d\n", info->node, offset_value); | 542 | pr_debug("fb%d: offset register : %d\n", info->node, offset_value); |
531 | svga_wcrt_multi(s3_offset_regs, offset_value); | 543 | svga_wcrt_multi(s3_offset_regs, offset_value); |
532 | 544 | ||
533 | vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ | 545 | if (par->chip != CHIP_360_TRIO3D_1X && |
534 | vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ | 546 | par->chip != CHIP_362_TRIO3D_2X && |
535 | vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ | 547 | par->chip != CHIP_368_TRIO3D_2X) { |
536 | vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ | 548 | vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ |
549 | vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ | ||
550 | vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ | ||
551 | vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ | ||
552 | } | ||
537 | 553 | ||
538 | vga_wcrt(NULL, 0x3A, 0x35); | 554 | vga_wcrt(NULL, 0x3A, 0x35); |
539 | svga_wattr(0x33, 0x00); | 555 | svga_wattr(0x33, 0x00); |
@@ -570,6 +586,16 @@ static int s3fb_set_par(struct fb_info *info) | |||
570 | vga_wcrt(NULL, 0x66, 0x90); | 586 | vga_wcrt(NULL, 0x66, 0x90); |
571 | } | 587 | } |
572 | 588 | ||
589 | if (par->chip == CHIP_360_TRIO3D_1X || | ||
590 | par->chip == CHIP_362_TRIO3D_2X || | ||
591 | par->chip == CHIP_368_TRIO3D_2X) { | ||
592 | dbytes = info->var.xres * ((bpp+7)/8); | ||
593 | vga_wcrt(NULL, 0x91, (dbytes + 7) / 8); | ||
594 | vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); | ||
595 | |||
596 | vga_wcrt(NULL, 0x66, 0x81); | ||
597 | } | ||
598 | |||
573 | svga_wcrt_mask(0x31, 0x00, 0x40); | 599 | svga_wcrt_mask(0x31, 0x00, 0x40); |
574 | multiplex = 0; | 600 | multiplex = 0; |
575 | hmul = 1; | 601 | hmul = 1; |
@@ -615,11 +641,13 @@ static int s3fb_set_par(struct fb_info *info) | |||
615 | break; | 641 | break; |
616 | case 3: | 642 | case 3: |
617 | pr_debug("fb%d: 8 bit pseudocolor\n", info->node); | 643 | pr_debug("fb%d: 8 bit pseudocolor\n", info->node); |
618 | if (info->var.pixclock > 20000) { | 644 | svga_wcrt_mask(0x50, 0x00, 0x30); |
619 | svga_wcrt_mask(0x50, 0x00, 0x30); | 645 | if (info->var.pixclock > 20000 || |
646 | par->chip == CHIP_360_TRIO3D_1X || | ||
647 | par->chip == CHIP_362_TRIO3D_2X || | ||
648 | par->chip == CHIP_368_TRIO3D_2X) | ||
620 | svga_wcrt_mask(0x67, 0x00, 0xF0); | 649 | svga_wcrt_mask(0x67, 0x00, 0xF0); |
621 | } else { | 650 | else { |
622 | svga_wcrt_mask(0x50, 0x00, 0x30); | ||
623 | svga_wcrt_mask(0x67, 0x10, 0xF0); | 651 | svga_wcrt_mask(0x67, 0x10, 0xF0); |
624 | multiplex = 1; | 652 | multiplex = 1; |
625 | } | 653 | } |
@@ -634,7 +662,10 @@ static int s3fb_set_par(struct fb_info *info) | |||
634 | } else { | 662 | } else { |
635 | svga_wcrt_mask(0x50, 0x10, 0x30); | 663 | svga_wcrt_mask(0x50, 0x10, 0x30); |
636 | svga_wcrt_mask(0x67, 0x30, 0xF0); | 664 | svga_wcrt_mask(0x67, 0x30, 0xF0); |
637 | hmul = 2; | 665 | if (par->chip != CHIP_360_TRIO3D_1X && |
666 | par->chip != CHIP_362_TRIO3D_2X && | ||
667 | par->chip != CHIP_368_TRIO3D_2X) | ||
668 | hmul = 2; | ||
638 | } | 669 | } |
639 | break; | 670 | break; |
640 | case 5: | 671 | case 5: |
@@ -647,7 +678,10 @@ static int s3fb_set_par(struct fb_info *info) | |||
647 | } else { | 678 | } else { |
648 | svga_wcrt_mask(0x50, 0x10, 0x30); | 679 | svga_wcrt_mask(0x50, 0x10, 0x30); |
649 | svga_wcrt_mask(0x67, 0x50, 0xF0); | 680 | svga_wcrt_mask(0x67, 0x50, 0xF0); |
650 | hmul = 2; | 681 | if (par->chip != CHIP_360_TRIO3D_1X && |
682 | par->chip != CHIP_362_TRIO3D_2X && | ||
683 | par->chip != CHIP_368_TRIO3D_2X) | ||
684 | hmul = 2; | ||
651 | } | 685 | } |
652 | break; | 686 | break; |
653 | case 6: | 687 | case 6: |
@@ -866,6 +900,17 @@ static int __devinit s3_identification(int chip) | |||
866 | return CHIP_385_VIRGE_GX; | 900 | return CHIP_385_VIRGE_GX; |
867 | } | 901 | } |
868 | 902 | ||
903 | if (chip == CHIP_36X_TRIO3D_1X_2X) { | ||
904 | switch (vga_rcrt(NULL, 0x2f)) { | ||
905 | case 0x00: | ||
906 | return CHIP_360_TRIO3D_1X; | ||
907 | case 0x01: | ||
908 | return CHIP_362_TRIO3D_2X; | ||
909 | case 0x02: | ||
910 | return CHIP_368_TRIO3D_2X; | ||
911 | } | ||
912 | } | ||
913 | |||
869 | return CHIP_UNKNOWN; | 914 | return CHIP_UNKNOWN; |
870 | } | 915 | } |
871 | 916 | ||
@@ -930,17 +975,32 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i | |||
930 | vga_wcrt(NULL, 0x38, 0x48); | 975 | vga_wcrt(NULL, 0x38, 0x48); |
931 | vga_wcrt(NULL, 0x39, 0xA5); | 976 | vga_wcrt(NULL, 0x39, 0xA5); |
932 | 977 | ||
933 | /* Find how many physical memory there is on card */ | 978 | /* Identify chip type */ |
934 | /* 0x36 register is accessible even if other registers are locked */ | ||
935 | regval = vga_rcrt(NULL, 0x36); | ||
936 | info->screen_size = s3_memsizes[regval >> 5] << 10; | ||
937 | info->fix.smem_len = info->screen_size; | ||
938 | |||
939 | par->chip = id->driver_data & CHIP_MASK; | 979 | par->chip = id->driver_data & CHIP_MASK; |
940 | par->rev = vga_rcrt(NULL, 0x2f); | 980 | par->rev = vga_rcrt(NULL, 0x2f); |
941 | if (par->chip & CHIP_UNDECIDED_FLAG) | 981 | if (par->chip & CHIP_UNDECIDED_FLAG) |
942 | par->chip = s3_identification(par->chip); | 982 | par->chip = s3_identification(par->chip); |
943 | 983 | ||
984 | /* Find how many physical memory there is on card */ | ||
985 | /* 0x36 register is accessible even if other registers are locked */ | ||
986 | regval = vga_rcrt(NULL, 0x36); | ||
987 | if (par->chip == CHIP_360_TRIO3D_1X || | ||
988 | par->chip == CHIP_362_TRIO3D_2X || | ||
989 | par->chip == CHIP_368_TRIO3D_2X) { | ||
990 | switch ((regval & 0xE0) >> 5) { | ||
991 | case 0: /* 8MB -- only 4MB usable for display */ | ||
992 | case 1: /* 4MB with 32-bit bus */ | ||
993 | case 2: /* 4MB */ | ||
994 | info->screen_size = 4 << 20; | ||
995 | break; | ||
996 | case 6: /* 2MB */ | ||
997 | info->screen_size = 2 << 20; | ||
998 | break; | ||
999 | } | ||
1000 | } else | ||
1001 | info->screen_size = s3_memsizes[regval >> 5] << 10; | ||
1002 | info->fix.smem_len = info->screen_size; | ||
1003 | |||
944 | /* Find MCLK frequency */ | 1004 | /* Find MCLK frequency */ |
945 | regval = vga_rseq(NULL, 0x10); | 1005 | regval = vga_rseq(NULL, 0x10); |
946 | par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); | 1006 | par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); |
@@ -1131,6 +1191,7 @@ static struct pci_device_id s3_devices[] __devinitdata = { | |||
1131 | {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2}, | 1191 | {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2}, |
1132 | {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, | 1192 | {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, |
1133 | {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, | 1193 | {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, |
1194 | {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X}, | ||
1134 | 1195 | ||
1135 | {0, 0, 0, 0, 0, 0, 0} | 1196 | {0, 0, 0, 0, 0, 0, 0} |
1136 | }; | 1197 | }; |
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c index 7a3a5e28eca1..53455f295510 100644 --- a/drivers/video/sgivwfb.c +++ b/drivers/video/sgivwfb.c | |||
@@ -47,7 +47,7 @@ static int ywrap = 0; | |||
47 | 47 | ||
48 | static int flatpanel_id = -1; | 48 | static int flatpanel_id = -1; |
49 | 49 | ||
50 | static struct fb_fix_screeninfo sgivwfb_fix __initdata = { | 50 | static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = { |
51 | .id = "SGI Vis WS FB", | 51 | .id = "SGI Vis WS FB", |
52 | .type = FB_TYPE_PACKED_PIXELS, | 52 | .type = FB_TYPE_PACKED_PIXELS, |
53 | .visual = FB_VISUAL_PSEUDOCOLOR, | 53 | .visual = FB_VISUAL_PSEUDOCOLOR, |
@@ -57,7 +57,7 @@ static struct fb_fix_screeninfo sgivwfb_fix __initdata = { | |||
57 | .line_length = 640, | 57 | .line_length = 640, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static struct fb_var_screeninfo sgivwfb_var __initdata = { | 60 | static struct fb_var_screeninfo sgivwfb_var __devinitdata = { |
61 | /* 640x480, 8 bpp */ | 61 | /* 640x480, 8 bpp */ |
62 | .xres = 640, | 62 | .xres = 640, |
63 | .yres = 480, | 63 | .yres = 480, |
@@ -79,7 +79,7 @@ static struct fb_var_screeninfo sgivwfb_var __initdata = { | |||
79 | .vmode = FB_VMODE_NONINTERLACED | 79 | .vmode = FB_VMODE_NONINTERLACED |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = { | 82 | static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = { |
83 | /* 1600x1024, 8 bpp */ | 83 | /* 1600x1024, 8 bpp */ |
84 | .xres = 1600, | 84 | .xres = 1600, |
85 | .yres = 1024, | 85 | .yres = 1024, |
@@ -825,7 +825,7 @@ fail_ioremap_regs: | |||
825 | return -ENXIO; | 825 | return -ENXIO; |
826 | } | 826 | } |
827 | 827 | ||
828 | static int sgivwfb_remove(struct platform_device *dev) | 828 | static int __devexit sgivwfb_remove(struct platform_device *dev) |
829 | { | 829 | { |
830 | struct fb_info *info = platform_get_drvdata(dev); | 830 | struct fb_info *info = platform_get_drvdata(dev); |
831 | 831 | ||
@@ -845,7 +845,7 @@ static int sgivwfb_remove(struct platform_device *dev) | |||
845 | 845 | ||
846 | static struct platform_driver sgivwfb_driver = { | 846 | static struct platform_driver sgivwfb_driver = { |
847 | .probe = sgivwfb_probe, | 847 | .probe = sgivwfb_probe, |
848 | .remove = sgivwfb_remove, | 848 | .remove = __devexit_p(sgivwfb_remove), |
849 | .driver = { | 849 | .driver = { |
850 | .name = "sgivwfb", | 850 | .name = "sgivwfb", |
851 | }, | 851 | }, |
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index a531a0f7cdf2..559bf1727a2b 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c | |||
@@ -1845,7 +1845,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) | |||
1845 | 1845 | ||
1846 | memset(fix, 0, sizeof(struct fb_fix_screeninfo)); | 1846 | memset(fix, 0, sizeof(struct fb_fix_screeninfo)); |
1847 | 1847 | ||
1848 | strcpy(fix->id, ivideo->myid); | 1848 | strlcpy(fix->id, ivideo->myid, sizeof(fix->id)); |
1849 | 1849 | ||
1850 | mutex_lock(&info->mm_lock); | 1850 | mutex_lock(&info->mm_lock); |
1851 | fix->smem_start = ivideo->video_base + ivideo->video_offset; | 1851 | fix->smem_start = ivideo->video_base + ivideo->video_offset; |
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index 9b5532b4de35..bc67251f1a2f 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c | |||
@@ -78,7 +78,7 @@ static void rvfree(void *mem, unsigned long size) | |||
78 | vfree(mem); | 78 | vfree(mem); |
79 | } | 79 | } |
80 | 80 | ||
81 | static struct fb_var_screeninfo vfb_default __initdata = { | 81 | static struct fb_var_screeninfo vfb_default __devinitdata = { |
82 | .xres = 640, | 82 | .xres = 640, |
83 | .yres = 480, | 83 | .yres = 480, |
84 | .xres_virtual = 640, | 84 | .xres_virtual = 640, |
@@ -100,7 +100,7 @@ static struct fb_var_screeninfo vfb_default __initdata = { | |||
100 | .vmode = FB_VMODE_NONINTERLACED, | 100 | .vmode = FB_VMODE_NONINTERLACED, |
101 | }; | 101 | }; |
102 | 102 | ||
103 | static struct fb_fix_screeninfo vfb_fix __initdata = { | 103 | static struct fb_fix_screeninfo vfb_fix __devinitdata = { |
104 | .id = "Virtual FB", | 104 | .id = "Virtual FB", |
105 | .type = FB_TYPE_PACKED_PIXELS, | 105 | .type = FB_TYPE_PACKED_PIXELS, |
106 | .visual = FB_VISUAL_PSEUDOCOLOR, | 106 | .visual = FB_VISUAL_PSEUDOCOLOR, |
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 149c47ac7e93..28ccab44a391 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
@@ -65,7 +65,7 @@ struct vga16fb_par { | |||
65 | 65 | ||
66 | /* --------------------------------------------------------------------- */ | 66 | /* --------------------------------------------------------------------- */ |
67 | 67 | ||
68 | static struct fb_var_screeninfo vga16fb_defined __initdata = { | 68 | static struct fb_var_screeninfo vga16fb_defined __devinitdata = { |
69 | .xres = 640, | 69 | .xres = 640, |
70 | .yres = 480, | 70 | .yres = 480, |
71 | .xres_virtual = 640, | 71 | .xres_virtual = 640, |
@@ -85,7 +85,7 @@ static struct fb_var_screeninfo vga16fb_defined __initdata = { | |||
85 | }; | 85 | }; |
86 | 86 | ||
87 | /* name should not depend on EGA/VGA */ | 87 | /* name should not depend on EGA/VGA */ |
88 | static struct fb_fix_screeninfo vga16fb_fix __initdata = { | 88 | static struct fb_fix_screeninfo vga16fb_fix __devinitdata = { |
89 | .id = "VGA16 VGA", | 89 | .id = "VGA16 VGA", |
90 | .smem_start = VGA_FB_PHYS, | 90 | .smem_start = VGA_FB_PHYS, |
91 | .smem_len = VGA_FB_PHYS_LEN, | 91 | .smem_len = VGA_FB_PHYS_LEN, |
@@ -1287,7 +1287,7 @@ static struct fb_ops vga16fb_ops = { | |||
1287 | }; | 1287 | }; |
1288 | 1288 | ||
1289 | #ifndef MODULE | 1289 | #ifndef MODULE |
1290 | static int vga16fb_setup(char *options) | 1290 | static int __init vga16fb_setup(char *options) |
1291 | { | 1291 | { |
1292 | char *this_opt; | 1292 | char *this_opt; |
1293 | 1293 | ||
@@ -1393,7 +1393,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev) | |||
1393 | return ret; | 1393 | return ret; |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | static int vga16fb_remove(struct platform_device *dev) | 1396 | static int __devexit vga16fb_remove(struct platform_device *dev) |
1397 | { | 1397 | { |
1398 | struct fb_info *info = platform_get_drvdata(dev); | 1398 | struct fb_info *info = platform_get_drvdata(dev); |
1399 | 1399 | ||
@@ -1405,7 +1405,7 @@ static int vga16fb_remove(struct platform_device *dev) | |||
1405 | 1405 | ||
1406 | static struct platform_driver vga16fb_driver = { | 1406 | static struct platform_driver vga16fb_driver = { |
1407 | .probe = vga16fb_probe, | 1407 | .probe = vga16fb_probe, |
1408 | .remove = vga16fb_remove, | 1408 | .remove = __devexit_p(vga16fb_remove), |
1409 | .driver = { | 1409 | .driver = { |
1410 | .name = "vga16fb", | 1410 | .name = "vga16fb", |
1411 | }, | 1411 | }, |
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 2bc40e682f95..1082541358f0 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c | |||
@@ -578,14 +578,9 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg) | |||
578 | break; | 578 | break; |
579 | 579 | ||
580 | case VIAFB_SET_GAMMA_LUT: | 580 | case VIAFB_SET_GAMMA_LUT: |
581 | viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL); | 581 | viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32)); |
582 | if (!viafb_gamma_table) | 582 | if (IS_ERR(viafb_gamma_table)) |
583 | return -ENOMEM; | 583 | return PTR_ERR(viafb_gamma_table); |
584 | if (copy_from_user(viafb_gamma_table, argp, | ||
585 | 256 * sizeof(u32))) { | ||
586 | kfree(viafb_gamma_table); | ||
587 | return -EFAULT; | ||
588 | } | ||
589 | viafb_set_gamma_table(viafb_bpp, viafb_gamma_table); | 584 | viafb_set_gamma_table(viafb_bpp, viafb_gamma_table); |
590 | kfree(viafb_gamma_table); | 585 | kfree(viafb_gamma_table); |
591 | break; | 586 | break; |
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 31b0e17ed090..e66b8b19ce5d 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c | |||
@@ -53,7 +53,7 @@ static void w100_update_enable(void); | |||
53 | static void w100_update_disable(void); | 53 | static void w100_update_disable(void); |
54 | static void calc_hsync(struct w100fb_par *par); | 54 | static void calc_hsync(struct w100fb_par *par); |
55 | static void w100_init_graphic_engine(struct w100fb_par *par); | 55 | static void w100_init_graphic_engine(struct w100fb_par *par); |
56 | struct w100_pll_info *w100_get_xtal_table(unsigned int freq); | 56 | struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit; |
57 | 57 | ||
58 | /* Pseudo palette size */ | 58 | /* Pseudo palette size */ |
59 | #define MAX_PALETTES 16 | 59 | #define MAX_PALETTES 16 |
@@ -782,7 +782,7 @@ out: | |||
782 | } | 782 | } |
783 | 783 | ||
784 | 784 | ||
785 | static int w100fb_remove(struct platform_device *pdev) | 785 | static int __devexit w100fb_remove(struct platform_device *pdev) |
786 | { | 786 | { |
787 | struct fb_info *info = platform_get_drvdata(pdev); | 787 | struct fb_info *info = platform_get_drvdata(pdev); |
788 | struct w100fb_par *par=info->par; | 788 | struct w100fb_par *par=info->par; |
@@ -1020,7 +1020,7 @@ static struct pll_entries { | |||
1020 | { 0 }, | 1020 | { 0 }, |
1021 | }; | 1021 | }; |
1022 | 1022 | ||
1023 | struct w100_pll_info *w100_get_xtal_table(unsigned int freq) | 1023 | struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq) |
1024 | { | 1024 | { |
1025 | struct pll_entries *pll_entry = w100_pll_tables; | 1025 | struct pll_entries *pll_entry = w100_pll_tables; |
1026 | 1026 | ||
@@ -1611,7 +1611,7 @@ static void w100_vsync(void) | |||
1611 | 1611 | ||
1612 | static struct platform_driver w100fb_driver = { | 1612 | static struct platform_driver w100fb_driver = { |
1613 | .probe = w100fb_probe, | 1613 | .probe = w100fb_probe, |
1614 | .remove = w100fb_remove, | 1614 | .remove = __devexit_p(w100fb_remove), |
1615 | .suspend = w100fb_suspend, | 1615 | .suspend = w100fb_suspend, |
1616 | .resume = w100fb_resume, | 1616 | .resume = w100fb_resume, |
1617 | .driver = { | 1617 | .driver = { |
@@ -1619,7 +1619,7 @@ static struct platform_driver w100fb_driver = { | |||
1619 | }, | 1619 | }, |
1620 | }; | 1620 | }; |
1621 | 1621 | ||
1622 | int __devinit w100fb_init(void) | 1622 | int __init w100fb_init(void) |
1623 | { | 1623 | { |
1624 | return platform_driver_register(&w100fb_driver); | 1624 | return platform_driver_register(&w100fb_driver); |
1625 | } | 1625 | } |