Browse Source

Merge git://git.kernel.org/pub/scm/linux/kernel/git/nico/orion into devel-stable

Russell King 15 years ago
parent
commit
4af8f24d99

+ 1 - 0
arch/arm/configs/kirkwood_defconfig

@@ -15,6 +15,7 @@ CONFIG_MACH_MV88F6281GTW_GE=y
 CONFIG_MACH_SHEEVAPLUG=y
 CONFIG_MACH_SHEEVAPLUG=y
 CONFIG_MACH_ESATA_SHEEVAPLUG=y
 CONFIG_MACH_ESATA_SHEEVAPLUG=y
 CONFIG_MACH_GURUPLUG=y
 CONFIG_MACH_GURUPLUG=y
+CONFIG_MACH_DOCKSTAR=y
 CONFIG_MACH_TS219=y
 CONFIG_MACH_TS219=y
 CONFIG_MACH_TS41X=y
 CONFIG_MACH_TS41X=y
 CONFIG_MACH_OPENRD_BASE=y
 CONFIG_MACH_OPENRD_BASE=y

+ 12 - 0
arch/arm/mach-kirkwood/Kconfig

@@ -58,6 +58,12 @@ config MACH_TS41X
 	  QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS
 	  QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS
 	  devices.
 	  devices.
 
 
+config MACH_DOCKSTAR
+	bool "Seagate FreeAgent DockStar"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Seagate FreeAgent DockStar.
+
 config MACH_OPENRD
 config MACH_OPENRD
         bool
         bool
 
 
@@ -100,6 +106,12 @@ config MACH_NETSPACE_MAX_V2
 	  Say 'Y' here if you want your kernel to support the
 	  Say 'Y' here if you want your kernel to support the
 	  LaCie Network Space Max v2 NAS.
 	  LaCie Network Space Max v2 NAS.
 
 
+config MACH_D2NET_V2
+	bool "LaCie d2 Network v2 NAS Board"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  LaCie d2 Network v2 NAS.
+
 config MACH_NET2BIG_V2
 config MACH_NET2BIG_V2
 	bool "LaCie 2Big Network v2 NAS Board"
 	bool "LaCie 2Big Network v2 NAS Board"
 	help
 	help

+ 7 - 5
arch/arm/mach-kirkwood/Makefile

@@ -7,14 +7,16 @@ obj-$(CONFIG_MACH_MV88F6281GTW_GE)	+= mv88f6281gtw_ge-setup.o
 obj-$(CONFIG_MACH_SHEEVAPLUG)		+= sheevaplug-setup.o
 obj-$(CONFIG_MACH_SHEEVAPLUG)		+= sheevaplug-setup.o
 obj-$(CONFIG_MACH_ESATA_SHEEVAPLUG)	+= sheevaplug-setup.o
 obj-$(CONFIG_MACH_ESATA_SHEEVAPLUG)	+= sheevaplug-setup.o
 obj-$(CONFIG_MACH_GURUPLUG)		+= guruplug-setup.o
 obj-$(CONFIG_MACH_GURUPLUG)		+= guruplug-setup.o
+obj-$(CONFIG_MACH_DOCKSTAR)		+= dockstar-setup.o
 obj-$(CONFIG_MACH_TS219)		+= ts219-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_TS219)		+= ts219-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_TS41X)		+= ts41x-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_TS41X)		+= ts41x-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_OPENRD)		+= openrd-setup.o
 obj-$(CONFIG_MACH_OPENRD)		+= openrd-setup.o
-obj-$(CONFIG_MACH_NETSPACE_V2)		+= netspace_v2-setup.o
-obj-$(CONFIG_MACH_INETSPACE_V2)		+= netspace_v2-setup.o
-obj-$(CONFIG_MACH_NETSPACE_MAX_V2)	+= netspace_v2-setup.o
-obj-$(CONFIG_MACH_NET2BIG_V2)		+= netxbig_v2-setup.o
-obj-$(CONFIG_MACH_NET5BIG_V2)		+= netxbig_v2-setup.o
+obj-$(CONFIG_MACH_NETSPACE_V2)		+= netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_INETSPACE_V2)		+= netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NETSPACE_MAX_V2)	+= netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_D2NET_V2)		+= d2net_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NET2BIG_V2)		+= netxbig_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NET5BIG_V2)		+= netxbig_v2-setup.o lacie_v2-common.o
 obj-$(CONFIG_MACH_T5325)		+= t5325-setup.o
 obj-$(CONFIG_MACH_T5325)		+= t5325-setup.o
 
 
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o
 obj-$(CONFIG_CPU_IDLE)			+= cpuidle.o

+ 231 - 0
arch/arm/mach-kirkwood/d2net_v2-setup.c

@@ -0,0 +1,231 @@
+/*
+ * arch/arm/mach-kirkwood/d2net_v2-setup.c
+ *
+ * LaCie d2 Network Space v2 Board Setup
+ *
+ * Copyright (C) 2010 Simon Guinot <sguinot@lacie.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include <mach/leds-ns2.h>
+#include "common.h"
+#include "mpp.h"
+#include "lacie_v2-common.h"
+
+/*****************************************************************************
+ * Ethernet
+ ****************************************************************************/
+
+static struct mv643xx_eth_platform_data d2net_v2_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
+};
+
+/*****************************************************************************
+ * SATA
+ ****************************************************************************/
+
+static struct mv_sata_platform_data d2net_v2_sata_data = {
+	.n_ports	= 2,
+};
+
+/*****************************************************************************
+ * GPIO keys
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_PUSH_BUTTON          34
+#define D2NET_V2_GPIO_POWER_SWITCH_ON      13
+#define D2NET_V2_GPIO_POWER_SWITCH_OFF     15
+
+#define D2NET_V2_SWITCH_POWER_ON           0x1
+#define D2NET_V2_SWITCH_POWER_OFF          0x2
+
+static struct gpio_keys_button d2net_v2_buttons[] = {
+	[0] = {
+		.type           = EV_SW,
+		.code           = D2NET_V2_SWITCH_POWER_ON,
+		.gpio           = D2NET_V2_GPIO_POWER_SWITCH_ON,
+		.desc           = "Back power switch (on|auto)",
+		.active_low     = 0,
+	},
+	[1] = {
+		.type           = EV_SW,
+		.code           = D2NET_V2_SWITCH_POWER_OFF,
+		.gpio           = D2NET_V2_GPIO_POWER_SWITCH_OFF,
+		.desc           = "Back power switch (auto|off)",
+		.active_low     = 0,
+	},
+	[2] = {
+		.code           = KEY_POWER,
+		.gpio           = D2NET_V2_GPIO_PUSH_BUTTON,
+		.desc           = "Front Push Button",
+		.active_low     = 1,
+	},
+};
+
+static struct gpio_keys_platform_data d2net_v2_button_data = {
+	.buttons	= d2net_v2_buttons,
+	.nbuttons	= ARRAY_SIZE(d2net_v2_buttons),
+};
+
+static struct platform_device d2net_v2_gpio_buttons = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &d2net_v2_button_data,
+	},
+};
+
+/*****************************************************************************
+ * GPIO LEDs
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_RED_LED		12
+
+static struct gpio_led d2net_v2_gpio_led_pins[] = {
+	{
+		.name	= "d2net_v2:red:fail",
+		.gpio	= D2NET_V2_GPIO_RED_LED,
+	},
+};
+
+static struct gpio_led_platform_data d2net_v2_gpio_leds_data = {
+	.num_leds	= ARRAY_SIZE(d2net_v2_gpio_led_pins),
+	.leds		= d2net_v2_gpio_led_pins,
+};
+
+static struct platform_device d2net_v2_gpio_leds = {
+	.name		= "leds-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &d2net_v2_gpio_leds_data,
+	},
+};
+
+/*****************************************************************************
+ * Dual-GPIO CPLD LEDs
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_BLUE_LED_SLOW	29
+#define D2NET_V2_GPIO_BLUE_LED_CMD	30
+
+static struct ns2_led d2net_v2_led_pins[] = {
+	{
+		.name	= "d2net_v2:blue:sata",
+		.cmd	= D2NET_V2_GPIO_BLUE_LED_CMD,
+		.slow	= D2NET_V2_GPIO_BLUE_LED_SLOW,
+	},
+};
+
+static struct ns2_led_platform_data d2net_v2_leds_data = {
+	.num_leds	= ARRAY_SIZE(d2net_v2_led_pins),
+	.leds		= d2net_v2_led_pins,
+};
+
+static struct platform_device d2net_v2_leds = {
+	.name		= "leds-ns2",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &d2net_v2_leds_data,
+	},
+};
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+
+static unsigned int d2net_v2_mpp_config[] __initdata = {
+	MPP0_SPI_SCn,
+	MPP1_SPI_MOSI,
+	MPP2_SPI_SCK,
+	MPP3_SPI_MISO,
+	MPP6_SYSRST_OUTn,
+	MPP7_GPO,		/* Request power-off */
+	MPP8_TW0_SDA,
+	MPP9_TW0_SCK,
+	MPP10_UART0_TXD,
+	MPP11_UART0_RXD,
+	MPP12_GPO,		/* Red led */
+	MPP13_GPIO,		/* Rear power switch (on|auto) */
+	MPP14_GPIO,		/* USB fuse */
+	MPP15_GPIO,		/* Rear power switch (auto|off) */
+	MPP16_GPIO,		/* SATA 0 power */
+	MPP21_SATA0_ACTn,
+	MPP24_GPIO,		/* USB mode select */
+	MPP26_GPIO,		/* USB device vbus */
+	MPP28_GPIO,		/* USB enable host vbus */
+	MPP29_GPIO,		/* Blue led (slow register) */
+	MPP30_GPIO,		/* Blue led (command register) */
+	MPP34_GPIO,		/* Power button (1 = Released, 0 = Pushed) */
+	MPP35_GPIO,		/* Inhibit power-off */
+	0
+};
+
+#define D2NET_V2_GPIO_POWER_OFF		7
+
+static void d2net_v2_power_off(void)
+{
+	gpio_set_value(D2NET_V2_GPIO_POWER_OFF, 1);
+}
+
+static void __init d2net_v2_init(void)
+{
+	/*
+	 * Basic setup. Needs to be called early.
+	 */
+	kirkwood_init();
+	kirkwood_mpp_conf(d2net_v2_mpp_config);
+
+	lacie_v2_hdd_power_init(1);
+
+	kirkwood_ehci_init();
+	kirkwood_ge00_init(&d2net_v2_ge00_data);
+	kirkwood_sata_init(&d2net_v2_sata_data);
+	kirkwood_uart0_init();
+	lacie_v2_register_flash();
+	lacie_v2_register_i2c_devices();
+
+	platform_device_register(&d2net_v2_leds);
+	platform_device_register(&d2net_v2_gpio_leds);
+	platform_device_register(&d2net_v2_gpio_buttons);
+
+	if (gpio_request(D2NET_V2_GPIO_POWER_OFF, "power-off") == 0 &&
+	    gpio_direction_output(D2NET_V2_GPIO_POWER_OFF, 0) == 0)
+		pm_power_off = d2net_v2_power_off;
+	else
+		pr_err("d2net_v2: failed to configure power-off GPIO\n");
+}
+
+MACHINE_START(D2NET_V2, "LaCie d2 Network v2")
+	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
+	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0x00000100,
+	.init_machine	= d2net_v2_init,
+	.map_io		= kirkwood_map_io,
+	.init_irq	= kirkwood_init_irq,
+	.timer		= &lacie_v2_timer,
+MACHINE_END

