public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] 24xx Irda update
@ 2006-01-06 14:00 Komal Shah
  2006-01-10  6:18 ` Komal Shah
  0 siblings, 1 reply; 3+ messages in thread
From: Komal Shah @ 2006-01-06 14:00 UTC (permalink / raw)
  To: linux-omap-open-source

[-- Attachment #1: Type: text/plain, Size: 334 bytes --]

Tony,

Attached the updated IrDA patch (integrated workqueue) with 24xx
support.

Signed-off-by: Komal Shah <komal_shah802003@yahoo.com>

---Komal Shah
http://komalshah.blogspot.com/


		
__________________________________________ 
Yahoo! DSL – Something to write home about. 
Just $16.99/mo. or less. 
dsl.yahoo.com 

[-- Attachment #2: 3736203677-irda-update.patch --]
[-- Type: text/plain, Size: 59398 bytes --]

diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 7335ad2..3bd850c 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -36,6 +36,7 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
+#include <asm/arch/irda.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/common.h>
 
@@ -171,10 +172,44 @@ static struct platform_device h2_smc91x_
 	.resource	= h2_smc91x_resources,
 };
 
+#define H2_IRDA_FIRSEL_GPIO_PIN	17
+
+static int h2_transceiver_mode(struct device *dev, int state)
+{
+	if (state & IR_SIRMODE)
+		omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 0);
+	else    /* MIR/FIR */
+		omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 1);
+		
+	return 0;
+}
+
+static struct omap_irda_config h2_irda_data = {
+	.transceiver_cap	= IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+};
+
+static struct resource h2_irda_resources[] = {
+	[0] = {
+		.start	= INT_UART3,
+		.end	= INT_UART3,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+static struct platform_device h2_irda_device = {
+	.name		= "omapirda",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &h2_irda_data,
+	},
+	.num_resources	= ARRAY_SIZE(h2_irda_resources),
+	.resource	= h2_irda_resources,
+};
+
 static struct platform_device *h2_devices[] __initdata = {
 	&h2_nor_device,
 	&h2_nand_device,
 	&h2_smc91x_device,
+	&h2_irda_device,
 };
 
 static void __init h2_init_smc91x(void)
@@ -267,6 +302,15 @@ static void __init h2_init(void)
 	// omap_cfg_reg(U19_ARMIO1);		/* CD */
 	omap_cfg_reg(BALLOUT_V8_ARMIO3);	/* WP */
 
+	/* Irda */
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+	omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A);
+	if (!(omap_request_gpio(H2_IRDA_FIRSEL_GPIO_PIN))) {
+		omap_set_gpio_direction(H2_IRDA_FIRSEL_GPIO_PIN, 0);
+		h2_irda_data.transceiver_mode = h2_transceiver_mode;
+	}
+#endif
+
 	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
 	omap_board_config = h2_config;
 	omap_board_config_size = ARRAY_SIZE(h2_config);
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 2e7527a..1fe7c4b 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/errno.h>
+#include <linux/workqueue.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -34,9 +35,11 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/gpio.h>
+#include <asm/arch/gpioexpander.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
+#include <asm/arch/irda.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/common.h>
 
@@ -193,11 +196,96 @@ static struct platform_device intlat_dev
 	.resource       = intlat_resources,
 };
 
+/* Select between the IrDA and aGPS module
+ */
+static int h3_select_irda(struct device *dev, int state)
+{
+	unsigned char expa;
+	int err = 0;
+
+	if ((err = read_gpio_expa(&expa, 0x26))) {
+		printk(KERN_ERR "Error reading from I/O EXPANDER \n");
+		return err;
+	}
+
+	/* 'P6' enable/disable IRDA_TX and IRDA_RX */
+	if (state & IR_SEL) { /* IrDA */
+		if ((err = write_gpio_expa(expa | 0x40, 0x26))) {
+			printk(KERN_ERR "Error writing to I/O EXPANDER \n");
+			return err;
+		}
+	} else {
+		if ((err = write_gpio_expa(expa & ~0x40, 0x26))) {
+			printk(KERN_ERR "Error writing to I/O EXPANDER \n");
+			return err;
+		}
+	}
+	return err;
+}
+
+static void set_trans_mode(void *data)
+{
+	int *mode = data;
+	unsigned char expa;
+	int err = 0;
+	
+	if ((err = read_gpio_expa(&expa, 0x27)) != 0) {
+		printk(KERN_ERR "Error reading from I/O expander\n");
+	}
+
+	expa &= ~0x03;
+
+	if (*mode & IR_SIRMODE) {
+		expa |= 0x01;
+	} else { /* MIR/FIR */
+		expa |= 0x03;
+	}
+
+	if ((err = write_gpio_expa(expa, 0x27)) != 0) {
+		printk(KERN_ERR "Error writing to I/O expander\n");
+	}
+}
+
+static int h3_transceiver_mode(struct device *dev, int mode)
+{
+	struct omap_irda_config *irda_config = dev->platform_data;
+
+	cancel_delayed_work(irda_config->gpio_expa);
+	PREPARE_WORK(irda_config->gpio_expa, set_trans_mode, &mode);
+	schedule_work(irda_config->gpio_expa);
+
+	return 0;
+}
+
+static struct omap_irda_config h3_irda_data = {
+	.transceiver_cap	= IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+	.transceiver_mode	= h3_transceiver_mode,
+	.select_irda	 	= h3_select_irda,
+};
+
+static struct resource h3_irda_resources[] = {
+	[0] = {
+		.start	= INT_UART3,
+		.end	= INT_UART3,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+static struct platform_device h3_irda_device = {
+	.name		= "omapirda",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &h3_irda_data,
+	},
+	.num_resources	= ARRAY_SIZE(h3_irda_resources),
+	.resource	= h3_irda_resources,
+};
+
 static struct platform_device *devices[] __initdata = {
 	&nor_device,
 	&nand_device,
         &smc91x_device,
 	&intlat_device,
+	&h3_irda_device,
 };
 
 static struct omap_usb_config h3_usb_config __initdata = {
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 19b498d..6f5e7ec 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -17,6 +17,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
+#include <linux/workqueue.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -25,8 +26,10 @@
 #include <asm/mach/flash.h>
 
 #include <asm/arch/gpio.h>
+#include <asm/arch/gpioexpander.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/usb.h>
+#include <asm/arch/irda.h>
 #include <asm/arch/board.h>
 #include <asm/arch/common.h>
 #include "prcm-regs.h"
@@ -108,9 +111,93 @@ static struct platform_device h4_smc91x_
 	.resource	= h4_smc91x_resources,
 };
 
+/* Select between the IrDA and aGPS module
+ */
+static int h4_select_irda(struct device *dev, int state)
+{
+	unsigned char expa;
+	int err = 0;
+
+	if ((err = read_gpio_expa(&expa, 0x21))) {
+		printk(KERN_ERR "Error reading from I/O expander\n");
+		return err;
+	}
+
+	/* 'P6' enable/disable IRDA_TX and IRDA_RX */
+	if (state & IR_SEL) {	/* IrDa */
+		if ((err = write_gpio_expa(expa | 0x01, 0x21))) {
+			printk(KERN_ERR "Error writing to I/O expander\n");
+			return err;
+		}
+	} else {		
+		if ((err = write_gpio_expa(expa & ~0x01, 0x21))) {
+			printk(KERN_ERR "Error writing to I/O expander\n");
+			return err;
+		}
+	}
+	return err;
+}
+
+static void set_trans_mode(void *data)
+{
+	int *mode = data;
+	unsigned char expa;
+	int err = 0;
+    
+	if ((err = read_gpio_expa(&expa, 0x20)) != 0) {
+		printk(KERN_ERR "Error reading from I/O expander\n");
+	}
+
+	expa &= ~0x01;
+
+	if (!(*mode & IR_SIRMODE)) { /* MIR/FIR */
+		expa |= 0x01;
+	}
+
+	if ((err = write_gpio_expa(expa, 0x20)) != 0) {
+		printk(KERN_ERR "Error writing to I/O expander\n");
+	}
+}
+
+static int h4_transceiver_mode(struct device *dev, int mode)
+{
+	struct omap_irda_config *irda_config = dev->platform_data;
+
+	cancel_delayed_work(&irda_config->gpio_expa);
+	PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode);
+	schedule_work(&irda_config->gpio_expa);
+
+	return 0;
+}
+
+static struct omap_irda_config h4_irda_data = {
+	.transceiver_cap	= IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
+	.transceiver_mode	= h4_transceiver_mode,
+	.select_irda	 	= h4_select_irda,
+};
+
+static struct resource h4_irda_resources[] = {
+	[0] = {
+		.start	= INT_24XX_UART3_IRQ,
+		.end	= INT_24XX_UART3_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device h4_irda_device = {
+	.name		= "omapirda",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &h4_irda_data,
+	},
+	.num_resources	= 1,
+	.resource	= h4_irda_resources,
+};
+
 static struct platform_device *h4_devices[] __initdata = {
 	&h4_smc91x_device,
 	&h4_flash_device,
+	&h4_irda_device,
 };
 
 static inline void __init h4_init_smc91x(void)
@@ -174,6 +261,10 @@ static void __init omap_h4_init(void)
 	 * You have to mux them off in device drivers later on
 	 * if not needed.
 	 */
+#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE)
+	omap_cfg_reg(K15_24XX_UART3_TX);
+	omap_cfg_reg(K14_24XX_UART3_RX);
+#endif
 	platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
 	omap_board_config = h4_config;
 	omap_board_config_size = ARRAY_SIZE(h4_config);
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index ea46548..9e6b79f 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -54,6 +54,10 @@ MUX_CFG_24XX("W19_24XX_SYS_NIRQ",	0x12c,
 MUX_CFG_24XX("Y20_24XX_GPIO60",		0x12c,	3,	0,	0,	1)
 MUX_CFG_24XX("M15_24XX_GPIO92",		0x10a,	3,	0,	0,	1)
 
+/* UART3  */
+MUX_CFG_24XX("K15_24XX_UART3_TX",	0x118,	0,	0,	0,	1)
+MUX_CFG_24XX("K14_24XX_UART3_RX",	0x119,	0,	0,	0,	1)
+
 };
 
 int __init omap2_mux_init(void)
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index b200c50..b4562c2 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -341,12 +341,12 @@ config TOSHIBA_FIR
 	  To compile it as a module, choose M here: the module will be called
 	  donauboe.
 
-config OMAP1610_IR
-        tristate "OMAP1610 IrDA(SIR/MIR/FIR)"
-	depends on IRDA && ARCH_OMAP
-	select GPIOEXPANDER_OMAP if MACH_OMAP_H3
+config OMAP_IR
+        tristate "OMAP IrDA(SIR/MIR/FIR)"
+	depends on IRDA && (ARCH_OMAP1 || ARCH_OMAP2)
+	select GPIOEXPANDER_OMAP if (MACH_OMAP_H3 || MACH_OMAP_H4)
         help
-          Say Y here if you want to build support for the Omap1610 IR.
+          Say Y here if you want to build support for the OMAP IR.
 
 config AU1000_FIR
 	tristate "Alchemy Au1000 SIR/FIR"
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 7db79a2..494b0f8 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -43,7 +43,7 @@ obj-$(CONFIG_OLD_BELKIN_DONGLE)	+= old_b
 obj-$(CONFIG_MCP2120_DONGLE)	+= mcp2120-sir.o
 obj-$(CONFIG_ACT200L_DONGLE)	+= act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)	+= ma600-sir.o
-obj-$(CONFIG_OMAP1610_IR)       += omap1610-ir.o
+obj-$(CONFIG_OMAP_IR)		+= omap-ir.o
 
 
 # The SIR helper module
diff --git a/drivers/net/irda/omap-ir.c b/drivers/net/irda/omap-ir.c
new file mode 100644
index 0000000..99071cb
--- /dev/null
+++ b/drivers/net/irda/omap-ir.c
@@ -0,0 +1,1022 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ *	Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 Platforms
+ *          (SIR/MIR/FIR modes)
+ *          (based on omap-sir.c)
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *	   source@mvista.com
+ * 
+ * Copyright 2004 Texas Instruments.
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ Modifications:
+ Feb 2004, Texas Instruments
+ - Ported to 2.6 kernel (Feb 2004).
+ *
+ Apr 2004, Texas Instruments
+ - Added support for H3 (Apr 2004). 
+ Nov 2004, Texas Instruments
+ - Added support for Power Management.
+ 
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/serial.h>
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/irda.h>
+
+#define UART3_EFR_EN			(1 << 4)
+#define UART3_MCR_EN_TCR_TLR 		(1 << 6)
+
+#define UART3_LCR_WL_8			(3 << 0)
+#define UART3_LCR_SP2			(1 << 2)
+#define UART3_LCR_DIVEN			(1 << 7)
+
+#define UART3_FCR_FIFO_EN		(1 << 0)
+#define UART3_FCR_FIFO_RX		(1 << 1)
+#define UART3_FCR_FIFO_TX		(1 << 2)
+#define UART3_FCR_FIFO_DMA1		(1 << 3)
+#define UART3_FCR_FIFO_TX_TRIG16	(1 << 4)
+#define UART3_FCR_FIFO_RX_TRIG16	(1 << 6)
+#define UART3_FCR_CONFIG	UART3_FCR_FIFO_EN | UART3_FCR_FIFO_RX |	\
+				UART3_FCR_FIFO_TX | UART3_FCR_FIFO_DMA1 | \
+				UART3_FCR_FIFO_TX_TRIG16 | \
+				UART3_FCR_FIFO_RX_TRIG16 
+
+#define UART3_SCR_TX_TRIG1		(1 << 6)
+#define UART3_SCR_RX_TRIG1		(1 << 7)
+
+#define UART3_MDR1_RESET 		(0x07)
+#define UART3_MDR1_SIR			(1 << 0)
+#define UART3_MDR1_MIR			(4 << 0)
+#define UART3_MDR1_FIR			(5 << 0)
+#define UART3_MDR1_SIP_AUTO		(1 << 6)
+
+#define UART3_MDR2_TRIG1		(0 << 1)
+#define UART3_MDR2_IRTX_UNDERRUN	(1 << 0)
+				
+#define UART3_ACERG_TX_UNDERRUN_DIS	(1 << 4)
+#define UART3_ACERG_SD_MODE_LOW		(1 << 6)
+#define UART3_ACERG_DIS_IR_RX		(1 << 5)
+
+#define UART3_IER_EOF			(1 << 5)
+#define UART3_IER_CTS			(1 << 7)
+
+#define UART3_IIR_TX_STATUS		(1 << 5)
+#define UART3_IIR_EOF			(0x80)
+
+#define IS_FIR(si)		((si)->speed >= 4000000)
+#define IRDA_FRAME_SIZE_LIMIT	4096
+
+static int rx_state = 0;	/* RX state for IOCTL */
+
+struct omap_irda {
+	unsigned char open;
+	int speed;		/* Current IrDA speed */
+	int newspeed;
+
+	struct net_device_stats stats;
+	struct irlap_cb *irlap;
+	struct qos_info qos;
+
+	int rx_dma_channel;
+	int tx_dma_channel;
+
+	dma_addr_t rx_buf_dma_phys;	/* Physical adress of RX DMA buffer */
+	dma_addr_t tx_buf_dma_phys;	/* Physical adress of TX DMA buffer */
+
+	void *rx_buf_dma_virt;	/* Virtual adress of RX DMA buffer */
+	void *tx_buf_dma_virt;	/* Virtual adress of TX DMA buffer */
+
+	struct device *dev;
+	struct omap_irda_config *pdata;
+};
+
+#define OMAP_IRDA_DEBUG	0
+
+#if (OMAP_IRDA_DEBUG > 0)
+#define DBG(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args);
+#define DBG_IRQ(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args);
+#else
+#define DBG(format, args...)
+#define DBG_IRQ(format, args...)
+#endif
+
+#if (OMAP_IRDA_DEBUG > 1)
+#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__);
+#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__);
+#else
+#define __ECHO_IN
+#define __ECHO_OUT
+#endif
+
+#ifdef OMAP1610_IR_HARDWARE_DEBUG_ENABLE
+#define HDBG_DELAY 200
+
+void hard_debug1(u16 i)
+{
+	for (; i; i--) {
+		omap_writew(0x2000,
+			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_CLEAR_DATAOUT);
+		udelay(HDBG_DELAY);
+
+		omap_writew(0x2000,
+			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_SET_DATAOUT);
+		udelay(HDBG_DELAY);
+	}
+}
+
+void hard_debug2(u16 i)
+{
+	for (; i; i--) {
+		omap_writew(0x8000,
+			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_CLEAR_DATAOUT);
+		udelay(HDBG_DELAY);
+
+		omap_writew(0x8000,
+			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_SET_DATAOUT);
+		udelay(HDBG_DELAY);
+	}
+}
+
+#define HDBG1(i) hard_debug1(i)
+#define HDBG2(i) hard_debug2(i)
+#else
+#define HDBG1(i)
+#define HDBG2(i)
+#endif
+
+static void inline uart_reg_out(int idx, u8 val)
+{
+	omap_writeb(val, idx);
+}
+
+static u8 inline uart_reg_in(int idx)
+{
+	u8 b = omap_readb(idx);
+	return b;
+}
+
+/* forward declarations */
+extern void irda_device_setup(struct net_device *dev);
+extern void omap_stop_dma(int lch);
+static int omap_irda_set_speed(struct net_device *dev, int speed);
+
+static void omap_irda_start_rx_dma(struct omap_irda *si)
+{
+	/* default for h2/h3 */
+	unsigned long src_start = 0xfffb9800;
+	unsigned int trigger = 0;	
+
+	if (machine_is_omap_h2() || machine_is_omap_h3()) {
+		src_start = UART3_RHR;
+		trigger = 0;
+	}
+	if (machine_is_omap_h4()) {
+		src_start = OMAP_UART3_BASE;
+		trigger = OMAP24XX_DMA_UART3_RX;
+	}
+	    
+	/* Configure DMA */
+    	omap_set_dma_src_params(si->rx_dma_channel, 0x3, 0x0, src_start,
+				0, 0);
+
+	omap_enable_dma_irq(si->rx_dma_channel, 0x01);
+
+	omap_set_dma_dest_params(si->rx_dma_channel, 0x0, 0x1,
+				 si->rx_buf_dma_phys,
+				 0, 0);
+
+	omap_set_dma_transfer_params(si->rx_dma_channel, 0x0,
+				     IRDA_FRAME_SIZE_LIMIT, 0x1,
+				     0x0, trigger, 0);
+
+	omap_start_dma(si->rx_dma_channel);
+}
+
+static void omap_start_tx_dma(struct omap_irda *si, int size)
+{
+	/* default for h2/h3 */
+	unsigned long dest_start = 0xfffb9800;
+	unsigned int trigger = 0;	
+
+	if (machine_is_omap_h2() || machine_is_omap_h3()) {
+		dest_start = UART3_THR;
+		trigger = 0;
+	}
+	if (machine_is_omap_h4()) {
+		dest_start = OMAP_UART3_BASE;
+		trigger = OMAP24XX_DMA_UART3_TX;
+	}
+
+	__ECHO_IN;
+	/* Configure DMA */
+	omap_set_dma_dest_params(si->tx_dma_channel, 0x03, 0x0,
+				 dest_start, 0, 0);
+	omap_enable_dma_irq(si->tx_dma_channel, 0x01);
+
+	omap_set_dma_src_params(si->tx_dma_channel, 0x0, 0x1,
+				si->tx_buf_dma_phys,
+				0, 0);
+
+	omap_set_dma_transfer_params(si->tx_dma_channel, 0x0, size, 0x1,
+				     0x0, trigger, 0);
+
+	HDBG1(1);
+
+	/* Start DMA */
+	omap_start_dma(si->tx_dma_channel);
+
+	HDBG1(1);
+
+	__ECHO_OUT;
+}
+
+/* DMA RX callback - normally, we should not go here, 
+   it calls only if something is going wrong
+ */
+static void omap_irda_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct net_device *dev = data;
+	struct omap_irda *si = dev->priv;
+
+	printk(KERN_ERR "RX Transfer error or very big frame\n");
+
+	/* Clear interrupts */
+	uart_reg_in(UART3_IIR);
+
+	si->stats.rx_frame_errors++;
+
+	uart_reg_in(UART3_RESUME);
+
+	/* Re-init RX DMA */
+	omap_irda_start_rx_dma(si);
+
+}
+
+/* DMA TX callback - calling when frame transfer has been finished */
+
+static void omap_irda_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct net_device *dev = data;
+	struct omap_irda *si = dev->priv;
+
+	__ECHO_IN;
+
+	/*Stop DMA controller */
+	omap_stop_dma(si->tx_dma_channel);
+
+	__ECHO_OUT;
+
+}
+
+/*
+ * Set the IrDA communications speed.
+ * Interrupt have to be disabled here.
+ */
+
+static int omap_irda_startup(struct net_device *dev)
+{
+	struct omap_irda *si = dev->priv;
+	__ECHO_IN;
+
+	
+	/* FIXME: use clk_* apis for UART3 clock*/
+	/* Enable UART3 clock and set UART3 to IrDA mode */
+	if (machine_is_omap_h2() || machine_is_omap_h3())
+		omap_writel(omap_readl(MOD_CONF_CTRL_0) | (1 << 31) | (1 << 15),
+			    MOD_CONF_CTRL_0);
+	
+	/* Only for H2?
+	 */
+	if (si->pdata->transceiver_mode && machine_is_omap_h2()) {
+	    	/* Is it select_irda on H2 ? */
+		omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7,
+		       FUNC_MUX_CTRL_A);
+		si->pdata->transceiver_mode(si->dev, IR_SIRMODE);
+	}
+
+	uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);	/* Reset mode */
+
+	/* Clear DLH and DLL */
+	uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+	uart_reg_out(UART3_DLL, 0);
+	uart_reg_out(UART3_DLH, 0);
+	uart_reg_out(UART3_LCR, 0xbf);	/* FIXME: Add #define */
+
+	uart_reg_out(UART3_EFR, UART3_EFR_EN);
+	uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+	/* Enable access to UART3_TLR and UART3_TCR registers */
+	uart_reg_out(UART3_MCR, UART3_MCR_EN_TCR_TLR);
+
+	uart_reg_out(UART3_SCR, 0);
+	/* Set Rx trigger to 1 and Tx trigger to 1 */
+	uart_reg_out(UART3_TLR, 0);
+
+	/* Set LCR to 8 bits and 1 stop bit */
+	uart_reg_out(UART3_LCR, 0x03);
+
+	/* Clear RX and TX FIFO and enable FIFO */
+	/* Use DMA Req for transfers */
+	uart_reg_out(UART3_FCR, UART3_FCR_CONFIG);
+
+	uart_reg_out(UART3_MCR, 0);
+
+	uart_reg_out(UART3_SCR, UART3_SCR_TX_TRIG1 |
+		     UART3_SCR_RX_TRIG1);
+
+	/* Enable UART3 SIR Mode,(Frame-length method to end frames) */
+	uart_reg_out(UART3_MDR1, UART3_MDR1_SIR);
+
+	/* Set Status FIFO trig to 1 */
+	uart_reg_out(UART3_MDR2, 0);
+
+	/* Enables RXIR input */
+	/* and disable TX underrun */
+	/* SEND_SIP pulse */
+	uart_reg_out(UART3_ACREG, UART3_ACERG_SD_MODE_LOW |
+		     UART3_ACERG_TX_UNDERRUN_DIS);
+
+	/* Enable EOF Interrupt only */
+	uart_reg_out(UART3_IER, UART3_IER_CTS | UART3_IER_EOF);
+
+	/* Set Maximum Received Frame size to 2048 bytes */
+	uart_reg_out(UART3_RXFLL, 0x00);
+	uart_reg_out(UART3_RXFLH, 0x08);
+
+	uart_reg_in(UART3_RESUME);
+
+	__ECHO_OUT;
+
+	return 0;
+
+}
+
+static int omap_irda_shutdown(struct omap_irda *si)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	/* Disable all UART3 Interrupts */
+	uart_reg_out(UART3_IER, 0);
+
+	/* Disable UART3 and disable baud rate generator */
+	uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);
+
+	/* set SD_MODE pin to high and Disable RX IR */
+	uart_reg_out(UART3_ACREG, (UART3_ACERG_DIS_IR_RX |
+		     ~(UART3_ACERG_SD_MODE_LOW)));
+
+	/* Clear DLH and DLL */
+	uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+	uart_reg_out(UART3_DLL, 0);
+	uart_reg_out(UART3_DLH, 0);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static irqreturn_t
+omap_irda_irq(int irq, void *dev_id, struct pt_regs *hw_regs)
+{
+	struct net_device *dev = dev_id;
+	struct omap_irda *si = dev->priv;
+	struct sk_buff *skb;
+
+	u8 status;
+	int w = 0;
+
+	__ECHO_IN;
+
+	/* Clear EOF interrupt */
+	status = uart_reg_in(UART3_IIR);
+
+	if (status & UART3_IIR_TX_STATUS) {
+		u8 mdr2 = uart_reg_in(UART3_MDR2);
+		HDBG1(2);
+		if (mdr2 & UART3_MDR2_IRTX_UNDERRUN)
+			printk(KERN_ERR "IrDA Buffer underrun error\n");
+
+		si->stats.tx_packets++;
+
+		if (si->newspeed) {
+			omap_irda_set_speed(dev, si->newspeed);
+			si->newspeed = 0;
+		}
+
+		netif_wake_queue(dev);
+		if (!(status & UART3_IIR_EOF))
+			return IRQ_HANDLED;
+	}
+
+	/* Stop DMA and if there are no errors, send frame to upper layer */
+	omap_stop_dma(si->rx_dma_channel);
+
+	status = uart_reg_in(UART3_SFLSR);	/* Take a frame status */
+
+	if (status != 0) {	/* Bad frame? */
+		si->stats.rx_frame_errors++;
+		uart_reg_in(UART3_RESUME);
+	} else {
+		/* We got a frame! */
+		skb = alloc_skb(IRDA_FRAME_SIZE_LIMIT, GFP_ATOMIC);
+
+		if (!skb) {
+			printk(KERN_ERR "omap_sir: out of memory for RX SKB\n");
+			return IRQ_HANDLED;
+		}
+		/*
+		 * Align any IP headers that may be contained
+		 * within the frame.
+		 */
+
+		skb_reserve(skb, 1);
+
+		w = OMAP_DMA_CDAC_REG(si->rx_dma_channel);
+
+		if (cpu_is_omap16xx())
+			w -= OMAP1_DMA_CDSA_L_REG(si->rx_dma_channel);
+		if (cpu_is_omap24xx())
+			w -= OMAP2_DMA_CDSA_REG(si->rx_dma_channel);
+
+		if (!IS_FIR(si)) {
+			/* Copy DMA buffer to skb */
+			memcpy(skb_put(skb, w - 2), si->rx_buf_dma_virt, w - 2);
+		} else {  		
+			/* Copy DMA buffer to skb */
+			memcpy(skb_put(skb, w - 4), si->rx_buf_dma_virt, w - 4);
+		}
+
+		skb->dev = dev;
+		skb->mac.raw = skb->data;
+		skb->protocol = htons(ETH_P_IRDA);
+		si->stats.rx_packets++;
+		si->stats.rx_bytes += skb->len;
+		netif_receive_skb(skb);	/* Send data to upper level */
+	}
+
+	/* Re-init RX DMA */
+	omap_irda_start_rx_dma(si);
+
+	dev->last_rx = jiffies;
+
+	__ECHO_OUT;
+
+	return IRQ_HANDLED;
+}
+
+static int omap_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct omap_irda *si = dev->priv;
+	int speed = irda_get_next_speed(skb);
+	int mtt = irda_get_mtt(skb);
+	int xbofs = irda_get_next_xbofs(skb);
+
+	__ECHO_IN;
+
+	/*
+	 * Does this packet contain a request to change the interface
+	 * speed?  If so, remember it until we complete the transmission
+	 * of this frame.
+	 */
+	if (speed != si->speed && speed != -1)
+		si->newspeed = speed;
+
+	if (xbofs) {
+		/* Set number of addtional BOFS */
+		uart_reg_out(UART3_EBLR, xbofs + 1);
+	}
+	
+	/*
+	 * If this is an empty frame, we can bypass a lot.
+	 */
+	if (skb->len == 0) {
+		if (si->newspeed) {
+			si->newspeed = 0;
+			omap_irda_set_speed(dev, speed);
+		}
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	netif_stop_queue(dev);
+
+	/* Copy skb data to DMA buffer */
+	memcpy(si->tx_buf_dma_virt, skb->data, skb->len);
+
+	/* Copy skb data to DMA buffer */
+	si->stats.tx_bytes += skb->len;
+
+	/* Set frame length */
+	uart_reg_out(UART3_TXFLL, (skb->len & 0xff));
+	uart_reg_out(UART3_TXFLH, (skb->len >> 8));
+
+	if (mtt > 1000)
+		mdelay(mtt / 1000);
+	else
+		udelay(mtt);
+
+	/* Start TX DMA transfer */
+	omap_start_tx_dma(si, skb->len);
+
+	/* We can free skb now because it's already in DMA buffer */
+	dev_kfree_skb(skb);
+
+	dev->trans_start = jiffies;
+
+	__ECHO_OUT;
+
+	return 0;
+}
+
+static int
+omap_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+	struct omap_irda *si = dev->priv;
+	int ret = -EOPNOTSUPP;
+
+	__ECHO_IN;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH:
+		if (capable(CAP_NET_ADMIN)) {
+			/*
+			 * We are unable to set the speed if the
+			 * device is not running.
+			 */
+			if (si->open) {
+				ret =
+				    omap_irda_set_speed(dev, rq->ifr_baudrate);
+			} else {
+				printk(KERN_ERR "omap_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
+				ret = 0;
+			}
+		}
+		break;
+
+	case SIOCSMEDIABUSY:
+		ret = -EPERM;
+		if (capable(CAP_NET_ADMIN)) {
+			irda_device_set_media_busy(dev, TRUE);
+			ret = 0;
+		}
+		break;
+
+	case SIOCGRECEIVING:
+		rq->ifr_receiving = rx_state;
+		break;
+
+	default:
+		break;
+	}
+
+	__ECHO_OUT;
+
+	return ret;
+}
+
+static struct net_device_stats *omap_irda_stats(struct net_device *dev)
+{
+	struct omap_irda *si = dev->priv;
+	return &si->stats;
+}
+
+static int omap_irda_start(struct net_device *dev)
+{
+	struct omap_irda *si = dev->priv;
+	int err;
+	int rx_channel = OMAP_DMA_NO_DEVICE;
+	int tx_channel = OMAP_DMA_NO_DEVICE;
+
+	__ECHO_IN;
+	si->speed = 9600;
+
+	err = request_irq(dev->irq, omap_irda_irq, 0, dev->name, dev);
+	if (err)
+		goto err_irq;
+
+	/*
+	 * The interrupt must remain disabled for now.
+	 */
+	disable_irq(dev->irq);
+	
+	/* FIXME: These info can come from board-* files, if no one
+	 * objects
+	 */
+	if (machine_is_omap_h2() || machine_is_omap_h3()) {
+		rx_channel = OMAP_DMA_UART3_RX;
+		tx_channel = OMAP_DMA_UART3_TX;
+	}
+	if (machine_is_omap_h4()) {
+		rx_channel = OMAP24XX_DMA_UART3_RX;
+		tx_channel = OMAP24XX_DMA_UART3_TX;
+	}
+
+	/*  Request DMA channels for IrDA hardware */
+	if (omap_request_dma(rx_channel, "IrDA Rx DMA",
+			     (void *)omap_irda_rx_dma_callback,
+			     dev, &(si->rx_dma_channel))) {
+		printk(KERN_ERR "Failed to request IrDA Rx DMA\n");
+		goto err_irq;
+	}
+
+	if (omap_request_dma(tx_channel, "IrDA Tx DMA",
+			     (void *)omap_irda_tx_dma_callback,
+			     dev, &(si->tx_dma_channel))) {
+		printk(KERN_ERR "Failed to request IrDA Tx DMA\n");
+		goto err_irq;
+	}
+
+	/* Allocate TX and RX buffers for DMA channels */
+	si->rx_buf_dma_virt =
+	    dma_alloc_coherent(NULL, IRDA_FRAME_SIZE_LIMIT, &(si->rx_buf_dma_phys),
+			       GFP_KERNEL);
+
+	si->tx_buf_dma_virt =
+	    dma_alloc_coherent(NULL, IRDA_FRAME_SIZE_LIMIT, &(si->tx_buf_dma_phys),
+			       GFP_KERNEL);
+
+	/*
+	 * Setup the serial port for the specified config.
+	 */
+	if (si->pdata->select_irda)
+		si->pdata->select_irda(si->dev, IR_SEL);
+	
+	err = omap_irda_startup(dev);
+
+	if (err)
+		goto err_startup;
+
+	omap_irda_set_speed(dev, si->speed = 9600);
+
+	/*
+	 * Open a new IrLAP layer instance.
+	 */
+	si->irlap = irlap_open(dev, &si->qos, "omap_sir");
+
+	err = -ENOMEM;
+	if (!si->irlap)
+		goto err_irlap;
+
+	/* Now enable the interrupt and start the queue  */
+	si->open = 1;
+
+	/* Start RX DMA */
+	omap_irda_start_rx_dma(si);
+
+	enable_irq(dev->irq);
+	netif_start_queue(dev);
+
+	__ECHO_OUT;
+
+	return 0;
+
+err_irlap:
+	si->open = 0;
+	omap_irda_shutdown(si);
+err_startup:
+err_irq:
+	free_irq(dev->irq, dev);
+	return err;
+}
+
+static int omap_irda_stop(struct net_device *dev)
+{
+	struct omap_irda *si = dev->priv;
+
+	__ECHO_IN;
+
+	disable_irq(dev->irq);
+
+	netif_stop_queue(dev);
+
+	omap_free_dma(si->rx_dma_channel);
+	omap_free_dma(si->tx_dma_channel);
+
+	if (si->rx_buf_dma_virt)
+		dma_free_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+				  si->rx_buf_dma_virt, si->rx_buf_dma_phys);
+	if (si->tx_buf_dma_virt)
+		dma_free_coherent(NULL, IRDA_FRAME_SIZE_LIMIT,
+				  si->tx_buf_dma_virt, si->tx_buf_dma_phys);
+
+	omap_irda_shutdown(si);
+
+	/* Stop IrLAP */
+	if (si->irlap) {
+		irlap_close(si->irlap);
+		si->irlap = NULL;
+	}
+
+	si->open = 0;
+
+	/*
+	 * Free resources
+	 */
+	free_irq(dev->irq, dev);
+
+	__ECHO_OUT;
+
+	return 0;
+}
+
+static int omap_irda_set_speed(struct net_device *dev, int speed)
+{
+	struct omap_irda *si = dev->priv;
+	int divisor;
+	unsigned long flags;
+
+	__ECHO_IN;
+
+	/* Set IrDA speed */
+	if (speed <= 115200) {
+
+		local_irq_save(flags);
+	    
+		/* SIR mode */
+		if (si->pdata->transceiver_mode)
+			si->pdata->transceiver_mode(si->dev, IR_SIRMODE);
+
+		/* Set SIR mode */
+		uart_reg_out(UART3_MDR1, 1);
+		uart_reg_out(UART3_EBLR, 1);
+
+		divisor = 48000000 / (16 * speed);	/* Base clock 48 MHz */
+
+		HDBG2(1);
+
+		uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+		uart_reg_out(UART3_DLL, (divisor & 0xff));
+		uart_reg_out(UART3_DLH, (divisor >> 8));
+		uart_reg_out(UART3_LCR, 0x03);
+
+		uart_reg_out(UART3_MCR, 0);
+
+		HDBG2(1);
+		
+		local_irq_restore(flags);
+
+	} else if (speed <= 1152000) {
+	
+		local_irq_save(flags);
+			    
+		/* Set MIR mode, auto SIP */
+		uart_reg_out(UART3_MDR1, UART3_MDR1_MIR |
+			     UART3_MDR1_SIP_AUTO);	
+
+		uart_reg_out(UART3_EBLR, 2);
+
+		divisor = 48000000 / (41 * speed);	/* Base clock 48 MHz */
+
+		uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+		uart_reg_out(UART3_DLL, (divisor & 0xff));
+		uart_reg_out(UART3_DLH, (divisor >> 8));
+		uart_reg_out(UART3_LCR, 0x03);
+
+		if (si->pdata->transceiver_mode)
+			si->pdata->transceiver_mode(si->dev, IR_MIRMODE);
+
+		local_irq_restore(flags);
+
+	} else {
+		local_irq_save(flags);
+		 		
+		/* FIR mode */
+		uart_reg_out(UART3_MDR1, UART3_MDR1_FIR |
+			     UART3_MDR1_SIP_AUTO);	
+
+		if (si->pdata->transceiver_mode)
+			si->pdata->transceiver_mode(si->dev, IR_FIRMODE);
+
+		local_irq_restore(flags);
+	}
+
+	si->speed = speed;
+
+	__ECHO_OUT;
+
+	return 0;
+
+}
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int omap_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct omap_irda *si = dev->priv;
+
+	if (!dev)
+		return 0;
+
+	if (si->open) {
+		/*
+		 * Stop the transmit queue
+		 */
+		netif_device_detach(dev);
+		disable_irq(dev->irq);
+		omap_irda_shutdown(si);
+	}
+	return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int omap_irda_resume(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+	struct omap_irda *si= dev->priv;
+
+	if (!dev)
+		return 0;
+
+	if (si->open) {
+		/*
+		 * If we missed a speed change, initialise at the new speed
+		 * directly.  It is debatable whether this is actually
+		 * required, but in the interests of continuing from where
+		 * we left off it is desireable.  The converse argument is
+		 * that we should re-negotiate at 9600 baud again.
+		 */
+		if (si->newspeed) {
+			si->speed = si->newspeed;
+			si->newspeed = 0;
+		}
+
+		omap_irda_startup(dev);
+		omap_irda_set_speed(dev, si->speed);
+		enable_irq(dev->irq);
+
+		/*
+		 * This automatically wakes up the queue
+		 */
+		netif_device_attach(dev);
+	}
+
+	return 0;
+}
+#else
+#define omap_irda_suspend	NULL
+#define omap_irda_resume	NULL
+#endif
+
+static int omap_irda_probe(struct platform_device *pdev)
+{
+	struct net_device *dev;
+	struct omap_irda *si;
+	unsigned int baudrate_mask;
+	int err = 0;
+	int irq = NO_IRQ;
+
+	if (!pdev->dev.platform_data) {
+		printk(KERN_ERR "IrDA Platform data not supplied\n");
+		return -ENOENT;
+	}
+
+	dev = alloc_irdadev(sizeof(struct omap_irda));
+	if (!dev)
+		goto err_mem_1;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0) {
+		printk(KERN_WARNING "no irq for IrDA\n");
+		return -ENOENT;
+	}
+
+	si = dev->priv;
+	si->dev = &pdev->dev;
+	si->pdata = pdev->dev.platform_data;
+
+	dev->hard_start_xmit	= omap_irda_hard_xmit;
+	dev->open		= omap_irda_start;
+	dev->stop		= omap_irda_stop;
+	dev->do_ioctl		= omap_irda_ioctl;
+	dev->get_stats		= omap_irda_stats;
+	dev->irq		= irq;
+
+	irda_init_max_qos_capabilies(&si->qos);
+
+	baudrate_mask = 0;
+	if (si->pdata->transceiver_cap & IR_SIRMODE)
+		baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	if (si->pdata->transceiver_cap & IR_MIRMODE)
+		baudrate_mask |= IR_57600 | IR_1152000;
+	if (si->pdata->transceiver_cap & IR_FIRMODE)
+		baudrate_mask |= IR_4000000 << 8;
+
+	si->qos.baud_rate.bits &= baudrate_mask;
+	si->qos.min_turn_time.bits = 7;
+
+	irda_qos_bits_to_value(&si->qos);
+
+	/* Any better way to avoid this? No. */
+	if (machine_is_omap_h3() || machine_is_omap_h4()) {
+		INIT_WORK(&si->pdata->gpio_expa, NULL, NULL);
+	}
+
+	err = register_netdev(dev);
+	if (!err)
+		platform_set_drvdata(pdev, dev);
+	else 
+		free_netdev(dev);
+
+err_mem_1:
+	return err;
+}
+
+static int omap_irda_remove(struct platform_device *pdev)
+{
+	struct net_device *dev = platform_get_drvdata(pdev);
+
+	if (pdev) {
+		unregister_netdev(dev);
+		free_netdev(dev);
+	}
+	return 0;
+}
+
+static struct platform_driver omapir_driver = {
+	.probe		= omap_irda_probe,
+	.remove		= omap_irda_remove,
+	.suspend	= omap_irda_suspend,
+	.resume		= omap_irda_resume,
+	.driver		= {
+		.name	= "omapirda",
+	},
+};
+
+static char __initdata banner[] = "OMAP IrDA driver\n";
+
+static int __init omap_irda_init(void)
+{
+	printk(banner);
+	return platform_driver_register(&omapir_driver);
+}
+
+static void __exit omap_irda_exit(void)
+{
+	platform_driver_unregister(&omapir_driver);
+}
+
+module_init(omap_irda_init);
+module_exit(omap_irda_exit);
+
+MODULE_AUTHOR("MontaVista");
+MODULE_DESCRIPTION("OMAP IrDA Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/net/irda/omap1610-ir.c b/drivers/net/irda/omap1610-ir.c
deleted file mode 100644
index 1fa8e89..0000000
--- a/drivers/net/irda/omap1610-ir.c
+++ /dev/null
@@ -1,997 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *
- *	Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 Platforms
- *          (SIR/MIR/FIR modes)
- *          (based on omap-sir.c)
- *
- * Copyright 2003 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *	   source@mvista.com
- * 
- * Copyright 2004 Texas Instruments.
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
- *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
- *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- Modifications:
- Feb 2004, Texas Instruments
- - Ported to 2.6 kernel (Feb 2004).
- *
- Apr 2004, Texas Instruments
- - Added support for H3 (Apr 2004). 
- Nov 2004, Texas Instruments
- - Added support for Power Management.
- 
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/rtnetlink.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/wrapper.h>
-#include <net/irda/irda_device.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/serial.h>
-#include <asm/mach-types.h>
-#include <asm/dma.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/gpio.h>
-#include <linux/i2c.h>
-
-#ifdef CONFIG_MACH_OMAP_H3
-#include <asm/arch/gpioexpander.h>
-#endif
-
-#define SIR_MODE 0
-#define MIR_MODE 1
-#define FIR_MODE 2
-
-#define OMAP1610_H2_FIRSEL_GPIO 17
-
-static int rx_state = 0;	/* RX state for IOCTL */
-
-struct omap1610_irda {
-	unsigned char open;
-	int speed;		/* Current IrDA speed */
-	int newspeed;
-
-	struct net_device_stats stats;
-	struct irlap_cb *irlap;
-	struct qos_info qos;
-
-	int rx_dma_channel;
-	int tx_dma_channel;
-
-	dma_addr_t rx_buf_dma_phys;	/* Physical adress of RX DMA buffer */
-	dma_addr_t tx_buf_dma_phys;	/* Physical adress of TX DMA buffer */
-
-	void *rx_buf_dma_virt;	/* Virtual adress of RX DMA buffer */
-	void *tx_buf_dma_virt;	/* Virtual adress of TX DMA buffer */
-
-	struct device *dev;
-};
-
-#define OMAP_IRDA_DEBUG	0
-
-#if (OMAP_IRDA_DEBUG > 0)
-#define DBG(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args);
-#define DBG_IRQ(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args);
-#else
-#define DBG(format, args...)
-#define DBG_IRQ(format, args...)
-#endif
-
-#if (OMAP_IRDA_DEBUG > 1)
-#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__);
-#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__);
-#else
-#define __ECHO_IN
-#define __ECHO_OUT
-#endif
-
-#ifdef OMAP1610_IR_HARDWARE_DEBUG_ENABLE
-#define HDBG_DELAY 200
-
-void hard_debug1(u16 i)
-{
-	for (; i; i--) {
-		omap_writew(0x2000,
-			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_CLEAR_DATAOUT);
-		udelay(HDBG_DELAY);
-
-		omap_writew(0x2000,
-			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_SET_DATAOUT);
-		udelay(HDBG_DELAY);
-	}
-}
-
-void hard_debug2(u16 i)
-{
-	for (; i; i--) {
-		omap_writew(0x8000,
-			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_CLEAR_DATAOUT);
-		udelay(HDBG_DELAY);
-
-		omap_writew(0x8000,
-			    OMAP1610_GPIO1_BASE + OMAP1610_GPIO_SET_DATAOUT);
-		udelay(HDBG_DELAY);
-	}
-}
-
-#define HDBG1(i) hard_debug1(i)
-#define HDBG2(i) hard_debug2(i)
-#else
-#define HDBG1(i)
-#define HDBG2(i)
-#endif
-
-/* forward declarations */
-
-extern void irda_device_setup(struct net_device *dev);
-extern void omap_stop_dma(int lch);
-static int omap1610_irda_set_speed(struct net_device *dev, int speed);
-
-static void omap1610_irda_start_rx_dma(struct omap1610_irda *si)
-{
-	/* Configure DMA */
-	omap_set_dma_src_params(si->rx_dma_channel, 0x3, 0x0, (unsigned long)UART3_RHR,
-				0, 0);
-
-	omap_enable_dma_irq(si->rx_dma_channel, 0x01);
-
-	omap_set_dma_dest_params(si->rx_dma_channel, 0x0, 0x1,
-				 si->rx_buf_dma_phys,
-				 0, 0);
-
-	omap_set_dma_transfer_params(si->rx_dma_channel, 0x0, 4096, 0x1, 0x0, 0, 0);
-
-	omap_start_dma(si->rx_dma_channel);
-}
-
-static void omap1610_start_tx_dma(struct omap1610_irda *si, int size)
-{
-	__ECHO_IN;
-
-	/* Configure DMA */
-	omap_set_dma_dest_params(si->tx_dma_channel, 0x03, 0x0, (unsigned long)UART3_THR,
-					0, 0);
-	omap_enable_dma_irq(si->tx_dma_channel, 0x01);
-
-	omap_set_dma_src_params(si->tx_dma_channel, 0x0, 0x1,
-				si->tx_buf_dma_phys,
-				0, 0);
-
-	omap_set_dma_transfer_params(si->tx_dma_channel, 0x0, size, 0x1, 0x0, 0, 0);
-
-	HDBG1(1);
-
-	/* Start DMA */
-	omap_start_dma(si->tx_dma_channel);
-
-	HDBG1(1);
-
-	__ECHO_OUT;
-}
-
-/* DMA RX callback - normally, we should not go here, 
-   it calls only if something is going wrong
- */
-
-static void omap1610_irda_rx_dma_callback(int lch, u16 ch_status, void *data)
-{
-	struct net_device *dev = data;
-	struct omap1610_irda *si = dev->priv;
-
-	printk(KERN_ERR "RX Transfer error or very big frame \n");
-
-	/* Clear interrupts */
-	omap_readb(UART3_IIR);
-
-	si->stats.rx_frame_errors++;
-
-	omap_readb(UART3_RESUME);
-
-	/* Re-init RX DMA */
-	omap1610_irda_start_rx_dma(si);
-
-}
-
-/* DMA TX callback - calling when frame transfer has been finished */
-
-static void omap1610_irda_tx_dma_callback(int lch, u16 ch_status, void *data)
-{
-	struct net_device *dev = data;
-	struct omap1610_irda *si = dev->priv;
-
-	__ECHO_IN;
-
-	/*Stop DMA controller */
-	omap_stop_dma(si->tx_dma_channel);
-
-	__ECHO_OUT;
-
-}
-
-/*
- * Set the IrDA communications speed.
- * Interrupt have to be disabled here.
- */
-
-static int omap1610_irda_startup(struct net_device *dev)
-{
-	__ECHO_IN;
-
-	/* Enable UART3 clock and set UART3 to IrDA mode */
-	omap_writel(omap_readl(MOD_CONF_CTRL_0) | (1 << 31) | (1 << 15),
-		    MOD_CONF_CTRL_0);
-
-	if (machine_is_omap_h2()) {
-//              omap_cfg_reg(Y15_1610_GPIO17);
-		omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A);
-
-		omap_set_gpio_direction(OMAP1610_H2_FIRSEL_GPIO, 0);
-		omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 0);
-	}
-
-	omap_writeb(0x07, UART3_MDR1);	/* Put UART3 in reset mode */
-
-	/* Clear DLH and DLL */
-	omap_writeb(1 << 7, UART3_LCR);
-
-	omap_writeb(0, UART3_DLL);
-	omap_writeb(0, UART3_DLH);
-
-	omap_writeb(0xbf, UART3_LCR);
-
-	omap_writeb(1 << 4, UART3_EFR);
-
-	omap_writeb(1 << 7, UART3_LCR);
-
-	/* Enable access to UART3_TLR and UART3_TCR registers */
-	omap_writeb(1 << 6, UART3_MCR);
-
-	omap_writeb(0, UART3_SCR);
-
-	/* Set Rx trigger to 1 and Tx trigger to 1 */
-	omap_writeb(0, UART3_TLR);
-
-	/* Set LCR to 8 bits and 1 stop bit */
-	omap_writeb(0x03, UART3_LCR);
-
-	/* Clear RX and TX FIFO and enable FIFO */
-	/* Use DMA Req for transfers */
-
-	omap_writeb((1 << 2) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 6) | 1,
-		    UART3_FCR);
-
-	omap_writeb(0, UART3_MCR);
-
-	omap_writeb((1 << 7) | (1 << 6), UART3_SCR);
-
-	/* Enable UART3 SIR Mode,(Frame-length method to end frames) */
-	omap_writeb(1, UART3_MDR1);
-
-	/* Set Status FIFO trig to 1 */
-	omap_writeb(0, UART3_MDR2);
-
-	/* Enables RXIR input */
-	/* and disable TX underrun */
-	/* SEND_SIP pulse */
-
-	//   omap_writeb((1 << 7) | (1 << 6) | (1 << 4), UART3_ACREG);
-	omap_writeb((1 << 6) | (1 << 4), UART3_ACREG);
-
-	/* Enable EOF Interrupt only */
-	omap_writeb((1 << 7) | (1 << 5), UART3_IER);
-
-	/* Set Maximum Received Frame size to 2048 bytes */
-	omap_writeb(0x00, UART3_RXFLL);
-	omap_writeb(0x08, UART3_RXFLH);
-
-	omap_readb(UART3_RESUME);
-
-	__ECHO_OUT;
-
-	return 0;
-
-}
-
-static int omap1610_irda_shutdown(struct omap1610_irda *si)
-{
-	/* Disable all UART3 Interrupts */
-	omap_writeb(0, UART3_IER);
-
-	/* Disable UART3 and disable baud rate generator */
-	omap_writeb(0x07, UART3_MDR1);	/* Put UART3 in reset mode */
-
-	omap_writeb((1 << 5), UART3_ACREG);	/* set SD_MODE pin to high and Disable RX IR */
-
-	/* Clear DLH and DLL */
-	omap_writeb(1 << 7, UART3_LCR);
-	omap_writeb(0, UART3_DLL);
-	omap_writeb(0, UART3_DLH);
-
-	return 0;
-}
-
-static irqreturn_t
-omap1610_irda_irq(int irq, void *dev_id, struct pt_regs *hw_regs)
-{
-	struct net_device *dev = dev_id;
-	struct omap1610_irda *si = dev->priv;
-	struct sk_buff *skb;
-
-	u8 status;
-	int w = 0;
-
-	__ECHO_IN;
-
-	/* Clear EOF interrupt */
-	status = omap_readb(UART3_IIR);
-
-	if (status & (1 << 5)) {
-		u8 mdr2 = omap_readb(UART3_MDR2);
-		HDBG1(2);
-		if (mdr2 & 1)
-			printk(KERN_ERR "IRDA Buffer underrun error");
-
-		si->stats.tx_packets++;
-
-		if (si->newspeed) {
-			omap1610_irda_set_speed(dev, si->newspeed);
-			si->newspeed = 0;
-		}
-
-		netif_wake_queue(dev);
-
-		if (!(status & 0x80))
-			return IRQ_HANDLED;
-	}
-
-	/* Stop DMA and if there are no errors, send frame to upper layer */
-
-	omap_stop_dma(si->rx_dma_channel);
-
-	status = omap_readb(UART3_SFLSR);	/* Take a frame status */
-
-	if (status != 0) {	/* Bad frame? */
-		si->stats.rx_frame_errors++;
-		omap_readb(UART3_RESUME);
-	} else {
-		/* We got a frame! */
-		skb = alloc_skb(4096, GFP_ATOMIC);
-
-		if (!skb) {
-			printk(KERN_ERR "omap_sir: out of memory for RX SKB\n");
-			return IRQ_HANDLED;
-		}
-		/*
-		 * Align any IP headers that may be contained
-		 * within the frame.
-		 */
-
-		skb_reserve(skb, 1);
-
-		w = OMAP_DMA_CDAC_REG(si->rx_dma_channel);
-		w -= OMAP1_DMA_CDSA_L_REG(si->rx_dma_channel);
-
-		if (si->speed != 4000000) {
-			memcpy(skb_put(skb, w - 2), si->rx_buf_dma_virt, w - 2);	/* Copy DMA buffer to skb */
-		} else {
-			memcpy(skb_put(skb, w - 4), si->rx_buf_dma_virt, w - 4);	/* Copy DMA buffer to skb */
-		}
-
-		skb->dev = dev;
-		skb->mac.raw = skb->data;
-		skb->protocol = htons(ETH_P_IRDA);
-		si->stats.rx_packets++;
-		si->stats.rx_bytes += skb->len;
-		netif_receive_skb(skb);	/* Send data to upper level */
-	}
-
-	/* Re-init RX DMA */
-	omap1610_irda_start_rx_dma(si);
-
-	dev->last_rx = jiffies;
-
-	__ECHO_OUT;
-
-	return IRQ_HANDLED;
-}
-
-static int omap1610_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct omap1610_irda *si = dev->priv;
-	int speed = irda_get_next_speed(skb);
-	int mtt = irda_get_mtt(skb);
-	int xbofs = irda_get_next_xbofs(skb);
-
-	__ECHO_IN;
-
-	/*
-	 * Does this packet contain a request to change the interface
-	 * speed?  If so, remember it until we complete the transmission
-	 * of this frame.
-	 */
-	if (speed != si->speed && speed != -1)
-		si->newspeed = speed;
-
-	if (xbofs) {
-		/* Set number of addtional BOFS */
-		omap_writeb(xbofs + 1, UART3_EBLR);
-	}
-
-	/*
-	 * If this is an empty frame, we can bypass a lot.
-	 */
-	if (skb->len == 0) {
-		if (si->newspeed) {
-			si->newspeed = 0;
-			omap1610_irda_set_speed(dev, speed);
-		}
-		dev_kfree_skb(skb);
-		return 0;
-	}
-
-	netif_stop_queue(dev);
-
-	/* Copy skb data to DMA buffer */
-
-	memcpy(si->tx_buf_dma_virt, skb->data, skb->len);
-
-	si->stats.tx_bytes += skb->len;
-
-	/* Set frame length */
-
-	omap_writeb((skb->len & 0xff), UART3_TXFLL);
-	omap_writeb((skb->len >> 8), UART3_TXFLH);
-
-	if (mtt > 1000)
-		mdelay(mtt / 1000);
-	else
-		udelay(mtt);
-
-	/* Start TX DMA transfer */
-
-	omap1610_start_tx_dma(si, skb->len);
-
-	/* We can free skb now because it's already in DMA buffer */
-
-	dev_kfree_skb(skb);
-
-	dev->trans_start = jiffies;
-
-	__ECHO_OUT;
-
-	return 0;
-}
-
-static int
-omap1610_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
-{
-	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
-	struct omap1610_irda *si = dev->priv;
-	int ret = -EOPNOTSUPP;
-
-	__ECHO_IN;
-
-	switch (cmd) {
-	case SIOCSBANDWIDTH:
-		if (capable(CAP_NET_ADMIN)) {
-			/*
-			 * We are unable to set the speed if the
-			 * device is not running.
-			 */
-			if (si->open) {
-				ret =
-				    omap1610_irda_set_speed(dev,
-							    rq->ifr_baudrate);
-			} else {
-				printk
-				    (KERN_ERR
-				     "omap_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
-				ret = 0;
-			}
-		}
-		break;
-
-	case SIOCSMEDIABUSY:
-		ret = -EPERM;
-		if (capable(CAP_NET_ADMIN)) {
-			irda_device_set_media_busy(dev, TRUE);
-			ret = 0;
-		}
-		break;
-
-	case SIOCGRECEIVING:
-		rq->ifr_receiving = rx_state;
-		break;
-
-	default:
-		break;
-	}
-
-	__ECHO_OUT;
-
-	return ret;
-}
-
-static struct net_device_stats *omap1610_irda_stats(struct net_device *dev)
-{
-	struct omap1610_irda *si = dev->priv;
-	return &si->stats;
-}
-
-static int omap1610_irda_start(struct net_device *dev)
-{
-	struct omap1610_irda *si = dev->priv;
-	int err;
-	unsigned long flags = 0;
-
-#ifdef CONFIG_MACH_OMAP_H3
-	u8 ioExpanderVal = 0;
-#endif
-
-	__ECHO_IN;
-	si->speed = 9600;
-
-	err = request_irq(dev->irq, omap1610_irda_irq, 0, dev->name, dev);
-	if (err)
-		goto err_irq;
-
-	/*
-	 * The interrupt must remain disabled for now.
-	 */
-
-	disable_irq(dev->irq);
-
-	/*  Request DMA channels for IrDA hardware */
-
-	if (omap_request_dma(OMAP_DMA_UART3_RX, "IrDA Rx DMA",
-			     (void *)omap1610_irda_rx_dma_callback,
-			     dev, &(si->rx_dma_channel))) {
-		printk(KERN_ERR "Failed to request IrDA Rx DMA \n");
-		goto err_irq;
-	}
-
-	if (omap_request_dma(OMAP_DMA_UART3_TX, "IrDA Tx DMA",
-			     (void *)omap1610_irda_tx_dma_callback,
-			     dev, &(si->tx_dma_channel))) {
-		printk(KERN_ERR "Failed to request IrDA Tx DMA \n");
-		goto err_irq;
-	}
-
-	/* Allocate TX and RX buffers for DMA channels */
-
-	si->rx_buf_dma_virt =
-	    dma_alloc_coherent(NULL, 4096, &(si->rx_buf_dma_phys), flags);
-
-	si->tx_buf_dma_virt =
-	    dma_alloc_coherent(NULL, 4096, &(si->tx_buf_dma_phys), flags);
-
-	/*
-	 * Setup the serial port for the specified config.
-	 */
-
-#ifdef CONFIG_MACH_OMAP_H3
-
-	if ((err = read_gpio_expa(&ioExpanderVal, 0x26))) {
-		printk(KERN_ERR "Error reading from I/O EXPANDER \n");
-		return err;
-	}
-
-	ioExpanderVal |= 0x40;	/* 'P6' Enable IRDA_TX and IRDA_RX */
-
-	if ((err = write_gpio_expa(ioExpanderVal, 0x26))) {
-		printk(KERN_ERR "Error writing to I/O EXPANDER \n");
-		return err;
-	}
-#endif
-	err = omap1610_irda_startup(dev);
-
-	if (err)
-		goto err_startup;
-
-	omap1610_irda_set_speed(dev, si->speed = 9600);
-
-	/*
-	 * Open a new IrLAP layer instance.
-	 */
-
-	si->irlap = irlap_open(dev, &si->qos, "omap_sir");
-
-	err = -ENOMEM;
-	if (!si->irlap)
-		goto err_irlap;
-
-	/* Now enable the interrupt and start the queue  */
-	si->open = 1;
-
-	/* Start RX DMA */
-
-	omap1610_irda_start_rx_dma(si);
-
-	enable_irq(dev->irq);
-	netif_start_queue(dev);
-
-	__ECHO_OUT;
-
-	return 0;
-
-      err_irlap:
-	si->open = 0;
-	omap1610_irda_shutdown(si);
-      err_startup:
-      err_irq:
-	free_irq(dev->irq, dev);
-	return err;
-}
-
-static int omap1610_irda_stop(struct net_device *dev)
-{
-	struct omap1610_irda *si = dev->priv;
-
-	__ECHO_IN;
-
-	disable_irq(dev->irq);
-
-	netif_stop_queue(dev);
-
-	omap_free_dma(si->rx_dma_channel);
-	omap_free_dma(si->tx_dma_channel);
-
-	dma_free_coherent(NULL, 4096, si->rx_buf_dma_virt, si->rx_buf_dma_phys);
-	dma_free_coherent(NULL, 4096, si->tx_buf_dma_virt, si->tx_buf_dma_phys);
-
-	omap1610_irda_shutdown(si);
-
-	/* Stop IrLAP */
-	if (si->irlap) {
-		irlap_close(si->irlap);
-		si->irlap = NULL;
-	}
-
-	si->open = 0;
-
-	/*
-	 * Free resources
-	 */
-
-	free_irq(dev->irq, dev);
-
-	__ECHO_OUT;
-
-	return 0;
-}
-
-#ifdef CONFIG_MACH_OMAP_H3
-
-static void set_h3_gpio_expa(u8 FIR_SEL, u8 IrDA_INVSEL)
-{
-	u8 ioExpanderVal = 0;
-
-	if (read_gpio_expa(&ioExpanderVal, 0x27) != 0) {
-		printk(KERN_ERR "Error reading from I/O EXPANDER \n");
-		return;
-	}
-
-	ioExpanderVal &= ~0x03;
-	ioExpanderVal |= FIR_SEL << 1;
-	ioExpanderVal |= IrDA_INVSEL << 0;
-
-	if (write_gpio_expa(ioExpanderVal, 0x27) != 0) {
-		printk(KERN_ERR "Error writing to I/O EXPANDER \n");
-		return;
-	}
-	if (read_gpio_expa(&ioExpanderVal, 0x27) != 0) {
-		printk(KERN_ERR "Error reading from I/O EXPANDER \n");
-		return;
-	}
-}
-
-int which_speed;
-
-static void set_h3_gpio_expa_handler(void *data)
-{
-	int *mode = data;
-
-	if (*mode == SIR_MODE)
-		set_h3_gpio_expa(0, 1);
-	else if (*mode == MIR_MODE)
-		set_h3_gpio_expa(1, 1);
-	else if (*mode == FIR_MODE)
-		set_h3_gpio_expa(1, 1);
-}
-
-DECLARE_WORK(set_h3_gpio_expa_work, &set_h3_gpio_expa_handler, &which_speed);
-
-static inline void set_h3_irda_mode(int mode)
-{
-	cancel_delayed_work(&set_h3_gpio_expa_work);
-	which_speed = mode;
-	schedule_work(&set_h3_gpio_expa_work);
-}
-#else
-#define set_h3_irda_mode(x)
-#endif
-
-static int omap1610_irda_set_speed(struct net_device *dev, int speed)
-{
-	struct omap1610_irda *si = dev->priv;
-	int divisor;
-
-	__ECHO_IN;
-
-	/* Set IrDA speed */
-	if (speed <= 115200) {
-		/* SIR mode */
-		if (machine_is_omap_h2()) {
-			omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 0);
-		}
-
-		if (machine_is_omap_h3())
-			set_h3_irda_mode(SIR_MODE);
-
-		printk("Set SIR Mode! Speed: %d\n", speed);
-
-		omap_writeb(1, UART3_MDR1);	/* Set SIR mode */
-
-		omap_writeb(1, UART3_EBLR);
-
-		divisor = 48000000 / (16 * speed);	/* Base clock 48 MHz */
-
-		HDBG2(1);
-		omap_writeb(1 << 7, UART3_LCR);
-
-		omap_writeb((divisor & 0xFF), UART3_DLL);
-
-		omap_writeb((divisor >> 8), UART3_DLH);
-
-		omap_writeb(0x03, UART3_LCR);
-
-		omap_writeb(0, UART3_MCR);
-
-		HDBG2(1);
-
-	} else if (speed <= 1152000) {
-		/* MIR mode */
-		printk("Set MIR Mode! Speed: %d\n", speed);
-
-		omap_writeb((1 << 2) | (1 << 6), UART3_MDR1);	/* Set MIR mode with 
-								   SIP after each frame */
-
-		omap_writeb(2, UART3_EBLR);
-
-		divisor = 48000000 / (41 * speed);	/* Base clock 48 MHz */
-
-		omap_writeb(1 << 7, UART3_LCR);
-
-		omap_writeb((divisor & 0xFF), UART3_DLL);
-
-		omap_writeb((divisor >> 8), UART3_DLH);
-
-		omap_writeb(0x03, UART3_LCR);
-
-		if (machine_is_omap_h2())
-			omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 1);
-
-		if (machine_is_omap_h3())
-			set_h3_irda_mode(MIR_MODE);
-
-	} else {
-		/* FIR mode */
-
-		printk("Set FIR Mode! Speed: %d\n", speed);
-
-		omap_writeb((1 << 2) | (1 << 6) | 1, UART3_MDR1);	/* Set FIR mode
-									   with SIP after each frame */
-		if (machine_is_omap_h2())
-			omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 1);
-
-		if (machine_is_omap_h3())
-			set_h3_irda_mode(FIR_MODE);
-	}
-
-	si->speed = speed;
-
-	__ECHO_OUT;
-
-	return 0;
-
-}
-
-#ifdef CONFIG_PM
-/*
- * Suspend the IrDA interface.
- */
-static int omap1610_irda_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-	struct omap1610_irda *si = dev->priv;
-
-	if (!dev)
-		return 0;
-
-	if (si->open) {
-		/*
-		 * Stop the transmit queue
-		 */
-		netif_device_detach(dev);
-		disable_irq(dev->irq);
-		omap1610_irda_shutdown(si);
-	}
-	return 0;
-}
-
-/*
- * Resume the IrDA interface.
- */
-static int omap1610_irda_resume(struct platform_device *pdev)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-	struct omap1610_irda *si= dev->priv;
-
-	if (!dev)
-		return 0;
-
-	if (si->open) {
-		/*
-		 * If we missed a speed change, initialise at the new speed
-		 * directly.  It is debatable whether this is actually
-		 * required, but in the interests of continuing from where
-		 * we left off it is desireable.  The converse argument is
-		 * that we should re-negotiate at 9600 baud again.
-		 */
-		if (si->newspeed) {
-			si->speed = si->newspeed;
-			si->newspeed = 0;
-		}
-
-		omap1610_irda_startup(dev);
-		omap1610_irda_set_speed(dev, si->speed);
-		enable_irq(dev->irq);
-
-		/*
-		 * This automatically wakes up the queue
-		 */
-		netif_device_attach(dev);
-	}
-
-	return 0;
-}
-#else
-#define omap1610_irda_suspend	NULL
-#define omap1610_irda_resume	NULL
-#endif
-
-static int omap1610_irda_probe(struct platform_device *pdev)
-{
-	struct net_device *dev;
-	struct omap1610_irda *si;
-	unsigned int baudrate_mask;
-	int err = 0;
-
-	dev = alloc_irdadev(sizeof(struct omap1610_irda));
-	if (!dev)
-		goto err_mem_1;
-
-	si = dev->priv;
-	si->dev = &pdev->dev;
-	dev->hard_start_xmit = omap1610_irda_hard_xmit;
-	dev->open = omap1610_irda_start;
-	dev->stop = omap1610_irda_stop;
-	dev->do_ioctl = omap1610_irda_ioctl;
-	dev->get_stats = omap1610_irda_stats;
-	dev->irq = INT_UART3;
-
-	irda_init_max_qos_capabilies(&si->qos);
-
-	/*
-	 *  OMAP1610  supports SIR, MIR, FIR modes,
-	 *  but actualy supported modes depend on hardware implementation.
-	 *  OMAP1610 Innovator supports only SIR and 
-	 *  OMAP1610 H2 supports both SIR and FIR
-	 */
-
-	baudrate_mask =
-	    IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 | IR_576000 |
-	    IR_1152000;
-
-	if (machine_is_omap_h2() || machine_is_omap_h3()) {
-
-		baudrate_mask |= (IR_4000000 << 8);
-	}
-
-	si->qos.baud_rate.bits &= baudrate_mask;
-	si->qos.min_turn_time.bits = 7;
-
-	irda_qos_bits_to_value(&si->qos);
-
-	err = register_netdev(dev);
-	if (!err)
-		platform_set_drvdata(pdev, dev);
-	else 
-		free_netdev(dev);
-
- err_mem_1:
-	return err;
-}
-
-static int omap1610_irda_remove(struct platform_device *pdev)
-{
-	struct net_device *dev = platform_get_drvdata(pdev);
-
-#ifdef CONFIG_MACH_OMAP_H3
-	if (machine_is_omap_h3())
-		cancel_delayed_work(&set_h3_gpio_expa_work);
-#endif
-	if (pdev) {
-		unregister_netdev(dev);
-		free_netdev(dev);
-	}
-	return 0;
-}
-
-static struct platform_driver omap1610ir_driver = {
-	.probe		= omap1610_irda_probe,
-	.remove		= omap1610_irda_remove,
-	.suspend	= omap1610_irda_suspend,
-	.resume		= omap1610_irda_resume,
-	.driver		= {
-		.name	= "omap1610-ir",
-	},
-};
-
-static char __initdata banner[] = "OMAP1610 IrDA driver\n";
-
-static int __init omap1610_irda_init(void)
-{
-	printk(banner);
-	return platform_driver_register(&omap1610ir_driver);
-}
-
-static void __exit omap1610_irda_exit(void)
-{
-	platform_driver_unregister(&omap1610ir_driver);
-}
-
-module_init(omap1610_irda_init);
-module_exit(omap1610_irda_exit);
-
-MODULE_AUTHOR("MontaVista");
-MODULE_DESCRIPTION("OMAP IrDA Driver");
-MODULE_LICENSE("GPL");
-
diff --git a/include/asm-arm/arch-omap/irda.h b/include/asm-arm/arch-omap/irda.h
new file mode 100644
index 0000000..ad71e4b
--- /dev/null
+++ b/include/asm-arm/arch-omap/irda.h
@@ -0,0 +1,30 @@
+/*
+ *  linux/include/asm-arm/arch-omap/irda.h
+ *
+ *  Copyright (C) 2005 Komal Shah <komal_shah802003@yahoo.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.
+ */
+#ifndef ASMARM_ARCH_IRDA_H
+#define ASMARM_ARCH_IRDA_H
+
+/* board specific transceiver capabilities */
+
+#define IR_SEL		1	/* Selects IrDA */
+#define IR_SIRMODE	2
+#define IR_FIRMODE	4
+#define IR_MIRMODE	8
+
+struct omap_irda_config {
+	int transceiver_cap;
+	int (*transceiver_mode)(struct device *dev, int mode);
+	int (*select_irda)(struct device *dev, int state);
+	/* Very specific to the needs of some platforms (h3,h4)
+	 * having calls which can sleep in irda_set_speed.
+	 */
+	struct work_struct gpio_expa;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 4ffce1d..42bb4c2 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -242,6 +242,7 @@
 #define INT_24XX_GPIO_BANK2	30
 #define INT_24XX_GPIO_BANK3	31
 #define INT_24XX_GPIO_BANK4	32
+#define INT_24XX_UART3_IRQ	74
 
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
  * 16 MPUIO lines */
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
index 8d1c62e..9776338 100644
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -410,6 +410,11 @@ enum omap24xx_index {
 	/* 24xx GPIO */
 	Y20_24XX_GPIO60,
 	M15_24XX_GPIO92,
+
+	/* UART3 */
+	K15_24XX_UART3_TX,
+	K14_24XX_UART3_RX,
+
 };
 
 #ifdef	CONFIG_OMAP_MUX

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-01-12 22:32 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-06 14:00 [PATCH] 24xx Irda update Komal Shah
2006-01-10  6:18 ` Komal Shah
2006-01-12 22:32   ` Tony Lindgren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox