提交 4af8f24d 编写于 作者: R Russell King
......@@ -15,6 +15,7 @@ CONFIG_MACH_MV88F6281GTW_GE=y
CONFIG_MACH_SHEEVAPLUG=y
CONFIG_MACH_ESATA_SHEEVAPLUG=y
CONFIG_MACH_GURUPLUG=y
CONFIG_MACH_DOCKSTAR=y
CONFIG_MACH_TS219=y
CONFIG_MACH_TS41X=y
CONFIG_MACH_OPENRD_BASE=y
......
......@@ -58,6 +58,12 @@ config MACH_TS41X
QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS
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
bool
......@@ -100,6 +106,12 @@ config MACH_NETSPACE_MAX_V2
Say 'Y' here if you want your kernel to support the
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
bool "LaCie 2Big Network v2 NAS Board"
help
......
......@@ -7,14 +7,16 @@ obj-$(CONFIG_MACH_MV88F6281GTW_GE) += mv88f6281gtw_ge-setup.o
obj-$(CONFIG_MACH_SHEEVAPLUG) += sheevaplug-setup.o
obj-$(CONFIG_MACH_ESATA_SHEEVAPLUG) += sheevaplug-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_TS41X) += ts41x-setup.o tsx1x-common.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_CPU_IDLE) += cpuidle.o
/*
* 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
/*
* 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
/*
* 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 */
/*
* 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,
};
/*
* 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
......@@ -24,56 +24,19 @@
#include <linux/kernel.h>
#include <linux/init.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/mv643xx_eth.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.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 <asm/mach/time.h>
#include <mach/kirkwood.h>
#include <mach/leds-ns2.h>
#include <plat/time.h>
#include "common.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
......@@ -83,27 +46,6 @@ static struct mv643xx_eth_platform_data netspace_v2_ge00_data = {
.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
****************************************************************************/
......@@ -112,35 +54,6 @@ static struct mv_sata_platform_data netspace_v2_sata_data = {
.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
****************************************************************************/
......@@ -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
****************************************************************************/
......@@ -291,18 +190,17 @@ static void __init netspace_v2_init(void)
kirkwood_init();
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_ge00_init(&netspace_v2_ge00_data);
kirkwood_sata_init(&netspace_v2_sata_data);
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_gpio_leds);
......@@ -323,7 +221,7 @@ MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
.init_machine = netspace_v2_init,
.map_io = kirkwood_map_io,
.init_irq = kirkwood_init_irq,
.timer = &netspace_v2_timer,
.timer = &lacie_v2_timer,
MACHINE_END
#endif
......@@ -335,7 +233,7 @@ MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
.init_machine = netspace_v2_init,
.map_io = kirkwood_map_io,
.init_irq = kirkwood_init_irq,
.timer = &netspace_v2_timer,
.timer = &lacie_v2_timer,
MACHINE_END
#endif
......@@ -347,6 +245,6 @@ MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
.init_machine = netspace_v2_init,
.map_io = kirkwood_map_io,
.init_irq = kirkwood_init_irq,
.timer = &netspace_v2_timer,
.timer = &lacie_v2_timer,
MACHINE_END
#endif
......@@ -23,55 +23,19 @@
#include <linux/kernel.h>
#include <linux/init.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/mv643xx_eth.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.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 <asm/mach/time.h>
#include <mach/kirkwood.h>
#include <plat/time.h>
#include <mach/leds-netxbig.h>
#include "common.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
......@@ -85,27 +49,6 @@ static struct mv643xx_eth_platform_data netxbig_v2_ge01_data = {
.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
****************************************************************************/
......@@ -114,34 +57,6 @@ static struct mv_sata_platform_data netxbig_v2_sata_data = {
.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
****************************************************************************/
......@@ -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]
* - data register : bit [0-2] -> GPIO [44-46]
* - 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:
*
* addr | register
* ----------------------------
* 0 | front LED
* 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:
*
......@@ -233,30 +161,107 @@ static struct platform_device netxbig_v2_gpio_buttons = {
* 6 | blink blue on=1 sec and red on=1 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
* 2 | fix red on
* 3 | blink blue on=1 sec and blue 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
* 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 */
MPP26_GPIO, /* USB device vbus */
MPP28_GPIO, /* USB enable host vbus */
MPP29_GPIO, /* CPLD extension ALE */
MPP29_GPIO, /* GPIO extension ALE */
MPP34_GPIO, /* Rear Push button */
MPP35_GPIO, /* Inhibit switch power-off */
MPP36_GPIO, /* SATA HDD1 presence */
MPP37_GPIO, /* SATA HDD2 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
};
......@@ -324,7 +329,7 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
MPP26_GE1_RXD2,
MPP27_GE1_RXD3,
MPP28_GPIO, /* USB enable host vbus */
MPP29_GPIO, /* CPLD extension ALE */
MPP29_GPIO, /* GPIO extension ALE */
MPP30_GE1_RXCTL,
MPP31_GE1_RXCLK,
MPP32_GE1_TCLKOUT,
......@@ -339,12 +344,12 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
MPP41_GPIO, /* SATA HDD3 power */
MPP42_GPIO, /* SATA HDD4 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
};
......@@ -366,7 +371,10 @@ static void __init netxbig_v2_init(void)
else
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_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_sata_init(&netxbig_v2_sata_data);
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);
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,
.map_io = kirkwood_map_io,
.init_irq = kirkwood_init_irq,
.timer = &netxbig_v2_timer,
.timer = &lacie_v2_timer,
MACHINE_END
#endif
......@@ -410,6 +417,6 @@ MACHINE_START(NET5BIG_V2, "LaCie 5Big Network v2")
.init_machine = netxbig_v2_init,
.map_io = kirkwood_map_io,
.init_irq = kirkwood_init_irq,
.timer = &netxbig_v2_timer,
.timer = &lacie_v2_timer,
MACHINE_END
#endif
......@@ -16,6 +16,7 @@
#include <linux/ata_platform.h>
#include <linux/mv643xx_eth.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
......@@ -57,7 +58,22 @@ static struct mvsdio_platform_data openrd_mvsdio_data = {
};
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,
MPP34_GPIO,
0
};
/* Configure MPP for UART1 */
static unsigned int openrd_uart1_mpp_config[] __initdata = {
MPP13_UART1_TXD,
MPP14_UART1_RXD,
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)
{
/*
......@@ -90,7 +168,6 @@ static void __init openrd_init(void)
kirkwood_ge01_init(&openrd_ge01_data);
kirkwood_sata_init(&openrd_sata_data);
kirkwood_sdio_init(&openrd_mvsdio_data);
kirkwood_i2c_init();
......@@ -99,6 +176,28 @@ static void __init openrd_init(void)
ARRAY_SIZE(i2c_board_info));
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)
......
......@@ -304,13 +304,22 @@ config LEDS_MC13783
config LEDS_NS2
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
help
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 (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
bool "LED Trigger support"
help
......
......@@ -38,6 +38,7 @@ obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o
obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
......
/*
* 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");
......@@ -141,10 +141,12 @@ static ssize_t ns2_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 ns2_led_data *led_dat =
container_of(led_cdev, struct ns2_led_data, cdev);
int ret;
unsigned long enable;
enum ns2_led_modes mode;
struct ns2_led_data *led_dat = dev_get_drvdata(dev);
ret = strict_strtoul(buff, 10, &enable);
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,
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);
}
......@@ -234,7 +238,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
if (ret < 0)
goto err_free_slow;
dev_set_drvdata(led_dat->cdev.dev, led_dat);
ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
if (ret < 0)
goto err_free_cdev;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册