+ 112 - 0
arch/arm/mach-kirkwood/dockstar-setup.c

@@ -0,0 +1,112 @@
+/*
+ * arch/arm/mach-kirkwood/dockstar-setup.c
+ *
+ * Seagate FreeAgent DockStar Setup
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include <plat/mvsdio.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mtd_partition dockstar_nand_parts[] = {
+	{
+		.name = "u-boot",
+		.offset = 0,
+		.size = SZ_1M
+	}, {
+		.name = "uImage",
+		.offset = MTDPART_OFS_NXTBLK,
+		.size = SZ_4M
+	}, {
+		.name = "root",
+		.offset = MTDPART_OFS_NXTBLK,
+		.size = MTDPART_SIZ_FULL
+	},
+};
+
+static struct mv643xx_eth_platform_data dockstar_ge00_data = {
+	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
+};
+
+static struct gpio_led dockstar_led_pins[] = {
+	{
+		.name			= "dockstar:green:health",
+		.default_trigger	= "default-on",
+		.gpio			= 46,
+		.active_low		= 1,
+	},
+	{
+		.name			= "dockstar:orange:misc",
+		.default_trigger	= "none",
+		.gpio			= 47,
+		.active_low		= 1,
+	},
+};
+
+static struct gpio_led_platform_data dockstar_led_data = {
+	.leds		= dockstar_led_pins,
+	.num_leds	= ARRAY_SIZE(dockstar_led_pins),
+};
+
+static struct platform_device dockstar_leds = {
+	.name	= "leds-gpio",
+	.id	= -1,
+	.dev	= {
+		.platform_data	= &dockstar_led_data,
+	}
+};
+
+static unsigned int dockstar_mpp_config[] __initdata = {
+	MPP29_GPIO,	/* USB Power Enable */
+	MPP46_GPIO,	/* LED green */
+	MPP47_GPIO,	/* LED orange */
+	0
+};
+
+static void __init dockstar_init(void)
+{
+	/*
+	 * Basic setup. Needs to be called early.
+	 */
+	kirkwood_init();
+
+	/* setup gpio pin select */
+	kirkwood_mpp_conf(dockstar_mpp_config);
+
+	kirkwood_uart0_init();
+	kirkwood_nand_init(ARRAY_AND_SIZE(dockstar_nand_parts), 25);
+
+	if (gpio_request(29, "USB Power Enable") != 0 ||
+	    gpio_direction_output(29, 1) != 0)
+		printk(KERN_ERR "can't set up GPIO 29 (USB Power Enable)\n");
+	kirkwood_ehci_init();
+
+	kirkwood_ge00_init(&dockstar_ge00_data);
+
+	platform_device_register(&dockstar_leds);
+}
+
+MACHINE_START(DOCKSTAR, "Seagate FreeAgent DockStar")
+	.phys_io	= KIRKWOOD_REGS_PHYS_BASE,
+	.io_pg_offst	= ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0x00000100,
+	.init_machine	= dockstar_init,
+	.map_io		= kirkwood_map_io,
+	.init_irq	= kirkwood_init_irq,
+	.timer		= &kirkwood_timer,
+MACHINE_END

+ 55 - 0
arch/arm/mach-kirkwood/include/mach/leds-netxbig.h

@@ -0,0 +1,55 @@
+/*
+ * arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
+ *
+ * Platform data structure for netxbig LED driver
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_LEDS_NETXBIG_H
+#define __MACH_LEDS_NETXBIG_H
+
+struct netxbig_gpio_ext {
+	unsigned	*addr;
+	int		num_addr;
+	unsigned	*data;
+	int		num_data;
+	unsigned	enable;
+};
+
+enum netxbig_led_mode {
+	NETXBIG_LED_OFF,
+	NETXBIG_LED_ON,
+	NETXBIG_LED_SATA,
+	NETXBIG_LED_TIMER1,
+	NETXBIG_LED_TIMER2,
+	NETXBIG_LED_MODE_NUM,
+};
+
+#define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM
+
+struct netxbig_led_timer {
+	unsigned long		delay_on;
+	unsigned long		delay_off;
+	enum netxbig_led_mode	mode;
+};
+
+struct netxbig_led {
+	const char	*name;
+	const char	*default_trigger;
+	int		mode_addr;
+	int		*mode_val;
+	int		bright_addr;
+};
+
+struct netxbig_led_platform_data {
+	struct netxbig_gpio_ext	*gpio_ext;
+	struct netxbig_led_timer *timer;
+	int			num_timer;
+	struct netxbig_led	*leds;
+	int			num_leds;
+};
+
+#endif /* __MACH_LEDS_NETXBIG_H */

+ 127 - 0
arch/arm/mach-kirkwood/lacie_v2-common.c

