Index: linux-2.6.21/arch/arm/mach-pxa/ezx-emu.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21/arch/arm/mach-pxa/ezx-emu.c	2007-09-07 15:27:23.000000000 -0300
@@ -0,0 +1,219 @@
+/*
+ *  EMU Driver for Motorola EZX phones
+ *
+ *  Copyright (c) 2007 Daniel Ribeiro <drwyrm@gmail.com>
+ *
+ *  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/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/ezx.h>
+#include <asm/arch/ezx-pcap.h>
+#include <asm/arch/udc.h>
+
+static struct pxa2xx_udc_mach_info ezx_udc_info;
+extern int ezx_pcap_bit_set(u_int32_t, u_int8_t);
+extern int ezx_pcap_read_bit(u_int32_t);
+static int emu_irq_usb4v;
+static int emu_irq_usb1v;
+
+
+#if defined CONFIG_EZX_EMU_USB
+#define emu_switch_to_default() emu_switch_to_usb()
+#elif defined CONFIG_EZX_EMU_UART
+#define emu_switch_to_default() emu_switch_to_uart()
+#else
+#define emu_switch_to_default() emu_switch_to_nothing()
+#endif
+
+void emu_switch_to_usb(void)
+{
+	printk(KERN_NOTICE "EMU: Switching to USB\n");
+	pxa_gpio_mode(GPIO34_USB_P2_2_MD);
+	pxa_gpio_mode(GPIO35_USB_P2_1_MD);
+	pxa_gpio_mode(GPIO36_USB_P2_4_MD);
+	pxa_gpio_mode(GPIO39_USB_P2_6_MD);
+	pxa_gpio_mode(GPIO40_USB_P2_5_MD);
+	pxa_gpio_mode(GPIO53_USB_P2_3_MD);
+	UP2OCR = 0x02000000;
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_RS232ENB, 1);
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_FSENB, 0);
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_VUSB_EN, 1);
+	clr_GPIO(GPIO_EMU_MUX1);
+	clr_GPIO(GPIO_EMU_MUX2);
+}
+
+void emu_switch_to_uart(void)
+{
+	printk(KERN_NOTICE "EMU: Switching to UART\n");
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_VUSB_EN,0);
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_RS232ENB, 0);
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_RS232_DIR, 1);
+	set_GPIO(GPIO39_FFTXD);
+	pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT);
+	set_GPIO(GPIO34_TXENB);
+	pxa_gpio_mode(GPIO35_XRXD | GPIO_IN);
+	pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN);
+	pxa_gpio_mode(GPIO40_VPIN | GPIO_IN);
+	pxa_gpio_mode(GPIO39_FFTXD_MD);
+	pxa_gpio_mode(GPIO53_FFRXD_MD);
+	CKEN |= CKEN6_FFUART;
+	clr_GPIO(GPIO_EMU_MUX1);
+	clr_GPIO(GPIO_EMU_MUX2);
+
+}
+
+void emu_switch_to_audio(int stereo)
+{
+	printk(KERN_NOTICE "EMU: Switching to audio(%s)\n", (stereo ? "stereo" : "mono"));
+	clr_GPIO(GPIO39_VPOUT);
+	if (stereo) {
+		pxa_gpio_mode(GPIO34_TXENB | GPIO_IN);
+		clr_GPIO(GPIO39_VPOUT);
+	} else {
+		pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT);
+		set_GPIO(GPIO34_TXENB);
+	}
+
+	pxa_gpio_mode(GPIO35_XRXD  | GPIO_IN);
+	pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN);
+	pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN);
+	pxa_gpio_mode(GPIO40_VPIN  | GPIO_IN);
+	pxa_gpio_mode(GPIO53_VMIN  | GPIO_IN);
+	set_GPIO(GPIO_EMU_MUX1);
+	if (stereo)
+		set_GPIO(GPIO_EMU_MUX2);
+	else
+		clr_GPIO(GPIO_EMU_MUX2);
+}
+
+void emu_switch_to_nothing(void)
+{
+	printk(KERN_NOTICE "EMU: Switching to disconnected\n");
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_VUSB_EN, 0);
+	ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_RS232ENB, 1);
+	pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT);
+	set_GPIO(GPIO34_TXENB);
+	pxa_gpio_mode(GPIO35_XRXD  | GPIO_IN);
+	pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN);
+	pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN);
+	pxa_gpio_mode(GPIO40_VPIN  | GPIO_IN);
+	pxa_gpio_mode(GPIO53_VMIN  | GPIO_IN);
+}
+
+
+static irqreturn_t emu_irq(int irq, void *data)
+{
+	switch (irq) {
+	case EZX_IRQ_USB4V:
+		if(ezx_pcap_read_bit(pbit(PCAP_REG_PSTAT, PCAP_IRQ_USB4V)))
+			emu_switch_to_default();
+		break;
+	case EZX_IRQ_USB1V:
+		if(!ezx_pcap_read_bit(pbit(PCAP_REG_PSTAT, PCAP_IRQ_USB1V)))
+			emu_switch_to_nothing();
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __init ezx_emu_probe(struct platform_device *dev)
+{
+	pxa_gpio_mode(GPIO_SNP_INT_IN | GPIO_IN);
+	pxa_gpio_mode(GPIO_EMU_MUX1 | GPIO_OUT);
+	pxa_gpio_mode(GPIO_EMU_MUX2 | GPIO_OUT);
+
+	emu_irq_usb4v = platform_get_irq(dev, 0);
+	if(emu_irq_usb4v < 0) {
+		printk(KERN_ERR "Unable to get IRQ for USB4V!\n");
+		return emu_irq_usb4v;
+	}
+	emu_irq_usb1v = platform_get_irq(dev, 1);
+	if(emu_irq_usb1v < 0) {
+		printk(KERN_ERR "Unable to get IRQ for USB1V!\n");
+		return emu_irq_usb1v;
+	}
+
+	request_irq(emu_irq_usb4v, &emu_irq, SA_INTERRUPT, "usb 4v", NULL);
+	request_irq(emu_irq_usb1v, &emu_irq, SA_INTERRUPT, "usb 1v", NULL);
+
+	pxa_set_udc_info(&ezx_udc_info);
+
+	if(ezx_pcap_read_bit(pbit(PCAP_REG_PSTAT, PCAP_IRQ_USB4V)))
+		emu_switch_to_default();
+	else
+		emu_switch_to_nothing();
+
+	return 0;
+}
+
+static int ezx_emu_remove(struct platform_device *dev)
+{
+	free_irq(emu_irq_usb4v, NULL);
+	free_irq(emu_irq_usb1v, NULL);
+
+	return 0;
+}
+
+/* USB Device Controller */
+static int udc_connected_status;
+static void ezx_udc_command(int cmd)
+{
+	switch (cmd) {
+	case PXA2XX_UDC_CMD_DISCONNECT:
+		printk(KERN_NOTICE "USB cmd disconnect\n");
+		ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_USB_PU,0);
+		udc_connected_status = 0;
+		break;
+	case PXA2XX_UDC_CMD_CONNECT:
+		printk(KERN_NOTICE "USB cmd connect\n");
+		ezx_pcap_bit_set(PCAP_BIT_BUSCTRL_USB_PU,1);
+		udc_connected_status = 1;
+		break;
+	}
+}
+
+static int ezx_udc_is_connected(void)
+{
+	return udc_connected_status;
+}
+
+static struct pxa2xx_udc_mach_info ezx_udc_info __initdata = {
+	.udc_is_connected	= ezx_udc_is_connected,
+	.udc_command		= ezx_udc_command,
+};
+
+static struct platform_driver ezxemu_driver = {
+	.probe		= ezx_emu_probe,
+	.remove		= ezx_emu_remove,
+	.driver		= {
+		.name	= "ezx-emu",
+		.owner	= THIS_MODULE,
+	},
+};
+
+int __init ezx_emu_init(void)
+{
+	return platform_driver_register(&ezxemu_driver);
+}
+
+void ezx_emu_fini(void)
+{
+	return platform_driver_unregister(&ezxemu_driver);
+}
+
+module_init(ezx_emu_init);
+module_exit(ezx_emu_fini);
+
+MODULE_DESCRIPTION("Motorola Enchanced Mini Usb driver");
+MODULE_AUTHOR("Daniel Ribeiro <drwyrm@gmail.com>");
+MODULE_LICENSE("GPL");
Index: linux-2.6.21/arch/arm/mach-pxa/Kconfig
===================================================================
--- linux-2.6.21.orig/arch/arm/mach-pxa/Kconfig	2007-09-07 11:32:26.000000000 -0300
+++ linux-2.6.21/arch/arm/mach-pxa/Kconfig	2007-09-07 15:34:08.000000000 -0300
@@ -108,6 +108,28 @@
 config EZX_PCAP
 	bool "PCAP Support"
 
+config EZX_EMU
+	bool "Motorola Enchanced Mini Usb"
+	depends on EZX_PCAP
+
+if EZX_EMU
+
+choice
+	prompt "Select default EMU mode"
+
+config EZX_EMU_USB
+	bool "USB"
+
+config EZX_EMU_UART
+	bool "UART"
+
+config EZX_EMU_NOTHING
+	bool "nothing"
+
+endchoice
+
+endif
+
 endif
 
 endmenu
Index: linux-2.6.21/arch/arm/mach-pxa/Makefile
===================================================================
--- linux-2.6.21.orig/arch/arm/mach-pxa/Makefile	2007-09-07 11:32:26.000000000 -0300
+++ linux-2.6.21/arch/arm/mach-pxa/Makefile	2007-09-07 15:34:08.000000000 -0300
@@ -26,6 +26,7 @@
 obj-$(CONFIG_PXA_EZX_E6)	+= ezx-e6.o
 obj-$(CONFIG_EZX_BP)		+= ezx-bp.o
 obj-$(CONFIG_EZX_PCAP)		+= ezx-pcap.o
+obj-$(CONFIG_EZX_EMU)		+= ezx-emu.o
 
 # Support for blinky lights
 led-y := leds.o