mirror of
https://github.com/archlinuxarm/PKGBUILDs.git
synced 2024-11-28 22:57:37 +00:00
3988 lines
102 KiB
Diff
3988 lines
102 KiB
Diff
diff -urN a/arch/arm/mach-kirkwood/dockstar-setup.c b/arch/arm/mach-kirkwood/dockstar-setup.c
|
|
--- a/arch/arm/mach-kirkwood/dockstar-setup.c 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/arch/arm/mach-kirkwood/dockstar-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -19,7 +19,6 @@
|
|
#include <asm/mach-types.h>
|
|
#include <asm/mach/arch.h>
|
|
#include <mach/kirkwood.h>
|
|
-#include <plat/mvsdio.h>
|
|
#include "common.h"
|
|
#include "mpp.h"
|
|
|
|
@@ -33,6 +32,10 @@
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = SZ_4M
|
|
}, {
|
|
+ .name = "pogoplug",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M
|
|
+ }, {
|
|
.name = "root",
|
|
.offset = MTDPART_OFS_NXTBLK,
|
|
.size = MTDPART_SIZ_FULL
|
|
@@ -45,17 +48,17 @@
|
|
|
|
static struct gpio_led dockstar_led_pins[] = {
|
|
{
|
|
- .name = "dockstar:green:health",
|
|
+ .name = "status:green:health",
|
|
.default_trigger = "default-on",
|
|
.gpio = 46,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "dockstar:orange:misc",
|
|
+ .name = "status:orange:fault",
|
|
.default_trigger = "none",
|
|
.gpio = 47,
|
|
.active_low = 1,
|
|
- },
|
|
+ }
|
|
};
|
|
|
|
static struct gpio_led_platform_data dockstar_led_data = {
|
|
@@ -73,8 +76,8 @@
|
|
|
|
static unsigned int dockstar_mpp_config[] __initdata = {
|
|
MPP29_GPIO, /* USB Power Enable */
|
|
- MPP46_GPIO, /* LED green */
|
|
- MPP47_GPIO, /* LED orange */
|
|
+ MPP47_GPIO, /* LED Orange */
|
|
+ MPP46_GPIO, /* LED Green */
|
|
0
|
|
};
|
|
|
|
diff -urN a/arch/arm/mach-kirkwood/goflexhome-setup.c b/arch/arm/mach-kirkwood/goflexhome-setup.c
|
|
--- a/arch/arm/mach-kirkwood/goflexhome-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/goflexhome-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,123 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/goflexhome-setup.c
|
|
+ *
|
|
+ * Seagate GoFlex Home 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 "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition goflexhome_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_2M + SZ_4M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data goflexhome_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data goflexhome_sata_data = {
|
|
+ .n_ports = 1,
|
|
+};
|
|
+
|
|
+static struct gpio_led goflexhome_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 46,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 47,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:misc",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 40,
|
|
+ .active_low = 0,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data goflexhome_led_data = {
|
|
+ .leds = goflexhome_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(goflexhome_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device goflexhome_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &goflexhome_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int goflexhome_mpp_config[] __initdata = {
|
|
+ MPP29_GPIO, /* USB Power Enable */
|
|
+ MPP47_GPIO, /* LED Orange */
|
|
+ MPP46_GPIO, /* LED Green */
|
|
+ MPP40_GPIO, /* LED White */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init goflexhome_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(goflexhome_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(goflexhome_nand_parts), 40);
|
|
+
|
|
+ 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(&goflexhome_ge00_data);
|
|
+ kirkwood_sata_init(&goflexhome_sata_data);
|
|
+
|
|
+ platform_device_register(&goflexhome_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(GOFLEXHOME, "Seagate GoFlex Home")
|
|
+ /* Maintainer: Peter Carmichael <peterjncarm@ovi.com> */
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = goflexhome_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
+
|
|
diff -urN a/arch/arm/mach-kirkwood/goflexnet-setup.c b/arch/arm/mach-kirkwood/goflexnet-setup.c
|
|
--- a/arch/arm/mach-kirkwood/goflexnet-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/goflexnet-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,176 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/goflexnet-setup.c
|
|
+ *
|
|
+ * Seagate GoFlex Net 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 "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition goflexnet_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_4M
|
|
+ }, {
|
|
+ .name = "pogoplug",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data goflexnet_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data goflexnet_sata_data = {
|
|
+ .n_ports = 2,
|
|
+};
|
|
+
|
|
+static struct gpio_led goflexnet_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 46, // 0x4000
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 47, // 0x8000
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left0",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 42, // 0x0400
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left1",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 43, // 0x0800
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 44, // 0x1000
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:left3",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 45, // 0x2000
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right0",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 38, // 0x0040
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right1",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 39, // 0x0080
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 40, // 0x0100
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:white:right3",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 41, // 0x0200
|
|
+ .active_low = 0,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data goflexnet_led_data = {
|
|
+ .leds = goflexnet_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(goflexnet_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device goflexnet_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &goflexnet_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int goflexnet_mpp_config[] __initdata = {
|
|
+ MPP29_GPIO, /* USB Power Enable */
|
|
+ MPP47_GPIO, /* LED Orange */
|
|
+ MPP46_GPIO, /* LED Green */
|
|
+ MPP45_GPIO, /* LED Left Capacity 3 */
|
|
+ MPP44_GPIO, /* LED Left Capacity 2 */
|
|
+ MPP43_GPIO, /* LED Left Capacity 1 */
|
|
+ MPP42_GPIO, /* LED Left Capacity 0 */
|
|
+ MPP41_GPIO, /* LED Right Capacity 3 */
|
|
+ MPP40_GPIO, /* LED Right Capacity 2 */
|
|
+ MPP39_GPIO, /* LED Right Capacity 1 */
|
|
+ MPP38_GPIO, /* LED Right Capacity 0 */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init goflexnet_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(goflexnet_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(goflexnet_nand_parts), 40);
|
|
+
|
|
+ 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(&goflexnet_ge00_data);
|
|
+ kirkwood_sata_init(&goflexnet_sata_data);
|
|
+
|
|
+ platform_device_register(&goflexnet_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(GOFLEXNET, "Seagate GoFlex Net")
|
|
+ /* Maintainer: Peter Carmichael <peterjncarm@ovi.com> */
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = goflexnet_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
+
|
|
diff -urN a/arch/arm/mach-kirkwood/guruplug-setup.c b/arch/arm/mach-kirkwood/guruplug-setup.c
|
|
--- a/arch/arm/mach-kirkwood/guruplug-setup.c 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/arch/arm/mach-kirkwood/guruplug-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -57,22 +57,24 @@
|
|
|
|
static struct gpio_led guruplug_led_pins[] = {
|
|
{
|
|
- .name = "guruplug:red:health",
|
|
+ .name = "status:red:fault",
|
|
+ .default_trigger = "none",
|
|
.gpio = 46,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "guruplug:green:health",
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
.gpio = 47,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "guruplug:red:wmode",
|
|
+ .name = "status:red:wmode",
|
|
.gpio = 48,
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "guruplug:green:wmode",
|
|
+ .name = "status:green:wmode",
|
|
.gpio = 49,
|
|
.active_low = 1,
|
|
},
|
|
diff -urN a/arch/arm/mach-kirkwood/iconnect-setup.c b/arch/arm/mach-kirkwood/iconnect-setup.c
|
|
--- a/arch/arm/mach-kirkwood/iconnect-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/iconnect-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,203 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/iconnect-setup.c
|
|
+ *
|
|
+ * Iomega iConnect Wireless
|
|
+ *
|
|
+ * 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/irq.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/ethtool.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/leds.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition iconnect_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_1M + SZ_2M
|
|
+ }, {
|
|
+ .name = "rootfs",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M,
|
|
+ }, {
|
|
+ .name = "data",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data iconnect_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(11),
|
|
+};
|
|
+
|
|
+static struct gpio_led iconnect_led_pins[] = {
|
|
+ {
|
|
+ .name = "iconnect:led_level",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 41,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:power",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 42,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:red:power",
|
|
+ .gpio = 43,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb1",
|
|
+ .gpio = 44,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb2",
|
|
+ .gpio = 45,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb3",
|
|
+ .gpio = 46,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:usb4",
|
|
+ .gpio = 47,
|
|
+ },
|
|
+ {
|
|
+ .name = "iconnect:blue:otb",
|
|
+ .gpio = 48,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data iconnect_led_data = {
|
|
+ .leds = iconnect_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(iconnect_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device iconnect_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &iconnect_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+#define ICONNECT_GPIO_KEY_RESET 12
|
|
+#define ICONNECT_GPIO_KEY_OTB 35
|
|
+
|
|
+#define ICONNECT_SW_RESET 0x00
|
|
+#define ICONNECT_SW_OTB 0x01
|
|
+
|
|
+static struct gpio_keys_button iconnect_buttons[] = {
|
|
+ {
|
|
+ .type = EV_SW,
|
|
+ .code = ICONNECT_SW_RESET,
|
|
+ .gpio = ICONNECT_GPIO_KEY_RESET,
|
|
+ .desc = "Reset Button",
|
|
+ .active_low = 1,
|
|
+ .debounce_interval = 100,
|
|
+ },
|
|
+ {
|
|
+ .type = EV_SW,
|
|
+ .code = ICONNECT_SW_OTB,
|
|
+ .gpio = ICONNECT_GPIO_KEY_OTB,
|
|
+ .desc = "OTB Button",
|
|
+ .active_low = 1,
|
|
+ .debounce_interval = 100,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data iconnect_button_data = {
|
|
+ .buttons = iconnect_buttons,
|
|
+ .nbuttons = ARRAY_SIZE(iconnect_buttons),
|
|
+};
|
|
+
|
|
+static struct platform_device iconnect_button_device = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &iconnect_button_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static unsigned int iconnect_mpp_config[] __initdata = {
|
|
+ MPP12_GPIO, /*Input for reset button*/
|
|
+ MPP35_GPIO, /*Input for OTB button*/
|
|
+ MPP41_GPIO,
|
|
+ MPP42_GPIO,
|
|
+ MPP43_GPIO,
|
|
+ MPP44_GPIO,
|
|
+ MPP45_GPIO,
|
|
+ MPP46_GPIO,
|
|
+ MPP47_GPIO,
|
|
+ MPP48_GPIO,
|
|
+ 0
|
|
+};
|
|
+
|
|
+static struct i2c_board_info __initdata iconnect_i2c_rtc = {
|
|
+ I2C_BOARD_INFO("lm63", 0x4c),
|
|
+};
|
|
+
|
|
+static void __init iconnect_init(void)
|
|
+{
|
|
+ u32 dev, rev;
|
|
+
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+ kirkwood_mpp_conf(iconnect_mpp_config);
|
|
+
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(iconnect_nand_parts), 40);
|
|
+ kirkwood_ehci_init();
|
|
+
|
|
+ kirkwood_ge00_init(&iconnect_ge00_data);
|
|
+ kirkwood_pcie_id(&dev, &rev);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+
|
|
+ platform_device_register(&iconnect_leds);
|
|
+ platform_device_register(&iconnect_button_device);
|
|
+
|
|
+ kirkwood_i2c_init();
|
|
+ i2c_register_board_info(0, &iconnect_i2c_rtc, 1);
|
|
+
|
|
+}
|
|
+
|
|
+static int __init iconnect_pci_init(void)
|
|
+{
|
|
+ if (machine_is_iconnect())
|
|
+ kirkwood_pcie_init(KW_PCIE0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+subsys_initcall(iconnect_pci_init);
|
|
+
|
|
+
|
|
+MACHINE_START(ICONNECT, "Iomega iConnect Wireless")
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = iconnect_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/ionics-stratus-setup.c b/arch/arm/mach-kirkwood/ionics-stratus-setup.c
|
|
--- a/arch/arm/mach-kirkwood/ionics-stratus-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/ionics-stratus-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,136 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/ionics-stratus-setup.c
|
|
+ *
|
|
+ * Ionics Stratus Board Setup arcNumber 4184
|
|
+ *
|
|
+ * 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 ionics_stratus_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 ionics_stratus_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mvsdio_platform_data ionics_stratus_mvsdio_data = {
|
|
+ /* unfortunately the CD signal has not been connected */
|
|
+};
|
|
+
|
|
+static struct gpio_led ionics_stratus_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:led1",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 44,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:led2",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 40,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:led3",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 36,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:led4",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 39,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data ionics_stratus_led_data = {
|
|
+ .leds = ionics_stratus_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(ionics_stratus_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device ionics_stratus_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &ionics_stratus_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int ionics_stratus_mpp_config[] __initdata = {
|
|
+ MPP21_GPIO, /* USB PORT 1 Pw Enable */
|
|
+ MPP32_GPIO, /* USB PORT 2 Pw Enable */
|
|
+ MPP48_GPIO, /* WIFI Power Down */
|
|
+ MPP49_GPIO, /* WIFI Host Wakeup */
|
|
+ MPP42_GPIO, /* WIFI MAC Wakeup */
|
|
+ MPP44_GPIO, /* LED 1 */
|
|
+ MPP40_GPIO, /* LED 2 */
|
|
+ MPP36_GPIO, /* LED 3 */
|
|
+ MPP39_GPIO, /* LED 4 */
|
|
+ MPP23_GPIO, /* BTN 1 */
|
|
+ MPP37_GPIO, /* BTN 2 */
|
|
+ MPP38_GPIO, /* BTN 3 */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init ionics_stratus_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(ionics_stratus_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(ionics_stratus_nand_parts), 25);
|
|
+
|
|
+ kirkwood_ehci_init();
|
|
+
|
|
+ kirkwood_ge00_init(&ionics_stratus_ge00_data);
|
|
+ kirkwood_sdio_init(&ionics_stratus_mvsdio_data);
|
|
+
|
|
+ platform_device_register(&ionics_stratus_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(IONICS_STRATUS, "Ionics Plug Computer Plus - Stratus")
|
|
+ /* Maintainer: Mike Brown <mbrown@archlinuxarm.org> */
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = ionics_stratus_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
|
|
--- a/arch/arm/mach-kirkwood/Kconfig 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/arch/arm/mach-kirkwood/Kconfig 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -78,6 +78,54 @@
|
|
Say 'Y' here if you want your kernel to support the
|
|
Seagate FreeAgent DockStar.
|
|
|
|
+config MACH_GOFLEXNET
|
|
+ bool "Seagate GoFlex Net"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Seagate GoFlex Net.
|
|
+
|
|
+config MACH_GOFLEXHOME
|
|
+ bool "Seagate GoFlex Home"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Seagate GoFlex Home.
|
|
+
|
|
+config MACH_ICONNECT
|
|
+ bool "Iomega iConnect Wireless"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Iomega iConnect Wireless.
|
|
+
|
|
+config MACH_POGOPLUGV4
|
|
+ bool "Pogoplug Series 4"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Pogoplug Series 4.
|
|
+
|
|
+config MACH_POGO_E02
|
|
+ bool "CE Pogoplug E02"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ CloudEngines Pogoplug e02.
|
|
+
|
|
+config MACH_NAS6210
|
|
+ bool "RaidSonic ICY BOX IB-NAS6210"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ RaidSonic ICY BOX IB-NAS6210 device.
|
|
+
|
|
+config MACH_TOPKICK
|
|
+ bool "USI Topkick"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ USI Topkick.
|
|
+
|
|
+config MACH_IONICS_STRATUS
|
|
+ bool "Ionics Stratus"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Ionics Stratus.
|
|
+
|
|
config MACH_OPENRD
|
|
bool
|
|
|
|
diff -urN a/arch/arm/mach-kirkwood/Kconfig.orig b/arch/arm/mach-kirkwood/Kconfig.orig
|
|
--- a/arch/arm/mach-kirkwood/Kconfig.orig 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/Kconfig.orig 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,149 @@
|
|
+if ARCH_KIRKWOOD
|
|
+
|
|
+menu "Marvell Kirkwood Implementations"
|
|
+
|
|
+config MACH_DB88F6281_BP
|
|
+ bool "Marvell DB-88F6281-BP Development Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell DB-88F6281-BP Development Board.
|
|
+
|
|
+config MACH_RD88F6192_NAS
|
|
+ bool "Marvell RD-88F6192-NAS Reference Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell RD-88F6192-NAS Reference Board.
|
|
+
|
|
+config MACH_RD88F6281
|
|
+ bool "Marvell RD-88F6281 Reference Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell RD-88F6281 Reference Board.
|
|
+
|
|
+config MACH_MV88F6281GTW_GE
|
|
+ bool "Marvell 88F6281 GTW GE Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell 88F6281 GTW GE Board.
|
|
+
|
|
+config MACH_SHEEVAPLUG
|
|
+ bool "Marvell SheevaPlug Reference Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell SheevaPlug Reference Board.
|
|
+
|
|
+config MACH_ESATA_SHEEVAPLUG
|
|
+ bool "Marvell eSATA SheevaPlug Reference Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell eSATA SheevaPlug Reference Board.
|
|
+
|
|
+config MACH_GURUPLUG
|
|
+ bool "Marvell GuruPlug Reference Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell GuruPlug Reference Board.
|
|
+
|
|
+config ARCH_KIRKWOOD_DT
|
|
+ bool "Marvell Kirkwood Flattened Device Tree"
|
|
+ select USE_OF
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell Kirkwood using flattened device tree.
|
|
+
|
|
+config MACH_DREAMPLUG_DT
|
|
+ bool "Marvell DreamPlug (Flattened Device Tree)"
|
|
+ select ARCH_KIRKWOOD_DT
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell DreamPlug (Flattened Device Tree).
|
|
+
|
|
+config MACH_TS219
|
|
+ bool "QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and TS-219P+ Turbo NAS"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and
|
|
+ TS-219P+ Turbo NAS devices.
|
|
+
|
|
+config MACH_TS41X
|
|
+ bool "QNAP TS-410, TS-410U, TS-419P, TS-419P+ and TS-419U Turbo NAS"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ QNAP TS-410, TS-410U, TS-419P, 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
|
|
+
|
|
+config MACH_OPENRD_BASE
|
|
+ bool "Marvell OpenRD Base Board"
|
|
+ select MACH_OPENRD
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell OpenRD Base Board.
|
|
+
|
|
+config MACH_OPENRD_CLIENT
|
|
+ bool "Marvell OpenRD Client Board"
|
|
+ select MACH_OPENRD
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell OpenRD Client Board.
|
|
+
|
|
+config MACH_OPENRD_ULTIMATE
|
|
+ bool "Marvell OpenRD Ultimate Board"
|
|
+ select MACH_OPENRD
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ Marvell OpenRD Ultimate Board.
|
|
+
|
|
+config MACH_NETSPACE_V2
|
|
+ bool "LaCie Network Space v2 NAS Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ LaCie Network Space v2 NAS.
|
|
+
|
|
+config MACH_INETSPACE_V2
|
|
+ bool "LaCie Internet Space v2 NAS Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ LaCie Internet Space v2 NAS.
|
|
+
|
|
+config MACH_NETSPACE_MAX_V2
|
|
+ bool "LaCie Network Space Max v2 NAS Board"
|
|
+ help
|
|
+ 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
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ LaCie 2Big Network v2 NAS.
|
|
+
|
|
+config MACH_NET5BIG_V2
|
|
+ bool "LaCie 5Big Network v2 NAS Board"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ LaCie 5Big Network v2 NAS.
|
|
+
|
|
+config MACH_T5325
|
|
+ bool "HP t5325 Thin Client"
|
|
+ help
|
|
+ Say 'Y' here if you want your kernel to support the
|
|
+ HP t5325 Thin Client.
|
|
+
|
|
+endmenu
|
|
+
|
|
+endif
|
|
diff -urN a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
|
|
--- a/arch/arm/mach-kirkwood/Makefile 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/arch/arm/mach-kirkwood/Makefile 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -8,6 +8,14 @@
|
|
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_GOFLEXNET) += goflexnet-setup.o
|
|
+obj-$(CONFIG_MACH_GOFLEXHOME) += goflexhome-setup.o
|
|
+obj-$(CONFIG_MACH_ICONNECT) += iconnect-setup.o
|
|
+obj-$(CONFIG_MACH_POGOPLUGV4) += pogoplugv4-setup.o
|
|
+obj-$(CONFIG_MACH_POGO_E02) += pogo_e02-setup.o
|
|
+obj-$(CONFIG_MACH_NAS6210) += nas6210-setup.o
|
|
+obj-$(CONFIG_MACH_TOPKICK) += topkick-setup.o
|
|
+obj-$(CONFIG_MACH_IONICS_STRATUS) += ionics-stratus-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
|
|
diff -urN a/arch/arm/mach-kirkwood/mpp.h b/arch/arm/mach-kirkwood/mpp.h
|
|
--- a/arch/arm/mach-kirkwood/mpp.h 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/arch/arm/mach-kirkwood/mpp.h 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -102,7 +102,7 @@
|
|
#define MPP11_SATA0_ACTn MPP( 11, 0x5, 0, 0, 0, 1, 1, 1, 1 )
|
|
|
|
#define MPP12_GPO MPP( 12, 0x0, 0, 1, 1, 1, 1, 1, 1 )
|
|
-#define MPP12_GPIO MPP( 12, 0x0, 1, 1, 0, 0, 0, 1, 0 )
|
|
+#define MPP12_GPIO MPP( 12, 0x0, 1, 1, 1, 1, 1, 1, 1 )
|
|
#define MPP12_SD_CLK MPP( 12, 0x1, 0, 0, 1, 1, 1, 1, 1 )
|
|
#define MPP12_AU_SPDIF0 MPP( 12, 0xa, 0, 0, 0, 0, 0, 0, 1 )
|
|
#define MPP12_SPI_MOSI MPP( 12, 0xb, 0, 0, 0, 0, 0, 0, 1 )
|
|
diff -urN a/arch/arm/mach-kirkwood/nas6210-setup.c b/arch/arm/mach-kirkwood/nas6210-setup.c
|
|
--- a/arch/arm/mach-kirkwood/nas6210-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/nas6210-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,185 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/nas6210-setup.c
|
|
+ *
|
|
+ * Raidsonic ICYBOX NAS6210 Board 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/mtd/partitions.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/leds.h>
|
|
+#include <asm/mach-types.h>
|
|
+#include <asm/mach/arch.h>
|
|
+#include <mach/kirkwood.h>
|
|
+#include "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+#define NAS6210_GPIO_POWER_OFF 24
|
|
+
|
|
+static struct mtd_partition nas6210_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 6*SZ_1M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data nas6210_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(8),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data nas6210_sata_data = {
|
|
+ .n_ports = 2,
|
|
+};
|
|
+
|
|
+static struct gpio_led nas6210_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:power",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 25,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:power",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 22,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:usb_copy",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 27,
|
|
+ .active_low = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data nas6210_led_data = {
|
|
+ .leds = nas6210_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(nas6210_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device nas6210_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &nas6210_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_keys_button nas6210_buttons[] = {
|
|
+ {
|
|
+ .code = KEY_COPY,
|
|
+ .gpio = 29,
|
|
+ .desc = "USB Copy",
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .code = KEY_RESTART,
|
|
+ .gpio = 28,
|
|
+ .desc = "Reset",
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data nas6210_button_data = {
|
|
+ .buttons = nas6210_buttons,
|
|
+ .nbuttons = ARRAY_SIZE(nas6210_buttons),
|
|
+};
|
|
+
|
|
+static struct platform_device nas6210_button_device = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &nas6210_button_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int nas6210_mpp_config[] __initdata = {
|
|
+ MPP0_NF_IO2,
|
|
+ MPP1_NF_IO3,
|
|
+ MPP2_NF_IO4,
|
|
+ MPP3_NF_IO5,
|
|
+ MPP4_NF_IO6,
|
|
+ MPP5_NF_IO7,
|
|
+ MPP18_NF_IO0,
|
|
+ MPP19_NF_IO1,
|
|
+ MPP22_GPIO, /* Power LED red */
|
|
+ MPP24_GPIO, /* Power off device */
|
|
+ MPP25_GPIO, /* Power LED green */
|
|
+ MPP27_GPIO, /* USB transfer LED */
|
|
+ MPP28_GPIO, /* Reset button */
|
|
+ MPP29_GPIO, /* USB Copy button */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void nas6210_power_off(void)
|
|
+{
|
|
+ gpio_set_value(NAS6210_GPIO_POWER_OFF, 1);
|
|
+}
|
|
+
|
|
+static void __init nas6210_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+ kirkwood_mpp_conf(nas6210_mpp_config);
|
|
+
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(nas6210_nand_parts), 25);
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_ge00_init(&nas6210_ge00_data);
|
|
+ kirkwood_sata_init(&nas6210_sata_data);
|
|
+ kirkwood_uart0_init();
|
|
+ platform_device_register(&nas6210_leds);
|
|
+ platform_device_register(&nas6210_button_device);
|
|
+ if (gpio_request(NAS6210_GPIO_POWER_OFF, "power-off") == 0 &&
|
|
+ gpio_direction_output(NAS6210_GPIO_POWER_OFF, 0) == 0)
|
|
+ pm_power_off = nas6210_power_off;
|
|
+ else
|
|
+ pr_err("nas6210: failed to configure power-off GPIO\n");
|
|
+}
|
|
+
|
|
+static int __init nas6210_pci_init(void)
|
|
+{
|
|
+ if (machine_is_nas6210()) {
|
|
+ u32 dev, rev;
|
|
+
|
|
+ kirkwood_pcie_id(&dev, &rev);
|
|
+ if (dev == MV88F6282_DEV_ID)
|
|
+ kirkwood_pcie_init(KW_PCIE1 | KW_PCIE0);
|
|
+ else
|
|
+ kirkwood_pcie_init(KW_PCIE0);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+subsys_initcall(nas6210_pci_init);
|
|
+
|
|
+MACHINE_START(NAS6210, "RaidSonic ICY BOX IB-NAS6210")
|
|
+ /* Maintainer: <gmbnomis at gmail dot com> */
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = nas6210_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/pogo_e02-setup.c b/arch/arm/mach-kirkwood/pogo_e02-setup.c
|
|
--- a/arch/arm/mach-kirkwood/pogo_e02-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/pogo_e02-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,114 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/pogo_e02-setup.c
|
|
+ *
|
|
+ * CloudEngines Pogoplug E02 support
|
|
+ *
|
|
+ * 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 "common.h"
|
|
+#include "mpp.h"
|
|
+
|
|
+static struct mtd_partition pogo_e02_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_4M
|
|
+ }, {
|
|
+ .name = "pogoplug",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_32M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data pogo_e02_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct gpio_led pogo_e02_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 48,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 49,
|
|
+ .active_low = 1,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data pogo_e02_led_data = {
|
|
+ .leds = pogo_e02_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(pogo_e02_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device pogo_e02_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &pogo_e02_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int pogo_e02_mpp_config[] __initdata = {
|
|
+ MPP29_GPIO, /* USB Power Enable */
|
|
+ MPP48_GPIO, /* LED Green */
|
|
+ MPP49_GPIO, /* LED Orange */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init pogo_e02_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(pogo_e02_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(pogo_e02_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(&pogo_e02_ge00_data);
|
|
+
|
|
+ platform_device_register(&pogo_e02_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(POGO_E02, "Pogoplug E02")
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = pogo_e02_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/pogoplugv4-setup.c b/arch/arm/mach-kirkwood/pogoplugv4-setup.c
|
|
--- a/arch/arm/mach-kirkwood/pogoplugv4-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/pogoplugv4-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,194 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/pogoplugv4-setup.c
|
|
+ *
|
|
+ * Pogoplug Series 4 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/mtd/partitions.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/gpio_keys.h>
|
|
+#include <linux/leds.h>
|
|
+#include <linux/pci.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/spi/flash.h>
|
|
+#include <linux/spi/spi.h>
|
|
+#include <linux/spi/orion_spi.h>
|
|
+#include <linux/input.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"
|
|
+
|
|
+#define POGOPLUGV4_GPIO_USB_VBUS 10
|
|
+
|
|
+static struct mtd_partition ppv4_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = 2 * SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 3 * SZ_1M
|
|
+ }, {
|
|
+ .name = "uImage2",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = 3 * SZ_1M
|
|
+ }, {
|
|
+ .name = "failsafe",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = SZ_8M
|
|
+ }, {
|
|
+ .name = "root",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data pogoplugv4_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data pogoplugv4_sata_data = {
|
|
+ .n_ports = 1,
|
|
+};
|
|
+
|
|
+static struct gpio_keys_button pogoplugv4_button_pins[] = {
|
|
+ {
|
|
+ .code = KEY_EJECTCD,
|
|
+ .gpio = 29,
|
|
+ .desc = "Eject Button",
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_keys_platform_data pogoplugv4_button_data = {
|
|
+ .buttons = pogoplugv4_button_pins,
|
|
+ .nbuttons = ARRAY_SIZE(pogoplugv4_button_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device pogoplugv4_buttons = {
|
|
+ .name = "gpio-keys",
|
|
+ .id = -1,
|
|
+ .num_resources = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &pogoplugv4_button_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led pogoplugv4_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 22,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 24,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data pogoplugv4_led_data = {
|
|
+ .leds = pogoplugv4_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(pogoplugv4_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device pogoplugv4_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &pogoplugv4_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static struct mvsdio_platform_data ppv4_mvsdio_data = {
|
|
+ .gpio_card_detect = 27,
|
|
+};
|
|
+
|
|
+static unsigned int ppv4_mpp_config[] __initdata = {
|
|
+ MPP27_GPIO, /* SD card detect */
|
|
+ MPP29_GPIO, /* Eject button */
|
|
+ MPP22_GPIO, /* Green LED */
|
|
+ MPP24_GPIO, /* Red LED */
|
|
+ MPP12_SD_CLK,
|
|
+ MPP13_SD_CMD,
|
|
+ MPP14_SD_D0,
|
|
+ MPP15_SD_D1,
|
|
+ MPP16_SD_D2,
|
|
+ MPP17_SD_D3,
|
|
+ 0
|
|
+};
|
|
+
|
|
+static const struct flash_platform_data pogoplugv4_spi_slave_data = {
|
|
+ .type = "m25p05-nonjedec",
|
|
+};
|
|
+
|
|
+static struct spi_board_info __initdata pogoplugv4_spi_slave_info[] = {
|
|
+ {
|
|
+ .modalias = "m25p05-nonjedec",
|
|
+ .platform_data = &pogoplugv4_spi_slave_data,
|
|
+ .irq = -1,
|
|
+ .max_speed_hz = 20000000,
|
|
+ .bus_num = 0,
|
|
+ .chip_select = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static void __init pogoplugv4_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+ kirkwood_mpp_conf(ppv4_mpp_config);
|
|
+
|
|
+ orion_gpio_set_valid(POGOPLUGV4_GPIO_USB_VBUS, 1);
|
|
+ if (gpio_request(POGOPLUGV4_GPIO_USB_VBUS, "USB VBUS") != 0 ||
|
|
+ gpio_direction_output(POGOPLUGV4_GPIO_USB_VBUS, 1) != 0)
|
|
+ pr_err("POGOPLUGV4: failed to setup USB VBUS GPIO\n");
|
|
+
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_ge00_init(&pogoplugv4_ge00_data);
|
|
+ kirkwood_sata_init(&pogoplugv4_sata_data);
|
|
+ spi_register_board_info(pogoplugv4_spi_slave_info,
|
|
+ ARRAY_SIZE(pogoplugv4_spi_slave_info));
|
|
+ kirkwood_spi_init();
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(ppv4_nand_parts), 25);
|
|
+ kirkwood_sdio_init(&ppv4_mvsdio_data);
|
|
+ platform_device_register(&pogoplugv4_leds);
|
|
+ platform_device_register(&pogoplugv4_buttons);
|
|
+}
|
|
+
|
|
+static int __init pogoplugv4_pci_init(void)
|
|
+{
|
|
+ if (machine_is_pogoplugv4())
|
|
+ kirkwood_pcie_init(KW_PCIE0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+subsys_initcall(pogoplugv4_pci_init);
|
|
+
|
|
+MACHINE_START(POGOPLUGV4, "Pogoplug V4")
|
|
+ /* Maintainer: Kevin Mihelich <kevin@archlinuxarm.org> */
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = pogoplugv4_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/mach-kirkwood/sheevaplug-setup.c b/arch/arm/mach-kirkwood/sheevaplug-setup.c
|
|
--- a/arch/arm/mach-kirkwood/sheevaplug-setup.c 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/arch/arm/mach-kirkwood/sheevaplug-setup.c 2012-05-24 12:05:49.000000000 -0400
|
|
@@ -43,7 +43,7 @@
|
|
.phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
};
|
|
|
|
-static struct mv_sata_platform_data sheeva_esata_sata_data = {
|
|
+static struct mv_sata_platform_data esata_sheevaplug_sata_data = {
|
|
.n_ports = 2,
|
|
};
|
|
|
|
@@ -51,7 +51,7 @@
|
|
/* unfortunately the CD signal has not been connected */
|
|
};
|
|
|
|
-static struct mvsdio_platform_data sheeva_esata_mvsdio_data = {
|
|
+static struct mvsdio_platform_data esata_sheevaplug_mvsdio_data = {
|
|
.gpio_write_protect = 44, /* MPP44 used as SD write protect */
|
|
.gpio_card_detect = 47, /* MPP47 used as SD card detect */
|
|
};
|
|
@@ -64,7 +64,13 @@
|
|
.active_low = 1,
|
|
},
|
|
{
|
|
- .name = "plug:green:health",
|
|
+ .name = "status:green:health",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 48,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:blue:health",
|
|
.default_trigger = "default-on",
|
|
.gpio = 49,
|
|
.active_low = 1,
|
|
@@ -87,15 +93,18 @@
|
|
static unsigned int sheevaplug_mpp_config[] __initdata = {
|
|
MPP29_GPIO, /* USB Power Enable */
|
|
MPP46_GPIO, /* LED Red */
|
|
- MPP49_GPIO, /* LED */
|
|
+ MPP48_GPIO, /* LED Green */
|
|
+ MPP49_GPIO, /* LED Blue */
|
|
0
|
|
};
|
|
|
|
-static unsigned int sheeva_esata_mpp_config[] __initdata = {
|
|
+static unsigned int esata_sheevaplug_mpp_config[] __initdata = {
|
|
MPP29_GPIO, /* USB Power Enable */
|
|
MPP44_GPIO, /* SD Write Protect */
|
|
MPP47_GPIO, /* SD Card Detect */
|
|
- MPP49_GPIO, /* LED Green */
|
|
+ MPP46_GPIO, /* LED Red */
|
|
+ MPP48_GPIO, /* LED Green */
|
|
+ MPP49_GPIO, /* LED Blue */
|
|
0
|
|
};
|
|
|
|
@@ -108,7 +117,7 @@
|
|
|
|
/* setup gpio pin select */
|
|
if (machine_is_esata_sheevaplug())
|
|
- kirkwood_mpp_conf(sheeva_esata_mpp_config);
|
|
+ kirkwood_mpp_conf(esata_sheevaplug_mpp_config);
|
|
else
|
|
kirkwood_mpp_conf(sheevaplug_mpp_config);
|
|
|
|
@@ -124,11 +133,11 @@
|
|
|
|
/* honor lower power consumption for plugs with out eSATA */
|
|
if (machine_is_esata_sheevaplug())
|
|
- kirkwood_sata_init(&sheeva_esata_sata_data);
|
|
+ kirkwood_sata_init(&esata_sheevaplug_sata_data);
|
|
|
|
/* enable sd wp and sd cd on plugs with esata */
|
|
if (machine_is_esata_sheevaplug())
|
|
- kirkwood_sdio_init(&sheeva_esata_mvsdio_data);
|
|
+ kirkwood_sdio_init(&esata_sheevaplug_mvsdio_data);
|
|
else
|
|
kirkwood_sdio_init(&sheevaplug_mvsdio_data);
|
|
|
|
diff -urN a/arch/arm/mach-kirkwood/topkick-setup.c b/arch/arm/mach-kirkwood/topkick-setup.c
|
|
--- a/arch/arm/mach-kirkwood/topkick-setup.c 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/mach-kirkwood/topkick-setup.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,164 @@
|
|
+/*
|
|
+ * arch/arm/mach-kirkwood/topkick-setup.c
|
|
+ *
|
|
+ * USI Topkick 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/nand.h>
|
|
+#include <linux/mtd/partitions.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/i2c.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 topkick_nand_parts[] = {
|
|
+ {
|
|
+ .name = "u-boot",
|
|
+ .offset = 0,
|
|
+ .size = 0x180000
|
|
+ }, {
|
|
+ .name = "u-boot-env",
|
|
+ .offset = 0x180000,
|
|
+ .size = 128 * 1024
|
|
+ }, {
|
|
+ .name = "uImage",
|
|
+ .offset = 2 * 1024 * 1024,
|
|
+ .size = 6 * 1024 * 1024
|
|
+ }, {
|
|
+ .name = "rootfs",
|
|
+ .offset = MTDPART_OFS_NXTBLK,
|
|
+ .size = MTDPART_SIZ_FULL
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv643xx_eth_platform_data topkick_ge00_data = {
|
|
+ .phy_addr = MV643XX_ETH_PHY_ADDR(0),
|
|
+};
|
|
+
|
|
+static struct mv_sata_platform_data topkick_sata_data = {
|
|
+ .n_ports = 1,
|
|
+};
|
|
+
|
|
+static struct mvsdio_platform_data topkick_mvsdio_data = {
|
|
+ .gpio_card_detect = 47, /* MPP47 used as SD card detect */
|
|
+};
|
|
+
|
|
+
|
|
+static struct gpio_led topkick_led_pins[] = {
|
|
+ {
|
|
+ .name = "status:blue:disk",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 21,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:red:fault",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 37,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:blue:health",
|
|
+ .default_trigger = "default-on",
|
|
+ .gpio = 38,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:green:misc",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 39,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+ {
|
|
+ .name = "status:orange:misc",
|
|
+ .default_trigger = "none",
|
|
+ .gpio = 48,
|
|
+ .active_low = 1,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct gpio_led_platform_data topkick_led_data = {
|
|
+ .leds = topkick_led_pins,
|
|
+ .num_leds = ARRAY_SIZE(topkick_led_pins),
|
|
+};
|
|
+
|
|
+static struct platform_device topkick_leds = {
|
|
+ .name = "leds-gpio",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &topkick_led_data,
|
|
+ }
|
|
+};
|
|
+
|
|
+static unsigned int topkick_mpp_config[] __initdata = {
|
|
+ MPP12_SD_CLK, /* SDIO Clock */
|
|
+ MPP13_SD_CMD, /* SDIO Cmd */
|
|
+ MPP14_SD_D0, /* SDIO Data 0 */
|
|
+ MPP15_SD_D1, /* SDIO Data 1 */
|
|
+ MPP16_SD_D2, /* SDIO Data 2 */
|
|
+ MPP17_SD_D3, /* SDIO Data 3 */
|
|
+ MPP21_GPIO, /* LED Blue SATA */
|
|
+ MPP35_GPIO, /* USB Power Enable */
|
|
+ MPP36_GPIO, /* SATA Power Enable */
|
|
+ MPP37_GPIO, /* LED Red System */
|
|
+ MPP38_GPIO, /* LED Blue System */
|
|
+ MPP39_GPIO, /* LED Green Misc/WiFi */
|
|
+ MPP43_GPIO, /* WOL Eth WOL */
|
|
+ MPP44_GPIO, /* SW GW Mode */
|
|
+ MPP45_GPIO, /* SW AP Mode */
|
|
+ MPP46_GPIO, /* SW Power Off */
|
|
+ MPP47_GPIO, /* SDIO Detect */
|
|
+ MPP48_GPIO, /* LED Orange Misc/WiFi */
|
|
+ 0
|
|
+};
|
|
+
|
|
+static void __init topkick_init(void)
|
|
+{
|
|
+ /*
|
|
+ * Basic setup. Needs to be called early.
|
|
+ */
|
|
+ kirkwood_init();
|
|
+
|
|
+ /* setup gpio pin select */
|
|
+ kirkwood_mpp_conf(topkick_mpp_config);
|
|
+
|
|
+ kirkwood_uart0_init();
|
|
+ kirkwood_nand_init(ARRAY_AND_SIZE(topkick_nand_parts), 40);
|
|
+
|
|
+ if (gpio_request(35, "USB Power Enable") != 0 ||
|
|
+ gpio_direction_output(35, 1) != 0)
|
|
+ printk(KERN_ERR "can't set up GPIO 35 (USB Power Enable)\n");
|
|
+ if (gpio_request(36, "SATA Power Enable") != 0 ||
|
|
+ gpio_direction_output(36, 1) != 0)
|
|
+ printk(KERN_ERR "can't set up GPIO 36 (SATA Power Enable)\n");
|
|
+ kirkwood_ge00_init(&topkick_ge00_data);
|
|
+ kirkwood_ehci_init();
|
|
+ kirkwood_sata_init(&topkick_sata_data);
|
|
+ kirkwood_sdio_init(&topkick_mvsdio_data);
|
|
+
|
|
+ platform_device_register(&topkick_leds);
|
|
+}
|
|
+
|
|
+MACHINE_START(TOPKICK, "USI Topkick")
|
|
+ /* Maintainer: Mike Brown <mbrown@archlinuxarm.org> */
|
|
+ .atag_offset = 0x100,
|
|
+ .init_machine = topkick_init,
|
|
+ .map_io = kirkwood_map_io,
|
|
+ .init_early = kirkwood_init_early,
|
|
+ .init_irq = kirkwood_init_irq,
|
|
+ .timer = &kirkwood_timer,
|
|
+MACHINE_END
|
|
diff -urN a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
|
|
--- a/arch/arm/plat-orion/common.c 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/arch/arm/plat-orion/common.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -222,7 +222,9 @@
|
|
/*****************************************************************************
|
|
* GE00
|
|
****************************************************************************/
|
|
-struct mv643xx_eth_shared_platform_data orion_ge00_shared_data;
|
|
+struct mv643xx_eth_shared_platform_data orion_ge00_shared_data = {
|
|
+ .tx_csum_limit = 1600,
|
|
+};
|
|
|
|
static struct resource orion_ge00_shared_resources[] = {
|
|
{
|
|
diff -urN a/arch/arm/plat-orion/common.c.orig b/arch/arm/plat-orion/common.c.orig
|
|
--- a/arch/arm/plat-orion/common.c.orig 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/arch/arm/plat-orion/common.c.orig 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,936 @@
|
|
+/*
|
|
+ * arch/arm/plat-orion/common.c
|
|
+ *
|
|
+ * Marvell Orion SoC common setup code used by multiple mach-/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/platform_device.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/serial_8250.h>
|
|
+#include <linux/ata_platform.h>
|
|
+#include <linux/mv643xx_eth.h>
|
|
+#include <linux/mv643xx_i2c.h>
|
|
+#include <net/dsa.h>
|
|
+#include <linux/spi/orion_spi.h>
|
|
+#include <plat/orion_wdt.h>
|
|
+#include <plat/mv_xor.h>
|
|
+#include <plat/ehci-orion.h>
|
|
+#include <mach/bridge-regs.h>
|
|
+
|
|
+/* Fill in the resources structure and link it into the platform
|
|
+ device structure. There is always a memory region, and nearly
|
|
+ always an interrupt.*/
|
|
+static void fill_resources(struct platform_device *device,
|
|
+ struct resource *resources,
|
|
+ resource_size_t mapbase,
|
|
+ resource_size_t size,
|
|
+ unsigned int irq)
|
|
+{
|
|
+ device->resource = resources;
|
|
+ device->num_resources = 1;
|
|
+ resources[0].flags = IORESOURCE_MEM;
|
|
+ resources[0].start = mapbase;
|
|
+ resources[0].end = mapbase + size;
|
|
+
|
|
+ if (irq != NO_IRQ) {
|
|
+ device->num_resources++;
|
|
+ resources[1].flags = IORESOURCE_IRQ;
|
|
+ resources[1].start = irq;
|
|
+ resources[1].end = irq;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * UART
|
|
+ ****************************************************************************/
|
|
+static void __init uart_complete(
|
|
+ struct platform_device *orion_uart,
|
|
+ struct plat_serial8250_port *data,
|
|
+ struct resource *resources,
|
|
+ unsigned int membase,
|
|
+ resource_size_t mapbase,
|
|
+ unsigned int irq,
|
|
+ unsigned int uartclk)
|
|
+{
|
|
+ data->mapbase = mapbase;
|
|
+ data->membase = (void __iomem *)membase;
|
|
+ data->irq = irq;
|
|
+ data->uartclk = uartclk;
|
|
+ orion_uart->dev.platform_data = data;
|
|
+
|
|
+ fill_resources(orion_uart, resources, mapbase, 0xff, irq);
|
|
+ platform_device_register(orion_uart);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * UART0
|
|
+ ****************************************************************************/
|
|
+static struct plat_serial8250_port orion_uart0_data[] = {
|
|
+ {
|
|
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
|
|
+ .iotype = UPIO_MEM,
|
|
+ .regshift = 2,
|
|
+ }, {
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_uart0_resources[2];
|
|
+
|
|
+static struct platform_device orion_uart0 = {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM,
|
|
+};
|
|
+
|
|
+void __init orion_uart0_init(unsigned int membase,
|
|
+ resource_size_t mapbase,
|
|
+ unsigned int irq,
|
|
+ unsigned int uartclk)
|
|
+{
|
|
+ uart_complete(&orion_uart0, orion_uart0_data, orion_uart0_resources,
|
|
+ membase, mapbase, irq, uartclk);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * UART1
|
|
+ ****************************************************************************/
|
|
+static struct plat_serial8250_port orion_uart1_data[] = {
|
|
+ {
|
|
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
|
|
+ .iotype = UPIO_MEM,
|
|
+ .regshift = 2,
|
|
+ }, {
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_uart1_resources[2];
|
|
+
|
|
+static struct platform_device orion_uart1 = {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
|
+};
|
|
+
|
|
+void __init orion_uart1_init(unsigned int membase,
|
|
+ resource_size_t mapbase,
|
|
+ unsigned int irq,
|
|
+ unsigned int uartclk)
|
|
+{
|
|
+ uart_complete(&orion_uart1, orion_uart1_data, orion_uart1_resources,
|
|
+ membase, mapbase, irq, uartclk);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * UART2
|
|
+ ****************************************************************************/
|
|
+static struct plat_serial8250_port orion_uart2_data[] = {
|
|
+ {
|
|
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
|
|
+ .iotype = UPIO_MEM,
|
|
+ .regshift = 2,
|
|
+ }, {
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_uart2_resources[2];
|
|
+
|
|
+static struct platform_device orion_uart2 = {
|
|
+ .name = "serial8250",
|
|
+ .id = PLAT8250_DEV_PLATFORM2,
|
|
+};
|
|
+
|
|
+void __init orion_uart2_init(unsigned int membase,
|
|
+ resource_size_t mapbase,
|
|
+ unsigned int irq,
|
|
+ unsigned int uartclk)
|
|
+{
|
|
+ uart_complete(&orion_uart2, orion_uart2_data, orion_uart2_resources,
|
|
+ membase, mapbase, irq, uartclk);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * UART3
|
|
+ ****************************************************************************/
|
|
+static struct plat_serial8250_port orion_uart3_data[] = {
|
|
+ {
|
|
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
|
|
+ .iotype = UPIO_MEM,
|
|
+ .regshift = 2,
|
|
+ }, {
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_uart3_resources[2];
|
|
+
|
|
+static struct platform_device orion_uart3 = {
|
|
+ .name = "serial8250",
|
|
+ .id = 3,
|
|
+};
|
|
+
|
|
+void __init orion_uart3_init(unsigned int membase,
|
|
+ resource_size_t mapbase,
|
|
+ unsigned int irq,
|
|
+ unsigned int uartclk)
|
|
+{
|
|
+ uart_complete(&orion_uart3, orion_uart3_data, orion_uart3_resources,
|
|
+ membase, mapbase, irq, uartclk);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * SoC RTC
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_rtc_resource[2];
|
|
+
|
|
+void __init orion_rtc_init(unsigned long mapbase,
|
|
+ unsigned long irq)
|
|
+{
|
|
+ orion_rtc_resource[0].start = mapbase;
|
|
+ orion_rtc_resource[0].end = mapbase + SZ_32 - 1;
|
|
+ orion_rtc_resource[0].flags = IORESOURCE_MEM;
|
|
+ orion_rtc_resource[1].start = irq;
|
|
+ orion_rtc_resource[1].end = irq;
|
|
+ orion_rtc_resource[1].flags = IORESOURCE_IRQ;
|
|
+
|
|
+ platform_device_register_simple("rtc-mv", -1, orion_rtc_resource, 2);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * GE
|
|
+ ****************************************************************************/
|
|
+static __init void ge_complete(
|
|
+ struct mv643xx_eth_shared_platform_data *orion_ge_shared_data,
|
|
+ int tclk,
|
|
+ struct resource *orion_ge_resource, unsigned long irq,
|
|
+ struct platform_device *orion_ge_shared,
|
|
+ struct mv643xx_eth_platform_data *eth_data,
|
|
+ struct platform_device *orion_ge)
|
|
+{
|
|
+ orion_ge_shared_data->t_clk = tclk;
|
|
+ orion_ge_resource->start = irq;
|
|
+ orion_ge_resource->end = irq;
|
|
+ eth_data->shared = orion_ge_shared;
|
|
+ orion_ge->dev.platform_data = eth_data;
|
|
+
|
|
+ platform_device_register(orion_ge_shared);
|
|
+ platform_device_register(orion_ge);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * GE00
|
|
+ ****************************************************************************/
|
|
+struct mv643xx_eth_shared_platform_data orion_ge00_shared_data;
|
|
+
|
|
+static struct resource orion_ge00_shared_resources[] = {
|
|
+ {
|
|
+ .name = "ge00 base",
|
|
+ }, {
|
|
+ .name = "ge00 err irq",
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge00_shared = {
|
|
+ .name = MV643XX_ETH_SHARED_NAME,
|
|
+ .id = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_ge00_shared_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_ge00_resources[] = {
|
|
+ {
|
|
+ .name = "ge00 irq",
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge00 = {
|
|
+ .name = MV643XX_ETH_NAME,
|
|
+ .id = 0,
|
|
+ .num_resources = 1,
|
|
+ .resource = orion_ge00_resources,
|
|
+ .dev = {
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
|
|
+ unsigned long mapbase,
|
|
+ unsigned long irq,
|
|
+ unsigned long irq_err,
|
|
+ int tclk)
|
|
+{
|
|
+ fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
|
|
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
|
|
+ ge_complete(&orion_ge00_shared_data, tclk,
|
|
+ orion_ge00_resources, irq, &orion_ge00_shared,
|
|
+ eth_data, &orion_ge00);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * GE01
|
|
+ ****************************************************************************/
|
|
+struct mv643xx_eth_shared_platform_data orion_ge01_shared_data = {
|
|
+ .shared_smi = &orion_ge00_shared,
|
|
+};
|
|
+
|
|
+static struct resource orion_ge01_shared_resources[] = {
|
|
+ {
|
|
+ .name = "ge01 base",
|
|
+ }, {
|
|
+ .name = "ge01 err irq",
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge01_shared = {
|
|
+ .name = MV643XX_ETH_SHARED_NAME,
|
|
+ .id = 1,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_ge01_shared_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_ge01_resources[] = {
|
|
+ {
|
|
+ .name = "ge01 irq",
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge01 = {
|
|
+ .name = MV643XX_ETH_NAME,
|
|
+ .id = 1,
|
|
+ .num_resources = 1,
|
|
+ .resource = orion_ge01_resources,
|
|
+ .dev = {
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
|
|
+ unsigned long mapbase,
|
|
+ unsigned long irq,
|
|
+ unsigned long irq_err,
|
|
+ int tclk)
|
|
+{
|
|
+ fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
|
|
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
|
|
+ ge_complete(&orion_ge01_shared_data, tclk,
|
|
+ orion_ge01_resources, irq, &orion_ge01_shared,
|
|
+ eth_data, &orion_ge01);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * GE10
|
|
+ ****************************************************************************/
|
|
+struct mv643xx_eth_shared_platform_data orion_ge10_shared_data = {
|
|
+ .shared_smi = &orion_ge00_shared,
|
|
+};
|
|
+
|
|
+static struct resource orion_ge10_shared_resources[] = {
|
|
+ {
|
|
+ .name = "ge10 base",
|
|
+ }, {
|
|
+ .name = "ge10 err irq",
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge10_shared = {
|
|
+ .name = MV643XX_ETH_SHARED_NAME,
|
|
+ .id = 1,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_ge10_shared_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_ge10_resources[] = {
|
|
+ {
|
|
+ .name = "ge10 irq",
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge10 = {
|
|
+ .name = MV643XX_ETH_NAME,
|
|
+ .id = 1,
|
|
+ .num_resources = 2,
|
|
+ .resource = orion_ge10_resources,
|
|
+ .dev = {
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
|
|
+ unsigned long mapbase,
|
|
+ unsigned long irq,
|
|
+ unsigned long irq_err,
|
|
+ int tclk)
|
|
+{
|
|
+ fill_resources(&orion_ge10_shared, orion_ge10_shared_resources,
|
|
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
|
|
+ ge_complete(&orion_ge10_shared_data, tclk,
|
|
+ orion_ge10_resources, irq, &orion_ge10_shared,
|
|
+ eth_data, &orion_ge10);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * GE11
|
|
+ ****************************************************************************/
|
|
+struct mv643xx_eth_shared_platform_data orion_ge11_shared_data = {
|
|
+ .shared_smi = &orion_ge00_shared,
|
|
+};
|
|
+
|
|
+static struct resource orion_ge11_shared_resources[] = {
|
|
+ {
|
|
+ .name = "ge11 base",
|
|
+ }, {
|
|
+ .name = "ge11 err irq",
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge11_shared = {
|
|
+ .name = MV643XX_ETH_SHARED_NAME,
|
|
+ .id = 1,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_ge11_shared_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_ge11_resources[] = {
|
|
+ {
|
|
+ .name = "ge11 irq",
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_ge11 = {
|
|
+ .name = MV643XX_ETH_NAME,
|
|
+ .id = 1,
|
|
+ .num_resources = 2,
|
|
+ .resource = orion_ge11_resources,
|
|
+ .dev = {
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
|
|
+ unsigned long mapbase,
|
|
+ unsigned long irq,
|
|
+ unsigned long irq_err,
|
|
+ int tclk)
|
|
+{
|
|
+ fill_resources(&orion_ge11_shared, orion_ge11_shared_resources,
|
|
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
|
|
+ ge_complete(&orion_ge11_shared_data, tclk,
|
|
+ orion_ge11_resources, irq, &orion_ge11_shared,
|
|
+ eth_data, &orion_ge11);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * Ethernet switch
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_switch_resources[] = {
|
|
+ {
|
|
+ .start = 0,
|
|
+ .end = 0,
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_switch_device = {
|
|
+ .name = "dsa",
|
|
+ .id = 0,
|
|
+ .num_resources = 0,
|
|
+ .resource = orion_switch_resources,
|
|
+};
|
|
+
|
|
+void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (irq != NO_IRQ) {
|
|
+ orion_switch_resources[0].start = irq;
|
|
+ orion_switch_resources[0].end = irq;
|
|
+ orion_switch_device.num_resources = 1;
|
|
+ }
|
|
+
|
|
+ d->netdev = &orion_ge00.dev;
|
|
+ for (i = 0; i < d->nr_chips; i++)
|
|
+ d->chip[i].mii_bus = &orion_ge00_shared.dev;
|
|
+ orion_switch_device.dev.platform_data = d;
|
|
+
|
|
+ platform_device_register(&orion_switch_device);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * I2C
|
|
+ ****************************************************************************/
|
|
+static struct mv64xxx_i2c_pdata orion_i2c_pdata = {
|
|
+ .freq_n = 3,
|
|
+ .timeout = 1000, /* Default timeout of 1 second */
|
|
+};
|
|
+
|
|
+static struct resource orion_i2c_resources[2];
|
|
+
|
|
+static struct platform_device orion_i2c = {
|
|
+ .name = MV64XXX_I2C_CTLR_NAME,
|
|
+ .id = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_i2c_pdata,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv64xxx_i2c_pdata orion_i2c_1_pdata = {
|
|
+ .freq_n = 3,
|
|
+ .timeout = 1000, /* Default timeout of 1 second */
|
|
+};
|
|
+
|
|
+static struct resource orion_i2c_1_resources[2];
|
|
+
|
|
+static struct platform_device orion_i2c_1 = {
|
|
+ .name = MV64XXX_I2C_CTLR_NAME,
|
|
+ .id = 1,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_i2c_1_pdata,
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_i2c_init(unsigned long mapbase,
|
|
+ unsigned long irq,
|
|
+ unsigned long freq_m)
|
|
+{
|
|
+ orion_i2c_pdata.freq_m = freq_m;
|
|
+ fill_resources(&orion_i2c, orion_i2c_resources, mapbase,
|
|
+ SZ_32 - 1, irq);
|
|
+ platform_device_register(&orion_i2c);
|
|
+}
|
|
+
|
|
+void __init orion_i2c_1_init(unsigned long mapbase,
|
|
+ unsigned long irq,
|
|
+ unsigned long freq_m)
|
|
+{
|
|
+ orion_i2c_1_pdata.freq_m = freq_m;
|
|
+ fill_resources(&orion_i2c_1, orion_i2c_1_resources, mapbase,
|
|
+ SZ_32 - 1, irq);
|
|
+ platform_device_register(&orion_i2c_1);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * SPI
|
|
+ ****************************************************************************/
|
|
+static struct orion_spi_info orion_spi_plat_data;
|
|
+static struct resource orion_spi_resources;
|
|
+
|
|
+static struct platform_device orion_spi = {
|
|
+ .name = "orion_spi",
|
|
+ .id = 0,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_spi_plat_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct orion_spi_info orion_spi_1_plat_data;
|
|
+static struct resource orion_spi_1_resources;
|
|
+
|
|
+static struct platform_device orion_spi_1 = {
|
|
+ .name = "orion_spi",
|
|
+ .id = 1,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_spi_1_plat_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+/* Note: The SPI silicon core does have interrupts. However the
|
|
+ * current Linux software driver does not use interrupts. */
|
|
+
|
|
+void __init orion_spi_init(unsigned long mapbase,
|
|
+ unsigned long tclk)
|
|
+{
|
|
+ orion_spi_plat_data.tclk = tclk;
|
|
+ fill_resources(&orion_spi, &orion_spi_resources,
|
|
+ mapbase, SZ_512 - 1, NO_IRQ);
|
|
+ platform_device_register(&orion_spi);
|
|
+}
|
|
+
|
|
+void __init orion_spi_1_init(unsigned long mapbase,
|
|
+ unsigned long tclk)
|
|
+{
|
|
+ orion_spi_1_plat_data.tclk = tclk;
|
|
+ fill_resources(&orion_spi_1, &orion_spi_1_resources,
|
|
+ mapbase, SZ_512 - 1, NO_IRQ);
|
|
+ platform_device_register(&orion_spi_1);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * Watchdog
|
|
+ ****************************************************************************/
|
|
+static struct orion_wdt_platform_data orion_wdt_data;
|
|
+
|
|
+static struct resource orion_wdt_resource =
|
|
+ DEFINE_RES_MEM(TIMER_VIRT_BASE, 0x28);
|
|
+
|
|
+static struct platform_device orion_wdt_device = {
|
|
+ .name = "orion_wdt",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &orion_wdt_data,
|
|
+ },
|
|
+ .resource = &orion_wdt_resource,
|
|
+ .num_resources = 1,
|
|
+};
|
|
+
|
|
+void __init orion_wdt_init(unsigned long tclk)
|
|
+{
|
|
+ orion_wdt_data.tclk = tclk;
|
|
+ platform_device_register(&orion_wdt_device);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * XOR
|
|
+ ****************************************************************************/
|
|
+static u64 orion_xor_dmamask = DMA_BIT_MASK(32);
|
|
+
|
|
+void __init orion_xor_init_channels(
|
|
+ struct mv_xor_platform_data *orion_xor0_data,
|
|
+ struct platform_device *orion_xor0_channel,
|
|
+ struct mv_xor_platform_data *orion_xor1_data,
|
|
+ struct platform_device *orion_xor1_channel)
|
|
+{
|
|
+ /*
|
|
+ * two engines can't do memset simultaneously, this limitation
|
|
+ * satisfied by removing memset support from one of the engines.
|
|
+ */
|
|
+ dma_cap_set(DMA_MEMCPY, orion_xor0_data->cap_mask);
|
|
+ dma_cap_set(DMA_XOR, orion_xor0_data->cap_mask);
|
|
+ platform_device_register(orion_xor0_channel);
|
|
+
|
|
+ dma_cap_set(DMA_MEMCPY, orion_xor1_data->cap_mask);
|
|
+ dma_cap_set(DMA_MEMSET, orion_xor1_data->cap_mask);
|
|
+ dma_cap_set(DMA_XOR, orion_xor1_data->cap_mask);
|
|
+ platform_device_register(orion_xor1_channel);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * XOR0
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_xor0_shared_resources[] = {
|
|
+ {
|
|
+ .name = "xor 0 low",
|
|
+ .flags = IORESOURCE_MEM,
|
|
+ }, {
|
|
+ .name = "xor 0 high",
|
|
+ .flags = IORESOURCE_MEM,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_xor0_shared = {
|
|
+ .name = MV_XOR_SHARED_NAME,
|
|
+ .id = 0,
|
|
+ .num_resources = ARRAY_SIZE(orion_xor0_shared_resources),
|
|
+ .resource = orion_xor0_shared_resources,
|
|
+};
|
|
+
|
|
+static struct resource orion_xor00_resources[] = {
|
|
+ [0] = {
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv_xor_platform_data orion_xor00_data = {
|
|
+ .shared = &orion_xor0_shared,
|
|
+ .hw_id = 0,
|
|
+ .pool_size = PAGE_SIZE,
|
|
+};
|
|
+
|
|
+static struct platform_device orion_xor00_channel = {
|
|
+ .name = MV_XOR_NAME,
|
|
+ .id = 0,
|
|
+ .num_resources = ARRAY_SIZE(orion_xor00_resources),
|
|
+ .resource = orion_xor00_resources,
|
|
+ .dev = {
|
|
+ .dma_mask = &orion_xor_dmamask,
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(64),
|
|
+ .platform_data = &orion_xor00_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_xor01_resources[] = {
|
|
+ [0] = {
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv_xor_platform_data orion_xor01_data = {
|
|
+ .shared = &orion_xor0_shared,
|
|
+ .hw_id = 1,
|
|
+ .pool_size = PAGE_SIZE,
|
|
+};
|
|
+
|
|
+static struct platform_device orion_xor01_channel = {
|
|
+ .name = MV_XOR_NAME,
|
|
+ .id = 1,
|
|
+ .num_resources = ARRAY_SIZE(orion_xor01_resources),
|
|
+ .resource = orion_xor01_resources,
|
|
+ .dev = {
|
|
+ .dma_mask = &orion_xor_dmamask,
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(64),
|
|
+ .platform_data = &orion_xor01_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_xor0_init(unsigned long mapbase_low,
|
|
+ unsigned long mapbase_high,
|
|
+ unsigned long irq_0,
|
|
+ unsigned long irq_1)
|
|
+{
|
|
+ orion_xor0_shared_resources[0].start = mapbase_low;
|
|
+ orion_xor0_shared_resources[0].end = mapbase_low + 0xff;
|
|
+ orion_xor0_shared_resources[1].start = mapbase_high;
|
|
+ orion_xor0_shared_resources[1].end = mapbase_high + 0xff;
|
|
+
|
|
+ orion_xor00_resources[0].start = irq_0;
|
|
+ orion_xor00_resources[0].end = irq_0;
|
|
+ orion_xor01_resources[0].start = irq_1;
|
|
+ orion_xor01_resources[0].end = irq_1;
|
|
+
|
|
+ platform_device_register(&orion_xor0_shared);
|
|
+
|
|
+ orion_xor_init_channels(&orion_xor00_data, &orion_xor00_channel,
|
|
+ &orion_xor01_data, &orion_xor01_channel);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * XOR1
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_xor1_shared_resources[] = {
|
|
+ {
|
|
+ .name = "xor 1 low",
|
|
+ .flags = IORESOURCE_MEM,
|
|
+ }, {
|
|
+ .name = "xor 1 high",
|
|
+ .flags = IORESOURCE_MEM,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_xor1_shared = {
|
|
+ .name = MV_XOR_SHARED_NAME,
|
|
+ .id = 1,
|
|
+ .num_resources = ARRAY_SIZE(orion_xor1_shared_resources),
|
|
+ .resource = orion_xor1_shared_resources,
|
|
+};
|
|
+
|
|
+static struct resource orion_xor10_resources[] = {
|
|
+ [0] = {
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv_xor_platform_data orion_xor10_data = {
|
|
+ .shared = &orion_xor1_shared,
|
|
+ .hw_id = 0,
|
|
+ .pool_size = PAGE_SIZE,
|
|
+};
|
|
+
|
|
+static struct platform_device orion_xor10_channel = {
|
|
+ .name = MV_XOR_NAME,
|
|
+ .id = 2,
|
|
+ .num_resources = ARRAY_SIZE(orion_xor10_resources),
|
|
+ .resource = orion_xor10_resources,
|
|
+ .dev = {
|
|
+ .dma_mask = &orion_xor_dmamask,
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(64),
|
|
+ .platform_data = &orion_xor10_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct resource orion_xor11_resources[] = {
|
|
+ [0] = {
|
|
+ .flags = IORESOURCE_IRQ,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mv_xor_platform_data orion_xor11_data = {
|
|
+ .shared = &orion_xor1_shared,
|
|
+ .hw_id = 1,
|
|
+ .pool_size = PAGE_SIZE,
|
|
+};
|
|
+
|
|
+static struct platform_device orion_xor11_channel = {
|
|
+ .name = MV_XOR_NAME,
|
|
+ .id = 3,
|
|
+ .num_resources = ARRAY_SIZE(orion_xor11_resources),
|
|
+ .resource = orion_xor11_resources,
|
|
+ .dev = {
|
|
+ .dma_mask = &orion_xor_dmamask,
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(64),
|
|
+ .platform_data = &orion_xor11_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_xor1_init(unsigned long mapbase_low,
|
|
+ unsigned long mapbase_high,
|
|
+ unsigned long irq_0,
|
|
+ unsigned long irq_1)
|
|
+{
|
|
+ orion_xor1_shared_resources[0].start = mapbase_low;
|
|
+ orion_xor1_shared_resources[0].end = mapbase_low + 0xff;
|
|
+ orion_xor1_shared_resources[1].start = mapbase_high;
|
|
+ orion_xor1_shared_resources[1].end = mapbase_high + 0xff;
|
|
+
|
|
+ orion_xor10_resources[0].start = irq_0;
|
|
+ orion_xor10_resources[0].end = irq_0;
|
|
+ orion_xor11_resources[0].start = irq_1;
|
|
+ orion_xor11_resources[0].end = irq_1;
|
|
+
|
|
+ platform_device_register(&orion_xor1_shared);
|
|
+
|
|
+ orion_xor_init_channels(&orion_xor10_data, &orion_xor10_channel,
|
|
+ &orion_xor11_data, &orion_xor11_channel);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * EHCI
|
|
+ ****************************************************************************/
|
|
+static struct orion_ehci_data orion_ehci_data;
|
|
+static u64 ehci_dmamask = DMA_BIT_MASK(32);
|
|
+
|
|
+
|
|
+/*****************************************************************************
|
|
+ * EHCI0
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_ehci_resources[2];
|
|
+
|
|
+static struct platform_device orion_ehci = {
|
|
+ .name = "orion-ehci",
|
|
+ .id = 0,
|
|
+ .dev = {
|
|
+ .dma_mask = &ehci_dmamask,
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ .platform_data = &orion_ehci_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_ehci_init(unsigned long mapbase,
|
|
+ unsigned long irq,
|
|
+ enum orion_ehci_phy_ver phy_version)
|
|
+{
|
|
+ orion_ehci_data.phy_version = phy_version;
|
|
+ fill_resources(&orion_ehci, orion_ehci_resources, mapbase, SZ_4K - 1,
|
|
+ irq);
|
|
+
|
|
+ platform_device_register(&orion_ehci);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * EHCI1
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_ehci_1_resources[2];
|
|
+
|
|
+static struct platform_device orion_ehci_1 = {
|
|
+ .name = "orion-ehci",
|
|
+ .id = 1,
|
|
+ .dev = {
|
|
+ .dma_mask = &ehci_dmamask,
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ .platform_data = &orion_ehci_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_ehci_1_init(unsigned long mapbase,
|
|
+ unsigned long irq)
|
|
+{
|
|
+ fill_resources(&orion_ehci_1, orion_ehci_1_resources,
|
|
+ mapbase, SZ_4K - 1, irq);
|
|
+
|
|
+ platform_device_register(&orion_ehci_1);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * EHCI2
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_ehci_2_resources[2];
|
|
+
|
|
+static struct platform_device orion_ehci_2 = {
|
|
+ .name = "orion-ehci",
|
|
+ .id = 2,
|
|
+ .dev = {
|
|
+ .dma_mask = &ehci_dmamask,
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ .platform_data = &orion_ehci_data,
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_ehci_2_init(unsigned long mapbase,
|
|
+ unsigned long irq)
|
|
+{
|
|
+ fill_resources(&orion_ehci_2, orion_ehci_2_resources,
|
|
+ mapbase, SZ_4K - 1, irq);
|
|
+
|
|
+ platform_device_register(&orion_ehci_2);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * SATA
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_sata_resources[2] = {
|
|
+ {
|
|
+ .name = "sata base",
|
|
+ }, {
|
|
+ .name = "sata irq",
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_sata = {
|
|
+ .name = "sata_mv",
|
|
+ .id = 0,
|
|
+ .dev = {
|
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
|
+ },
|
|
+};
|
|
+
|
|
+void __init orion_sata_init(struct mv_sata_platform_data *sata_data,
|
|
+ unsigned long mapbase,
|
|
+ unsigned long irq)
|
|
+{
|
|
+ orion_sata.dev.platform_data = sata_data;
|
|
+ fill_resources(&orion_sata, orion_sata_resources,
|
|
+ mapbase, 0x5000 - 1, irq);
|
|
+
|
|
+ platform_device_register(&orion_sata);
|
|
+}
|
|
+
|
|
+/*****************************************************************************
|
|
+ * Cryptographic Engines and Security Accelerator (CESA)
|
|
+ ****************************************************************************/
|
|
+static struct resource orion_crypto_resources[] = {
|
|
+ {
|
|
+ .name = "regs",
|
|
+ }, {
|
|
+ .name = "crypto interrupt",
|
|
+ }, {
|
|
+ .name = "sram",
|
|
+ .flags = IORESOURCE_MEM,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct platform_device orion_crypto = {
|
|
+ .name = "mv_crypto",
|
|
+ .id = -1,
|
|
+};
|
|
+
|
|
+void __init orion_crypto_init(unsigned long mapbase,
|
|
+ unsigned long srambase,
|
|
+ unsigned long sram_size,
|
|
+ unsigned long irq)
|
|
+{
|
|
+ fill_resources(&orion_crypto, orion_crypto_resources,
|
|
+ mapbase, 0xffff, irq);
|
|
+ orion_crypto.num_resources = 3;
|
|
+ orion_crypto_resources[2].start = srambase;
|
|
+ orion_crypto_resources[2].end = srambase + sram_size - 1;
|
|
+
|
|
+ platform_device_register(&orion_crypto);
|
|
+}
|
|
diff -urN a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
|
|
--- a/drivers/mmc/core/core.c 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/drivers/mmc/core/core.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -536,7 +536,7 @@
|
|
*/
|
|
limit_us = 3000000;
|
|
else
|
|
- limit_us = 100000;
|
|
+ limit_us = 200000;
|
|
|
|
/*
|
|
* SDHC cards always use these fixed values.
|
|
diff -urN a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
|
|
--- a/drivers/mmc/core/sd.c 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/drivers/mmc/core/sd.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -389,6 +389,15 @@
|
|
return -ENOMEM;
|
|
}
|
|
|
|
+ /*
|
|
+ * Some SDHC cards, notably those with a Sandisk SD controller
|
|
+ * (also found in Kingston products) need a bit of slack
|
|
+ * before successfully handling the SWITCH command. So far,
|
|
+ * cards identifying themselves as "SD04G" and "SD08G" are
|
|
+ * affected
|
|
+ */
|
|
+ udelay(100);
|
|
+
|
|
err = mmc_sd_switch(card, 1, 0, 1, status);
|
|
if (err)
|
|
goto out;
|
|
diff -urN a/drivers/mmc/core/sd.c.orig b/drivers/mmc/core/sd.c.orig
|
|
--- a/drivers/mmc/core/sd.c.orig 1969-12-31 19:00:00.000000000 -0500
|
|
+++ b/drivers/mmc/core/sd.c.orig 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -0,0 +1,1245 @@
|
|
+/*
|
|
+ * linux/drivers/mmc/core/sd.c
|
|
+ *
|
|
+ * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
|
|
+ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
|
|
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+
|
|
+#include <linux/err.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/stat.h>
|
|
+
|
|
+#include <linux/mmc/host.h>
|
|
+#include <linux/mmc/card.h>
|
|
+#include <linux/mmc/mmc.h>
|
|
+#include <linux/mmc/sd.h>
|
|
+
|
|
+#include "core.h"
|
|
+#include "bus.h"
|
|
+#include "mmc_ops.h"
|
|
+#include "sd.h"
|
|
+#include "sd_ops.h"
|
|
+
|
|
+static const unsigned int tran_exp[] = {
|
|
+ 10000, 100000, 1000000, 10000000,
|
|
+ 0, 0, 0, 0
|
|
+};
|
|
+
|
|
+static const unsigned char tran_mant[] = {
|
|
+ 0, 10, 12, 13, 15, 20, 25, 30,
|
|
+ 35, 40, 45, 50, 55, 60, 70, 80,
|
|
+};
|
|
+
|
|
+static const unsigned int tacc_exp[] = {
|
|
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
|
|
+};
|
|
+
|
|
+static const unsigned int tacc_mant[] = {
|
|
+ 0, 10, 12, 13, 15, 20, 25, 30,
|
|
+ 35, 40, 45, 50, 55, 60, 70, 80,
|
|
+};
|
|
+
|
|
+#define UNSTUFF_BITS(resp,start,size) \
|
|
+ ({ \
|
|
+ const int __size = size; \
|
|
+ const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
|
|
+ const int __off = 3 - ((start) / 32); \
|
|
+ const int __shft = (start) & 31; \
|
|
+ u32 __res; \
|
|
+ \
|
|
+ __res = resp[__off] >> __shft; \
|
|
+ if (__size + __shft > 32) \
|
|
+ __res |= resp[__off-1] << ((32 - __shft) % 32); \
|
|
+ __res & __mask; \
|
|
+ })
|
|
+
|
|
+/*
|
|
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
|
|
+ */
|
|
+void mmc_decode_cid(struct mmc_card *card)
|
|
+{
|
|
+ u32 *resp = card->raw_cid;
|
|
+
|
|
+ memset(&card->cid, 0, sizeof(struct mmc_cid));
|
|
+
|
|
+ /*
|
|
+ * SD doesn't currently have a version field so we will
|
|
+ * have to assume we can parse this.
|
|
+ */
|
|
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
|
|
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
|
|
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
|
|
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
|
|
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
|
|
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
|
|
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
|
|
+ card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
|
|
+ card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
|
|
+ card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
|
|
+ card->cid.year = UNSTUFF_BITS(resp, 12, 8);
|
|
+ card->cid.month = UNSTUFF_BITS(resp, 8, 4);
|
|
+
|
|
+ card->cid.year += 2000; /* SD cards year offset */
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Given a 128-bit response, decode to our card CSD structure.
|
|
+ */
|
|
+static int mmc_decode_csd(struct mmc_card *card)
|
|
+{
|
|
+ struct mmc_csd *csd = &card->csd;
|
|
+ unsigned int e, m, csd_struct;
|
|
+ u32 *resp = card->raw_csd;
|
|
+
|
|
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
|
|
+
|
|
+ switch (csd_struct) {
|
|
+ case 0:
|
|
+ m = UNSTUFF_BITS(resp, 115, 4);
|
|
+ e = UNSTUFF_BITS(resp, 112, 3);
|
|
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
|
|
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
|
|
+
|
|
+ m = UNSTUFF_BITS(resp, 99, 4);
|
|
+ e = UNSTUFF_BITS(resp, 96, 3);
|
|
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
|
|
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
|
|
+
|
|
+ e = UNSTUFF_BITS(resp, 47, 3);
|
|
+ m = UNSTUFF_BITS(resp, 62, 12);
|
|
+ csd->capacity = (1 + m) << (e + 2);
|
|
+
|
|
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
|
|
+ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
|
|
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
|
|
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
|
|
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
|
|
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
|
|
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
|
|
+
|
|
+ if (UNSTUFF_BITS(resp, 46, 1)) {
|
|
+ csd->erase_size = 1;
|
|
+ } else if (csd->write_blkbits >= 9) {
|
|
+ csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
|
|
+ csd->erase_size <<= csd->write_blkbits - 9;
|
|
+ }
|
|
+ break;
|
|
+ case 1:
|
|
+ /*
|
|
+ * This is a block-addressed SDHC or SDXC card. Most
|
|
+ * interesting fields are unused and have fixed
|
|
+ * values. To avoid getting tripped by buggy cards,
|
|
+ * we assume those fixed values ourselves.
|
|
+ */
|
|
+ mmc_card_set_blockaddr(card);
|
|
+
|
|
+ csd->tacc_ns = 0; /* Unused */
|
|
+ csd->tacc_clks = 0; /* Unused */
|
|
+
|
|
+ m = UNSTUFF_BITS(resp, 99, 4);
|
|
+ e = UNSTUFF_BITS(resp, 96, 3);
|
|
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
|
|
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
|
|
+ csd->c_size = UNSTUFF_BITS(resp, 48, 22);
|
|
+
|
|
+ /* SDXC cards have a minimum C_SIZE of 0x00FFFF */
|
|
+ if (csd->c_size >= 0xFFFF)
|
|
+ mmc_card_set_ext_capacity(card);
|
|
+
|
|
+ m = UNSTUFF_BITS(resp, 48, 22);
|
|
+ csd->capacity = (1 + m) << 10;
|
|
+
|
|
+ csd->read_blkbits = 9;
|
|
+ csd->read_partial = 0;
|
|
+ csd->write_misalign = 0;
|
|
+ csd->read_misalign = 0;
|
|
+ csd->r2w_factor = 4; /* Unused */
|
|
+ csd->write_blkbits = 9;
|
|
+ csd->write_partial = 0;
|
|
+ csd->erase_size = 1;
|
|
+ break;
|
|
+ default:
|
|
+ pr_err("%s: unrecognised CSD structure version %d\n",
|
|
+ mmc_hostname(card->host), csd_struct);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ card->erase_size = csd->erase_size;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Given a 64-bit response, decode to our card SCR structure.
|
|
+ */
|
|
+static int mmc_decode_scr(struct mmc_card *card)
|
|
+{
|
|
+ struct sd_scr *scr = &card->scr;
|
|
+ unsigned int scr_struct;
|
|
+ u32 resp[4];
|
|
+
|
|
+ resp[3] = card->raw_scr[1];
|
|
+ resp[2] = card->raw_scr[0];
|
|
+
|
|
+ scr_struct = UNSTUFF_BITS(resp, 60, 4);
|
|
+ if (scr_struct != 0) {
|
|
+ pr_err("%s: unrecognised SCR structure version %d\n",
|
|
+ mmc_hostname(card->host), scr_struct);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
|
|
+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
|
|
+ if (scr->sda_vsn == SCR_SPEC_VER_2)
|
|
+ /* Check if Physical Layer Spec v3.0 is supported */
|
|
+ scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
|
|
+
|
|
+ if (UNSTUFF_BITS(resp, 55, 1))
|
|
+ card->erased_byte = 0xFF;
|
|
+ else
|
|
+ card->erased_byte = 0x0;
|
|
+
|
|
+ if (scr->sda_spec3)
|
|
+ scr->cmds = UNSTUFF_BITS(resp, 32, 2);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Fetch and process SD Status register.
|
|
+ */
|
|
+static int mmc_read_ssr(struct mmc_card *card)
|
|
+{
|
|
+ unsigned int au, es, et, eo;
|
|
+ int err, i;
|
|
+ u32 *ssr;
|
|
+
|
|
+ if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
|
|
+ pr_warning("%s: card lacks mandatory SD Status "
|
|
+ "function.\n", mmc_hostname(card->host));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ssr = kmalloc(64, GFP_KERNEL);
|
|
+ if (!ssr)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ err = mmc_app_sd_status(card, ssr);
|
|
+ if (err) {
|
|
+ pr_warning("%s: problem reading SD Status "
|
|
+ "register.\n", mmc_hostname(card->host));
|
|
+ err = 0;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < 16; i++)
|
|
+ ssr[i] = be32_to_cpu(ssr[i]);
|
|
+
|
|
+ /*
|
|
+ * UNSTUFF_BITS only works with four u32s so we have to offset the
|
|
+ * bitfield positions accordingly.
|
|
+ */
|
|
+ au = UNSTUFF_BITS(ssr, 428 - 384, 4);
|
|
+ if (au > 0 || au <= 9) {
|
|
+ card->ssr.au = 1 << (au + 4);
|
|
+ es = UNSTUFF_BITS(ssr, 408 - 384, 16);
|
|
+ et = UNSTUFF_BITS(ssr, 402 - 384, 6);
|
|
+ eo = UNSTUFF_BITS(ssr, 400 - 384, 2);
|
|
+ if (es && et) {
|
|
+ card->ssr.erase_timeout = (et * 1000) / es;
|
|
+ card->ssr.erase_offset = eo * 1000;
|
|
+ }
|
|
+ } else {
|
|
+ pr_warning("%s: SD Status: Invalid Allocation Unit "
|
|
+ "size.\n", mmc_hostname(card->host));
|
|
+ }
|
|
+out:
|
|
+ kfree(ssr);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Fetches and decodes switch information
|
|
+ */
|
|
+static int mmc_read_switch(struct mmc_card *card)
|
|
+{
|
|
+ int err;
|
|
+ u8 *status;
|
|
+
|
|
+ if (card->scr.sda_vsn < SCR_SPEC_VER_1)
|
|
+ return 0;
|
|
+
|
|
+ if (!(card->csd.cmdclass & CCC_SWITCH)) {
|
|
+ pr_warning("%s: card lacks mandatory switch "
|
|
+ "function, performance might suffer.\n",
|
|
+ mmc_hostname(card->host));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ err = -EIO;
|
|
+
|
|
+ status = kmalloc(64, GFP_KERNEL);
|
|
+ if (!status) {
|
|
+ pr_err("%s: could not allocate a buffer for "
|
|
+ "switch capabilities.\n",
|
|
+ mmc_hostname(card->host));
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Find out the supported Bus Speed Modes. */
|
|
+ err = mmc_sd_switch(card, 0, 0, 1, status);
|
|
+ if (err) {
|
|
+ /*
|
|
+ * If the host or the card can't do the switch,
|
|
+ * fail more gracefully.
|
|
+ */
|
|
+ if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
|
|
+ goto out;
|
|
+
|
|
+ pr_warning("%s: problem reading Bus Speed modes.\n",
|
|
+ mmc_hostname(card->host));
|
|
+ err = 0;
|
|
+
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (status[13] & SD_MODE_HIGH_SPEED)
|
|
+ card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
|
|
+
|
|
+ if (card->scr.sda_spec3) {
|
|
+ card->sw_caps.sd3_bus_mode = status[13];
|
|
+
|
|
+ /* Find out Driver Strengths supported by the card */
|
|
+ err = mmc_sd_switch(card, 0, 2, 1, status);
|
|
+ if (err) {
|
|
+ /*
|
|
+ * If the host or the card can't do the switch,
|
|
+ * fail more gracefully.
|
|
+ */
|
|
+ if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
|
|
+ goto out;
|
|
+
|
|
+ pr_warning("%s: problem reading "
|
|
+ "Driver Strength.\n",
|
|
+ mmc_hostname(card->host));
|
|
+ err = 0;
|
|
+
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ card->sw_caps.sd3_drv_type = status[9];
|
|
+
|
|
+ /* Find out Current Limits supported by the card */
|
|
+ err = mmc_sd_switch(card, 0, 3, 1, status);
|
|
+ if (err) {
|
|
+ /*
|
|
+ * If the host or the card can't do the switch,
|
|
+ * fail more gracefully.
|
|
+ */
|
|
+ if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
|
|
+ goto out;
|
|
+
|
|
+ pr_warning("%s: problem reading "
|
|
+ "Current Limit.\n",
|
|
+ mmc_hostname(card->host));
|
|
+ err = 0;
|
|
+
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ card->sw_caps.sd3_curr_limit = status[7];
|
|
+ }
|
|
+
|
|
+out:
|
|
+ kfree(status);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Test if the card supports high-speed mode and, if so, switch to it.
|
|
+ */
|
|
+int mmc_sd_switch_hs(struct mmc_card *card)
|
|
+{
|
|
+ int err;
|
|
+ u8 *status;
|
|
+
|
|
+ if (card->scr.sda_vsn < SCR_SPEC_VER_1)
|
|
+ return 0;
|
|
+
|
|
+ if (!(card->csd.cmdclass & CCC_SWITCH))
|
|
+ return 0;
|
|
+
|
|
+ if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
|
|
+ return 0;
|
|
+
|
|
+ if (card->sw_caps.hs_max_dtr == 0)
|
|
+ return 0;
|
|
+
|
|
+ err = -EIO;
|
|
+
|
|
+ status = kmalloc(64, GFP_KERNEL);
|
|
+ if (!status) {
|
|
+ pr_err("%s: could not allocate a buffer for "
|
|
+ "switch capabilities.\n", mmc_hostname(card->host));
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ err = mmc_sd_switch(card, 1, 0, 1, status);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
+ if ((status[16] & 0xF) != 1) {
|
|
+ pr_warning("%s: Problem switching card "
|
|
+ "into high-speed mode!\n",
|
|
+ mmc_hostname(card->host));
|
|
+ err = 0;
|
|
+ } else {
|
|
+ err = 1;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ kfree(status);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int sd_select_driver_type(struct mmc_card *card, u8 *status)
|
|
+{
|
|
+ int host_drv_type = SD_DRIVER_TYPE_B;
|
|
+ int card_drv_type = SD_DRIVER_TYPE_B;
|
|
+ int drive_strength;
|
|
+ int err;
|
|
+
|
|
+ /*
|
|
+ * If the host doesn't support any of the Driver Types A,C or D,
|
|
+ * or there is no board specific handler then default Driver
|
|
+ * Type B is used.
|
|
+ */
|
|
+ if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
|
|
+ | MMC_CAP_DRIVER_TYPE_D)))
|
|
+ return 0;
|
|
+
|
|
+ if (!card->host->ops->select_drive_strength)
|
|
+ return 0;
|
|
+
|
|
+ if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
|
|
+ host_drv_type |= SD_DRIVER_TYPE_A;
|
|
+
|
|
+ if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
|
|
+ host_drv_type |= SD_DRIVER_TYPE_C;
|
|
+
|
|
+ if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
|
|
+ host_drv_type |= SD_DRIVER_TYPE_D;
|
|
+
|
|
+ if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
|
|
+ card_drv_type |= SD_DRIVER_TYPE_A;
|
|
+
|
|
+ if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
|
|
+ card_drv_type |= SD_DRIVER_TYPE_C;
|
|
+
|
|
+ if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
|
|
+ card_drv_type |= SD_DRIVER_TYPE_D;
|
|
+
|
|
+ /*
|
|
+ * The drive strength that the hardware can support
|
|
+ * depends on the board design. Pass the appropriate
|
|
+ * information and let the hardware specific code
|
|
+ * return what is possible given the options
|
|
+ */
|
|
+ mmc_host_clk_hold(card->host);
|
|
+ drive_strength = card->host->ops->select_drive_strength(
|
|
+ card->sw_caps.uhs_max_dtr,
|
|
+ host_drv_type, card_drv_type);
|
|
+ mmc_host_clk_release(card->host);
|
|
+
|
|
+ err = mmc_sd_switch(card, 1, 2, drive_strength, status);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if ((status[15] & 0xF) != drive_strength) {
|
|
+ pr_warning("%s: Problem setting drive strength!\n",
|
|
+ mmc_hostname(card->host));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ mmc_set_driver_type(card->host, drive_strength);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void sd_update_bus_speed_mode(struct mmc_card *card)
|
|
+{
|
|
+ /*
|
|
+ * If the host doesn't support any of the UHS-I modes, fallback on
|
|
+ * default speed.
|
|
+ */
|
|
+ if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
|
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
|
|
+ card->sd_bus_speed = 0;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
|
|
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
|
|
+ card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
|
|
+ } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
|
|
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
|
|
+ card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
|
|
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
|
+ MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
|
|
+ SD_MODE_UHS_SDR50)) {
|
|
+ card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
|
|
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
|
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
|
|
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
|
|
+ card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
|
|
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
|
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
|
|
+ MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
|
|
+ SD_MODE_UHS_SDR12)) {
|
|
+ card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
|
|
+{
|
|
+ int err;
|
|
+ unsigned int timing = 0;
|
|
+
|
|
+ switch (card->sd_bus_speed) {
|
|
+ case UHS_SDR104_BUS_SPEED:
|
|
+ timing = MMC_TIMING_UHS_SDR104;
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
|
|
+ break;
|
|
+ case UHS_DDR50_BUS_SPEED:
|
|
+ timing = MMC_TIMING_UHS_DDR50;
|
|
+ card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
|
|
+ break;
|
|
+ case UHS_SDR50_BUS_SPEED:
|
|
+ timing = MMC_TIMING_UHS_SDR50;
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
|
|
+ break;
|
|
+ case UHS_SDR25_BUS_SPEED:
|
|
+ timing = MMC_TIMING_UHS_SDR25;
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
|
|
+ break;
|
|
+ case UHS_SDR12_BUS_SPEED:
|
|
+ timing = MMC_TIMING_UHS_SDR12;
|
|
+ card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
|
|
+ break;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if ((status[16] & 0xF) != card->sd_bus_speed)
|
|
+ pr_warning("%s: Problem setting bus speed mode!\n",
|
|
+ mmc_hostname(card->host));
|
|
+ else {
|
|
+ mmc_set_timing(card->host, timing);
|
|
+ mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int sd_set_current_limit(struct mmc_card *card, u8 *status)
|
|
+{
|
|
+ int current_limit = 0;
|
|
+ int err;
|
|
+
|
|
+ /*
|
|
+ * Current limit switch is only defined for SDR50, SDR104, and DDR50
|
|
+ * bus speed modes. For other bus speed modes, we set the default
|
|
+ * current limit of 200mA.
|
|
+ */
|
|
+ if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
|
|
+ (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
|
|
+ (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
|
|
+ if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
|
|
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_800;
|
|
+ else if (card->sw_caps.sd3_curr_limit &
|
|
+ SD_MAX_CURRENT_600)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_600;
|
|
+ else if (card->sw_caps.sd3_curr_limit &
|
|
+ SD_MAX_CURRENT_400)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_400;
|
|
+ else if (card->sw_caps.sd3_curr_limit &
|
|
+ SD_MAX_CURRENT_200)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_200;
|
|
+ } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
|
|
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_600;
|
|
+ else if (card->sw_caps.sd3_curr_limit &
|
|
+ SD_MAX_CURRENT_400)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_400;
|
|
+ else if (card->sw_caps.sd3_curr_limit &
|
|
+ SD_MAX_CURRENT_200)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_200;
|
|
+ } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
|
|
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_400;
|
|
+ else if (card->sw_caps.sd3_curr_limit &
|
|
+ SD_MAX_CURRENT_200)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_200;
|
|
+ } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
|
|
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_200;
|
|
+ }
|
|
+ } else
|
|
+ current_limit = SD_SET_CURRENT_LIMIT_200;
|
|
+
|
|
+ err = mmc_sd_switch(card, 1, 3, current_limit, status);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (((status[15] >> 4) & 0x0F) != current_limit)
|
|
+ pr_warning("%s: Problem setting current limit!\n",
|
|
+ mmc_hostname(card->host));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * UHS-I specific initialization procedure
|
|
+ */
|
|
+static int mmc_sd_init_uhs_card(struct mmc_card *card)
|
|
+{
|
|
+ int err;
|
|
+ u8 *status;
|
|
+
|
|
+ if (!card->scr.sda_spec3)
|
|
+ return 0;
|
|
+
|
|
+ if (!(card->csd.cmdclass & CCC_SWITCH))
|
|
+ return 0;
|
|
+
|
|
+ status = kmalloc(64, GFP_KERNEL);
|
|
+ if (!status) {
|
|
+ pr_err("%s: could not allocate a buffer for "
|
|
+ "switch capabilities.\n", mmc_hostname(card->host));
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Set 4-bit bus width */
|
|
+ if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
|
|
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
|
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Select the bus speed mode depending on host
|
|
+ * and card capability.
|
|
+ */
|
|
+ sd_update_bus_speed_mode(card);
|
|
+
|
|
+ /* Set the driver strength for the card */
|
|
+ err = sd_select_driver_type(card, status);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
+ /* Set current limit for the card */
|
|
+ err = sd_set_current_limit(card, status);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
+ /* Set bus speed mode of the card */
|
|
+ err = sd_set_bus_speed_mode(card, status);
|
|
+ if (err)
|
|
+ goto out;
|
|
+
|
|
+ /* SPI mode doesn't define CMD19 */
|
|
+ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
|
|
+ mmc_host_clk_hold(card->host);
|
|
+ err = card->host->ops->execute_tuning(card->host,
|
|
+ MMC_SEND_TUNING_BLOCK);
|
|
+ mmc_host_clk_release(card->host);
|
|
+ }
|
|
+
|
|
+out:
|
|
+ kfree(status);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
|
|
+ card->raw_cid[2], card->raw_cid[3]);
|
|
+MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
|
|
+ card->raw_csd[2], card->raw_csd[3]);
|
|
+MMC_DEV_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
|
|
+MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
|
|
+MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
|
|
+MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
|
|
+MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
|
|
+MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
|
|
+MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
|
|
+MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
|
|
+MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
|
|
+MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
|
|
+
|
|
+
|
|
+static struct attribute *sd_std_attrs[] = {
|
|
+ &dev_attr_cid.attr,
|
|
+ &dev_attr_csd.attr,
|
|
+ &dev_attr_scr.attr,
|
|
+ &dev_attr_date.attr,
|
|
+ &dev_attr_erase_size.attr,
|
|
+ &dev_attr_preferred_erase_size.attr,
|
|
+ &dev_attr_fwrev.attr,
|
|
+ &dev_attr_hwrev.attr,
|
|
+ &dev_attr_manfid.attr,
|
|
+ &dev_attr_name.attr,
|
|
+ &dev_attr_oemid.attr,
|
|
+ &dev_attr_serial.attr,
|
|
+ NULL,
|
|
+};
|
|
+
|
|
+static struct attribute_group sd_std_attr_group = {
|
|
+ .attrs = sd_std_attrs,
|
|
+};
|
|
+
|
|
+static const struct attribute_group *sd_attr_groups[] = {
|
|
+ &sd_std_attr_group,
|
|
+ NULL,
|
|
+};
|
|
+
|
|
+struct device_type sd_type = {
|
|
+ .groups = sd_attr_groups,
|
|
+};
|
|
+
|
|
+/*
|
|
+ * Fetch CID from card.
|
|
+ */
|
|
+int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ /*
|
|
+ * Since we're changing the OCR value, we seem to
|
|
+ * need to tell some cards to go back to the idle
|
|
+ * state. We wait 1ms to give cards time to
|
|
+ * respond.
|
|
+ */
|
|
+ mmc_go_idle(host);
|
|
+
|
|
+ /*
|
|
+ * If SD_SEND_IF_COND indicates an SD 2.0
|
|
+ * compliant card and we should set bit 30
|
|
+ * of the ocr to indicate that we can handle
|
|
+ * block-addressed SDHC cards.
|
|
+ */
|
|
+ err = mmc_send_if_cond(host, ocr);
|
|
+ if (!err)
|
|
+ ocr |= SD_OCR_CCS;
|
|
+
|
|
+ /*
|
|
+ * If the host supports one of UHS-I modes, request the card
|
|
+ * to switch to 1.8V signaling level.
|
|
+ */
|
|
+ if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
|
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
|
|
+ ocr |= SD_OCR_S18R;
|
|
+
|
|
+ /* If the host can supply more than 150mA, XPC should be set to 1. */
|
|
+ if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
|
|
+ MMC_CAP_SET_XPC_180))
|
|
+ ocr |= SD_OCR_XPC;
|
|
+
|
|
+try_again:
|
|
+ err = mmc_send_app_op_cond(host, ocr, rocr);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ /*
|
|
+ * In case CCS and S18A in the response is set, start Signal Voltage
|
|
+ * Switch procedure. SPI mode doesn't support CMD11.
|
|
+ */
|
|
+ if (!mmc_host_is_spi(host) && rocr &&
|
|
+ ((*rocr & 0x41000000) == 0x41000000)) {
|
|
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
|
|
+ if (err) {
|
|
+ ocr &= ~SD_OCR_S18R;
|
|
+ goto try_again;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (mmc_host_is_spi(host))
|
|
+ err = mmc_send_cid(host, cid);
|
|
+ else
|
|
+ err = mmc_all_send_cid(host, cid);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ /*
|
|
+ * Fetch CSD from card.
|
|
+ */
|
|
+ err = mmc_send_csd(card, card->raw_csd);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = mmc_decode_csd(card);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
|
|
+ bool reinit)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ if (!reinit) {
|
|
+ /*
|
|
+ * Fetch SCR from card.
|
|
+ */
|
|
+ err = mmc_app_send_scr(card, card->raw_scr);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = mmc_decode_scr(card);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ /*
|
|
+ * Fetch and process SD Status register.
|
|
+ */
|
|
+ err = mmc_read_ssr(card);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ /* Erase init depends on CSD and SSR */
|
|
+ mmc_init_erase(card);
|
|
+
|
|
+ /*
|
|
+ * Fetch switch information from card.
|
|
+ */
|
|
+ err = mmc_read_switch(card);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * For SPI, enable CRC as appropriate.
|
|
+ * This CRC enable is located AFTER the reading of the
|
|
+ * card registers because some SDHC cards are not able
|
|
+ * to provide valid CRCs for non-512-byte blocks.
|
|
+ */
|
|
+ if (mmc_host_is_spi(host)) {
|
|
+ err = mmc_spi_set_crc(host, use_spi_crc);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Check if read-only switch is active.
|
|
+ */
|
|
+ if (!reinit) {
|
|
+ int ro = -1;
|
|
+
|
|
+ if (host->ops->get_ro) {
|
|
+ mmc_host_clk_hold(card->host);
|
|
+ ro = host->ops->get_ro(host);
|
|
+ mmc_host_clk_release(card->host);
|
|
+ }
|
|
+
|
|
+ if (ro < 0) {
|
|
+ pr_warning("%s: host does not "
|
|
+ "support reading read-only "
|
|
+ "switch. assuming write-enable.\n",
|
|
+ mmc_hostname(host));
|
|
+ } else if (ro > 0) {
|
|
+ mmc_card_set_readonly(card);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+unsigned mmc_sd_get_max_clock(struct mmc_card *card)
|
|
+{
|
|
+ unsigned max_dtr = (unsigned int)-1;
|
|
+
|
|
+ if (mmc_card_highspeed(card)) {
|
|
+ if (max_dtr > card->sw_caps.hs_max_dtr)
|
|
+ max_dtr = card->sw_caps.hs_max_dtr;
|
|
+ } else if (max_dtr > card->csd.max_dtr) {
|
|
+ max_dtr = card->csd.max_dtr;
|
|
+ }
|
|
+
|
|
+ return max_dtr;
|
|
+}
|
|
+
|
|
+void mmc_sd_go_highspeed(struct mmc_card *card)
|
|
+{
|
|
+ mmc_card_set_highspeed(card);
|
|
+ mmc_set_timing(card->host, MMC_TIMING_SD_HS);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Handle the detection and initialisation of a card.
|
|
+ *
|
|
+ * In the case of a resume, "oldcard" will contain the card
|
|
+ * we're trying to reinitialise.
|
|
+ */
|
|
+static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
|
+ struct mmc_card *oldcard)
|
|
+{
|
|
+ struct mmc_card *card;
|
|
+ int err;
|
|
+ u32 cid[4];
|
|
+ u32 rocr = 0;
|
|
+
|
|
+ BUG_ON(!host);
|
|
+ WARN_ON(!host->claimed);
|
|
+
|
|
+ /* The initialization should be done at 3.3 V I/O voltage. */
|
|
+ mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
|
|
+
|
|
+ err = mmc_sd_get_cid(host, ocr, cid, &rocr);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (oldcard) {
|
|
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
|
|
+ return -ENOENT;
|
|
+
|
|
+ card = oldcard;
|
|
+ } else {
|
|
+ /*
|
|
+ * Allocate card structure.
|
|
+ */
|
|
+ card = mmc_alloc_card(host, &sd_type);
|
|
+ if (IS_ERR(card))
|
|
+ return PTR_ERR(card);
|
|
+
|
|
+ card->type = MMC_TYPE_SD;
|
|
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * For native busses: get card RCA and quit open drain mode.
|
|
+ */
|
|
+ if (!mmc_host_is_spi(host)) {
|
|
+ err = mmc_send_relative_addr(host, &card->rca);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ if (!oldcard) {
|
|
+ err = mmc_sd_get_csd(host, card);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ mmc_decode_cid(card);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Select card, as all following commands rely on that.
|
|
+ */
|
|
+ if (!mmc_host_is_spi(host)) {
|
|
+ err = mmc_select_card(card);
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ err = mmc_sd_setup_card(host, card, oldcard != NULL);
|
|
+ if (err)
|
|
+ goto free_card;
|
|
+
|
|
+ /* Initialization sequence for UHS-I cards */
|
|
+ if (rocr & SD_ROCR_S18A) {
|
|
+ err = mmc_sd_init_uhs_card(card);
|
|
+ if (err)
|
|
+ goto free_card;
|
|
+
|
|
+ /* Card is an ultra-high-speed card */
|
|
+ mmc_card_set_uhs(card);
|
|
+
|
|
+ /*
|
|
+ * Since initialization is now complete, enable preset
|
|
+ * value registers for UHS-I cards.
|
|
+ */
|
|
+ if (host->ops->enable_preset_value) {
|
|
+ mmc_host_clk_hold(card->host);
|
|
+ host->ops->enable_preset_value(host, true);
|
|
+ mmc_host_clk_release(card->host);
|
|
+ }
|
|
+ } else {
|
|
+ /*
|
|
+ * Attempt to change to high-speed (if supported)
|
|
+ */
|
|
+ err = mmc_sd_switch_hs(card);
|
|
+ if (err > 0)
|
|
+ mmc_sd_go_highspeed(card);
|
|
+ else if (err)
|
|
+ goto free_card;
|
|
+
|
|
+ /*
|
|
+ * Set bus speed.
|
|
+ */
|
|
+ mmc_set_clock(host, mmc_sd_get_max_clock(card));
|
|
+
|
|
+ /*
|
|
+ * Switch to wider bus (if supported).
|
|
+ */
|
|
+ if ((host->caps & MMC_CAP_4_BIT_DATA) &&
|
|
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
|
|
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
|
|
+ if (err)
|
|
+ goto free_card;
|
|
+
|
|
+ mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ host->card = card;
|
|
+ return 0;
|
|
+
|
|
+free_card:
|
|
+ if (!oldcard)
|
|
+ mmc_remove_card(card);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Host is being removed. Free up the current card.
|
|
+ */
|
|
+static void mmc_sd_remove(struct mmc_host *host)
|
|
+{
|
|
+ BUG_ON(!host);
|
|
+ BUG_ON(!host->card);
|
|
+
|
|
+ mmc_remove_card(host->card);
|
|
+ host->card = NULL;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Card detection - card is alive.
|
|
+ */
|
|
+static int mmc_sd_alive(struct mmc_host *host)
|
|
+{
|
|
+ return mmc_send_status(host->card, NULL);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Card detection callback from host.
|
|
+ */
|
|
+static void mmc_sd_detect(struct mmc_host *host)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ BUG_ON(!host);
|
|
+ BUG_ON(!host->card);
|
|
+
|
|
+ mmc_claim_host(host);
|
|
+
|
|
+ /*
|
|
+ * Just check if our card has been removed.
|
|
+ */
|
|
+ err = _mmc_detect_card_removed(host);
|
|
+
|
|
+ mmc_release_host(host);
|
|
+
|
|
+ if (err) {
|
|
+ mmc_sd_remove(host);
|
|
+
|
|
+ mmc_claim_host(host);
|
|
+ mmc_detach_bus(host);
|
|
+ mmc_power_off(host);
|
|
+ mmc_release_host(host);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Suspend callback from host.
|
|
+ */
|
|
+static int mmc_sd_suspend(struct mmc_host *host)
|
|
+{
|
|
+ BUG_ON(!host);
|
|
+ BUG_ON(!host->card);
|
|
+
|
|
+ mmc_claim_host(host);
|
|
+ if (!mmc_host_is_spi(host))
|
|
+ mmc_deselect_cards(host);
|
|
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
|
|
+ mmc_release_host(host);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Resume callback from host.
|
|
+ *
|
|
+ * This function tries to determine if the same card is still present
|
|
+ * and, if so, restore all state to it.
|
|
+ */
|
|
+static int mmc_sd_resume(struct mmc_host *host)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ BUG_ON(!host);
|
|
+ BUG_ON(!host->card);
|
|
+
|
|
+ mmc_claim_host(host);
|
|
+ err = mmc_sd_init_card(host, host->ocr, host->card);
|
|
+ mmc_release_host(host);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int mmc_sd_power_restore(struct mmc_host *host)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
|
|
+ mmc_claim_host(host);
|
|
+ ret = mmc_sd_init_card(host, host->ocr, host->card);
|
|
+ mmc_release_host(host);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct mmc_bus_ops mmc_sd_ops = {
|
|
+ .remove = mmc_sd_remove,
|
|
+ .detect = mmc_sd_detect,
|
|
+ .suspend = NULL,
|
|
+ .resume = NULL,
|
|
+ .power_restore = mmc_sd_power_restore,
|
|
+ .alive = mmc_sd_alive,
|
|
+};
|
|
+
|
|
+static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
|
|
+ .remove = mmc_sd_remove,
|
|
+ .detect = mmc_sd_detect,
|
|
+ .suspend = mmc_sd_suspend,
|
|
+ .resume = mmc_sd_resume,
|
|
+ .power_restore = mmc_sd_power_restore,
|
|
+ .alive = mmc_sd_alive,
|
|
+};
|
|
+
|
|
+static void mmc_sd_attach_bus_ops(struct mmc_host *host)
|
|
+{
|
|
+ const struct mmc_bus_ops *bus_ops;
|
|
+
|
|
+ if (!mmc_card_is_removable(host))
|
|
+ bus_ops = &mmc_sd_ops_unsafe;
|
|
+ else
|
|
+ bus_ops = &mmc_sd_ops;
|
|
+ mmc_attach_bus(host, bus_ops);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Starting point for SD card init.
|
|
+ */
|
|
+int mmc_attach_sd(struct mmc_host *host)
|
|
+{
|
|
+ int err;
|
|
+ u32 ocr;
|
|
+
|
|
+ BUG_ON(!host);
|
|
+ WARN_ON(!host->claimed);
|
|
+
|
|
+ /* Disable preset value enable if already set since last time */
|
|
+ if (host->ops->enable_preset_value) {
|
|
+ mmc_host_clk_hold(host);
|
|
+ host->ops->enable_preset_value(host, false);
|
|
+ mmc_host_clk_release(host);
|
|
+ }
|
|
+
|
|
+ err = mmc_send_app_op_cond(host, 0, &ocr);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ mmc_sd_attach_bus_ops(host);
|
|
+ if (host->ocr_avail_sd)
|
|
+ host->ocr_avail = host->ocr_avail_sd;
|
|
+
|
|
+ /*
|
|
+ * We need to get OCR a different way for SPI.
|
|
+ */
|
|
+ if (mmc_host_is_spi(host)) {
|
|
+ mmc_go_idle(host);
|
|
+
|
|
+ err = mmc_spi_read_ocr(host, 0, &ocr);
|
|
+ if (err)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Sanity check the voltages that the card claims to
|
|
+ * support.
|
|
+ */
|
|
+ if (ocr & 0x7F) {
|
|
+ pr_warning("%s: card claims to support voltages "
|
|
+ "below the defined range. These will be ignored.\n",
|
|
+ mmc_hostname(host));
|
|
+ ocr &= ~0x7F;
|
|
+ }
|
|
+
|
|
+ if ((ocr & MMC_VDD_165_195) &&
|
|
+ !(host->ocr_avail_sd & MMC_VDD_165_195)) {
|
|
+ pr_warning("%s: SD card claims to support the "
|
|
+ "incompletely defined 'low voltage range'. This "
|
|
+ "will be ignored.\n", mmc_hostname(host));
|
|
+ ocr &= ~MMC_VDD_165_195;
|
|
+ }
|
|
+
|
|
+ host->ocr = mmc_select_voltage(host, ocr);
|
|
+
|
|
+ /*
|
|
+ * Can we support the voltage(s) of the card(s)?
|
|
+ */
|
|
+ if (!host->ocr) {
|
|
+ err = -EINVAL;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Detect and init the card.
|
|
+ */
|
|
+ err = mmc_sd_init_card(host, host->ocr, NULL);
|
|
+ if (err)
|
|
+ goto err;
|
|
+
|
|
+ mmc_release_host(host);
|
|
+ err = mmc_add_card(host->card);
|
|
+ mmc_claim_host(host);
|
|
+ if (err)
|
|
+ goto remove_card;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+remove_card:
|
|
+ mmc_release_host(host);
|
|
+ mmc_remove_card(host->card);
|
|
+ host->card = NULL;
|
|
+ mmc_claim_host(host);
|
|
+err:
|
|
+ mmc_detach_bus(host);
|
|
+
|
|
+ pr_err("%s: error %d whilst initialising SD card\n",
|
|
+ mmc_hostname(host), err);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
diff -urN a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
|
|
--- a/drivers/mmc/host/mvsdio.c 2012-05-20 18:29:13.000000000 -0400
|
|
+++ b/drivers/mmc/host/mvsdio.c 2012-05-24 12:02:12.000000000 -0400
|
|
@@ -21,6 +21,7 @@
|
|
#include <linux/irq.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/mmc/host.h>
|
|
+#include <linux/mmc/sd.h>
|
|
|
|
#include <asm/sizes.h>
|
|
#include <asm/unaligned.h>
|
|
@@ -148,6 +149,7 @@
|
|
|
|
dev_dbg(host->dev, "cmd %d (hw state 0x%04x)\n",
|
|
cmd->opcode, mvsd_read(MVSD_HW_STATE));
|
|
+ if (cmd->opcode == SD_SWITCH) mdelay(1); /* Voodoo */
|
|
|
|
cmdreg = MVSD_CMD_INDEX(cmd->opcode);
|
|
|