summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-21 15:40:55 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-21 15:40:55 -0700
commit85b375a613085b78531ec86369a51c2f3b922f95 (patch)
tree716437d598de92bbd7acaf24622e9a7d74fc209a /drivers
parentec965350bb98bd291eb34f6ecddfdcfc36da1e6e (diff)
parentcf816ecb533ab96b883dfdc0db174598b5b5c4d2 (diff)
downloadlinux-85b375a613085b78531ec86369a51c2f3b922f95.tar.gz
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (212 commits)
  [ARM] pxa: Phycore pcm-990-specific code for the PXA270 Quick Capture driver
  [ARM] pxa: V4L2 soc_camera driver for PXA270
  [ARM] pxa: restrict availability of pxa2xx PCMCIA drivers
  [ARM] 5005/1: BAST: Fix kset_name initialiser
  [ARM] 4967/1: Adds functions to set clkout rate for Samsung S3C2410
  [ARM] 4988/1: Add GPIO lib support to the EP93xx
  [ARM] Add initial sparsemem support
  [ARM] pxa: initialise PXA devices before platform init code
  [ARM] 5002/1: tosa: add two more leds
  [ARM] 5004/1: Tosa: make several unreferenced structures static.
  [ARM] 5003/1: Shut up sparse warnings
  [ARM] 4977/2: soc - pxa2xx-ac97 - Add missing clk_enable()
  [ARM] 4976/1: zylonite: Configure GPIO for WM9713 IRQ line
  [ARM] 4974/1: Drop unused leds-tosa.
  [ARM] 4973/1: Tosa: use leds-gpio driver.
  [ARM] 4972/1: Tosa: convert scoop GPIOs usage to generic gpio code
  [ARM] 4971/1: pxaficp_ir: provide startup and shutdown hooks
  [ARM] pxa: lubbock: move mis-placed SPI info
  [ARM] 4970/1: tosa: correct gpio used for wake up.
  [ARM] 4966/1: magician: add MFP pin configuration
  ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/sata_mv.c31
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c1
-rw-r--r--drivers/i2c/chips/Kconfig1
-rw-r--r--drivers/i2c/chips/tps65010.c101
-rw-r--r--drivers/input/keyboard/corgikbd.c1
-rw-r--r--drivers/input/keyboard/spitzkbd.c1
-rw-r--r--drivers/input/touchscreen/ads7846.c40
-rw-r--r--drivers/input/touchscreen/corgi_ts.c1
-rw-r--r--drivers/leds/Kconfig7
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-tosa.c132
-rw-r--r--drivers/mfd/Kconfig16
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/htc-egpio.c440
-rw-r--r--drivers/mfd/htc-pasic3.c265
-rw-r--r--drivers/mtd/nand/Kconfig2
-rw-r--r--drivers/mtd/nand/orion_nand.c2
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/arm/at91_ether.c4
-rw-r--r--drivers/net/irda/pxaficp_ir.c11
-rw-r--r--drivers/pcmcia/Kconfig1
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x270.c1
-rw-r--r--drivers/serial/imx.c111
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-orion.c37
-rw-r--r--drivers/video/pxafb.c1
27 files changed, 969 insertions, 248 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 05ff8c776497..d52ce1188327 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -76,6 +76,7 @@
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/ata_platform.h>
+#include <linux/mbus.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -370,6 +371,9 @@ enum {
 #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
 #define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
 
