X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fserial%2Fpxa.c;h=b4f7ffb7688d16b99facc3bd859042836bc66246;hb=7371fd11a6e2aed99895db4f100940fa5022f7fe;hp=ae3649568541d091a24e121f391d061f514285fd;hpb=55b4d6a52195a8f277ffddf755ddaff359878f41;p=linux-2.6 diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index ae36495685..b4f7ffb768 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -24,7 +24,6 @@ * with the serial core maintainer satisfaction to appear soon. */ -#include #if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ @@ -43,6 +42,7 @@ #include #include #include +#include #include #include @@ -56,7 +56,7 @@ struct uart_pxa_port { unsigned char lcr; unsigned char mcr; unsigned int lsr_break_flag; - unsigned int cken; + struct clk *clk; char *name; }; @@ -99,8 +99,7 @@ static void serial_pxa_stop_rx(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -static inline void -receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) +static inline void receive_chars(struct uart_pxa_port *up, int *status) { struct tty_struct *tty = up->port.info->tty; unsigned int ch, flag; @@ -154,7 +153,7 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch, regs)) + if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); @@ -232,10 +231,9 @@ static inline void check_modem_status(struct uart_pxa_port *up) /* * This handles the interrupt from one port. */ -static inline irqreturn_t -serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs) +static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) { - struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id; + struct uart_pxa_port *up = dev_id; unsigned int iir, lsr; iir = serial_in(up, UART_IIR); @@ -243,7 +241,7 @@ serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; lsr = serial_in(up, UART_LSR); if (lsr & UART_LSR_DR) - receive_chars(up, &lsr, regs); + receive_chars(up, &lsr); check_modem_status(up); if (lsr & UART_LSR_THRE) transmit_chars(up); @@ -354,6 +352,8 @@ static int serial_pxa_startup(struct uart_port *port) else up->mcr = 0; + up->port.uartclk = clk_get_rate(up->clk); + /* * Allocate the IRQ */ @@ -390,7 +390,7 @@ static int serial_pxa_startup(struct uart_port *port) /* * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occuring imminently + * are set via set_termios(), which will be occurring imminently * anyway, so we don't enable them here. */ up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; @@ -436,8 +436,8 @@ static void serial_pxa_shutdown(struct uart_port *port) } static void -serial_pxa_set_termios(struct uart_port *port, struct termios *termios, - struct termios *old) +serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; unsigned char cval, fcr = 0; @@ -549,9 +549,11 @@ serial_pxa_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; - pxa_set_cken(up->cken, !state); + if (!state) - udelay(1); + clk_enable(up->clk); + else + clk_disable(up->clk); } static void serial_pxa_release_port(struct uart_port *port) @@ -583,11 +585,11 @@ serial_pxa_type(struct uart_port *port) return up->name; } -#ifdef CONFIG_SERIAL_PXA_CONSOLE - -static struct uart_pxa_port serial_pxa_ports[]; +static struct uart_pxa_port *serial_pxa_ports[4]; static struct uart_driver serial_pxa_reg; +#ifdef CONFIG_SERIAL_PXA_CONSOLE + #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) /* @@ -635,9 +637,11 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch) static void serial_pxa_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_pxa_port *up = &serial_pxa_ports[co->index]; + struct uart_pxa_port *up = serial_pxa_ports[co->index]; unsigned int ier; + clk_enable(up->clk); + /* * First save the IER then disable the interrupts */ @@ -652,6 +656,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) */ wait_for_xmitr(up); serial_out(up, UART_IER, ier); + + clk_disable(up->clk); } static int __init @@ -665,7 +671,9 @@ serial_pxa_console_setup(struct console *co, char *options) if (co->index == -1 || co->index >= serial_pxa_reg.nr) co->index = 0; - up = &serial_pxa_ports[co->index]; + up = serial_pxa_ports[co->index]; + if (!up) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -683,15 +691,6 @@ static struct console serial_pxa_console = { .data = &serial_pxa_reg, }; -static int __init -serial_pxa_console_init(void) -{ - register_console(&serial_pxa_console); - return 0; -} - -console_initcall(serial_pxa_console_init); - #define PXA_CONSOLE &serial_pxa_console #else #define PXA_CONSOLE NULL @@ -717,74 +716,13 @@ struct uart_ops serial_pxa_pops = { .verify_port = serial_pxa_verify_port, }; -static struct uart_pxa_port serial_pxa_ports[] = { - { /* FFUART */ - .name = "FFUART", - .cken = CKEN6_FFUART, - .port = { - .type = PORT_PXA, - .iotype = UPIO_MEM, - .membase = (void *)&FFUART, - .mapbase = __PREG(FFUART), - .irq = IRQ_FFUART, - .uartclk = 921600 * 16, - .fifosize = 64, - .ops = &serial_pxa_pops, - .line = 0, - }, - }, { /* BTUART */ - .name = "BTUART", - .cken = CKEN7_BTUART, - .port = { - .type = PORT_PXA, - .iotype = UPIO_MEM, - .membase = (void *)&BTUART, - .mapbase = __PREG(BTUART), - .irq = IRQ_BTUART, - .uartclk = 921600 * 16, - .fifosize = 64, - .ops = &serial_pxa_pops, - .line = 1, - }, - }, { /* STUART */ - .name = "STUART", - .cken = CKEN5_STUART, - .port = { - .type = PORT_PXA, - .iotype = UPIO_MEM, - .membase = (void *)&STUART, - .mapbase = __PREG(STUART), - .irq = IRQ_STUART, - .uartclk = 921600 * 16, - .fifosize = 64, - .ops = &serial_pxa_pops, - .line = 2, - }, - }, { /* HWUART */ - .name = "HWUART", - .cken = CKEN4_HWUART, - .port = { - .type = PORT_PXA, - .iotype = UPIO_MEM, - .membase = (void *)&HWUART, - .mapbase = __PREG(HWUART), - .irq = IRQ_HWUART, - .uartclk = 921600 * 16, - .fifosize = 64, - .ops = &serial_pxa_pops, - .line = 3, - }, - } -}; - static struct uart_driver serial_pxa_reg = { .owner = THIS_MODULE, .driver_name = "PXA serial", - .devfs_name = "tts/", .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, - .nr = ARRAY_SIZE(serial_pxa_ports), + .nr = 4, .cons = PXA_CONSOLE, }; @@ -810,10 +748,68 @@ static int serial_pxa_resume(struct platform_device *dev) static int serial_pxa_probe(struct platform_device *dev) { - serial_pxa_ports[dev->id].port.dev = &dev->dev; - uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port); - platform_set_drvdata(dev, &serial_pxa_ports[dev->id]); + struct uart_pxa_port *sport; + struct resource *mmres, *irqres; + int ret; + + mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); + irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); + if (!mmres || !irqres) + return -ENODEV; + + sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + sport->clk = clk_get(&dev->dev, "UARTCLK"); + if (IS_ERR(sport->clk)) { + ret = PTR_ERR(sport->clk); + goto err_free; + } + + sport->port.type = PORT_PXA; + sport->port.iotype = UPIO_MEM; + sport->port.mapbase = mmres->start; + sport->port.irq = irqres->start; + sport->port.fifosize = 64; + sport->port.ops = &serial_pxa_pops; + sport->port.line = dev->id; + sport->port.dev = &dev->dev; + sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; + sport->port.uartclk = clk_get_rate(sport->clk); + + /* + * Is it worth keeping this? + */ + if (mmres->start == __PREG(FFUART)) + sport->name = "FFUART"; + else if (mmres->start == __PREG(BTUART)) + sport->name = "BTUART"; + else if (mmres->start == __PREG(STUART)) + sport->name = "STUART"; + else if (mmres->start == __PREG(HWUART)) + sport->name = "HWUART"; + else + sport->name = "???"; + + sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1); + if (!sport->port.membase) { + ret = -ENOMEM; + goto err_clk; + } + + serial_pxa_ports[dev->id] = sport; + + uart_add_one_port(&serial_pxa_reg, &sport->port); + platform_set_drvdata(dev, sport); + return 0; + + err_clk: + clk_put(sport->clk); + err_free: + kfree(sport); + return ret; } static int serial_pxa_remove(struct platform_device *dev) @@ -822,8 +818,9 @@ static int serial_pxa_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); - if (sport) - uart_remove_one_port(&serial_pxa_reg, &sport->port); + uart_remove_one_port(&serial_pxa_reg, &sport->port); + clk_put(sport->clk); + kfree(sport); return 0; } @@ -836,6 +833,7 @@ static struct platform_driver serial_pxa_driver = { .resume = serial_pxa_resume, .driver = { .name = "pxa2xx-uart", + .owner = THIS_MODULE, }, }; @@ -864,4 +862,4 @@ module_init(serial_pxa_init); module_exit(serial_pxa_exit); MODULE_LICENSE("GPL"); - +MODULE_ALIAS("platform:pxa2xx-uart");