* Revised patch series for minimal HTC Dream support
@ 2009-06-18 0:31 Brian Swetland
2009-06-18 0:31 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
0 siblings, 1 reply; 22+ messages in thread
From: Brian Swetland @ 2009-06-18 0:31 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: linux-kernel, pavel
This incorporates feedback from lkml/lakml, and I think is in
pretty good shape now.
msm_serial.c
- Ryan Mallon
- remove some likely/unlikely not in hot-path code, for clarity
- UART_TO_MSM() -> to_msm_uart()
- clean up static structure declarations
- Pavel Machek
- SUPPORT_SYSRQ needed for console break handling
- remove hrtimer.h, other unused headers
- Kconfig cleanup
- Alan Cox
- set_termios should propogate used settings
- Linus Walleij
- use resource_size() when appropriate
- dev_err instead of printk(KERN_ERR...
- remove some chatty printks
- use __exit, __exit_p()
board-dream.c
- Stefan Schmidt
- remove smc resources
- remove unused headers
ll debug support
- Pavel Machek
- remove extraneous 1002 label
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-18 0:31 Revised patch series for minimal HTC Dream support Brian Swetland
@ 2009-06-18 0:31 ` Brian Swetland
2009-06-18 0:31 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Brian Swetland
2009-06-18 9:20 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Alan Cox
0 siblings, 2 replies; 22+ messages in thread
From: Brian Swetland @ 2009-06-18 0:31 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: linux-kernel, pavel, Robert Love, Brian Swetland
From: Robert Love <rlove@google.com>
Provides support for the "lowspeed" UARTs on the MSM7k and QSD8k
family of SoCs from Qualcomm. Serial console support included.
Signed-off-by: Robert Love <rlove@google.com>
Signed-off-by: Brian Swetland <swetland@google.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
drivers/serial/Kconfig | 10 +
drivers/serial/Makefile | 1 +
drivers/serial/msm_serial.c | 762 +++++++++++++++++++++++++++++++++++++++++++
drivers/serial/msm_serial.h | 117 +++++++
include/linux/serial_core.h | 3 +
5 files changed, 893 insertions(+), 0 deletions(-)
create mode 100644 drivers/serial/msm_serial.c
create mode 100644 drivers/serial/msm_serial.h
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 1132c5c..1e3cc15 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1320,6 +1320,16 @@ config SERIAL_SGI_IOC3
If you have an SGI Altix with an IOC3 serial card,
say Y or M. Otherwise, say N.
+config SERIAL_MSM
+ bool "MSM on-chip serial port support"
+ depends on ARM && ARCH_MSM
+ select SERIAL_CORE
+
+config SERIAL_MSM_CONSOLE
+ bool "MSM serial console support"
+ depends on SERIAL_MSM
+ select SERIAL_CORE_CONSOLE
+
config SERIAL_NETX
tristate "NetX serial port support"
depends on ARM && ARCH_NETX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 45a8658..d5a2998 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
+obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
new file mode 100644
index 0000000..b0569d9
--- /dev/null
+++ b/drivers/serial/msm_serial.c
@@ -0,0 +1,762 @@
+/*
+ * drivers/serial/msm_serial.c - driver for msm7k serial device and console
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "msm_serial.h"
+
+struct msm_port {
+ struct uart_port uart;
+ char name[16];
+ struct clk *clk;
+ unsigned int imr;
+};
+
+#define to_msm_uart(uart_port) ((struct msm_port *) uart_port)
+
+static inline void msm_write(struct uart_port *port, unsigned int val,
+ unsigned int off)
+{
+ __raw_writel(val, port->membase + off);
+}
+
+static inline unsigned int msm_read(struct uart_port *port, unsigned int off)
+{
+ return __raw_readl(port->membase + off);
+}
+
+static void msm_stop_tx(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+
+ msm_port->imr &= ~UART_IMR_TXLEV;
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_start_tx(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+
+ msm_port->imr |= UART_IMR_TXLEV;
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_stop_rx(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+
+ msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_enable_ms(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+
+ msm_port->imr |= UART_IMR_DELTA_CTS;
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+ struct tty_struct *tty = port->info->port.tty;
+ unsigned int sr;
+
+ /*
+ * Handle overrun. My understanding of the hardware is that overrun
+ * is not tied to the RX buffer, so we handle the case out of band.
+ */
+ if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
+ port->icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ }
+
+ /* and now the main RX loop */
+ while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
+ unsigned int c;
+ char flag = TTY_NORMAL;
+
+ c = msm_read(port, UART_RF);
+
+ if (sr & UART_SR_RX_BREAK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & UART_SR_PAR_FRAME_ERR) {
+ port->icount.frame++;
+ } else {
+ port->icount.rx++;
+ }
+
+ /* Mask conditions we're ignorning. */
+ sr &= port->read_status_mask;
+
+ if (sr & UART_SR_RX_BREAK) {
+ flag = TTY_BREAK;
+ } else if (sr & UART_SR_PAR_FRAME_ERR) {
+ flag = TTY_FRAME;
+ }
+
+ if (!uart_handle_sysrq_char(port, c))
+ tty_insert_flip_char(tty, c, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+ struct msm_port *msm_port = to_msm_uart(port);
+ int sent_tx;
+
+ if (port->x_char) {
+ msm_write(port, port->x_char, UART_TF);
+ port->icount.tx++;
+ port->x_char = 0;
+ }
+
+ while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
+ if (uart_circ_empty(xmit)) {
+ /* disable tx interrupts */
+ msm_port->imr &= ~UART_IMR_TXLEV;
+ msm_write(port, msm_port->imr, UART_IMR);
+ break;
+ }
+
+ msm_write(port, xmit->buf[xmit->tail], UART_TF);
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ sent_tx = 1;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+ msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+ port->icount.cts++;
+ wake_up_interruptible(&port->info->delta_msr_wait);
+}
+
+static irqreturn_t msm_irq(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct msm_port *msm_port = to_msm_uart(port);
+ unsigned int misr;
+
+ spin_lock(&port->lock);
+ misr = msm_read(port, UART_MISR);
+ msm_write(port, 0, UART_IMR); /* disable interrupt */
+
+ if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
+ handle_rx(port);
+ if (misr & UART_IMR_TXLEV)
+ handle_tx(port);
+ if (misr & UART_IMR_DELTA_CTS)
+ handle_delta_cts(port);
+
+ msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int msm_tx_empty(struct uart_port *port)
+{
+ return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int msm_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
+}
+
+static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned int mr;
+
+ mr = msm_read(port, UART_MR1);
+
+ if (!(mctrl & TIOCM_RTS)) {
+ mr &= ~UART_MR1_RX_RDY_CTL;
+ msm_write(port, mr, UART_MR1);
+ msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
+ } else {
+ mr |= UART_MR1_RX_RDY_CTL;
+ msm_write(port, mr, UART_MR1);
+ }
+}
+
+static void msm_break_ctl(struct uart_port *port, int break_ctl)
+{
+ if (break_ctl)
+ msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
+ else
+ msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
+}
+
+static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+ unsigned int baud_code, rxstale, watermark;
+
+ switch (baud) {
+ case 300:
+ baud_code = UART_CSR_300;
+ rxstale = 1;
+ break;
+ case 600:
+ baud_code = UART_CSR_600;
+ rxstale = 1;
+ break;
+ case 1200:
+ baud_code = UART_CSR_1200;
+ rxstale = 1;
+ break;
+ case 2400:
+ baud_code = UART_CSR_2400;
+ rxstale = 1;
+ break;
+ case 4800:
+ baud_code = UART_CSR_4800;
+ rxstale = 1;
+ break;
+ case 9600:
+ baud_code = UART_CSR_9600;
+ rxstale = 2;
+ break;
+ case 14400:
+ baud_code = UART_CSR_14400;
+ rxstale = 3;
+ break;
+ case 19200:
+ baud_code = UART_CSR_19200;
+ rxstale = 4;
+ break;
+ case 28800:
+ baud_code = UART_CSR_28800;
+ rxstale = 6;
+ break;
+ case 38400:
+ baud_code = UART_CSR_38400;
+ rxstale = 8;
+ break;
+ case 57600:
+ baud_code = UART_CSR_57600;
+ rxstale = 16;
+ break;
+ case 115200:
+ default:
+ baud_code = UART_CSR_115200;
+ baud = 115200;
+ rxstale = 31;
+ break;
+ }
+
+ msm_write(port, baud_code, UART_CSR);
+
+ /* RX stale watermark */
+ watermark = UART_IPR_STALE_LSB & rxstale;
+ watermark |= UART_IPR_RXSTALE_LAST;
+ watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
+ msm_write(port, watermark, UART_IPR);
+
+ /* set RX watermark */
+ watermark = (port->fifosize * 3) / 4;
+ msm_write(port, watermark, UART_RFWR);
+
+ /* set TX watermark */
+ msm_write(port, 10, UART_TFWR);
+
+ return baud;
+}
+
+static void msm_reset(struct uart_port *port)
+{
+ /* reset everything */
+ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+ msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+}
+
+static void msm_init_clock(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+
+ clk_enable(msm_port->clk);
+
+ msm_write(port, 0xC0, UART_MREG);
+ msm_write(port, 0xB2, UART_NREG);
+ msm_write(port, 0x7D, UART_DREG);
+ msm_write(port, 0x1C, UART_MNDREG);
+}
+
+static int msm_startup(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+ unsigned int data, rfr_level;
+ int ret;
+
+ snprintf(msm_port->name, sizeof(msm_port->name),
+ "msm_serial%d", port->line);
+
+ ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
+ msm_port->name, port);
+ if (ret)
+ return ret;
+
+ msm_init_clock(port);
+
+ if (port->fifosize > 12)
+ rfr_level = port->fifosize - 12;
+ else
+ rfr_level = port->fifosize;
+
+ /* set automatic RFR level */
+ data = msm_read(port, UART_MR1);
+ data &= ~UART_MR1_AUTO_RFR_LEVEL1;
+ data &= ~UART_MR1_AUTO_RFR_LEVEL0;
+ data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
+ data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
+ msm_write(port, data, UART_MR1);
+
+ /* make sure that RXSTALE count is non-zero */
+ data = msm_read(port, UART_IPR);
+ if (!data) {
+ data |= UART_IPR_RXSTALE_LAST;
+ data |= UART_IPR_STALE_LSB;
+ msm_write(port, data, UART_IPR);
+ }
+
+ msm_reset(port);
+
+ msm_write(port, 0x05, UART_CR); /* enable TX & RX */
+
+ /* turn on RX and CTS interrupts */
+ msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
+ UART_IMR_CURRENT_CTS;
+ msm_write(port, msm_port->imr, UART_IMR);
+
+ return 0;
+}
+
+static void msm_shutdown(struct uart_port *port)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+
+ msm_port->imr = 0;
+ msm_write(port, 0, UART_IMR); /* disable interrupts */
+
+ clk_disable(msm_port->clk);
+
+ free_irq(port->irq, port);
+}
+
+static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud, mr;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* calculate and set baud rate */
+ baud = uart_get_baud_rate(port, termios, old, 300, 115200);
+ baud = msm_set_baud_rate(port, baud);
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+
+ /* calculate parity */
+ mr = msm_read(port, UART_MR2);
+ mr &= ~UART_MR2_PARITY_MODE;
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & PARODD)
+ mr |= UART_MR2_PARITY_MODE_ODD;
+ else if (termios->c_cflag & CMSPAR)
+ mr |= UART_MR2_PARITY_MODE_SPACE;
+ else
+ mr |= UART_MR2_PARITY_MODE_EVEN;
+ }
+
+ /* calculate bits per char */
+ mr &= ~UART_MR2_BITS_PER_CHAR;
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ mr |= UART_MR2_BITS_PER_CHAR_5;
+ break;
+ case CS6:
+ mr |= UART_MR2_BITS_PER_CHAR_6;
+ break;
+ case CS7:
+ mr |= UART_MR2_BITS_PER_CHAR_7;
+ break;
+ case CS8:
+ default:
+ mr |= UART_MR2_BITS_PER_CHAR_8;
+ break;
+ }
+
+ /* calculate stop bits */
+ mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
+ if (termios->c_cflag & CSTOPB)
+ mr |= UART_MR2_STOP_BIT_LEN_TWO;
+ else
+ mr |= UART_MR2_STOP_BIT_LEN_ONE;
+
+ /* set parity, bits per char, and stop bit */
+ msm_write(port, mr, UART_MR2);
+
+ /* calculate and set hardware flow control */
+ mr = msm_read(port, UART_MR1);
+ mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
+ if (termios->c_cflag & CRTSCTS) {
+ mr |= UART_MR1_CTS_CTL;
+ mr |= UART_MR1_RX_RDY_CTL;
+ }
+ msm_write(port, mr, UART_MR1);
+
+ /* Configure status bits to ignore based on termio flags. */
+ port->read_status_mask = 0;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= UART_SR_RX_BREAK;
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *msm_type(struct uart_port *port)
+{
+ return "MSM";
+}
+
+static void msm_release_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *resource;
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource)
+ return;
+
+ release_mem_region(port->mapbase, resource_size(resource));
+ iounmap(port->membase);
+ port->membase = NULL;
+}
+
+static int msm_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *resource;
+ resource_size_t size;
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource)
+ return -ENXIO;
+ size = resource_size(resource);
+
+ if (!request_mem_region(port->mapbase, size, "msm_serial"))
+ return -EBUSY;
+
+ port->membase = ioremap(port->mapbase, size);
+ if (!port->membase) {
+ release_mem_region(port->mapbase, size);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void msm_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_MSM;
+ msm_request_port(port);
+ }
+}
+
+static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_MSM)
+ return -EINVAL;
+ if (port->irq != ser->irq)
+ return -EINVAL;
+ return 0;
+}
+
+static void msm_power(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct msm_port *msm_port = to_msm_uart(port);
+
+ switch (state) {
+ case 0:
+ clk_enable(msm_port->clk);
+ break;
+ case 3:
+ clk_disable(msm_port->clk);
+ break;
+ default:
+ dev_err(port->dev, "Unknown PM state %d\n", state);
+ }
+}
+
+static struct uart_ops msm_uart_pops = {
+ .tx_empty = msm_tx_empty,
+ .set_mctrl = msm_set_mctrl,
+ .get_mctrl = msm_get_mctrl,
+ .stop_tx = msm_stop_tx,
+ .start_tx = msm_start_tx,
+ .stop_rx = msm_stop_rx,
+ .enable_ms = msm_enable_ms,
+ .break_ctl = msm_break_ctl,
+ .startup = msm_startup,
+ .shutdown = msm_shutdown,
+ .set_termios = msm_set_termios,
+ .type = msm_type,
+ .release_port = msm_release_port,
+ .request_port = msm_request_port,
+ .config_port = msm_config_port,
+ .verify_port = msm_verify_port,
+ .pm = msm_power,
+};
+
+static struct msm_port msm_uart_ports[] = {
+ {
+ .uart = {
+ .iotype = UPIO_MEM,
+ .ops = &msm_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .fifosize = 512,
+ .line = 0,
+ },
+ },
+ {
+ .uart = {
+ .iotype = UPIO_MEM,
+ .ops = &msm_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .fifosize = 512,
+ .line = 1,
+ },
+ },
+ {
+ .uart = {
+ .iotype = UPIO_MEM,
+ .ops = &msm_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .fifosize = 64,
+ .line = 2,
+ },
+ },
+};
+
+#define UART_NR ARRAY_SIZE(msm_uart_ports)
+
+static inline struct uart_port *get_port_from_line(unsigned int line)
+{
+ return &msm_uart_ports[line].uart;
+}
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+
+static void msm_console_putchar(struct uart_port *port, int c)
+{
+ while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+ ;
+ msm_write(port, c, UART_TF);
+}
+
+static void msm_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port;
+ struct msm_port *msm_port;
+
+ BUG_ON(co->index < 0 || co->index >= UART_NR);
+
+ port = get_port_from_line(co->index);
+ msm_port = to_msm_uart(port);
+
+ spin_lock(&port->lock);
+ uart_console_write(port, s, count, msm_console_putchar);
+ spin_unlock(&port->lock);
+}
+
+static int __init msm_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud, flow, bits, parity;
+
+ if (co->index >= UART_NR || co->index < 0)
+ return -ENXIO;
+
+ port = get_port_from_line(co->index);
+
+ if (!port->membase)
+ return -ENXIO;
+
+ port->cons = co;
+
+ msm_init_clock(port);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ bits = 8;
+ parity = 'n';
+ flow = 'n';
+ msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
+ UART_MR2); /* 8N1 */
+
+ if (baud < 300 || baud > 115200)
+ baud = 115200;
+ msm_set_baud_rate(port, baud);
+
+ msm_reset(port);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver msm_uart_driver;
+
+static struct console msm_console = {
+ .name = "ttyMSM",
+ .write = msm_console_write,
+ .device = uart_console_device,
+ .setup = msm_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &msm_uart_driver,
+};
+
+#define MSM_CONSOLE (&msm_console)
+
+#else
+#define MSM_CONSOLE NULL
+#endif
+
+static struct uart_driver msm_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "msm_serial",
+ .dev_name = "ttyMSM",
+ .nr = UART_NR,
+ .cons = MSM_CONSOLE,
+};
+
+static int __init msm_serial_probe(struct platform_device *pdev)
+{
+ struct msm_port *msm_port;
+ struct resource *resource;
+ struct uart_port *port;
+
+ if (pdev->id < 0 || pdev->id >= UART_NR)
+ return -ENXIO;
+
+ port = get_port_from_line(pdev->id);
+ port->dev = &pdev->dev;
+ msm_port = to_msm_uart(port);
+
+ msm_port->clk = clk_get(&pdev->dev, "uart_clk");
+ if (IS_ERR(msm_port->clk))
+ return PTR_ERR(msm_port->clk);
+ port->uartclk = clk_get_rate(msm_port->clk);
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!resource)
+ return -ENXIO;
+ port->mapbase = resource->start;
+
+ port->irq = platform_get_irq(pdev, 0);
+ if (port->irq < 0)
+ return -ENXIO;
+
+ platform_set_drvdata(pdev, port);
+
+ return uart_add_one_port(&msm_uart_driver, port);
+}
+
+static int __exit msm_serial_remove(struct platform_device *pdev)
+{
+ struct msm_port *msm_port = platform_get_drvdata(pdev);
+
+ clk_put(msm_port->clk);
+
+ return 0;
+}
+
+static struct platform_driver msm_platform_driver = {
+ .probe = msm_serial_probe,
+ .remove = __exit_p(msm_serial_remove),
+ .driver = {
+ .name = "msm_serial",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_serial_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&msm_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
+ if (ret)
+ uart_unregister_driver(&msm_uart_driver);
+
+ return ret;
+}
+
+static void __exit msm_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+ unregister_console(&msm_console);
+#endif
+ platform_driver_unregister(&msm_platform_driver);
+ uart_unregister_driver(&msm_uart_driver);
+}
+
+module_init(msm_serial_init);
+module_exit(msm_serial_exit);
+
+MODULE_AUTHOR("Robert Love <rlove@google.com>");
+MODULE_DESCRIPTION("Driver for msm7x serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
new file mode 100644
index 0000000..689f1fa
--- /dev/null
+++ b/drivers/serial/msm_serial.h
@@ -0,0 +1,117 @@
+/*
+ * drivers/serial/msm_serial.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
+#define __DRIVERS_SERIAL_MSM_SERIAL_H
+
+#define UART_MR1 0x0000
+
+#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
+#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
+#define UART_MR1_RX_RDY_CTL (1 << 7)
+#define UART_MR1_CTS_CTL (1 << 6)
+
+#define UART_MR2 0x0004
+#define UART_MR2_ERROR_MODE (1 << 6)
+#define UART_MR2_BITS_PER_CHAR 0x30
+#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
+#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
+#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
+#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
+#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
+#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
+#define UART_MR2_PARITY_MODE_NONE 0x0
+#define UART_MR2_PARITY_MODE_ODD 0x1
+#define UART_MR2_PARITY_MODE_EVEN 0x2
+#define UART_MR2_PARITY_MODE_SPACE 0x3
+#define UART_MR2_PARITY_MODE 0x3
+
+#define UART_CSR 0x0008
+#define UART_CSR_115200 0xFF
+#define UART_CSR_57600 0xEE
+#define UART_CSR_38400 0xDD
+#define UART_CSR_28800 0xCC
+#define UART_CSR_19200 0xBB
+#define UART_CSR_14400 0xAA
+#define UART_CSR_9600 0x99
+#define UART_CSR_4800 0x77
+#define UART_CSR_2400 0x55
+#define UART_CSR_1200 0x44
+#define UART_CSR_600 0x33
+#define UART_CSR_300 0x22
+
+#define UART_TF 0x000C
+
+#define UART_CR 0x0010
+#define UART_CR_CMD_NULL (0 << 4)
+#define UART_CR_CMD_RESET_RX (1 << 4)
+#define UART_CR_CMD_RESET_TX (2 << 4)
+#define UART_CR_CMD_RESET_ERR (3 << 4)
+#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
+#define UART_CR_CMD_START_BREAK (5 << 4)
+#define UART_CR_CMD_STOP_BREAK (6 << 4)
+#define UART_CR_CMD_RESET_CTS (7 << 4)
+#define UART_CR_CMD_PACKET_MODE (9 << 4)
+#define UART_CR_CMD_MODE_RESET (12 << 4)
+#define UART_CR_CMD_SET_RFR (13 << 4)
+#define UART_CR_CMD_RESET_RFR (14 << 4)
+#define UART_CR_TX_DISABLE (1 << 3)
+#define UART_CR_TX_ENABLE (1 << 3)
+#define UART_CR_RX_DISABLE (1 << 3)
+#define UART_CR_RX_ENABLE (1 << 3)
+
+#define UART_IMR 0x0014
+#define UART_IMR_TXLEV (1 << 0)
+#define UART_IMR_RXSTALE (1 << 3)
+#define UART_IMR_RXLEV (1 << 4)
+#define UART_IMR_DELTA_CTS (1 << 5)
+#define UART_IMR_CURRENT_CTS (1 << 6)
+
+#define UART_IPR_RXSTALE_LAST 0x20
+#define UART_IPR_STALE_LSB 0x1F
+#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
+
+#define UART_IPR 0x0018
+#define UART_TFWR 0x001C
+#define UART_RFWR 0x0020
+#define UART_HCR 0x0024
+
+#define UART_MREG 0x0028
+#define UART_NREG 0x002C
+#define UART_DREG 0x0030
+#define UART_MNDREG 0x0034
+#define UART_IRDA 0x0038
+#define UART_MISR_MODE 0x0040
+#define UART_MISR_RESET 0x0044
+#define UART_MISR_EXPORT 0x0048
+#define UART_MISR_VAL 0x004C
+#define UART_TEST_CTRL 0x0050
+
+#define UART_SR 0x0008
+#define UART_SR_HUNT_CHAR (1 << 7)
+#define UART_SR_RX_BREAK (1 << 6)
+#define UART_SR_PAR_FRAME_ERR (1 << 5)
+#define UART_SR_OVERRUN (1 << 4)
+#define UART_SR_TX_EMPTY (1 << 3)
+#define UART_SR_TX_READY (1 << 2)
+#define UART_SR_RX_FULL (1 << 1)
+#define UART_SR_RX_READY (1 << 0)
+
+#define UART_RF 0x000C
+#define UART_MISR 0x0010
+#define UART_ISR 0x0014
+
+#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 6fd80c4..23d2fb0 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -171,6 +171,9 @@
/* Timberdale UART */
#define PORT_TIMBUART 87
+/* Qualcomm MSM SoCs */
+#define PORT_MSM 88
+
#ifdef __KERNEL__
#include <linux/compiler.h>
--
1.6.2.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable
2009-06-18 0:31 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
@ 2009-06-18 0:31 ` Brian Swetland
2009-06-18 0:31 ` [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device Brian Swetland
2009-06-18 10:26 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Pavel Machek
2009-06-18 9:20 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Alan Cox
1 sibling, 2 replies; 22+ messages in thread
From: Brian Swetland @ 2009-06-18 0:31 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: linux-kernel, pavel, Brian Swetland
Provides options to select one of the three "lowspeed" UARTs
on MSM7k SoCs for DEBUG_LL output from the zImage decompressor
and kernel.
Signed-off-by: Brian Swetland <swetland@google.com>
---
arch/arm/mach-msm/Kconfig | 24 ++++++++++++++++++++++++
arch/arm/mach-msm/include/mach/debug-macro.S | 24 +++++++++++++++++-------
arch/arm/mach-msm/include/mach/msm_iomap.h | 12 ++++++++++++
arch/arm/mach-msm/include/mach/uncompress.h | 7 +++++++
arch/arm/mach-msm/io.c | 3 +++
5 files changed, 63 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index d140abc..35f2a90 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -3,6 +3,30 @@ if ARCH_MSM
comment "MSM Board Type"
depends on ARCH_MSM
+config MSM_DEBUG_UART
+ int
+ default 1 if MSM_DEBUG_UART1
+ default 2 if MSM_DEBUG_UART2
+ default 3 if MSM_DEBUG_UART3
+
+choice
+ prompt "Debug UART"
+
+ default MSM_DEBUG_UART_NONE
+
+ config MSM_DEBUG_UART_NONE
+ bool "None"
+
+ config MSM_DEBUG_UART1
+ bool "UART1"
+
+ config MSM_DEBUG_UART2
+ bool "UART2"
+
+ config MSM_DEBUG_UART3
+ bool "UART3"
+endchoice
+
config MACH_HALIBUT
depends on ARCH_MSM
default y
diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S
index 1db3c97..d48747e 100644
--- a/arch/arm/mach-msm/include/mach/debug-macro.S
+++ b/arch/arm/mach-msm/include/mach/debug-macro.S
@@ -14,15 +14,18 @@
*
*/
+
+
#include <mach/hardware.h>
#include <mach/msm_iomap.h>
+#ifdef CONFIG_MSM_DEBUG_UART
.macro addruart,rx
@ see if the MMU is enabled and select appropriate base address
mrc p15, 0, \rx, c1, c0
tst \rx, #1
- ldreq \rx, =MSM_UART1_PHYS
- movne \rx, #0
+ ldreq \rx, =MSM_DEBUG_UART_PHYS
+ ldrne \rx, =MSM_DEBUG_UART_BASE
.endm
.macro senduart,rd,rx
@@ -32,13 +35,20 @@
.macro waituart,rd,rx
@ wait for TX_READY
- teq \rx, #0
- bne 2f
-1: ldr \rd, [\rx, #0x08]
+1001: ldr \rd, [\rx, #0x08]
tst \rd, #0x04
- beq 1b
-2:
+ beq 1001b
+ .endm
+#else
+ .macro addruart,rx
+ .endm
+
+ .macro senduart,rd,rx
+ .endm
+
+ .macro waituart,rd,rx
.endm
+#endif
.macro busyuart,rd,rx
.endm
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 2f7b4c8..9dae1a9 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -84,6 +84,18 @@
#define MSM_UART3_PHYS 0xA9C00000
#define MSM_UART3_SIZE SZ_4K
+#ifdef CONFIG_MSM_DEBUG_UART
+#define MSM_DEBUG_UART_BASE 0xE1000000
+#if CONFIG_MSM_DEBUG_UART == 1
+#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS
+#elif CONFIG_MSM_DEBUG_UART == 2
+#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS
+#elif CONFIG_MSM_DEBUG_UART == 3
+#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS
+#endif
+#define MSM_DEBUG_UART_SIZE SZ_4K
+#endif
+
#define MSM_SDC1_PHYS 0xA0400000
#define MSM_SDC1_SIZE SZ_4K
diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h
index 026e895..d94292c 100644
--- a/arch/arm/mach-msm/include/mach/uncompress.h
+++ b/arch/arm/mach-msm/include/mach/uncompress.h
@@ -16,9 +16,16 @@
#ifndef __ASM_ARCH_MSM_UNCOMPRESS_H
#include "hardware.h"
+#include "linux/io.h"
+#include "mach/msm_iomap.h"
static void putc(int c)
{
+#if defined(MSM_DEBUG_UART_PHYS)
+ unsigned base = MSM_DEBUG_UART_PHYS;
+ while (!(readl(base + 0x08) & 0x04)) ;
+ writel(c, base + 0x0c);
+#endif
}
static inline void flush(void)
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 6e7692f..1c5e7da 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -42,6 +42,9 @@ static struct map_desc msm_io_desc[] __initdata = {
MSM_DEVICE(GPIO1),
MSM_DEVICE(GPIO2),
MSM_DEVICE(CLK_CTL),
+#ifdef CONFIG_MSM_DEBUG_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
{
.virtual = (unsigned long) MSM_SHARED_RAM_BASE,
.pfn = __phys_to_pfn(MSM_SHARED_RAM_PHYS),
--
1.6.2.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device
2009-06-18 0:31 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Brian Swetland
@ 2009-06-18 0:31 ` Brian Swetland
2009-06-18 1:56 ` GeunSik Lim
2009-06-18 10:26 ` Pavel Machek
2009-06-18 10:26 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Pavel Machek
1 sibling, 2 replies; 22+ messages in thread
From: Brian Swetland @ 2009-06-18 0:31 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: linux-kernel, pavel, Brian Swetland
This is just enough to get the device booting and serial console
working. Sufficient for debugging further MSM7k/Dream Support.
This will support HTC Dream / T-Mobile G1 / Android ADP1 (which
are all the same hardware, known as "trout" to the ARM machine
database).
Signed-off-by: Brian Swetland <swetland@google.com>
---
arch/arm/mach-msm/Kconfig | 6 +++
arch/arm/mach-msm/Makefile | 1 +
arch/arm/mach-msm/board-dream.c | 84 +++++++++++++++++++++++++++++++++++++++
arch/arm/mach-msm/board-dream.h | 5 ++
4 files changed, 96 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-msm/board-dream.c
create mode 100644 arch/arm/mach-msm/board-dream.h
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 35f2a90..f780086 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -34,4 +34,10 @@ config MACH_HALIBUT
help
Support for the Qualcomm SURF7201A eval board.
+config MACH_TROUT
+ default y
+ bool "HTC Dream (aka trout)"
+ help
+ Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
+
endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 1aa4700..91e6f5c 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -6,3 +6,4 @@ obj-y += clock.o clock-7x01a.o
obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
+obj-$(CONFIG_MACH_TROUT) += board-dream.o
diff --git a/arch/arm/mach-msm/board-dream.c b/arch/arm/mach-msm/board-dream.c
new file mode 100644
index 0000000..6eae7e3
--- /dev/null
+++ b/arch/arm/mach-msm/board-dream.c
@@ -0,0 +1,84 @@
+/* linux/arch/arm/mach-msm/board-dream.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board.h>
+#include <mach/hardware.h>
+#include <mach/msm_iomap.h>
+
+#include "devices.h"
+#include "board-dream.h"
+
+static struct platform_device *devices[] __initdata = {
+ &msm_device_uart3,
+ &msm_device_smd,
+ &msm_device_nand,
+ &msm_device_hsusb,
+ &msm_device_i2c,
+};
+
+extern struct sys_timer msm_timer;
+
+static void __init trout_init_irq(void)
+{
+ msm_init_irq();
+}
+
+static void __init trout_init(void)
+{
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static struct map_desc trout_io_desc[] __initdata = {
+ {
+ .virtual = TROUT_CPLD_BASE,
+ .pfn = __phys_to_pfn(TROUT_CPLD_START),
+ .length = TROUT_CPLD_SIZE,
+ .type = MT_DEVICE_NONSHARED
+ }
+};
+
+static void __init trout_map_io(void)
+{
+ msm_map_common_io();
+ iotable_init(trout_io_desc, ARRAY_SIZE(trout_io_desc));
+
+#ifdef CONFIG_MSM_DEBUG_UART3
+ /* route UART3 to the "H2W" extended usb connector */
+ writeb(0x80, TROUT_CPLD_BASE + 0x00);
+#endif
+
+ msm_clock_init();
+}
+
+MACHINE_START(TROUT, "HTC Dream")
+#ifdef CONFIG_MSM_DEBUG_UART
+ .phys_io = MSM_DEBUG_UART_PHYS,
+ .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
+#endif
+ .boot_params = 0x10000100,
+ .map_io = trout_map_io,
+ .init_irq = trout_init_irq,
+ .init_machine = trout_init,
+ .timer = &msm_timer,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-dream.h b/arch/arm/mach-msm/board-dream.h
new file mode 100644
index 0000000..4f345a5
--- /dev/null
+++ b/arch/arm/mach-msm/board-dream.h
@@ -0,0 +1,5 @@
+
+#define TROUT_CPLD_BASE 0xE8100000
+#define TROUT_CPLD_START 0x98000000
+#define TROUT_CPLD_SIZE SZ_4K
+
--
1.6.2.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device
2009-06-18 0:31 ` [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device Brian Swetland
@ 2009-06-18 1:56 ` GeunSik Lim
2009-06-18 2:44 ` Brian Swetland
2009-06-18 10:26 ` Pavel Machek
1 sibling, 1 reply; 22+ messages in thread
From: GeunSik Lim @ 2009-06-18 1:56 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel, pavel
On Thu, Jun 18, 2009 at 9:31 AM, Brian Swetland<swetland@google.com> wrote:
> This is just enough to get the device booting and serial console
> working. Sufficient for debugging further MSM7k/Dream Support.
> This will support HTC Dream / T-Mobile G1 / Android ADP1 (which
> are all the same hardware, known as "trout" to the ARM machine
> database).
Hi Brian,
I have one silly question.
I still not understand "trout" meaning with your description.
> +config MACH_TROUT
> + default y
> + bool "HTC Dream (aka trout)"
> + help
> + Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
> +
"trout" word just means HTC Dream Model. Is it right?
Thks,
--
Regards,
GeunSik Lim ( Samsung Electronics )
Blog : http://blog.naver.com/invain/
e-Mail: geunsik.lim@samsung.com
leemgs@gmail.com , leemgs1@gmail.com
--
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/
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device
2009-06-18 1:56 ` GeunSik Lim
@ 2009-06-18 2:44 ` Brian Swetland
2009-06-18 14:01 ` GeunSik Lim
0 siblings, 1 reply; 22+ messages in thread
From: Brian Swetland @ 2009-06-18 2:44 UTC (permalink / raw)
To: GeunSik Lim; +Cc: linux-arm-kernel, linux-kernel, pavel
On Wed, Jun 17, 2009 at 6:56 PM, GeunSik Lim<leemgs1@gmail.com> wrote:
> On Thu, Jun 18, 2009 at 9:31 AM, Brian Swetland<swetland@google.com> wrote:
>> This is just enough to get the device booting and serial console
>> working. Sufficient for debugging further MSM7k/Dream Support.
>> This will support HTC Dream / T-Mobile G1 / Android ADP1 (which
>> are all the same hardware, known as "trout" to the ARM machine
>> database).
> Hi Brian,
> I have one silly question.
> I still not understand "trout" meaning with your description.
>
>> +config MACH_TROUT
>> + default y
>> + bool "HTC Dream (aka trout)"
>> + help
>> + Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
>> +
> "trout" word just means HTC Dream Model. Is it right?
Yes -- this is the ARM linux kernel machine ID for this hardware:
http://www.arm.linux.org.uk/developer/machines/list.php?id=1440
Brian
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-18 0:31 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
2009-06-18 0:31 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Brian Swetland
@ 2009-06-18 9:20 ` Alan Cox
2009-06-18 19:29 ` Brian Swetland
1 sibling, 1 reply; 22+ messages in thread
From: Alan Cox @ 2009-06-18 9:20 UTC (permalink / raw)
To: Brian Swetland
Cc: linux-arm-kernel, linux-kernel, pavel, Robert Love, Brian Swetland
On Wed, 17 Jun 2009 17:31:13 -0700
Brian Swetland <swetland@google.com> wrote:
> From: Robert Love <rlove@google.com>
>
> Provides support for the "lowspeed" UARTs on the MSM7k and QSD8k
> family of SoCs from Qualcomm. Serial console support included.
>
> Signed-off-by: Robert Love <rlove@google.com>
> Signed-off-by: Brian Swetland <swetland@google.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
If you fold other peoples patches into something please preserve the
authorship data and preferably keep the two patches separated as it
otherwise causes merge problems if stuff (eg the serial patches) goes via
two trees at once.
At the moment the ttydev tree has
-> your original -> my (intel's I guess) fixes ->
and if the updated one also went in via the arm tree git can't always
figure out what is going on.
If its only going by one path and you know that then just adding an
additional note on the authorship of updates is fine but this being
serial/tty and ARM is likely to hit both trees.
Alan
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable
2009-06-18 0:31 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Brian Swetland
2009-06-18 0:31 ` [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device Brian Swetland
@ 2009-06-18 10:26 ` Pavel Machek
1 sibling, 0 replies; 22+ messages in thread
From: Pavel Machek @ 2009-06-18 10:26 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel
On Wed 2009-06-17 17:31:14, Brian Swetland wrote:
> Provides options to select one of the three "lowspeed" UARTs
> on MSM7k SoCs for DEBUG_LL output from the zImage decompressor
> and kernel.
>
> Signed-off-by: Brian Swetland <swetland@google.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device
2009-06-18 0:31 ` [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device Brian Swetland
2009-06-18 1:56 ` GeunSik Lim
@ 2009-06-18 10:26 ` Pavel Machek
1 sibling, 0 replies; 22+ messages in thread
From: Pavel Machek @ 2009-06-18 10:26 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel
On Wed 2009-06-17 17:31:15, Brian Swetland wrote:
> This is just enough to get the device booting and serial console
> working. Sufficient for debugging further MSM7k/Dream Support.
> This will support HTC Dream / T-Mobile G1 / Android ADP1 (which
> are all the same hardware, known as "trout" to the ARM machine
> database).
>
> Signed-off-by: Brian Swetland <swetland@google.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device
2009-06-18 2:44 ` Brian Swetland
@ 2009-06-18 14:01 ` GeunSik Lim
0 siblings, 0 replies; 22+ messages in thread
From: GeunSik Lim @ 2009-06-18 14:01 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel, pavel
On Thu, Jun 18, 2009 at 11:44 AM, Brian Swetland<swetland@google.com> wrote:
> On Wed, Jun 17, 2009 at 6:56 PM, GeunSik Lim<leemgs1@gmail.com> wrote:
>> On Thu, Jun 18, 2009 at 9:31 AM, Brian Swetland<swetland@google.com> wrote:
>>> This is just enough to get the device booting and serial console
>>> working. Sufficient for debugging further MSM7k/Dream Support.
>>> This will support HTC Dream / T-Mobile G1 / Android ADP1 (which
>>> are all the same hardware, known as "trout" to the ARM machine
>>> database).
>> Hi Brian,
>> I have one silly question.
>> I still not understand "trout" meaning with your description.
>>
>>> +config MACH_TROUT
>>> + default y
>>> + bool "HTC Dream (aka trout)"
>>> + help
>>> + Support for the HTC Dream, T-Mobile G1, Android ADP1 devices.
>>> +
>> "trout" word just means HTC Dream Model. Is it right?
>
> Yes -- this is the ARM linux kernel machine ID for this hardware:
> http://www.arm.linux.org.uk/developer/machines/list.php?id=1440
>
> Brian
>
Looks good to me.
Reviewed-by: GeunSik Lim <geunsik.lim@samsung.com>
--
Regards,
GeunSik Lim ( Samsung Electronics )
Blog : http://blog.naver.com/invain/
e-Mail: geunsik.lim@samsung.com
leemgs@gmail.com , leemgs1@gmail.com
--
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/
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-18 9:20 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Alan Cox
@ 2009-06-18 19:29 ` Brian Swetland
0 siblings, 0 replies; 22+ messages in thread
From: Brian Swetland @ 2009-06-18 19:29 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-arm-kernel, linux-kernel, pavel, Robert Love
On Thu, Jun 18, 2009 at 2:20 AM, Alan Cox<alan@lxorguk.ukuu.org.uk> wrote:
> On Wed, 17 Jun 2009 17:31:13 -0700
> Brian Swetland <swetland@google.com> wrote:
>
>> From: Robert Love <rlove@google.com>
>>
>> Provides support for the "lowspeed" UARTs on the MSM7k and QSD8k
>> family of SoCs from Qualcomm. Serial console support included.
>>
>> Signed-off-by: Robert Love <rlove@google.com>
>> Signed-off-by: Brian Swetland <swetland@google.com>
>> Acked-by: Pavel Machek <pavel@ucw.cz>
>
> If you fold other peoples patches into something please preserve the
> authorship data and preferably keep the two patches separated as it
> otherwise causes merge problems if stuff (eg the serial patches) goes via
> two trees at once.
Ah, sorry about that -- I can resend the revised patch that your patch
applies against (but without your changes merged in). Previously, for
the ARM stuff I got the impression that a single patch folding small
changes in was preferred, but I may have misunderstood the workflow.
> At the moment the ttydev tree has
> -> your original -> my (intel's I guess) fixes ->
>
> and if the updated one also went in via the arm tree git can't always
> figure out what is going on.
>
> If its only going by one path and you know that then just adding an
> additional note on the authorship of updates is fine but this being
> serial/tty and ARM is likely to hit both trees.
>
> Alan
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 2:39 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
` (3 preceding siblings ...)
2009-06-15 9:05 ` Linus Walleij
@ 2009-06-17 12:17 ` Robert Love
4 siblings, 0 replies; 22+ messages in thread
From: Robert Love @ 2009-06-17 12:17 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel, pavel
Signed-off-by: Robert Love <rlove@google.com>
Robert
On Sun, Jun 14, 2009 at 10:39 PM, Brian Swetland<swetland@google.com> wrote:
> From: Robert Love <rlove@google.com>
>
> Signed-off-by: Brian Swetland <swetland@google.com>
> ---
> drivers/serial/Kconfig | 10 +
> drivers/serial/Makefile | 1 +
> drivers/serial/msm_serial.c | 767 +++++++++++++++++++++++++++++++++++++++++++
> drivers/serial/msm_serial.h | 117 +++++++
> include/linux/serial_core.h | 3 +
> 5 files changed, 898 insertions(+), 0 deletions(-)
> create mode 100644 drivers/serial/msm_serial.c
> create mode 100644 drivers/serial/msm_serial.h
>
> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
> index 1132c5c..037c1e0 100644
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -1320,6 +1320,16 @@ config SERIAL_SGI_IOC3
> If you have an SGI Altix with an IOC3 serial card,
> say Y or M. Otherwise, say N.
>
> +config SERIAL_MSM
> + bool "MSM on-chip serial port support"
> + depends on ARM && ARCH_MSM
> + select SERIAL_CORE
> +
> +config SERIAL_MSM_CONSOLE
> + bool "MSM serial console support"
> + depends on SERIAL_MSM=y
> + select SERIAL_CORE_CONSOLE
> +
> config SERIAL_NETX
> tristate "NetX serial port support"
> depends on ARM && ARCH_NETX
> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
> index 45a8658..d5a2998 100644
> --- a/drivers/serial/Makefile
> +++ b/drivers/serial/Makefile
> @@ -71,6 +71,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
> obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
> obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
> obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
> +obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
> obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
> obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
> obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
> diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
> new file mode 100644
> index 0000000..1a7c856
> --- /dev/null
> +++ b/drivers/serial/msm_serial.c
> @@ -0,0 +1,767 @@
> +/*
> + * drivers/serial/msm_serial.c - driver for msm7k serial device and console
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Robert Love <rlove@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +# define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/hrtimer.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/irq.h>
> +#include <linux/init.h>
> +#include <linux/console.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/serial_core.h>
> +#include <linux/serial.h>
> +#include <linux/clk.h>
> +#include <linux/platform_device.h>
> +
> +#include "msm_serial.h"
> +
> +struct msm_port {
> + struct uart_port uart;
> + char name[16];
> + struct clk *clk;
> + unsigned int imr;
> +};
> +
> +#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
> +
> +static inline void msm_write(struct uart_port *port, unsigned int val,
> + unsigned int off)
> +{
> + __raw_writel(val, port->membase + off);
> +}
> +
> +static inline unsigned int msm_read(struct uart_port *port, unsigned int off)
> +{
> + return __raw_readl(port->membase + off);
> +}
> +
> +static void msm_stop_tx(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr &= ~UART_IMR_TXLEV;
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void msm_start_tx(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr |= UART_IMR_TXLEV;
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void msm_stop_rx(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void msm_enable_ms(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr |= UART_IMR_DELTA_CTS;
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void handle_rx(struct uart_port *port)
> +{
> + struct tty_struct *tty = port->info->port.tty;
> + unsigned int sr;
> +
> + /*
> + * Handle overrun. My understanding of the hardware is that overrun
> + * is not tied to the RX buffer, so we handle the case out of band.
> + */
> + if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
> + port->icount.overrun++;
> + tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
> + }
> +
> + /* and now the main RX loop */
> + while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
> + unsigned int c;
> + char flag = TTY_NORMAL;
> +
> + c = msm_read(port, UART_RF);
> +
> + if (sr & UART_SR_RX_BREAK) {
> + port->icount.brk++;
> + if (uart_handle_break(port))
> + continue;
> + } else if (sr & UART_SR_PAR_FRAME_ERR) {
> + port->icount.frame++;
> + } else {
> + port->icount.rx++;
> + }
> +
> + /* Mask conditions we're ignorning. */
> + sr &= port->read_status_mask;
> +
> + if (sr & UART_SR_RX_BREAK) {
> + flag = TTY_BREAK;
> + } else if (sr & UART_SR_PAR_FRAME_ERR) {
> + flag = TTY_FRAME;
> + }
> +
> + if (!uart_handle_sysrq_char(port, c))
> + tty_insert_flip_char(tty, c, flag);
> + }
> +
> + tty_flip_buffer_push(tty);
> +}
> +
> +static void handle_tx(struct uart_port *port)
> +{
> + struct circ_buf *xmit = &port->info->xmit;
> + struct msm_port *msm_port = UART_TO_MSM(port);
> + int sent_tx;
> +
> + if (port->x_char) {
> + msm_write(port, port->x_char, UART_TF);
> + port->icount.tx++;
> + port->x_char = 0;
> + }
> +
> + while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
> + if (uart_circ_empty(xmit)) {
> + /* disable tx interrupts */
> + msm_port->imr &= ~UART_IMR_TXLEV;
> + msm_write(port, msm_port->imr, UART_IMR);
> + break;
> + }
> +
> + msm_write(port, xmit->buf[xmit->tail], UART_TF);
> +
> + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> + port->icount.tx++;
> + sent_tx = 1;
> + }
> +
> + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> + uart_write_wakeup(port);
> +}
> +
> +static void handle_delta_cts(struct uart_port *port)
> +{
> + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
> + port->icount.cts++;
> + wake_up_interruptible(&port->info->delta_msr_wait);
> +}
> +
> +static irqreturn_t msm_irq(int irq, void *dev_id)
> +{
> + struct uart_port *port = dev_id;
> + struct msm_port *msm_port = UART_TO_MSM(port);
> + unsigned int misr;
> +
> + spin_lock(&port->lock);
> + misr = msm_read(port, UART_MISR);
> + msm_write(port, 0, UART_IMR); /* disable interrupt */
> +
> + if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
> + handle_rx(port);
> + if (misr & UART_IMR_TXLEV)
> + handle_tx(port);
> + if (misr & UART_IMR_DELTA_CTS)
> + handle_delta_cts(port);
> +
> + msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
> + spin_unlock(&port->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static unsigned int msm_tx_empty(struct uart_port *port)
> +{
> + return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
> +}
> +
> +static unsigned int msm_get_mctrl(struct uart_port *port)
> +{
> + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
> +}
> +
> +static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> + unsigned int mr;
> +
> + mr = msm_read(port, UART_MR1);
> +
> + if (!(mctrl & TIOCM_RTS)) {
> + mr &= ~UART_MR1_RX_RDY_CTL;
> + msm_write(port, mr, UART_MR1);
> + msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
> + } else {
> + mr |= UART_MR1_RX_RDY_CTL;
> + msm_write(port, mr, UART_MR1);
> + }
> +}
> +
> +static void msm_break_ctl(struct uart_port *port, int break_ctl)
> +{
> + if (break_ctl)
> + msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
> + else
> + msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
> +}
> +
> +static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
> +{
> + unsigned int baud_code, rxstale, watermark;
> +
> + switch (baud) {
> + case 300:
> + baud_code = UART_CSR_300;
> + rxstale = 1;
> + break;
> + case 600:
> + baud_code = UART_CSR_600;
> + rxstale = 1;
> + break;
> + case 1200:
> + baud_code = UART_CSR_1200;
> + rxstale = 1;
> + break;
> + case 2400:
> + baud_code = UART_CSR_2400;
> + rxstale = 1;
> + break;
> + case 4800:
> + baud_code = UART_CSR_4800;
> + rxstale = 1;
> + break;
> + case 9600:
> + baud_code = UART_CSR_9600;
> + rxstale = 2;
> + break;
> + case 14400:
> + baud_code = UART_CSR_14400;
> + rxstale = 3;
> + break;
> + case 19200:
> + baud_code = UART_CSR_19200;
> + rxstale = 4;
> + break;
> + case 28800:
> + baud_code = UART_CSR_28800;
> + rxstale = 6;
> + break;
> + case 38400:
> + baud_code = UART_CSR_38400;
> + rxstale = 8;
> + break;
> + case 57600:
> + baud_code = UART_CSR_57600;
> + rxstale = 16;
> + break;
> + case 115200:
> + default:
> + baud_code = UART_CSR_115200;
> + rxstale = 31;
> + break;
> + }
> +
> + msm_write(port, baud_code, UART_CSR);
> +
> + /* RX stale watermark */
> + watermark = UART_IPR_STALE_LSB & rxstale;
> + watermark |= UART_IPR_RXSTALE_LAST;
> + watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
> + msm_write(port, watermark, UART_IPR);
> +
> + /* set RX watermark */
> + watermark = (port->fifosize * 3) / 4;
> + msm_write(port, watermark, UART_RFWR);
> +
> + /* set TX watermark */
> + msm_write(port, 10, UART_TFWR);
> +}
> +
> +static void msm_reset(struct uart_port *port)
> +{
> + /* reset everything */
> + msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
> + msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
> +}
> +
> +static void msm_init_clock(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + clk_enable(msm_port->clk);
> +
> + msm_write(port, 0xC0, UART_MREG);
> + msm_write(port, 0xB2, UART_NREG);
> + msm_write(port, 0x7D, UART_DREG);
> + msm_write(port, 0x1C, UART_MNDREG);
> +}
> +
> +static int msm_startup(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> + unsigned int data, rfr_level;
> + int ret;
> +
> + snprintf(msm_port->name, sizeof(msm_port->name),
> + "msm_serial%d", port->line);
> +
> + ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
> + msm_port->name, port);
> + if (unlikely(ret))
> + return ret;
> +
> + msm_init_clock(port);
> +
> + if (likely(port->fifosize > 12))
> + rfr_level = port->fifosize - 12;
> + else
> + rfr_level = port->fifosize;
> +
> + /* set automatic RFR level */
> + data = msm_read(port, UART_MR1);
> + data &= ~UART_MR1_AUTO_RFR_LEVEL1;
> + data &= ~UART_MR1_AUTO_RFR_LEVEL0;
> + data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
> + data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
> + msm_write(port, data, UART_MR1);
> +
> + /* make sure that RXSTALE count is non-zero */
> + data = msm_read(port, UART_IPR);
> + if (unlikely(!data)) {
> + data |= UART_IPR_RXSTALE_LAST;
> + data |= UART_IPR_STALE_LSB;
> + msm_write(port, data, UART_IPR);
> + }
> +
> + msm_reset(port);
> +
> + msm_write(port, 0x05, UART_CR); /* enable TX & RX */
> +
> + /* turn on RX and CTS interrupts */
> + msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
> + UART_IMR_CURRENT_CTS;
> + msm_write(port, msm_port->imr, UART_IMR);
> +
> + return 0;
> +}
> +
> +static void msm_shutdown(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr = 0;
> + msm_write(port, 0, UART_IMR); /* disable interrupts */
> +
> + clk_disable(msm_port->clk);
> +
> + free_irq(port->irq, port);
> +}
> +
> +static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
> + struct ktermios *old)
> +{
> + unsigned long flags;
> + unsigned int baud, mr;
> +
> + spin_lock_irqsave(&port->lock, flags);
> +
> + /* calculate and set baud rate */
> + baud = uart_get_baud_rate(port, termios, old, 300, 115200);
> + msm_set_baud_rate(port, baud);
> +
> + /* calculate parity */
> + mr = msm_read(port, UART_MR2);
> + mr &= ~UART_MR2_PARITY_MODE;
> + if (termios->c_cflag & PARENB) {
> + if (termios->c_cflag & PARODD)
> + mr |= UART_MR2_PARITY_MODE_ODD;
> + else if (termios->c_cflag & CMSPAR)
> + mr |= UART_MR2_PARITY_MODE_SPACE;
> + else
> + mr |= UART_MR2_PARITY_MODE_EVEN;
> + }
> +
> + /* calculate bits per char */
> + mr &= ~UART_MR2_BITS_PER_CHAR;
> + switch (termios->c_cflag & CSIZE) {
> + case CS5:
> + mr |= UART_MR2_BITS_PER_CHAR_5;
> + break;
> + case CS6:
> + mr |= UART_MR2_BITS_PER_CHAR_6;
> + break;
> + case CS7:
> + mr |= UART_MR2_BITS_PER_CHAR_7;
> + break;
> + case CS8:
> + default:
> + mr |= UART_MR2_BITS_PER_CHAR_8;
> + break;
> + }
> +
> + /* calculate stop bits */
> + mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
> + if (termios->c_cflag & CSTOPB)
> + mr |= UART_MR2_STOP_BIT_LEN_TWO;
> + else
> + mr |= UART_MR2_STOP_BIT_LEN_ONE;
> +
> + /* set parity, bits per char, and stop bit */
> + msm_write(port, mr, UART_MR2);
> +
> + /* calculate and set hardware flow control */
> + mr = msm_read(port, UART_MR1);
> + mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
> + if (termios->c_cflag & CRTSCTS) {
> + mr |= UART_MR1_CTS_CTL;
> + mr |= UART_MR1_RX_RDY_CTL;
> + }
> + msm_write(port, mr, UART_MR1);
> +
> + /* Configure status bits to ignore based on termio flags. */
> + port->read_status_mask = 0;
> + if (termios->c_iflag & INPCK)
> + port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
> + if (termios->c_iflag & (BRKINT | PARMRK))
> + port->read_status_mask |= UART_SR_RX_BREAK;
> +
> + uart_update_timeout(port, termios->c_cflag, baud);
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *msm_type(struct uart_port *port)
> +{
> + return "MSM";
> +}
> +
> +static void msm_release_port(struct uart_port *port)
> +{
> + struct platform_device *pdev = to_platform_device(port->dev);
> + struct resource *resource;
> + resource_size_t size;
> +
> + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (unlikely(!resource))
> + return;
> + size = resource->end - resource->start + 1;
> +
> + release_mem_region(port->mapbase, size);
> + iounmap(port->membase);
> + port->membase = NULL;
> +}
> +
> +static int msm_request_port(struct uart_port *port)
> +{
> + struct platform_device *pdev = to_platform_device(port->dev);
> + struct resource *resource;
> + resource_size_t size;
> +
> + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (unlikely(!resource))
> + return -ENXIO;
> + size = resource->end - resource->start + 1;
> +
> + if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
> + return -EBUSY;
> +
> + port->membase = ioremap(port->mapbase, size);
> + if (!port->membase) {
> + release_mem_region(port->mapbase, size);
> + return -EBUSY;
> + }
> +
> + return 0;
> +}
> +
> +static void msm_config_port(struct uart_port *port, int flags)
> +{
> + if (flags & UART_CONFIG_TYPE) {
> + port->type = PORT_MSM;
> + msm_request_port(port);
> + }
> +}
> +
> +static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> + if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
> + return -EINVAL;
> + if (unlikely(port->irq != ser->irq))
> + return -EINVAL;
> + return 0;
> +}
> +
> +static void msm_power(struct uart_port *port, unsigned int state,
> + unsigned int oldstate)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + switch (state) {
> + case 0:
> + clk_enable(msm_port->clk);
> + break;
> + case 3:
> + clk_disable(msm_port->clk);
> + break;
> + default:
> + printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
> + }
> +}
> +
> +static struct uart_ops msm_uart_pops = {
> + .tx_empty = msm_tx_empty,
> + .set_mctrl = msm_set_mctrl,
> + .get_mctrl = msm_get_mctrl,
> + .stop_tx = msm_stop_tx,
> + .start_tx = msm_start_tx,
> + .stop_rx = msm_stop_rx,
> + .enable_ms = msm_enable_ms,
> + .break_ctl = msm_break_ctl,
> + .startup = msm_startup,
> + .shutdown = msm_shutdown,
> + .set_termios = msm_set_termios,
> + .type = msm_type,
> + .release_port = msm_release_port,
> + .request_port = msm_request_port,
> + .config_port = msm_config_port,
> + .verify_port = msm_verify_port,
> + .pm = msm_power,
> +};
> +
> +static struct msm_port msm_uart_ports[] = {
> + {
> + .uart = {
> + .iotype = UPIO_MEM,
> + .ops = &msm_uart_pops,
> + .flags = UPF_BOOT_AUTOCONF,
> + .fifosize = 512,
> + .line = 0,
> + },
> + },
> + {
> + .uart = {
> + .iotype = UPIO_MEM,
> + .ops = &msm_uart_pops,
> + .flags = UPF_BOOT_AUTOCONF,
> + .fifosize = 512,
> + .line = 1,
> + },
> + },
> + {
> + .uart = {
> + .iotype = UPIO_MEM,
> + .ops = &msm_uart_pops,
> + .flags = UPF_BOOT_AUTOCONF,
> + .fifosize = 64,
> + .line = 2,
> + },
> + },
> +};
> +
> +#define UART_NR ARRAY_SIZE(msm_uart_ports)
> +
> +static inline struct uart_port *get_port_from_line(unsigned int line)
> +{
> + return &msm_uart_ports[line].uart;
> +}
> +
> +#ifdef CONFIG_SERIAL_MSM_CONSOLE
> +
> +static void msm_console_putchar(struct uart_port *port, int c)
> +{
> + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
> + ;
> + msm_write(port, c, UART_TF);
> +}
> +
> +static void msm_console_write(struct console *co, const char *s,
> + unsigned int count)
> +{
> + struct uart_port *port;
> + struct msm_port *msm_port;
> +
> + BUG_ON(co->index < 0 || co->index >= UART_NR);
> +
> + port = get_port_from_line(co->index);
> + msm_port = UART_TO_MSM(port);
> +
> + spin_lock(&port->lock);
> + uart_console_write(port, s, count, msm_console_putchar);
> + spin_unlock(&port->lock);
> +}
> +
> +static int __init msm_console_setup(struct console *co, char *options)
> +{
> + struct uart_port *port;
> + int baud, flow, bits, parity;
> +
> + if (unlikely(co->index >= UART_NR || co->index < 0))
> + return -ENXIO;
> +
> + port = get_port_from_line(co->index);
> +
> + if (unlikely(!port->membase))
> + return -ENXIO;
> +
> + port->cons = co;
> +
> + msm_init_clock(port);
> +
> + if (options)
> + uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> + bits = 8;
> + parity = 'n';
> + flow = 'n';
> + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
> + UART_MR2); /* 8N1 */
> +
> + if (baud < 300 || baud > 115200)
> + baud = 115200;
> + msm_set_baud_rate(port, baud);
> +
> + msm_reset(port);
> +
> + printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
> +
> + return uart_set_options(port, co, baud, parity, bits, flow);
> +}
> +
> +static struct uart_driver msm_uart_driver;
> +
> +static struct console msm_console = {
> + .name = "ttyMSM",
> + .write = msm_console_write,
> + .device = uart_console_device,
> + .setup = msm_console_setup,
> + .flags = CON_PRINTBUFFER,
> + .index = -1,
> + .data = &msm_uart_driver,
> +};
> +
> +#define MSM_CONSOLE (&msm_console)
> +
> +#else
> +#define MSM_CONSOLE NULL
> +#endif
> +
> +static struct uart_driver msm_uart_driver = {
> + .owner = THIS_MODULE,
> + .driver_name = "msm_serial",
> + .dev_name = "ttyMSM",
> + .nr = UART_NR,
> + .cons = MSM_CONSOLE,
> +};
> +
> +static int __init msm_serial_probe(struct platform_device *pdev)
> +{
> + struct msm_port *msm_port;
> + struct resource *resource;
> + struct uart_port *port;
> +
> + if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
> + return -ENXIO;
> +
> + printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
> +
> + port = get_port_from_line(pdev->id);
> + port->dev = &pdev->dev;
> + msm_port = UART_TO_MSM(port);
> +
> + msm_port->clk = clk_get(&pdev->dev, "uart_clk");
> + if (unlikely(IS_ERR(msm_port->clk)))
> + return PTR_ERR(msm_port->clk);
> + port->uartclk = clk_get_rate(msm_port->clk);
> +
> + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (unlikely(!resource))
> + return -ENXIO;
> + port->mapbase = resource->start;
> +
> + port->irq = platform_get_irq(pdev, 0);
> + if (unlikely(port->irq < 0))
> + return -ENXIO;
> +
> + platform_set_drvdata(pdev, port);
> +
> + return uart_add_one_port(&msm_uart_driver, port);
> +}
> +
> +static int __devexit msm_serial_remove(struct platform_device *pdev)
> +{
> + struct msm_port *msm_port = platform_get_drvdata(pdev);
> +
> + clk_put(msm_port->clk);
> +
> + return 0;
> +}
> +
> +static struct platform_driver msm_platform_driver = {
> + .probe = msm_serial_probe,
> + .remove = msm_serial_remove,
> + .driver = {
> + .name = "msm_serial",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init msm_serial_init(void)
> +{
> + int ret;
> +
> + ret = uart_register_driver(&msm_uart_driver);
> + if (unlikely(ret))
> + return ret;
> +
> + ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
> + if (unlikely(ret))
> + uart_unregister_driver(&msm_uart_driver);
> +
> + printk(KERN_INFO "msm_serial: driver initialized\n");
> +
> + return ret;
> +}
> +
> +static void __exit msm_serial_exit(void)
> +{
> +#ifdef CONFIG_SERIAL_MSM_CONSOLE
> + unregister_console(&msm_console);
> +#endif
> + platform_driver_unregister(&msm_platform_driver);
> + uart_unregister_driver(&msm_uart_driver);
> +}
> +
> +module_init(msm_serial_init);
> +module_exit(msm_serial_exit);
> +
> +MODULE_AUTHOR("Robert Love <rlove@google.com>");
> +MODULE_DESCRIPTION("Driver for msm7x serial device");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
> new file mode 100644
> index 0000000..689f1fa
> --- /dev/null
> +++ b/drivers/serial/msm_serial.h
> @@ -0,0 +1,117 @@
> +/*
> + * drivers/serial/msm_serial.h
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Robert Love <rlove@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
> +#define __DRIVERS_SERIAL_MSM_SERIAL_H
> +
> +#define UART_MR1 0x0000
> +
> +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
> +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
> +#define UART_MR1_RX_RDY_CTL (1 << 7)
> +#define UART_MR1_CTS_CTL (1 << 6)
> +
> +#define UART_MR2 0x0004
> +#define UART_MR2_ERROR_MODE (1 << 6)
> +#define UART_MR2_BITS_PER_CHAR 0x30
> +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
> +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
> +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
> +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
> +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
> +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
> +#define UART_MR2_PARITY_MODE_NONE 0x0
> +#define UART_MR2_PARITY_MODE_ODD 0x1
> +#define UART_MR2_PARITY_MODE_EVEN 0x2
> +#define UART_MR2_PARITY_MODE_SPACE 0x3
> +#define UART_MR2_PARITY_MODE 0x3
> +
> +#define UART_CSR 0x0008
> +#define UART_CSR_115200 0xFF
> +#define UART_CSR_57600 0xEE
> +#define UART_CSR_38400 0xDD
> +#define UART_CSR_28800 0xCC
> +#define UART_CSR_19200 0xBB
> +#define UART_CSR_14400 0xAA
> +#define UART_CSR_9600 0x99
> +#define UART_CSR_4800 0x77
> +#define UART_CSR_2400 0x55
> +#define UART_CSR_1200 0x44
> +#define UART_CSR_600 0x33
> +#define UART_CSR_300 0x22
> +
> +#define UART_TF 0x000C
> +
> +#define UART_CR 0x0010
> +#define UART_CR_CMD_NULL (0 << 4)
> +#define UART_CR_CMD_RESET_RX (1 << 4)
> +#define UART_CR_CMD_RESET_TX (2 << 4)
> +#define UART_CR_CMD_RESET_ERR (3 << 4)
> +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
> +#define UART_CR_CMD_START_BREAK (5 << 4)
> +#define UART_CR_CMD_STOP_BREAK (6 << 4)
> +#define UART_CR_CMD_RESET_CTS (7 << 4)
> +#define UART_CR_CMD_PACKET_MODE (9 << 4)
> +#define UART_CR_CMD_MODE_RESET (12 << 4)
> +#define UART_CR_CMD_SET_RFR (13 << 4)
> +#define UART_CR_CMD_RESET_RFR (14 << 4)
> +#define UART_CR_TX_DISABLE (1 << 3)
> +#define UART_CR_TX_ENABLE (1 << 3)
> +#define UART_CR_RX_DISABLE (1 << 3)
> +#define UART_CR_RX_ENABLE (1 << 3)
> +
> +#define UART_IMR 0x0014
> +#define UART_IMR_TXLEV (1 << 0)
> +#define UART_IMR_RXSTALE (1 << 3)
> +#define UART_IMR_RXLEV (1 << 4)
> +#define UART_IMR_DELTA_CTS (1 << 5)
> +#define UART_IMR_CURRENT_CTS (1 << 6)
> +
> +#define UART_IPR_RXSTALE_LAST 0x20
> +#define UART_IPR_STALE_LSB 0x1F
> +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
> +
> +#define UART_IPR 0x0018
> +#define UART_TFWR 0x001C
> +#define UART_RFWR 0x0020
> +#define UART_HCR 0x0024
> +
> +#define UART_MREG 0x0028
> +#define UART_NREG 0x002C
> +#define UART_DREG 0x0030
> +#define UART_MNDREG 0x0034
> +#define UART_IRDA 0x0038
> +#define UART_MISR_MODE 0x0040
> +#define UART_MISR_RESET 0x0044
> +#define UART_MISR_EXPORT 0x0048
> +#define UART_MISR_VAL 0x004C
> +#define UART_TEST_CTRL 0x0050
> +
> +#define UART_SR 0x0008
> +#define UART_SR_HUNT_CHAR (1 << 7)
> +#define UART_SR_RX_BREAK (1 << 6)
> +#define UART_SR_PAR_FRAME_ERR (1 << 5)
> +#define UART_SR_OVERRUN (1 << 4)
> +#define UART_SR_TX_EMPTY (1 << 3)
> +#define UART_SR_TX_READY (1 << 2)
> +#define UART_SR_RX_FULL (1 << 1)
> +#define UART_SR_RX_READY (1 << 0)
> +
> +#define UART_RF 0x000C
> +#define UART_MISR 0x0010
> +#define UART_ISR 0x0014
> +
> +#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
> index 6fd80c4..23d2fb0 100644
> --- a/include/linux/serial_core.h
> +++ b/include/linux/serial_core.h
> @@ -171,6 +171,9 @@
> /* Timberdale UART */
> #define PORT_TIMBUART 87
>
> +/* Qualcomm MSM SoCs */
> +#define PORT_MSM 88
> +
> #ifdef __KERNEL__
>
> #include <linux/compiler.h>
> --
> 1.6.2.4
>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 8:52 ` Alan Cox
@ 2009-06-17 3:07 ` Brian Swetland
0 siblings, 0 replies; 22+ messages in thread
From: Brian Swetland @ 2009-06-17 3:07 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-arm-kernel, linux-kernel, pavel, Robert Love
On Mon, Jun 15, 2009 at 1:52 AM, Alan Cox<alan@lxorguk.ukuu.org.uk> wrote:
> On Sun, 14 Jun 2009 19:39:15 -0700 Brian Swetland <swetland@google.com> wrote:
>
> The set_termios method also needs to properly propogate back the settings
> it actually used (in your case thats mostly the setting the actual speed
> selected).
Would something like:
if (tty_termios_baud_rate(termios))
tty_termios_encode_baud_rate(termios, baud, baud);
Be the reasonable thing to do? 8250.c seems to do that.
Thanks,
Brian
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 9:55 ` Brian Swetland
@ 2009-06-16 7:35 ` Russell King - ARM Linux
0 siblings, 0 replies; 22+ messages in thread
From: Russell King - ARM Linux @ 2009-06-16 7:35 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel, Robert Love, Pavel Machek
On Mon, Jun 15, 2009 at 02:55:15AM -0700, Brian Swetland wrote:
> On Mon, Jun 15, 2009 at 1:52 AM, Pavel Machek<pavel@ucw.cz> wrote:
> >
> > Otherwise seems to be okay (plus the issues someone pointed in other
> > email), you can add my acked-by:. I guess you should submit it to
> > rmk's patch system...
>
> Russell,
>
> Do you want this stuff to end up in the patch system, or would
> accumulating patches into a for-rmk git branch somewhere make sense?
> That seemed to work reasonably well last time around. I'm happy to do
> either, but am most comfortable working with git.
>
> Does that even make sense for stuff like the serial driver or should
> everything outside of arch/arm/... be going through various different
> subsystem maintainers?
If there's no dependency on ARM stuff, it should go via the subsystem
maintainers trees. In the case of serial, that's Alan.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 8:52 ` Pavel Machek
2009-06-15 8:58 ` Russell King - ARM Linux
@ 2009-06-15 9:55 ` Brian Swetland
2009-06-16 7:35 ` Russell King - ARM Linux
1 sibling, 1 reply; 22+ messages in thread
From: Brian Swetland @ 2009-06-15 9:55 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: linux-kernel, Robert Love, Pavel Machek
On Mon, Jun 15, 2009 at 1:52 AM, Pavel Machek<pavel@ucw.cz> wrote:
>
> Otherwise seems to be okay (plus the issues someone pointed in other
> email), you can add my acked-by:. I guess you should submit it to
> rmk's patch system...
Russell,
Do you want this stuff to end up in the patch system, or would
accumulating patches into a for-rmk git branch somewhere make sense?
That seemed to work reasonably well last time around. I'm happy to do
either, but am most comfortable working with git.
Does that even make sense for stuff like the serial driver or should
everything outside of arch/arm/... be going through various different
subsystem maintainers?
Thanks,
Brian
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 2:39 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
` (2 preceding siblings ...)
2009-06-15 8:52 ` Alan Cox
@ 2009-06-15 9:05 ` Linus Walleij
2009-06-17 12:17 ` Robert Love
4 siblings, 0 replies; 22+ messages in thread
From: Linus Walleij @ 2009-06-15 9:05 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel, pavel, Robert Love
Hi Brian, some comments:
2009/6/15 Brian Swetland <swetland@google.com>:
> From: Robert Love <rlove@google.com>
>
> Signed-off-by: Brian Swetland <swetland@google.com>
> ---
> drivers/serial/Kconfig | 10 +
> drivers/serial/Makefile | 1 +
> drivers/serial/msm_serial.c | 767 +++++++++++++++++++++++++++++++++++++++++++
> drivers/serial/msm_serial.h | 117 +++++++
> include/linux/serial_core.h | 3 +
> 5 files changed, 898 insertions(+), 0 deletions(-)
> create mode 100644 drivers/serial/msm_serial.c
> create mode 100644 drivers/serial/msm_serial.h
>
> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
> index 1132c5c..037c1e0 100644
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -1320,6 +1320,16 @@ config SERIAL_SGI_IOC3
> If you have an SGI Altix with an IOC3 serial card,
> say Y or M. Otherwise, say N.
>
> +config SERIAL_MSM
> + bool "MSM on-chip serial port support"
> + depends on ARM && ARCH_MSM
> + select SERIAL_CORE
> +
> +config SERIAL_MSM_CONSOLE
> + bool "MSM serial console support"
> + depends on SERIAL_MSM=y
> + select SERIAL_CORE_CONSOLE
> +
> config SERIAL_NETX
> tristate "NetX serial port support"
> depends on ARM && ARCH_NETX
> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
> index 45a8658..d5a2998 100644
> --- a/drivers/serial/Makefile
> +++ b/drivers/serial/Makefile
> @@ -71,6 +71,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
> obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
> obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
> obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
> +obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
> obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
> obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
> obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
> diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
> new file mode 100644
> index 0000000..1a7c856
> --- /dev/null
> +++ b/drivers/serial/msm_serial.c
> @@ -0,0 +1,767 @@
> +/*
> + * drivers/serial/msm_serial.c - driver for msm7k serial device and console
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Robert Love <rlove@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +# define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/hrtimer.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/irq.h>
> +#include <linux/init.h>
> +#include <linux/console.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/serial_core.h>
> +#include <linux/serial.h>
> +#include <linux/clk.h>
> +#include <linux/platform_device.h>
> +
> +#include "msm_serial.h"
> +
> +struct msm_port {
> + struct uart_port uart;
> + char name[16];
> + struct clk *clk;
> + unsigned int imr;
> +};
> +
> +#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
> +
> +static inline void msm_write(struct uart_port *port, unsigned int val,
> + unsigned int off)
> +{
> + __raw_writel(val, port->membase + off);
> +}
> +
> +static inline unsigned int msm_read(struct uart_port *port, unsigned int off)
> +{
> + return __raw_readl(port->membase + off);
> +}
> +
> +static void msm_stop_tx(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr &= ~UART_IMR_TXLEV;
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void msm_start_tx(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr |= UART_IMR_TXLEV;
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void msm_stop_rx(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void msm_enable_ms(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr |= UART_IMR_DELTA_CTS;
> + msm_write(port, msm_port->imr, UART_IMR);
> +}
> +
> +static void handle_rx(struct uart_port *port)
> +{
> + struct tty_struct *tty = port->info->port.tty;
> + unsigned int sr;
> +
> + /*
> + * Handle overrun. My understanding of the hardware is that overrun
> + * is not tied to the RX buffer, so we handle the case out of band.
> + */
> + if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
> + port->icount.overrun++;
> + tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
> + }
> +
> + /* and now the main RX loop */
> + while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
> + unsigned int c;
> + char flag = TTY_NORMAL;
> +
> + c = msm_read(port, UART_RF);
> +
> + if (sr & UART_SR_RX_BREAK) {
> + port->icount.brk++;
> + if (uart_handle_break(port))
> + continue;
> + } else if (sr & UART_SR_PAR_FRAME_ERR) {
> + port->icount.frame++;
> + } else {
> + port->icount.rx++;
> + }
> +
> + /* Mask conditions we're ignorning. */
> + sr &= port->read_status_mask;
> +
> + if (sr & UART_SR_RX_BREAK) {
> + flag = TTY_BREAK;
> + } else if (sr & UART_SR_PAR_FRAME_ERR) {
> + flag = TTY_FRAME;
> + }
> +
> + if (!uart_handle_sysrq_char(port, c))
> + tty_insert_flip_char(tty, c, flag);
> + }
> +
> + tty_flip_buffer_push(tty);
> +}
> +
> +static void handle_tx(struct uart_port *port)
> +{
> + struct circ_buf *xmit = &port->info->xmit;
> + struct msm_port *msm_port = UART_TO_MSM(port);
> + int sent_tx;
> +
> + if (port->x_char) {
> + msm_write(port, port->x_char, UART_TF);
> + port->icount.tx++;
> + port->x_char = 0;
> + }
> +
> + while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
> + if (uart_circ_empty(xmit)) {
> + /* disable tx interrupts */
> + msm_port->imr &= ~UART_IMR_TXLEV;
> + msm_write(port, msm_port->imr, UART_IMR);
> + break;
> + }
> +
> + msm_write(port, xmit->buf[xmit->tail], UART_TF);
> +
> + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> + port->icount.tx++;
> + sent_tx = 1;
> + }
> +
> + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> + uart_write_wakeup(port);
> +}
> +
> +static void handle_delta_cts(struct uart_port *port)
> +{
> + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
> + port->icount.cts++;
> + wake_up_interruptible(&port->info->delta_msr_wait);
> +}
> +
> +static irqreturn_t msm_irq(int irq, void *dev_id)
> +{
> + struct uart_port *port = dev_id;
> + struct msm_port *msm_port = UART_TO_MSM(port);
> + unsigned int misr;
> +
> + spin_lock(&port->lock);
> + misr = msm_read(port, UART_MISR);
> + msm_write(port, 0, UART_IMR); /* disable interrupt */
> +
> + if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
> + handle_rx(port);
> + if (misr & UART_IMR_TXLEV)
> + handle_tx(port);
> + if (misr & UART_IMR_DELTA_CTS)
> + handle_delta_cts(port);
> +
> + msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
> + spin_unlock(&port->lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static unsigned int msm_tx_empty(struct uart_port *port)
> +{
> + return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
> +}
> +
> +static unsigned int msm_get_mctrl(struct uart_port *port)
> +{
> + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
> +}
> +
> +static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> + unsigned int mr;
> +
> + mr = msm_read(port, UART_MR1);
> +
> + if (!(mctrl & TIOCM_RTS)) {
> + mr &= ~UART_MR1_RX_RDY_CTL;
> + msm_write(port, mr, UART_MR1);
> + msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
> + } else {
> + mr |= UART_MR1_RX_RDY_CTL;
> + msm_write(port, mr, UART_MR1);
> + }
> +}
> +
> +static void msm_break_ctl(struct uart_port *port, int break_ctl)
> +{
> + if (break_ctl)
> + msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
> + else
> + msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
> +}
> +
> +static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
> +{
> + unsigned int baud_code, rxstale, watermark;
> +
> + switch (baud) {
> + case 300:
> + baud_code = UART_CSR_300;
> + rxstale = 1;
> + break;
> + case 600:
> + baud_code = UART_CSR_600;
> + rxstale = 1;
> + break;
> + case 1200:
> + baud_code = UART_CSR_1200;
> + rxstale = 1;
> + break;
> + case 2400:
> + baud_code = UART_CSR_2400;
> + rxstale = 1;
> + break;
> + case 4800:
> + baud_code = UART_CSR_4800;
> + rxstale = 1;
> + break;
> + case 9600:
> + baud_code = UART_CSR_9600;
> + rxstale = 2;
> + break;
> + case 14400:
> + baud_code = UART_CSR_14400;
> + rxstale = 3;
> + break;
> + case 19200:
> + baud_code = UART_CSR_19200;
> + rxstale = 4;
> + break;
> + case 28800:
> + baud_code = UART_CSR_28800;
> + rxstale = 6;
> + break;
> + case 38400:
> + baud_code = UART_CSR_38400;
> + rxstale = 8;
> + break;
> + case 57600:
> + baud_code = UART_CSR_57600;
> + rxstale = 16;
> + break;
> + case 115200:
> + default:
> + baud_code = UART_CSR_115200;
> + rxstale = 31;
> + break;
> + }
> +
> + msm_write(port, baud_code, UART_CSR);
> +
> + /* RX stale watermark */
> + watermark = UART_IPR_STALE_LSB & rxstale;
> + watermark |= UART_IPR_RXSTALE_LAST;
> + watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
> + msm_write(port, watermark, UART_IPR);
> +
> + /* set RX watermark */
> + watermark = (port->fifosize * 3) / 4;
> + msm_write(port, watermark, UART_RFWR);
> +
> + /* set TX watermark */
> + msm_write(port, 10, UART_TFWR);
> +}
> +
> +static void msm_reset(struct uart_port *port)
> +{
> + /* reset everything */
> + msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
> + msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
> + msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
> +}
> +
> +static void msm_init_clock(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + clk_enable(msm_port->clk);
> +
> + msm_write(port, 0xC0, UART_MREG);
> + msm_write(port, 0xB2, UART_NREG);
> + msm_write(port, 0x7D, UART_DREG);
> + msm_write(port, 0x1C, UART_MNDREG);
> +}
> +
> +static int msm_startup(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> + unsigned int data, rfr_level;
> + int ret;
> +
> + snprintf(msm_port->name, sizeof(msm_port->name),
> + "msm_serial%d", port->line);
Perhaps be sure that you terminate this string with
msm_port->name[sizeof(msm_port->name)-1] = '\0';
> +
> + ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
> + msm_port->name, port);
> + if (unlikely(ret))
> + return ret;
> +
> + msm_init_clock(port);
> +
> + if (likely(port->fifosize > 12))
> + rfr_level = port->fifosize - 12;
> + else
> + rfr_level = port->fifosize;
> +
> + /* set automatic RFR level */
> + data = msm_read(port, UART_MR1);
> + data &= ~UART_MR1_AUTO_RFR_LEVEL1;
> + data &= ~UART_MR1_AUTO_RFR_LEVEL0;
> + data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
> + data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
> + msm_write(port, data, UART_MR1);
> +
> + /* make sure that RXSTALE count is non-zero */
> + data = msm_read(port, UART_IPR);
> + if (unlikely(!data)) {
> + data |= UART_IPR_RXSTALE_LAST;
> + data |= UART_IPR_STALE_LSB;
> + msm_write(port, data, UART_IPR);
> + }
> +
> + msm_reset(port);
> +
> + msm_write(port, 0x05, UART_CR); /* enable TX & RX */
> +
> + /* turn on RX and CTS interrupts */
> + msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
> + UART_IMR_CURRENT_CTS;
> + msm_write(port, msm_port->imr, UART_IMR);
> +
> + return 0;
> +}
> +
> +static void msm_shutdown(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + msm_port->imr = 0;
> + msm_write(port, 0, UART_IMR); /* disable interrupts */
> +
> + clk_disable(msm_port->clk);
> +
> + free_irq(port->irq, port);
> +}
> +
> +static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
> + struct ktermios *old)
> +{
> + unsigned long flags;
> + unsigned int baud, mr;
> +
> + spin_lock_irqsave(&port->lock, flags);
> +
> + /* calculate and set baud rate */
> + baud = uart_get_baud_rate(port, termios, old, 300, 115200);
> + msm_set_baud_rate(port, baud);
> +
> + /* calculate parity */
> + mr = msm_read(port, UART_MR2);
> + mr &= ~UART_MR2_PARITY_MODE;
> + if (termios->c_cflag & PARENB) {
> + if (termios->c_cflag & PARODD)
> + mr |= UART_MR2_PARITY_MODE_ODD;
> + else if (termios->c_cflag & CMSPAR)
> + mr |= UART_MR2_PARITY_MODE_SPACE;
> + else
> + mr |= UART_MR2_PARITY_MODE_EVEN;
> + }
> +
> + /* calculate bits per char */
> + mr &= ~UART_MR2_BITS_PER_CHAR;
> + switch (termios->c_cflag & CSIZE) {
> + case CS5:
> + mr |= UART_MR2_BITS_PER_CHAR_5;
> + break;
> + case CS6:
> + mr |= UART_MR2_BITS_PER_CHAR_6;
> + break;
> + case CS7:
> + mr |= UART_MR2_BITS_PER_CHAR_7;
> + break;
> + case CS8:
> + default:
> + mr |= UART_MR2_BITS_PER_CHAR_8;
> + break;
> + }
> +
> + /* calculate stop bits */
> + mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
> + if (termios->c_cflag & CSTOPB)
> + mr |= UART_MR2_STOP_BIT_LEN_TWO;
> + else
> + mr |= UART_MR2_STOP_BIT_LEN_ONE;
> +
> + /* set parity, bits per char, and stop bit */
> + msm_write(port, mr, UART_MR2);
> +
> + /* calculate and set hardware flow control */
> + mr = msm_read(port, UART_MR1);
> + mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
> + if (termios->c_cflag & CRTSCTS) {
> + mr |= UART_MR1_CTS_CTL;
> + mr |= UART_MR1_RX_RDY_CTL;
> + }
> + msm_write(port, mr, UART_MR1);
> +
> + /* Configure status bits to ignore based on termio flags. */
> + port->read_status_mask = 0;
> + if (termios->c_iflag & INPCK)
> + port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
> + if (termios->c_iflag & (BRKINT | PARMRK))
> + port->read_status_mask |= UART_SR_RX_BREAK;
> +
> + uart_update_timeout(port, termios->c_cflag, baud);
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *msm_type(struct uart_port *port)
> +{
> + return "MSM";
> +}
> +
> +static void msm_release_port(struct uart_port *port)
> +{
> + struct platform_device *pdev = to_platform_device(port->dev);
> + struct resource *resource;
> + resource_size_t size;
Remove size variable
> +
> + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (unlikely(!resource))
> + return;
> + size = resource->end - resource->start + 1;
Remove assignment
> +
> + release_mem_region(port->mapbase, size);
release_mem_region(port->mapbase, resource_size(resource));
> + iounmap(port->membase);
> + port->membase = NULL;
> +}
> +
> +static int msm_request_port(struct uart_port *port)
> +{
> + struct platform_device *pdev = to_platform_device(port->dev);
> + struct resource *resource;
> + resource_size_t size;
Hm here it may be warranted
> +
> + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (unlikely(!resource))
> + return -ENXIO;
> + size = resource->end - resource->start + 1;
size = resource_size(resource);
> +
> + if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
> + return -EBUSY;
> +
> + port->membase = ioremap(port->mapbase, size);
> + if (!port->membase) {
> + release_mem_region(port->mapbase, size);
> + return -EBUSY;
> + }
> +
> + return 0;
> +}
> +
> +static void msm_config_port(struct uart_port *port, int flags)
> +{
> + if (flags & UART_CONFIG_TYPE) {
> + port->type = PORT_MSM;
> + msm_request_port(port);
> + }
> +}
> +
> +static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> + if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
> + return -EINVAL;
> + if (unlikely(port->irq != ser->irq))
> + return -EINVAL;
> + return 0;
> +}
> +
> +static void msm_power(struct uart_port *port, unsigned int state,
> + unsigned int oldstate)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> +
> + switch (state) {
> + case 0:
> + clk_enable(msm_port->clk);
> + break;
> + case 3:
> + clk_disable(msm_port->clk);
> + break;
> + default:
> + printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
dev_err(port->dev, "unknown PM state...");
> + }
> +}
> +
> +static struct uart_ops msm_uart_pops = {
> + .tx_empty = msm_tx_empty,
> + .set_mctrl = msm_set_mctrl,
> + .get_mctrl = msm_get_mctrl,
> + .stop_tx = msm_stop_tx,
> + .start_tx = msm_start_tx,
> + .stop_rx = msm_stop_rx,
> + .enable_ms = msm_enable_ms,
> + .break_ctl = msm_break_ctl,
> + .startup = msm_startup,
> + .shutdown = msm_shutdown,
> + .set_termios = msm_set_termios,
> + .type = msm_type,
> + .release_port = msm_release_port,
> + .request_port = msm_request_port,
> + .config_port = msm_config_port,
> + .verify_port = msm_verify_port,
> + .pm = msm_power,
> +};
> +
> +static struct msm_port msm_uart_ports[] = {
> + {
> + .uart = {
> + .iotype = UPIO_MEM,
> + .ops = &msm_uart_pops,
> + .flags = UPF_BOOT_AUTOCONF,
> + .fifosize = 512,
> + .line = 0,
> + },
> + },
> + {
> + .uart = {
> + .iotype = UPIO_MEM,
> + .ops = &msm_uart_pops,
> + .flags = UPF_BOOT_AUTOCONF,
> + .fifosize = 512,
> + .line = 1,
> + },
> + },
> + {
> + .uart = {
> + .iotype = UPIO_MEM,
> + .ops = &msm_uart_pops,
> + .flags = UPF_BOOT_AUTOCONF,
> + .fifosize = 64,
> + .line = 2,
> + },
> + },
> +};
> +
> +#define UART_NR ARRAY_SIZE(msm_uart_ports)
> +
> +static inline struct uart_port *get_port_from_line(unsigned int line)
> +{
> + return &msm_uart_ports[line].uart;
> +}
> +
> +#ifdef CONFIG_SERIAL_MSM_CONSOLE
> +
> +static void msm_console_putchar(struct uart_port *port, int c)
> +{
> + while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
> + ;
> + msm_write(port, c, UART_TF);
> +}
> +
> +static void msm_console_write(struct console *co, const char *s,
> + unsigned int count)
> +{
> + struct uart_port *port;
> + struct msm_port *msm_port;
> +
> + BUG_ON(co->index < 0 || co->index >= UART_NR);
> +
> + port = get_port_from_line(co->index);
> + msm_port = UART_TO_MSM(port);
> +
> + spin_lock(&port->lock);
> + uart_console_write(port, s, count, msm_console_putchar);
> + spin_unlock(&port->lock);
> +}
> +
> +static int __init msm_console_setup(struct console *co, char *options)
> +{
> + struct uart_port *port;
> + int baud, flow, bits, parity;
> +
> + if (unlikely(co->index >= UART_NR || co->index < 0))
> + return -ENXIO;
> +
> + port = get_port_from_line(co->index);
> +
> + if (unlikely(!port->membase))
> + return -ENXIO;
> +
> + port->cons = co;
> +
> + msm_init_clock(port);
> +
> + if (options)
> + uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> + bits = 8;
> + parity = 'n';
> + flow = 'n';
> + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
> + UART_MR2); /* 8N1 */
> +
> + if (baud < 300 || baud > 115200)
> + baud = 115200;
> + msm_set_baud_rate(port, baud);
> +
> + msm_reset(port);
> +
> + printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
dev_info(port->dev, "console set...");
But perhaps a check that port->dev is not NULL then pr_info() instead,
I don't know the exact details if console can be used before port is init()
below.
> +
> + return uart_set_options(port, co, baud, parity, bits, flow);
> +}
> +
> +static struct uart_driver msm_uart_driver;
> +
> +static struct console msm_console = {
> + .name = "ttyMSM",
> + .write = msm_console_write,
> + .device = uart_console_device,
> + .setup = msm_console_setup,
> + .flags = CON_PRINTBUFFER,
> + .index = -1,
> + .data = &msm_uart_driver,
> +};
> +
> +#define MSM_CONSOLE (&msm_console)
> +
> +#else
> +#define MSM_CONSOLE NULL
> +#endif
> +
> +static struct uart_driver msm_uart_driver = {
> + .owner = THIS_MODULE,
> + .driver_name = "msm_serial",
> + .dev_name = "ttyMSM",
> + .nr = UART_NR,
> + .cons = MSM_CONSOLE,
> +};
> +
> +static int __init msm_serial_probe(struct platform_device *pdev)
> +{
> + struct msm_port *msm_port;
> + struct resource *resource;
> + struct uart_port *port;
> +
> + if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
> + return -ENXIO;
> +
> + printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
dev_info(pdev->dev, "detected...");
> +
> + port = get_port_from_line(pdev->id);
> + port->dev = &pdev->dev;
> + msm_port = UART_TO_MSM(port);
> +
> + msm_port->clk = clk_get(&pdev->dev, "uart_clk");
> + if (unlikely(IS_ERR(msm_port->clk)))
> + return PTR_ERR(msm_port->clk);
> + port->uartclk = clk_get_rate(msm_port->clk);
> +
> + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (unlikely(!resource))
> + return -ENXIO;
> + port->mapbase = resource->start;
> +
> + port->irq = platform_get_irq(pdev, 0);
> + if (unlikely(port->irq < 0))
> + return -ENXIO;
> +
> + platform_set_drvdata(pdev, port);
> +
> + return uart_add_one_port(&msm_uart_driver, port);
> +}
> +
> +static int __devexit msm_serial_remove(struct platform_device *pdev)
__devexit, that means that the MSM serial port can be hot-plugged.
Is this possible on this platform? Do you mean __exit?
> +{
> + struct msm_port *msm_port = platform_get_drvdata(pdev);
> +
> + clk_put(msm_port->clk);
> +
> + return 0;
> +}
> +
> +static struct platform_driver msm_platform_driver = {
> + .probe = msm_serial_probe,
> + .remove = msm_serial_remove,
__exit_p(msm_serial_remove), or __devexit_p(msm_serial_remove) at
your choice.
> + .driver = {
> + .name = "msm_serial",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init msm_serial_init(void)
> +{
> + int ret;
> +
> + ret = uart_register_driver(&msm_uart_driver);
> + if (unlikely(ret))
> + return ret;
> +
> + ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
> + if (unlikely(ret))
> + uart_unregister_driver(&msm_uart_driver);
> +
> + printk(KERN_INFO "msm_serial: driver initialized\n");
pr_info()
> +
> + return ret;
> +}
> +
> +static void __exit msm_serial_exit(void)
> +{
> +#ifdef CONFIG_SERIAL_MSM_CONSOLE
> + unregister_console(&msm_console);
> +#endif
> + platform_driver_unregister(&msm_platform_driver);
> + uart_unregister_driver(&msm_uart_driver);
> +}
> +
> +module_init(msm_serial_init);
> +module_exit(msm_serial_exit);
> +
> +MODULE_AUTHOR("Robert Love <rlove@google.com>");
> +MODULE_DESCRIPTION("Driver for msm7x serial device");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
> new file mode 100644
> index 0000000..689f1fa
> --- /dev/null
> +++ b/drivers/serial/msm_serial.h
> @@ -0,0 +1,117 @@
> +/*
> + * drivers/serial/msm_serial.h
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Robert Love <rlove@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
> +#define __DRIVERS_SERIAL_MSM_SERIAL_H
> +
> +#define UART_MR1 0x0000
> +
> +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
> +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
> +#define UART_MR1_RX_RDY_CTL (1 << 7)
> +#define UART_MR1_CTS_CTL (1 << 6)
> +
> +#define UART_MR2 0x0004
> +#define UART_MR2_ERROR_MODE (1 << 6)
> +#define UART_MR2_BITS_PER_CHAR 0x30
> +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
> +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
> +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
> +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
> +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
> +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
> +#define UART_MR2_PARITY_MODE_NONE 0x0
> +#define UART_MR2_PARITY_MODE_ODD 0x1
> +#define UART_MR2_PARITY_MODE_EVEN 0x2
> +#define UART_MR2_PARITY_MODE_SPACE 0x3
> +#define UART_MR2_PARITY_MODE 0x3
> +
> +#define UART_CSR 0x0008
> +#define UART_CSR_115200 0xFF
> +#define UART_CSR_57600 0xEE
> +#define UART_CSR_38400 0xDD
> +#define UART_CSR_28800 0xCC
> +#define UART_CSR_19200 0xBB
> +#define UART_CSR_14400 0xAA
> +#define UART_CSR_9600 0x99
> +#define UART_CSR_4800 0x77
> +#define UART_CSR_2400 0x55
> +#define UART_CSR_1200 0x44
> +#define UART_CSR_600 0x33
> +#define UART_CSR_300 0x22
> +
> +#define UART_TF 0x000C
> +
> +#define UART_CR 0x0010
> +#define UART_CR_CMD_NULL (0 << 4)
> +#define UART_CR_CMD_RESET_RX (1 << 4)
> +#define UART_CR_CMD_RESET_TX (2 << 4)
> +#define UART_CR_CMD_RESET_ERR (3 << 4)
> +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
> +#define UART_CR_CMD_START_BREAK (5 << 4)
> +#define UART_CR_CMD_STOP_BREAK (6 << 4)
> +#define UART_CR_CMD_RESET_CTS (7 << 4)
> +#define UART_CR_CMD_PACKET_MODE (9 << 4)
> +#define UART_CR_CMD_MODE_RESET (12 << 4)
> +#define UART_CR_CMD_SET_RFR (13 << 4)
> +#define UART_CR_CMD_RESET_RFR (14 << 4)
> +#define UART_CR_TX_DISABLE (1 << 3)
> +#define UART_CR_TX_ENABLE (1 << 3)
> +#define UART_CR_RX_DISABLE (1 << 3)
> +#define UART_CR_RX_ENABLE (1 << 3)
> +
> +#define UART_IMR 0x0014
> +#define UART_IMR_TXLEV (1 << 0)
> +#define UART_IMR_RXSTALE (1 << 3)
> +#define UART_IMR_RXLEV (1 << 4)
> +#define UART_IMR_DELTA_CTS (1 << 5)
> +#define UART_IMR_CURRENT_CTS (1 << 6)
> +
> +#define UART_IPR_RXSTALE_LAST 0x20
> +#define UART_IPR_STALE_LSB 0x1F
> +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
> +
> +#define UART_IPR 0x0018
> +#define UART_TFWR 0x001C
> +#define UART_RFWR 0x0020
> +#define UART_HCR 0x0024
> +
> +#define UART_MREG 0x0028
> +#define UART_NREG 0x002C
> +#define UART_DREG 0x0030
> +#define UART_MNDREG 0x0034
> +#define UART_IRDA 0x0038
> +#define UART_MISR_MODE 0x0040
> +#define UART_MISR_RESET 0x0044
> +#define UART_MISR_EXPORT 0x0048
> +#define UART_MISR_VAL 0x004C
> +#define UART_TEST_CTRL 0x0050
> +
> +#define UART_SR 0x0008
> +#define UART_SR_HUNT_CHAR (1 << 7)
> +#define UART_SR_RX_BREAK (1 << 6)
> +#define UART_SR_PAR_FRAME_ERR (1 << 5)
> +#define UART_SR_OVERRUN (1 << 4)
> +#define UART_SR_TX_EMPTY (1 << 3)
> +#define UART_SR_TX_READY (1 << 2)
> +#define UART_SR_RX_FULL (1 << 1)
> +#define UART_SR_RX_READY (1 << 0)
> +
> +#define UART_RF 0x000C
> +#define UART_MISR 0x0010
> +#define UART_ISR 0x0014
> +
> +#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
> index 6fd80c4..23d2fb0 100644
> --- a/include/linux/serial_core.h
> +++ b/include/linux/serial_core.h
> @@ -171,6 +171,9 @@
> /* Timberdale UART */
> #define PORT_TIMBUART 87
>
> +/* Qualcomm MSM SoCs */
> +#define PORT_MSM 88
> +
> #ifdef __KERNEL__
>
> #include <linux/compiler.h>
> --
> 1.6.2.4
>
> --
> 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/
>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 8:52 ` Pavel Machek
@ 2009-06-15 8:58 ` Russell King - ARM Linux
2009-06-15 9:55 ` Brian Swetland
1 sibling, 0 replies; 22+ messages in thread
From: Russell King - ARM Linux @ 2009-06-15 8:58 UTC (permalink / raw)
To: Pavel Machek; +Cc: Brian Swetland, linux-arm-kernel, linux-kernel, Robert Love
On Mon, Jun 15, 2009 at 10:52:16AM +0200, Pavel Machek wrote:
> > +#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> > +# define SUPPORT_SYSRQ
> > +#endif
>
> SUPPORT_SYSRQ seems to be unused.
It's used in include/linux/serial_core.h to enable the additional sysrq
stuff - but that's something that desperately need to die now that the
additional member is not at the end of the struct (it's buggy as
currently stands).
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 3:18 ` Ryan Mallon
@ 2009-06-15 8:54 ` Alan Cox
0 siblings, 0 replies; 22+ messages in thread
From: Alan Cox @ 2009-06-15 8:54 UTC (permalink / raw)
To: Ryan Mallon
Cc: Brian Swetland, linux-arm-kernel, linux-kernel, pavel, Robert Love
> > + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
> > + UART_MR2); /* 8N1 */
> > +
> > + if (baud < 300 || baud > 115200)
> > + baud = 115200;
>
> return -EINVAL?
TNo - this is your console so its far better to do something than fail.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 2:39 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
2009-06-15 3:18 ` Ryan Mallon
2009-06-15 8:52 ` Pavel Machek
@ 2009-06-15 8:52 ` Alan Cox
2009-06-17 3:07 ` Brian Swetland
2009-06-15 9:05 ` Linus Walleij
2009-06-17 12:17 ` Robert Love
4 siblings, 1 reply; 22+ messages in thread
From: Alan Cox @ 2009-06-15 8:52 UTC (permalink / raw)
To: Brian Swetland
Cc: linux-arm-kernel, linux-kernel, pavel, Robert Love, Brian Swetland
On Sun, 14 Jun 2009 19:39:15 -0700
Brian Swetland <swetland@google.com> wrote:
> From: Robert Love <rlove@google.com>
>
> Signed-off-by: Brian Swetland <swetland@google.com>
The set_termios method also needs to properly propogate back the settings
it actually used (in your case thats mostly the setting the actual speed
selected).
The locking on port.tty also wants looking at but thats a general
drivers/serial project.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 2:39 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
2009-06-15 3:18 ` Ryan Mallon
@ 2009-06-15 8:52 ` Pavel Machek
2009-06-15 8:58 ` Russell King - ARM Linux
2009-06-15 9:55 ` Brian Swetland
2009-06-15 8:52 ` Alan Cox
` (2 subsequent siblings)
4 siblings, 2 replies; 22+ messages in thread
From: Pavel Machek @ 2009-06-15 8:52 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel, Robert Love
Hi!
> From: Robert Love <rlove@google.com>
>
> Signed-off-by: Brian Swetland <swetland@google.com>
Some kind of Changelog would be nice ( Enable support for serial
devices on MSM...), and I guess Robert's Signed-off-by: would be welcome.
> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
> index 1132c5c..037c1e0 100644
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -1320,6 +1320,16 @@ config SERIAL_SGI_IOC3
> If you have an SGI Altix with an IOC3 serial card,
> say Y or M. Otherwise, say N.
>
> +config SERIAL_MSM
> + bool "MSM on-chip serial port support"
> + depends on ARM && ARCH_MSM
> + select SERIAL_CORE
> +
> +config SERIAL_MSM_CONSOLE
> + bool "MSM serial console support"
> + depends on SERIAL_MSM=y
"depends on SERIAL_MSM" should be enough?
> diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
> new file mode 100644
> index 0000000..1a7c856
> --- /dev/null
> +++ b/drivers/serial/msm_serial.c
> @@ -0,0 +1,767 @@
> +/*
> + * drivers/serial/msm_serial.c - driver for msm7k serial device and console
> + *
> + * Copyright (C) 2007 Google, Inc.
> + * Author: Robert Love <rlove@google.com>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +# define SUPPORT_SYSRQ
> +#endif
SUPPORT_SYSRQ seems to be unused.
> +#include <linux/hrtimer.h>
Are hrtimes required?
Otherwise seems to be okay (plus the issues someone pointed in other
email), you can add my acked-by:. I guess you should submit it to
rmk's patch system...
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 2:39 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
@ 2009-06-15 3:18 ` Ryan Mallon
2009-06-15 8:54 ` Alan Cox
2009-06-15 8:52 ` Pavel Machek
` (3 subsequent siblings)
4 siblings, 1 reply; 22+ messages in thread
From: Ryan Mallon @ 2009-06-15 3:18 UTC (permalink / raw)
To: Brian Swetland; +Cc: linux-arm-kernel, linux-kernel, pavel, Robert Love
Brian Swetland wrote:
> From: Robert Love <rlove@google.com>
>
> Signed-off-by: Brian Swetland <swetland@google.com>
Hi Brian, some comments below:
> +
> +struct msm_port {
> + struct uart_port uart;
> + char name[16];
> + struct clk *clk;
> + unsigned int imr;
> +};
> +
> +#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
Should this be:
#define to_msm_uart(up) container_of(up, msm_port, uart_port)
Container conversion macros are usually lower case.
> +static int msm_startup(struct uart_port *port)
> +{
> + struct msm_port *msm_port = UART_TO_MSM(port);
> + unsigned int data, rfr_level;
> + int ret;
> +
> + snprintf(msm_port->name, sizeof(msm_port->name),
> + "msm_serial%d", port->line);
> +
> + ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
> + msm_port->name, port);
> + if (unlikely(ret))
> + return ret;
Not sure that you need the likely/unlikely macros here or in the other
startup/release functions. They are usually for hot-path code. They
aren't strictly wrong, its just probably not necessary.
> +
> +static struct uart_ops msm_uart_pops = {
> + .tx_empty = msm_tx_empty,
> + .set_mctrl = msm_set_mctrl,
> + .get_mctrl = msm_get_mctrl,
> + .stop_tx = msm_stop_tx,
> + .start_tx = msm_start_tx,
> + .stop_rx = msm_stop_rx,
> + .enable_ms = msm_enable_ms,
> + .break_ctl = msm_break_ctl,
> + .startup = msm_startup,
> + .shutdown = msm_shutdown,
> + .set_termios = msm_set_termios,
> + .type = msm_type,
> + .release_port = msm_release_port,
> + .request_port = msm_request_port,
> + .config_port = msm_config_port,
> + .verify_port = msm_verify_port,
> + .pm = msm_power,
> +};
Tab-delimit this to make it look nicer, ie:
.tx_empty = msm_tx_empty,
.set_mctrl = msm_set_mctrl,
...
> +
> +static struct msm_port msm_uart_ports[] = {
> + {
> + .uart = {
> + .iotype = UPIO_MEM,
> + .ops = &msm_uart_pops,
> + .flags = UPF_BOOT_AUTOCONF,
> + .fifosize = 512,
> + .line = 0,
> + },
Same here, and all the other struct initialisations.
> +
> +static int __init msm_console_setup(struct console *co, char *options)
> +{
> + struct uart_port *port;
> + int baud, flow, bits, parity;
> +
> + if (unlikely(co->index >= UART_NR || co->index < 0))
> + return -ENXIO;
> +
> + port = get_port_from_line(co->index);
> +
> + if (unlikely(!port->membase))
> + return -ENXIO;
> +
> + port->cons = co;
> +
> + msm_init_clock(port);
> +
> + if (options)
> + uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> + bits = 8;
> + parity = 'n';
> + flow = 'n';
> + msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
> + UART_MR2); /* 8N1 */
> +
> + if (baud < 300 || baud > 115200)
> + baud = 115200;
return -EINVAL?
> + msm_set_baud_rate(port, baud);
> +
> + msm_reset(port);
> +
> + printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
pr_info? Also, this may just be noise, IIRC, the serial sub-system
prints information about the uarts anyway.
~Ryan
--
Bluewater Systems Ltd - ARM Technology Solution Centre
Ryan Mallon Unit 5, Amuri Park
Phone: +64 3 3779127 404 Barbadoes St
Fax: +64 3 3779135 PO Box 13 889
Email: ryan@bluewatersys.com Christchurch, 8013
Web: http://www.bluewatersys.com New Zealand
Freecall Australia 1800 148 751 USA 1800 261 2934
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral.
2009-06-15 2:39 Patches to get serial working on msm7k / htc dream Brian Swetland
@ 2009-06-15 2:39 ` Brian Swetland
2009-06-15 3:18 ` Ryan Mallon
` (4 more replies)
0 siblings, 5 replies; 22+ messages in thread
From: Brian Swetland @ 2009-06-15 2:39 UTC (permalink / raw)
To: linux-arm-kernel; +Cc: linux-kernel, pavel, Robert Love, Brian Swetland
From: Robert Love <rlove@google.com>
Signed-off-by: Brian Swetland <swetland@google.com>
---
drivers/serial/Kconfig | 10 +
drivers/serial/Makefile | 1 +
drivers/serial/msm_serial.c | 767 +++++++++++++++++++++++++++++++++++++++++++
drivers/serial/msm_serial.h | 117 +++++++
include/linux/serial_core.h | 3 +
5 files changed, 898 insertions(+), 0 deletions(-)
create mode 100644 drivers/serial/msm_serial.c
create mode 100644 drivers/serial/msm_serial.h
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 1132c5c..037c1e0 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1320,6 +1320,16 @@ config SERIAL_SGI_IOC3
If you have an SGI Altix with an IOC3 serial card,
say Y or M. Otherwise, say N.
+config SERIAL_MSM
+ bool "MSM on-chip serial port support"
+ depends on ARM && ARCH_MSM
+ select SERIAL_CORE
+
+config SERIAL_MSM_CONSOLE
+ bool "MSM serial console support"
+ depends on SERIAL_MSM=y
+ select SERIAL_CORE_CONSOLE
+
config SERIAL_NETX
tristate "NetX serial port support"
depends on ARM && ARCH_NETX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 45a8658..d5a2998 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
+obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
new file mode 100644
index 0000000..1a7c856
--- /dev/null
+++ b/drivers/serial/msm_serial.c
@@ -0,0 +1,767 @@
+/*
+ * drivers/serial/msm_serial.c - driver for msm7k serial device and console
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#if defined(CONFIG_SERIAL_MSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+# define SUPPORT_SYSRQ
+#endif
+
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "msm_serial.h"
+
+struct msm_port {
+ struct uart_port uart;
+ char name[16];
+ struct clk *clk;
+ unsigned int imr;
+};
+
+#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
+
+static inline void msm_write(struct uart_port *port, unsigned int val,
+ unsigned int off)
+{
+ __raw_writel(val, port->membase + off);
+}
+
+static inline unsigned int msm_read(struct uart_port *port, unsigned int off)
+{
+ return __raw_readl(port->membase + off);
+}
+
+static void msm_stop_tx(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ msm_port->imr &= ~UART_IMR_TXLEV;
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_start_tx(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ msm_port->imr |= UART_IMR_TXLEV;
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_stop_rx(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_enable_ms(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ msm_port->imr |= UART_IMR_DELTA_CTS;
+ msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void handle_rx(struct uart_port *port)
+{
+ struct tty_struct *tty = port->info->port.tty;
+ unsigned int sr;
+
+ /*
+ * Handle overrun. My understanding of the hardware is that overrun
+ * is not tied to the RX buffer, so we handle the case out of band.
+ */
+ if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
+ port->icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ }
+
+ /* and now the main RX loop */
+ while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
+ unsigned int c;
+ char flag = TTY_NORMAL;
+
+ c = msm_read(port, UART_RF);
+
+ if (sr & UART_SR_RX_BREAK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (sr & UART_SR_PAR_FRAME_ERR) {
+ port->icount.frame++;
+ } else {
+ port->icount.rx++;
+ }
+
+ /* Mask conditions we're ignorning. */
+ sr &= port->read_status_mask;
+
+ if (sr & UART_SR_RX_BREAK) {
+ flag = TTY_BREAK;
+ } else if (sr & UART_SR_PAR_FRAME_ERR) {
+ flag = TTY_FRAME;
+ }
+
+ if (!uart_handle_sysrq_char(port, c))
+ tty_insert_flip_char(tty, c, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+}
+
+static void handle_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ int sent_tx;
+
+ if (port->x_char) {
+ msm_write(port, port->x_char, UART_TF);
+ port->icount.tx++;
+ port->x_char = 0;
+ }
+
+ while (msm_read(port, UART_SR) & UART_SR_TX_READY) {
+ if (uart_circ_empty(xmit)) {
+ /* disable tx interrupts */
+ msm_port->imr &= ~UART_IMR_TXLEV;
+ msm_write(port, msm_port->imr, UART_IMR);
+ break;
+ }
+
+ msm_write(port, xmit->buf[xmit->tail], UART_TF);
+
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ sent_tx = 1;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+}
+
+static void handle_delta_cts(struct uart_port *port)
+{
+ msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+ port->icount.cts++;
+ wake_up_interruptible(&port->info->delta_msr_wait);
+}
+
+static irqreturn_t msm_irq(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ unsigned int misr;
+
+ spin_lock(&port->lock);
+ misr = msm_read(port, UART_MISR);
+ msm_write(port, 0, UART_IMR); /* disable interrupt */
+
+ if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE))
+ handle_rx(port);
+ if (misr & UART_IMR_TXLEV)
+ handle_tx(port);
+ if (misr & UART_IMR_DELTA_CTS)
+ handle_delta_cts(port);
+
+ msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int msm_tx_empty(struct uart_port *port)
+{
+ return (msm_read(port, UART_SR) & UART_SR_TX_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int msm_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
+}
+
+static void msm_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned int mr;
+
+ mr = msm_read(port, UART_MR1);
+
+ if (!(mctrl & TIOCM_RTS)) {
+ mr &= ~UART_MR1_RX_RDY_CTL;
+ msm_write(port, mr, UART_MR1);
+ msm_write(port, UART_CR_CMD_RESET_RFR, UART_CR);
+ } else {
+ mr |= UART_MR1_RX_RDY_CTL;
+ msm_write(port, mr, UART_MR1);
+ }
+}
+
+static void msm_break_ctl(struct uart_port *port, int break_ctl)
+{
+ if (break_ctl)
+ msm_write(port, UART_CR_CMD_START_BREAK, UART_CR);
+ else
+ msm_write(port, UART_CR_CMD_STOP_BREAK, UART_CR);
+}
+
+static void msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+{
+ unsigned int baud_code, rxstale, watermark;
+
+ switch (baud) {
+ case 300:
+ baud_code = UART_CSR_300;
+ rxstale = 1;
+ break;
+ case 600:
+ baud_code = UART_CSR_600;
+ rxstale = 1;
+ break;
+ case 1200:
+ baud_code = UART_CSR_1200;
+ rxstale = 1;
+ break;
+ case 2400:
+ baud_code = UART_CSR_2400;
+ rxstale = 1;
+ break;
+ case 4800:
+ baud_code = UART_CSR_4800;
+ rxstale = 1;
+ break;
+ case 9600:
+ baud_code = UART_CSR_9600;
+ rxstale = 2;
+ break;
+ case 14400:
+ baud_code = UART_CSR_14400;
+ rxstale = 3;
+ break;
+ case 19200:
+ baud_code = UART_CSR_19200;
+ rxstale = 4;
+ break;
+ case 28800:
+ baud_code = UART_CSR_28800;
+ rxstale = 6;
+ break;
+ case 38400:
+ baud_code = UART_CSR_38400;
+ rxstale = 8;
+ break;
+ case 57600:
+ baud_code = UART_CSR_57600;
+ rxstale = 16;
+ break;
+ case 115200:
+ default:
+ baud_code = UART_CSR_115200;
+ rxstale = 31;
+ break;
+ }
+
+ msm_write(port, baud_code, UART_CSR);
+
+ /* RX stale watermark */
+ watermark = UART_IPR_STALE_LSB & rxstale;
+ watermark |= UART_IPR_RXSTALE_LAST;
+ watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
+ msm_write(port, watermark, UART_IPR);
+
+ /* set RX watermark */
+ watermark = (port->fifosize * 3) / 4;
+ msm_write(port, watermark, UART_RFWR);
+
+ /* set TX watermark */
+ msm_write(port, 10, UART_TFWR);
+}
+
+static void msm_reset(struct uart_port *port)
+{
+ /* reset everything */
+ msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_BREAK_INT, UART_CR);
+ msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
+ msm_write(port, UART_CR_CMD_SET_RFR, UART_CR);
+}
+
+static void msm_init_clock(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ clk_enable(msm_port->clk);
+
+ msm_write(port, 0xC0, UART_MREG);
+ msm_write(port, 0xB2, UART_NREG);
+ msm_write(port, 0x7D, UART_DREG);
+ msm_write(port, 0x1C, UART_MNDREG);
+}
+
+static int msm_startup(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+ unsigned int data, rfr_level;
+ int ret;
+
+ snprintf(msm_port->name, sizeof(msm_port->name),
+ "msm_serial%d", port->line);
+
+ ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
+ msm_port->name, port);
+ if (unlikely(ret))
+ return ret;
+
+ msm_init_clock(port);
+
+ if (likely(port->fifosize > 12))
+ rfr_level = port->fifosize - 12;
+ else
+ rfr_level = port->fifosize;
+
+ /* set automatic RFR level */
+ data = msm_read(port, UART_MR1);
+ data &= ~UART_MR1_AUTO_RFR_LEVEL1;
+ data &= ~UART_MR1_AUTO_RFR_LEVEL0;
+ data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
+ data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
+ msm_write(port, data, UART_MR1);
+
+ /* make sure that RXSTALE count is non-zero */
+ data = msm_read(port, UART_IPR);
+ if (unlikely(!data)) {
+ data |= UART_IPR_RXSTALE_LAST;
+ data |= UART_IPR_STALE_LSB;
+ msm_write(port, data, UART_IPR);
+ }
+
+ msm_reset(port);
+
+ msm_write(port, 0x05, UART_CR); /* enable TX & RX */
+
+ /* turn on RX and CTS interrupts */
+ msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
+ UART_IMR_CURRENT_CTS;
+ msm_write(port, msm_port->imr, UART_IMR);
+
+ return 0;
+}
+
+static void msm_shutdown(struct uart_port *port)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ msm_port->imr = 0;
+ msm_write(port, 0, UART_IMR); /* disable interrupts */
+
+ clk_disable(msm_port->clk);
+
+ free_irq(port->irq, port);
+}
+
+static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud, mr;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* calculate and set baud rate */
+ baud = uart_get_baud_rate(port, termios, old, 300, 115200);
+ msm_set_baud_rate(port, baud);
+
+ /* calculate parity */
+ mr = msm_read(port, UART_MR2);
+ mr &= ~UART_MR2_PARITY_MODE;
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & PARODD)
+ mr |= UART_MR2_PARITY_MODE_ODD;
+ else if (termios->c_cflag & CMSPAR)
+ mr |= UART_MR2_PARITY_MODE_SPACE;
+ else
+ mr |= UART_MR2_PARITY_MODE_EVEN;
+ }
+
+ /* calculate bits per char */
+ mr &= ~UART_MR2_BITS_PER_CHAR;
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ mr |= UART_MR2_BITS_PER_CHAR_5;
+ break;
+ case CS6:
+ mr |= UART_MR2_BITS_PER_CHAR_6;
+ break;
+ case CS7:
+ mr |= UART_MR2_BITS_PER_CHAR_7;
+ break;
+ case CS8:
+ default:
+ mr |= UART_MR2_BITS_PER_CHAR_8;
+ break;
+ }
+
+ /* calculate stop bits */
+ mr &= ~(UART_MR2_STOP_BIT_LEN_ONE | UART_MR2_STOP_BIT_LEN_TWO);
+ if (termios->c_cflag & CSTOPB)
+ mr |= UART_MR2_STOP_BIT_LEN_TWO;
+ else
+ mr |= UART_MR2_STOP_BIT_LEN_ONE;
+
+ /* set parity, bits per char, and stop bit */
+ msm_write(port, mr, UART_MR2);
+
+ /* calculate and set hardware flow control */
+ mr = msm_read(port, UART_MR1);
+ mr &= ~(UART_MR1_CTS_CTL | UART_MR1_RX_RDY_CTL);
+ if (termios->c_cflag & CRTSCTS) {
+ mr |= UART_MR1_CTS_CTL;
+ mr |= UART_MR1_RX_RDY_CTL;
+ }
+ msm_write(port, mr, UART_MR1);
+
+ /* Configure status bits to ignore based on termio flags. */
+ port->read_status_mask = 0;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= UART_SR_PAR_FRAME_ERR;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= UART_SR_RX_BREAK;
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *msm_type(struct uart_port *port)
+{
+ return "MSM";
+}
+
+static void msm_release_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *resource;
+ resource_size_t size;
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!resource))
+ return;
+ size = resource->end - resource->start + 1;
+
+ release_mem_region(port->mapbase, size);
+ iounmap(port->membase);
+ port->membase = NULL;
+}
+
+static int msm_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *resource;
+ resource_size_t size;
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!resource))
+ return -ENXIO;
+ size = resource->end - resource->start + 1;
+
+ if (unlikely(!request_mem_region(port->mapbase, size, "msm_serial")))
+ return -EBUSY;
+
+ port->membase = ioremap(port->mapbase, size);
+ if (!port->membase) {
+ release_mem_region(port->mapbase, size);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void msm_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_MSM;
+ msm_request_port(port);
+ }
+}
+
+static int msm_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if (unlikely(ser->type != PORT_UNKNOWN && ser->type != PORT_MSM))
+ return -EINVAL;
+ if (unlikely(port->irq != ser->irq))
+ return -EINVAL;
+ return 0;
+}
+
+static void msm_power(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ struct msm_port *msm_port = UART_TO_MSM(port);
+
+ switch (state) {
+ case 0:
+ clk_enable(msm_port->clk);
+ break;
+ case 3:
+ clk_disable(msm_port->clk);
+ break;
+ default:
+ printk(KERN_ERR "msm_serial: Unknown PM state %d\n", state);
+ }
+}
+
+static struct uart_ops msm_uart_pops = {
+ .tx_empty = msm_tx_empty,
+ .set_mctrl = msm_set_mctrl,
+ .get_mctrl = msm_get_mctrl,
+ .stop_tx = msm_stop_tx,
+ .start_tx = msm_start_tx,
+ .stop_rx = msm_stop_rx,
+ .enable_ms = msm_enable_ms,
+ .break_ctl = msm_break_ctl,
+ .startup = msm_startup,
+ .shutdown = msm_shutdown,
+ .set_termios = msm_set_termios,
+ .type = msm_type,
+ .release_port = msm_release_port,
+ .request_port = msm_request_port,
+ .config_port = msm_config_port,
+ .verify_port = msm_verify_port,
+ .pm = msm_power,
+};
+
+static struct msm_port msm_uart_ports[] = {
+ {
+ .uart = {
+ .iotype = UPIO_MEM,
+ .ops = &msm_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .fifosize = 512,
+ .line = 0,
+ },
+ },
+ {
+ .uart = {
+ .iotype = UPIO_MEM,
+ .ops = &msm_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .fifosize = 512,
+ .line = 1,
+ },
+ },
+ {
+ .uart = {
+ .iotype = UPIO_MEM,
+ .ops = &msm_uart_pops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .fifosize = 64,
+ .line = 2,
+ },
+ },
+};
+
+#define UART_NR ARRAY_SIZE(msm_uart_ports)
+
+static inline struct uart_port *get_port_from_line(unsigned int line)
+{
+ return &msm_uart_ports[line].uart;
+}
+
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+
+static void msm_console_putchar(struct uart_port *port, int c)
+{
+ while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
+ ;
+ msm_write(port, c, UART_TF);
+}
+
+static void msm_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port;
+ struct msm_port *msm_port;
+
+ BUG_ON(co->index < 0 || co->index >= UART_NR);
+
+ port = get_port_from_line(co->index);
+ msm_port = UART_TO_MSM(port);
+
+ spin_lock(&port->lock);
+ uart_console_write(port, s, count, msm_console_putchar);
+ spin_unlock(&port->lock);
+}
+
+static int __init msm_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud, flow, bits, parity;
+
+ if (unlikely(co->index >= UART_NR || co->index < 0))
+ return -ENXIO;
+
+ port = get_port_from_line(co->index);
+
+ if (unlikely(!port->membase))
+ return -ENXIO;
+
+ port->cons = co;
+
+ msm_init_clock(port);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ bits = 8;
+ parity = 'n';
+ flow = 'n';
+ msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
+ UART_MR2); /* 8N1 */
+
+ if (baud < 300 || baud > 115200)
+ baud = 115200;
+ msm_set_baud_rate(port, baud);
+
+ msm_reset(port);
+
+ printk(KERN_INFO "msm_serial: console setup on port #%d\n", port->line);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver msm_uart_driver;
+
+static struct console msm_console = {
+ .name = "ttyMSM",
+ .write = msm_console_write,
+ .device = uart_console_device,
+ .setup = msm_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &msm_uart_driver,
+};
+
+#define MSM_CONSOLE (&msm_console)
+
+#else
+#define MSM_CONSOLE NULL
+#endif
+
+static struct uart_driver msm_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "msm_serial",
+ .dev_name = "ttyMSM",
+ .nr = UART_NR,
+ .cons = MSM_CONSOLE,
+};
+
+static int __init msm_serial_probe(struct platform_device *pdev)
+{
+ struct msm_port *msm_port;
+ struct resource *resource;
+ struct uart_port *port;
+
+ if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
+ return -ENXIO;
+
+ printk(KERN_INFO "msm_serial: detected port #%d\n", pdev->id);
+
+ port = get_port_from_line(pdev->id);
+ port->dev = &pdev->dev;
+ msm_port = UART_TO_MSM(port);
+
+ msm_port->clk = clk_get(&pdev->dev, "uart_clk");
+ if (unlikely(IS_ERR(msm_port->clk)))
+ return PTR_ERR(msm_port->clk);
+ port->uartclk = clk_get_rate(msm_port->clk);
+
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!resource))
+ return -ENXIO;
+ port->mapbase = resource->start;
+
+ port->irq = platform_get_irq(pdev, 0);
+ if (unlikely(port->irq < 0))
+ return -ENXIO;
+
+ platform_set_drvdata(pdev, port);
+
+ return uart_add_one_port(&msm_uart_driver, port);
+}
+
+static int __devexit msm_serial_remove(struct platform_device *pdev)
+{
+ struct msm_port *msm_port = platform_get_drvdata(pdev);
+
+ clk_put(msm_port->clk);
+
+ return 0;
+}
+
+static struct platform_driver msm_platform_driver = {
+ .probe = msm_serial_probe,
+ .remove = msm_serial_remove,
+ .driver = {
+ .name = "msm_serial",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_serial_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&msm_uart_driver);
+ if (unlikely(ret))
+ return ret;
+
+ ret = platform_driver_probe(&msm_platform_driver, msm_serial_probe);
+ if (unlikely(ret))
+ uart_unregister_driver(&msm_uart_driver);
+
+ printk(KERN_INFO "msm_serial: driver initialized\n");
+
+ return ret;
+}
+
+static void __exit msm_serial_exit(void)
+{
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+ unregister_console(&msm_console);
+#endif
+ platform_driver_unregister(&msm_platform_driver);
+ uart_unregister_driver(&msm_uart_driver);
+}
+
+module_init(msm_serial_init);
+module_exit(msm_serial_exit);
+
+MODULE_AUTHOR("Robert Love <rlove@google.com>");
+MODULE_DESCRIPTION("Driver for msm7x serial device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
new file mode 100644
index 0000000..689f1fa
--- /dev/null
+++ b/drivers/serial/msm_serial.h
@@ -0,0 +1,117 @@
+/*
+ * drivers/serial/msm_serial.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Robert Love <rlove@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
+#define __DRIVERS_SERIAL_MSM_SERIAL_H
+
+#define UART_MR1 0x0000
+
+#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
+#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
+#define UART_MR1_RX_RDY_CTL (1 << 7)
+#define UART_MR1_CTS_CTL (1 << 6)
+
+#define UART_MR2 0x0004
+#define UART_MR2_ERROR_MODE (1 << 6)
+#define UART_MR2_BITS_PER_CHAR 0x30
+#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
+#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
+#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
+#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
+#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
+#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
+#define UART_MR2_PARITY_MODE_NONE 0x0
+#define UART_MR2_PARITY_MODE_ODD 0x1
+#define UART_MR2_PARITY_MODE_EVEN 0x2
+#define UART_MR2_PARITY_MODE_SPACE 0x3
+#define UART_MR2_PARITY_MODE 0x3
+
+#define UART_CSR 0x0008
+#define UART_CSR_115200 0xFF
+#define UART_CSR_57600 0xEE
+#define UART_CSR_38400 0xDD
+#define UART_CSR_28800 0xCC
+#define UART_CSR_19200 0xBB
+#define UART_CSR_14400 0xAA
+#define UART_CSR_9600 0x99
+#define UART_CSR_4800 0x77
+#define UART_CSR_2400 0x55
+#define UART_CSR_1200 0x44
+#define UART_CSR_600 0x33
+#define UART_CSR_300 0x22
+
+#define UART_TF 0x000C
+
+#define UART_CR 0x0010
+#define UART_CR_CMD_NULL (0 << 4)
+#define UART_CR_CMD_RESET_RX (1 << 4)
+#define UART_CR_CMD_RESET_TX (2 << 4)
+#define UART_CR_CMD_RESET_ERR (3 << 4)
+#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
+#define UART_CR_CMD_START_BREAK (5 << 4)
+#define UART_CR_CMD_STOP_BREAK (6 << 4)
+#define UART_CR_CMD_RESET_CTS (7 << 4)
+#define UART_CR_CMD_PACKET_MODE (9 << 4)
+#define UART_CR_CMD_MODE_RESET (12 << 4)
+#define UART_CR_CMD_SET_RFR (13 << 4)
+#define UART_CR_CMD_RESET_RFR (14 << 4)
+#define UART_CR_TX_DISABLE (1 << 3)
+#define UART_CR_TX_ENABLE (1 << 3)
+#define UART_CR_RX_DISABLE (1 << 3)
+#define UART_CR_RX_ENABLE (1 << 3)
+
+#define UART_IMR 0x0014
+#define UART_IMR_TXLEV (1 << 0)
+#define UART_IMR_RXSTALE (1 << 3)
+#define UART_IMR_RXLEV (1 << 4)
+#define UART_IMR_DELTA_CTS (1 << 5)
+#define UART_IMR_CURRENT_CTS (1 << 6)
+
+#define UART_IPR_RXSTALE_LAST 0x20
+#define UART_IPR_STALE_LSB 0x1F
+#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
+
+#define UART_IPR 0x0018
+#define UART_TFWR 0x001C
+#define UART_RFWR 0x0020
+#define UART_HCR 0x0024
+
+#define UART_MREG 0x0028
+#define UART_NREG 0x002C
+#define UART_DREG 0x0030
+#define UART_MNDREG 0x0034
+#define UART_IRDA 0x0038
+#define UART_MISR_MODE 0x0040
+#define UART_MISR_RESET 0x0044
+#define UART_MISR_EXPORT 0x0048
+#define UART_MISR_VAL 0x004C
+#define UART_TEST_CTRL 0x0050
+
+#define UART_SR 0x0008
+#define UART_SR_HUNT_CHAR (1 << 7)
+#define UART_SR_RX_BREAK (1 << 6)
+#define UART_SR_PAR_FRAME_ERR (1 << 5)
+#define UART_SR_OVERRUN (1 << 4)
+#define UART_SR_TX_EMPTY (1 << 3)
+#define UART_SR_TX_READY (1 << 2)
+#define UART_SR_RX_FULL (1 << 1)
+#define UART_SR_RX_READY (1 << 0)
+
+#define UART_RF 0x000C
+#define UART_MISR 0x0010
+#define UART_ISR 0x0014
+
+#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 6fd80c4..23d2fb0 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -171,6 +171,9 @@
/* Timberdale UART */
#define PORT_TIMBUART 87
+/* Qualcomm MSM SoCs */
+#define PORT_MSM 88
+
#ifdef __KERNEL__
#include <linux/compiler.h>
--
1.6.2.4
^ permalink raw reply related [flat|nested] 22+ messages in thread
end of thread, other threads:[~2009-06-18 19:29 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-18 0:31 Revised patch series for minimal HTC Dream support Brian Swetland
2009-06-18 0:31 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
2009-06-18 0:31 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Brian Swetland
2009-06-18 0:31 ` [PATCH 3/3] [ARM] msm: add minimal board file for HTC Dream device Brian Swetland
2009-06-18 1:56 ` GeunSik Lim
2009-06-18 2:44 ` Brian Swetland
2009-06-18 14:01 ` GeunSik Lim
2009-06-18 10:26 ` Pavel Machek
2009-06-18 10:26 ` [PATCH 2/3] [ARM] msm: make debugging UART (for DEBUG_LL) configurable Pavel Machek
2009-06-18 9:20 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Alan Cox
2009-06-18 19:29 ` Brian Swetland
-- strict thread matches above, loose matches on Subject: below --
2009-06-15 2:39 Patches to get serial working on msm7k / htc dream Brian Swetland
2009-06-15 2:39 ` [PATCH 1/3] [ARM] msm_serial: serial driver for MSM7K onboard serial peripheral Brian Swetland
2009-06-15 3:18 ` Ryan Mallon
2009-06-15 8:54 ` Alan Cox
2009-06-15 8:52 ` Pavel Machek
2009-06-15 8:58 ` Russell King - ARM Linux
2009-06-15 9:55 ` Brian Swetland
2009-06-16 7:35 ` Russell King - ARM Linux
2009-06-15 8:52 ` Alan Cox
2009-06-17 3:07 ` Brian Swetland
2009-06-15 9:05 ` Linus Walleij
2009-06-17 12:17 ` Robert Love
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.