+#define WINDOW_CTRL(i)		(0x20030 + ((i) << 4))
+#define WINDOW_BASE(i)		(0x20034 + ((i) << 4))
+
 enum {
 	/* DMA boundary 0xffff is required by the s/g splitting
 	 * we need on /length/ in mv_fill-sg().
@@ -2769,6 +2773,27 @@ static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
 	return 0;
 }
 
+static void mv_conf_mbus_windows(struct mv_host_priv *hpriv,
+				 struct mbus_dram_target_info *dram)
+{
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		writel(0, hpriv->base + WINDOW_CTRL(i));
+		writel(0, hpriv->base + WINDOW_BASE(i));
+	}
+
+	for (i = 0; i < dram->num_cs; i++) {
+		struct mbus_dram_window *cs = dram->cs + i;
+
+		writel(((cs->size - 1) & 0xffff0000) |
+			(cs->mbus_attr << 8) |
+			(dram->mbus_dram_target_id << 4) | 1,
+			hpriv->base + WINDOW_CTRL(i));
+		writel(cs->base, hpriv->base + WINDOW_BASE(i));
+	}
+}
+
 /**
  *      mv_platform_probe - handle a positive probe of an soc Marvell
  *      host
@@ -2823,6 +2848,12 @@ static int mv_platform_probe(struct platform_device *pdev)
 				   res->end - res->start + 1);
 	hpriv->base -= MV_SATAHC0_REG_BASE;
 
+	/*
+	 * (Re-)program MBUS remapping windows if we are asked to.
+	 */
+	if (mv_platform_data->dram != NULL)
+		mv_conf_mbus_windows(hpriv, mv_platform_data->dram);
+
 	rc = mv_create_dma_pools(hpriv, &pdev->dev);
 	if (rc)
 		return rc;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5fa9c3c67e0c..b04c99580d0d 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -645,7 +645,7 @@ config I2C_PCA_ISA
 
 config I2C_MV64XXX
 	tristate "Marvell mv64xxx I2C Controller"
-	depends on (MV64X60 || ARCH_ORION) && EXPERIMENTAL
+	depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
 	help
 	  If you say yes to this option, support will be included for the
 	  built-in I2C interface on the Marvell 64xxx line of host bridges.
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 2d2087ad708f..6fd2d6a84eff 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -39,6 +39,7 @@
 #include <asm/io.h>
 #include <asm/arch/i2c.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
 
 struct pxa_i2c {
 	spinlock_t		lock;
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index b21593f93586..2da2edfa68ec 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -93,6 +93,7 @@ config ISP1301_OMAP
 
 config TPS65010
 	tristate "TPS6501x Power Management chips"
+	depends on HAVE_GPIO_LIB
 	default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
 	help
 	  If you say yes here you get support for the TPS6501x series of
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 4154a9108859..b67f69c2e7f3 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -30,9 +30,13 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
+#include <linux/platform_device.h>
 
 #include <linux/i2c/tps65010.h>
 
+#include <asm/gpio.h>
+
+
 /*-------------------------------------------------------------------------*/
 
 #define	DRIVER_VERSION	"2 May 2005"
@@ -84,7 +88,9 @@ struct tps65010 {
 	u8			chgstatus, regstatus, chgconf;
 	u8			nmask1, nmask2;
 
-	/* not currently tracking GPIO state */
+	u8			outmask;
+	struct gpio_chip	chip;
+	struct platform_device	*leds;
 };
 
 #define	POWER_POLL_DELAY	msecs_to_jiffies(5000)
@@ -449,12 +455,72 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
 
 /*-------------------------------------------------------------------------*/
 
+/* offsets 0..3 == GPIO1..GPIO4
+ * offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
+ */
+static void
+tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	if (offset < 4)
+		tps65010_set_gpio_out_value(offset + 1, value);
+	else
+		tps65010_set_led(offset - 3, value ? ON : OFF);
+}
+
+static int
+tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	/* GPIOs may be input-only */
+	if (offset < 4) {
+		struct tps65010		*tps;
+
+		tps = container_of(chip, struct tps65010, chip);
+		if (!(tps->outmask & (1 << offset)))
+			return -EINVAL;
+		tps65010_set_gpio_out_value(offset + 1, value);
+	} else
+		tps65010_set_led(offset - 3, value ? ON : OFF);
+
+	return 0;
+}
+
+static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	int			value;
+	struct tps65010		*tps;
+
+	tps = container_of(chip, struct tps65010, chip);
+
+	if (offset < 4) {
+		value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
+		if (value < 0)
+			return 0;
+		if (value & (1 << (offset + 4)))	/* output */
+			return !(value & (1 << offset));
+		else					/* input */
+			return (value & (1 << offset));
+	}
+
+	/* REVISIT we *could* report LED1/nPG and LED2 state ... */
+	return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
 static struct tps65010 *the_tps;
 
 static int __exit tps65010_remove(struct i2c_client *client)
 {
 	struct tps65010		*tps = i2c_get_clientdata(client);
+	struct tps65010_board	*board = client->dev.platform_data;
 
+	if (board && board->teardown) {
+		int status = board->teardown(client, board->context);
+		if (status < 0)
+			dev_dbg(&client->dev, "board %s %s err %d\n",
+				"teardown", client->name, status);
+	}
 	if (client->irq > 0)
 		free_irq(client->irq, tps);
 	cancel_delayed_work(&tps->work);
@@ -469,6 +535,7 @@ static int tps65010_probe(struct i2c_client *client)
 {
 	struct tps65010		*tps;
 	int			status;
+	struct tps65010_board	*board = client->dev.platform_data;
 
 	if (the_tps) {
 		dev_dbg(&client->dev, "only one tps6501x chip allowed\n");
@@ -577,6 +644,38 @@ static int tps65010_probe(struct i2c_client *client)
 
 	tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
 				tps, DEBUG_FOPS);
+
+	/* optionally register GPIOs */
+	if (board && board->base > 0) {
+		tps->outmask = board->outmask;
+
+		tps->chip.label = client->name;
+
+		tps->chip.set = tps65010_gpio_set;
+		tps->chip.direction_output = tps65010_output;
+
+		/* NOTE:  only partial support for inputs; nyet IRQs */
+		tps->chip.get = tps65010_gpio_get;
+
+		tps->chip.base = board->base;
+		tps->chip.ngpio = 6;
+		tps->chip.can_sleep = 1;
+
+		status = gpiochip_add(&tps->chip);
+		if (status < 0)
+			dev_err(&client->dev, "can't add gpiochip, err %d\n",
+					status);
+		else if (board->setup) {
+			status = board->setup(client, board->context);
+			if (status < 0) {
+				dev_dbg(&client->dev,
+					"board %s %s err %d\n",
+					"setup", client->name, status);
+				status = 0;
+			}
+		}
+	}
+
 	return 0;
 fail1:
 	kfree(tps);
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 790fed368aae..5d6cc7f1dc94 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -23,6 +23,7 @@
 #include <asm/arch/corgi.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
 #include <asm/hardware/scoop.h>
 
 #define KB_ROWS				8
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 1d59a2dc3c17..0be74bfc58fe 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -23,6 +23,7 @@
 #include <asm/arch/spitz.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
 
 #define KB_ROWS			7
 #define KB_COLS			11
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 57a1c28bf122..39573b91c8de 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -28,13 +28,6 @@
 #include <linux/spi/ads7846.h>
 #include <asm/irq.h>
 
-#ifdef	CONFIG_ARM
-#include <asm/mach-types.h>
-#ifdef	CONFIG_ARCH_OMAP
-#include <asm/arch/gpio.h>
-#endif
-#endif
-
 
 /*
  * This code has been heavily tested on a Nokia 770, and lightly
@@ -1174,31 +1167,6 @@ static struct spi_driver ads7846_driver = {
 
 static int __init ads7846_init(void)
 {
-	/* grr, board-specific init should stay out of drivers!! */
-
-#ifdef	CONFIG_ARCH_OMAP
-	if (machine_is_omap_osk()) {
-		/* GPIO4 = PENIRQ; GPIO6 = BUSY */
-		omap_request_gpio(4);
-		omap_set_gpio_direction(4, 1);
-		omap_request_gpio(6);
-		omap_set_gpio_direction(6, 1);
-	}
-	// also TI 1510 Innovator, bitbanging through FPGA
-	// also Nokia 770
-	// also Palm Tungsten T2
-#endif
-
-	// PXA:
-	// also Dell Axim X50
-	// also HP iPaq H191x/H192x/H415x/H435x
-	// also Intel Lubbock (additional to UCB1400; as temperature sensor)
-	// also Sharp Zaurus C7xx, C8xx (corgi/sheperd/husky)
-
-	// Atmel at91sam9261-EK uses ads7843
-
-	// also various AMD Au1x00 devel boards
-
 	return spi_register_driver(&ads7846_driver);
 }
 module_init(ads7846_init);
@@ -1206,14 +1174,6 @@ module_init(ads7846_init);
 static void __exit ads7846_exit(void)
 {
 	spi_unregister_driver(&ads7846_driver);
-
-#ifdef	CONFIG_ARCH_OMAP
-	if (machine_is_omap_osk()) {
-		omap_free_gpio(4);
-		omap_free_gpio(6);
-	}
-#endif
-
 }
 module_exit(ads7846_exit);
 
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 99d92f5c93d6..a22576779acd 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -22,6 +22,7 @@
 #include <asm/arch/sharpsl.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
 
 
 #define PWR_MODE_ACTIVE		0
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 859814f62cb0..a3a6199639f9 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -46,13 +46,6 @@ config LEDS_SPITZ
 	  This option enables support for the LEDs on Sharp Zaurus
 	  SL-Cxx00 series (C1000, C3000, C3100).
 
-config LEDS_TOSA
-	tristate "LED Support for the Sharp SL-6000 series"
-	depends on LEDS_CLASS && PXA_SHARPSL
-	help
-	  This option enables support for the LEDs on Sharp Zaurus
-	  SL-6000 series.
-
 config LEDS_S3C24XX
 	tristate "LED Support for Samsung S3C24XX GPIO LEDs"
 	depends on LEDS_CLASS && ARCH_S3C2410
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 84ced3b1a13d..e54f42da21a2 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_LEDS_ATMEL_PWM)		+= leds-atmel-pwm.o
 obj-$(CONFIG_LEDS_CORGI)		+= leds-corgi.o
 obj-$(CONFIG_LEDS_LOCOMO)		+= leds-locomo.o
 obj-$(CONFIG_LEDS_SPITZ)		+= leds-spitz.o
