1/* 2 * ADM5120 generic platform devices 3 * 4 * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published 8 * by the Free Software Foundation. 9 * 10 */ 11 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/list.h> 15#include <linux/device.h> 16#include <linux/dma-mapping.h> 17#include <linux/platform_device.h> 18#include <linux/gpio.h> 19#include <linux/irq.h> 20#include <linux/slab.h> 21#include <linux/export.h> 22 23#include <asm/bootinfo.h> 24 25#include <asm/mach-adm5120/adm5120_defs.h> 26#include <asm/mach-adm5120/adm5120_info.h> 27#include <asm/mach-adm5120/adm5120_switch.h> 28#include <asm/mach-adm5120/adm5120_nand.h> 29#include <asm/mach-adm5120/adm5120_platform.h> 30 31#if 1 32/* 33 * TODO:remove global adm5120_eth* variables when the switch driver will be 34 * converted into a real platform driver 35 */ 36unsigned int adm5120_eth_num_ports = 6; 37EXPORT_SYMBOL_GPL(adm5120_eth_num_ports); 38 39unsigned char adm5120_eth_macs[6][6] = { 40 {'\00', 'A', 'D', 'M', '\x51', '\x20' }, 41 {'\00', 'A', 'D', 'M', '\x51', '\x21' }, 42 {'\00', 'A', 'D', 'M', '\x51', '\x22' }, 43 {'\00', 'A', 'D', 'M', '\x51', '\x23' }, 44 {'\00', 'A', 'D', 'M', '\x51', '\x24' }, 45 {'\00', 'A', 'D', 'M', '\x51', '\x25' } 46}; 47EXPORT_SYMBOL_GPL(adm5120_eth_macs); 48 49unsigned char adm5120_eth_vlans[6] = { 50 0x41, 0x42, 0x44, 0x48, 0x50, 0x60 51}; 52EXPORT_SYMBOL_GPL(adm5120_eth_vlans); 53#endif 54 55void __init adm5120_setup_eth_macs(u8 *mac_base) 56{ 57 u32 t; 58 int i, j; 59 60 t = ((u32) mac_base[3] << 16) | ((u32) mac_base[4] << 8) 61 | ((u32) mac_base[5]); 62 63 for (i = 0; i < ARRAY_SIZE(adm5120_eth_macs); i++) { 64 for (j = 0; j < 3; j++) 65 adm5120_eth_macs[i][j] = mac_base[j]; 66 67 adm5120_eth_macs[i][3] = (t >> 16) & 0xff; 68 adm5120_eth_macs[i][4] = (t >> 8) & 0xff; 69 adm5120_eth_macs[i][5] = t & 0xff; 70 71 t++; 72 } 73} 74 75/* 76 * Built-in ethernet switch 77 */ 78struct resource adm5120_switch_resources[] = { 79 [0] = { 80 .start = ADM5120_SWITCH_BASE, 81 .end = ADM5120_SWITCH_BASE+ADM5120_SWITCH_SIZE-1, 82 .flags = IORESOURCE_MEM, 83 }, 84 [1] = { 85 .start = ADM5120_IRQ_SWITCH, 86 .end = ADM5120_IRQ_SWITCH, 87 .flags = IORESOURCE_IRQ, 88 }, 89}; 90 91struct adm5120_switch_platform_data adm5120_switch_data; 92struct platform_device adm5120_switch_device = { 93 .name = "adm5120-switch", 94 .id = -1, 95 .num_resources = ARRAY_SIZE(adm5120_switch_resources), 96 .resource = adm5120_switch_resources, 97 .dev.platform_data = &adm5120_switch_data, 98}; 99 100void __init adm5120_add_device_switch(unsigned num_ports, u8 *vlan_map) 101{ 102 if (num_ports > 0) 103 adm5120_eth_num_ports = num_ports; 104 105 if (vlan_map) 106 memcpy(adm5120_eth_vlans, vlan_map, sizeof(adm5120_eth_vlans)); 107 108 platform_device_register(&adm5120_switch_device); 109} 110 111/* 112 * USB Host Controller 113 */ 114struct resource adm5120_hcd_resources[] = { 115 [0] = { 116 .start = ADM5120_USBC_BASE, 117 .end = ADM5120_USBC_BASE+ADM5120_USBC_SIZE-1, 118 .flags = IORESOURCE_MEM, 119 }, 120 [1] = { 121 .start = ADM5120_IRQ_USBC, 122 .end = ADM5120_IRQ_USBC, 123 .flags = IORESOURCE_IRQ, 124 }, 125}; 126 127static u64 adm5120_hcd_dma_mask = DMA_BIT_MASK(24); 128struct platform_device adm5120_hcd_device = { 129 .name = "adm5120-hcd", 130 .id = -1, 131 .num_resources = ARRAY_SIZE(adm5120_hcd_resources), 132 .resource = adm5120_hcd_resources, 133 .dev = { 134 .dma_mask = &adm5120_hcd_dma_mask, 135 .coherent_dma_mask = DMA_BIT_MASK(24), 136 } 137}; 138 139void __init adm5120_add_device_usb(void) 140{ 141 platform_device_register(&adm5120_hcd_device); 142} 143 144/* 145 * NOR flash devices 146 */ 147struct adm5120_flash_platform_data adm5120_flash0_data; 148struct platform_device adm5120_flash0_device = { 149 .name = "adm5120-flash", 150 .id = 0, 151 .dev.platform_data = &adm5120_flash0_data, 152}; 153 154struct adm5120_flash_platform_data adm5120_flash1_data; 155struct platform_device adm5120_flash1_device = { 156 .name = "adm5120-flash", 157 .id = 1, 158 .dev.platform_data = &adm5120_flash1_data, 159}; 160 161void __init adm5120_add_device_flash(unsigned id) 162{ 163 struct platform_device *pdev; 164 165 switch (id) { 166 case 0: 167 pdev = &adm5120_flash0_device; 168 break; 169 case 1: 170 pdev = &adm5120_flash1_device; 171 break; 172 default: 173 pdev = NULL; 174 break; 175 } 176 177 if (pdev) 178 platform_device_register(pdev); 179} 180 181/* 182 * built-in UARTs 183 */ 184static void adm5120_uart_set_mctrl(struct amba_device *dev, void __iomem *base, 185 unsigned int mctrl) 186{ 187} 188 189struct amba_pl010_data adm5120_uart0_data = { 190 .set_mctrl = adm5120_uart_set_mctrl 191}; 192 193struct amba_device adm5120_uart0_device = { 194 .dev = { 195 .init_name = "apb:uart0", 196 .platform_data = &adm5120_uart0_data, 197 }, 198 .res = { 199 .start = ADM5120_UART0_BASE, 200 .end = ADM5120_UART0_BASE + ADM5120_UART_SIZE - 1, 201 .flags = IORESOURCE_MEM, 202 }, 203 .irq = { ADM5120_IRQ_UART0, 0 }, 204 .periphid = 0x0041010, 205}; 206 207struct amba_pl010_data adm5120_uart1_data = { 208 .set_mctrl = adm5120_uart_set_mctrl 209}; 210 211struct amba_device adm5120_uart1_device = { 212 .dev = { 213 .init_name = "apb:uart1", 214 .platform_data = &adm5120_uart1_data, 215 }, 216 .res = { 217 .start = ADM5120_UART1_BASE, 218 .end = ADM5120_UART1_BASE + ADM5120_UART_SIZE - 1, 219 .flags = IORESOURCE_MEM, 220 }, 221 .irq = { ADM5120_IRQ_UART1, 0 }, 222 .periphid = 0x0041010, 223}; 224 225void __init adm5120_add_device_uart(unsigned id) 226{ 227 struct amba_device *dev; 228 229 switch (id) { 230 case 0: 231 dev = &adm5120_uart0_device; 232 break; 233 case 1: 234 dev = &adm5120_uart1_device; 235 break; 236 default: 237 dev = NULL; 238 break; 239 } 240 241 if (dev) 242 amba_device_register(dev, &iomem_resource); 243} 244 245/* 246 * GPIO buttons 247 */ 248void __init adm5120_register_gpio_buttons(int id, 249 unsigned poll_interval, 250 unsigned nbuttons, 251 struct gpio_keys_button *buttons) 252{ 253 struct platform_device *pdev; 254 struct gpio_keys_platform_data pdata; 255 struct gpio_keys_button *p; 256 int err; 257 258 p = kmemdup(buttons, nbuttons * sizeof(*p), GFP_KERNEL); 259 if (!p) 260 return; 261 262 pdev = platform_device_alloc("gpio-keys-polled", id); 263 if (!pdev) 264 goto err_free_buttons; 265 266 memset(&pdata, 0, sizeof(pdata)); 267 pdata.poll_interval = poll_interval; 268 pdata.nbuttons = nbuttons; 269 pdata.buttons = p; 270 271 err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); 272 if (err) 273 goto err_put_pdev; 274 275 err = platform_device_add(pdev); 276 if (err) 277 goto err_put_pdev; 278 279 return; 280 281err_put_pdev: 282 platform_device_put(pdev); 283 284err_free_buttons: 285 kfree(p); 286} 287 288/* 289 * GPIO LEDS 290 */ 291struct gpio_led_platform_data adm5120_gpio_leds_data; 292struct platform_device adm5120_gpio_leds_device = { 293 .name = "leds-gpio", 294 .id = -1, 295 .dev.platform_data = &adm5120_gpio_leds_data, 296}; 297 298void __init adm5120_add_device_gpio_leds(unsigned num_leds, 299 struct gpio_led *leds) 300{ 301 struct gpio_led *p; 302 303 p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL); 304 if (!p) 305 return; 306 307 memcpy(p, leds, num_leds * sizeof(*p)); 308 adm5120_gpio_leds_data.num_leds = num_leds; 309 adm5120_gpio_leds_data.leds = p; 310 311 platform_device_register(&adm5120_gpio_leds_device); 312} 313 314/* 315 * NAND flash 316 */ 317struct resource adm5120_nand_resources[] = { 318 [0] = { 319 .start = ADM5120_NAND_BASE, 320 .end = ADM5120_NAND_BASE + ADM5120_NAND_SIZE-1, 321 .flags = IORESOURCE_MEM, 322 }, 323}; 324 325static int adm5120_nand_ready(struct mtd_info *mtd) 326{ 327 return ((adm5120_nand_get_status() & ADM5120_NAND_STATUS_READY) != 0); 328} 329 330static void adm5120_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, 331 unsigned int ctrl) 332{ 333 if (ctrl & NAND_CTRL_CHANGE) { 334 adm5120_nand_set_cle(ctrl & NAND_CLE); 335 adm5120_nand_set_ale(ctrl & NAND_ALE); 336 adm5120_nand_set_cen(ctrl & NAND_NCE); 337 } 338 339 if (cmd != NAND_CMD_NONE) 340 NAND_WRITE_REG(NAND_REG_DATA, cmd); 341} 342 343void __init adm5120_add_device_nand(struct platform_nand_data *pdata) 344{ 345 struct platform_device *pdev; 346 int err; 347 348 pdev = platform_device_alloc("gen_nand", -1); 349 if (!pdev) 350 goto err_out; 351 352 err = platform_device_add_resources(pdev, adm5120_nand_resources, 353 ARRAY_SIZE(adm5120_nand_resources)); 354 if (err) 355 goto err_put; 356 357 err = platform_device_add_data(pdev, pdata, sizeof(*pdata)); 358 if (err) 359 goto err_put; 360 361 pdata = pdev->dev.platform_data; 362 pdata->ctrl.dev_ready = adm5120_nand_ready; 363 pdata->ctrl.cmd_ctrl = adm5120_nand_cmd_ctrl; 364 365 err = platform_device_add(pdev); 366 if (err) 367 goto err_put; 368 369 return; 370 371err_put: 372 platform_device_put(pdev); 373err_out: 374 return; 375} 376