162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/arch/arm/mach-omap1/serial.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * OMAP1 serial support.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/gpio/machine.h>
862306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/irq.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/serial.h>
1562306a36Sopenharmony_ci#include <linux/tty.h>
1662306a36Sopenharmony_ci#include <linux/serial_8250.h>
1762306a36Sopenharmony_ci#include <linux/serial_reg.h>
1862306a36Sopenharmony_ci#include <linux/clk.h>
1962306a36Sopenharmony_ci#include <linux/io.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <asm/mach-types.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "common.h"
2462306a36Sopenharmony_ci#include "serial.h"
2562306a36Sopenharmony_ci#include "mux.h"
2662306a36Sopenharmony_ci#include "pm.h"
2762306a36Sopenharmony_ci#include "soc.h"
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic struct clk * uart1_ck;
3062306a36Sopenharmony_cistatic struct clk * uart2_ck;
3162306a36Sopenharmony_cistatic struct clk * uart3_ck;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
3462306a36Sopenharmony_ci					  int offset)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	offset <<= up->regshift;
3762306a36Sopenharmony_ci	return (unsigned int)__raw_readb(up->membase + offset);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
4162306a36Sopenharmony_ci				    int value)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	offset <<= p->regshift;
4462306a36Sopenharmony_ci	__raw_writeb(value, p->membase + offset);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci * Internal UARTs need to be initialized for the 8250 autoconfig to work
4962306a36Sopenharmony_ci * properly. Note that the TX watermark initialization may not be needed
5062306a36Sopenharmony_ci * once the 8250.c watermark handling code is merged.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic void __init omap_serial_reset(struct plat_serial8250_port *p)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	omap_serial_outp(p, UART_OMAP_MDR1,
5562306a36Sopenharmony_ci			UART_OMAP_MDR1_DISABLE);	/* disable UART */
5662306a36Sopenharmony_ci	omap_serial_outp(p, UART_OMAP_SCR, 0x08);	/* TX watermark */
5762306a36Sopenharmony_ci	omap_serial_outp(p, UART_OMAP_MDR1,
5862306a36Sopenharmony_ci			UART_OMAP_MDR1_16X_MODE);	/* enable UART */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (!cpu_is_omap15xx()) {
6162306a36Sopenharmony_ci		omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
6262306a36Sopenharmony_ci		while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic struct plat_serial8250_port serial_platform_data[] = {
6762306a36Sopenharmony_ci	{
6862306a36Sopenharmony_ci		.mapbase	= OMAP1_UART1_BASE,
6962306a36Sopenharmony_ci		.irq		= INT_UART1,
7062306a36Sopenharmony_ci		.flags		= UPF_BOOT_AUTOCONF,
7162306a36Sopenharmony_ci		.iotype		= UPIO_MEM,
7262306a36Sopenharmony_ci		.regshift	= 2,
7362306a36Sopenharmony_ci		.uartclk	= OMAP16XX_BASE_BAUD * 16,
7462306a36Sopenharmony_ci	},
7562306a36Sopenharmony_ci	{
7662306a36Sopenharmony_ci		.mapbase	= OMAP1_UART2_BASE,
7762306a36Sopenharmony_ci		.irq		= INT_UART2,
7862306a36Sopenharmony_ci		.flags		= UPF_BOOT_AUTOCONF,
7962306a36Sopenharmony_ci		.iotype		= UPIO_MEM,
8062306a36Sopenharmony_ci		.regshift	= 2,
8162306a36Sopenharmony_ci		.uartclk	= OMAP16XX_BASE_BAUD * 16,
8262306a36Sopenharmony_ci	},
8362306a36Sopenharmony_ci	{
8462306a36Sopenharmony_ci		.mapbase	= OMAP1_UART3_BASE,
8562306a36Sopenharmony_ci		.irq		= INT_UART3,
8662306a36Sopenharmony_ci		.flags		= UPF_BOOT_AUTOCONF,
8762306a36Sopenharmony_ci		.iotype		= UPIO_MEM,
8862306a36Sopenharmony_ci		.regshift	= 2,
8962306a36Sopenharmony_ci		.uartclk	= OMAP16XX_BASE_BAUD * 16,
9062306a36Sopenharmony_ci	},
9162306a36Sopenharmony_ci	{ },
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic struct platform_device serial_device = {
9562306a36Sopenharmony_ci	.name			= "serial8250",
9662306a36Sopenharmony_ci	.id			= PLAT8250_DEV_PLATFORM,
9762306a36Sopenharmony_ci	.dev			= {
9862306a36Sopenharmony_ci		.platform_data	= serial_platform_data,
9962306a36Sopenharmony_ci	},
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci/*
10362306a36Sopenharmony_ci * Note that on Innovator-1510 UART2 pins conflict with USB2.
10462306a36Sopenharmony_ci * By default UART2 does not work on Innovator-1510 if you have
10562306a36Sopenharmony_ci * USB OHCI enabled. To use UART2, you must disable USB2 first.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_civoid __init omap_serial_init(void)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	int i;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (cpu_is_omap15xx()) {
11262306a36Sopenharmony_ci		serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
11362306a36Sopenharmony_ci		serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
11462306a36Sopenharmony_ci		serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) {
11862306a36Sopenharmony_ci		/* Static mapping, never released */
11962306a36Sopenharmony_ci		serial_platform_data[i].membase =
12062306a36Sopenharmony_ci			ioremap(serial_platform_data[i].mapbase, SZ_2K);
12162306a36Sopenharmony_ci		if (!serial_platform_data[i].membase) {
12262306a36Sopenharmony_ci			printk(KERN_ERR "Could not ioremap uart%i\n", i);
12362306a36Sopenharmony_ci			continue;
12462306a36Sopenharmony_ci		}
12562306a36Sopenharmony_ci		switch (i) {
12662306a36Sopenharmony_ci		case 0:
12762306a36Sopenharmony_ci			uart1_ck = clk_get(NULL, "uart1_ck");
12862306a36Sopenharmony_ci			if (IS_ERR(uart1_ck))
12962306a36Sopenharmony_ci				printk("Could not get uart1_ck\n");
13062306a36Sopenharmony_ci			else {
13162306a36Sopenharmony_ci				clk_prepare_enable(uart1_ck);
13262306a36Sopenharmony_ci				if (cpu_is_omap15xx())
13362306a36Sopenharmony_ci					clk_set_rate(uart1_ck, 12000000);
13462306a36Sopenharmony_ci			}
13562306a36Sopenharmony_ci			break;
13662306a36Sopenharmony_ci		case 1:
13762306a36Sopenharmony_ci			uart2_ck = clk_get(NULL, "uart2_ck");
13862306a36Sopenharmony_ci			if (IS_ERR(uart2_ck))
13962306a36Sopenharmony_ci				printk("Could not get uart2_ck\n");
14062306a36Sopenharmony_ci			else {
14162306a36Sopenharmony_ci				clk_prepare_enable(uart2_ck);
14262306a36Sopenharmony_ci				if (cpu_is_omap15xx())
14362306a36Sopenharmony_ci					clk_set_rate(uart2_ck, 12000000);
14462306a36Sopenharmony_ci				else
14562306a36Sopenharmony_ci					clk_set_rate(uart2_ck, 48000000);
14662306a36Sopenharmony_ci			}
14762306a36Sopenharmony_ci			break;
14862306a36Sopenharmony_ci		case 2:
14962306a36Sopenharmony_ci			uart3_ck = clk_get(NULL, "uart3_ck");
15062306a36Sopenharmony_ci			if (IS_ERR(uart3_ck))
15162306a36Sopenharmony_ci				printk("Could not get uart3_ck\n");
15262306a36Sopenharmony_ci			else {
15362306a36Sopenharmony_ci				clk_prepare_enable(uart3_ck);
15462306a36Sopenharmony_ci				if (cpu_is_omap15xx())
15562306a36Sopenharmony_ci					clk_set_rate(uart3_ck, 12000000);
15662306a36Sopenharmony_ci			}
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci		omap_serial_reset(&serial_platform_data[i]);
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#ifdef CONFIG_OMAP_SERIAL_WAKE
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	/* Need to do something with serial port right after wake-up? */
16862306a36Sopenharmony_ci	return IRQ_HANDLED;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/*
17262306a36Sopenharmony_ci * Reroutes serial RX lines to GPIO lines for the duration of
17362306a36Sopenharmony_ci * sleep to allow waking up the device from serial port even
17462306a36Sopenharmony_ci * in deep sleep.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_civoid omap_serial_wake_trigger(int enable)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	if (!cpu_is_omap16xx())
17962306a36Sopenharmony_ci		return;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (uart1_ck != NULL) {
18262306a36Sopenharmony_ci		if (enable)
18362306a36Sopenharmony_ci			omap_cfg_reg(V14_16XX_GPIO37);
18462306a36Sopenharmony_ci		else
18562306a36Sopenharmony_ci			omap_cfg_reg(V14_16XX_UART1_RX);
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci	if (uart2_ck != NULL) {
18862306a36Sopenharmony_ci		if (enable)
18962306a36Sopenharmony_ci			omap_cfg_reg(R9_16XX_GPIO18);
19062306a36Sopenharmony_ci		else
19162306a36Sopenharmony_ci			omap_cfg_reg(R9_16XX_UART2_RX);
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci	if (uart3_ck != NULL) {
19462306a36Sopenharmony_ci		if (enable)
19562306a36Sopenharmony_ci			omap_cfg_reg(L14_16XX_GPIO49);
19662306a36Sopenharmony_ci		else
19762306a36Sopenharmony_ci			omap_cfg_reg(L14_16XX_UART3_RX);
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void __init omap_serial_set_port_wakeup(int idx)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct gpio_desc *d;
20462306a36Sopenharmony_ci	int ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	d = gpiod_get_index(NULL, "wakeup", idx, GPIOD_IN);
20762306a36Sopenharmony_ci	if (IS_ERR(d)) {
20862306a36Sopenharmony_ci		pr_err("Unable to get UART wakeup GPIO descriptor\n");
20962306a36Sopenharmony_ci		return;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	ret = request_irq(gpiod_to_irq(d), &omap_serial_wake_interrupt,
21262306a36Sopenharmony_ci			  IRQF_TRIGGER_RISING, "serial wakeup", NULL);
21362306a36Sopenharmony_ci	if (ret) {
21462306a36Sopenharmony_ci		gpiod_put(d);
21562306a36Sopenharmony_ci		pr_err("No interrupt for UART%d wake GPIO\n", idx + 1);
21662306a36Sopenharmony_ci		return;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci	enable_irq_wake(gpiod_to_irq(d));
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciint __init omap_serial_wakeup_init(void)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	if (!cpu_is_omap16xx())
22562306a36Sopenharmony_ci		return 0;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (uart1_ck != NULL)
22862306a36Sopenharmony_ci		omap_serial_set_port_wakeup(0);
22962306a36Sopenharmony_ci	if (uart2_ck != NULL)
23062306a36Sopenharmony_ci		omap_serial_set_port_wakeup(1);
23162306a36Sopenharmony_ci	if (uart3_ck != NULL)
23262306a36Sopenharmony_ci		omap_serial_set_port_wakeup(2);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return 0;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci#endif	/* CONFIG_OMAP_SERIAL_WAKE */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int __init omap_init(void)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	if (!cpu_class_is_omap1())
24262306a36Sopenharmony_ci		return -ENODEV;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return platform_device_register(&serial_device);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ciarch_initcall(omap_init);
247