/* * Copyright (C) 2015-2016 Wills Wang * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; enum periph_id { PERIPH_ID_UART0, PERIPH_ID_SPI0, PERIPH_ID_NONE = -1, }; struct qca953x_pinctrl_priv { void __iomem *regs; }; static void pinctrl_qca953x_spi_config(struct qca953x_pinctrl_priv *priv, int cs) { switch (cs) { case 0: clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE, QCA953X_GPIO(5) | QCA953X_GPIO(6) | QCA953X_GPIO(7), QCA953X_GPIO(8)); clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC1, QCA953X_GPIO_MUX_MASK(8) | QCA953X_GPIO_MUX_MASK(16) | QCA953X_GPIO_MUX_MASK(24), (QCA953X_GPIO_OUT_MUX_SPI_CS0 << 8) | (QCA953X_GPIO_OUT_MUX_SPI_CLK << 16) | (QCA953X_GPIO_OUT_MUX_SPI_MOSI << 24)); clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0, QCA953X_GPIO_MUX_MASK(0), QCA953X_GPIO_IN_MUX_SPI_DATA_IN); setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT, QCA953X_GPIO(8)); break; } } static void pinctrl_qca953x_uart_config(struct qca953x_pinctrl_priv *priv, int uart_id) { switch (uart_id) { case PERIPH_ID_UART0: clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE, QCA953X_GPIO(9), QCA953X_GPIO(10)); clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC2, QCA953X_GPIO_MUX_MASK(16), QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16); clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0, QCA953X_GPIO_MUX_MASK(8), QCA953X_GPIO_IN_MUX_UART0_SIN << 8); setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT, QCA953X_GPIO(10)); break; } } static int qca953x_pinctrl_request(struct udevice *dev, int func, int flags) { struct qca953x_pinctrl_priv *priv = dev_get_priv(dev); debug("%s: func=%x, flags=%x\n", __func__, func, flags); switch (func) { case PERIPH_ID_SPI0: pinctrl_qca953x_spi_config(priv, flags); break; case PERIPH_ID_UART0: pinctrl_qca953x_uart_config(priv, func); break; default: return -EINVAL; } return 0; } static int qca953x_pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph) { u32 cell[2]; int ret; ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset, "interrupts", cell, ARRAY_SIZE(cell)); if (ret < 0) return -EINVAL; switch (cell[0]) { case 128: return PERIPH_ID_UART0; case 129: return PERIPH_ID_SPI0; } return -ENOENT; } static int qca953x_pinctrl_set_state_simple(struct udevice *dev, struct udevice *periph) { int func; func = qca953x_pinctrl_get_periph_id(dev, periph); if (func < 0) return func; return qca953x_pinctrl_request(dev, func, 0); } static struct pinctrl_ops qca953x_pinctrl_ops = { .set_state_simple = qca953x_pinctrl_set_state_simple, .request = qca953x_pinctrl_request, .get_periph_id = qca953x_pinctrl_get_periph_id, }; static int qca953x_pinctrl_probe(struct udevice *dev) { struct qca953x_pinctrl_priv *priv = dev_get_priv(dev); fdt_addr_t addr; addr = dev_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; priv->regs = map_physmem(addr, AR71XX_GPIO_SIZE, MAP_NOCACHE); return 0; } static const struct udevice_id qca953x_pinctrl_ids[] = { { .compatible = "qca,qca953x-pinctrl" }, { } }; U_BOOT_DRIVER(pinctrl_qca953x) = { .name = "pinctrl_qca953x", .id = UCLASS_PINCTRL, .of_match = qca953x_pinctrl_ids, .priv_auto_alloc_size = sizeof(struct qca953x_pinctrl_priv), .ops = &qca953x_pinctrl_ops, .probe = qca953x_pinctrl_probe, };