| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 | /* * arch/arm/mach-orion5x/dns323-setup.c * * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> * * Support for HW Rev C1: * * Copyright (C) 2010 Benjamin Herrenschmidt <benh@kernel.crashing.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * */#include <linux/gpio.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/pci.h>#include <linux/irq.h>#include <linux/mtd/physmap.h>#include <linux/mv643xx_eth.h>#include <linux/leds.h>#include <linux/gpio_keys.h>#include <linux/input.h>#include <linux/i2c.h>#include <linux/ata_platform.h>#include <linux/phy.h>#include <linux/marvell_phy.h>#include <asm/mach-types.h>#include <asm/mach/arch.h>#include <asm/mach/pci.h>#include <asm/system_info.h>#include <mach/orion5x.h>#include <plat/orion-gpio.h>#include "common.h"#include "mpp.h"/* Rev A1 and B1 */#define DNS323_GPIO_LED_RIGHT_AMBER	1#define DNS323_GPIO_LED_LEFT_AMBER	2#define DNS323_GPIO_SYSTEM_UP		3#define DNS323_GPIO_LED_POWER1		4#define DNS323_GPIO_LED_POWER2		5#define DNS323_GPIO_OVERTEMP		6#define DNS323_GPIO_RTC			7#define DNS323_GPIO_POWER_OFF		8#define DNS323_GPIO_KEY_POWER		9#define DNS323_GPIO_KEY_RESET		10/* Rev C1 */#define DNS323C_GPIO_KEY_POWER		1#define DNS323C_GPIO_POWER_OFF		2#define DNS323C_GPIO_LED_RIGHT_AMBER	8#define DNS323C_GPIO_LED_LEFT_AMBER	9#define DNS323C_GPIO_LED_POWER		17#define DNS323C_GPIO_FAN_BIT1		18#define DNS323C_GPIO_FAN_BIT0		19/* Exposed to userspace, do not change */enum {	DNS323_REV_A1,	/* 0 */	DNS323_REV_B1,	/* 1 */	DNS323_REV_C1,	/* 2 */};/**************************************************************************** * PCI setup */static int __init dns323_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin){	int irq;	/*	 * Check for devices with hard-wired IRQs.	 */	irq = orion5x_pci_map_irq(dev, slot, pin);	if (irq != -1)		return irq;	return -1;}static struct hw_pci dns323_pci __initdata = {	.nr_controllers = 2,	.setup		= orion5x_pci_sys_setup,	.scan		= orion5x_pci_sys_scan_bus,	.map_irq	= dns323_pci_map_irq,};static int __init dns323_pci_init(void){	/* Rev B1 and C1 doesn't really use its PCI bus, and initialising PCI	 * gets in the way of initialising the SATA controller.	 */	if (machine_is_dns323() && system_rev == DNS323_REV_A1)		pci_common_init(&dns323_pci);	return 0;}subsys_initcall(dns323_pci_init);/**************************************************************************** * 8MiB NOR flash (Spansion S29GL064M90TFIR4) * * Layout as used by D-Link: *  0x00000000-0x00010000 : "MTD1" *  0x00010000-0x00020000 : "MTD2" *  0x00020000-0x001a0000 : "Linux Kernel" *  0x001a0000-0x007d0000 : "File System" *  0x007d0000-0x00800000 : "u-boot" */#define DNS323_NOR_BOOT_BASE 0xf4000000#define DNS323_NOR_BOOT_SIZE SZ_8Mstatic struct mtd_partition dns323_partitions[] = {	{		.name	= "MTD1",		.size	= 0x00010000,		.offset	= 0,	}, {		.name	= "MTD2",		.size	= 0x00010000,		.offset = 0x00010000,	}, {		.name	= "Linux Kernel",		.size	= 0x00180000,		.offset	= 0x00020000,	}, {		.name	= "File System",		.size	= 0x00630000,		.offset	= 0x001A0000,	}, {		.name	= "u-boot",		.size	= 0x00030000,		.offset	= 0x007d0000,	},};static struct physmap_flash_data dns323_nor_flash_data = {	.width		= 1,	.parts		= dns323_partitions,	.nr_parts	= ARRAY_SIZE(dns323_partitions)};static struct resource dns323_nor_flash_resource = {	.flags		= IORESOURCE_MEM,	.start		= DNS323_NOR_BOOT_BASE,	.end		= DNS323_NOR_BOOT_BASE + DNS323_NOR_BOOT_SIZE - 1,};static struct platform_device dns323_nor_flash = {	.name		= "physmap-flash",	.id		= 0,	.dev		= {		.platform_data	= &dns323_nor_flash_data,	},	.resource	= &dns323_nor_flash_resource,	.num_resources	= 1,};/**************************************************************************** * Ethernet */static struct mv643xx_eth_platform_data dns323_eth_data = {	.phy_addr = MV643XX_ETH_PHY_ADDR(8),};/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these * functions be kept somewhere? */static int __init dns323_parse_hex_nibble(char n){	if (n >= '0' && n <= '9')		return n - '0';	if (n >= 'A' && n <= 'F')		return n - 'A' + 10;	if (n >= 'a' && n <= 'f')		return n - 'a' + 10;	return -1;}static int __init dns323_parse_hex_byte(const char *b){	int hi;	int lo;	hi = dns323_parse_hex_nibble(b[0]);	lo = dns323_parse_hex_nibble(b[1]);	if (hi < 0 || lo < 0)		return -1;	return (hi << 4) | lo;}static int __init dns323_read_mac_addr(void){	u_int8_t addr[6];	int i;	char *mac_page;	/* MAC address is stored as a regular ol' string in /dev/mtdblock4	 * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).	 */	mac_page = ioremap(DNS323_NOR_BOOT_BASE + 0x7d0000 + 196480, 1024);	if (!mac_page)		return -ENOMEM;	/* Sanity check the string we're looking at */	for (i = 0; i < 5; i++) {		if (*(mac_page + (i * 3) + 2) != ':') {			goto error_fail;		}	}	for (i = 0; i < 6; i++)	{		int byte;		byte = dns323_parse_hex_byte(mac_page + (i * 3));		if (byte < 0) {			goto error_fail;		}		addr[i] = byte;	}	iounmap(mac_page);	printk("DNS-323: Found ethernet MAC address: ");	for (i = 0; i < 6; i++)		printk("%.2x%s", addr[i], (i < 5) ? ":" : ".\n");	memcpy(dns323_eth_data.mac_addr, addr, 6);	return 0;error_fail:	iounmap(mac_page);	return -EINVAL;}/**************************************************************************** * GPIO LEDs (simple - doesn't use hardware blinking support) */static struct gpio_led dns323ab_leds[] = {	{		.name = "power:blue",		.gpio = DNS323_GPIO_LED_POWER2,		.default_trigger = "default-on",	}, {		.name = "right:amber",		.gpio = DNS323_GPIO_LED_RIGHT_AMBER,		.active_low = 1,	}, {		.name = "left:amber",		.gpio = DNS323_GPIO_LED_LEFT_AMBER,		.active_low = 1,	},};static struct gpio_led dns323c_leds[] = {	{		.name = "power:blue",		.gpio = DNS323C_GPIO_LED_POWER,		.default_trigger = "timer",		.active_low = 1,	}, {		.name = "right:amber",		.gpio = DNS323C_GPIO_LED_RIGHT_AMBER,		.active_low = 1,	}, {		.name = "left:amber",		.gpio = DNS323C_GPIO_LED_LEFT_AMBER,		.active_low = 1,	},};static struct gpio_led_platform_data dns323ab_led_data = {	.num_leds	= ARRAY_SIZE(dns323ab_leds),	.leds		= dns323ab_leds,	.gpio_blink_set = orion_gpio_led_blink_set,};static struct gpio_led_platform_data dns323c_led_data = {	.num_leds	= ARRAY_SIZE(dns323c_leds),	.leds		= dns323c_leds,	.gpio_blink_set = orion_gpio_led_blink_set,};static struct platform_device dns323_gpio_leds = {	.name		= "leds-gpio",	.id		= -1,	.dev		= {		.platform_data	= &dns323ab_led_data,	},};/**************************************************************************** * GPIO Attached Keys */static struct gpio_keys_button dns323ab_buttons[] = {	{		.code		= KEY_RESTART,		.gpio		= DNS323_GPIO_KEY_RESET,		.desc		= "Reset Button",		.active_low	= 1,	}, {		.code		= KEY_POWER,		.gpio		= DNS323_GPIO_KEY_POWER,		.desc		= "Power Button",		.active_low	= 1,	},};static struct gpio_keys_platform_data dns323ab_button_data = {	.buttons	= dns323ab_buttons,	.nbuttons	= ARRAY_SIZE(dns323ab_buttons),};static struct gpio_keys_button dns323c_buttons[] = {	{		.code		= KEY_POWER,		.gpio		= DNS323C_GPIO_KEY_POWER,		.desc		= "Power Button",		.active_low	= 1,	},};static struct gpio_keys_platform_data dns323c_button_data = {	.buttons	= dns323c_buttons,	.nbuttons	= ARRAY_SIZE(dns323c_buttons),};static struct platform_device dns323_button_device = {	.name		= "gpio-keys",	.id		= -1,	.num_resources	= 0,	.dev		= {		.platform_data	= &dns323ab_button_data,	},};/***************************************************************************** * SATA */static struct mv_sata_platform_data dns323_sata_data = {       .n_ports        = 2,};/**************************************************************************** * General Setup */static unsigned int dns323a_mpp_modes[] __initdata = {	MPP0_PCIE_RST_OUTn,	MPP1_GPIO,		/* right amber LED (sata ch0) */	MPP2_GPIO,		/* left amber LED (sata ch1) */	MPP3_UNUSED,	MPP4_GPIO,		/* power button LED */	MPP5_GPIO,		/* power button LED */	MPP6_GPIO,		/* GMT G751-2f overtemp */	MPP7_GPIO,		/* M41T80 nIRQ/OUT/SQW */	MPP8_GPIO,		/* triggers power off */	MPP9_GPIO,		/* power button switch */	MPP10_GPIO,		/* reset button switch */	MPP11_UNUSED,	MPP12_UNUSED,	MPP13_UNUSED,	MPP14_UNUSED,	MPP15_UNUSED,	MPP16_UNUSED,	MPP17_UNUSED,	MPP18_UNUSED,	MPP19_UNUSED,	0,};static unsigned int dns323b_mpp_modes[] __initdata = {	MPP0_UNUSED,	MPP1_GPIO,		/* right amber LED (sata ch0) */	MPP2_GPIO,		/* left amber LED (sata ch1) */	MPP3_GPIO,		/* system up flag */	MPP4_GPIO,		/* power button LED */	MPP5_GPIO,		/* power button LED */	MPP6_GPIO,		/* GMT G751-2f overtemp */	MPP7_GPIO,		/* M41T80 nIRQ/OUT/SQW */	MPP8_GPIO,		/* triggers power off */	MPP9_GPIO,		/* power button switch */	MPP10_GPIO,		/* reset button switch */	MPP11_UNUSED,	MPP12_SATA_LED,	MPP13_SATA_LED,	MPP14_SATA_LED,	MPP15_SATA_LED,	MPP16_UNUSED,	MPP17_UNUSED,	MPP18_UNUSED,	MPP19_UNUSED,	0,};static unsigned int dns323c_mpp_modes[] __initdata = {	MPP0_GPIO,		/* ? input */	MPP1_GPIO,		/* input power switch (0 = pressed) */	MPP2_GPIO,		/* output power off */	MPP3_UNUSED,		/* ? output */	MPP4_UNUSED,		/* ? output */	MPP5_UNUSED,		/* ? output */	MPP6_UNUSED,		/* ? output */	MPP7_UNUSED,		/* ? output */	MPP8_GPIO,		/* i/o right amber LED */	MPP9_GPIO,		/* i/o left amber LED */	MPP10_GPIO,		/* input */	MPP11_UNUSED,	MPP12_SATA_LED,	MPP13_SATA_LED,	MPP14_SATA_LED,	MPP15_SATA_LED,	MPP16_UNUSED,	MPP17_GPIO,		/* power button LED */	MPP18_GPIO,		/* fan speed bit 0 */	MPP19_GPIO,		/* fan speed bit 1 */	0,};/* Rev C1 Fan speed notes: * * The fan is controlled by 2 GPIOs on this board. The settings * of the bits is as follow: * *  GPIO 18    GPIO 19    Fan * *    0          0        stopped *    0          1        low speed *    1          0        high speed *    1          1        don't do that (*) * * (*) I think the two bits control two feed-in resistors into a fixed *     PWN circuit, setting both bits will basically go a 'bit' faster *     than high speed, but d-link doesn't do it and you may get out of *     HW spec so don't do it. *//* * On the DNS-323 A1 and B1 the following devices are attached via I2C: * *  i2c addr | chip        | description *  0x3e     | GMT G760Af  | fan speed PWM controller *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible) *  0x68     | ST M41T80   | RTC w/ alarm */static struct i2c_board_info __initdata dns323ab_i2c_devices[] = {	{		I2C_BOARD_INFO("g760a", 0x3e),	}, {		I2C_BOARD_INFO("lm75", 0x48),	}, {		I2C_BOARD_INFO("m41t80", 0x68),	},};/* * On the DNS-323 C1 the following devices are attached via I2C: * *  i2c addr | chip        | description *  0x48     | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible) *  0x68     | ST M41T80   | RTC w/ alarm */static struct i2c_board_info __initdata dns323c_i2c_devices[] = {	{		I2C_BOARD_INFO("lm75", 0x48),	}, {		I2C_BOARD_INFO("m41t80", 0x68),	},};/* DNS-323 rev. A specific power off method */static void dns323a_power_off(void){	pr_info("DNS-323: Triggering power-off...\n");	gpio_set_value(DNS323_GPIO_POWER_OFF, 1);}/* DNS-323 rev B specific power off method */static void dns323b_power_off(void){	pr_info("DNS-323: Triggering power-off...\n");	/* Pin has to be changed to 1 and back to 0 to do actual power off. */	gpio_set_value(DNS323_GPIO_POWER_OFF, 1);	mdelay(100);	gpio_set_value(DNS323_GPIO_POWER_OFF, 0);}/* DNS-323 rev. C specific power off method */static void dns323c_power_off(void){	pr_info("DNS-323: Triggering power-off...\n");	gpio_set_value(DNS323C_GPIO_POWER_OFF, 1);}static int dns323c_phy_fixup(struct phy_device *phy){	phy->dev_flags |= MARVELL_PHY_M1118_DNS323_LEDS;	return 0;}static int __init dns323_identify_rev(void){
 |