aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/atmel_lcdfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/atmel_lcdfb.c')
-rw-r--r--drivers/video/atmel_lcdfb.c105
1 files changed, 67 insertions, 38 deletions
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 3f7d6dc3408d..0d7214df1237 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -20,12 +20,44 @@
20#include <linux/gfp.h> 20#include <linux/gfp.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/platform_data/atmel.h> 22#include <linux/platform_data/atmel.h>
23#include <video/of_display_timing.h>
23 24
24#include <mach/cpu.h> 25#include <mach/cpu.h>
25#include <asm/gpio.h> 26#include <asm/gpio.h>
26 27
27#include <video/atmel_lcdc.h> 28#include <video/atmel_lcdc.h>
28 29
30struct atmel_lcdfb_config {
31 bool have_alt_pixclock;
32 bool have_hozval;
33 bool have_intensity_bit;
34};
35
36 /* LCD Controller info data structure, stored in device platform_data */
37struct atmel_lcdfb_info {
38 spinlock_t lock;
39 struct fb_info *info;
40 void __iomem *mmio;
41 int irq_base;
42 struct work_struct task;
43
44 unsigned int smem_len;
45 struct platform_device *pdev;
46 struct clk *bus_clk;
47 struct clk *lcdc_clk;
48
49 struct backlight_device *backlight;
50 u8 bl_power;
51 u8 saved_lcdcon;
52
53 u32 pseudo_palette[16];
54 bool have_intensity_bit;
55
56 struct atmel_lcdfb_pdata pdata;
57
58 struct atmel_lcdfb_config *config;
59};
60
29#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) 61#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
30#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) 62#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
31 63
@@ -34,12 +66,6 @@
34#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ 66#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
35#define ATMEL_LCDC_FIFO_SIZE 512 /* words */ 67#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
36 68
37struct atmel_lcdfb_config {
38 bool have_alt_pixclock;
39 bool have_hozval;
40 bool have_intensity_bit;
41};
42
43static struct atmel_lcdfb_config at91sam9261_config = { 69static struct atmel_lcdfb_config at91sam9261_config = {
44 .have_hozval = true, 70 .have_hozval = true,
45 .have_intensity_bit = true, 71 .have_intensity_bit = true,
@@ -248,15 +274,17 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
248 274
249static void init_contrast(struct atmel_lcdfb_info *sinfo) 275static void init_contrast(struct atmel_lcdfb_info *sinfo)
250{ 276{
277 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
278
251 /* contrast pwm can be 'inverted' */ 279 /* contrast pwm can be 'inverted' */
252 if (sinfo->lcdcon_pol_negative) 280 if (pdata->lcdcon_pol_negative)
253 contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); 281 contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
254 282
255 /* have some default contrast/backlight settings */ 283 /* have some default contrast/backlight settings */
256 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); 284 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
257 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); 285 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
258 286
259 if (sinfo->lcdcon_is_backlight) 287 if (pdata->lcdcon_is_backlight)
260 init_backlight(sinfo); 288 init_backlight(sinfo);
261} 289}
262 290
@@ -299,9 +327,11 @@ static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo,
299 327
300static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) 328static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
301{ 329{
330 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
331
302 /* Turn off the LCD controller and the DMA controller */ 332 /* Turn off the LCD controller and the DMA controller */
303 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, 333 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
304 sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); 334 pdata->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
305 335
306 /* Wait for the LCDC core to become idle */ 336 /* Wait for the LCDC core to become idle */
307 while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) 337 while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
@@ -321,9 +351,11 @@ static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
321 351
322static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) 352static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
323{ 353{
324 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); 354 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
355
356 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, pdata->default_dmacon);
325 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, 357 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
326 (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) 358 (pdata->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
327 | ATMEL_LCDC_PWR); 359 | ATMEL_LCDC_PWR);
328} 360}
329 361
@@ -424,6 +456,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
424{ 456{
425 struct device *dev = info->device; 457 struct device *dev = info->device;
426 struct atmel_lcdfb_info *sinfo = info->par; 458 struct atmel_lcdfb_info *sinfo = info->par;
459 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
427 unsigned long clk_value_khz; 460 unsigned long clk_value_khz;
428 461
429 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; 462 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
@@ -510,7 +543,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
510 else 543 else
511 var->green.length = 6; 544 var->green.length = 6;
512 545
513 if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { 546 if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
514 /* RGB:5X5 mode */ 547 /* RGB:5X5 mode */
515 var->red.offset = var->green.length + 5; 548 var->red.offset = var->green.length + 5;
516 var->blue.offset = 0; 549 var->blue.offset = 0;
@@ -527,7 +560,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
527 var->transp.length = 8; 560 var->transp.length = 8;
528 /* fall through */ 561 /* fall through */
529 case 24: 562 case 24:
530 if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { 563 if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
531 /* RGB:888 mode */ 564 /* RGB:888 mode */
532 var->red.offset = 16; 565 var->red.offset = 16;
533 var->blue.offset = 0; 566 var->blue.offset = 0;
@@ -576,6 +609,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
576static int atmel_lcdfb_set_par(struct fb_info *info) 609static int atmel_lcdfb_set_par(struct fb_info *info)
577{ 610{
578 struct atmel_lcdfb_info *sinfo = info->par; 611 struct atmel_lcdfb_info *sinfo = info->par;
612 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
579 unsigned long hozval_linesz; 613 unsigned long hozval_linesz;
580 unsigned long value; 614 unsigned long value;
581 unsigned long clk_value_khz; 615 unsigned long clk_value_khz;
@@ -637,7 +671,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
637 671
638 672
639 /* Initialize control register 2 */ 673 /* Initialize control register 2 */
640 value = sinfo->default_lcdcon2; 674 value = pdata->default_lcdcon2;
641 675
642 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) 676 if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
643 value |= ATMEL_LCDC_INVLINE_INVERTED; 677 value |= ATMEL_LCDC_INVLINE_INVERTED;
@@ -741,6 +775,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
741 unsigned int transp, struct fb_info *info) 775 unsigned int transp, struct fb_info *info)
742{ 776{
743 struct atmel_lcdfb_info *sinfo = info->par; 777 struct atmel_lcdfb_info *sinfo = info->par;
778 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
744 unsigned int val; 779 unsigned int val;
745 u32 *pal; 780 u32 *pal;
746 int ret = 1; 781 int ret = 1;
@@ -777,8 +812,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
777 */ 812 */
778 } else { 813 } else {
779 /* new style BGR:565 / RGB:565 */ 814 /* new style BGR:565 / RGB:565 */
780 if (sinfo->lcd_wiring_mode == 815 if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
781 ATMEL_LCDC_WIRING_RGB) {
782 val = ((blue >> 11) & 0x001f); 816 val = ((blue >> 11) & 0x001f);
783 val |= ((red >> 0) & 0xf800); 817 val |= ((red >> 0) & 0xf800);
784 } else { 818 } else {
@@ -918,7 +952,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
918 struct device *dev = &pdev->dev; 952 struct device *dev = &pdev->dev;
919 struct fb_info *info; 953 struct fb_info *info;
920 struct atmel_lcdfb_info *sinfo; 954 struct atmel_lcdfb_info *sinfo;
921 struct atmel_lcdfb_info *pdata_sinfo; 955 struct atmel_lcdfb_pdata *pdata;
922 struct fb_videomode fbmode; 956 struct fb_videomode fbmode;
923 struct resource *regs = NULL; 957 struct resource *regs = NULL;
924 struct resource *map = NULL; 958 struct resource *map = NULL;
@@ -936,17 +970,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
936 sinfo = info->par; 970 sinfo = info->par;
937 971
938 if (dev_get_platdata(dev)) { 972 if (dev_get_platdata(dev)) {
939 pdata_sinfo = dev_get_platdata(dev); 973 pdata = dev_get_platdata(dev);
940 sinfo->default_bpp = pdata_sinfo->default_bpp; 974 sinfo->pdata = *pdata;
941 sinfo->default_dmacon = pdata_sinfo->default_dmacon;
942 sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
943 sinfo->default_monspecs = pdata_sinfo->default_monspecs;
944 sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
945 sinfo->guard_time = pdata_sinfo->guard_time;
946 sinfo->smem_len = pdata_sinfo->smem_len;
947 sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
948 sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
949 sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
950 } else { 975 } else {
951 dev_err(dev, "cannot get default configuration\n"); 976 dev_err(dev, "cannot get default configuration\n");
952 goto free_info; 977 goto free_info;
@@ -962,7 +987,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
962 info->pseudo_palette = sinfo->pseudo_palette; 987 info->pseudo_palette = sinfo->pseudo_palette;
963 info->fbops = &atmel_lcdfb_ops; 988 info->fbops = &atmel_lcdfb_ops;
964 989
965 memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs)); 990 memcpy(&info->monspecs, pdata->default_monspecs, sizeof(info->monspecs));
966 info->fix = atmel_lcdfb_fix; 991 info->fix = atmel_lcdfb_fix;
967 992
968 /* Enable LCDC Clocks */ 993 /* Enable LCDC Clocks */
@@ -980,7 +1005,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
980 1005
981 ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, 1006 ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
982 info->monspecs.modedb_len, info->monspecs.modedb, 1007 info->monspecs.modedb_len, info->monspecs.modedb,
983 sinfo->default_bpp); 1008 pdata->default_bpp);
984 if (!ret) { 1009 if (!ret) {
985 dev_err(dev, "no suitable video mode found\n"); 1010 dev_err(dev, "no suitable video mode found\n");
986 goto stop_clk; 1011 goto stop_clk;
@@ -1097,8 +1122,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
1097 fb_add_videomode(&fbmode, &info->modelist); 1122 fb_add_videomode(&fbmode, &info->modelist);
1098 1123
1099 /* Power up the LCDC screen */ 1124 /* Power up the LCDC screen */
1100 if (sinfo->atmel_lcdfb_power_control) 1125 if (pdata->atmel_lcdfb_power_control)
1101 sinfo->atmel_lcdfb_power_control(1); 1126 pdata->atmel_lcdfb_power_control(1);
1102 1127
1103 dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n", 1128 dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
1104 info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); 1129 info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
@@ -1141,15 +1166,17 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
1141 struct device *dev = &pdev->dev; 1166 struct device *dev = &pdev->dev;
1142 struct fb_info *info = dev_get_drvdata(dev); 1167 struct fb_info *info = dev_get_drvdata(dev);
1143 struct atmel_lcdfb_info *sinfo; 1168 struct atmel_lcdfb_info *sinfo;
1169 struct atmel_lcdfb_pdata *pdata;
1144 1170
1145 if (!info || !info->par) 1171 if (!info || !info->par)
1146 return 0; 1172 return 0;
1147 sinfo = info->par; 1173 sinfo = info->par;
1174 pdata = &sinfo->pdata;
1148 1175
1149 cancel_work_sync(&sinfo->task); 1176 cancel_work_sync(&sinfo->task);
1150 exit_backlight(sinfo); 1177 exit_backlight(sinfo);
1151 if (sinfo->atmel_lcdfb_power_control) 1178 if (pdata->atmel_lcdfb_power_control)
1152 sinfo->atmel_lcdfb_power_control(0); 1179 pdata->atmel_lcdfb_power_control(0);
1153 unregister_framebuffer(info); 1180 unregister_framebuffer(info);
1154 atmel_lcdfb_stop_clock(sinfo); 1181 atmel_lcdfb_stop_clock(sinfo);
1155 clk_put(sinfo->lcdc_clk); 1182 clk_put(sinfo->lcdc_clk);
@@ -1176,6 +1203,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1176{ 1203{
1177 struct fb_info *info = platform_get_drvdata(pdev); 1204 struct fb_info *info = platform_get_drvdata(pdev);
1178 struct atmel_lcdfb_info *sinfo = info->par; 1205 struct atmel_lcdfb_info *sinfo = info->par;
1206 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
1179 1207
1180 /* 1208 /*
1181 * We don't want to handle interrupts while the clock is 1209 * We don't want to handle interrupts while the clock is
@@ -1185,8 +1213,8 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
1185 1213
1186 sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR); 1214 sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
1187 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); 1215 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
1188 if (sinfo->atmel_lcdfb_power_control) 1216 if (pdata->atmel_lcdfb_power_control)
1189 sinfo->atmel_lcdfb_power_control(0); 1217 pdata->atmel_lcdfb_power_control(0);
1190 1218
1191 atmel_lcdfb_stop(sinfo); 1219 atmel_lcdfb_stop(sinfo);
1192 atmel_lcdfb_stop_clock(sinfo); 1220 atmel_lcdfb_stop_clock(sinfo);
@@ -1198,11 +1226,12 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
1198{ 1226{
1199 struct fb_info *info = platform_get_drvdata(pdev); 1227 struct fb_info *info = platform_get_drvdata(pdev);
1200 struct atmel_lcdfb_info *sinfo = info->par; 1228 struct atmel_lcdfb_info *sinfo = info->par;
1229 struct atmel_lcdfb_pdata *pdata = &sinfo->pdata;
1201 1230
1202 atmel_lcdfb_start_clock(sinfo); 1231 atmel_lcdfb_start_clock(sinfo);
1203 atmel_lcdfb_start(sinfo); 1232 atmel_lcdfb_start(sinfo);
1204 if (sinfo->atmel_lcdfb_power_control) 1233 if (pdata->atmel_lcdfb_power_control)
1205 sinfo->atmel_lcdfb_power_control(1); 1234 pdata->atmel_lcdfb_power_control(1);
1206 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); 1235 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
1207 1236
1208 /* Enable FIFO & DMA errors */ 1237 /* Enable FIFO & DMA errors */