From d882cbcef62f70bb308985bc75a4f310404ed117 Mon Sep 17 00:00:00 2001 From: Komal Shah Date: Thu, 12 Jan 2006 14:30:44 -0800 Subject: [PATCH] [PATCH] ARM: OMAP: 24xx Irda update Attached the updated IrDA patch (integrated workqueue) with 24xx support. Signed-off-by: Komal Shah Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-h2.c | 44 ++ arch/arm/mach-omap1/board-h3.c | 88 +++ arch/arm/mach-omap2/board-h4.c | 91 +++ arch/arm/mach-omap2/mux.c | 4 + drivers/net/irda/Kconfig | 10 +- drivers/net/irda/Makefile | 2 +- drivers/net/irda/omap-ir.c | 1022 ++++++++++++++++++++++++++++++ drivers/net/irda/omap1610-ir.c | 997 ----------------------------- include/asm-arm/arch-omap/irda.h | 30 + include/asm-arm/arch-omap/irqs.h | 1 + include/asm-arm/arch-omap/mux.h | 5 + 11 files changed, 1291 insertions(+), 1003 deletions(-) create mode 100644 drivers/net/irda/omap-ir.c create mode 100644 include/asm-arm/arch-omap/irda.h diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 7335ad26e29..5840e78ca21 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -171,10 +172,44 @@ static struct platform_device h2_smc91x_device = { .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 2e7527a0ae8..826e7417705 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -34,9 +35,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -193,11 +196,96 @@ static struct platform_device intlat_device = { .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 19b498d7002..157fd99ceb3 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -25,8 +26,10 @@ #include #include +#include #include #include +#include #include #include #include "prcm-regs.h" @@ -108,9 +111,93 @@ static struct platform_device h4_smc91x_device = { .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/mux.c b/arch/arm/mach-omap2/mux.c index ea4654815dd..9e6b79f40fd 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, 0, 1, 1, 1) 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 b200c50a229..32c0c199ad1 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 7db79a23222..494b0f85753 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -43,7 +43,7 @@ obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin-sir.o 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 00000000000..475770db4dd --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 1fa8e89f734..e69de29bb2d 100644 --- a/drivers/net/irda/omap1610-ir.c +++ b/drivers/net/irda/omap1610-ir.c @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_MACH_OMAP_H3 -#include -#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 00000000000..ad71e4b56d9 --- /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 + * + * 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 4ffce1d7775..42bb4c24c7d 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 8d1c62e00c3..9776338361a 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 -- 2.41.1