diff options
Diffstat (limited to 'tty/u6715-8250-serial-like-driver.patch')
| -rw-r--r-- | tty/u6715-8250-serial-like-driver.patch | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/tty/u6715-8250-serial-like-driver.patch b/tty/u6715-8250-serial-like-driver.patch new file mode 100644 index 00000000000000..a6a45bd69f9ee5 --- /dev/null +++ b/tty/u6715-8250-serial-like-driver.patch @@ -0,0 +1,340 @@ +From philippe.langlais@stericsson.com Thu Jul 22 15:53:24 2010 +From: Philippe Langlais <philippe.langlais@stericsson.com> +To: <linux-kernel@vger.kernel.org> +Cc: <gregkh@suse.de>, <ludovic.barre@stericsson.com>, + Philippe Langlais <philippe.langlais@stericsson.com> +Subject: U6715 8250 serial like driver +Date: Mon, 19 Jul 2010 11:27:40 +0200 +Message-ID: <1279531660-16317-1-git-send-email-philippe.langlais@stericsson.com> + +UART Features extract from STEricsson U6715 datasheet (arm926 SoC for mobile phone): +* Fully compatible with industry standard 16C550 and 16C450 from various +manufacturers +* RX and TX 64 byte FIFO reduces CPU interrupts +* Full double buffering +* Modem control signals include CTS, RTS, (and DSR, DTR on UART1 only) +* Automatic baud rate selection +* Manual or automatic RTS/CTS smart hardware flow control +* Programmable serial characteristics: +– Baud rate generation (50 to 3.25M baud) +– 5, 6, 7 or 8-bit characters +– Even, odd or no-parity bit generation and detection +– 1, 1.5 or 2 stop bit generation +* Independent control of transmit, receive, line status, data set interrupts and FIFOs +* Full status-reporting capabilities +* Separate DMA signalling for RX and TX +* Timed interrupt to spread receive interrupt on known duration +* DMA time-out interrupt to allow detection of end of reception +* Carkit pulse coding and decoding compliant with USB carkit control interface [40] + +This UART IP is auto-detected as a 16550A type + +Clock specificities: + It's parent clock depend on baud rate. + The UART port can be used before u6xxx clock framework initialization + +Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/8250.c | 26 ++++++ + drivers/serial/8250_u6.c | 179 ++++++++++++++++++++++++++++++++++++++++++++ + drivers/serial/Kconfig | 19 ++++ + drivers/serial/Makefile | 1 + include/linux/serial_8250.h | 8 + + 5 files changed, 232 insertions(+), 1 deletion(-) + +--- a/drivers/serial/8250.c ++++ b/drivers/serial/8250.c +@@ -199,10 +199,16 @@ static const struct serial8250_config ua + }, + [PORT_16550A] = { + .name = "16550A", ++#if defined(CONFIG_SERIAL_8250_U6XXX) ++ .fifo_size = 64, ++ .tx_loadsz = 64, ++ .flags = UART_CAP_FIFO | UART_CAP_AFE, ++#else + .fifo_size = 16, + .tx_loadsz = 16, +- .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, ++#endif ++ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + }, + [PORT_CIRRUS] = { + .name = "Cirrus", +@@ -2268,6 +2274,13 @@ serial8250_set_termios(struct uart_port + /* + * Ask the core to calculate the divisor for us. + */ ++#ifdef CONFIG_SERIAL_8250_CUSTOM_CLOCK ++ baud = uart_get_baud_rate(port, termios, old, 0, ++ CONFIG_SERIAL_8250_CUSTOM_MAX_BAUDRATE); ++ /* Calculate the new uart clock frequency if it is tunable */ ++ port->uartclk = serial8250_get_custom_clock(port, baud); ++#endif ++ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 16); +@@ -2298,6 +2311,13 @@ serial8250_set_termios(struct uart_port + up->mcr &= ~UART_MCR_AFE; + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; ++#if defined(CONFIG_SERIAL_8250_U6XXX) ++ /** ++ * When AFE is active, let the HW handle the stop/restart TX ++ * upon CTS change. It reacts much quicker than the SW driver. ++ */ ++ port->flags &= ~ASYNC_CTS_FLOW; ++#endif + } + + /* +@@ -2383,6 +2403,10 @@ serial8250_set_termios(struct uart_port + serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + } + ++#ifdef CONFIG_SERIAL_8250_CUSTOM_CLOCK ++ /* set the new uart clock frequency if it is tunable */ ++ serial8250_set_custom_clock(port); ++#endif + serial_dl_write(up, quot); + + /* +--- /dev/null ++++ b/drivers/serial/8250_u6.c +@@ -0,0 +1,179 @@ ++/* ++ * linux/drivers/serial/8250_pnx.c ++ * ++ * Copyright (C) ST-Ericsson SA 2010 ++ * Author: Ludovic Barre <ludovic.barre@stericsson.com> for ST-Ericsson. ++ * License terms: GNU General Public License (GPL), version 2 ++ */ ++ ++#include <linux/serial_core.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++ ++#include <mach/serial.h> ++#include <mach/hardware.h> ++#include <mach/clock.h> ++ ++/* Register description for FDIV_CTRL */ ++/* UART FDIV_CTRL Register (8 bits) */ ++#define UARTX_FDIV_CTRL_OFFSET 0xC00 ++/* UART FDIV_M Register (16 bits) */ ++#define UARTX_FDIV_M_OFFSET 0xC04 ++/* UART FDIV_N Register (16 bits) */ ++#define UARTX_FDIV_N_OFFSET 0xC08 ++ ++/* Bits definition for register UARTX_FDIV_CTRL */ ++#define UARTX_FDIV_ENABLE_SHIFT 7 ++#define UARTX_FDIV_ENABLE_FIELD (0xFFFFFFFF - (0x1UL<<UARTX_FDIV_ENABLE_SHIFT)) ++#define UARTX_FDIV_ENABLE_OFF (0x0UL<<UARTX_FDIV_ENABLE_SHIFT) ++#define UARTX_FDIV_ENABLE_ON (0x1UL<<UARTX_FDIV_ENABLE_SHIFT) ++#define UARTX_FDIV_ENABLE (0x1UL<<UARTX_FDIV_ENABLE_SHIFT) ++#define UARTX_CLKSEL_SHIFT 0 ++#define UARTX_CLKSEL_FIELD (0xFFFFFFFF - (0x3UL<<UARTX_CLKSEL_SHIFT)) ++#define UARTX_CLKSEL_PCLK (0x0UL<<UARTX_CLKSEL_SHIFT) ++#define UARTX_CLKSEL_13M (0x1UL<<UARTX_CLKSEL_SHIFT) ++#define UARTX_CLKSEL_26M (0x2UL<<UARTX_CLKSEL_SHIFT) ++#define UARTX_CLKSEL_3 (0x3UL<<UARTX_CLKSEL_SHIFT) ++ ++/* ++ * console and pctools has needed to start before serial_init ++ * (with cgu interface) ++ */ ++static int uart_enable_clock(struct uart_port *port) ++{ ++ u32 v; ++ v = readl(CGU_GATESC1_REG); ++ ++ if (port->irq == IRQ_UART1) ++ v |= CGU_UART1EN_1; ++ else if (port->irq == IRQ_UART2) ++ v |= CGU_UART2EN_1; ++ ++ writel(v, CGU_GATESC1_REG); ++ ++ return 0; ++} ++ ++static int uart_disable_clock(struct uart_port *port) ++{ ++ u32 v; ++ v = readl(CGU_GATESC1_REG); ++ ++ if (port->irq == IRQ_UART1) ++ v &= ~CGU_UART1EN_0; ++ else if (port->irq == IRQ_UART2) ++ v &= ~CGU_UART2EN_0; ++ ++ writel(v, CGU_GATESC1_REG); ++ ++ return 0; ++} ++ ++unsigned int serial8250_enable_clock(struct uart_port *port) ++{ ++ struct u6_uart *uart_u6 = port->private_data; ++ ++ if (!uart_u6) ++ return uart_enable_clock(port); ++ ++ if (IS_ERR(uart_u6->uartClk)) { ++ printk(KERN_WARNING "%s - uart clock failed error:%ld\n", ++ __func__, PTR_ERR(uart_u6->uartClk)); ++ return PTR_ERR(uart_u6->uartClk); ++ } ++ ++ if (clk_get_usecount(uart_u6->uartClk) == 0) ++ clk_enable(uart_u6->uartClk); ++ return 0; ++} ++ ++unsigned int serial8250_disable_clock(struct uart_port *port) ++{ ++ struct u6_uart *uart_u6 = port->private_data; ++ ++ if (!uart_u6) ++ return uart_disable_clock(port); ++ ++ if (IS_ERR(uart_u6->uartClk)) { ++ printk(KERN_WARNING "%s - uart clk error :%ld\n", __func__, ++ PTR_ERR(uart_u6->uartClk)); ++ return PTR_ERR(uart_u6->uartClk); ++ } ++ if (clk_get_usecount(uart_u6->uartClk) >= 1) ++ clk_disable(uart_u6->uartClk); ++ ++ return 0; ++} ++ ++unsigned int serial8250_get_custom_clock(struct uart_port *port, ++ unsigned int baud) ++{ ++ switch (baud) { ++ case 3250000: ++ return 52000000; ++ case 2000000: ++ return 32000000; ++ case 1843200: ++ return 29491200; ++ case 921600: ++ return 14745600; ++ default: ++ return 7372800; ++ } ++} ++ ++void serial8250_set_custom_clock(struct uart_port *port) ++{ ++ u32 fdiv_m = 0x5F37; ++ u32 fdiv_n = 0x3600; ++ u32 fdiv_ctrl = UARTX_FDIV_ENABLE_ON; ++ struct u6_uart *uart_u6 = port->private_data; ++ ++ switch (port->uartclk) { ++ case 7372800: /* clk=13MHz */ ++ fdiv_ctrl |= UARTX_CLKSEL_13M; ++ break; ++ case 14745600: /* clk=26MHz */ ++ fdiv_ctrl |= UARTX_CLKSEL_26M; ++ break; ++ case 29491200: /* clk=pclk */ ++ fdiv_ctrl |= UARTX_CLKSEL_PCLK; ++ break; ++ case 32000000: /* clk=pclk */ ++ fdiv_n = 0x3A98; ++ fdiv_ctrl |= UARTX_CLKSEL_PCLK; ++ break; ++ case 52000000: /* clk=pclk */ ++ fdiv_n = 0x5F37; ++ fdiv_ctrl |= UARTX_CLKSEL_PCLK; ++ break; ++ } ++ ++ if (uart_u6 != NULL && !IS_ERR(uart_u6->uartClk)) { ++ /* if cgu interface is ready and u6_serial_init */ ++ struct clk *parentClk; ++ ++ if (fdiv_ctrl & UARTX_CLKSEL_26M) ++ parentClk = clk_get(NULL, "clk26m_ck"); ++ else if (fdiv_ctrl & UARTX_CLKSEL_PCLK) ++ parentClk = clk_get(NULL, "pclk2_ck"); ++ else ++ parentClk = clk_get(NULL, "clk13m_ck"); ++ ++ if (!IS_ERR(parentClk)) { ++ serial8250_disable_clock(port); ++ ++ if (clk_set_parent(uart_u6->uartClk, parentClk) != 0) ++ printk(KERN_WARNING "%s: set parent failed\n", __func__); ++ ++ serial8250_enable_clock(port); ++ clk_put(parentClk); ++ } ++ } ++ ++ writel(fdiv_m, port->membase + UARTX_FDIV_M_OFFSET); ++ writel(fdiv_n, port->membase + UARTX_FDIV_N_OFFSET); ++ writel(fdiv_ctrl, port->membase + UARTX_FDIV_CTRL_OFFSET); ++} +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -163,6 +163,25 @@ config SERIAL_8250_MANY_PORTS + say N here to save some memory. You can also say Y if you have an + "intelligent" multiport card such as Cyclades, Digiboards, etc. + ++config SERIAL_8250_U6XXX ++ bool ++ depends on SERIAL_8250_EXTENDED && PLAT_U6XXX ++ default y ++ ++config SERIAL_8250_CUSTOM_CLOCK ++ bool "Support serial ports with tunable input clock frequency" ++ depends on SERIAL_8250_EXTENDED && SERIAL_8250_U6XXX ++ default y ++ help ++ Say Y here if your platform has specific registers to change UART clock frequency. ++ ++config SERIAL_8250_CUSTOM_MAX_BAUDRATE ++ int "Maximal reachable baudrate" ++ depends on SERIAL_8250_CUSTOM_CLOCK ++ default "3250000" ++ help ++ The value of the maximal reachable baudrate when tuning UART clock frequency (default value: 3.25MBds). ++ + # + # Multi-port serial cards + # +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_b + obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o + obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o + obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o ++obj-$(CONFIG_SERIAL_8250_U6XXX) += 8250_u6.o + obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o + obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o + obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o +--- a/include/linux/serial_8250.h ++++ b/include/linux/serial_8250.h +@@ -72,4 +72,12 @@ extern int serial8250_find_port(struct u + extern int serial8250_find_port_for_earlycon(void); + extern int setup_early_serial8250_console(char *cmdline); + ++#ifdef CONFIG_SERIAL_8250_CUSTOM_CLOCK ++unsigned int serial8250_enable_clock(struct uart_port *port); ++unsigned int serial8250_disable_clock(struct uart_port *port); ++unsigned int serial8250_get_custom_clock(struct uart_port *port, ++ unsigned int baud); ++void serial8250_set_custom_clock(struct uart_port *port); ++#endif ++ + #endif |
