18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-omap1/serial.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * OMAP1 serial support.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/gpio.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/irq.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/serial.h>
148c2ecf20Sopenharmony_ci#include <linux/tty.h>
158c2ecf20Sopenharmony_ci#include <linux/serial_8250.h>
168c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>
178c2ecf20Sopenharmony_ci#include <linux/clk.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <mach/mux.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "pm.h"
258c2ecf20Sopenharmony_ci#include "soc.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic struct clk * uart1_ck;
288c2ecf20Sopenharmony_cistatic struct clk * uart2_ck;
298c2ecf20Sopenharmony_cistatic struct clk * uart3_ck;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
328c2ecf20Sopenharmony_ci					  int offset)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	offset <<= up->regshift;
358c2ecf20Sopenharmony_ci	return (unsigned int)__raw_readb(up->membase + offset);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
398c2ecf20Sopenharmony_ci				    int value)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	offset <<= p->regshift;
428c2ecf20Sopenharmony_ci	__raw_writeb(value, p->membase + offset);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * Internal UARTs need to be initialized for the 8250 autoconfig to work
478c2ecf20Sopenharmony_ci * properly. Note that the TX watermark initialization may not be needed
488c2ecf20Sopenharmony_ci * once the 8250.c watermark handling code is merged.
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_cistatic void __init omap_serial_reset(struct plat_serial8250_port *p)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	omap_serial_outp(p, UART_OMAP_MDR1,
538c2ecf20Sopenharmony_ci			UART_OMAP_MDR1_DISABLE);	/* disable UART */
548c2ecf20Sopenharmony_ci	omap_serial_outp(p, UART_OMAP_SCR, 0x08);	/* TX watermark */
558c2ecf20Sopenharmony_ci	omap_serial_outp(p, UART_OMAP_MDR1,
568c2ecf20Sopenharmony_ci			UART_OMAP_MDR1_16X_MODE);	/* enable UART */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (!cpu_is_omap15xx()) {
598c2ecf20Sopenharmony_ci		omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
608c2ecf20Sopenharmony_ci		while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic struct plat_serial8250_port serial_platform_data[] = {
658c2ecf20Sopenharmony_ci	{
668c2ecf20Sopenharmony_ci		.mapbase	= OMAP1_UART1_BASE,
678c2ecf20Sopenharmony_ci		.irq		= INT_UART1,
688c2ecf20Sopenharmony_ci		.flags		= UPF_BOOT_AUTOCONF,
698c2ecf20Sopenharmony_ci		.iotype		= UPIO_MEM,
708c2ecf20Sopenharmony_ci		.regshift	= 2,
718c2ecf20Sopenharmony_ci		.uartclk	= OMAP16XX_BASE_BAUD * 16,
728c2ecf20Sopenharmony_ci	},
738c2ecf20Sopenharmony_ci	{
748c2ecf20Sopenharmony_ci		.mapbase	= OMAP1_UART2_BASE,
758c2ecf20Sopenharmony_ci		.irq		= INT_UART2,
768c2ecf20Sopenharmony_ci		.flags		= UPF_BOOT_AUTOCONF,
778c2ecf20Sopenharmony_ci		.iotype		= UPIO_MEM,
788c2ecf20Sopenharmony_ci		.regshift	= 2,
798c2ecf20Sopenharmony_ci		.uartclk	= OMAP16XX_BASE_BAUD * 16,
808c2ecf20Sopenharmony_ci	},
818c2ecf20Sopenharmony_ci	{
828c2ecf20Sopenharmony_ci		.mapbase	= OMAP1_UART3_BASE,
838c2ecf20Sopenharmony_ci		.irq		= INT_UART3,
848c2ecf20Sopenharmony_ci		.flags		= UPF_BOOT_AUTOCONF,
858c2ecf20Sopenharmony_ci		.iotype		= UPIO_MEM,
868c2ecf20Sopenharmony_ci		.regshift	= 2,
878c2ecf20Sopenharmony_ci		.uartclk	= OMAP16XX_BASE_BAUD * 16,
888c2ecf20Sopenharmony_ci	},
898c2ecf20Sopenharmony_ci	{ },
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic struct platform_device serial_device = {
938c2ecf20Sopenharmony_ci	.name			= "serial8250",
948c2ecf20Sopenharmony_ci	.id			= PLAT8250_DEV_PLATFORM,
958c2ecf20Sopenharmony_ci	.dev			= {
968c2ecf20Sopenharmony_ci		.platform_data	= serial_platform_data,
978c2ecf20Sopenharmony_ci	},
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/*
1018c2ecf20Sopenharmony_ci * Note that on Innovator-1510 UART2 pins conflict with USB2.
1028c2ecf20Sopenharmony_ci * By default UART2 does not work on Innovator-1510 if you have
1038c2ecf20Sopenharmony_ci * USB OHCI enabled. To use UART2, you must disable USB2 first.
1048c2ecf20Sopenharmony_ci */
1058c2ecf20Sopenharmony_civoid __init omap_serial_init(void)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int i;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (cpu_is_omap7xx()) {
1108c2ecf20Sopenharmony_ci		serial_platform_data[0].regshift = 0;
1118c2ecf20Sopenharmony_ci		serial_platform_data[1].regshift = 0;
1128c2ecf20Sopenharmony_ci		serial_platform_data[0].irq = INT_7XX_UART_MODEM_1;
1138c2ecf20Sopenharmony_ci		serial_platform_data[1].irq = INT_7XX_UART_MODEM_IRDA_2;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (cpu_is_omap15xx()) {
1178c2ecf20Sopenharmony_ci		serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
1188c2ecf20Sopenharmony_ci		serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
1198c2ecf20Sopenharmony_ci		serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) {
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		/* Don't look at UARTs higher than 2 for omap7xx */
1258c2ecf20Sopenharmony_ci		if (cpu_is_omap7xx() && i > 1) {
1268c2ecf20Sopenharmony_ci			serial_platform_data[i].membase = NULL;
1278c2ecf20Sopenharmony_ci			serial_platform_data[i].mapbase = 0;
1288c2ecf20Sopenharmony_ci			continue;
1298c2ecf20Sopenharmony_ci		}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		/* Static mapping, never released */
1328c2ecf20Sopenharmony_ci		serial_platform_data[i].membase =
1338c2ecf20Sopenharmony_ci			ioremap(serial_platform_data[i].mapbase, SZ_2K);
1348c2ecf20Sopenharmony_ci		if (!serial_platform_data[i].membase) {
1358c2ecf20Sopenharmony_ci			printk(KERN_ERR "Could not ioremap uart%i\n", i);
1368c2ecf20Sopenharmony_ci			continue;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci		switch (i) {
1398c2ecf20Sopenharmony_ci		case 0:
1408c2ecf20Sopenharmony_ci			uart1_ck = clk_get(NULL, "uart1_ck");
1418c2ecf20Sopenharmony_ci			if (IS_ERR(uart1_ck))
1428c2ecf20Sopenharmony_ci				printk("Could not get uart1_ck\n");
1438c2ecf20Sopenharmony_ci			else {
1448c2ecf20Sopenharmony_ci				clk_enable(uart1_ck);
1458c2ecf20Sopenharmony_ci				if (cpu_is_omap15xx())
1468c2ecf20Sopenharmony_ci					clk_set_rate(uart1_ck, 12000000);
1478c2ecf20Sopenharmony_ci			}
1488c2ecf20Sopenharmony_ci			break;
1498c2ecf20Sopenharmony_ci		case 1:
1508c2ecf20Sopenharmony_ci			uart2_ck = clk_get(NULL, "uart2_ck");
1518c2ecf20Sopenharmony_ci			if (IS_ERR(uart2_ck))
1528c2ecf20Sopenharmony_ci				printk("Could not get uart2_ck\n");
1538c2ecf20Sopenharmony_ci			else {
1548c2ecf20Sopenharmony_ci				clk_enable(uart2_ck);
1558c2ecf20Sopenharmony_ci				if (cpu_is_omap15xx())
1568c2ecf20Sopenharmony_ci					clk_set_rate(uart2_ck, 12000000);
1578c2ecf20Sopenharmony_ci				else
1588c2ecf20Sopenharmony_ci					clk_set_rate(uart2_ck, 48000000);
1598c2ecf20Sopenharmony_ci			}
1608c2ecf20Sopenharmony_ci			break;
1618c2ecf20Sopenharmony_ci		case 2:
1628c2ecf20Sopenharmony_ci			uart3_ck = clk_get(NULL, "uart3_ck");
1638c2ecf20Sopenharmony_ci			if (IS_ERR(uart3_ck))
1648c2ecf20Sopenharmony_ci				printk("Could not get uart3_ck\n");
1658c2ecf20Sopenharmony_ci			else {
1668c2ecf20Sopenharmony_ci				clk_enable(uart3_ck);
1678c2ecf20Sopenharmony_ci				if (cpu_is_omap15xx())
1688c2ecf20Sopenharmony_ci					clk_set_rate(uart3_ck, 12000000);
1698c2ecf20Sopenharmony_ci			}
1708c2ecf20Sopenharmony_ci			break;
1718c2ecf20Sopenharmony_ci		}
1728c2ecf20Sopenharmony_ci		omap_serial_reset(&serial_platform_data[i]);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#ifdef CONFIG_OMAP_SERIAL_WAKE
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	/* Need to do something with serial port right after wake-up? */
1818c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci/*
1858c2ecf20Sopenharmony_ci * Reroutes serial RX lines to GPIO lines for the duration of
1868c2ecf20Sopenharmony_ci * sleep to allow waking up the device from serial port even
1878c2ecf20Sopenharmony_ci * in deep sleep.
1888c2ecf20Sopenharmony_ci */
1898c2ecf20Sopenharmony_civoid omap_serial_wake_trigger(int enable)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	if (!cpu_is_omap16xx())
1928c2ecf20Sopenharmony_ci		return;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (uart1_ck != NULL) {
1958c2ecf20Sopenharmony_ci		if (enable)
1968c2ecf20Sopenharmony_ci			omap_cfg_reg(V14_16XX_GPIO37);
1978c2ecf20Sopenharmony_ci		else
1988c2ecf20Sopenharmony_ci			omap_cfg_reg(V14_16XX_UART1_RX);
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci	if (uart2_ck != NULL) {
2018c2ecf20Sopenharmony_ci		if (enable)
2028c2ecf20Sopenharmony_ci			omap_cfg_reg(R9_16XX_GPIO18);
2038c2ecf20Sopenharmony_ci		else
2048c2ecf20Sopenharmony_ci			omap_cfg_reg(R9_16XX_UART2_RX);
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci	if (uart3_ck != NULL) {
2078c2ecf20Sopenharmony_ci		if (enable)
2088c2ecf20Sopenharmony_ci			omap_cfg_reg(L14_16XX_GPIO49);
2098c2ecf20Sopenharmony_ci		else
2108c2ecf20Sopenharmony_ci			omap_cfg_reg(L14_16XX_UART3_RX);
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic void __init omap_serial_set_port_wakeup(int gpio_nr)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	int ret;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	ret = gpio_request(gpio_nr, "UART wake");
2198c2ecf20Sopenharmony_ci	if (ret < 0) {
2208c2ecf20Sopenharmony_ci		printk(KERN_ERR "Could not request UART wake GPIO: %i\n",
2218c2ecf20Sopenharmony_ci		       gpio_nr);
2228c2ecf20Sopenharmony_ci		return;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci	gpio_direction_input(gpio_nr);
2258c2ecf20Sopenharmony_ci	ret = request_irq(gpio_to_irq(gpio_nr), &omap_serial_wake_interrupt,
2268c2ecf20Sopenharmony_ci			  IRQF_TRIGGER_RISING, "serial wakeup", NULL);
2278c2ecf20Sopenharmony_ci	if (ret) {
2288c2ecf20Sopenharmony_ci		gpio_free(gpio_nr);
2298c2ecf20Sopenharmony_ci		printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n",
2308c2ecf20Sopenharmony_ci		       gpio_nr);
2318c2ecf20Sopenharmony_ci		return;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	enable_irq_wake(gpio_to_irq(gpio_nr));
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ciint __init omap_serial_wakeup_init(void)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	if (!cpu_is_omap16xx())
2398c2ecf20Sopenharmony_ci		return 0;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (uart1_ck != NULL)
2428c2ecf20Sopenharmony_ci		omap_serial_set_port_wakeup(37);
2438c2ecf20Sopenharmony_ci	if (uart2_ck != NULL)
2448c2ecf20Sopenharmony_ci		omap_serial_set_port_wakeup(18);
2458c2ecf20Sopenharmony_ci	if (uart3_ck != NULL)
2468c2ecf20Sopenharmony_ci		omap_serial_set_port_wakeup(49);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return 0;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci#endif	/* CONFIG_OMAP_SERIAL_WAKE */
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int __init omap_init(void)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	if (!cpu_class_is_omap1())
2568c2ecf20Sopenharmony_ci		return -ENODEV;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return platform_device_register(&serial_device);
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ciarch_initcall(omap_init);
261