summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/ath79/pinctrl_qca953x.c
blob: d02597e968aca76fd1edc5b1482e1030cad48ab9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
 *
 * SPDX-License-Identifier: GPL-2.0+
 */

#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <dm/pinctrl.h>
#include <mach/ar71xx_regs.h>

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,
};
OpenPOWER on IntegriCloud