Skip to content
atmel_serial.c 54 KiB
Newer Older
		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);
#define atmel_serial_suspend NULL
#define atmel_serial_resume NULL
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 = pdev->dev.platform_data;
	int ret = -ENODEV;
	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:
		 * auto-enumerate it */
		ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART);
	if (ret >= ATMEL_MAX_UART) {
	if (test_and_set_bit(ret, atmel_ports_in_use)) {
		/* port already in use */
		ret = -EBUSY;
		goto err;
	}

	port = &atmel_ports[ret];
	port->uart.line = ret;
	ret = atmel_init_port(port, pdev);
	if (ret)
		goto err;
	if (!atmel_use_pdc_rx(&port->uart)) {
		ret = -ENOMEM;
		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 (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);
	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);
	}

	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);
	int ret = 0;

	device_init_wakeup(&pdev->dev, 0);

	ret = uart_remove_one_port(&atmel_uart, port);

	tasklet_kill(&atmel_port->tasklet);
	kfree(atmel_port->rx_ring.buf);

	/* "port" is allocated statically, so we shouldn't free it */

	clear_bit(port->line, atmel_ports_in_use);
static struct platform_driver atmel_serial_driver = {
	.probe		= atmel_serial_probe,
	.remove		= atmel_serial_remove,
	.suspend	= atmel_serial_suspend,
	.resume		= atmel_serial_resume,
		.owner	= THIS_MODULE,
		.of_match_table	= of_match_ptr(atmel_serial_dt_ids),
static int __init atmel_serial_init(void)
	ret = uart_register_driver(&atmel_uart);
	ret = platform_driver_register(&atmel_serial_driver);
		uart_unregister_driver(&atmel_uart);
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");