From 5f645d0668b469c4738fe1e9d3994287a519d0f3 Mon Sep 17 00:00:00 2001 From: Kurt Mahan <kmahan@freescale.com> Date: Tue, 8 Jul 2008 15:57:47 -0600 Subject: [PATCH] Add Coldfire IRDA support in serial driver. LTIBName: mcfv4e-irda Signed-off-by: Kurt Mahan <kmahan@freescale.com> Signed-off-by: Huan, Wang <b18965@freescale.com> --- drivers/serial/Kconfig | 6 ++ drivers/serial/mcfserial.c | 110 ++++++++++++++++++++++++++++++++++++++++++-- net/irda/irlap.c | 2 +- 3 files changed, 113 insertions(+), 5 deletions(-) --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -979,6 +979,12 @@ config SERIAL_COLDFIRE This driver supports the built-in serial ports of the Motorola ColdFire family of CPUs. +config SERIAL_COLDFIRE_IRDA + bool "ColdFire IRDA support" + depends on SERIAL_COLDFIRE + help + This driver supports IRDA on the Motorola ColdFire. + config SERIAL_MCF bool "Coldfire serial support (new style driver)" depends on COLDFIRE --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -109,6 +109,10 @@ static struct tty_driver *mcfrs_serial_d #define IRQBASE 73 #endif +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA +#define SERIAL_IRDA_LINE (2) +#endif + /* * Configuration table, UARTs to look for at startup. */ @@ -393,6 +397,9 @@ static inline void receive_chars(struct static inline void transmit_chars(struct mcf_serial *info) { volatile unsigned char *uartp; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + int i; +#endif uartp = info->addr; @@ -404,13 +411,36 @@ static inline void transmit_chars(struct } if ((info->xmit_cnt <= 0) || info->tty->stopped) { +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + /* Enable receiver for IRDA */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; + /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_TXENABLE | MCFUART_UCR_RXENABLE; + } +#endif info->imr &= ~MCFUART_UIR_TXREADY; uartp[MCFUART_UIMR] = info->imr; return; } while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) { +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + while (!(uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)); + i = 0; + /* delay for settle */ +#if defined(CONFIG_M548X) + udelay(1); +#elif defined(CONFIG_M547X) + udelay(2); +#else + while (i++ < 25000) udelay(1); +#endif + } +#endif uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++]; + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->stats.tx++; if (--info->xmit_cnt <= 0) @@ -567,6 +597,28 @@ static int startup(struct mcf_serial * i */ mcfrs_change_speed(info); +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + /* Put PSC in IrDA mode */ + MCF_PSC_SICR(info->line) = MCF_PSC_SICR_SIM_SIR; + + /* Set pulse width to 1.6 uS */ + MCF_PSC_IRSDR(info->line) = (uint8_t) + (16 * (CONFIG_MCFCLK / 10000000)); + MCF_PSC_IRCR1(info->line) = MCF_PSC_IRCR1_SPUL; + MCF_PSC_IRCR2(info->line) = 0; + + /* Enable RTS to send */ + MCF_PSC_OPSET(info->line) = MCF_PSC_OPSET_RTS; + + /* Setup FIFO Alarms */ + MCF_PSC_RFAR(info->line) = MCF_PSC_RFAR_ALARM(248); + MCF_PSC_TFAR(info->line) = MCF_PSC_TFAR_ALARM(248); + + MCF_PSC_RFCR(info->line) = MCF_PSC_RFCR_FRMEN | MCF_PSC_RFCR_GR(4); + MCF_PSC_TFCR(info->line) = MCF_PSC_TFCR_FRMEN | MCF_PSC_RFCR_GR(4); + } +#endif /* * Lastly enable the UART transmitter and receiver, and * interrupt enables. @@ -588,10 +640,20 @@ static void shutdown(struct mcf_serial * { volatile unsigned char *uartp; unsigned long flags; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + unsigned long delay_counter = 0; +#endif if (!(info->flags & ASYNC_INITIALIZED)) return; - +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + uartp = (volatile unsigned char *) info->addr; + while (!(uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)) { + if(delay_counter++ > 25000) + break; + udelay(10); + } +#endif #ifdef SERIAL_DEBUG_OPEN printk("Shutting down serial port %d (irq %d)....\n", info->line, info->irq); @@ -820,10 +882,19 @@ static int mcfrs_write(struct tty_struct local_irq_disable(); uartp = info->addr; + +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (info->line == SERIAL_IRDA_LINE) { + /* Disable IRDA receiver*/ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ + uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ + + uartp[MCFUART_UCR] = MCFUART_UCR_TXENABLE; + } +#endif info->imr |= MCFUART_UIR_TXREADY; uartp[MCFUART_UIMR] = info->imr; local_irq_restore(flags); - return total; } @@ -884,9 +955,21 @@ static void mcfrs_throttle(struct tty_st if (serial_paranoia_check(info, tty->name, "mcfrs_throttle")) return; - +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (I_IXOFF(tty)) { + /* Force STOP_CHAR (xoff) out */ + volatile unsigned char *uartp; + unsigned long flags; + uartp = (volatile unsigned char *) info->addr; + local_irq_save(flags); + info->imr |= MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + local_irq_restore(flags); + } +#else if (I_IXOFF(tty)) info->x_char = STOP_CHAR(tty); +#endif /* Turn off RTS line (do this atomic) */ } @@ -907,8 +990,22 @@ static void mcfrs_unthrottle(struct tty_ if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + else { + /* Force START_CHAR (xon) out */ + volatile unsigned char *uartp; + unsigned long flags; + info->x_char = START_CHAR(tty); + uartp = (volatile unsigned char *) info->addr; + local_irq_save(flags); + info->imr |= MCFUART_UIR_TXREADY; + uartp[MCFUART_UIMR] = info->imr; + local_irq_restore(flags); + } +#else else info->x_char = START_CHAR(tty); +#endif } /* Assert RTS line (do this atomic) */ @@ -1156,12 +1253,17 @@ static int mcfrs_ioctl(struct tty_struct static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + int i = 0; /* hush GCC */ +#endif if (tty->termios->c_cflag == old_termios->c_cflag) return; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + while (i++ < 35000) udelay(1); +#endif mcfrs_change_speed(info); - if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -627,7 +627,7 @@ void irlap_status_indication(struct irla { switch (quality_of_link) { case STATUS_NO_ACTIVITY: - IRDA_MESSAGE("IrLAP, no activity on link!\n"); + /* IRDA_MESSAGE("IrLAP, no activity on link!\n"); */ break; case STATUS_NOISY: IRDA_MESSAGE("IrLAP, noisy link!\n");