@@ -0,0 +1,127 @@
+/*
+ * arch/arm/mach-kirkwood/lacie_v2-common.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/gpio.h>
+#include <asm/mach/time.h>
+#include <mach/kirkwood.h>
+#include <mach/irqs.h>
+#include <plat/time.h>
+#include "common.h"
+
+/*****************************************************************************
+ * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
+ ****************************************************************************/
+
+static struct mtd_partition lacie_v2_flash_parts[] = {
+	{
+		.name = "u-boot",
+		.size = MTDPART_SIZ_FULL,
+		.offset = 0,
+		.mask_flags = MTD_WRITEABLE, /* force read-only */
+	},
+};
+
+static const struct flash_platform_data lacie_v2_flash = {
+	.type		= "mx25l4005a",
+	.name		= "spi_flash",
+	.parts		= lacie_v2_flash_parts,
+	.nr_parts	= ARRAY_SIZE(lacie_v2_flash_parts),
+};
+
+static struct spi_board_info __initdata lacie_v2_spi_slave_info[] = {
+	{
+		.modalias	= "m25p80",
+		.platform_data	= &lacie_v2_flash,
+		.irq		= -1,
+		.max_speed_hz	= 20000000,
+		.bus_num	= 0,
+		.chip_select	= 0,
+	},
+};
+
+void __init lacie_v2_register_flash(void)
+{
+	spi_register_board_info(lacie_v2_spi_slave_info,
+				ARRAY_SIZE(lacie_v2_spi_slave_info));
+	kirkwood_spi_init();
+}
+
+/*****************************************************************************
+ * I2C devices
+ ****************************************************************************/
+
+static struct at24_platform_data at24c04 = {
+	.byte_len	= SZ_4K / 8,
+	.page_size	= 16,
+};
+
+/*
+ * i2c addr | chip         | description
+ * 0x50     | HT24LC04     | eeprom (512B)
+ */
+
+static struct i2c_board_info __initdata lacie_v2_i2c_info[] = {
+	{
+		I2C_BOARD_INFO("24c04", 0x50),
+		.platform_data  = &at24c04,
+	}
+};
+
+void __init lacie_v2_register_i2c_devices(void)
+{
+	kirkwood_i2c_init();
+	i2c_register_board_info(0, lacie_v2_i2c_info,
+				ARRAY_SIZE(lacie_v2_i2c_info));
+}
+
+/*****************************************************************************
+ * Hard Disk power
+ ****************************************************************************/
+
+static int __initdata lacie_v2_gpio_hdd_power[] = { 16, 17, 41, 42, 43 };
+
+void __init lacie_v2_hdd_power_init(int hdd_num)
+{
+	int i;
+	int err;
+
+	/* Power up all hard disks. */
+	for (i = 0; i < hdd_num; i++) {
+		err = gpio_request(lacie_v2_gpio_hdd_power[i], NULL);
+		if (err == 0) {
+			err = gpio_direction_output(
+					lacie_v2_gpio_hdd_power[i], 1);
+			/* Free the HDD power GPIOs. This allow user-space to
+			 * configure them via the gpiolib sysfs interface. */
+			gpio_free(lacie_v2_gpio_hdd_power[i]);
+		}
+		if (err)
+			pr_err("Failed to power up HDD%d\n", i + 1);
+	}
+}
+
+/*****************************************************************************
+ * Timer
+ ****************************************************************************/
+
+static void lacie_v2_timer_init(void)
+{
+	kirkwood_tclk = 166666667;
+	orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
+}
+
+struct sys_timer lacie_v2_timer = {
+	.init = lacie_v2_timer_init,
+};

+ 18 - 0
arch/arm/mach-kirkwood/lacie_v2-common.h

@@ -0,0 +1,18 @@
+/*
+ * arch/arm/mach-kirkwood/lacie_v2-common.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ARCH_KIRKWOOD_LACIE_V2_COMMON_H
+#define __ARCH_KIRKWOOD_LACIE_V2_COMMON_H
+
+void lacie_v2_register_flash(void);
+void lacie_v2_register_i2c_devices(void);
+void lacie_v2_hdd_power_init(int hdd_num);
+
+extern struct sys_timer lacie_v2_timer;
+
+#endif

+ 10 - 112
arch/arm/mach-kirkwood/netspace_v2-setup.c

@@ -24,56 +24,19 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
 #include <linux/ata_platform.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/mv643xx_eth.h>
-#include <linux/i2c.h>
-#include <linux/i2c/at24.h>
 #include <linux/input.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
 #include <linux/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
 #include <mach/kirkwood.h>
 #include <mach/kirkwood.h>
 #include <mach/leds-ns2.h>
 #include <mach/leds-ns2.h>
-#include <plat/time.h>
 #include "common.h"
 #include "common.h"
 #include "mpp.h"
 #include "mpp.h"
-
-/*****************************************************************************
- * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
- ****************************************************************************/
-
-static struct mtd_partition netspace_v2_flash_parts[] = {
-	{
-		.name = "u-boot",
-		.size = MTDPART_SIZ_FULL,
-		.offset = 0,
-		.mask_flags = MTD_WRITEABLE, /* force read-only */
-	},
-};
-
-static const struct flash_platform_data netspace_v2_flash = {
-	.type		= "mx25l4005a",
-	.name		= "spi_flash",
-	.parts		= netspace_v2_flash_parts,
-	.nr_parts	= ARRAY_SIZE(netspace_v2_flash_parts),
-};
-
-static struct spi_board_info __initdata netspace_v2_spi_slave_info[] = {
-	{
-		.modalias	= "m25p80",
-		.platform_data	= &netspace_v2_flash,
-		.irq		= -1,
-		.max_speed_hz	= 20000000,
-		.bus_num	= 0,
-		.chip_select	= 0,
-	},
-};
+#include "lacie_v2-common.h"
 
 
 /*****************************************************************************
 /*****************************************************************************
  * Ethernet
  * Ethernet
@@ -83,27 +46,6 @@ static struct mv643xx_eth_platform_data netspace_v2_ge00_data = {
 	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 	.phy_addr	= MV643XX_ETH_PHY_ADDR(8),
 };
 };
 
 
-/*****************************************************************************
- * I2C devices
- ****************************************************************************/
-
-static struct at24_platform_data at24c04 = {
-	.byte_len	= SZ_4K / 8,
-	.page_size	= 16,
-};
-
-/*
- * i2c addr | chip         | description
- * 0x50     | HT24LC04     | eeprom (512B)
- */
-
-static struct i2c_board_info __initdata netspace_v2_i2c_info[] = {
-	{
-		I2C_BOARD_INFO("24c04", 0x50),
-		.platform_data  = &at24c04,
-	}
-};
-
 /*****************************************************************************
 /*****************************************************************************
  * SATA
  * SATA
  ****************************************************************************/
  ****************************************************************************/
@@ -112,35 +54,6 @@ static struct mv_sata_platform_data netspace_v2_sata_data = {
 	.n_ports	= 2,
 	.n_ports	= 2,
 };
 };
 
 
-#define NETSPACE_V2_GPIO_SATA0_POWER	16
-#define NETSPACE_V2_GPIO_SATA1_POWER	17
-
-static void __init netspace_v2_sata_power_init(void)
-{
-	int err;
-
-	err = gpio_request(NETSPACE_V2_GPIO_SATA0_POWER, "SATA0 power");
-	if (err == 0) {
-		err = gpio_direction_output(NETSPACE_V2_GPIO_SATA0_POWER, 1);
-		if (err)
-			gpio_free(NETSPACE_V2_GPIO_SATA0_POWER);
-	}
-	if (err)
-		pr_err("netspace_v2: failed to setup SATA0 power\n");
-
-	if (machine_is_netspace_max_v2()) {
-		err = gpio_request(NETSPACE_V2_GPIO_SATA1_POWER, "SATA1 power");
-		if (err == 0) {
-			err = gpio_direction_output(
-					NETSPACE_V2_GPIO_SATA1_POWER, 1);
-			if (err)
-				gpio_free(NETSPACE_V2_GPIO_SATA1_POWER);
-		}
-		if (err)
-			pr_err("netspace_v2: failed to setup SATA1 power\n");
-	}
-}
-
 /*****************************************************************************
 /*****************************************************************************
  * GPIO keys
  * GPIO keys
  ****************************************************************************/
  ****************************************************************************/
@@ -223,20 +136,6 @@ static struct platform_device netspace_v2_leds = {
 	},
 	},
 };
 };
 
 
-/*****************************************************************************
- * Timer
- ****************************************************************************/
-
-static void netspace_v2_timer_init(void)
-{
-	kirkwood_tclk = 166666667;
-	orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
-}
-
-struct sys_timer netspace_v2_timer = {
-	.init = netspace_v2_timer_init,
-};
-
 /*****************************************************************************
 /*****************************************************************************
  * General Setup
  * General Setup
  ****************************************************************************/
  ****************************************************************************/
@@ -291,18 +190,17 @@ static void __init netspace_v2_init(void)
 	kirkwood_init();
 	kirkwood_init();
 	kirkwood_mpp_conf(netspace_v2_mpp_config);
 	kirkwood_mpp_conf(netspace_v2_mpp_config);
 
 
