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