Newer
Older
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= ATMEL_US_RXBRK;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= ATMEL_US_OVRE;
/* TODO: Ignore all characters if CREAD is set.*/
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
/*
* save/disable interrupts. The tty layer will ensure that the
* transmitter is empty if requested by the caller, so there's
* no need to wait for it here.
*/
imr = UART_GET_IMR(port);
UART_PUT_IDR(port, -1);
/* disable receiver and transmitter */
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
/* Resetting serial mode to RS232 (0x0) */
mode &= ~ATMEL_US_USMODE;
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
if ((atmel_port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port,
atmel_port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
}
/* set the parity, stop bits and data size */
UART_PUT_MR(port, mode);
/* set the baud rate */
UART_PUT_BRGR(port, quot);
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
/* restore interrupts */
UART_PUT_IER(port, imr);
/* CTS flow-control and modem-status interrupts */
if (UART_ENABLE_MS(port, termios->c_cflag))
atmel_enable_ms(port);
else
atmel_disable_ms(port);
spin_unlock_irqrestore(&port->lock, flags);
}
static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios)
if (termios->c_line == N_PPS) {
spin_lock_irq(&port->lock);
spin_unlock_irq(&port->lock);
} else {
port->flags &= ~UPF_HARDPPS_CD;
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
spin_lock_irq(&port->lock);
atmel_disable_ms(port);
spin_unlock_irq(&port->lock);
}
/*
* Return string describing the specified port
*/
static const char *atmel_type(struct uart_port *port)
return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
}
/*
* Release the memory region(s) being used by 'port'.
*/
static void atmel_release_port(struct uart_port *port)
struct platform_device *pdev = to_platform_device(port->dev);
int size = pdev->resource[0].end - pdev->resource[0].start + 1;
release_mem_region(port->mapbase, size);
if (port->flags & UPF_IOREMAP) {
iounmap(port->membase);
port->membase = NULL;
}
}
/*
* Request the memory region(s) being used by 'port'.
*/
static int atmel_request_port(struct uart_port *port)
struct platform_device *pdev = to_platform_device(port->dev);
int size = pdev->resource[0].end - pdev->resource[0].start + 1;
if (!request_mem_region(port->mapbase, size, "atmel_serial"))
return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (port->membase == NULL) {
release_mem_region(port->mapbase, size);
return -ENOMEM;
}
}
}
/*
* Configure/autoconfigure the port.
*/
static void atmel_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_ATMEL;
atmel_request_port(port);
}
}
/*
* Verify the new serial_struct (for TIOCSSERIAL).
*/
static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
ret = -EINVAL;
if (port->irq != ser->irq)
ret = -EINVAL;
if (ser->io_type != SERIAL_IO_MEM)
ret = -EINVAL;
if (port->uartclk / 16 != ser->baud_base)
ret = -EINVAL;
if ((void *)port->mapbase != ser->iomem_base)
ret = -EINVAL;
if (port->iobase != ser->port)
ret = -EINVAL;
if (ser->hub6 != 0)
ret = -EINVAL;
return ret;
}
#ifdef CONFIG_CONSOLE_POLL
static int atmel_poll_get_char(struct uart_port *port)
{
while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY))
cpu_relax();
return UART_GET_CHAR(port);
}
static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
{
while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
cpu_relax();
UART_PUT_CHAR(port, ch);
}
#endif
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
static int
atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
{
struct serial_rs485 rs485conf;
switch (cmd) {
case TIOCSRS485:
if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
sizeof(rs485conf)))
return -EFAULT;
atmel_config_rs485(port, &rs485conf);
break;
case TIOCGRS485:
if (copy_to_user((struct serial_rs485 *) arg,
&(to_atmel_uart_port(port)->rs485),
sizeof(rs485conf)))
return -EFAULT;
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
static struct uart_ops atmel_pops = {
.tx_empty = atmel_tx_empty,
.set_mctrl = atmel_set_mctrl,
.get_mctrl = atmel_get_mctrl,
.stop_tx = atmel_stop_tx,
.start_tx = atmel_start_tx,
.stop_rx = atmel_stop_rx,
.enable_ms = atmel_enable_ms,
.break_ctl = atmel_break_ctl,
.startup = atmel_startup,
.shutdown = atmel_shutdown,
.flush_buffer = atmel_flush_buffer,
.set_termios = atmel_set_termios,
.type = atmel_type,
.release_port = atmel_release_port,
.request_port = atmel_request_port,
.config_port = atmel_config_port,
.verify_port = atmel_verify_port,
.pm = atmel_serial_pm,
.ioctl = atmel_ioctl,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = atmel_poll_get_char,
.poll_put_char = atmel_poll_put_char,
#endif
/*
* Configure the port from the platform device resource info.
*/
static int atmel_init_port(struct atmel_uart_port *atmel_port,
struct uart_port *port = &atmel_port->uart;
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
if (!atmel_init_property(atmel_port, pdev))
atmel_set_ops(port);
atmel_init_rs485(atmel_port, pdev);
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &atmel_pops;
port->fifosize = 1;
port->dev = &pdev->dev;
port->mapbase = pdev->resource[0].start;
port->irq = pdev->resource[1].start;
tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
(unsigned long)port);
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
if (pdata && pdata->regs) {
Haavard Skinnemoen
committed
/* Already mapped by setup code */
port->membase = pdata->regs;
port->flags |= UPF_IOREMAP;
port->membase = NULL;
}
/* for console, the clock could already be configured */
if (!atmel_port->clk) {
atmel_port->clk = clk_get(&pdev->dev, "usart");
if (IS_ERR(atmel_port->clk)) {
ret = PTR_ERR(atmel_port->clk);
atmel_port->clk = NULL;
return ret;
}
ret = clk_prepare_enable(atmel_port->clk);
if (ret) {
clk_put(atmel_port->clk);
atmel_port->clk = NULL;
return ret;
}
port->uartclk = clk_get_rate(atmel_port->clk);
clk_disable_unprepare(atmel_port->clk);
/* only enable clock when USART is in use */
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
else if (atmel_use_pdc_tx(port)) {
atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
} else {
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
}
Jean-Christophe PLAGNIOL-VILLARD
committed
struct platform_device *atmel_default_console_device; /* the serial console device */
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
static void atmel_console_putchar(struct uart_port *port, int ch)
while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
UART_PUT_CHAR(port, ch);
}
/*
* Interrupts are disabled on entering
*/
static void atmel_console_write(struct console *co, const char *s, u_int count)
struct uart_port *port = &atmel_ports[co->index].uart;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, imr;
* First, save IMR and then disable interrupts
UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
/* Store PDC transmit status and disable it */
pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
uart_console_write(port, s, count, atmel_console_putchar);
* Finally, wait for transmitter to become empty
* and restore IMR
*/
do {
status = UART_GET_CSR(port);
} while (!(status & ATMEL_US_TXRDY));
/* Restore PDC transmit status */
if (pdc_tx)
UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
/* set interrupts back the way they were */
UART_PUT_IER(port, imr);
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
static void __init atmel_console_get_options(struct uart_port *port, int *baud,
int *parity, int *bits)
{
unsigned int mr, quot;
/*
* If the baud rate generator isn't running, the port wasn't
* initialized by the boot loader.
*/
quot = UART_GET_BRGR(port) & ATMEL_US_CD;
if (!quot)
return;
mr = UART_GET_MR(port) & ATMEL_US_CHRL;
if (mr == ATMEL_US_CHRL_8)
*bits = 8;
else
*bits = 7;
mr = UART_GET_MR(port) & ATMEL_US_PAR;
if (mr == ATMEL_US_PAR_EVEN)
else if (mr == ATMEL_US_PAR_ODD)
/*
* The serial core only rounds down when matching this to a
* supported baud rate. Make sure we don't end up slightly
* lower than one of those, as it would make us fall through
* to a much lower baud rate than we really want.
*/
*baud = port->uartclk / (16 * (quot - 1));
static int __init atmel_console_setup(struct console *co, char *options)
struct uart_port *port = &atmel_ports[co->index].uart;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (port->membase == NULL) {
/* Port not initialized yet - delay setup */
ret = clk_prepare_enable(atmel_ports[co->index].clk);
if (ret)
return ret;
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
atmel_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver atmel_uart;
static struct console atmel_console = {
.name = ATMEL_DEVICENAME,
.write = atmel_console_write,
.device = uart_console_device,
.setup = atmel_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &atmel_uart,
#define ATMEL_CONSOLE_DEVICE (&atmel_console)
/*
* Early console initialization (before VM subsystem initialized).
*/
static int __init atmel_console_init(void)
if (atmel_default_console_device) {
struct atmel_uart_data *pdata =
dev_get_platdata(&atmel_default_console_device->dev);
Linus Torvalds
committed
int id = pdata->num;
struct atmel_uart_port *port = &atmel_ports[id];
port->backup_imr = 0;
port->uart.line = id;
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
ret = atmel_init_port(port, atmel_default_console_device);
if (ret)
return ret;
register_console(&atmel_console);
return 0;
}
console_initcall(atmel_console_init);
/*
* Late console initialization.
*/
static int __init atmel_late_console_init(void)
if (atmel_default_console_device
&& !(atmel_console.flags & CON_ENABLED))
register_console(&atmel_console);
core_initcall(atmel_late_console_init);
static inline bool atmel_is_console_port(struct uart_port *port)
{
return port->cons && port->cons->index == port->line;
}
#define ATMEL_CONSOLE_DEVICE NULL
static inline bool atmel_is_console_port(struct uart_port *port)
{
return false;
}
static struct uart_driver atmel_uart = {
.owner = THIS_MODULE,
.driver_name = "atmel_serial",
.dev_name = ATMEL_DEVICENAME,
.major = SERIAL_ATMEL_MAJOR,
.minor = MINOR_START,
.nr = ATMEL_MAX_UART,
.cons = ATMEL_CONSOLE_DEVICE,
static bool atmel_serial_clk_will_stop(void)
{
#ifdef CONFIG_ARCH_AT91
return at91_suspend_entering_slow_clock();
#else
return false;
#endif
}
static int atmel_serial_suspend(struct platform_device *pdev,
pm_message_t state)
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
if (atmel_is_console_port(port) && console_suspend_enabled) {
/* Drain the TX shifter */
while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
cpu_relax();
}
/* we can not wake up if we're running on slow clock */
atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
if (atmel_serial_clk_will_stop())
device_set_wakeup_enable(&pdev->dev, 0);
uart_suspend_port(&atmel_uart, port);
static int atmel_serial_resume(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
uart_resume_port(&atmel_uart, port);
device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
return 0;
}
#define atmel_serial_suspend NULL
#define atmel_serial_resume NULL
static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
{
enum mctrl_gpio_idx i;
struct gpio_desc *gpiod;
p->gpios = mctrl_gpio_init(dev, 0);
if (IS_ERR_OR_NULL(p->gpios))
return -1;
for (i = 0; i < UART_GPIO_MAX; i++) {
gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
p->gpio_irq[i] = gpiod_to_irq(gpiod);
else
p->gpio_irq[i] = -EINVAL;
}
static int atmel_serial_probe(struct platform_device *pdev)
struct atmel_uart_port *port;
struct device_node *np = pdev->dev.of_node;
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
if (np)
ret = of_alias_get_id(np, "serial");
else
if (pdata)
ret = pdata->num;
/* port id not found in platform data nor device-tree aliases:
ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART);
if (ret >= ATMEL_MAX_UART) {
ret = -ENODEV;
goto err;
}
if (test_and_set_bit(ret, atmel_ports_in_use)) {
/* port already in use */
ret = -EBUSY;
goto err;
}
port = &atmel_ports[ret];
port->backup_imr = 0;
ret = atmel_init_gpios(port, &pdev->dev);
if (ret < 0)
dev_err(&pdev->dev, "%s",
"Failed to initialize GPIOs. The serial port may not work as expected");
ret = atmel_init_port(port, pdev);
if (ret)
goto err;
if (!atmel_use_pdc_rx(&port->uart)) {
data = kmalloc(sizeof(struct atmel_uart_char)
* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
if (!data)
goto err_alloc_ring;
port->rx_ring.buf = data;
}
ret = uart_add_one_port(&atmel_uart, &port->uart);
if (ret)
goto err_add_port;
Albin Tonnerre
committed
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
if (atmel_is_console_port(&port->uart)
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
/*
* The serial core enabled the clock for us, so undo
* the clk_prepare_enable() in atmel_console_setup()
clk_disable_unprepare(port->clk);
Albin Tonnerre
committed
#endif
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, port);
if (port->rs485.flags & SER_RS485_ENABLED) {
UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
}
/*
* Get port name of usart or uart
*/
atmel_get_ip_name(&port->uart);
return 0;
err_add_port:
kfree(port->rx_ring.buf);
port->rx_ring.buf = NULL;
err_alloc_ring:
if (!atmel_is_console_port(&port->uart)) {
clk_put(port->clk);
port->clk = NULL;
static int atmel_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
tasklet_kill(&atmel_port->tasklet);
device_init_wakeup(&pdev->dev, 0);
ret = uart_remove_one_port(&atmel_uart, port);
kfree(atmel_port->rx_ring.buf);
/* "port" is allocated statically, so we shouldn't free it */
clear_bit(port->line, atmel_ports_in_use);
clk_put(atmel_port->clk);
return ret;
}
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
.suspend = atmel_serial_suspend,
.resume = atmel_serial_resume,
.name = "atmel_usart",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
static int __init atmel_serial_init(void)
ret = uart_register_driver(&atmel_uart);
if (ret)
return ret;
ret = platform_driver_register(&atmel_serial_driver);
uart_unregister_driver(&atmel_uart);
return ret;
}
static void __exit atmel_serial_exit(void)
platform_driver_unregister(&atmel_serial_driver);
uart_unregister_driver(&atmel_uart);
module_init(atmel_serial_init);
module_exit(atmel_serial_exit);
MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:atmel_usart");