-	netspace_v2_sata_power_init();
+	if (machine_is_netspace_max_v2())
+		lacie_v2_hdd_power_init(2);
+	else
+		lacie_v2_hdd_power_init(1);
 
 
 	kirkwood_ehci_init();
 	kirkwood_ehci_init();
 	kirkwood_ge00_init(&netspace_v2_ge00_data);
 	kirkwood_ge00_init(&netspace_v2_ge00_data);
 	kirkwood_sata_init(&netspace_v2_sata_data);
 	kirkwood_sata_init(&netspace_v2_sata_data);
 	kirkwood_uart0_init();
 	kirkwood_uart0_init();
-	spi_register_board_info(netspace_v2_spi_slave_info,
-				ARRAY_SIZE(netspace_v2_spi_slave_info));
-	kirkwood_spi_init();
-	kirkwood_i2c_init();
-	i2c_register_board_info(0, netspace_v2_i2c_info,
-				ARRAY_SIZE(netspace_v2_i2c_info));
+	lacie_v2_register_flash();
+	lacie_v2_register_i2c_devices();
 
 
 	platform_device_register(&netspace_v2_leds);
 	platform_device_register(&netspace_v2_leds);
 	platform_device_register(&netspace_v2_gpio_leds);
 	platform_device_register(&netspace_v2_gpio_leds);
@@ -323,7 +221,7 @@ MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
 	.init_machine	= netspace_v2_init,
 	.init_machine	= netspace_v2_init,
 	.map_io		= kirkwood_map_io,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netspace_v2_timer,
+	.timer		= &lacie_v2_timer,
 MACHINE_END
 MACHINE_END
 #endif
 #endif
 
 
@@ -335,7 +233,7 @@ MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
 	.init_machine	= netspace_v2_init,
 	.init_machine	= netspace_v2_init,
 	.map_io		= kirkwood_map_io,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netspace_v2_timer,
+	.timer		= &lacie_v2_timer,
 MACHINE_END
 MACHINE_END
 #endif
 #endif
 
 
@@ -347,6 +245,6 @@ MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
 	.init_machine	= netspace_v2_init,
 	.init_machine	= netspace_v2_init,
 	.map_io		= kirkwood_map_io,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netspace_v2_timer,
+	.timer		= &lacie_v2_timer,
 MACHINE_END
 MACHINE_END
 #endif
 #endif

+ 138 - 131
arch/arm/mach-kirkwood/netxbig_v2-setup.c

@@ -23,55 +23,19 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
 #include <linux/ata_platform.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/mv643xx_eth.h>
-#include <linux/i2c.h>
-#include <linux/i2c/at24.h>
 #include <linux/input.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
 #include <linux/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
 #include <mach/kirkwood.h>
 #include <mach/kirkwood.h>
-#include <plat/time.h>
+#include <mach/leds-netxbig.h>
 #include "common.h"
 #include "common.h"
 #include "mpp.h"
 #include "mpp.h"
-
-/*****************************************************************************
- * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
- ****************************************************************************/
-
-static struct mtd_partition netxbig_v2_flash_parts[] = {
-	{
-		.name = "u-boot",
-		.size = MTDPART_SIZ_FULL,
-		.offset = 0,
-		.mask_flags = MTD_WRITEABLE, /* force read-only */
-	},
-};
-
-static const struct flash_platform_data netxbig_v2_flash = {
-	.type		= "mx25l4005a",
-	.name		= "spi_flash",
-	.parts		= netxbig_v2_flash_parts,
-	.nr_parts	= ARRAY_SIZE(netxbig_v2_flash_parts),
-};
-
-static struct spi_board_info __initdata netxbig_v2_spi_slave_info[] = {
-	{
-		.modalias	= "m25p80",
-		.platform_data	= &netxbig_v2_flash,
-		.irq		= -1,
-		.max_speed_hz	= 20000000,
-		.bus_num	= 0,
-		.chip_select	= 0,
-	},
-};
+#include "lacie_v2-common.h"
 
 
 /*****************************************************************************
 /*****************************************************************************
  * Ethernet
  * Ethernet
@@ -85,27 +49,6 @@ static struct mv643xx_eth_platform_data netxbig_v2_ge01_data = {
 	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
 	.phy_addr	= MV643XX_ETH_PHY_ADDR(0),
 };
 };
 
 
-/*****************************************************************************
- * I2C devices
- ****************************************************************************/
-
-static struct at24_platform_data at24c04 = {
-	.byte_len	= SZ_4K / 8,
-	.page_size	= 16,
-};
-
-/*
- * i2c addr | chip         | description
- * 0x50     | HT24LC04     | eeprom (512B)
- */
-
-static struct i2c_board_info __initdata netxbig_v2_i2c_info[] = {
-	{
-		I2C_BOARD_INFO("24c04", 0x50),
-		.platform_data  = &at24c04,
-	}
-};
-
 /*****************************************************************************
 /*****************************************************************************
  * SATA
  * SATA
  ****************************************************************************/
  ****************************************************************************/
@@ -114,34 +57,6 @@ static struct mv_sata_platform_data netxbig_v2_sata_data = {
 	.n_ports	= 2,
 	.n_ports	= 2,
 };
 };
 
 
-static int __initdata netxbig_v2_gpio_hdd_power[] = { 16, 17, 41, 42, 43 };
-
-static void __init netxbig_v2_sata_power_init(void)
-{
-	int i;
-	int err;
-	int hdd_nb;
-
-	if (machine_is_net2big_v2())
-		hdd_nb = 2;
-	else
-		hdd_nb = 5;
-
-	/* Power up all hard disks. */
-	for (i = 0; i < hdd_nb; i++) {
-		err = gpio_request(netxbig_v2_gpio_hdd_power[i], NULL);
-		if (err == 0) {
-			err = gpio_direction_output(
-					netxbig_v2_gpio_hdd_power[i], 1);
-			/* Free the HDD power GPIOs. This allow user-space to
-			 * configure them via the gpiolib sysfs interface. */
-			gpio_free(netxbig_v2_gpio_hdd_power[i]);
-		}
-		if (err)
-			pr_err("netxbig_v2: failed to power up HDD%d\n", i + 1);
-	}
-}
-
 /*****************************************************************************
 /*****************************************************************************
  * GPIO keys
  * GPIO keys
  ****************************************************************************/
  ****************************************************************************/
@@ -190,7 +105,7 @@ static struct platform_device netxbig_v2_gpio_buttons = {
 };
 };
 
 
 /*****************************************************************************
 /*****************************************************************************
- * GPIO LEDs
+ * GPIO extension LEDs
  ****************************************************************************/
  ****************************************************************************/
 
 
 /*
 /*
@@ -200,19 +115,32 @@ static struct platform_device netxbig_v2_gpio_buttons = {
  * - address register : bit [0-2] -> GPIO [47-49]
  * - address register : bit [0-2] -> GPIO [47-49]
  * - data register    : bit [0-2] -> GPIO [44-46]
  * - data register    : bit [0-2] -> GPIO [44-46]
  * - enable register  : GPIO 29
  * - enable register  : GPIO 29
- *
+ */
+
+static int netxbig_v2_gpio_ext_addr[] = { 47, 48, 49 };
+static int netxbig_v2_gpio_ext_data[] = { 44, 45, 46 };
+
+static struct netxbig_gpio_ext netxbig_v2_gpio_ext = {
+	.addr		= netxbig_v2_gpio_ext_addr,
+	.num_addr	= ARRAY_SIZE(netxbig_v2_gpio_ext_addr),
+	.data		= netxbig_v2_gpio_ext_data,
+	.num_data	= ARRAY_SIZE(netxbig_v2_gpio_ext_data),
+	.enable		= 29,
+};
+
+/*
  * Address register selection:
  * Address register selection:
  *
  *
  * addr | register
  * addr | register
  * ----------------------------
  * ----------------------------
  *   0  | front LED
  *   0  | front LED
  *   1  | front LED brightness
  *   1  | front LED brightness
- *   2  | HDD LED brightness
- *   3  | HDD1 LED
- *   4  | HDD2 LED
- *   5  | HDD3 LED
- *   6  | HDD4 LED
- *   7  | HDD5 LED
+ *   2  | SATA LED brightness
+ *   3  | SATA0 LED
+ *   4  | SATA1 LED
+ *   5  | SATA2 LED
+ *   6  | SATA3 LED
+ *   7  | SATA4 LED
  *
  *
  * Data register configuration:
  * Data register configuration:
  *
  *
@@ -233,30 +161,107 @@ static struct platform_device netxbig_v2_gpio_buttons = {
  *   6  | blink blue on=1 sec and red on=1 sec
  *   6  | blink blue on=1 sec and red on=1 sec
  *   7  | blink blue on=0.5 sec and blue off=2.5 sec
  *   7  | blink blue on=0.5 sec and blue off=2.5 sec
  *
  *
- * data | HDD LED mode
+ * data | SATA LED mode
  * -------------------------------------------------
  * -------------------------------------------------
- *   0  | fix blue on
+ *   0  | fix off
  *   1  | SATA activity blink
  *   1  | SATA activity blink
  *   2  | fix red on
  *   2  | fix red on
  *   3  | blink blue on=1 sec and blue off=1 sec
  *   3  | blink blue on=1 sec and blue off=1 sec
  *   4  | blink red on=1 sec and red off=1 sec
  *   4  | blink red on=1 sec and red off=1 sec
  *   5  | blink blue on=2.5 sec and red on=0.5 sec
  *   5  | blink blue on=2.5 sec and red on=0.5 sec
  *   6  | blink blue on=1 sec and red on=1 sec
  *   6  | blink blue on=1 sec and red on=1 sec
- *   7  | blink blue on=0.5 sec and blue off=2.5 sec
+ *   7  | fix blue on
  */
  */
 
 