-obj-$(CONFIG_LEDS_TOSA)			+= leds-tosa.o
 obj-$(CONFIG_LEDS_S3C24XX)		+= leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)		+= leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)		+= leds-net48xx.o
diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c
deleted file mode 100644
index 7ebecc41a9be..000000000000
--- a/drivers/leds/leds-tosa.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * LED Triggers Core
- *
- * Copyright 2005 Dirk Opfer
- *
- * Author: Dirk Opfer <Dirk@Opfer-Online.de>
- *	based on spitz.c
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/leds.h>
-#include <asm/hardware/scoop.h>
-#include <asm/mach-types.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/tosa.h>
-
-static void tosaled_amber_set(struct led_classdev *led_cdev,
-				enum led_brightness value)
-{
-	if (value)
-		set_scoop_gpio(&tosascoop_jc_device.dev,
-				TOSA_SCOOP_JC_CHRG_ERR_LED);
-	else
-		reset_scoop_gpio(&tosascoop_jc_device.dev,
-				TOSA_SCOOP_JC_CHRG_ERR_LED);
-}
-
-static void tosaled_green_set(struct led_classdev *led_cdev,
-				enum led_brightness value)
-{
-	if (value)
-		set_scoop_gpio(&tosascoop_jc_device.dev,
-				TOSA_SCOOP_JC_NOTE_LED);
-	else
-		reset_scoop_gpio(&tosascoop_jc_device.dev,
-				TOSA_SCOOP_JC_NOTE_LED);
-}
-
-static struct led_classdev tosa_amber_led = {
-	.name			= "tosa:amber:charge",
-	.default_trigger	= "sharpsl-charge",
-	.brightness_set		= tosaled_amber_set,
-};
-
-static struct led_classdev tosa_green_led = {
-	.name			= "tosa:green:mail",
-	.default_trigger	= "nand-disk",
-	.brightness_set		= tosaled_green_set,
-};
-
-#ifdef CONFIG_PM
-static int tosaled_suspend(struct platform_device *dev, pm_message_t state)
-{
-#ifdef CONFIG_LEDS_TRIGGERS
-	if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name,
-						"sharpsl-charge"))
-#endif
-		led_classdev_suspend(&tosa_amber_led);
-	led_classdev_suspend(&tosa_green_led);
-	return 0;
-}
-
-static int tosaled_resume(struct platform_device *dev)
-{
-	led_classdev_resume(&tosa_amber_led);
-	led_classdev_resume(&tosa_green_led);
-	return 0;
-}
-#else
-#define tosaled_suspend NULL
-#define tosaled_resume NULL
-#endif
-
-static int tosaled_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	ret = led_classdev_register(&pdev->dev, &tosa_amber_led);
-	if (ret < 0)
-		return ret;
-
-	ret = led_classdev_register(&pdev->dev, &tosa_green_led);
-	if (ret < 0)
-		led_classdev_unregister(&tosa_amber_led);
-
-	return ret;
-}
-
-static int tosaled_remove(struct platform_device *pdev)
-{
-	led_classdev_unregister(&tosa_amber_led);
-	led_classdev_unregister(&tosa_green_led);
-
-	return 0;
-}
-
-static struct platform_driver tosaled_driver = {
-	.probe		= tosaled_probe,
-	.remove		= tosaled_remove,
-	.suspend	= tosaled_suspend,
-	.resume		= tosaled_resume,
-	.driver		= {
-		.name		= "tosa-led",
-		.owner		= THIS_MODULE,
-	},
-};
-
-static int __init tosaled_init(void)
-{
-	return platform_driver_register(&tosaled_driver);
-}
-
-static void __exit tosaled_exit(void)
-{
- 	platform_driver_unregister(&tosaled_driver);
-}
-
-module_init(tosaled_init);
-module_exit(tosaled_exit);
-
-MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>");
-MODULE_DESCRIPTION("Tosa LED driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:tosa-led");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0c886c882385..2566479937c9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -22,6 +22,22 @@ config MFD_ASIC3
 	  This driver supports the ASIC3 multifunction chip found on many
 	  PDAs (mainly iPAQ and HTC based ones)
 
+config HTC_EGPIO
+	bool "HTC EGPIO support"
+	depends on GENERIC_HARDIRQS && HAVE_GPIO_LIB
+	help
+	    This driver supports the CPLD egpio chip present on
+	    several HTC phones.  It provides basic support for input
+	    pins, output pins, and irqs.
+
+config HTC_PASIC3
+	tristate "HTC PASIC3 LED/DS1WM chip support"
+	help
+	  This core driver provides register access for the LED/DS1WM
+	  chips labeled "AIC2" and "AIC3", found on HTC Blueangel and
+	  HTC Magician devices, respectively. Actual functionality is
+	  handled by the leds-pasic3 and ds1wm drivers.
+
 endmenu
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 521cd5cb68af..eef4e26807df 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -5,6 +5,9 @@
 obj-$(CONFIG_MFD_SM501)		+= sm501.o
 obj-$(CONFIG_MFD_ASIC3)		+= asic3.o
 
+obj-$(CONFIG_HTC_EGPIO)		+= htc-egpio.o
+obj-$(CONFIG_HTC_PASIC3)	+= htc-pasic3.o
+
 obj-$(CONFIG_MCP)		+= mcp-core.o
 obj-$(CONFIG_MCP_SA11X0)	+= mcp-sa11x0.o
 obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
