static int s3c24xx_serial_init_port()

in serial/samsung_tty.c [2020:2149]


static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
				    struct platform_device *platdev)
{
	struct uart_port *port = &ourport->port;
	struct s3c2410_uartcfg *cfg = ourport->cfg;
	struct resource *res;
	int ret;

	if (platdev == NULL)
		return -ENODEV;

	if (port->mapbase != 0)
		return -EINVAL;

	/* setup info for port */
	port->dev	= &platdev->dev;

	port->uartclk = 1;

	if (cfg->uart_flags & UPF_CONS_FLOW) {
		dev_dbg(port->dev, "enabling flow control\n");
		port->flags |= UPF_CONS_FLOW;
	}

	/* sort our the physical and virtual addresses for each UART */

	res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		dev_err(port->dev, "failed to find memory resource for uart\n");
		return -EINVAL;
	}

	dev_dbg(port->dev, "resource %pR)\n", res);

	port->membase = devm_ioremap_resource(port->dev, res);
	if (IS_ERR(port->membase)) {
		dev_err(port->dev, "failed to remap controller address\n");
		return -EBUSY;
	}

	port->mapbase = res->start;
	ret = platform_get_irq(platdev, 0);
	if (ret < 0) {
		port->irq = 0;
	} else {
		port->irq = ret;
		ourport->rx_irq = ret;
		ourport->tx_irq = ret + 1;
	}

	switch (ourport->info->type) {
	case TYPE_S3C24XX:
		ret = platform_get_irq(platdev, 1);
		if (ret > 0)
			ourport->tx_irq = ret;
		break;
	default:
		break;
	}

	/*
	 * DMA is currently supported only on DT platforms, if DMA properties
	 * are specified.
	 */
	if (platdev->dev.of_node && of_find_property(platdev->dev.of_node,
						     "dmas", NULL)) {
		ourport->dma = devm_kzalloc(port->dev,
					    sizeof(*ourport->dma),
					    GFP_KERNEL);
		if (!ourport->dma) {
			ret = -ENOMEM;
			goto err;
		}
	}

	ourport->clk	= clk_get(&platdev->dev, "uart");
	if (IS_ERR(ourport->clk)) {
		pr_err("%s: Controller clock not found\n",
				dev_name(&platdev->dev));
		ret = PTR_ERR(ourport->clk);
		goto err;
	}

	ret = clk_prepare_enable(ourport->clk);
	if (ret) {
		pr_err("uart: clock failed to prepare+enable: %d\n", ret);
		clk_put(ourport->clk);
		goto err;
	}

	ret = s3c24xx_serial_enable_baudclk(ourport);
	if (ret)
		pr_warn("uart: failed to enable baudclk\n");

	/* Keep all interrupts masked and cleared */
	switch (ourport->info->type) {
	case TYPE_S3C6400:
		wr_regl(port, S3C64XX_UINTM, 0xf);
		wr_regl(port, S3C64XX_UINTP, 0xf);
		wr_regl(port, S3C64XX_UINTSP, 0xf);
		break;
	case TYPE_APPLE_S5L: {
		unsigned int ucon;

		ucon = rd_regl(port, S3C2410_UCON);
		ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
			APPLE_S5L_UCON_RXTHRESH_ENA_MSK |
			APPLE_S5L_UCON_RXTO_ENA_MSK);
		wr_regl(port, S3C2410_UCON, ucon);

		wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS);
		break;
	}
	default:
		break;
	}

	dev_dbg(port->dev, "port: map=%pa, mem=%p, irq=%d (%d,%d), clock=%u\n",
		&port->mapbase, port->membase, port->irq,
		ourport->rx_irq, ourport->tx_irq, port->uartclk);

	/* reset the fifos (and setup the uart) */
	s3c24xx_serial_resetport(port, cfg);

	return 0;

err:
	port->mapbase = 0;
	return ret;
}