18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Synopsys DesignWare 8250 driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2011 Picochip, Jamie Iles. 68c2ecf20Sopenharmony_ci * Copyright 2013 Intel Corporation 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the 98c2ecf20Sopenharmony_ci * LCR is written whilst busy. If it is, then a busy detect interrupt is 108c2ecf20Sopenharmony_ci * raised, the LCR needs to be rewritten and the uart status register read. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/serial_8250.h> 178c2ecf20Sopenharmony_ci#include <linux/serial_reg.h> 188c2ecf20Sopenharmony_ci#include <linux/of.h> 198c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 208c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 238c2ecf20Sopenharmony_ci#include <linux/notifier.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/acpi.h> 268c2ecf20Sopenharmony_ci#include <linux/clk.h> 278c2ecf20Sopenharmony_ci#include <linux/reset.h> 288c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "8250_dwlib.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Offsets for the DesignWare specific registers */ 358c2ecf20Sopenharmony_ci#define DW_UART_USR 0x1f /* UART Status Register */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* DesignWare specific register fields */ 388c2ecf20Sopenharmony_ci#define DW_UART_MCR_SIRE BIT(6) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct dw8250_data { 418c2ecf20Sopenharmony_ci struct dw8250_port_data data; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci u8 usr_reg; 448c2ecf20Sopenharmony_ci int msr_mask_on; 458c2ecf20Sopenharmony_ci int msr_mask_off; 468c2ecf20Sopenharmony_ci struct clk *clk; 478c2ecf20Sopenharmony_ci struct clk *pclk; 488c2ecf20Sopenharmony_ci struct notifier_block clk_notifier; 498c2ecf20Sopenharmony_ci struct work_struct clk_work; 508c2ecf20Sopenharmony_ci struct reset_control *rst; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci unsigned int skip_autocfg:1; 538c2ecf20Sopenharmony_ci unsigned int uart_16550_compatible:1; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return container_of(data, struct dw8250_data, data); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return container_of(nb, struct dw8250_data, clk_notifier); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic inline struct dw8250_data *work_to_dw8250_data(struct work_struct *work) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return container_of(work, struct dw8250_data, clk_work); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Override any modem control signals if needed */ 768c2ecf20Sopenharmony_ci if (offset == UART_MSR) { 778c2ecf20Sopenharmony_ci value |= d->msr_mask_on; 788c2ecf20Sopenharmony_ci value &= ~d->msr_mask_off; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return value; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void dw8250_force_idle(struct uart_port *p) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(p); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci serial8250_clear_and_reinit_fifos(up); 898c2ecf20Sopenharmony_ci (void)p->serial_in(p, UART_RX); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void dw8250_check_lcr(struct uart_port *p, int value) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci void __iomem *offset = p->membase + (UART_LCR << p->regshift); 958c2ecf20Sopenharmony_ci int tries = 1000; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Make sure LCR write wasn't ignored */ 988c2ecf20Sopenharmony_ci while (tries--) { 998c2ecf20Sopenharmony_ci unsigned int lcr = p->serial_in(p, UART_LCR); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci dw8250_force_idle(p); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 1078c2ecf20Sopenharmony_ci if (p->type == PORT_OCTEON) 1088c2ecf20Sopenharmony_ci __raw_writeq(value & 0xff, offset); 1098c2ecf20Sopenharmony_ci else 1108c2ecf20Sopenharmony_ci#endif 1118c2ecf20Sopenharmony_ci if (p->iotype == UPIO_MEM32) 1128c2ecf20Sopenharmony_ci writel(value, offset); 1138c2ecf20Sopenharmony_ci else if (p->iotype == UPIO_MEM32BE) 1148c2ecf20Sopenharmony_ci iowrite32be(value, offset); 1158c2ecf20Sopenharmony_ci else 1168c2ecf20Sopenharmony_ci writeb(value, offset); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * FIXME: this deadlocks if port->lock is already held 1208c2ecf20Sopenharmony_ci * dev_err(p->dev, "Couldn't set LCR to %d\n", value); 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Returns once the transmitter is empty or we run out of retries */ 1258c2ecf20Sopenharmony_cistatic void dw8250_tx_wait_empty(struct uart_port *p) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(p); 1288c2ecf20Sopenharmony_ci unsigned int tries = 20000; 1298c2ecf20Sopenharmony_ci unsigned int delay_threshold = tries - 1000; 1308c2ecf20Sopenharmony_ci unsigned int lsr; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci while (tries--) { 1338c2ecf20Sopenharmony_ci lsr = readb (p->membase + (UART_LSR << p->regshift)); 1348c2ecf20Sopenharmony_ci up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (lsr & UART_LSR_TEMT) 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* The device is first given a chance to empty without delay, 1408c2ecf20Sopenharmony_ci * to avoid slowdowns at high bitrates. If after 1000 tries 1418c2ecf20Sopenharmony_ci * the buffer has still not emptied, allow more time for low- 1428c2ecf20Sopenharmony_ci * speed links. */ 1438c2ecf20Sopenharmony_ci if (tries < delay_threshold) 1448c2ecf20Sopenharmony_ci udelay (1); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void dw8250_serial_out38x(struct uart_port *p, int offset, int value) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* Allow the TX to drain before we reconfigure */ 1538c2ecf20Sopenharmony_ci if (offset == UART_LCR) 1548c2ecf20Sopenharmony_ci dw8250_tx_wait_empty(p); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci writeb(value, p->membase + (offset << p->regshift)); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (offset == UART_LCR && !d->uart_16550_compatible) 1598c2ecf20Sopenharmony_ci dw8250_check_lcr(p, value); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void dw8250_serial_out(struct uart_port *p, int offset, int value) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci writeb(value, p->membase + (offset << p->regshift)); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (offset == UART_LCR && !d->uart_16550_compatible) 1708c2ecf20Sopenharmony_ci dw8250_check_lcr(p, value); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic unsigned int dw8250_serial_in(struct uart_port *p, int offset) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci unsigned int value = readb(p->membase + (offset << p->regshift)); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return dw8250_modify_msr(p, offset, value); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 1818c2ecf20Sopenharmony_cistatic unsigned int dw8250_serial_inq(struct uart_port *p, int offset) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci unsigned int value; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci value = (u8)__raw_readq(p->membase + (offset << p->regshift)); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return dw8250_modify_msr(p, offset, value); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void dw8250_serial_outq(struct uart_port *p, int offset, int value) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci value &= 0xff; 1958c2ecf20Sopenharmony_ci __raw_writeq(value, p->membase + (offset << p->regshift)); 1968c2ecf20Sopenharmony_ci /* Read back to ensure register write ordering. */ 1978c2ecf20Sopenharmony_ci __raw_readq(p->membase + (UART_LCR << p->regshift)); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (offset == UART_LCR && !d->uart_16550_compatible) 2008c2ecf20Sopenharmony_ci dw8250_check_lcr(p, value); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci#endif /* CONFIG_64BIT */ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void dw8250_serial_out32(struct uart_port *p, int offset, int value) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci writel(value, p->membase + (offset << p->regshift)); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (offset == UART_LCR && !d->uart_16550_compatible) 2118c2ecf20Sopenharmony_ci dw8250_check_lcr(p, value); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic unsigned int dw8250_serial_in32(struct uart_port *p, int offset) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci unsigned int value = readl(p->membase + (offset << p->regshift)); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return dw8250_modify_msr(p, offset, value); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void dw8250_serial_out32be(struct uart_port *p, int offset, int value) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci iowrite32be(value, p->membase + (offset << p->regshift)); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (offset == UART_LCR && !d->uart_16550_compatible) 2288c2ecf20Sopenharmony_ci dw8250_check_lcr(p, value); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic unsigned int dw8250_serial_in32be(struct uart_port *p, int offset) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci unsigned int value = ioread32be(p->membase + (offset << p->regshift)); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return dw8250_modify_msr(p, offset, value); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic int dw8250_handle_irq(struct uart_port *p) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(p); 2428c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 2438c2ecf20Sopenharmony_ci unsigned int iir = p->serial_in(p, UART_IIR); 2448c2ecf20Sopenharmony_ci unsigned int status; 2458c2ecf20Sopenharmony_ci unsigned long flags; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * There are ways to get Designware-based UARTs into a state where 2498c2ecf20Sopenharmony_ci * they are asserting UART_IIR_RX_TIMEOUT but there is no actual 2508c2ecf20Sopenharmony_ci * data available. If we see such a case then we'll do a bogus 2518c2ecf20Sopenharmony_ci * read. If we don't do this then the "RX TIMEOUT" interrupt will 2528c2ecf20Sopenharmony_ci * fire forever. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * This problem has only been observed so far when not in DMA mode 2558c2ecf20Sopenharmony_ci * so we limit the workaround only to non-DMA mode. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci if (!up->dma && ((iir & 0x3f) == UART_IIR_RX_TIMEOUT)) { 2588c2ecf20Sopenharmony_ci spin_lock_irqsave(&p->lock, flags); 2598c2ecf20Sopenharmony_ci status = p->serial_in(p, UART_LSR); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (!(status & (UART_LSR_DR | UART_LSR_BI))) 2628c2ecf20Sopenharmony_ci (void) p->serial_in(p, UART_RX); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&p->lock, flags); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (serial8250_handle_irq(p, iir)) 2688c2ecf20Sopenharmony_ci return 1; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { 2718c2ecf20Sopenharmony_ci /* Clear the USR */ 2728c2ecf20Sopenharmony_ci (void)p->serial_in(p, d->usr_reg); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 1; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void dw8250_clk_work_cb(struct work_struct *work) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct dw8250_data *d = work_to_dw8250_data(work); 2838c2ecf20Sopenharmony_ci struct uart_8250_port *up; 2848c2ecf20Sopenharmony_ci unsigned long rate; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci rate = clk_get_rate(d->clk); 2878c2ecf20Sopenharmony_ci if (rate <= 0) 2888c2ecf20Sopenharmony_ci return; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci up = serial8250_get_port(d->data.line); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci serial8250_update_uartclk(&up->port, rate); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int dw8250_clk_notifier_cb(struct notifier_block *nb, 2968c2ecf20Sopenharmony_ci unsigned long event, void *data) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct dw8250_data *d = clk_to_dw8250_data(nb); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* 3018c2ecf20Sopenharmony_ci * We have no choice but to defer the uartclk update due to two 3028c2ecf20Sopenharmony_ci * deadlocks. First one is caused by a recursive mutex lock which 3038c2ecf20Sopenharmony_ci * happens when clk_set_rate() is called from dw8250_set_termios(). 3048c2ecf20Sopenharmony_ci * Second deadlock is more tricky and is caused by an inverted order of 3058c2ecf20Sopenharmony_ci * the clk and tty-port mutexes lock. It happens if clock rate change 3068c2ecf20Sopenharmony_ci * is requested asynchronously while set_termios() is executed between 3078c2ecf20Sopenharmony_ci * tty-port mutex lock and clk_set_rate() function invocation and 3088c2ecf20Sopenharmony_ci * vise-versa. Anyway if we didn't have the reference clock alteration 3098c2ecf20Sopenharmony_ci * in the dw8250_set_termios() method we wouldn't have needed this 3108c2ecf20Sopenharmony_ci * deferred event handling complication. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci if (event == POST_RATE_CHANGE) { 3138c2ecf20Sopenharmony_ci queue_work(system_unbound_wq, &d->clk_work); 3148c2ecf20Sopenharmony_ci return NOTIFY_OK; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return NOTIFY_DONE; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void 3218c2ecf20Sopenharmony_cidw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci if (!state) 3248c2ecf20Sopenharmony_ci pm_runtime_get_sync(port->dev); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci serial8250_do_pm(port, state, old); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (state) 3298c2ecf20Sopenharmony_ci pm_runtime_put_sync_suspend(port->dev); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, 3338c2ecf20Sopenharmony_ci struct ktermios *old) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci unsigned long newrate = tty_termios_baud_rate(termios) * 16; 3368c2ecf20Sopenharmony_ci struct dw8250_data *d = to_dw8250_data(p->private_data); 3378c2ecf20Sopenharmony_ci long rate; 3388c2ecf20Sopenharmony_ci int ret; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci clk_disable_unprepare(d->clk); 3418c2ecf20Sopenharmony_ci rate = clk_round_rate(d->clk, newrate); 3428c2ecf20Sopenharmony_ci if (rate > 0) { 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Premilinary set the uartclk to the new clock rate so the 3458c2ecf20Sopenharmony_ci * clock update event handler caused by the clk_set_rate() 3468c2ecf20Sopenharmony_ci * calling wouldn't actually update the UART divisor since 3478c2ecf20Sopenharmony_ci * we about to do this anyway. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci swap(p->uartclk, rate); 3508c2ecf20Sopenharmony_ci ret = clk_set_rate(d->clk, newrate); 3518c2ecf20Sopenharmony_ci if (ret) 3528c2ecf20Sopenharmony_ci swap(p->uartclk, rate); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci clk_prepare_enable(d->clk); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci p->status &= ~UPSTAT_AUTOCTS; 3578c2ecf20Sopenharmony_ci if (termios->c_cflag & CRTSCTS) 3588c2ecf20Sopenharmony_ci p->status |= UPSTAT_AUTOCTS; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci serial8250_do_set_termios(p, termios, old); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct uart_8250_port *up = up_to_u8250p(p); 3668c2ecf20Sopenharmony_ci unsigned int mcr = p->serial_in(p, UART_MCR); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (up->capabilities & UART_CAP_IRDA) { 3698c2ecf20Sopenharmony_ci if (termios->c_line == N_IRDA) 3708c2ecf20Sopenharmony_ci mcr |= DW_UART_MCR_SIRE; 3718c2ecf20Sopenharmony_ci else 3728c2ecf20Sopenharmony_ci mcr &= ~DW_UART_MCR_SIRE; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci p->serial_out(p, UART_MCR, mcr); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci serial8250_do_set_ldisc(p, termios); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* 3808c2ecf20Sopenharmony_ci * dw8250_fallback_dma_filter will prevent the UART from getting just any free 3818c2ecf20Sopenharmony_ci * channel on platforms that have DMA engines, but don't have any channels 3828c2ecf20Sopenharmony_ci * assigned to the UART. 3838c2ecf20Sopenharmony_ci * 3848c2ecf20Sopenharmony_ci * REVISIT: This is a work around for limitation in the DMA Engine API. Once the 3858c2ecf20Sopenharmony_ci * core problem is fixed, this function is no longer needed. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_cistatic bool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci return false; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic bool dw8250_idma_filter(struct dma_chan *chan, void *param) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci return param == chan->device->dev; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci if (p->dev->of_node) { 4008c2ecf20Sopenharmony_ci struct device_node *np = p->dev->of_node; 4018c2ecf20Sopenharmony_ci int id; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* get index of serial line, if found in DT aliases */ 4048c2ecf20Sopenharmony_ci id = of_alias_get_id(np, "serial"); 4058c2ecf20Sopenharmony_ci if (id >= 0) 4068c2ecf20Sopenharmony_ci p->line = id; 4078c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 4088c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { 4098c2ecf20Sopenharmony_ci p->serial_in = dw8250_serial_inq; 4108c2ecf20Sopenharmony_ci p->serial_out = dw8250_serial_outq; 4118c2ecf20Sopenharmony_ci p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; 4128c2ecf20Sopenharmony_ci p->type = PORT_OCTEON; 4138c2ecf20Sopenharmony_ci data->usr_reg = 0x27; 4148c2ecf20Sopenharmony_ci data->skip_autocfg = true; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci#endif 4178c2ecf20Sopenharmony_ci if (of_device_is_big_endian(p->dev->of_node)) { 4188c2ecf20Sopenharmony_ci p->iotype = UPIO_MEM32BE; 4198c2ecf20Sopenharmony_ci p->serial_in = dw8250_serial_in32be; 4208c2ecf20Sopenharmony_ci p->serial_out = dw8250_serial_out32be; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "marvell,armada-38x-uart")) 4238c2ecf20Sopenharmony_ci p->serial_out = dw8250_serial_out38x; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci } else if (acpi_dev_present("APMC0D08", NULL, -1)) { 4268c2ecf20Sopenharmony_ci p->iotype = UPIO_MEM32; 4278c2ecf20Sopenharmony_ci p->regshift = 2; 4288c2ecf20Sopenharmony_ci p->serial_in = dw8250_serial_in32; 4298c2ecf20Sopenharmony_ci data->uart_16550_compatible = true; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* Platforms with iDMA 64-bit */ 4338c2ecf20Sopenharmony_ci if (platform_get_resource_byname(to_platform_device(p->dev), 4348c2ecf20Sopenharmony_ci IORESOURCE_MEM, "lpss_priv")) { 4358c2ecf20Sopenharmony_ci data->data.dma.rx_param = p->dev->parent; 4368c2ecf20Sopenharmony_ci data->data.dma.tx_param = p->dev->parent; 4378c2ecf20Sopenharmony_ci data->data.dma.fn = dw8250_idma_filter; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int dw8250_probe(struct platform_device *pdev) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct uart_8250_port uart = {}, *up = &uart; 4448c2ecf20Sopenharmony_ci struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4458c2ecf20Sopenharmony_ci struct uart_port *p = &up->port; 4468c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4478c2ecf20Sopenharmony_ci struct dw8250_data *data; 4488c2ecf20Sopenharmony_ci int irq; 4498c2ecf20Sopenharmony_ci int err; 4508c2ecf20Sopenharmony_ci u32 val; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (!regs) { 4538c2ecf20Sopenharmony_ci dev_err(dev, "no registers defined\n"); 4548c2ecf20Sopenharmony_ci return -EINVAL; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 4588c2ecf20Sopenharmony_ci if (irq < 0) 4598c2ecf20Sopenharmony_ci return irq; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci spin_lock_init(&p->lock); 4628c2ecf20Sopenharmony_ci p->mapbase = regs->start; 4638c2ecf20Sopenharmony_ci p->irq = irq; 4648c2ecf20Sopenharmony_ci p->handle_irq = dw8250_handle_irq; 4658c2ecf20Sopenharmony_ci p->pm = dw8250_do_pm; 4668c2ecf20Sopenharmony_ci p->type = PORT_8250; 4678c2ecf20Sopenharmony_ci p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; 4688c2ecf20Sopenharmony_ci p->dev = dev; 4698c2ecf20Sopenharmony_ci p->iotype = UPIO_MEM; 4708c2ecf20Sopenharmony_ci p->serial_in = dw8250_serial_in; 4718c2ecf20Sopenharmony_ci p->serial_out = dw8250_serial_out; 4728c2ecf20Sopenharmony_ci p->set_ldisc = dw8250_set_ldisc; 4738c2ecf20Sopenharmony_ci p->set_termios = dw8250_set_termios; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci p->membase = devm_ioremap(dev, regs->start, resource_size(regs)); 4768c2ecf20Sopenharmony_ci if (!p->membase) 4778c2ecf20Sopenharmony_ci return -ENOMEM; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 4808c2ecf20Sopenharmony_ci if (!data) 4818c2ecf20Sopenharmony_ci return -ENOMEM; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci data->data.dma.fn = dw8250_fallback_dma_filter; 4848c2ecf20Sopenharmony_ci data->usr_reg = DW_UART_USR; 4858c2ecf20Sopenharmony_ci p->private_data = &data->data; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci data->uart_16550_compatible = device_property_read_bool(dev, 4888c2ecf20Sopenharmony_ci "snps,uart-16550-compatible"); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci err = device_property_read_u32(dev, "reg-shift", &val); 4918c2ecf20Sopenharmony_ci if (!err) 4928c2ecf20Sopenharmony_ci p->regshift = val; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci err = device_property_read_u32(dev, "reg-io-width", &val); 4958c2ecf20Sopenharmony_ci if (!err && val == 4) { 4968c2ecf20Sopenharmony_ci p->iotype = UPIO_MEM32; 4978c2ecf20Sopenharmony_ci p->serial_in = dw8250_serial_in32; 4988c2ecf20Sopenharmony_ci p->serial_out = dw8250_serial_out32; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (device_property_read_bool(dev, "dcd-override")) { 5028c2ecf20Sopenharmony_ci /* Always report DCD as active */ 5038c2ecf20Sopenharmony_ci data->msr_mask_on |= UART_MSR_DCD; 5048c2ecf20Sopenharmony_ci data->msr_mask_off |= UART_MSR_DDCD; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (device_property_read_bool(dev, "dsr-override")) { 5088c2ecf20Sopenharmony_ci /* Always report DSR as active */ 5098c2ecf20Sopenharmony_ci data->msr_mask_on |= UART_MSR_DSR; 5108c2ecf20Sopenharmony_ci data->msr_mask_off |= UART_MSR_DDSR; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (device_property_read_bool(dev, "cts-override")) { 5148c2ecf20Sopenharmony_ci /* Always report CTS as active */ 5158c2ecf20Sopenharmony_ci data->msr_mask_on |= UART_MSR_CTS; 5168c2ecf20Sopenharmony_ci data->msr_mask_off |= UART_MSR_DCTS; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (device_property_read_bool(dev, "ri-override")) { 5208c2ecf20Sopenharmony_ci /* Always report Ring indicator as inactive */ 5218c2ecf20Sopenharmony_ci data->msr_mask_off |= UART_MSR_RI; 5228c2ecf20Sopenharmony_ci data->msr_mask_off |= UART_MSR_TERI; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Always ask for fixed clock rate from a property. */ 5268c2ecf20Sopenharmony_ci device_property_read_u32(dev, "clock-frequency", &p->uartclk); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* If there is separate baudclk, get the rate from it. */ 5298c2ecf20Sopenharmony_ci data->clk = devm_clk_get_optional(dev, "baudclk"); 5308c2ecf20Sopenharmony_ci if (data->clk == NULL) 5318c2ecf20Sopenharmony_ci data->clk = devm_clk_get_optional(dev, NULL); 5328c2ecf20Sopenharmony_ci if (IS_ERR(data->clk)) 5338c2ecf20Sopenharmony_ci return PTR_ERR(data->clk); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci INIT_WORK(&data->clk_work, dw8250_clk_work_cb); 5368c2ecf20Sopenharmony_ci data->clk_notifier.notifier_call = dw8250_clk_notifier_cb; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci err = clk_prepare_enable(data->clk); 5398c2ecf20Sopenharmony_ci if (err) 5408c2ecf20Sopenharmony_ci dev_warn(dev, "could not enable optional baudclk: %d\n", err); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (data->clk) 5438c2ecf20Sopenharmony_ci p->uartclk = clk_get_rate(data->clk); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* If no clock rate is defined, fail. */ 5468c2ecf20Sopenharmony_ci if (!p->uartclk) { 5478c2ecf20Sopenharmony_ci dev_err(dev, "clock rate not defined\n"); 5488c2ecf20Sopenharmony_ci err = -EINVAL; 5498c2ecf20Sopenharmony_ci goto err_clk; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci data->pclk = devm_clk_get_optional(dev, "apb_pclk"); 5538c2ecf20Sopenharmony_ci if (IS_ERR(data->pclk)) { 5548c2ecf20Sopenharmony_ci err = PTR_ERR(data->pclk); 5558c2ecf20Sopenharmony_ci goto err_clk; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci err = clk_prepare_enable(data->pclk); 5598c2ecf20Sopenharmony_ci if (err) { 5608c2ecf20Sopenharmony_ci dev_err(dev, "could not enable apb_pclk\n"); 5618c2ecf20Sopenharmony_ci goto err_clk; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); 5658c2ecf20Sopenharmony_ci if (IS_ERR(data->rst)) { 5668c2ecf20Sopenharmony_ci err = PTR_ERR(data->rst); 5678c2ecf20Sopenharmony_ci goto err_pclk; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci reset_control_deassert(data->rst); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci dw8250_quirks(p, data); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* If the Busy Functionality is not implemented, don't handle it */ 5748c2ecf20Sopenharmony_ci if (data->uart_16550_compatible) 5758c2ecf20Sopenharmony_ci p->handle_irq = NULL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (!data->skip_autocfg) 5788c2ecf20Sopenharmony_ci dw8250_setup_port(p); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* If we have a valid fifosize, try hooking up DMA */ 5818c2ecf20Sopenharmony_ci if (p->fifosize) { 5828c2ecf20Sopenharmony_ci data->data.dma.rxconf.src_maxburst = p->fifosize / 4; 5838c2ecf20Sopenharmony_ci data->data.dma.txconf.dst_maxburst = p->fifosize / 4; 5848c2ecf20Sopenharmony_ci up->dma = &data->data.dma; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci data->data.line = serial8250_register_8250_port(up); 5888c2ecf20Sopenharmony_ci if (data->data.line < 0) { 5898c2ecf20Sopenharmony_ci err = data->data.line; 5908c2ecf20Sopenharmony_ci goto err_reset; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* 5948c2ecf20Sopenharmony_ci * Some platforms may provide a reference clock shared between several 5958c2ecf20Sopenharmony_ci * devices. In this case any clock state change must be known to the 5968c2ecf20Sopenharmony_ci * UART port at least post factum. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_ci if (data->clk) { 5998c2ecf20Sopenharmony_ci err = clk_notifier_register(data->clk, &data->clk_notifier); 6008c2ecf20Sopenharmony_ci if (err) 6018c2ecf20Sopenharmony_ci dev_warn(p->dev, "Failed to set the clock notifier\n"); 6028c2ecf20Sopenharmony_ci else 6038c2ecf20Sopenharmony_ci queue_work(system_unbound_wq, &data->clk_work); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, data); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 6098c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cierr_reset: 6148c2ecf20Sopenharmony_ci reset_control_assert(data->rst); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cierr_pclk: 6178c2ecf20Sopenharmony_ci clk_disable_unprepare(data->pclk); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cierr_clk: 6208c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return err; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int dw8250_remove(struct platform_device *pdev) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct dw8250_data *data = platform_get_drvdata(pdev); 6288c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci pm_runtime_get_sync(dev); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (data->clk) { 6338c2ecf20Sopenharmony_ci clk_notifier_unregister(data->clk, &data->clk_notifier); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci flush_work(&data->clk_work); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci serial8250_unregister_port(data->data.line); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci reset_control_assert(data->rst); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci clk_disable_unprepare(data->pclk); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 6478c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 6538c2ecf20Sopenharmony_cistatic int dw8250_suspend(struct device *dev) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct dw8250_data *data = dev_get_drvdata(dev); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci serial8250_suspend_port(data->data.line); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int dw8250_resume(struct device *dev) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct dw8250_data *data = dev_get_drvdata(dev); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci serial8250_resume_port(data->data.line); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci return 0; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6738c2ecf20Sopenharmony_cistatic int dw8250_runtime_suspend(struct device *dev) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct dw8250_data *data = dev_get_drvdata(dev); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci clk_disable_unprepare(data->clk); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci clk_disable_unprepare(data->pclk); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic int dw8250_runtime_resume(struct device *dev) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct dw8250_data *data = dev_get_drvdata(dev); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci clk_prepare_enable(data->pclk); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci clk_prepare_enable(data->clk); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci#endif 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dw8250_pm_ops = { 6978c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume) 6988c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL) 6998c2ecf20Sopenharmony_ci}; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic const struct of_device_id dw8250_of_match[] = { 7028c2ecf20Sopenharmony_ci { .compatible = "snps,dw-apb-uart" }, 7038c2ecf20Sopenharmony_ci { .compatible = "cavium,octeon-3860-uart" }, 7048c2ecf20Sopenharmony_ci { .compatible = "marvell,armada-38x-uart" }, 7058c2ecf20Sopenharmony_ci { .compatible = "renesas,rzn1-uart" }, 7068c2ecf20Sopenharmony_ci { /* Sentinel */ } 7078c2ecf20Sopenharmony_ci}; 7088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, dw8250_of_match); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic const struct acpi_device_id dw8250_acpi_match[] = { 7118c2ecf20Sopenharmony_ci { "INT33C4", 0 }, 7128c2ecf20Sopenharmony_ci { "INT33C5", 0 }, 7138c2ecf20Sopenharmony_ci { "INT3434", 0 }, 7148c2ecf20Sopenharmony_ci { "INT3435", 0 }, 7158c2ecf20Sopenharmony_ci { "80860F0A", 0 }, 7168c2ecf20Sopenharmony_ci { "8086228A", 0 }, 7178c2ecf20Sopenharmony_ci { "APMC0D08", 0}, 7188c2ecf20Sopenharmony_ci { "AMD0020", 0 }, 7198c2ecf20Sopenharmony_ci { "AMDI0020", 0 }, 7208c2ecf20Sopenharmony_ci { "AMDI0022", 0 }, 7218c2ecf20Sopenharmony_ci { "BRCM2032", 0 }, 7228c2ecf20Sopenharmony_ci { "HISI0031", 0 }, 7238c2ecf20Sopenharmony_ci { }, 7248c2ecf20Sopenharmony_ci}; 7258c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic struct platform_driver dw8250_platform_driver = { 7288c2ecf20Sopenharmony_ci .driver = { 7298c2ecf20Sopenharmony_ci .name = "dw-apb-uart", 7308c2ecf20Sopenharmony_ci .pm = &dw8250_pm_ops, 7318c2ecf20Sopenharmony_ci .of_match_table = dw8250_of_match, 7328c2ecf20Sopenharmony_ci .acpi_match_table = dw8250_acpi_match, 7338c2ecf20Sopenharmony_ci }, 7348c2ecf20Sopenharmony_ci .probe = dw8250_probe, 7358c2ecf20Sopenharmony_ci .remove = dw8250_remove, 7368c2ecf20Sopenharmony_ci}; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cimodule_platform_driver(dw8250_platform_driver); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jamie Iles"); 7418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 7428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver"); 7438c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:dw-apb-uart"); 744