new file mode 100644
index 000000000000..8872cc077519
--- /dev/null
+++ b/drivers/mfd/htc-egpio.c
@@ -0,0 +1,440 @@
+/*
+ * Support for the GPIO/IRQ expander chips present on several HTC phones.
+ * These are implemented in CPLD chips present on the board.
+ *
+ * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net>
+ * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * This file may be distributed under the terms of the GNU GPL license.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/mfd/htc-egpio.h>
+
+struct egpio_chip {
+	int              reg_start;
+	int              cached_values;
+	unsigned long    is_out;
+	struct device    *dev;
+	struct gpio_chip chip;
+};
+
+struct egpio_info {
+	spinlock_t        lock;
+
+	/* iomem info */
+	void __iomem      *base_addr;
+	int               bus_shift;	/* byte shift */
+	int               reg_shift;	/* bit shift */
+	int               reg_mask;
+
+	/* irq info */
+	int               ack_register;
+	int               ack_write;
+	u16               irqs_enabled;
+	uint              irq_start;
+	int               nirqs;
+	uint              chained_irq;
+
+	/* egpio info */
+	struct egpio_chip *chip;
+	int               nchips;
+};
+
+static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg)
+{
+	writew(value, ei->base_addr + (reg << ei->bus_shift));
+}
+
+static inline u16 egpio_readw(struct egpio_info *ei, int reg)
+{
+	return readw(ei->base_addr + (reg << ei->bus_shift));
+}
+
+/*
+ * IRQs
+ */
+
+static inline void ack_irqs(struct egpio_info *ei)
+{
+	egpio_writew(ei->ack_write, ei, ei->ack_register);
+	pr_debug("EGPIO ack - write %x to base+%x\n",
+			ei->ack_write, ei->ack_register << ei->bus_shift);
+}
+
+static void egpio_ack(unsigned int irq)
+{
+}
+
+/* There does not appear to be a way to proactively mask interrupts
+ * on the egpio chip itself.  So, we simply ignore interrupts that
+ * aren't desired. */
+static void egpio_mask(unsigned int irq)
+{
+	struct egpio_info *ei = get_irq_chip_data(irq);
+	ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));
+	pr_debug("EGPIO mask %d %04x\n", irq, ei->irqs_enabled);
+}
+static void egpio_unmask(unsigned int irq)
+{
+	struct egpio_info *ei = get_irq_chip_data(irq);
+	ei->irqs_enabled |= 1 << (irq - ei->irq_start);
+	pr_debug("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled);
+}
+
+static struct irq_chip egpio_muxed_chip = {
+	.name   = "htc-egpio",
+	.ack	= egpio_ack,
+	.mask   = egpio_mask,
+	.unmask = egpio_unmask,
+};
+
+static void egpio_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct egpio_info *ei = get_irq_data(irq);
+	int irqpin;
+
+	/* Read current pins. */
+	unsigned long readval = egpio_readw(ei, ei->ack_register);
+	pr_debug("IRQ reg: %x\n", (unsigned int)readval);
+	/* Ack/unmask interrupts. */
+	ack_irqs(ei);
+	/* Process all set pins. */
+	readval &= ei->irqs_enabled;
+	for_each_bit(irqpin, &readval, ei->nirqs) {
+		/* Run irq handler */
+		pr_debug("got IRQ %d\n", irqpin);
+		irq = ei->irq_start + irqpin;
+		desc = &irq_desc[irq];
+		desc->handle_irq(irq, desc);
+	}
+}
+
+int htc_egpio_get_wakeup_irq(struct device *dev)
+{
+	struct egpio_info *ei = dev_get_drvdata(dev);
+
+	/* Read current pins. */
+	u16 readval = egpio_readw(ei, ei->ack_register);
+	/* Ack/unmask interrupts. */
+	ack_irqs(ei);
+	/* Return first set pin. */
+	readval &= ei->irqs_enabled;
+	return ei->irq_start + ffs(readval) - 1;
+}
+EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
+
+static inline int egpio_pos(struct egpio_info *ei, int bit)
+{
+	return bit >> ei->reg_shift;
+}
+
+static inline int egpio_bit(struct egpio_info *ei, int bit)
+{
+	return 1 << (bit & ((1 << ei->reg_shift)-1));
+}
+
+/*
+ * Input pins
+ */
+
+static int egpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct egpio_chip *egpio;
+	struct egpio_info *ei;
+	unsigned           bit;
+	int                reg;
+	int                value;
+
+	pr_debug("egpio_get_value(%d)\n", chip->base + offset);
+
+	egpio = container_of(chip, struct egpio_chip, chip);
+	ei    = dev_get_drvdata(egpio->dev);
+	bit   = egpio_bit(ei, offset);
+	reg   = egpio->reg_start + egpio_pos(ei, offset);
+
+	value = egpio_readw(ei, reg);
+	pr_debug("readw(%p + %x) = %x\n",
+			ei->base_addr, reg << ei->bus_shift, value);
+	return value & bit;
+}
+
+static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct egpio_chip *egpio;
+
+	egpio = container_of(chip, struct egpio_chip, chip);
+	return test_bit(offset, &egpio->is_out) ? -EINVAL : 0;
+}
+
+
+/*
+ * Output pins
+ */
+
+static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	unsigned long     flag;
+	struct egpio_chip *egpio;
+	struct egpio_info *ei;
+	unsigned          bit;
+	int               pos;
+	int               reg;
+	int               shift;
+
+	pr_debug("egpio_set(%s, %d(%d), %d)\n",
+			chip->label, offset, offset+chip->base, value);
+
+	egpio = container_of(chip, struct egpio_chip, chip);
+	ei    = dev_get_drvdata(egpio->dev);
+	bit   = egpio_bit(ei, offset);
+	pos   = egpio_pos(ei, offset);
+	reg   = egpio->reg_start + pos;
+	shift = pos << ei->reg_shift;
+
+	pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear",
+			reg, (egpio->cached_values >> shift) & ei->reg_mask);
+
+	spin_lock_irqsave(&ei->lock, flag);
+	if (value)
+		egpio->cached_values |= (1 << offset);
+	else
+		egpio->cached_values &= ~(1 << offset);
+	egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg);
+	spin_unlock_irqrestore(&ei->lock, flag);
+}
+
+static int egpio_direction_output(struct gpio_chip *chip,
+					unsigned offset, int value)
+{
+	struct egpio_chip *egpio;
+
+	egpio = container_of(chip, struct egpio_chip, chip);
+	if (test_bit(offset, &egpio->is_out)) {
+		egpio_set(chip, offset, value);
+		return 0;
+	} else {
+		return -EINVAL;
+	}
+}
+
+static void egpio_write_cache(struct egpio_info *ei)
+{
+	int               i;
+	struct egpio_chip *egpio;
+	int               shift;
+
+	for (i = 0; i < ei->nchips; i++) {
+		egpio = &(ei->chip[i]);
+		if (!egpio->is_out)
+			continue;
+
+		for (shift = 0; shift < egpio->chip.ngpio;
+				shift += (1<<ei->reg_shift)) {
+
+			int reg = egpio->reg_start + egpio_pos(ei, shift);
+
+			if (!((egpio->is_out >> shift) & ei->reg_mask))
+				continue;
+
+			pr_debug("EGPIO: setting %x to %x, was %x\n", reg,
+				(egpio->cached_values >> shift) & ei->reg_mask,
+				egpio_readw(ei, reg));
+
+			egpio_writew((egpio->cached_values >> shift)
+					& ei->reg_mask, ei, reg);
+		}
+	}
+}
+
+
+/*
+ * Setup
+ */
+
+static int __init egpio_probe(struct platform_device *pdev)
+{
+	struct htc_egpio_platform_data *pdata = pdev->dev.platform_data;
+	struct resource   *res;
+	struct egpio_info *ei;
+	struct gpio_chip  *chip;
+	unsigned int      irq, irq_end;
+	int               i;
+	int               ret;
+
+	/* Initialize ei data structure. */
+	ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+	if (!ei)
+		return -ENOMEM;
+
+	spin_lock_init(&ei->lock);
+
+	/* Find chained irq */
+	ret = -EINVAL;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (res)
+		ei->chained_irq = res->start;
+
+	/* Map egpio chip into virtual address space. */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto fail;
+	ei->base_addr = ioremap_nocache(res->start, res->end - res->start);
+	if (!ei->base_addr)
+		goto fail;
+	pr_debug("EGPIO phys=%08x virt=%p\n", res->start, ei->base_addr);
+
+	if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
+		goto fail;
+	ei->bus_shift = fls(pdata->bus_width - 1) - 3;
+	pr_debug("bus_shift = %d\n", ei->bus_shift);
+
+	if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
+		goto fail;
+	ei->reg_shift = fls(pdata->reg_width - 1);
+	pr_debug("reg_shift = %d\n", ei->reg_shift);
+
+	ei->reg_mask = (1 << pdata->reg_width) - 1;
+
+	platform_set_drvdata(pdev, ei);
+
+	ei->nchips = pdata->num_chips;
+	ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL);
+	if (!ei) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+	for (i = 0; i < ei->nchips; i++) {
+		ei->chip[i].reg_start = pdata->chip[i].reg_start;
+		ei->chip[i].cached_values = pdata->chip[i].initial_values;
+		ei->chip[i].is_out = pdata->chip[i].direction;
+		ei->chip[i].dev = &(pdev->dev);
+		chip = &(ei->chip[i].chip);
+		chip->label           = "htc-egpio";
+		chip->get             = egpio_get;
+		chip->set             = egpio_set;
+		chip->direction_input = egpio_direction_input;
+		chip->direction_output = egpio_direction_output;
+		chip->base            = pdata->chip[i].gpio_base;
+		chip->ngpio           = pdata->chip[i].num_gpios;
+
+		gpiochip_add(chip);
+	}
+
+	/* Set initial pin values */
+	egpio_write_cache(ei);
+
+	ei->irq_start = pdata->irq_base;
+	ei->nirqs = pdata->num_irqs;
+	ei->ack_register = pdata->ack_register;
+
+	if (ei->chained_irq) {
+		/* Setup irq handlers */
+		ei->ack_write = 0xFFFF;
+		if (pdata->invert_acks)
+			ei->ack_write = 0;
+		irq_end = ei->irq_start + ei->nirqs;
+		for (irq = ei->irq_start; irq < irq_end; irq++) {
+			set_irq_chip(irq, &egpio_muxed_chip);
+			set_irq_chip_data(irq, ei);
+			set_irq_handler(irq, handle_simple_irq);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
+		set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING);
+		set_irq_data(ei->chained_irq, ei);
+		set_irq_chained_handler(ei->chained_irq, egpio_handler);
+		ack_irqs(ei);
+
+		device_init_wakeup(&pdev->dev, 1);
+	}
+
+	return 0;
+
+fail:
+	printk(KERN_ERR "EGPIO failed to setup\n");
+	kfree(ei);
+	return ret;
+}
+
+static int __exit egpio_remove(struct platform_device *pdev)
+{
+	struct egpio_info *ei = platform_get_drvdata(pdev);
+	unsigned int      irq, irq_end;
+
+	if (ei->chained_irq) {
+		irq_end = ei->irq_start + ei->nirqs;
+		for (irq = ei->irq_start; irq < irq_end; irq++) {
+			set_irq_chip(irq, NULL);
+			set_irq_handler(irq, NULL);
+			set_irq_flags(irq, 0);
+		}
+		set_irq_chained_handler(ei->chained_irq, NULL);
+		device_init_wakeup(&pdev->dev, 0);
+	}
+	iounmap(ei->base_addr);
+	kfree(ei->chip);
+	kfree(ei);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int egpio_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct egpio_info *ei = platform_get_drvdata(pdev);
+
+	if (ei->chained_irq && device_may_wakeup(&pdev->dev))
+		enable_irq_wake(ei->chained_irq);
+	return 0;
+}
+
+static int egpio_resume(struct platform_device *pdev)
+{
+	struct egpio_info *ei = platform_get_drvdata(pdev);
+
+	if (ei->chained_irq && device_may_wakeup(&pdev->dev))
+		disable_irq_wake(ei->chained_irq);
+
+	/* Update registers from the cache, in case
+	   the CPLD was powered off during suspend */
+	egpio_write_cache(ei);
+	return 0;
+}
+#else
+#define egpio_suspend NULL
+#define egpio_resume NULL
+#endif
+
+
+static struct platform_driver egpio_driver = {
+	.driver = {
+		.name = "htc-egpio",
+	},
+	.remove       = __exit_p(egpio_remove),
+	.suspend      = egpio_suspend,
+	.resume       = egpio_resume,
+};
+
+static int __init egpio_init(void)
+{
+	return platform_driver_probe(&egpio_driver, egpio_probe);
+}
+
+static void __exit egpio_exit(void)
+{
+	platform_driver_unregister(&egpio_driver);
+}
+
+/* start early for dependencies */
+subsys_initcall(egpio_init);
+module_exit(egpio_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>");
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
new file mode 100644
index 000000000000..af66f4f28300
--- /dev/null
+++ b/drivers/mfd/htc-pasic3.c
@@ -0,0 +1,265 @@
+/*
+ * Core driver for HTC PASIC3 LED/DS1WM chip.
+ *
+ * Copyright (C) 2006 Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/ds1wm.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/htc-pasic3.h>
+
+#include <asm/arch/pxa-regs.h>
+
+struct pasic3_data {
+	void __iomem *mapping;
+	unsigned int bus_shift;
+	struct platform_device *ds1wm_pdev;
+	struct platform_device *led_pdev;
+};
+
+#define REG_ADDR  5
+#define REG_DATA  6
+#define NUM_REGS  7
+
+#define READ_MODE 0x80
+
+/*
+ * write to a secondary register on the PASIC3
+ */
+void pasic3_write_register(struct device *dev, u32 reg, u8 val)
+{
+	struct pasic3_data *asic = dev->driver_data;
+	int bus_shift = asic->bus_shift;
+	void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
+	void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
+
+	__raw_writeb(~READ_MODE & reg, addr);
+	__raw_writeb(val, data);
+}
+EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */
+
+/*
+ * read from a secondary register on the PASIC3
+ */
+u8 pasic3_read_register(struct device *dev, u32 reg)
+{
+	struct pasic3_data *asic = dev->driver_data;
+	int bus_shift = asic->bus_shift;
+	void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
+	void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
+
+	__raw_writeb(READ_MODE | reg, addr);
+	return __raw_readb(data);
+}
+EXPORT_SYMBOL(pasic3_read_register); /* for leds-pasic3 */
+
+/*
+ * LEDs
+ */
+
+static int led_device_add(struct device *pasic3_dev,
+				const struct pasic3_leds_machinfo *pdata)
+{
+	struct pasic3_data *asic = pasic3_dev->driver_data;
+	struct platform_device *pdev;
+	int ret;
+
+	pdev = platform_device_alloc("pasic3-led", -1);
+	if (!pdev) {
+		dev_dbg(pasic3_dev, "failed to allocate LED platform device\n");
+		return -ENOMEM;
+	}
+
+	ret = platform_device_add_data(pdev, pdata,
+					sizeof(struct pasic3_leds_machinfo));
+	if (ret < 0) {
+		dev_dbg(pasic3_dev, "failed to add LED platform data\n");
+		goto exit_pdev_put;
+	}
+
+	pdev->dev.parent = pasic3_dev;
+	ret = platform_device_add(pdev);
+	if (ret < 0) {
+		dev_dbg(pasic3_dev, "failed to add LED platform device\n");
+		goto exit_pdev_put;
+	}
+
+	asic->led_pdev = pdev;
+	return 0;
+
+exit_pdev_put:
+	platform_device_put(pdev);
+	return ret;
+}
+
+/*
+ * DS1WM
+ */
+
+static void ds1wm_enable(struct platform_device *pdev)
+{
+	struct device *dev = pdev->dev.parent;
+	int c;
+
+	c = pasic3_read_register(dev, 0x28);
+	pasic3_write_register(dev, 0x28, c & 0x7f);
+
+	dev_dbg(dev, "DS1WM OWM_EN low (active) %02x\n", c & 0x7f);
+}
+
+static void ds1wm_disable(struct platform_device *pdev)
+{
+	struct device *dev = pdev->dev.parent;
+	int c;
+
+	c = pasic3_read_register(dev, 0x28);
+	pasic3_write_register(dev, 0x28, c | 0x80);
+
+	dev_dbg(dev, "DS1WM OWM_EN high (inactive) %02x\n", c | 0x80);
+}
+
+static struct ds1wm_platform_data ds1wm_pdata = {
+	.bus_shift = 2,
+	.enable    = ds1wm_enable,
+	.disable   = ds1wm_disable,
+};
+
+static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift)
+{
+	struct pasic3_data *asic = pasic3_dev->driver_data;
+	struct platform_device *pdev;
+	int ret;
+
+	pdev = platform_device_alloc("ds1wm", -1);
+	if (!pdev) {
+		dev_dbg(pasic3_dev, "failed to allocate DS1WM platform device\n");
+		return -ENOMEM;
+	}
+
+	ret = platform_device_add_resources(pdev, pdev->resource,
+						pdev->num_resources);
+	if (ret < 0) {
+		dev_dbg(pasic3_dev, "failed to add DS1WM resources\n");
+		goto exit_pdev_put;
+	}
+
+	ds1wm_pdata.bus_shift = asic->bus_shift;
+	ret = platform_device_add_data(pdev, &ds1wm_pdata,
+					sizeof(struct ds1wm_platform_data));
+	if (ret < 0) {
+		dev_dbg(pasic3_dev, "failed to add DS1WM platform data\n");
+		goto exit_pdev_put;
+	}
+
+	pdev->dev.parent = pasic3_dev;
+	ret = platform_device_add(pdev);
+	if (ret < 0) {
+		dev_dbg(pasic3_dev, "failed to add DS1WM platform device\n");
+		goto exit_pdev_put;
+	}
+
+	asic->ds1wm_pdev = pdev;
+	return 0;
+
+exit_pdev_put:
+	platform_device_put(pdev);
+	return ret;
+}
+
+static int __init pasic3_probe(struct platform_device *pdev)
+{
+	struct pasic3_platform_data *pdata = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct pasic3_data *asic;
+	struct resource *r;
+	int ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -ENXIO;
+
+	if (!request_mem_region(r->start, r->end - r->start + 1, "pasic3"))
+		return -EBUSY;
+
+	asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL);
+	if (!asic)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, asic);
+
+	if (pdata && pdata->bus_shift)
+		asic->bus_shift = pdata->bus_shift;
+	else
+		asic->bus_shift = 2;
+
+	asic->mapping = ioremap(r->start, r->end - r->start + 1);
+	if (!asic->mapping) {
+		dev_err(dev, "couldn't ioremap PASIC3\n");
+		kfree(asic);
+		return -ENOMEM;
+	}
+
+	ret = ds1wm_device_add(dev, asic->bus_shift);
+	if (ret < 0)
+		dev_warn(dev, "failed to register DS1WM\n");
+
+	if (pdata->led_pdata) {
+		ret = led_device_add(dev, pdata->led_pdata);
+		if (ret < 0)
+			dev_warn(dev, "failed to register LED device\n");
+	}
+
+	return 0;
+}
+
+static int pasic3_remove(struct platform_device *pdev)
+{
+	struct pasic3_data *asic = platform_get_drvdata(pdev);
+	struct resource *r;
+
+	if (asic->led_pdev)
+		platform_device_unregister(asic->led_pdev);
+	if (asic->ds1wm_pdev)
+		platform_device_unregister(asic->ds1wm_pdev);
+
+	iounmap(asic->mapping);
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(r->start, r->end - r->start + 1);
+	kfree(asic);
+	return 0;
+}
+
+static struct platform_driver pasic3_driver = {
+	.driver		= {
+		.name	= "pasic3",
+	},
+	.remove		= pasic3_remove,
+};
+
+static int __init pasic3_base_init(void)
+{
+	return platform_driver_probe(&pasic3_driver, pasic3_probe);
+}
+
+static void __exit pasic3_base_exit(void)
+{
+	platform_driver_unregister(&pasic3_driver);
+}
+
+module_init(pasic3_base_init);
+module_exit(pasic3_base_exit);
+
+MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>");
+MODULE_DESCRIPTION("Core driver for HTC PASIC3");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 4a3c6759492b..959fb86cda01 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -314,7 +314,7 @@ config MTD_ALAUDA
 
 config MTD_NAND_ORION
 	tristate "NAND Flash support for Marvell Orion SoC"