-/*****************************************************************************
- * Timer
- ****************************************************************************/
+static int netxbig_v2_red_mled[NETXBIG_LED_MODE_NUM] = {
+	[NETXBIG_LED_OFF]	= 0,
+	[NETXBIG_LED_ON]	= 2,
+	[NETXBIG_LED_SATA]	= NETXBIG_LED_INVALID_MODE,
+	[NETXBIG_LED_TIMER1]	= 4,
+	[NETXBIG_LED_TIMER2]	= NETXBIG_LED_INVALID_MODE,
+};
 
 
-static void netxbig_v2_timer_init(void)
-{
-	kirkwood_tclk = 166666667;
-	orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
-}
+static int netxbig_v2_blue_pwr_mled[NETXBIG_LED_MODE_NUM] = {
+	[NETXBIG_LED_OFF]	= 0,
+	[NETXBIG_LED_ON]	= 1,
+	[NETXBIG_LED_SATA]	= NETXBIG_LED_INVALID_MODE,
+	[NETXBIG_LED_TIMER1]	= 3,
+	[NETXBIG_LED_TIMER2]	= 7,
+};
+
+static int netxbig_v2_blue_sata_mled[NETXBIG_LED_MODE_NUM] = {
+	[NETXBIG_LED_OFF]	= 0,
+	[NETXBIG_LED_ON]	= 7,
+	[NETXBIG_LED_SATA]	= 1,
+	[NETXBIG_LED_TIMER1]	= 3,
+	[NETXBIG_LED_TIMER2]	= NETXBIG_LED_INVALID_MODE,
+};
+
+static struct netxbig_led_timer netxbig_v2_led_timer[] = {
+	[0] = {
+		.delay_on	= 500,
+		.delay_off	= 500,
+		.mode		= NETXBIG_LED_TIMER1,
+	},
+	[1] = {
+		.delay_on	= 500,
+		.delay_off	= 1000,
+		.mode		= NETXBIG_LED_TIMER2,
+	},
+};
+
+#define NETXBIG_LED(_name, maddr, mval, baddr)			\
+	{ .name		= _name,				\
+	  .mode_addr	= maddr,				\
+	  .mode_val	= mval,					\
+	  .bright_addr	= baddr }
+
+static struct netxbig_led net2big_v2_leds_ctrl[] = {
+	NETXBIG_LED("net2big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled,  1),
+	NETXBIG_LED("net2big-v2:red:power",  0, netxbig_v2_red_mled,       1),
+	NETXBIG_LED("net2big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net2big-v2:red:sata0",  3, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net2big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net2big-v2:red:sata1",  4, netxbig_v2_red_mled,       2),
+};
+
+static struct netxbig_led_platform_data net2big_v2_leds_data = {
+	.gpio_ext	= &netxbig_v2_gpio_ext,
+	.timer		= netxbig_v2_led_timer,
+	.num_timer	= ARRAY_SIZE(netxbig_v2_led_timer),
+	.leds		= net2big_v2_leds_ctrl,
+	.num_leds	= ARRAY_SIZE(net2big_v2_leds_ctrl),
+};
+
+static struct netxbig_led net5big_v2_leds_ctrl[] = {
+	NETXBIG_LED("net5big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled,  1),
+	NETXBIG_LED("net5big-v2:red:power",  0, netxbig_v2_red_mled,       1),
+	NETXBIG_LED("net5big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata0",  3, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata1",  4, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata2", 5, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata2",  5, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata3", 6, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata3",  6, netxbig_v2_red_mled,       2),
+	NETXBIG_LED("net5big-v2:blue:sata4", 7, netxbig_v2_blue_sata_mled, 2),
+	NETXBIG_LED("net5big-v2:red:sata5",  7, netxbig_v2_red_mled,       2),
+};
 
 
-struct sys_timer netxbig_v2_timer = {
-	.init = netxbig_v2_timer_init,
+static struct netxbig_led_platform_data net5big_v2_leds_data = {
+	.gpio_ext	= &netxbig_v2_gpio_ext,
+	.timer		= netxbig_v2_led_timer,
+	.num_timer	= ARRAY_SIZE(netxbig_v2_led_timer),
+	.leds		= net5big_v2_leds_ctrl,
+	.num_leds	= ARRAY_SIZE(net5big_v2_leds_ctrl),
+};
+
+static struct platform_device netxbig_v2_leds = {
+	.name		= "leds-netxbig",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &net2big_v2_leds_data,
+	},
 };
 };
 
 
 /*****************************************************************************
 /*****************************************************************************
@@ -284,18 +289,18 @@ static unsigned int net2big_v2_mpp_config[] __initdata = {
 	MPP24_GPIO,		/* USB mode select */
 	MPP24_GPIO,		/* USB mode select */
 	MPP26_GPIO,		/* USB device vbus */
 	MPP26_GPIO,		/* USB device vbus */
 	MPP28_GPIO,		/* USB enable host vbus */
 	MPP28_GPIO,		/* USB enable host vbus */
-	MPP29_GPIO,		/* CPLD extension ALE */
+	MPP29_GPIO,		/* GPIO extension ALE */
 	MPP34_GPIO,		/* Rear Push button */
 	MPP34_GPIO,		/* Rear Push button */
 	MPP35_GPIO,		/* Inhibit switch power-off */
 	MPP35_GPIO,		/* Inhibit switch power-off */
 	MPP36_GPIO,		/* SATA HDD1 presence */
 	MPP36_GPIO,		/* SATA HDD1 presence */
 	MPP37_GPIO,		/* SATA HDD2 presence */
 	MPP37_GPIO,		/* SATA HDD2 presence */
 	MPP40_GPIO,		/* eSATA presence */
 	MPP40_GPIO,		/* eSATA presence */
-	MPP44_GPIO,		/* CPLD extension (data 0) */
-	MPP45_GPIO,		/* CPLD extension (data 1) */
-	MPP46_GPIO,		/* CPLD extension (data 2) */
-	MPP47_GPIO,		/* CPLD extension (addr 0) */
-	MPP48_GPIO,		/* CPLD extension (addr 1) */
-	MPP49_GPIO,		/* CPLD extension (addr 2) */
+	MPP44_GPIO,		/* GPIO extension (data 0) */
+	MPP45_GPIO,		/* GPIO extension (data 1) */
+	MPP46_GPIO,		/* GPIO extension (data 2) */
+	MPP47_GPIO,		/* GPIO extension (addr 0) */
+	MPP48_GPIO,		/* GPIO extension (addr 1) */
+	MPP49_GPIO,		/* GPIO extension (addr 2) */
 	0
 	0
 };
 };
 
 
@@ -324,7 +329,7 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
 	MPP26_GE1_RXD2,
 	MPP26_GE1_RXD2,
 	MPP27_GE1_RXD3,
 	MPP27_GE1_RXD3,
 	MPP28_GPIO,		/* USB enable host vbus */
 	MPP28_GPIO,		/* USB enable host vbus */
-	MPP29_GPIO,		/* CPLD extension ALE */
+	MPP29_GPIO,		/* GPIO extension ALE */
 	MPP30_GE1_RXCTL,
 	MPP30_GE1_RXCTL,
 	MPP31_GE1_RXCLK,
 	MPP31_GE1_RXCLK,
 	MPP32_GE1_TCLKOUT,
 	MPP32_GE1_TCLKOUT,
@@ -339,12 +344,12 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
 	MPP41_GPIO,		/* SATA HDD3 power */
 	MPP41_GPIO,		/* SATA HDD3 power */
 	MPP42_GPIO,		/* SATA HDD4 power */
 	MPP42_GPIO,		/* SATA HDD4 power */
 	MPP43_GPIO,		/* SATA HDD5 power */
 	MPP43_GPIO,		/* SATA HDD5 power */
-	MPP44_GPIO,		/* CPLD extension (data 0) */
-	MPP45_GPIO,		/* CPLD extension (data 1) */
-	MPP46_GPIO,		/* CPLD extension (data 2) */
-	MPP47_GPIO,		/* CPLD extension (addr 0) */
-	MPP48_GPIO,		/* CPLD extension (addr 1) */
-	MPP49_GPIO,		/* CPLD extension (addr 2) */
+	MPP44_GPIO,		/* GPIO extension (data 0) */
+	MPP45_GPIO,		/* GPIO extension (data 1) */
+	MPP46_GPIO,		/* GPIO extension (data 2) */
+	MPP47_GPIO,		/* GPIO extension (addr 0) */
+	MPP48_GPIO,		/* GPIO extension (addr 1) */
+	MPP49_GPIO,		/* GPIO extension (addr 2) */
 	0
 	0
 };
 };
 
 
