| // SPDX-License-Identifier: GPL-2.0-only | |
| /* | |
| * linux/arch/arm/mach-omap1/serial.c | |
| * | |
| * OMAP1 serial support. | |
| */ | |
| #include <linux/gpio/machine.h> | |
| #include <linux/gpio/consumer.h> | |
| #include <linux/module.h> | |
| #include <linux/kernel.h> | |
| #include <linux/init.h> | |
| #include <linux/irq.h> | |
| #include <linux/delay.h> | |
| #include <linux/serial.h> | |
| #include <linux/tty.h> | |
| #include <linux/serial_8250.h> | |
| #include <linux/serial_reg.h> | |
| #include <linux/clk.h> | |
| #include <linux/io.h> | |
| #include <asm/mach-types.h> | |
| #include "common.h" | |
| #include "serial.h" | |
| #include "mux.h" | |
| #include "pm.h" | |
| #include "soc.h" | |
| static struct clk * uart1_ck; | |
| static struct clk * uart2_ck; | |
| static struct clk * uart3_ck; | |
| static inline unsigned int omap_serial_in(struct plat_serial8250_port *up, | |
| int offset) | |
| { | |
| offset <<= up->regshift; | |
| return (unsigned int)__raw_readb(up->membase + offset); | |
| } | |
| static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset, | |
| int value) | |
| { | |
| offset <<= p->regshift; | |
| __raw_writeb(value, p->membase + offset); | |
| } | |
| /* | |
| * Internal UARTs need to be initialized for the 8250 autoconfig to work | |
| * properly. Note that the TX watermark initialization may not be needed | |
| * once the 8250.c watermark handling code is merged. | |
| */ | |
| static void __init omap_serial_reset(struct plat_serial8250_port *p) | |
| { | |
| omap_serial_outp(p, UART_OMAP_MDR1, | |
| UART_OMAP_MDR1_DISABLE); /* disable UART */ | |
| omap_serial_outp(p, UART_OMAP_SCR, 0x08); /* TX watermark */ | |
| omap_serial_outp(p, UART_OMAP_MDR1, | |
| UART_OMAP_MDR1_16X_MODE); /* enable UART */ | |
| if (!cpu_is_omap15xx()) { | |
| omap_serial_outp(p, UART_OMAP_SYSC, 0x01); | |
| while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01)); | |
| } | |
| } | |
| static struct plat_serial8250_port serial_platform_data[] = { | |
| { | |
| .mapbase = OMAP1_UART1_BASE, | |
| .irq = INT_UART1, | |
| .flags = UPF_BOOT_AUTOCONF, | |
| .iotype = UPIO_MEM, | |
| .regshift = 2, | |
| .uartclk = OMAP16XX_BASE_BAUD * 16, | |
| }, | |
| { | |
| .mapbase = OMAP1_UART2_BASE, | |
| .irq = INT_UART2, | |
| .flags = UPF_BOOT_AUTOCONF, | |
| .iotype = UPIO_MEM, | |
| .regshift = 2, | |
| .uartclk = OMAP16XX_BASE_BAUD * 16, | |
| }, | |
| { | |
| .mapbase = OMAP1_UART3_BASE, | |
| .irq = INT_UART3, | |
| .flags = UPF_BOOT_AUTOCONF, | |
| .iotype = UPIO_MEM, | |
| .regshift = 2, | |
| .uartclk = OMAP16XX_BASE_BAUD * 16, | |
| }, | |
| { }, | |
| }; | |
| static struct platform_device serial_device = { | |
| .name = "serial8250", | |
| .id = PLAT8250_DEV_PLATFORM, | |
| .dev = { | |
| .platform_data = serial_platform_data, | |
| }, | |
| }; | |
| /* | |
| * Note that on Innovator-1510 UART2 pins conflict with USB2. | |
| * By default UART2 does not work on Innovator-1510 if you have | |
| * USB OHCI enabled. To use UART2, you must disable USB2 first. | |
| */ | |
| void __init omap_serial_init(void) | |
| { | |
| int i; | |
| if (cpu_is_omap15xx()) { | |
| serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16; | |
| serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16; | |
| serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16; | |
| } | |
| for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) { | |
| /* Static mapping, never released */ | |
| serial_platform_data[i].membase = | |
| ioremap(serial_platform_data[i].mapbase, SZ_2K); | |
| if (!serial_platform_data[i].membase) { | |
| printk(KERN_ERR "Could not ioremap uart%i\n", i); | |
| continue; | |
| } | |
| switch (i) { | |
| case 0: | |
| uart1_ck = clk_get(NULL, "uart1_ck"); | |
| if (IS_ERR(uart1_ck)) | |
| printk("Could not get uart1_ck\n"); | |
| else { | |
| clk_prepare_enable(uart1_ck); | |
| if (cpu_is_omap15xx()) | |
| clk_set_rate(uart1_ck, 12000000); | |
| } | |
| break; | |
| case 1: | |
| uart2_ck = clk_get(NULL, "uart2_ck"); | |
| if (IS_ERR(uart2_ck)) | |
| printk("Could not get uart2_ck\n"); | |
| else { | |
| clk_prepare_enable(uart2_ck); | |
| if (cpu_is_omap15xx()) | |
| clk_set_rate(uart2_ck, 12000000); | |
| else | |
| clk_set_rate(uart2_ck, 48000000); | |
| } | |
| break; | |
| case 2: | |
| uart3_ck = clk_get(NULL, "uart3_ck"); | |
| if (IS_ERR(uart3_ck)) | |
| printk("Could not get uart3_ck\n"); | |
| else { | |
| clk_prepare_enable(uart3_ck); | |
| if (cpu_is_omap15xx()) | |
| clk_set_rate(uart3_ck, 12000000); | |
| } | |
| break; | |
| } | |
| omap_serial_reset(&serial_platform_data[i]); | |
| } | |
| } | |
| #ifdef CONFIG_OMAP_SERIAL_WAKE | |
| static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id) | |
| { | |
| /* Need to do something with serial port right after wake-up? */ | |
| return IRQ_HANDLED; | |
| } | |
| /* | |
| * Reroutes serial RX lines to GPIO lines for the duration of | |
| * sleep to allow waking up the device from serial port even | |
| * in deep sleep. | |
| */ | |
| void omap_serial_wake_trigger(int enable) | |
| { | |
| if (!cpu_is_omap16xx()) | |
| return; | |
| if (uart1_ck != NULL) { | |
| if (enable) | |
| omap_cfg_reg(V14_16XX_GPIO37); | |
| else | |
| omap_cfg_reg(V14_16XX_UART1_RX); | |
| } | |
| if (uart2_ck != NULL) { | |
| if (enable) | |
| omap_cfg_reg(R9_16XX_GPIO18); | |
| else | |
| omap_cfg_reg(R9_16XX_UART2_RX); | |
| } | |
| if (uart3_ck != NULL) { | |
| if (enable) | |
| omap_cfg_reg(L14_16XX_GPIO49); | |
| else | |
| omap_cfg_reg(L14_16XX_UART3_RX); | |
| } | |
| } | |
| static void __init omap_serial_set_port_wakeup(int idx) | |
| { | |
| struct gpio_desc *d; | |
| int ret; | |
| d = gpiod_get_index(NULL, "wakeup", idx, GPIOD_IN); | |
| if (IS_ERR(d)) { | |
| pr_err("Unable to get UART wakeup GPIO descriptor\n"); | |
| return; | |
| } | |
| ret = request_irq(gpiod_to_irq(d), &omap_serial_wake_interrupt, | |
| IRQF_TRIGGER_RISING, "serial wakeup", NULL); | |
| if (ret) { | |
| gpiod_put(d); | |
| pr_err("No interrupt for UART%d wake GPIO\n", idx + 1); | |
| return; | |
| } | |
| enable_irq_wake(gpiod_to_irq(d)); | |
| } | |
| int __init omap_serial_wakeup_init(void) | |
| { | |
| if (!cpu_is_omap16xx()) | |
| return 0; | |
| if (uart1_ck != NULL) | |
| omap_serial_set_port_wakeup(0); | |
| if (uart2_ck != NULL) | |
| omap_serial_set_port_wakeup(1); | |
| if (uart3_ck != NULL) | |
| omap_serial_set_port_wakeup(2); | |
| return 0; | |
| } | |
| #endif /* CONFIG_OMAP_SERIAL_WAKE */ | |
| static int __init omap_init(void) | |
| { | |
| if (!cpu_class_is_omap1()) | |
| return -ENODEV; | |
| return platform_device_register(&serial_device); | |
| } | |
| arch_initcall(omap_init); |