diff --git a/Documentation/devicetree/bindings/serial/ingenic,uart.txt b/Documentation/devicetree/bindings/serial/ingenic,uart.txt new file mode 100644 index 00000000000000..c2d3b3abe7d9ab --- /dev/null +++ b/Documentation/devicetree/bindings/serial/ingenic,uart.txt @@ -0,0 +1,22 @@ +* Ingenic SoC UART + +Required properties: +- compatible : "ingenic,jz4740-uart" or "ingenic,jz4780-uart" +- reg : offset and length of the register set for the device. +- interrupts : should contain uart interrupt. +- clocks : phandles to the module & baud clocks. +- clock-names: tuple listing input clock names. + Required elements: "baud", "module" + +Example: + +uart0: serial@10030000 { + compatible = "ingenic,jz4740-uart"; + reg = <0x10030000 0x100>; + + interrupt-parent = <&intc>; + interrupts = <9>; + + clocks = <&ext>, <&cgu JZ4740_CLK_UART0>; + clock-names = "baud", "module"; +}; diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 147b9f05e0915b..9554a93eb48a02 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -261,7 +261,6 @@ config MACH_JZ4780 select GENERIC_CLOCKEVENTS_BROADCAST if SMP select IRQ_CPU select ARCH_REQUIRE_GPIOLIB - select SYS_HAS_EARLY_PRINTK select COMMON_CLK select PINCTRL select PINCTRL_JZ4780 diff --git a/arch/mips/boot/dts/ci20.dts b/arch/mips/boot/dts/ci20.dts index a65bf4077c8ae4..56afb95225e8fc 100644 --- a/arch/mips/boot/dts/ci20.dts +++ b/arch/mips/boot/dts/ci20.dts @@ -5,6 +5,17 @@ / { compatible = "imgtec,ci20", "ingenic,jz4780"; + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial3 = &uart3; + serial4 = &uart4; + }; + + chosen { + stdout-path = &uart4; + }; + memory { device_type = "memory"; reg = <0x0 0x10000000 diff --git a/arch/mips/boot/dts/jz4740.dtsi b/arch/mips/boot/dts/jz4740.dtsi index e0b362ecc75e61..d331a1dc9a8764 100644 --- a/arch/mips/boot/dts/jz4740.dtsi +++ b/arch/mips/boot/dts/jz4740.dtsi @@ -42,4 +42,26 @@ #clock-cells = <1>; }; + + uart0: serial@10030000 { + compatible = "ingenic,jz4740-uart"; + reg = <0x10030000 0x100>; + + interrupt-parent = <&intc>; + interrupts = <9>; + + clocks = <&ext>, <&cgu JZ4740_CLK_UART0>; + clock-names = "baud", "module"; + }; + + uart1: serial@10031000 { + compatible = "ingenic,jz4740-uart"; + reg = <0x10031000 0x100>; + + interrupt-parent = <&intc>; + interrupts = <8>; + + clocks = <&ext>, <&cgu JZ4740_CLK_UART1>; + clock-names = "baud", "module"; + }; }; diff --git a/arch/mips/boot/dts/jz4780.dtsi b/arch/mips/boot/dts/jz4780.dtsi index 4c0dc619cfc530..07e5845aed3204 100644 --- a/arch/mips/boot/dts/jz4780.dtsi +++ b/arch/mips/boot/dts/jz4780.dtsi @@ -392,7 +392,8 @@ interrupt-parent = <&intc>; interrupts = <51>; - clocks = <&cgu JZ4780_CLK_UART0>; + clocks = <&ext>, <&cgu JZ4780_CLK_UART0>; + clock-names = "baud", "module"; }; uart1: serial@10031000 { @@ -403,7 +404,8 @@ interrupt-parent = <&intc>; interrupts = <50>; - clocks = <&cgu JZ4780_CLK_UART1>; + clocks = <&ext>, <&cgu JZ4780_CLK_UART1>; + clock-names = "baud", "module"; }; uart2: serial@10032000 { @@ -416,7 +418,8 @@ pinctrl-names = "default"; pinctrl-0 = <&pins_uart2_dataplusflow>; - clocks = <&cgu JZ4780_CLK_UART2>; + clocks = <&ext>, <&cgu JZ4780_CLK_UART2>; + clock-names = "baud", "module"; }; uart3: serial@10033000 { @@ -427,7 +430,8 @@ interrupt-parent = <&intc>; interrupts = <48>; - clocks = <&cgu JZ4780_CLK_UART3>; + clocks = <&ext>, <&cgu JZ4780_CLK_UART3>; + clock-names = "baud", "module"; }; uart4: serial@10034000 { @@ -438,7 +442,8 @@ interrupt-parent = <&intc>; interrupts = <34>; - clocks = <&cgu JZ4780_CLK_UART4>; + clocks = <&ext>, <&cgu JZ4780_CLK_UART4>; + clock-names = "baud", "module"; }; i2c0: i2c0@0x10050000 { diff --git a/arch/mips/boot/dts/qi_lb60.dts b/arch/mips/boot/dts/qi_lb60.dts index 1a4f6cc7d0ab82..148fbecadbfd6f 100644 --- a/arch/mips/boot/dts/qi_lb60.dts +++ b/arch/mips/boot/dts/qi_lb60.dts @@ -4,6 +4,10 @@ / { compatible = "qi,lb60", "ingenic,jz4740"; + + chosen { + stdout-path = &uart0; + }; }; &ext { diff --git a/arch/mips/configs/ci20_defconfig b/arch/mips/configs/ci20_defconfig index aed6b1265250a4..c0a77dc0421508 100644 --- a/arch/mips/configs/ci20_defconfig +++ b/arch/mips/configs/ci20_defconfig @@ -97,6 +97,7 @@ CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=5 CONFIG_SERIAL_8250_RUNTIME_UARTS=5 +CONFIG_SERIAL_8250_INGENIC=y CONFIG_SERIAL_OF_PLATFORM=y # CONFIG_HW_RANDOM is not set CONFIG_I2C_JZ4780=y @@ -202,7 +203,6 @@ CONFIG_PANIC_ON_OOPS=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_STACKTRACE=y # CONFIG_FTRACE is not set -# CONFIG_EARLY_PRINTK is not set CONFIG_CMDLINE_BOOL=y CONFIG_CMDLINE="console=ttyS4,115200 clk_ignore_unused" CONFIG_XZ_DEC=y diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig index 2b965470c35b94..89194b3e545995 100644 --- a/arch/mips/configs/qi_lb60_defconfig +++ b/arch/mips/configs/qi_lb60_defconfig @@ -66,6 +66,7 @@ CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_DMA is not set CONFIG_SERIAL_8250_NR_UARTS=2 CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_INGENIC=y # CONFIG_HW_RANDOM is not set CONFIG_SPI=y CONFIG_SPI_GPIO=y diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h index 069b43a9da6f0e..32cfbe6a191be8 100644 --- a/arch/mips/include/asm/mach-jz4740/platform.h +++ b/arch/mips/include/asm/mach-jz4740/platform.h @@ -35,6 +35,4 @@ extern struct platform_device jz4740_wdt_device; extern struct platform_device jz4740_pwm_device; extern struct platform_device jz4740_dma_device; -void jz4740_serial_device_register(void); - #endif diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile index 3251d51fc29263..51c71cbac709a5 100644 --- a/arch/mips/jz4740/Makefile +++ b/arch/mips/jz4740/Makefile @@ -5,7 +5,7 @@ # Object file lists. obj-y += prom.o time.o reset.o setup.o \ - platform.o timer.o serial.o + platform.o timer.o obj-$(CONFIG_MACH_JZ4740) += gpio.o diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c index 0fbb2d8a12854a..f84526da3b63ae 100644 --- a/arch/mips/jz4740/board-qi_lb60.c +++ b/arch/mips/jz4740/board-qi_lb60.c @@ -473,8 +473,6 @@ static int __init qi_lb60_init_platform_devices(void) gpiod_add_lookup_table(&qi_lb60_audio_gpio_table); - jz4740_serial_device_register(); - spi_register_board_info(qi_lb60_spi_board_info, ARRAY_SIZE(qi_lb60_spi_board_info)); diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c index 2a5c7c7d0735e1..e8a463b9b663ed 100644 --- a/arch/mips/jz4740/platform.c +++ b/arch/mips/jz4740/platform.c @@ -30,7 +30,6 @@ #include #include -#include "serial.h" #include "clock.h" /* OHCI controller */ @@ -280,50 +279,6 @@ struct platform_device jz4740_adc_device = { .resource = jz4740_adc_resources, }; -/* Serial */ -#define JZ4740_UART_DATA(_id) \ - { \ - .flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE, \ - .iotype = UPIO_MEM, \ - .regshift = 2, \ - .serial_out = jz4740_serial_out, \ - .type = PORT_16550, \ - .mapbase = JZ4740_UART ## _id ## _BASE_ADDR, \ - .irq = JZ4740_IRQ_UART ## _id, \ - } - -static struct plat_serial8250_port jz4740_uart_data[] = { - JZ4740_UART_DATA(0), - JZ4740_UART_DATA(1), - {}, -}; - -static struct platform_device jz4740_uart_device = { - .name = "serial8250", - .id = 0, - .dev = { - .platform_data = jz4740_uart_data, - }, -}; - -void jz4740_serial_device_register(void) -{ - struct plat_serial8250_port *p; - struct clk *ext_clk; - unsigned long ext_rate; - - ext_clk = clk_get(NULL, "ext"); - if (IS_ERR(ext_clk)) - panic("unable to get ext clock"); - ext_rate = clk_get_rate(ext_clk); - clk_put(ext_clk); - - for (p = jz4740_uart_data; p->flags != 0; ++p) - p->uartclk = ext_rate; - - platform_device_register(&jz4740_uart_device); -} - /* Watchdog */ static struct resource jz4740_wdt_resources[] = { { diff --git a/arch/mips/jz4740/prom.c b/arch/mips/jz4740/prom.c index d67762d38b4f42..80c360ba75355f 100644 --- a/arch/mips/jz4740/prom.c +++ b/arch/mips/jz4740/prom.c @@ -59,16 +59,3 @@ void __init prom_init(void) void __init prom_free_prom_memory(void) { } - -#define UART_REG(_reg) ((void __iomem *)CKSEG1ADDR(JZ4740_UART0_BASE_ADDR + (_reg << 2))) - -void prom_putchar(char c) -{ - uint8_t lsr; - - do { - lsr = readb(UART_REG(UART_LSR)); - } while ((lsr & UART_LSR_TEMT) == 0); - - writeb(c, UART_REG(UART_TX)); -} diff --git a/arch/mips/jz4740/serial.c b/arch/mips/jz4740/serial.c deleted file mode 100644 index d23de45826d1c8..00000000000000 --- a/arch/mips/jz4740/serial.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010, Lars-Peter Clausen - * JZ4740 serial support - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include - -void jz4740_serial_out(struct uart_port *p, int offset, int value) -{ - switch (offset) { - case UART_FCR: - value |= 0x10; /* Enable uart module */ - break; - case UART_IER: - value |= (value & 0x4) << 2; - break; - default: - break; - } - writeb(value, p->membase + (offset << p->regshift)); -} diff --git a/arch/mips/jz4740/serial.h b/arch/mips/jz4740/serial.h deleted file mode 100644 index 8eb715bb1ea871..00000000000000 --- a/arch/mips/jz4740/serial.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2010, Lars-Peter Clausen - * JZ4740 serial support - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __MIPS_JZ4740_SERIAL_H__ -#define __MIPS_JZ4740_SERIAL_H__ - -struct uart_port; - -void jz4740_serial_out(struct uart_port *p, int offset, int value); - -#endif diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 013572f5e7beda..ca5cfdc1459a61 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -48,11 +48,6 @@ #include "8250.h" -#ifdef CONFIG_MACH_JZ4780 -#define JZ_UART_MCR_MDCE 0x80 /* Enable modem function */ -#define JZ_UART_MCR_FCM 0x40 /* flow control by hardware */ -#endif - /* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option @@ -334,13 +329,6 @@ static const struct serial8250_config uart_config[] = { .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .flags = UART_CAP_FIFO | UART_CAP_AFE, }, - [PORT_INGENIC_JZ4780] = { - .name = "Ingenic jz4780 UART", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_RTOIE, - }, }; /* Uart divisor latch read */ @@ -452,20 +440,6 @@ static void io_serial_out(struct uart_port *p, int offset, int value) outb(value, p->iobase + offset); } -static void jz47xx_serial_out(struct uart_port *p, int offset, int value) -{ - switch (offset) { - case UART_FCR: - value |= 0x10; /* Enable uart module */ - break; - default: - break; - } - - offset = offset << p->regshift; - writeb(value, p->membase + offset); -} - static int serial8250_default_handle_irq(struct uart_port *port); static int exar_handle_irq(struct uart_port *port); @@ -484,10 +458,7 @@ static void set_io_from_upio(struct uart_port *p) case UPIO_MEM: p->serial_in = mem_serial_in; - if (p->type == PORT_INGENIC_JZ4780) - p->serial_out = jz47xx_serial_out; - else - p->serial_out = mem_serial_out; + p->serial_out = mem_serial_out; break; case UPIO_MEM32: @@ -1950,13 +1921,6 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; - if (port->type == PORT_INGENIC_JZ4780) { - if (mctrl & JZ_UART_MCR_MDCE) - mcr |= JZ_UART_MCR_MDCE; - if (mctrl & JZ_UART_MCR_FCM) - mcr |= JZ_UART_MCR_FCM; - } - mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; serial_port_out(port, UART_MCR, mcr); @@ -2539,11 +2503,8 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, */ up->ier &= ~UART_IER_MSI; if (!(up->bugs & UART_BUG_NOMSR) && - UART_ENABLE_MS(&up->port, termios->c_cflag)) { + UART_ENABLE_MS(&up->port, termios->c_cflag)) up->ier |= UART_IER_MSI; - if (port->type == PORT_INGENIC_JZ4780) - up->port.mctrl = JZ_UART_MCR_MDCE | JZ_UART_MCR_FCM; - } if (up->capabilities & UART_CAP_UUE) up->ier |= UART_IER_UUE; if (up->capabilities & UART_CAP_RTOIE) diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c new file mode 100644 index 00000000000000..972e51e5e2db58 --- /dev/null +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2010 Lars-Peter Clausen + * Copyright (C) 2015 Imagination Technologies + * + * Ingenic SoC UART support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250.h" + +struct ingenic_uart_data { + struct clk *clk_module; + struct clk *clk_baud; + int line; +}; + +#define UART_FCR_UME BIT(4) + +#define UART_MCR_MDCE BIT(7) +#define UART_MCR_FCM BIT(6) + +static struct earlycon_device *early_device; + +static uint8_t __init early_in(struct uart_port *port, int offset) +{ + return readl(port->membase + (offset << 2)); +} + +static void __init early_out(struct uart_port *port, int offset, uint8_t value) +{ + writel(value, port->membase + (offset << 2)); +} + +static void __init ingenic_early_console_putc(struct uart_port *port, int c) +{ + uint8_t lsr; + + do { + lsr = early_in(port, UART_LSR); + } while ((lsr & UART_LSR_TEMT) == 0); + + early_out(port, UART_TX, c); +} + +static void __init ingenic_early_console_write(struct console *console, + const char *s, unsigned int count) +{ + uart_console_write(&early_device->port, s, count, + ingenic_early_console_putc); +} + +static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev) +{ + void *fdt = initial_boot_params; + const __be32 *prop; + int offset; + + offset = fdt_path_offset(fdt, "/ext"); + if (offset < 0) + return; + + prop = fdt_getprop(fdt, offset, "clock-frequency", NULL); + if (!prop) + return; + + dev->port.uartclk = be32_to_cpup(prop); +} + +static int __init ingenic_early_console_setup(struct earlycon_device *dev, + const char *opt) +{ + struct uart_port *port = &dev->port; + unsigned int baud, divisor; + + if (!dev->port.membase) + return -ENODEV; + + ingenic_early_console_setup_clock(dev); + + baud = dev->baud ?: 115200; + divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); + + early_out(port, UART_IER, 0); + early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); + early_out(port, UART_DLL, 0); + early_out(port, UART_DLM, 0); + early_out(port, UART_LCR, UART_LCR_WLEN8); + early_out(port, UART_FCR, UART_FCR_UME | UART_FCR_CLEAR_XMIT | + UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO); + early_out(port, UART_MCR, UART_MCR_RTS | UART_MCR_DTR); + + early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); + early_out(port, UART_DLL, divisor & 0xff); + early_out(port, UART_DLM, (divisor >> 8) & 0xff); + early_out(port, UART_LCR, UART_LCR_WLEN8); + + early_device = dev; + dev->con->write = ingenic_early_console_write; + + return 0; +} + +EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", + ingenic_early_console_setup); + +EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", + ingenic_early_console_setup); + +EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", + ingenic_early_console_setup); + +static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) +{ + int mcr, orig; + + switch (offset) { + case UART_FCR: + /* UART module enable */ + value |= UART_FCR_UME; + break; + + case UART_IER: + /* If we have enabled modem status IRQs we should enable modem + * mode. */ + mcr = orig = p->serial_in(p, UART_MCR); + if (value & UART_IER_MSI) { + mcr |= UART_MCR_MDCE | UART_MCR_FCM; + } else { + mcr &= ~(UART_MCR_MDCE | UART_MCR_FCM); + } + + if (mcr != orig) + ingenic_uart_serial_out(p, UART_MCR, mcr); + + value |= (value & 0x4) << 2; + break; + + default: + break; + } + + writeb(value, p->membase + (offset << p->regshift)); +} + +static int ingenic_uart_probe(struct platform_device *pdev) +{ + struct uart_8250_port uart = {}; + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct ingenic_uart_data *data; + int err, line; + + if (!regs || !irq) { + dev_err(&pdev->dev, "no registers/irq defined\n"); + return -EINVAL; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&uart.port.lock); + uart.port.type = PORT_16550; + uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; + uart.port.iotype = UPIO_MEM; + uart.port.mapbase = regs->start; + uart.port.regshift = 2; + uart.port.serial_out = ingenic_uart_serial_out; + uart.port.irq = irq->start; + uart.port.dev = &pdev->dev; + + /* Check for a fixed line number */ + line = of_alias_get_id(pdev->dev.of_node, "serial"); + if (line >= 0) + uart.port.line = line; + + uart.port.membase = devm_ioremap(&pdev->dev, regs->start, + resource_size(regs)); + if (!uart.port.membase) + return -ENOMEM; + + data->clk_module = devm_clk_get(&pdev->dev, "module"); + if (IS_ERR(data->clk_module)) { + err = PTR_ERR(data->clk_module); + if (err != -EPROBE_DEFER) + dev_err(&pdev->dev, + "unable to get module clock: %d\n", err); + return err; + } + + data->clk_baud = devm_clk_get(&pdev->dev, "baud"); + if (IS_ERR(data->clk_baud)) { + err = PTR_ERR(data->clk_baud); + if (err != -EPROBE_DEFER) + dev_err(&pdev->dev, + "unable to get baud clock: %d\n", err); + return err; + } + + err = clk_prepare_enable(data->clk_module); + if (err) { + dev_err(&pdev->dev, "could not enable module clock: %d\n", err); + goto out; + } + + err = clk_prepare_enable(data->clk_baud); + if (err) { + dev_err(&pdev->dev, "could not enable baud clock: %d\n", err); + goto out_disable_moduleclk; + } + uart.port.uartclk = clk_get_rate(data->clk_baud); + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) { + err = data->line; + goto out_disable_baudclk; + } + + platform_set_drvdata(pdev, data); + return 0; + +out_disable_baudclk: + clk_disable_unprepare(data->clk_baud); +out_disable_moduleclk: + clk_disable_unprepare(data->clk_module); +out: + return err; +} + +static int ingenic_uart_remove(struct platform_device *pdev) +{ + struct ingenic_uart_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + clk_disable_unprepare(data->clk_module); + clk_disable_unprepare(data->clk_baud); + return 0; +} + +static const struct of_device_id of_match[] = { + { .compatible = "ingenic,jz4740-uart" }, + { .compatible = "ingenic,jz4775-uart" }, + { .compatible = "ingenic,jz4780-uart" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match); + +static struct platform_driver ingenic_uart_platform_driver = { + .driver = { + .name = "ingenic-uart", + .owner = THIS_MODULE, + .of_match_table = of_match, + }, + .probe = ingenic_uart_probe, + .remove = ingenic_uart_remove, +}; + +module_platform_driver(ingenic_uart_platform_driver); + +MODULE_AUTHOR("Paul Burton"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Ingenic SoC UART driver"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 21eca79224e429..84a499af3cece2 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -313,3 +313,12 @@ config SERIAL_8250_MT6577 help If you have a Mediatek based board and want to use the serial port, say Y to this option. If unsure, say N. + +config SERIAL_8250_INGENIC + bool "Support for Ingenic SoC serial ports" + depends on SERIAL_8250_CONSOLE && OF_FLATTREE + select LIBFDT + select SERIAL_EARLYCON + help + If you have a system using an Ingenic SoC and wish to make use of + its UARTs, say Y to this option. If unsure, say N. diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 5256b894e46a91..c37cfebcfc6761 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -22,3 +22,6 @@ obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o +obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o + +CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 120729f0eb12bd..bf355050eab695 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -262,7 +262,6 @@ static struct of_device_id of_platform_serial_table[] = { { .compatible = "ibm,qpace-nwp-serial", .data = (void *)PORT_NWPSERIAL, }, #endif - { .compatible = "ingenic,jz4780-uart", .data = (void *)PORT_INGENIC_JZ4780, }, { .type = "serial", .data = (void *)PORT_UNKNOWN, }, { /* end of list */ }, }; diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index f831c9ffc9776a..16ad8521af6ad7 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -54,8 +54,7 @@ #define PORT_ALTR_16550_F32 26 /* Altera 16550 UART with 32 FIFOs */ #define PORT_ALTR_16550_F64 27 /* Altera 16550 UART with 64 FIFOs */ #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */ -#define PORT_INGENIC_JZ4780 29 -#define PORT_MAX_8250 29 /* max port ID */ +#define PORT_MAX_8250 28 /* max port ID */ /* * ARM specific type numbers. These are not currently guaranteed