-	depends on ARCH_ORION && MTD_NAND
+	depends on PLAT_ORION && MTD_NAND
 	help
 	  This enables the NAND flash controller on Orion machines.
 
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 9162cca0182b..ec5ad28b237e 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -18,8 +18,8 @@
 #include <linux/mtd/partitions.h>
 #include <asm/io.h>
 #include <asm/sizes.h>
-#include <asm/arch/platform.h>
 #include <asm/arch/hardware.h>
+#include <asm/plat-orion/orion_nand.h>
 
 #ifdef CONFIG_MTD_CMDLINE_PARTS
 static const char *part_probes[] = { "cmdlinepart", NULL };
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 45c3a208d93f..2399a3796f6e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2335,7 +2335,7 @@ config UGETH_TX_ON_DEMAND
 
 config MV643XX_ETH
 	tristate "Marvell Discovery (643XX) and Orion ethernet support"
-	depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION
+	depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
 	select MII
 	help
 	  This driver supports the gigabit ethernet MACs in the
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 0ae0d83e5d22..978e20a1791b 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -1043,7 +1043,9 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
 	} else if (machine_is_csb337()) {
 		/* mix link activity status into LED2 link state */
 		write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
-	}
+	} else if (machine_is_ecbat91())
+		write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
+
 	disable_mdi();
 	spin_unlock_irq(&lp->lock);
 
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 8c09344f58dc..8db71ab20456 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -36,6 +36,7 @@
 #include <asm/hardware.h>
 #include <asm/arch/irda.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
 
 #ifdef CONFIG_MACH_MAINSTONE
 #include <asm/arch/mainstone.h>
