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