diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-03-21 13:08:49 -0400 |
---|---|---|
committer | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2007-05-15 08:13:27 -0400 |
commit | d0a2b7af27f6d01a443f3af8252fa0b955bf1913 (patch) | |
tree | 2240f60b5e4f5cd4abec83812048962b4b959b88 /arch/avr32/mach-at32ap | |
parent | 78c129b949bdee21dd996ac5f5cfc655cd5bd42e (diff) |
[AVR32] Implement platform hooks for atmel_lcdfb driver
This modifies and extends the existing lcdc platform code to support
the new atmel_lcdfb driver. The ATSTK1000 board code is set up to use
the on-board Samsung LTV350QV LCD panel.
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/mach-at32ap')
-rw-r--r-- | arch/avr32/mach-at32ap/at32ap7000.c | 77 |
1 files changed, 60 insertions, 17 deletions
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c index 56db45b99a0f..1d2bf347a1d6 100644 --- a/arch/avr32/mach-at32ap/at32ap7000.c +++ b/arch/avr32/mach-at32ap/at32ap7000.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | #include <linux/clk.h> | 8 | #include <linux/clk.h> |
9 | #include <linux/fb.h> | ||
9 | #include <linux/init.h> | 10 | #include <linux/init.h> |
10 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
11 | #include <linux/spi/spi.h> | 12 | #include <linux/spi/spi.h> |
@@ -17,6 +18,8 @@ | |||
17 | #include <asm/arch/portmux.h> | 18 | #include <asm/arch/portmux.h> |
18 | #include <asm/arch/sm.h> | 19 | #include <asm/arch/sm.h> |
19 | 20 | ||
21 | #include <video/atmel_lcdc.h> | ||
22 | |||
20 | #include "clock.h" | 23 | #include "clock.h" |
21 | #include "hmatrix.h" | 24 | #include "hmatrix.h" |
22 | #include "pio.h" | 25 | #include "pio.h" |
@@ -881,20 +884,26 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n) | |||
881 | /* -------------------------------------------------------------------- | 884 | /* -------------------------------------------------------------------- |
882 | * LCDC | 885 | * LCDC |
883 | * -------------------------------------------------------------------- */ | 886 | * -------------------------------------------------------------------- */ |
884 | static struct lcdc_platform_data lcdc0_data; | 887 | static struct atmel_lcdfb_info atmel_lcdfb0_data; |
885 | static struct resource lcdc0_resource[] = { | 888 | static struct resource atmel_lcdfb0_resource[] = { |
886 | { | 889 | { |
887 | .start = 0xff000000, | 890 | .start = 0xff000000, |
888 | .end = 0xff000fff, | 891 | .end = 0xff000fff, |
889 | .flags = IORESOURCE_MEM, | 892 | .flags = IORESOURCE_MEM, |
890 | }, | 893 | }, |
891 | IRQ(1), | 894 | IRQ(1), |
895 | { | ||
896 | /* Placeholder for pre-allocated fb memory */ | ||
897 | .start = 0x00000000, | ||
898 | .end = 0x00000000, | ||
899 | .flags = 0, | ||
900 | }, | ||
892 | }; | 901 | }; |
893 | DEFINE_DEV_DATA(lcdc, 0); | 902 | DEFINE_DEV_DATA(atmel_lcdfb, 0); |
894 | DEV_CLK(hclk, lcdc0, hsb, 7); | 903 | DEV_CLK(hck1, atmel_lcdfb0, hsb, 7); |
895 | static struct clk lcdc0_pixclk = { | 904 | static struct clk atmel_lcdfb0_pixclk = { |
896 | .name = "pixclk", | 905 | .name = "lcdc_clk", |
897 | .dev = &lcdc0_device.dev, | 906 | .dev = &atmel_lcdfb0_device.dev, |
898 | .mode = genclk_mode, | 907 | .mode = genclk_mode, |
899 | .get_rate = genclk_get_rate, | 908 | .get_rate = genclk_get_rate, |
900 | .set_rate = genclk_set_rate, | 909 | .set_rate = genclk_set_rate, |
@@ -903,13 +912,34 @@ static struct clk lcdc0_pixclk = { | |||
903 | }; | 912 | }; |
904 | 913 | ||
905 | struct platform_device *__init | 914 | struct platform_device *__init |
906 | at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data) | 915 | at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data, |
916 | unsigned long fbmem_start, unsigned long fbmem_len) | ||
907 | { | 917 | { |
908 | struct platform_device *pdev; | 918 | struct platform_device *pdev; |
919 | struct atmel_lcdfb_info *info; | ||
920 | struct fb_monspecs *monspecs; | ||
921 | struct fb_videomode *modedb; | ||
922 | unsigned int modedb_size; | ||
923 | |||
924 | /* | ||
925 | * Do a deep copy of the fb data, monspecs and modedb. Make | ||
926 | * sure all allocations are done before setting up the | ||
927 | * portmux. | ||
928 | */ | ||
929 | monspecs = kmemdup(data->default_monspecs, | ||
930 | sizeof(struct fb_monspecs), GFP_KERNEL); | ||
931 | if (!monspecs) | ||
932 | return NULL; | ||
933 | |||
934 | modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len; | ||
935 | modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL); | ||
936 | if (!modedb) | ||
937 | goto err_dup_modedb; | ||
938 | monspecs->modedb = modedb; | ||
909 | 939 | ||
910 | switch (id) { | 940 | switch (id) { |
911 | case 0: | 941 | case 0: |
912 | pdev = &lcdc0_device; | 942 | pdev = &atmel_lcdfb0_device; |
913 | select_peripheral(PC(19), PERIPH_A, 0); /* CC */ | 943 | select_peripheral(PC(19), PERIPH_A, 0); /* CC */ |
914 | select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ | 944 | select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */ |
915 | select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ | 945 | select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */ |
@@ -942,19 +972,32 @@ at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data) | |||
942 | select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ | 972 | select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */ |
943 | select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ | 973 | select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */ |
944 | 974 | ||
945 | clk_set_parent(&lcdc0_pixclk, &pll0); | 975 | clk_set_parent(&atmel_lcdfb0_pixclk, &pll0); |
946 | clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0)); | 976 | clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0)); |
947 | break; | 977 | break; |
948 | 978 | ||
949 | default: | 979 | default: |
950 | return NULL; | 980 | goto err_invalid_id; |
951 | } | 981 | } |
952 | 982 | ||
953 | memcpy(pdev->dev.platform_data, data, | 983 | if (fbmem_len) { |
954 | sizeof(struct lcdc_platform_data)); | 984 | pdev->resource[2].start = fbmem_start; |
985 | pdev->resource[2].end = fbmem_start + fbmem_len - 1; | ||
986 | pdev->resource[2].flags = IORESOURCE_MEM; | ||
987 | } | ||
988 | |||
989 | info = pdev->dev.platform_data; | ||
990 | memcpy(info, data, sizeof(struct atmel_lcdfb_info)); | ||
991 | info->default_monspecs = monspecs; | ||
955 | 992 | ||
956 | platform_device_register(pdev); | 993 | platform_device_register(pdev); |
957 | return pdev; | 994 | return pdev; |
995 | |||
996 | err_invalid_id: | ||
997 | kfree(modedb); | ||
998 | err_dup_modedb: | ||
999 | kfree(monspecs); | ||
1000 | return NULL; | ||
958 | } | 1001 | } |
959 | 1002 | ||
960 | /* -------------------------------------------------------------------- | 1003 | /* -------------------------------------------------------------------- |
@@ -1037,8 +1080,8 @@ struct clk *at32_clock_list[] = { | |||
1037 | &macb1_pclk, | 1080 | &macb1_pclk, |
1038 | &atmel_spi0_spi_clk, | 1081 | &atmel_spi0_spi_clk, |
1039 | &atmel_spi1_spi_clk, | 1082 | &atmel_spi1_spi_clk, |
1040 | &lcdc0_hclk, | 1083 | &atmel_lcdfb0_hck1, |
1041 | &lcdc0_pixclk, | 1084 | &atmel_lcdfb0_pixclk, |
1042 | &gclk0, | 1085 | &gclk0, |
1043 | &gclk1, | 1086 | &gclk1, |
1044 | &gclk2, | 1087 | &gclk2, |
@@ -1077,7 +1120,7 @@ void __init at32_clock_init(void) | |||
1077 | genclk_init_parent(&gclk2); | 1120 | genclk_init_parent(&gclk2); |
1078 | genclk_init_parent(&gclk3); | 1121 | genclk_init_parent(&gclk3); |
1079 | genclk_init_parent(&gclk4); | 1122 | genclk_init_parent(&gclk4); |
1080 | genclk_init_parent(&lcdc0_pixclk); | 1123 | genclk_init_parent(&atmel_lcdfb0_pixclk); |
1081 | 1124 | ||
1082 | /* | 1125 | /* |
1083 | * Turn on all clocks that have at least one user already, and | 1126 | * Turn on all clocks that have at least one user already, and |