1 /*
2  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
3  *
4  * SPDX-License-Identifier: GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <asm/io.h>
11 #include <dm/pinctrl.h>
12 #include <mach/ar71xx_regs.h>
13 
14 DECLARE_GLOBAL_DATA_PTR;
15 
16 enum periph_id {
17 	PERIPH_ID_UART0,
18 	PERIPH_ID_SPI0,
19 	PERIPH_ID_NONE = -1,
20 };
21 
22 struct qca953x_pinctrl_priv {
23 	void __iomem *regs;
24 };
25 
26 static void pinctrl_qca953x_spi_config(struct qca953x_pinctrl_priv *priv, int cs)
27 {
28 	switch (cs) {
29 	case 0:
30 		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
31 				QCA953X_GPIO(5) | QCA953X_GPIO(6) |
32 				QCA953X_GPIO(7), QCA953X_GPIO(8));
33 
34 		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC1,
35 				QCA953X_GPIO_MUX_MASK(8) |
36 				QCA953X_GPIO_MUX_MASK(16) |
37 				QCA953X_GPIO_MUX_MASK(24),
38 				(QCA953X_GPIO_OUT_MUX_SPI_CS0 << 8) |
39 				(QCA953X_GPIO_OUT_MUX_SPI_CLK << 16) |
40 				(QCA953X_GPIO_OUT_MUX_SPI_MOSI << 24));
41 
42 		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
43 				QCA953X_GPIO_MUX_MASK(0),
44 				QCA953X_GPIO_IN_MUX_SPI_DATA_IN);
45 
46 		setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
47 			     QCA953X_GPIO(8));
48 		break;
49 	}
50 }
51 
52 static void pinctrl_qca953x_uart_config(struct qca953x_pinctrl_priv *priv, int uart_id)
53 {
54 	switch (uart_id) {
55 	case PERIPH_ID_UART0:
56 		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
57 				QCA953X_GPIO(9), QCA953X_GPIO(10));
58 
59 		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC2,
60 				QCA953X_GPIO_MUX_MASK(16),
61 				QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16);
62 
63 		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
64 				QCA953X_GPIO_MUX_MASK(8),
65 				QCA953X_GPIO_IN_MUX_UART0_SIN << 8);
66 
67 		setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
68 			     QCA953X_GPIO(10));
69 		break;
70 	}
71 }
72 
73 static int qca953x_pinctrl_request(struct udevice *dev, int func, int flags)
74 {
75 	struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
76 
77 	debug("%s: func=%x, flags=%x\n", __func__, func, flags);
78 	switch (func) {
79 	case PERIPH_ID_SPI0:
80 		pinctrl_qca953x_spi_config(priv, flags);
81 		break;
82 	case PERIPH_ID_UART0:
83 		pinctrl_qca953x_uart_config(priv, func);
84 		break;
85 	default:
86 		return -EINVAL;
87 	}
88 
89 	return 0;
90 }
91 
92 static int qca953x_pinctrl_get_periph_id(struct udevice *dev,
93 					struct udevice *periph)
94 {
95 	u32 cell[2];
96 	int ret;
97 
98 	ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(periph),
99 				   "interrupts", cell, ARRAY_SIZE(cell));
100 	if (ret < 0)
101 		return -EINVAL;
102 
103 	switch (cell[0]) {
104 	case 128:
105 		return PERIPH_ID_UART0;
106 	case 129:
107 		return PERIPH_ID_SPI0;
108 	}
109 	return -ENOENT;
110 }
111 
112 static int qca953x_pinctrl_set_state_simple(struct udevice *dev,
113 					   struct udevice *periph)
114 {
115 	int func;
116 
117 	func = qca953x_pinctrl_get_periph_id(dev, periph);
118 	if (func < 0)
119 		return func;
120 	return qca953x_pinctrl_request(dev, func, 0);
121 }
122 
123 static struct pinctrl_ops qca953x_pinctrl_ops = {
124 	.set_state_simple	= qca953x_pinctrl_set_state_simple,
125 	.request	= qca953x_pinctrl_request,
126 	.get_periph_id	= qca953x_pinctrl_get_periph_id,
127 };
128 
129 static int qca953x_pinctrl_probe(struct udevice *dev)
130 {
131 	struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
132 	fdt_addr_t addr;
133 
134 	addr = devfdt_get_addr(dev);
135 	if (addr == FDT_ADDR_T_NONE)
136 		return -EINVAL;
137 
138 	priv->regs = map_physmem(addr,
139 				 AR71XX_GPIO_SIZE,
140 				 MAP_NOCACHE);
141 	return 0;
142 }
143 
144 static const struct udevice_id qca953x_pinctrl_ids[] = {
145 	{ .compatible = "qca,qca953x-pinctrl" },
146 	{ }
147 };
148 
149 U_BOOT_DRIVER(pinctrl_qca953x) = {
150 	.name		= "pinctrl_qca953x",
151 	.id		= UCLASS_PINCTRL,
152 	.of_match	= qca953x_pinctrl_ids,
153 	.priv_auto_alloc_size = sizeof(struct qca953x_pinctrl_priv),
154 	.ops		= &qca953x_pinctrl_ops,
155 	.probe		= qca953x_pinctrl_probe,
156 };
157