diff options
Diffstat (limited to 'drivers/video/atmel_lcdfb.c')
-rw-r--r-- | drivers/video/atmel_lcdfb.c | 120 |
1 files changed, 92 insertions, 28 deletions
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 025428e04c33..c1a2914447e1 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c | |||
@@ -34,6 +34,77 @@ | |||
34 | #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ | 34 | #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */ |
35 | #define ATMEL_LCDC_FIFO_SIZE 512 /* words */ | 35 | #define ATMEL_LCDC_FIFO_SIZE 512 /* words */ |
36 | 36 | ||
37 | struct atmel_lcdfb_config { | ||
38 | bool have_alt_pixclock; | ||
39 | bool have_hozval; | ||
40 | bool have_intensity_bit; | ||
41 | }; | ||
42 | |||
43 | static struct atmel_lcdfb_config at91sam9261_config = { | ||
44 | .have_hozval = true, | ||
45 | .have_intensity_bit = true, | ||
46 | }; | ||
47 | |||
48 | static struct atmel_lcdfb_config at91sam9263_config = { | ||
49 | .have_intensity_bit = true, | ||
50 | }; | ||
51 | |||
52 | static struct atmel_lcdfb_config at91sam9g10_config = { | ||
53 | .have_hozval = true, | ||
54 | }; | ||
55 | |||
56 | static struct atmel_lcdfb_config at91sam9g45_config = { | ||
57 | .have_alt_pixclock = true, | ||
58 | }; | ||
59 | |||
60 | static struct atmel_lcdfb_config at91sam9g45es_config = { | ||
61 | }; | ||
62 | |||
63 | static struct atmel_lcdfb_config at91sam9rl_config = { | ||
64 | .have_intensity_bit = true, | ||
65 | }; | ||
66 | |||
67 | static struct atmel_lcdfb_config at32ap_config = { | ||
68 | .have_hozval = true, | ||
69 | }; | ||
70 | |||
71 | static const struct platform_device_id atmel_lcdfb_devtypes[] = { | ||
72 | { | ||
73 | .name = "at91sam9261-lcdfb", | ||
74 | .driver_data = (unsigned long)&at91sam9261_config, | ||
75 | }, { | ||
76 | .name = "at91sam9263-lcdfb", | ||
77 | .driver_data = (unsigned long)&at91sam9263_config, | ||
78 | }, { | ||
79 | .name = "at91sam9g10-lcdfb", | ||
80 | .driver_data = (unsigned long)&at91sam9g10_config, | ||
81 | }, { | ||
82 | .name = "at91sam9g45-lcdfb", | ||
83 | .driver_data = (unsigned long)&at91sam9g45_config, | ||
84 | }, { | ||
85 | .name = "at91sam9g45es-lcdfb", | ||
86 | .driver_data = (unsigned long)&at91sam9g45es_config, | ||
87 | }, { | ||
88 | .name = "at91sam9rl-lcdfb", | ||
89 | .driver_data = (unsigned long)&at91sam9rl_config, | ||
90 | }, { | ||
91 | .name = "at32ap-lcdfb", | ||
92 | .driver_data = (unsigned long)&at32ap_config, | ||
93 | }, { | ||
94 | /* terminator */ | ||
95 | } | ||
96 | }; | ||
97 | |||
98 | static struct atmel_lcdfb_config * | ||
99 | atmel_lcdfb_get_config(struct platform_device *pdev) | ||
100 | { | ||
101 | unsigned long data; | ||
102 | |||
103 | data = platform_get_device_id(pdev)->driver_data; | ||
104 | |||
105 | return (struct atmel_lcdfb_config *)data; | ||
106 | } | ||
107 | |||
37 | #if defined(CONFIG_ARCH_AT91) | 108 | #if defined(CONFIG_ARCH_AT91) |
38 | #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ | 109 | #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ |
39 | | FBINFO_PARTIAL_PAN_OK \ | 110 | | FBINFO_PARTIAL_PAN_OK \ |
@@ -193,14 +264,16 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { | |||
193 | .accel = FB_ACCEL_NONE, | 264 | .accel = FB_ACCEL_NONE, |
194 | }; | 265 | }; |
195 | 266 | ||
196 | static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) | 267 | static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo, |
268 | unsigned long xres) | ||
197 | { | 269 | { |
270 | unsigned long lcdcon2; | ||
198 | unsigned long value; | 271 | unsigned long value; |
199 | 272 | ||
200 | if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10() | 273 | if (!sinfo->config->have_hozval) |
201 | || cpu_is_at32ap7000())) | ||
202 | return xres; | 274 | return xres; |
203 | 275 | ||
276 | lcdcon2 = lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2); | ||
204 | value = xres; | 277 | value = xres; |
205 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { | 278 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { |
206 | /* STN display */ | 279 | /* STN display */ |
@@ -423,7 +496,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
423 | break; | 496 | break; |
424 | case 16: | 497 | case 16: |
425 | /* Older SOCs use IBGR:555 rather than BGR:565. */ | 498 | /* Older SOCs use IBGR:555 rather than BGR:565. */ |
426 | if (sinfo->have_intensity_bit) | 499 | if (sinfo->config->have_intensity_bit) |
427 | var->green.length = 5; | 500 | var->green.length = 5; |
428 | else | 501 | else |
429 | var->green.length = 6; | 502 | var->green.length = 6; |
@@ -531,7 +604,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
531 | /* Now, the LCDC core... */ | 604 | /* Now, the LCDC core... */ |
532 | 605 | ||
533 | /* Set pixel clock */ | 606 | /* Set pixel clock */ |
534 | if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) | 607 | if (sinfo->config->have_alt_pixclock) |
535 | pix_factor = 1; | 608 | pix_factor = 1; |
536 | 609 | ||
537 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; | 610 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; |
@@ -591,8 +664,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
591 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); | 664 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); |
592 | 665 | ||
593 | /* Horizontal value (aka line size) */ | 666 | /* Horizontal value (aka line size) */ |
594 | hozval_linesz = compute_hozval(info->var.xres, | 667 | hozval_linesz = compute_hozval(sinfo, info->var.xres); |
595 | lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); | ||
596 | 668 | ||
597 | /* Display size */ | 669 | /* Display size */ |
598 | value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; | 670 | value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; |
@@ -684,7 +756,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, | |||
684 | 756 | ||
685 | case FB_VISUAL_PSEUDOCOLOR: | 757 | case FB_VISUAL_PSEUDOCOLOR: |
686 | if (regno < 256) { | 758 | if (regno < 256) { |
687 | if (sinfo->have_intensity_bit) { | 759 | if (sinfo->config->have_intensity_bit) { |
688 | /* old style I+BGR:555 */ | 760 | /* old style I+BGR:555 */ |
689 | val = ((red >> 11) & 0x001f); | 761 | val = ((red >> 11) & 0x001f); |
690 | val |= ((green >> 6) & 0x03e0); | 762 | val |= ((green >> 6) & 0x03e0); |
@@ -821,15 +893,13 @@ static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) | |||
821 | 893 | ||
822 | static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo) | 894 | static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo) |
823 | { | 895 | { |
824 | if (sinfo->bus_clk) | 896 | clk_enable(sinfo->bus_clk); |
825 | clk_enable(sinfo->bus_clk); | ||
826 | clk_enable(sinfo->lcdc_clk); | 897 | clk_enable(sinfo->lcdc_clk); |
827 | } | 898 | } |
828 | 899 | ||
829 | static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) | 900 | static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) |
830 | { | 901 | { |
831 | if (sinfo->bus_clk) | 902 | clk_disable(sinfo->bus_clk); |
832 | clk_disable(sinfo->bus_clk); | ||
833 | clk_disable(sinfo->lcdc_clk); | 903 | clk_disable(sinfo->lcdc_clk); |
834 | } | 904 | } |
835 | 905 | ||
@@ -874,10 +944,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) | |||
874 | } | 944 | } |
875 | sinfo->info = info; | 945 | sinfo->info = info; |
876 | sinfo->pdev = pdev; | 946 | sinfo->pdev = pdev; |
877 | if (cpu_is_at91sam9261() || cpu_is_at91sam9263() || | 947 | sinfo->config = atmel_lcdfb_get_config(pdev); |
878 | cpu_is_at91sam9rl()) { | 948 | if (!sinfo->config) |
879 | sinfo->have_intensity_bit = true; | 949 | goto free_info; |
880 | } | ||
881 | 950 | ||
882 | strcpy(info->fix.id, sinfo->pdev->name); | 951 | strcpy(info->fix.id, sinfo->pdev->name); |
883 | info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; | 952 | info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; |
@@ -888,13 +957,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) | |||
888 | info->fix = atmel_lcdfb_fix; | 957 | info->fix = atmel_lcdfb_fix; |
889 | 958 | ||
890 | /* Enable LCDC Clocks */ | 959 | /* Enable LCDC Clocks */ |
891 | if (cpu_is_at91sam9261() || cpu_is_at91sam9g10() | 960 | sinfo->bus_clk = clk_get(dev, "hclk"); |
892 | || cpu_is_at32ap7000()) { | 961 | if (IS_ERR(sinfo->bus_clk)) { |
893 | sinfo->bus_clk = clk_get(dev, "hck1"); | 962 | ret = PTR_ERR(sinfo->bus_clk); |
894 | if (IS_ERR(sinfo->bus_clk)) { | 963 | goto free_info; |
895 | ret = PTR_ERR(sinfo->bus_clk); | ||
896 | goto free_info; | ||
897 | } | ||
898 | } | 964 | } |
899 | sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); | 965 | sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); |
900 | if (IS_ERR(sinfo->lcdc_clk)) { | 966 | if (IS_ERR(sinfo->lcdc_clk)) { |
@@ -1055,8 +1121,7 @@ stop_clk: | |||
1055 | atmel_lcdfb_stop_clock(sinfo); | 1121 | atmel_lcdfb_stop_clock(sinfo); |
1056 | clk_put(sinfo->lcdc_clk); | 1122 | clk_put(sinfo->lcdc_clk); |
1057 | put_bus_clk: | 1123 | put_bus_clk: |
1058 | if (sinfo->bus_clk) | 1124 | clk_put(sinfo->bus_clk); |
1059 | clk_put(sinfo->bus_clk); | ||
1060 | free_info: | 1125 | free_info: |
1061 | framebuffer_release(info); | 1126 | framebuffer_release(info); |
1062 | out: | 1127 | out: |
@@ -1081,8 +1146,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) | |||
1081 | unregister_framebuffer(info); | 1146 | unregister_framebuffer(info); |
1082 | atmel_lcdfb_stop_clock(sinfo); | 1147 | atmel_lcdfb_stop_clock(sinfo); |
1083 | clk_put(sinfo->lcdc_clk); | 1148 | clk_put(sinfo->lcdc_clk); |
1084 | if (sinfo->bus_clk) | 1149 | clk_put(sinfo->bus_clk); |
1085 | clk_put(sinfo->bus_clk); | ||
1086 | fb_dealloc_cmap(&info->cmap); | 1150 | fb_dealloc_cmap(&info->cmap); |
1087 | free_irq(sinfo->irq_base, info); | 1151 | free_irq(sinfo->irq_base, info); |
1088 | iounmap(sinfo->mmio); | 1152 | iounmap(sinfo->mmio); |
@@ -1151,7 +1215,7 @@ static struct platform_driver atmel_lcdfb_driver = { | |||
1151 | .remove = __exit_p(atmel_lcdfb_remove), | 1215 | .remove = __exit_p(atmel_lcdfb_remove), |
1152 | .suspend = atmel_lcdfb_suspend, | 1216 | .suspend = atmel_lcdfb_suspend, |
1153 | .resume = atmel_lcdfb_resume, | 1217 | .resume = atmel_lcdfb_resume, |
1154 | 1218 | .id_table = atmel_lcdfb_devtypes, | |
1155 | .driver = { | 1219 | .driver = { |
1156 | .name = "atmel_lcdfb", | 1220 | .name = "atmel_lcdfb", |
1157 | .owner = THIS_MODULE, | 1221 | .owner = THIS_MODULE, |