1d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos/* 2d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * Atheros AR933X SoC built-in UART driver 3d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * 4d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> 5d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * 6d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. 7d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * 8d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * This program is free software; you can redistribute it and/or modify it 9d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * under the terms of the GNU General Public License version 2 as published 10d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * by the Free Software Foundation. 11d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos */ 12d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 13d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/module.h> 14d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/ioport.h> 15d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/init.h> 16d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/console.h> 17d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/sysrq.h> 18d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/delay.h> 19d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/platform_device.h> 20dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos#include <linux/of.h> 21dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos#include <linux/of_platform.h> 22d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/tty.h> 23d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/tty_flip.h> 24d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/serial_core.h> 25d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/serial.h> 26d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/slab.h> 27d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/io.h> 28d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <linux/irq.h> 2915ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos#include <linux/clk.h> 30d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 312dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos#include <asm/div64.h> 322dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 33d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#include <asm/mach-ath79/ar933x_uart.h> 34d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 35d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#define DRIVER_NAME "ar933x-uart" 36d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 372dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos#define AR933X_UART_MAX_SCALE 0xff 382dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos#define AR933X_UART_MAX_STEP 0xffff 392dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 402dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos#define AR933X_UART_MIN_BAUD 300 412dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos#define AR933X_UART_MAX_BAUD 3000000 422dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 43d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos#define AR933X_DUMMY_STATUS_RD 0x01 44d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 45d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic struct uart_driver ar933x_uart_driver; 46d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 47d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstruct ar933x_uart_port { 48d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct uart_port port; 49d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int ier; /* shadow Interrupt Enable Register */ 502dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int min_baud; 512dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int max_baud; 5215ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos struct clk *clk; 53d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos}; 54d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 55124155351331a53feb00d10874f0c620405fd385Gabor Juhosstatic inline bool ar933x_uart_console_enabled(void) 56124155351331a53feb00d10874f0c620405fd385Gabor Juhos{ 57124155351331a53feb00d10874f0c620405fd385Gabor Juhos return config_enabled(CONFIG_SERIAL_AR933X_CONSOLE); 58124155351331a53feb00d10874f0c620405fd385Gabor Juhos} 59124155351331a53feb00d10874f0c620405fd385Gabor Juhos 60d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, 61d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int offset) 62d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 63d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return readl(up->port.membase + offset); 64d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 65d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 66d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline void ar933x_uart_write(struct ar933x_uart_port *up, 67d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int offset, unsigned int value) 68d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 69d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos writel(value, up->port.membase + offset); 70d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 71d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 72d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline void ar933x_uart_rmw(struct ar933x_uart_port *up, 73d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int offset, 74d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int mask, 75d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int val) 76d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 77d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int t; 78d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 79d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos t = ar933x_uart_read(up, offset); 80d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos t &= ~mask; 81d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos t |= val; 82d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, offset, t); 83d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 84d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 85d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline void ar933x_uart_rmw_set(struct ar933x_uart_port *up, 86d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int offset, 87d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int val) 88d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 89d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw(up, offset, 0, val); 90d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 91d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 92d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline void ar933x_uart_rmw_clear(struct ar933x_uart_port *up, 93d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int offset, 94d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int val) 95d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 96d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw(up, offset, val, 0); 97d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 98d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 99d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline void ar933x_uart_start_tx_interrupt(struct ar933x_uart_port *up) 100d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 101d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->ier |= AR933X_UART_INT_TX_EMPTY; 102d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); 103d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 104d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 105d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) 106d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 107d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->ier &= ~AR933X_UART_INT_TX_EMPTY; 108d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); 109d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 110d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 111d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) 112d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 113d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int rdata; 114d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 115d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos rdata = ch & AR933X_UART_DATA_TX_RX_MASK; 116d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos rdata |= AR933X_UART_DATA_TX_CSR; 117d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_DATA_REG, rdata); 118d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 119d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 120d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic unsigned int ar933x_uart_tx_empty(struct uart_port *port) 121d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 122d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 123d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned long flags; 124d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int rdata; 125d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 126d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_lock_irqsave(&up->port.lock, flags); 127d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); 128d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_unlock_irqrestore(&up->port.lock, flags); 129d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 130d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT; 131d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 132d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 133d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic unsigned int ar933x_uart_get_mctrl(struct uart_port *port) 134d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 135d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return TIOCM_CAR; 136d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 137d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 138d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) 139d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 140d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 141d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 142d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_start_tx(struct uart_port *port) 143d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 144d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 145d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 146d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_start_tx_interrupt(up); 147d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 148d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 149d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_stop_tx(struct uart_port *port) 150d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 151d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 152d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 153d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_stop_tx_interrupt(up); 154d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 155d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 156d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_stop_rx(struct uart_port *port) 157d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 158d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 159d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 160d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->ier &= ~AR933X_UART_INT_RX_VALID; 161d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); 162d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 163d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 164d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_break_ctl(struct uart_port *port, int break_state) 165d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 166d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 167d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned long flags; 168d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 169d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_lock_irqsave(&up->port.lock, flags); 170d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (break_state == -1) 171d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, 172d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_CS_TX_BREAK); 173d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos else 174d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, 175d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_CS_TX_BREAK); 176d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_unlock_irqrestore(&up->port.lock, flags); 177d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 178d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 1792dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos/* 1802dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17)) 1812dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos */ 1822dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhosstatic unsigned long ar933x_uart_get_baud(unsigned int clk, 1832dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int scale, 1842dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int step) 1852dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos{ 1862dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos u64 t; 1872dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos u32 div; 1882dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 1892dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos div = (2 << 16) * (scale + 1); 1902dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos t = clk; 1912dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos t *= step; 1922dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos t += (div / 2); 1932dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos do_div(t, div); 1942dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 1952dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos return t; 1962dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos} 1972dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 1982dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhosstatic void ar933x_uart_get_scale_step(unsigned int clk, 1992dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int baud, 2002dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int *scale, 2012dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int *step) 2022dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos{ 2032dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int tscale; 2042dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos long min_diff; 2052dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 2062dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos *scale = 0; 2072dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos *step = 0; 2082dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 2092dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos min_diff = baud; 2102dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) { 2112dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos u64 tstep; 2122dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos int diff; 2132dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 2142dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos tstep = baud * (tscale + 1); 2152dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos tstep *= (2 << 16); 2162dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos do_div(tstep, clk); 2172dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 2182dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos if (tstep > AR933X_UART_MAX_STEP) 2192dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos break; 2202dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 2212dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud); 2222dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos if (diff < min_diff) { 2232dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos min_diff = diff; 2242dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos *scale = tscale; 2252dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos *step = tstep; 2262dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos } 2272dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos } 2282dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos} 2292dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 230d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_set_termios(struct uart_port *port, 231d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ktermios *new, 232d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ktermios *old) 233d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 234d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 235d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int cs; 236d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned long flags; 2372dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int baud, scale, step; 238d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 239d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Only CS8 is supported */ 240d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos new->c_cflag &= ~CSIZE; 241d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos new->c_cflag |= CS8; 242d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 243d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Only one stop bit is supported */ 244d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos new->c_cflag &= ~CSTOPB; 245d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 246d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos cs = 0; 247d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (new->c_cflag & PARENB) { 248d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (!(new->c_cflag & PARODD)) 249d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos cs |= AR933X_UART_CS_PARITY_EVEN; 250d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos else 251d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos cs |= AR933X_UART_CS_PARITY_ODD; 252d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } else { 253d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos cs |= AR933X_UART_CS_PARITY_NONE; 254d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } 255d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 256d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Mark/space parity is not supported */ 257d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos new->c_cflag &= ~CMSPAR; 258d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 2592dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud); 2602dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step); 261d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 262d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* 263d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * Ok, we're now changing the port state. Do it with 264d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * interrupts disabled. 265d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos */ 266d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_lock_irqsave(&up->port.lock, flags); 267d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 2682dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos /* disable the UART */ 2692dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, 2702dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S); 2712dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 272d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Update the per-port timeout. */ 273d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos uart_update_timeout(port, new->c_cflag, baud); 274d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 275d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->port.ignore_status_mask = 0; 276d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 277d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* ignore all characters if CREAD is not set */ 278d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if ((new->c_cflag & CREAD) == 0) 279d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD; 280d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 281d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_CLOCK_REG, 2822dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos scale << AR933X_UART_CLOCK_SCALE_S | step); 283d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 284d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* setup configuration register */ 285d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs); 286d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 287d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* enable host interrupt */ 288d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, 289d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_CS_HOST_INT_EN); 290d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 2912dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos /* reenable the UART */ 2922dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos ar933x_uart_rmw(up, AR933X_UART_CS_REG, 2932dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S, 2942dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S); 2952dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 296d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_unlock_irqrestore(&up->port.lock, flags); 297d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 298d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (tty_termios_baud_rate(new)) 299d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos tty_termios_encode_baud_rate(new, baud, baud); 300d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 301d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 302d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_rx_chars(struct ar933x_uart_port *up) 303d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 30492a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby struct tty_port *port = &up->port.state->port; 305d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int max_count = 256; 306d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 307d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos do { 308d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int rdata; 309d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned char ch; 310d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 311d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); 312d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) 313d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos break; 314d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 315d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* remove the character from the FIFO */ 316d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_DATA_REG, 317d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_DATA_RX_CSR); 318d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 319d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->port.icount.rx++; 320d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ch = rdata & AR933X_UART_DATA_TX_RX_MASK; 321d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 322d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (uart_handle_sysrq_char(&up->port, ch)) 323d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos continue; 324d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 325d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0) 32692a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby tty_insert_flip_char(port, ch, TTY_NORMAL); 327d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } while (max_count-- > 0); 328d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 329b16c8e3eed122ec0ddac30de6cc8a904463478b6Viresh Kumar spin_unlock(&up->port.lock); 3302e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby tty_flip_buffer_push(port); 331b16c8e3eed122ec0ddac30de6cc8a904463478b6Viresh Kumar spin_lock(&up->port.lock); 332d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 333d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 334d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_tx_chars(struct ar933x_uart_port *up) 335d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 336d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct circ_buf *xmit = &up->port.state->xmit; 337d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int count; 338d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 339d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (uart_tx_stopped(&up->port)) 340d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return; 341d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 342d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos count = up->port.fifosize; 343d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos do { 344d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int rdata; 345d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 346d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG); 347d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if ((rdata & AR933X_UART_DATA_TX_CSR) == 0) 348d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos break; 349d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 350d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (up->port.x_char) { 351d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_putc(up, up->port.x_char); 352d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->port.icount.tx++; 353d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->port.x_char = 0; 354d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos continue; 355d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } 356d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 357d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (uart_circ_empty(xmit)) 358d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos break; 359d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 360d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_putc(up, xmit->buf[xmit->tail]); 361d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 362d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 363d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->port.icount.tx++; 364d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } while (--count > 0); 365d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 366d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 367d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos uart_write_wakeup(&up->port); 368d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 369d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (!uart_circ_empty(xmit)) 370d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_start_tx_interrupt(up); 371d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 372d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 373d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) 374d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 375d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = dev_id; 376d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int status; 377d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 378d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos status = ar933x_uart_read(up, AR933X_UART_CS_REG); 379d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if ((status & AR933X_UART_CS_HOST_INT) == 0) 380d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return IRQ_NONE; 381d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 382d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_lock(&up->port.lock); 383d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 384d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos status = ar933x_uart_read(up, AR933X_UART_INT_REG); 385d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG); 386d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 387d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (status & AR933X_UART_INT_RX_VALID) { 388d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_REG, 389d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_INT_RX_VALID); 390d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rx_chars(up); 391d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } 392d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 393d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (status & AR933X_UART_INT_TX_EMPTY) { 394d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_REG, 395d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_INT_TX_EMPTY); 396d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_stop_tx_interrupt(up); 397d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_tx_chars(up); 398d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } 399d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 400d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_unlock(&up->port.lock); 401d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 402d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return IRQ_HANDLED; 403d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 404d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 405d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic int ar933x_uart_startup(struct uart_port *port) 406d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 407d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 408d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned long flags; 409d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int ret; 410d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 411d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ret = request_irq(up->port.irq, ar933x_uart_interrupt, 412d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->port.irqflags, dev_name(up->port.dev), up); 413d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (ret) 414d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return ret; 415d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 416d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_lock_irqsave(&up->port.lock, flags); 417d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 418d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Enable HOST interrupts */ 419d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw_set(up, AR933X_UART_CS_REG, 420d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_CS_HOST_INT_EN); 421d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 422d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Enable RX interrupts */ 423d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->ier = AR933X_UART_INT_RX_VALID; 424d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); 425d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 426d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_unlock_irqrestore(&up->port.lock, flags); 427d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 428d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return 0; 429d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 430d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 431d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_shutdown(struct uart_port *port) 432d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 433d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 434d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 435d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Disable all interrupts */ 436d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up->ier = 0; 437d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); 438d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 439d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Disable break condition */ 440d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG, 441d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos AR933X_UART_CS_TX_BREAK); 442d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 443d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos free_irq(up->port.irq, up); 444d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 445d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 446d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic const char *ar933x_uart_type(struct uart_port *port) 447d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 448d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return (port->type == PORT_AR933X) ? "AR933X UART" : NULL; 449d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 450d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 451d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_release_port(struct uart_port *port) 452d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 453d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Nothing to release ... */ 454d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 455d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 456d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic int ar933x_uart_request_port(struct uart_port *port) 457d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 458d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* UARTs always present */ 459d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return 0; 460d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 461d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 462d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_config_port(struct uart_port *port, int flags) 463d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 464d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (flags & UART_CONFIG_TYPE) 465d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->type = PORT_AR933X; 466d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 467d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 468d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic int ar933x_uart_verify_port(struct uart_port *port, 469d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct serial_struct *ser) 470d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 4712dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 4722dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 473d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (ser->type != PORT_UNKNOWN && 474d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ser->type != PORT_AR933X) 475d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -EINVAL; 476d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 477d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (ser->irq < 0 || ser->irq >= NR_IRQS) 478d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -EINVAL; 479d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 4802dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos if (ser->baud_base < up->min_baud || 4812dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos ser->baud_base > up->max_baud) 482d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -EINVAL; 483d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 484d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return 0; 485d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 486d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 487d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic struct uart_ops ar933x_uart_ops = { 488d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .tx_empty = ar933x_uart_tx_empty, 489d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .set_mctrl = ar933x_uart_set_mctrl, 490d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .get_mctrl = ar933x_uart_get_mctrl, 491d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .stop_tx = ar933x_uart_stop_tx, 492d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .start_tx = ar933x_uart_start_tx, 493d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .stop_rx = ar933x_uart_stop_rx, 494d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .break_ctl = ar933x_uart_break_ctl, 495d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .startup = ar933x_uart_startup, 496d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .shutdown = ar933x_uart_shutdown, 497d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .set_termios = ar933x_uart_set_termios, 498d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .type = ar933x_uart_type, 499d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .release_port = ar933x_uart_release_port, 500d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .request_port = ar933x_uart_request_port, 501d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .config_port = ar933x_uart_config_port, 502d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .verify_port = ar933x_uart_verify_port, 503d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos}; 504d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 505d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic struct ar933x_uart_port * 506d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; 507d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 508d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up) 509d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 510d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int status; 511d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int timeout = 60000; 512d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 513d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* Wait up to 60ms for the character(s) to be sent. */ 514d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos do { 515d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos status = ar933x_uart_read(up, AR933X_UART_DATA_REG); 516d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (--timeout == 0) 517d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos break; 518d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos udelay(1); 519d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } while ((status & AR933X_UART_DATA_TX_CSR) == 0); 520d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 521d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 522d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_console_putchar(struct uart_port *port, int ch) 523d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 524d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = (struct ar933x_uart_port *) port; 525d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 526d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_wait_xmitr(up); 527d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_putc(up, ch); 528d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 529d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 530d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_console_write(struct console *co, const char *s, 531d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int count) 532d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 533d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up = ar933x_console_ports[co->index]; 534d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned long flags; 535d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos unsigned int int_en; 536d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int locked = 1; 537d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 538d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos local_irq_save(flags); 539d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 540d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (up->port.sysrq) 541d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos locked = 0; 542d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos else if (oops_in_progress) 543d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos locked = spin_trylock(&up->port.lock); 544d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos else 545d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_lock(&up->port.lock); 546d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 547d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* 548d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * First save the IER then disable the interrupts 549d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos */ 550d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int_en = ar933x_uart_read(up, AR933X_UART_INT_EN_REG); 551d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0); 552d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 553d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos uart_console_write(&up->port, s, count, ar933x_uart_console_putchar); 554d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 555d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos /* 556d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * Finally, wait for transmitter to become empty 557d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos * and restore the IER 558d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos */ 559d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_wait_xmitr(up); 560d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_EN_REG, int_en); 561d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 562d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS); 563d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 564d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (locked) 565d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos spin_unlock(&up->port.lock); 566d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 567d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos local_irq_restore(flags); 568d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 569d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 570d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic int ar933x_uart_console_setup(struct console *co, char *options) 571d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 572d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up; 573d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int baud = 115200; 574d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int bits = 8; 575d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int parity = 'n'; 576d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int flow = 'n'; 577d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 578d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (co->index < 0 || co->index >= CONFIG_SERIAL_AR933X_NR_UARTS) 579d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -EINVAL; 580d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 581d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up = ar933x_console_ports[co->index]; 582d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (!up) 583d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -ENODEV; 584d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 585d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (options) 586d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos uart_parse_options(options, &baud, &parity, &bits, &flow); 587d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 588d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return uart_set_options(&up->port, co, baud, parity, bits, flow); 589d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 590d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 591d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic struct console ar933x_uart_console = { 592d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .name = "ttyATH", 593d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .write = ar933x_uart_console_write, 594d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .device = uart_console_device, 595d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .setup = ar933x_uart_console_setup, 596d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .flags = CON_PRINTBUFFER, 597d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .index = -1, 598d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .data = &ar933x_uart_driver, 599d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos}; 600d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 601d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void ar933x_uart_add_console_port(struct ar933x_uart_port *up) 602d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 603124155351331a53feb00d10874f0c620405fd385Gabor Juhos if (!ar933x_uart_console_enabled()) 604124155351331a53feb00d10874f0c620405fd385Gabor Juhos return; 605124155351331a53feb00d10874f0c620405fd385Gabor Juhos 606d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_console_ports[up->port.line] = up; 607d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 608d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 609d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic struct uart_driver ar933x_uart_driver = { 610d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .owner = THIS_MODULE, 611d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .driver_name = DRIVER_NAME, 612d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .dev_name = "ttyATH", 613d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .nr = CONFIG_SERIAL_AR933X_NR_UARTS, 614124155351331a53feb00d10874f0c620405fd385Gabor Juhos .cons = NULL, /* filled in runtime */ 615d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos}; 616d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 6179671f09921d93e722a28ae9610d478e092ac5466Bill Pembertonstatic int ar933x_uart_probe(struct platform_device *pdev) 618d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 619d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up; 620d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct uart_port *port; 621d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct resource *mem_res; 622d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct resource *irq_res; 623dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos struct device_node *np; 6242dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos unsigned int baud; 625d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int id; 626d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int ret; 627d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 628dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos np = pdev->dev.of_node; 629dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos if (config_enabled(CONFIG_OF) && np) { 630dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos id = of_alias_get_id(np, "serial"); 631dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos if (id < 0) { 632dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos dev_err(&pdev->dev, "unable to get alias id, err=%d\n", 633dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos id); 634dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos return id; 635dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos } 636dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos } else { 637dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos id = pdev->id; 638dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos if (id == -1) 639dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos id = 0; 640dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos } 641d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 642d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (id > CONFIG_SERIAL_AR933X_NR_UARTS) 643d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -EINVAL; 644d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 645d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 646d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (!irq_res) { 647d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos dev_err(&pdev->dev, "no IRQ resource\n"); 648d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -EINVAL; 649d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos } 650d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 651a324e4de0ce5c467b33a54ed65cc2f41c68855aeGabor Juhos up = devm_kzalloc(&pdev->dev, sizeof(struct ar933x_uart_port), 652a324e4de0ce5c467b33a54ed65cc2f41c68855aeGabor Juhos GFP_KERNEL); 653d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (!up) 654d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return -ENOMEM; 655d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 65615ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos up->clk = devm_clk_get(&pdev->dev, "uart"); 65715ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos if (IS_ERR(up->clk)) { 65815ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos dev_err(&pdev->dev, "unable to get UART clock\n"); 65915ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos return PTR_ERR(up->clk); 66015ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos } 66115ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos 662d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port = &up->port; 663d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 664071eb0ff68f5898af724752b3527edcddf222e23Julia Lawall mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 665a324e4de0ce5c467b33a54ed65cc2f41c68855aeGabor Juhos port->membase = devm_ioremap_resource(&pdev->dev, mem_res); 666a324e4de0ce5c467b33a54ed65cc2f41c68855aeGabor Juhos if (IS_ERR(port->membase)) 667a324e4de0ce5c467b33a54ed65cc2f41c68855aeGabor Juhos return PTR_ERR(port->membase); 668d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 66915ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos ret = clk_prepare_enable(up->clk); 67015ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos if (ret) 67115ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos return ret; 67215ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos 67315ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos port->uartclk = clk_get_rate(up->clk); 67415ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos if (!port->uartclk) { 67515ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos ret = -EINVAL; 67615ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos goto err_disable_clk; 67715ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos } 67815ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos 679a324e4de0ce5c467b33a54ed65cc2f41c68855aeGabor Juhos port->mapbase = mem_res->start; 680d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->line = id; 681d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->irq = irq_res->start; 682d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->dev = &pdev->dev; 683d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->type = PORT_AR933X; 684d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->iotype = UPIO_MEM32; 685d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 686d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->regshift = 2; 687d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->fifosize = AR933X_UART_FIFO_SIZE; 688d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos port->ops = &ar933x_uart_ops; 689d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 6902dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); 6912dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); 6922dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 6932dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); 6942dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); 6952dff8ad92661b6c99e9ba8b5918e43b522551556Gabor Juhos 696d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ar933x_uart_add_console_port(up); 697d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 698d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ret = uart_add_one_port(&ar933x_uart_driver, &up->port); 699d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (ret) 70015ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos goto err_disable_clk; 701d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 702d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos platform_set_drvdata(pdev, up); 703d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return 0; 70415ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos 70515ef17f622033455dcf03ae96256e474073a7b11Gabor Juhoserr_disable_clk: 70615ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos clk_disable_unprepare(up->clk); 70715ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos return ret; 708d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 709d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 710ae8d8a146725a966bd7c59c94f4d0016dcf7a04fBill Pembertonstatic int ar933x_uart_remove(struct platform_device *pdev) 711d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 712d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos struct ar933x_uart_port *up; 713d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 714d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos up = platform_get_drvdata(pdev); 715d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 71615ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos if (up) { 717d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos uart_remove_one_port(&ar933x_uart_driver, &up->port); 71815ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos clk_disable_unprepare(up->clk); 71915ef17f622033455dcf03ae96256e474073a7b11Gabor Juhos } 720d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 721d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return 0; 722d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 723d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 724dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos#ifdef CONFIG_OF 725dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhosstatic const struct of_device_id ar933x_uart_of_ids[] = { 726dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos { .compatible = "qca,ar9330-uart" }, 727dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos {}, 728dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos}; 729dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor JuhosMODULE_DEVICE_TABLE(of, ar933x_uart_of_ids); 730dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos#endif 731dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos 732d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic struct platform_driver ar933x_uart_platform_driver = { 733d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .probe = ar933x_uart_probe, 7342d47b7160243b1422006b91debf438484a4fde58Bill Pemberton .remove = ar933x_uart_remove, 735d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .driver = { 736d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .name = DRIVER_NAME, 737d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos .owner = THIS_MODULE, 738dd910d98a2e240443db0090b0ae8a719a4a460f8Gabor Juhos .of_match_table = of_match_ptr(ar933x_uart_of_ids), 739d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos }, 740d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos}; 741d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 742d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic int __init ar933x_uart_init(void) 743d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 744d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos int ret; 745d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 746124155351331a53feb00d10874f0c620405fd385Gabor Juhos if (ar933x_uart_console_enabled()) 747124155351331a53feb00d10874f0c620405fd385Gabor Juhos ar933x_uart_driver.cons = &ar933x_uart_console; 748124155351331a53feb00d10874f0c620405fd385Gabor Juhos 749d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ret = uart_register_driver(&ar933x_uart_driver); 750d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (ret) 751d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos goto err_out; 752d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 753d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos ret = platform_driver_register(&ar933x_uart_platform_driver); 754d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos if (ret) 755d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos goto err_unregister_uart_driver; 756d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 757d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return 0; 758d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 759d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhoserr_unregister_uart_driver: 760d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos uart_unregister_driver(&ar933x_uart_driver); 761d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhoserr_out: 762d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos return ret; 763d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 764d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 765d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosstatic void __exit ar933x_uart_exit(void) 766d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos{ 767d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos platform_driver_unregister(&ar933x_uart_platform_driver); 768d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos uart_unregister_driver(&ar933x_uart_driver); 769d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos} 770d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 771d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosmodule_init(ar933x_uart_init); 772d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhosmodule_exit(ar933x_uart_exit); 773d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor Juhos 774d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor JuhosMODULE_DESCRIPTION("Atheros AR933X UART driver"); 775d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor JuhosMODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); 776d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor JuhosMODULE_LICENSE("GPL v2"); 777d57f341ba08c9f34ccd45a89729e73174d4a3325Gabor JuhosMODULE_ALIAS("platform:" DRIVER_NAME); 778