@@ -831,6 +832,11 @@ static int pxa_irda_probe(struct platform_device *pdev)
 	if (err)
 		goto err_mem_5;
 
+	if (si->pdata->startup)
+		err = si->pdata->startup(si->dev);
+	if (err)
+		goto err_startup;
+
 	dev->hard_start_xmit	= pxa_irda_hard_xmit;
 	dev->open		= pxa_irda_start;
 	dev->stop		= pxa_irda_stop;
@@ -856,6 +862,9 @@ static int pxa_irda_probe(struct platform_device *pdev)
 		dev_set_drvdata(&pdev->dev, dev);
 
 	if (err) {
+		if (si->pdata->shutdown)
+			si->pdata->shutdown(si->dev);
+err_startup:
 		kfree(si->tx_buff.head);
 err_mem_5:
 		kfree(si->rx_buff.head);
@@ -881,6 +890,8 @@ static int pxa_irda_remove(struct platform_device *_dev)
 	if (dev) {
 		struct pxa_irda *si = netdev_priv(dev);
 		unregister_netdev(dev);
+		if (si->pdata->shutdown)
+			si->pdata->shutdown(si->dev);
 		kfree(si->tx_buff.head);
 		kfree(si->rx_buff.head);
 		clk_put(si->fir_clk);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 8b22281b087f..ed8c06904807 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -200,6 +200,7 @@ config PCMCIA_AU1X00
 config PCMCIA_SA1100
 	tristate "SA1100 support"
 	depends on ARM && ARCH_SA1100 && PCMCIA
+	depends on ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL || MACH_ARMCORE
 	help
 	  Say Y here to include support for SA11x0-based PCMCIA or CF
 	  sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/
diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c
index fbf2f3a6984c..e7ab060ff118 100644
--- a/drivers/pcmcia/pxa2xx_cm_x270.c
+++ b/drivers/pcmcia/pxa2xx_cm_x270.c
@@ -20,6 +20,7 @@
 #include <asm/hardware.h>
 
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
 #include <asm/arch/cm-x270.h>
 
 #include "soc_common.h"
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 16ba9ac7a566..5a375bf0ebf4 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -166,15 +166,6 @@
 #define SERIAL_IMX_MAJOR	204
 #define MINOR_START		41
 
-#define NR_PORTS		2
-
-#define IMX_ISR_PASS_LIMIT	256
-
-/*
- * This is the size of our serial port register set.
- */
-#define UART_PORT_SIZE	0x100
-
 /*
  * This determines how often we check the modem status signals
  * for any change.  They generally aren't connected to an IRQ
@@ -358,66 +349,60 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
 	struct tty_struct *tty = sport->port.info->tty;
 	unsigned long flags, temp;
 
-	rx = readl(sport->port.membase + URXD0);
 	spin_lock_irqsave(&sport->port.lock,flags);
 
-	do {
+	while (readl(sport->port.membase + USR2) & USR2_RDR) {
 		flg = TTY_NORMAL;
 		sport->port.icount.rx++;
 
+		rx = readl(sport->port.membase + URXD0);
+
 		temp = readl(sport->port.membase + USR2);
-		if( temp & USR2_BRCD ) {
+		if (temp & USR2_BRCD) {
 			writel(temp | USR2_BRCD, sport->port.membase + USR2);
-			if(uart_handle_break(&sport->port))
-				goto ignore_char;
+			if (uart_handle_break(&sport->port))
+				continue;
 		}
 
 		if (uart_handle_sysrq_char
 		            (&sport->port, (unsigned char)rx))
-			goto ignore_char;
+			continue;
+
+		if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
+			if (rx & URXD_PRERR)
+				sport->port.icount.parity++;
+			else if (rx & URXD_FRMERR)
+				sport->port.icount.frame++;
+			if (rx & URXD_OVRRUN)
+				sport->port.icount.overrun++;
+
+			if (rx & sport->port.ignore_status_mask) {
+				if (++ignored > 100)
+					goto out;
+				continue;
+			}
+
+			rx &= sport->port.read_status_mask;
+
+			if (rx & URXD_PRERR)
+				flg = TTY_PARITY;
+			else if (rx & URXD_FRMERR)
+				flg = TTY_FRAME;
+			if (rx & URXD_OVRRUN)
+				flg = TTY_OVERRUN;
 
-		if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) )
-			goto handle_error;
+#ifdef SUPPORT_SYSRQ
+			sport->port.sysrq = 0;
+#endif
+		}
 
-	error_return:
 		tty_insert_flip_char(tty, rx, flg);
-
-	ignore_char:
-		rx = readl(sport->port.membase + URXD0);
-	} while(rx & URXD_CHARRDY);
+	}
 
 out:
 	spin_unlock_irqrestore(&sport->port.lock,flags);
 	tty_flip_buffer_push(tty);
 	return IRQ_HANDLED;
-
-handle_error:
-	if (rx & URXD_PRERR)
-		sport->port.icount.parity++;
-	else if (rx & URXD_FRMERR)
-		sport->port.icount.frame++;
-	if (rx & URXD_OVRRUN)
-		sport->port.icount.overrun++;
-
-	if (rx & sport->port.ignore_status_mask) {
-		if (++ignored > 100)
-			goto out;
-		goto ignore_char;
-	}
-
-	rx &= sport->port.read_status_mask;
-
-	if (rx & URXD_PRERR)
-		flg = TTY_PARITY;
-	else if (rx & URXD_FRMERR)
-		flg = TTY_FRAME;
-	if (rx & URXD_OVRRUN)
-		flg = TTY_OVERRUN;
-
-#ifdef SUPPORT_SYSRQ
-	sport->port.sysrq = 0;
-#endif
-	goto error_return;
 }
 
 /*
@@ -546,7 +531,7 @@ static int imx_startup(struct uart_port *port)
 	writel(USR1_RTSD, sport->port.membase + USR1);
 
 	temp = readl(sport->port.membase + UCR1);
-	temp |= (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+	temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
 	writel(temp, sport->port.membase + UCR1);
 
 	temp = readl(sport->port.membase + UCR2);
@@ -731,9 +716,11 @@ static const char *imx_type(struct uart_port *port)
  */
 static void imx_release_port(struct uart_port *port)
 {
-	struct imx_port *sport = (struct imx_port *)port;
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *mmres;
 
-	release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
+	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mmres->start, mmres->end - mmres->start + 1);
 }
 
 /*
@@ -741,10 +728,18 @@ static void imx_release_port(struct uart_port *port)
  */
 static int imx_request_port(struct uart_port *port)
 {
-	struct imx_port *sport = (struct imx_port *)port;
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *mmres;
+	void *ret;
+
+	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mmres)
+		return -ENODEV;
+
+	ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
+			"imx-uart");
 