@@ -366,7 +371,10 @@ static void __init netxbig_v2_init(void)
 	else
 	else
 		kirkwood_mpp_conf(net5big_v2_mpp_config);
 		kirkwood_mpp_conf(net5big_v2_mpp_config);
 
 
-	netxbig_v2_sata_power_init();
+	if (machine_is_net2big_v2())
+		lacie_v2_hdd_power_init(2);
+	else
+		lacie_v2_hdd_power_init(5);
 
 
 	kirkwood_ehci_init();
 	kirkwood_ehci_init();
 	kirkwood_ge00_init(&netxbig_v2_ge00_data);
 	kirkwood_ge00_init(&netxbig_v2_ge00_data);
@@ -374,13 +382,12 @@ static void __init netxbig_v2_init(void)
 		kirkwood_ge01_init(&netxbig_v2_ge01_data);
 		kirkwood_ge01_init(&netxbig_v2_ge01_data);
 	kirkwood_sata_init(&netxbig_v2_sata_data);
 	kirkwood_sata_init(&netxbig_v2_sata_data);
 	kirkwood_uart0_init();
 	kirkwood_uart0_init();
-	spi_register_board_info(netxbig_v2_spi_slave_info,
-				ARRAY_SIZE(netxbig_v2_spi_slave_info));
-	kirkwood_spi_init();
-	kirkwood_i2c_init();
-	i2c_register_board_info(0, netxbig_v2_i2c_info,
-				ARRAY_SIZE(netxbig_v2_i2c_info));
+	lacie_v2_register_flash();
+	lacie_v2_register_i2c_devices();
 
 
+	if (machine_is_net5big_v2())
+		netxbig_v2_leds.dev.platform_data = &net5big_v2_leds_data;
+	platform_device_register(&netxbig_v2_leds);
 	platform_device_register(&netxbig_v2_gpio_buttons);
 	platform_device_register(&netxbig_v2_gpio_buttons);
 
 
 	if (gpio_request(NETXBIG_V2_GPIO_POWER_OFF, "power-off") == 0 &&
 	if (gpio_request(NETXBIG_V2_GPIO_POWER_OFF, "power-off") == 0 &&
@@ -398,7 +405,7 @@ MACHINE_START(NET2BIG_V2, "LaCie 2Big Network v2")
 	.init_machine	= netxbig_v2_init,
 	.init_machine	= netxbig_v2_init,
 	.map_io		= kirkwood_map_io,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netxbig_v2_timer,
+	.timer		= &lacie_v2_timer,
 MACHINE_END
 MACHINE_END
 #endif
 #endif
 
 
@@ -410,6 +417,6 @@ MACHINE_START(NET5BIG_V2, "LaCie 5Big Network v2")
 	.init_machine	= netxbig_v2_init,
 	.init_machine	= netxbig_v2_init,
 	.map_io		= kirkwood_map_io,
 	.map_io		= kirkwood_map_io,
 	.init_irq	= kirkwood_init_irq,
 	.init_irq	= kirkwood_init_irq,
-	.timer		= &netxbig_v2_timer,
+	.timer		= &lacie_v2_timer,
 MACHINE_END
 MACHINE_END
 #endif
 #endif

+ 100 - 1
arch/arm/mach-kirkwood/openrd-setup.c

@@ -16,6 +16,7 @@
 #include <linux/ata_platform.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
 #include <mach/kirkwood.h>
@@ -57,7 +58,22 @@ static struct mvsdio_platform_data openrd_mvsdio_data = {
 };
 };
 
 
 static unsigned int openrd_mpp_config[] __initdata = {
 static unsigned int openrd_mpp_config[] __initdata = {
+	MPP12_SD_CLK,
+	MPP13_SD_CMD,
+	MPP14_SD_D0,
+	MPP15_SD_D1,
+	MPP16_SD_D2,
+	MPP17_SD_D3,
+	MPP28_GPIO,
 	MPP29_GPIO,
 	MPP29_GPIO,
+	MPP34_GPIO,
+	0
+};
+
+/* Configure MPP for UART1 */
+static unsigned int openrd_uart1_mpp_config[] __initdata = {
+	MPP13_UART1_TXD,
+	MPP14_UART1_RXD,
 	0
 	0
 };
 };
 
 
@@ -67,6 +83,68 @@ static struct i2c_board_info i2c_board_info[] __initdata = {
 	},
 	},
 };
 };
 
 
+static int __initdata uart1;
+
+static int __init sd_uart_selection(char *str)
+{
+	uart1 = -EINVAL;
+
+	/* Default is SD. Change if required, for UART */
+	if (!str)
+		return 0;
+
+	if (!strncmp(str, "232", 3)) {
+		uart1 = 232;
+	} else if (!strncmp(str, "485", 3)) {
+		/* OpenRD-Base doesn't have RS485. Treat is as an
+		 * unknown argument & just have default setting -
+		 * which is SD */
+		if (machine_is_openrd_base()) {
+			uart1 = -ENODEV;
+			return 1;
+		}
+
+		uart1 = 485;
+	}
+	return 1;
+}
+/* Parse boot_command_line string kw_openrd_init_uart1=232/485 */
+__setup("kw_openrd_init_uart1=", sd_uart_selection);
+
+static int __init uart1_mpp_config(void)
+{
+	kirkwood_mpp_conf(openrd_uart1_mpp_config);
+
+	if (gpio_request(34, "SD_UART1_SEL")) {
+		printk(KERN_ERR "GPIO request failed for SD/UART1 selection"
+				", gpio: 34\n");
+		return -EIO;
+	}
+
+	if (gpio_request(28, "RS232_RS485_SEL")) {
+		printk(KERN_ERR "GPIO request failed for RS232/RS485 selection"
+				", gpio# 28\n");
+		gpio_free(34);
+		return -EIO;
+	}
+
+	/* Select UART1
+	 * Pin # 34: 0 => UART1, 1 => SD */
+	gpio_direction_output(34, 0);
+
+	/* Select RS232 OR RS485
+	 * Pin # 28: 0 => RS232, 1 => RS485 */
+	if (uart1 == 232)
+		gpio_direction_output(28, 0);
+	else
+		gpio_direction_output(28, 1);
+
+	gpio_free(34);
+	gpio_free(28);
+
+	return 0;
+}
+
 static void __init openrd_init(void)
 static void __init openrd_init(void)
 {
 {
 	/*
 	/*
@@ -90,7 +168,6 @@ static void __init openrd_init(void)
 		kirkwood_ge01_init(&openrd_ge01_data);
 		kirkwood_ge01_init(&openrd_ge01_data);
 
 
 	kirkwood_sata_init(&openrd_sata_data);
 	kirkwood_sata_init(&openrd_sata_data);
-	kirkwood_sdio_init(&openrd_mvsdio_data);
 
 
 	kirkwood_i2c_init();
 	kirkwood_i2c_init();
 
 
@@ -99,6 +176,28 @@ static void __init openrd_init(void)
 			ARRAY_SIZE(i2c_board_info));
 			ARRAY_SIZE(i2c_board_info));
 		kirkwood_audio_init();
 		kirkwood_audio_init();
 	}
 	}
+
+	if (uart1 <= 0) {
+		if (uart1 < 0)
+			printk(KERN_ERR "Invalid kernel parameter to select "
+				"UART1. Defaulting to SD. ERROR CODE: %d\n",
+				uart1);
+
+		/* Select SD
+		 * Pin # 34: 0 => UART1, 1 => SD */
+		if (gpio_request(34, "SD_UART1_SEL")) {
+			printk(KERN_ERR "GPIO request failed for SD/UART1 "
+					"selection, gpio: 34\n");
+		} else {
+
+			gpio_direction_output(34, 1);
+			gpio_free(34);
+			kirkwood_sdio_init(&openrd_mvsdio_data);
+		}
+	} else {
+		if (!uart1_mpp_config())
+			kirkwood_uart1_init();
+	}
 }
 }
 
 
 static int __init openrd_pci_init(void)
 static int __init openrd_pci_init(void)

