1/* 2 * D-Link DIR-825 rev. B1 board support 3 * 4 * Copyright (C) 2009-2011 Lukas Kuna, Evkanet, s.r.o. 5 * 6 * based on mach-wndr3700.c 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License version 2 as published 10 * by the Free Software Foundation. 11 */ 12 13#include <linux/platform_device.h> 14#include <linux/delay.h> 15#include <linux/rtl8366.h> 16 17#include <asm/mach-ath79/ath79.h> 18 19#include "dev-eth.h" 20#include "dev-ap9x-pci.h" 21#include "dev-gpio-buttons.h" 22#include "dev-leds-gpio.h" 23#include "dev-m25p80.h" 24#include "dev-usb.h" 25#include "machtypes.h" 26 27#define DIR825B1_GPIO_LED_BLUE_USB 0 28#define DIR825B1_GPIO_LED_ORANGE_POWER 1 29#define DIR825B1_GPIO_LED_BLUE_POWER 2 30#define DIR825B1_GPIO_LED_BLUE_WPS 4 31#define DIR825B1_GPIO_LED_ORANGE_PLANET 6 32#define DIR825B1_GPIO_LED_BLUE_PLANET 11 33 34#define DIR825B1_GPIO_BTN_RESET 3 35#define DIR825B1_GPIO_BTN_WPS 8 36 37#define DIR825B1_GPIO_RTL8366_SDA 5 38#define DIR825B1_GPIO_RTL8366_SCK 7 39 40#define DIR825B1_KEYS_POLL_INTERVAL 20 /* msecs */ 41#define DIR825B1_KEYS_DEBOUNCE_INTERVAL (3 * DIR825B1_KEYS_POLL_INTERVAL) 42 43#define DIR825B1_CAL0_OFFSET 0x1000 44#define DIR825B1_CAL1_OFFSET 0x5000 45#define DIR825B1_MAC0_OFFSET 0xffa0 46#define DIR825B1_MAC1_OFFSET 0xffb4 47 48#define DIR825B1_CAL_LOCATION_0 0x1f660000 49#define DIR825B1_CAL_LOCATION_1 0x1f7f0000 50 51static struct gpio_led dir825b1_leds_gpio[] __initdata = { 52 { 53 .name = "d-link:blue:usb", 54 .gpio = DIR825B1_GPIO_LED_BLUE_USB, 55 .active_low = 1, 56 }, { 57 .name = "d-link:orange:power", 58 .gpio = DIR825B1_GPIO_LED_ORANGE_POWER, 59 .active_low = 1, 60 }, { 61 .name = "d-link:blue:power", 62 .gpio = DIR825B1_GPIO_LED_BLUE_POWER, 63 .active_low = 1, 64 }, { 65 .name = "d-link:blue:wps", 66 .gpio = DIR825B1_GPIO_LED_BLUE_WPS, 67 .active_low = 1, 68 }, { 69 .name = "d-link:orange:planet", 70 .gpio = DIR825B1_GPIO_LED_ORANGE_PLANET, 71 .active_low = 1, 72 }, { 73 .name = "d-link:blue:planet", 74 .gpio = DIR825B1_GPIO_LED_BLUE_PLANET, 75 .active_low = 1, 76 } 77}; 78 79static struct gpio_keys_button dir825b1_gpio_keys[] __initdata = { 80 { 81 .desc = "reset", 82 .type = EV_KEY, 83 .code = KEY_RESTART, 84 .debounce_interval = DIR825B1_KEYS_DEBOUNCE_INTERVAL, 85 .gpio = DIR825B1_GPIO_BTN_RESET, 86 .active_low = 1, 87 }, { 88 .desc = "wps", 89 .type = EV_KEY, 90 .code = KEY_WPS_BUTTON, 91 .debounce_interval = DIR825B1_KEYS_DEBOUNCE_INTERVAL, 92 .gpio = DIR825B1_GPIO_BTN_WPS, 93 .active_low = 1, 94 } 95}; 96 97static struct rtl8366_initval dir825b1_rtl8366s_initvals[] = { 98 { .reg = 0x06, .val = 0x0108 }, 99}; 100 101static struct rtl8366_platform_data dir825b1_rtl8366s_data = { 102 .gpio_sda = DIR825B1_GPIO_RTL8366_SDA, 103 .gpio_sck = DIR825B1_GPIO_RTL8366_SCK, 104 .num_initvals = ARRAY_SIZE(dir825b1_rtl8366s_initvals), 105 .initvals = dir825b1_rtl8366s_initvals, 106}; 107 108static struct platform_device dir825b1_rtl8366s_device = { 109 .name = RTL8366S_DRIVER_NAME, 110 .id = -1, 111 .dev = { 112 .platform_data = &dir825b1_rtl8366s_data, 113 } 114}; 115 116static void dir825b1_read_ascii_mac(u8 *dest, u8 *src) 117{ 118 int ret; 119 120 ret = sscanf(src, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 121 &dest[0], &dest[1], &dest[2], 122 &dest[3], &dest[4], &dest[5]); 123 124 if (ret != ETH_ALEN) 125 memset(dest, 0, ETH_ALEN); 126} 127 128static bool __init dir825b1_is_caldata_valid(u8 *p) 129{ 130 u16 *magic0, *magic1; 131 132 magic0 = (u16 *)(p + DIR825B1_CAL0_OFFSET); 133 magic1 = (u16 *)(p + DIR825B1_CAL1_OFFSET); 134 135 return (*magic0 == 0xa55a && *magic1 == 0xa55a); 136} 137 138static void __init dir825b1_wlan_init(void) 139{ 140 u8 *caldata; 141 u8 mac0[ETH_ALEN], mac1[ETH_ALEN]; 142 u8 wmac0[ETH_ALEN], wmac1[ETH_ALEN]; 143 144 caldata = (u8 *) KSEG1ADDR(DIR825B1_CAL_LOCATION_0); 145 if (!dir825b1_is_caldata_valid(caldata)) { 146 caldata = (u8 *)KSEG1ADDR(DIR825B1_CAL_LOCATION_1); 147 if (!dir825b1_is_caldata_valid(caldata)) { 148 pr_err("no calibration data found\n"); 149 return; 150 } 151 } 152 153 dir825b1_read_ascii_mac(mac0, caldata + DIR825B1_MAC0_OFFSET); 154 dir825b1_read_ascii_mac(mac1, caldata + DIR825B1_MAC1_OFFSET); 155 156 ath79_init_mac(ath79_eth0_data.mac_addr, mac0, 0); 157 ath79_init_mac(ath79_eth1_data.mac_addr, mac1, 0); 158 ath79_init_mac(wmac0, mac0, 0); 159 ath79_init_mac(wmac1, mac1, 1); 160 161 ap9x_pci_setup_wmac_led_pin(0, 5); 162 ap9x_pci_setup_wmac_led_pin(1, 5); 163 164 ap94_pci_init(caldata + DIR825B1_CAL0_OFFSET, wmac0, 165 caldata + DIR825B1_CAL1_OFFSET, wmac1); 166} 167 168static void __init dir825b1_setup(void) 169{ 170 dir825b1_wlan_init(); 171 172 ath79_register_mdio(0, 0x0); 173 174 ath79_eth0_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev; 175 ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; 176 ath79_eth0_data.speed = SPEED_1000; 177 ath79_eth0_data.duplex = DUPLEX_FULL; 178 ath79_eth0_pll_data.pll_1000 = 0x11110000; 179 180 ath79_eth1_data.mii_bus_dev = &dir825b1_rtl8366s_device.dev; 181 ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII; 182 ath79_eth1_data.phy_mask = 0x10; 183 ath79_eth1_pll_data.pll_1000 = 0x11110000; 184 185 ath79_register_eth(0); 186 ath79_register_eth(1); 187 188 ath79_register_m25p80(NULL); 189 190 ath79_register_leds_gpio(-1, ARRAY_SIZE(dir825b1_leds_gpio), 191 dir825b1_leds_gpio); 192 193 ath79_register_gpio_keys_polled(-1, DIR825B1_KEYS_POLL_INTERVAL, 194 ARRAY_SIZE(dir825b1_gpio_keys), 195 dir825b1_gpio_keys); 196 197 ath79_register_usb(); 198 199 platform_device_register(&dir825b1_rtl8366s_device); 200} 201 202MIPS_MACHINE(ATH79_MACH_DIR_825_B1, "DIR-825-B1", "D-Link DIR-825 rev. B1", 203 dir825b1_setup); 204