Commit | Line | Data |
---|---|---|
5f97f7f9 HS |
1 | /* |
2 | * ATSTK1002 daughterboard-specific init code | |
3 | * | |
4 | * Copyright (C) 2005-2006 Atmel Corporation | |
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 | */ | |
c164b901 HS |
10 | #include <linux/clk.h> |
11 | #include <linux/etherdevice.h> | |
5f97f7f9 | 12 | #include <linux/init.h> |
a6f92f3d | 13 | #include <linux/kernel.h> |
ad93ab0a | 14 | #include <linux/leds.h> |
c164b901 | 15 | #include <linux/platform_device.h> |
a6f92f3d HS |
16 | #include <linux/string.h> |
17 | #include <linux/types.h> | |
3d60ee1b | 18 | #include <linux/spi/spi.h> |
5f97f7f9 | 19 | |
d0a2b7af HS |
20 | #include <video/atmel_lcdc.h> |
21 | ||
c164b901 | 22 | #include <asm/io.h> |
a6f92f3d | 23 | #include <asm/setup.h> |
3d60ee1b | 24 | #include <asm/arch/at32ap7000.h> |
5f97f7f9 | 25 | #include <asm/arch/board.h> |
c194588d | 26 | #include <asm/arch/init.h> |
7f9f4678 | 27 | #include <asm/arch/portmux.h> |
5f97f7f9 | 28 | |
d0a2b7af | 29 | #include "atstk1000.h" |
a3d912c8 | 30 | |
a3d912c8 | 31 | |
c164b901 HS |
32 | struct eth_addr { |
33 | u8 addr[6]; | |
34 | }; | |
35 | ||
36 | static struct eth_addr __initdata hw_addr[2]; | |
587ca761 HS |
37 | static struct eth_platform_data __initdata eth_data[2] = { |
38 | { | |
39 | /* | |
40 | * The MDIO pullups on STK1000 are a bit too weak for | |
41 | * the autodetection to work properly, so we have to | |
42 | * mask out everything but the correct address. | |
43 | */ | |
44 | .phy_mask = ~(1U << 16), | |
45 | }, | |
46 | { | |
47 | .phy_mask = ~(1U << 17), | |
48 | }, | |
49 | }; | |
5f97f7f9 | 50 | |
a8e93ed8 | 51 | #ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM |
41d8ca45 | 52 | static struct spi_board_info spi0_board_info[] __initdata = { |
3d60ee1b | 53 | { |
41d8ca45 | 54 | /* QVGA display */ |
3d60ee1b | 55 | .modalias = "ltv350qv", |
3d60ee1b | 56 | .max_speed_hz = 16000000, |
3d60ee1b | 57 | .chip_select = 1, |
2fdfe8d9 | 58 | .mode = SPI_MODE_3, |
3d60ee1b HS |
59 | }, |
60 | }; | |
a8e93ed8 DB |
61 | #endif |
62 | ||
63 | #ifdef CONFIG_BOARD_ATSTK1002_SPI1 | |
64 | static struct spi_board_info spi1_board_info[] __initdata = { { | |
65 | /* patch in custom entries here */ | |
66 | } }; | |
67 | #endif | |
3d60ee1b | 68 | |
c164b901 HS |
69 | /* |
70 | * The next two functions should go away as the boot loader is | |
71 | * supposed to initialize the macb address registers with a valid | |
72 | * ethernet address. But we need to keep it around for a while until | |
73 | * we can be reasonably sure the boot loader does this. | |
74 | * | |
75 | * The phy_id is ignored as the driver will probe for it. | |
76 | */ | |
a6f92f3d HS |
77 | static int __init parse_tag_ethernet(struct tag *tag) |
78 | { | |
79 | int i; | |
80 | ||
81 | i = tag->u.ethernet.mac_index; | |
c164b901 HS |
82 | if (i < ARRAY_SIZE(hw_addr)) |
83 | memcpy(hw_addr[i].addr, tag->u.ethernet.hw_address, | |
84 | sizeof(hw_addr[i].addr)); | |
85 | ||
a6f92f3d HS |
86 | return 0; |
87 | } | |
88 | __tagtable(ATAG_ETHERNET, parse_tag_ethernet); | |
89 | ||
c164b901 HS |
90 | static void __init set_hw_addr(struct platform_device *pdev) |
91 | { | |
92 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
93 | const u8 *addr; | |
94 | void __iomem *regs; | |
95 | struct clk *pclk; | |
96 | ||
97 | if (!res) | |
98 | return; | |
99 | if (pdev->id >= ARRAY_SIZE(hw_addr)) | |
100 | return; | |
101 | ||
102 | addr = hw_addr[pdev->id].addr; | |
103 | if (!is_valid_ether_addr(addr)) | |
104 | return; | |
105 | ||
106 | /* | |
107 | * Since this is board-specific code, we'll cheat and use the | |
108 | * physical address directly as we happen to know that it's | |
109 | * the same as the virtual address. | |
110 | */ | |
111 | regs = (void __iomem __force *)res->start; | |
112 | pclk = clk_get(&pdev->dev, "pclk"); | |
113 | if (!pclk) | |
114 | return; | |
115 | ||
116 | clk_enable(pclk); | |
117 | __raw_writel((addr[3] << 24) | (addr[2] << 16) | |
118 | | (addr[1] << 8) | addr[0], regs + 0x98); | |
119 | __raw_writel((addr[5] << 8) | addr[4], regs + 0x9c); | |
120 | clk_disable(pclk); | |
121 | clk_put(pclk); | |
122 | } | |
123 | ||
ad93ab0a DB |
124 | #ifdef CONFIG_BOARD_ATSTK1002_J2_LED |
125 | ||
126 | static struct gpio_led stk_j2_led[] = { | |
127 | #ifdef CONFIG_BOARD_ATSTK1002_J2_LED8 | |
128 | #define LEDSTRING "J2 jumpered to LED8" | |
129 | { .name = "led0:amber", .gpio = GPIO_PIN_PB( 8), }, | |
130 | { .name = "led1:amber", .gpio = GPIO_PIN_PB( 9), }, | |
131 | { .name = "led2:amber", .gpio = GPIO_PIN_PB(10), }, | |
132 | { .name = "led3:amber", .gpio = GPIO_PIN_PB(13), }, | |
133 | { .name = "led4:amber", .gpio = GPIO_PIN_PB(14), }, | |
134 | { .name = "led5:amber", .gpio = GPIO_PIN_PB(15), }, | |
135 | { .name = "led6:amber", .gpio = GPIO_PIN_PB(16), }, | |
136 | { .name = "led7:amber", .gpio = GPIO_PIN_PB(30), | |
137 | .default_trigger = "heartbeat", }, | |
138 | #else /* RGB */ | |
139 | #define LEDSTRING "J2 jumpered to RGB LEDs" | |
140 | { .name = "r1:red", .gpio = GPIO_PIN_PB( 8), }, | |
141 | { .name = "g1:green", .gpio = GPIO_PIN_PB(10), }, | |
142 | { .name = "b1:blue", .gpio = GPIO_PIN_PB(14), }, | |
143 | ||
144 | { .name = "r2:red", .gpio = GPIO_PIN_PB( 9), | |
145 | .default_trigger = "heartbeat", }, | |
146 | { .name = "g2:green", .gpio = GPIO_PIN_PB(13), }, | |
147 | { .name = "b2:blue", .gpio = GPIO_PIN_PB(15), | |
148 | .default_trigger = "heartbeat", }, | |
149 | /* PB16, PB30 unused */ | |
150 | #endif | |
151 | }; | |
152 | ||
153 | static struct gpio_led_platform_data stk_j2_led_data = { | |
154 | .num_leds = ARRAY_SIZE(stk_j2_led), | |
155 | .leds = stk_j2_led, | |
156 | }; | |
157 | ||
158 | static struct platform_device stk_j2_led_dev = { | |
159 | .name = "leds-gpio", | |
160 | .id = 2, /* gpio block J2 */ | |
161 | .dev = { | |
162 | .platform_data = &stk_j2_led_data, | |
163 | }, | |
164 | }; | |
165 | ||
166 | static void setup_j2_leds(void) | |
167 | { | |
168 | unsigned i; | |
169 | ||
170 | for (i = 0; i < ARRAY_SIZE(stk_j2_led); i++) | |
171 | at32_select_gpio(stk_j2_led[i].gpio, AT32_GPIOF_OUTPUT); | |
172 | ||
173 | printk("STK1002: " LEDSTRING "\n"); | |
174 | platform_device_register(&stk_j2_led_dev); | |
175 | } | |
176 | ||
177 | #else | |
178 | static void setup_j2_leds(void) | |
179 | { | |
180 | } | |
181 | #endif | |
182 | ||
c194588d HS |
183 | void __init setup_board(void) |
184 | { | |
a8e93ed8 | 185 | #ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM |
a3d912c8 | 186 | at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */ |
a8e93ed8 DB |
187 | #else |
188 | at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */ | |
a3d912c8 DB |
189 | #endif |
190 | /* USART 2/unused: expansion connector */ | |
191 | at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */ | |
c194588d HS |
192 | |
193 | at32_setup_serial_console(0); | |
194 | } | |
195 | ||
5f97f7f9 HS |
196 | static int __init atstk1002_init(void) |
197 | { | |
7f9f4678 HS |
198 | /* |
199 | * ATSTK1000 uses 32-bit SDRAM interface. Reserve the | |
200 | * SDRAM-specific pins so that nobody messes with them. | |
201 | */ | |
202 | at32_reserve_pin(GPIO_PIN_PE(0)); /* DATA[16] */ | |
203 | at32_reserve_pin(GPIO_PIN_PE(1)); /* DATA[17] */ | |
204 | at32_reserve_pin(GPIO_PIN_PE(2)); /* DATA[18] */ | |
205 | at32_reserve_pin(GPIO_PIN_PE(3)); /* DATA[19] */ | |
206 | at32_reserve_pin(GPIO_PIN_PE(4)); /* DATA[20] */ | |
207 | at32_reserve_pin(GPIO_PIN_PE(5)); /* DATA[21] */ | |
208 | at32_reserve_pin(GPIO_PIN_PE(6)); /* DATA[22] */ | |
209 | at32_reserve_pin(GPIO_PIN_PE(7)); /* DATA[23] */ | |
210 | at32_reserve_pin(GPIO_PIN_PE(8)); /* DATA[24] */ | |
211 | at32_reserve_pin(GPIO_PIN_PE(9)); /* DATA[25] */ | |
212 | at32_reserve_pin(GPIO_PIN_PE(10)); /* DATA[26] */ | |
213 | at32_reserve_pin(GPIO_PIN_PE(11)); /* DATA[27] */ | |
214 | at32_reserve_pin(GPIO_PIN_PE(12)); /* DATA[28] */ | |
215 | at32_reserve_pin(GPIO_PIN_PE(13)); /* DATA[29] */ | |
216 | at32_reserve_pin(GPIO_PIN_PE(14)); /* DATA[30] */ | |
217 | at32_reserve_pin(GPIO_PIN_PE(15)); /* DATA[31] */ | |
218 | at32_reserve_pin(GPIO_PIN_PE(26)); /* SDCS */ | |
219 | ||
5f97f7f9 HS |
220 | at32_add_system_devices(); |
221 | ||
a8e93ed8 | 222 | #ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM |
c194588d | 223 | at32_add_device_usart(1); |
a8e93ed8 DB |
224 | #else |
225 | at32_add_device_usart(0); | |
a3d912c8 | 226 | #endif |
c194588d | 227 | at32_add_device_usart(2); |
5f97f7f9 | 228 | |
d4003ba0 | 229 | #ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM |
c164b901 | 230 | set_hw_addr(at32_add_device_eth(0, ð_data[0])); |
d4003ba0 | 231 | #endif |
a8e93ed8 | 232 | #ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM |
41d8ca45 | 233 | at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info)); |
a8e93ed8 DB |
234 | #endif |
235 | #ifdef CONFIG_BOARD_ATSTK1002_SPI1 | |
236 | at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info)); | |
237 | #endif | |
238 | #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM | |
239 | set_hw_addr(at32_add_device_eth(1, ð_data[1])); | |
240 | #else | |
d0a2b7af HS |
241 | at32_add_device_lcdc(0, &atstk1000_lcdc_data, |
242 | fbmem_start, fbmem_size); | |
a8e93ed8 | 243 | #endif |
95a42267 HCE |
244 | #ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM |
245 | at32_add_device_ssc(0, ATMEL_SSC_TX); | |
246 | #endif | |
5f97f7f9 | 247 | |
ad93ab0a DB |
248 | setup_j2_leds(); |
249 | ||
5f97f7f9 HS |
250 | return 0; |
251 | } | |
252 | postcore_initcall(atstk1002_init); |