lkml.org 
[lkml]   [2010]   [Jul]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subjectpatch "U6715 8250 serial like driver" added to gregkh-2.6 tree
From
Date

This is a note to let you know that I've just added the patch titled

U6715 8250 serial like driver

to my gregkh-2.6 tree which can be found in directory form at:
http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
and in git form at:
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/patches.git

The filename of this patch is:
u6715-8250-serial-like-driver.patch

The patch will show up in the next release of the linux-next tree
(usually sometime within the next 24 hours during the week.)

If this patch meets the merge guidelines for a bugfix, it should be
merged into Linus's tree before the next major kernel release.
If not, it will be merged into Linus's tree during the next merge window.

Either way, you will probably be copied on the patch when it gets sent
to Linus for merging so that others can see what is happening in kernel
development.

If you have any questions about this process, please let me know.


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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2010-07-23 02:01    [W:0.055 / U:0.036 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site