-	return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
-			"imx-uart") != NULL ? 0 : -EBUSY;
+	return  ret ? 0 : -EBUSY;
 }
 
 /*
@@ -815,7 +810,7 @@ static struct imx_port imx_ports[] = {
 		.type		= PORT_IMX,
 		.iotype		= UPIO_MEM,
 		.membase	= (void *)IMX_UART1_BASE,
-		.mapbase	= IMX_UART1_BASE, /* FIXME */
+		.mapbase	= 0x00206000,
 		.irq		= UART1_MINT_RX,
 		.uartclk	= 16000000,
 		.fifosize	= 32,
@@ -831,7 +826,7 @@ static struct imx_port imx_ports[] = {
 		.type		= PORT_IMX,
 		.iotype		= UPIO_MEM,
 		.membase	= (void *)IMX_UART2_BASE,
-		.mapbase	= IMX_UART2_BASE, /* FIXME */
+		.mapbase	= 0x00207000,
 		.irq		= UART2_MINT_RX,
 		.uartclk	= 16000000,
 		.fifosize	= 32,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 46ee7f4c0912..85074cb36f38 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1033,7 +1033,7 @@ MODULE_LICENSE ("GPL");
 #define OF_PLATFORM_DRIVER	ehci_hcd_ppc_of_driver
 #endif
 
-#ifdef CONFIG_ARCH_ORION
+#ifdef CONFIG_PLAT_ORION
 #include "ehci-orion.c"
 #define	PLATFORM_DRIVER		ehci_orion_driver
 #endif
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index e129981f139f..d187d0313742 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -11,15 +11,18 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <asm/arch/orion.h>
+#include <linux/mbus.h>
+#include <asm/plat-orion/ehci-orion.h>
 
 #define rdl(off)	__raw_readl(hcd->regs + (off))
 #define wrl(off, val)	__raw_writel((val), hcd->regs + (off))
 
-#define USB_CAUSE		0x310
-#define USB_MASK		0x314
 #define USB_CMD			0x140
 #define USB_MODE		0x1a8
+#define USB_CAUSE		0x310
+#define USB_MASK		0x314
+#define USB_WINDOW_CTRL(i)	(0x320 + ((i) << 4))
+#define USB_WINDOW_BASE(i)	(0x324 + ((i) << 4))
 #define USB_IPG			0x360
 #define USB_PHY_PWR_CTRL	0x400
 #define USB_PHY_TX_CTRL		0x420
@@ -162,8 +165,30 @@ static const struct hc_driver ehci_orion_hc_driver = {
 	.bus_resume = ehci_bus_resume,
 };
 
+static void __init
+ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
+				struct mbus_dram_target_info *dram)
+{
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		wrl(USB_WINDOW_CTRL(i), 0);
+		wrl(USB_WINDOW_BASE(i), 0);
+	}
+
+	for (i = 0; i < dram->num_cs; i++) {
+		struct mbus_dram_window *cs = dram->cs + i;
+
+		wrl(USB_WINDOW_CTRL(i), ((cs->size - 1) & 0xffff0000) |
+					(cs->mbus_attr << 8) |
+					(dram->mbus_dram_target_id << 4) | 1);
+		wrl(USB_WINDOW_BASE(i), cs->base);
+	}
+}
+
 static int __init ehci_orion_drv_probe(struct platform_device *pdev)
 {
+	struct orion_ehci_data *pd = pdev->dev.platform_data;
 	struct resource *res;
 	struct usb_hcd *hcd;
 	struct ehci_hcd *ehci;
@@ -227,6 +252,12 @@ static int __init ehci_orion_drv_probe(struct platform_device *pdev)
 	ehci->sbrn = 0x20;
 
 	/*
+	 * (Re-)program MBUS remapping windows if we are asked to.
+	 */
+	if (pd != NULL && pd->dram != NULL)
+		ehci_orion_conf_mbus_windows(hcd, pd->dram);
+
+	/*
 	 * setup Orion USB controller
 	 */
 	orion_usb_setup(hcd);
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 97facb121c73..757651954e6c 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -45,6 +45,7 @@
 #include <asm/irq.h>
 #include <asm/div64.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
 #include <asm/arch/bitfield.h>
 #include <asm/arch/pxafb.h>