+ 10 - 1
drivers/leds/Kconfig

@@ -304,13 +304,22 @@ config LEDS_MC13783
 
 
 config LEDS_NS2
 config LEDS_NS2
 	tristate "LED support for Network Space v2 GPIO LEDs"
 	tristate "LED support for Network Space v2 GPIO LEDs"
-	depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2
+	depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 || D2NET_V2
 	default y
 	default y
 	help
 	help
 	  This option enable support for the dual-GPIO LED found on the
 	  This option enable support for the dual-GPIO LED found on the
 	  Network Space v2 board (and parents). This include Internet Space v2,
 	  Network Space v2 board (and parents). This include Internet Space v2,
 	  Network Space (Max) v2 and d2 Network v2 boards.
 	  Network Space (Max) v2 and d2 Network v2 boards.
 
 
+config LEDS_NETXBIG
+	tristate "LED support for Big Network series LEDs"
+	depends on MACH_NET2BIG_V2 || MACH_NET5BIG_V2
+	default y
+	help
+	  This option enable support for LEDs found on the LaCie 2Big
+	  and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
+	  controlled through a GPIO extension bus.
+
 config LEDS_TRIGGERS
 config LEDS_TRIGGERS
 	bool "LED Trigger support"
 	bool "LED Trigger support"
 	help
 	help

+ 1 - 0
drivers/leds/Makefile

@@ -38,6 +38,7 @@ obj-$(CONFIG_LEDS_ADP5520)		+= leds-adp5520.o
 obj-$(CONFIG_LEDS_DELL_NETBOOKS)	+= dell-led.o
 obj-$(CONFIG_LEDS_DELL_NETBOOKS)	+= dell-led.o
 obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
 obj-$(CONFIG_LEDS_MC13783)		+= leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
 obj-$(CONFIG_LEDS_NS2)			+= leds-ns2.o
+obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
 
 
 # LED SPI Drivers
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o

+ 449 - 0
drivers/leds/leds-netxbig.c

