static int cpm_uart_init_port()

in serial/cpm_uart/cpm_uart_core.c [1146:1265]


static int cpm_uart_init_port(struct device_node *np,
                              struct uart_cpm_port *pinfo)
{
	const u32 *data;
	void __iomem *mem, *pram;
	struct device *dev = pinfo->port.dev;
	int len;
	int ret;
	int i;

	data = of_get_property(np, "clock", NULL);
	if (data) {
		struct clk *clk = clk_get(NULL, (const char*)data);
		if (!IS_ERR(clk))
			pinfo->clk = clk;
	}
	if (!pinfo->clk) {
		data = of_get_property(np, "fsl,cpm-brg", &len);
		if (!data || len != 4) {
			printk(KERN_ERR "CPM UART %pOFn has no/invalid "
			                "fsl,cpm-brg property.\n", np);
			return -EINVAL;
		}
		pinfo->brg = *data;
	}

	data = of_get_property(np, "fsl,cpm-command", &len);
	if (!data || len != 4) {
		printk(KERN_ERR "CPM UART %pOFn has no/invalid "
		                "fsl,cpm-command property.\n", np);
		return -EINVAL;
	}
	pinfo->command = *data;

	mem = of_iomap(np, 0);
	if (!mem)
		return -ENOMEM;

	if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
	    of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
		pinfo->sccp = mem;
		pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np);
	} else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
	           of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
		pinfo->flags |= FLAG_SMC;
		pinfo->smcp = mem;
		pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np);
	} else {
		ret = -ENODEV;
		goto out_mem;
	}

	if (!pram) {
		ret = -ENOMEM;
		goto out_mem;
	}

	pinfo->tx_nrfifos = TX_NUM_FIFO;
	pinfo->tx_fifosize = TX_BUF_SIZE;
	pinfo->rx_nrfifos = RX_NUM_FIFO;
	pinfo->rx_fifosize = RX_BUF_SIZE;

	pinfo->port.uartclk = ppc_proc_freq;
	pinfo->port.mapbase = (unsigned long)mem;
	pinfo->port.type = PORT_CPM;
	pinfo->port.ops = &cpm_uart_pops;
	pinfo->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_CPM_CONSOLE);
	pinfo->port.iotype = UPIO_MEM;
	pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize;
	spin_lock_init(&pinfo->port.lock);

	pinfo->port.irq = irq_of_parse_and_map(np, 0);
	if (pinfo->port.irq == NO_IRQ) {
		ret = -EINVAL;
		goto out_pram;
	}

	for (i = 0; i < NUM_GPIOS; i++) {
		struct gpio_desc *gpiod;

		pinfo->gpios[i] = NULL;

		gpiod = devm_gpiod_get_index_optional(dev, NULL, i, GPIOD_ASIS);

		if (IS_ERR(gpiod)) {
			ret = PTR_ERR(gpiod);
			goto out_irq;
		}

		if (gpiod) {
			if (i == GPIO_RTS || i == GPIO_DTR)
				ret = gpiod_direction_output(gpiod, 0);
			else
				ret = gpiod_direction_input(gpiod);
			if (ret) {
				pr_err("can't set direction for gpio #%d: %d\n",
					i, ret);
				continue;
			}
			pinfo->gpios[i] = gpiod;
		}
	}

#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
#ifdef CONFIG_CONSOLE_POLL
	if (!udbg_port)
#endif
		udbg_putc = NULL;
#endif

	return cpm_uart_request_port(&pinfo->port);

out_irq:
	irq_dispose_mapping(pinfo->port.irq);
out_pram:
	cpm_uart_unmap_pram(pinfo, pram);
out_mem:
	iounmap(mem);
	return ret;
}