@@ -0,0 +1,449 @@
+/*
+ * leds-netxbig.c - Driver for the 2Big and 5Big Network series LEDs
+ *
+ * Copyright (C) 2010 LaCie
+ *
+ * Author: Simon Guinot <sguinot@lacie.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <mach/leds-netxbig.h>
+
+/*
+ * GPIO extension bus.
+ */
+
+static DEFINE_SPINLOCK(gpio_ext_lock);
+
+static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr)
+{
+	int pin;
+
+	for (pin = 0; pin < gpio_ext->num_addr; pin++)
+		gpio_set_value(gpio_ext->addr[pin], (addr >> pin) & 1);
+}
+
+static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data)
+{
+	int pin;
+
+	for (pin = 0; pin < gpio_ext->num_data; pin++)
+		gpio_set_value(gpio_ext->data[pin], (data >> pin) & 1);
+}
+
+static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext)
+{
+	/* Enable select is done on the raising edge. */
+	gpio_set_value(gpio_ext->enable, 0);
+	gpio_set_value(gpio_ext->enable, 1);
+}
+
+static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
+			       int addr, int value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&gpio_ext_lock, flags);
+	gpio_ext_set_addr(gpio_ext, addr);
+	gpio_ext_set_data(gpio_ext, value);
+	gpio_ext_enable_select(gpio_ext);
+	spin_unlock_irqrestore(&gpio_ext_lock, flags);
+}
+
+static int __devinit gpio_ext_init(struct netxbig_gpio_ext *gpio_ext)
+{
+	int err;
+	int i;
+
+	if (unlikely(!gpio_ext))
+		return -EINVAL;
+
+	/* Configure address GPIOs. */
+	for (i = 0; i < gpio_ext->num_addr; i++) {
+		err = gpio_request(gpio_ext->addr[i], "GPIO extension addr");
+		if (err)
+			goto err_free_addr;
+		err = gpio_direction_output(gpio_ext->addr[i], 0);
+		if (err) {
+			gpio_free(gpio_ext->addr[i]);
+			goto err_free_addr;
+		}
+	}
+	/* Configure data GPIOs. */
+	for (i = 0; i < gpio_ext->num_data; i++) {
+		err = gpio_request(gpio_ext->data[i], "GPIO extension data");
+		if (err)
+			goto err_free_data;
+		err = gpio_direction_output(gpio_ext->data[i], 0);
+		if (err) {
+			gpio_free(gpio_ext->data[i]);
+			goto err_free_data;
+		}
+	}
+	/* Configure "enable select" GPIO. */
+	err = gpio_request(gpio_ext->enable, "GPIO extension enable");
+	if (err)
+		goto err_free_data;
+	err = gpio_direction_output(gpio_ext->enable, 0);
+	if (err) {
+		gpio_free(gpio_ext->enable);
+		goto err_free_data;
+	}
+
+	return 0;
+
+err_free_data:
+	for (i = i - 1; i >= 0; i--)
+		gpio_free(gpio_ext->data[i]);
+	i = gpio_ext->num_addr;
+err_free_addr:
+	for (i = i - 1; i >= 0; i--)
+		gpio_free(gpio_ext->addr[i]);
+
+	return err;
+}
+
+static void __devexit gpio_ext_free(struct netxbig_gpio_ext *gpio_ext)
+{
+	int i;
+
+	gpio_free(gpio_ext->enable);
+	for (i = gpio_ext->num_addr - 1; i >= 0; i--)
+		gpio_free(gpio_ext->addr[i]);
+	for (i = gpio_ext->num_data - 1; i >= 0; i--)
+		gpio_free(gpio_ext->data[i]);
+}
+
+/*
+ * Class LED driver.
+ */
+
+struct netxbig_led_data {
+	struct netxbig_gpio_ext	*gpio_ext;
+	struct led_classdev	cdev;
+	int			mode_addr;
+	int			*mode_val;
+	int			bright_addr;
+	int			bright_max;
+	struct			netxbig_led_timer *timer;
+	int			num_timer;
+	enum netxbig_led_mode	mode;
+	int			sata;
+	spinlock_t		lock;
+};
+
+static int netxbig_led_get_timer_mode(enum netxbig_led_mode *mode,
+				      unsigned long delay_on,
+				      unsigned long delay_off,
+				      struct netxbig_led_timer *timer,
+				      int num_timer)
+{
+	int i;
+
+	for (i = 0; i < num_timer; i++) {
+		if (timer[i].delay_on == delay_on &&
+		    timer[i].delay_off == delay_off) {
+			*mode = timer[i].mode;
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int netxbig_led_blink_set(struct led_classdev *led_cdev,
+				 unsigned long *delay_on,
+				 unsigned long *delay_off)
+{
+	struct netxbig_led_data *led_dat =
+		container_of(led_cdev, struct netxbig_led_data, cdev);
+	enum netxbig_led_mode mode;
+	int mode_val;
+	int ret;
+
+	/* Look for a LED mode with the requested timer frequency. */
+	ret = netxbig_led_get_timer_mode(&mode, *delay_on, *delay_off,
+					 led_dat->timer, led_dat->num_timer);
+	if (ret < 0)
+		return ret;
+
+	mode_val = led_dat->mode_val[mode];
+	if (mode_val == NETXBIG_LED_INVALID_MODE)
+		return -EINVAL;
+
+	spin_lock_irq(&led_dat->lock);
+
+	gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
+	led_dat->mode = mode;
+
+	spin_unlock_irq(&led_dat->lock);
+
+	return 0;
+}
+
+static void netxbig_led_set(struct led_classdev *led_cdev,
+			    enum led_brightness value)
+{
+	struct netxbig_led_data *led_dat =
+		container_of(led_cdev, struct netxbig_led_data, cdev);
+	enum netxbig_led_mode mode;
+	int mode_val, bright_val;
+	int set_brightness = 1;
+	unsigned long flags;
+
+	spin_lock_irqsave(&led_dat->lock, flags);
+
+	if (value == LED_OFF) {
+		mode = NETXBIG_LED_OFF;
+		set_brightness = 0;
+	} else {
+		if (led_dat->sata)
+			mode = NETXBIG_LED_SATA;
+		else if (led_dat->mode == NETXBIG_LED_OFF)
+			mode = NETXBIG_LED_ON;
+		else /* Keep 'timer' mode. */
+			mode = led_dat->mode;
+	}
+	mode_val = led_dat->mode_val[mode];
+
+	gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
+	led_dat->mode = mode;
+	/*
+	 * Note that the brightness register is shared between all the
+	 * SATA LEDs. So, change the brightness setting for a single
+	 * SATA LED will affect all the others.
+	 */
+	if (set_brightness) {
+		bright_val = DIV_ROUND_UP(value * led_dat->bright_max,
+					  LED_FULL);
+		gpio_ext_set_value(led_dat->gpio_ext,
+				   led_dat->bright_addr, bright_val);
+	}
+
+	spin_unlock_irqrestore(&led_dat->lock, flags);
+}
+
+static ssize_t netxbig_led_sata_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buff, size_t count)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct netxbig_led_data *led_dat =
+		container_of(led_cdev, struct netxbig_led_data, cdev);
+	unsigned long enable;
+	enum netxbig_led_mode mode;
+	int mode_val;
+	int ret;
+
+	ret = strict_strtoul(buff, 10, &enable);
+	if (ret < 0)
+		return ret;
+
+	enable = !!enable;
+
+	spin_lock_irq(&led_dat->lock);
+
+	if (led_dat->sata == enable) {
+		ret = count;
+		goto exit_unlock;
+	}
+
+	if (led_dat->mode != NETXBIG_LED_ON &&
+	    led_dat->mode != NETXBIG_LED_SATA)
+		mode = led_dat->mode; /* Keep modes 'off' and 'timer'. */
+	else if (enable)
+		mode = NETXBIG_LED_SATA;
+	else
+		mode = NETXBIG_LED_ON;
+
+	mode_val = led_dat->mode_val[mode];
+	if (mode_val == NETXBIG_LED_INVALID_MODE) {
+		ret = -EINVAL;
+		goto exit_unlock;
+	}
+
+	gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
+	led_dat->mode = mode;
+	led_dat->sata = enable;
+
+	ret = count;
+
+exit_unlock:
+	spin_unlock_irq(&led_dat->lock);
+
+	return ret;
+}
+
+static ssize_t netxbig_led_sata_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct netxbig_led_data *led_dat =
+		container_of(led_cdev, struct netxbig_led_data, cdev);
+
+	return sprintf(buf, "%d\n", led_dat->sata);
+}
+
+static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store);
+
+static void __devexit delete_netxbig_led(struct netxbig_led_data *led_dat)
+{
+	if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
+		device_remove_file(led_dat->cdev.dev, &dev_attr_sata);
+	led_classdev_unregister(&led_dat->cdev);
+}
+
+static int __devinit
+create_netxbig_led(struct platform_device *pdev,
+		   struct netxbig_led_data *led_dat,
+		   const struct netxbig_led *template)
+{
+	struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+	int ret;
+
+	spin_lock_init(&led_dat->lock);
+	led_dat->gpio_ext = pdata->gpio_ext;
+	led_dat->cdev.name = template->name;
+	led_dat->cdev.default_trigger = template->default_trigger;
+	led_dat->cdev.blink_set = netxbig_led_blink_set;
+	led_dat->cdev.brightness_set = netxbig_led_set;
+	/*
+	 * Because the GPIO extension bus don't allow to read registers
+	 * value, there is no way to probe the LED initial state.
+	 * So, the initial sysfs LED value for the "brightness" and "sata"
+	 * attributes are inconsistent.
+	 *
+	 * Note that the initial LED state can't be reconfigured.
+	 * The reason is that the LED behaviour must stay uniform during
+	 * the whole boot process (bootloader+linux).
+	 */
+	led_dat->sata = 0;
+	led_dat->cdev.brightness = LED_OFF;
+	led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
+	led_dat->mode_addr = template->mode_addr;
+	led_dat->mode_val = template->mode_val;
+	led_dat->bright_addr = template->bright_addr;
+	led_dat->bright_max = (1 << pdata->gpio_ext->num_data) - 1;
+	led_dat->timer = pdata->timer;
+	led_dat->num_timer = pdata->num_timer;
+
+	ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * If available, expose the SATA activity blink capability through
+	 * a "sata" sysfs attribute.
+	 */
+	if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) {
+		ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
+		if (ret)
+			led_classdev_unregister(&led_dat->cdev);
+	}
+
+	return ret;
+}
+
+static int __devinit netxbig_led_probe(struct platform_device *pdev)
+{
+	struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+	struct netxbig_led_data *leds_data;
+	int i;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	leds_data = kzalloc(sizeof(struct netxbig_led_data) * pdata->num_leds,
+			    GFP_KERNEL);
+	if (!leds_data)
+		return -ENOMEM;
+
+	ret = gpio_ext_init(pdata->gpio_ext);
+	if (ret < 0)
+		goto err_free_data;
+
+	for (i = 0; i < pdata->num_leds; i++) {
+		ret = create_netxbig_led(pdev, &leds_data[i], &pdata->leds[i]);
+		if (ret < 0)
+			goto err_free_leds;
+	}
+
+	platform_set_drvdata(pdev, leds_data);
+
+	return 0;
+
+err_free_leds:
+	for (i = i - 1; i >= 0; i--)
+		delete_netxbig_led(&leds_data[i]);
+
+	gpio_ext_free(pdata->gpio_ext);
+err_free_data:
+	kfree(leds_data);
+
+	return ret;
+}
+
+static int __devexit netxbig_led_remove(struct platform_device *pdev)
+{
+	struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+	struct netxbig_led_data *leds_data;
+	int i;
+
+	leds_data = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_leds; i++)
+		delete_netxbig_led(&leds_data[i]);
+
+	gpio_ext_free(pdata->gpio_ext);
+	kfree(leds_data);
+
+	return 0;
+}
+
+static struct platform_driver netxbig_led_driver = {
+	.probe		= netxbig_led_probe,
+	.remove		= __devexit_p(netxbig_led_remove),
+	.driver		= {
+		.name	= "leds-netxbig",
+		.owner	= THIS_MODULE,
+	},
+};
+MODULE_ALIAS("platform:leds-netxbig");
+
+static int __init netxbig_led_init(void)
+{
+	return platform_driver_register(&netxbig_led_driver);
+}
+
+static void __exit netxbig_led_exit(void)
+{
+	platform_driver_unregister(&netxbig_led_driver);
+}
+
+module_init(netxbig_led_init);
+module_exit(netxbig_led_exit);
+
+MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
+MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
+MODULE_LICENSE("GPL");

+ 6 - 3
drivers/leds/leds-ns2.c

@@ -141,10 +141,12 @@ static ssize_t ns2_led_sata_store(struct device *dev,
 				  struct device_attribute *attr,
 				  struct device_attribute *attr,
 				  const char *buff, size_t count)
 				  const char *buff, size_t count)
 {
 {
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct ns2_led_data *led_dat =
+		container_of(led_cdev, struct ns2_led_data, cdev);
 	int ret;
 	int ret;
 	unsigned long enable;
 	unsigned long enable;
 	enum ns2_led_modes mode;
 	enum ns2_led_modes mode;
-	struct ns2_led_data *led_dat = dev_get_drvdata(dev);
 
 
 	ret = strict_strtoul(buff, 10, &enable);
 	ret = strict_strtoul(buff, 10, &enable);
 	if (ret < 0)
 	if (ret < 0)
@@ -172,7 +174,9 @@ static ssize_t ns2_led_sata_store(struct device *dev,
 static ssize_t ns2_led_sata_show(struct device *dev,
 static ssize_t ns2_led_sata_show(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 				 struct device_attribute *attr, char *buf)
 {
 {
-	struct ns2_led_data *led_dat = dev_get_drvdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct ns2_led_data *led_dat =
+		container_of(led_cdev, struct ns2_led_data, cdev);
 
 
 	return sprintf(buf, "%d\n", led_dat->sata);
 	return sprintf(buf, "%d\n", led_dat->sata);
 }
 }
@@ -234,7 +238,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
 	if (ret < 0)
 	if (ret < 0)
 		goto err_free_slow;
 		goto err_free_slow;
 
 
-	dev_set_drvdata(led_dat->cdev.dev, led_dat);
 	ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
 	ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
 	if (ret < 0)
 	if (ret < 0)
 		goto err_free_cdev;
 		goto err_free_cdev;