summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/pinctrl-qe-io.c
blob: e129ab2f8311639cfda4cdd3f4f159a858aa72fd (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2006 Freescale Semiconductor, Inc.
 *
 * Dave Liu <daveliu@freescale.com>
 * based on source code of Shlomi Gridish
 */

#include <common.h>
#include <linux/errno.h>
#include <asm/io.h>
#include <asm/immap_83xx.h>

#if defined(CONFIG_PINCTRL)
#include <dm.h>
#include <dm/device_compat.h>
#include <dm/pinctrl.h>
#include <linux/ioport.h>

/**
 * struct qe_io_plat
 *
 * @base:		Base register address
 * @num_par_io_ports	number of io ports
 */
struct qe_io_plat {
	qepio83xx_t *base;
	u32 num_io_ports;
};
#endif

#define	NUM_OF_PINS	32

/** qe_cfg_iopin configure one io pin setting
 *
 * @par_io:	pointer to parallel I/O base
 * @port:	io pin port
 * @pin:	io pin number which get configured
 * @dir:	direction of io pin 2 bits valid
 *		00 = pin disabled
 *		01 = output
 *		10 = input
 *		11 = pin is I/O
 * @open_drain:	is pin open drain
 * @assign:	pin assignment registers select the function of the pin
 */
static void qe_cfg_iopin(qepio83xx_t *par_io, u8 port, u8 pin, int dir,
			 int open_drain, int assign)
{
	u32	dbit_mask;
	u32	dbit_dir;
	u32	dbit_asgn;
	u32	bit_mask;
	u32	tmp_val;
	int	offset;

	offset = (NUM_OF_PINS - (pin % (NUM_OF_PINS / 2) + 1) * 2);

	/* Calculate pin location and 2bit mask and dir */
	dbit_mask = (u32)(0x3 << offset);
	dbit_dir = (u32)(dir << offset);

	/* Setup the direction */
	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
		in_be32(&par_io->ioport[port].dir2) :
		in_be32(&par_io->ioport[port].dir1);

	if (pin > (NUM_OF_PINS / 2) - 1) {
		out_be32(&par_io->ioport[port].dir2, ~dbit_mask & tmp_val);
		out_be32(&par_io->ioport[port].dir2, dbit_dir | tmp_val);
	} else {
		out_be32(&par_io->ioport[port].dir1, ~dbit_mask & tmp_val);
		out_be32(&par_io->ioport[port].dir1, dbit_dir | tmp_val);
	}

	/* Calculate pin location for 1bit mask */
	bit_mask = (u32)(1 << (NUM_OF_PINS - (pin + 1)));

	/* Setup the open drain */
	tmp_val = in_be32(&par_io->ioport[port].podr);
	if (open_drain)
		out_be32(&par_io->ioport[port].podr, bit_mask | tmp_val);
	else
		out_be32(&par_io->ioport[port].podr, ~bit_mask & tmp_val);

	/* Setup the assignment */
	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
		in_be32(&par_io->ioport[port].ppar2) :
		in_be32(&par_io->ioport[port].ppar1);
	dbit_asgn = (u32)(assign << offset);

	/* Clear and set 2 bits mask */
	if (pin > (NUM_OF_PINS / 2) - 1) {
		out_be32(&par_io->ioport[port].ppar2, ~dbit_mask & tmp_val);
		out_be32(&par_io->ioport[port].ppar2, dbit_asgn | tmp_val);
	} else {
		out_be32(&par_io->ioport[port].ppar1, ~dbit_mask & tmp_val);
		out_be32(&par_io->ioport[port].ppar1, dbit_asgn | tmp_val);
	}
}

#if !defined(CONFIG_PINCTRL)
/** qe_config_iopin configure one io pin setting
 *
 * @port:	io pin port
 * @pin:	io pin number which get configured
 * @dir:	direction of io pin 2 bits valid
 *		00 = pin disabled
 *		01 = output
 *		10 = input
 *		11 = pin is I/O
 * @open_drain:	is pin open drain
 * @assign:	pin assignment registers select the function of the pin
 */
void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign)
{
	immap_t        *im = (immap_t *)CONFIG_SYS_IMMR;
	qepio83xx_t    *par_io = (qepio83xx_t *)&im->qepio;

	qe_cfg_iopin(par_io, port, pin, dir, open_drain, assign);
}
#else
static int qe_io_of_to_plat(struct udevice *dev)
{
	struct qe_io_plat *plat = dev_get_plat(dev);
	fdt_addr_t addr;

	addr = dev_read_addr(dev);
	if (addr == FDT_ADDR_T_NONE)
		return -EINVAL;

	plat->base = (qepio83xx_t *)addr;
	if (dev_read_u32(dev, "num-ports", &plat->num_io_ports))
		return -EINVAL;

	return 0;
}

/**
 * par_io_of_config_node	config
 * @dev:	pointer to pinctrl device
 * @pio:	ofnode of pinconfig property
 */
static int par_io_of_config_node(struct udevice *dev, ofnode pio)
{
	struct qe_io_plat *plat = dev_get_plat(dev);
	qepio83xx_t *par_io = plat->base;
	const unsigned int *pio_map;
	int pio_map_len;

	pio_map = ofnode_get_property(pio, "pio-map", &pio_map_len);
	if (!pio_map)
		return -ENOENT;

	pio_map_len /= sizeof(unsigned int);
	if ((pio_map_len % 6) != 0) {
		dev_err(dev, "%s: pio-map format wrong!\n", __func__);
		return -EINVAL;
	}

	while (pio_map_len > 0) {
		/*
		 * column pio_map[5] from linux (has_irq) not
		 * supported in u-boot yet.
		 */
		qe_cfg_iopin(par_io, (u8)pio_map[0], (u8)pio_map[1],
			     (int)pio_map[2], (int)pio_map[3],
			     (int)pio_map[4]);
		pio_map += 6;
		pio_map_len -= 6;
	}
	return 0;
}

int par_io_of_config(struct udevice *dev)
{
	u32 phandle;
	ofnode pio;
	int err;

	err = ofnode_read_u32(dev_ofnode(dev), "pio-handle", &phandle);
	if (err) {
		dev_err(dev, "%s: pio-handle not available\n", __func__);
		return err;
	}

	pio = ofnode_get_by_phandle(phandle);
	if (!ofnode_valid(pio)) {
		dev_err(dev, "%s: unable to find node\n", __func__);
		return -EINVAL;
	}

	/* To Do: find pinctrl device and pass it */
	return par_io_of_config_node(NULL, pio);
}

/*
 * This is not nice!
 * pinsettings should work with "pinctrl-" properties.
 * Unfortunately on mpc83xx powerpc linux device trees
 * devices handle this with "pio-handle" properties ...
 *
 * Even worser, old board code inits all par_io
 * pins in one step, if U-Boot uses the device
 * or not. So init all par_io definitions here too
 * as linux does this also.
 */
static void config_qe_ioports(struct udevice *dev)
{
	ofnode ofn;

	for (ofn = dev_read_first_subnode(dev); ofnode_valid(ofn);
	     ofn = dev_read_next_subnode(ofn)) {
		/*
		 * ignore errors here, as may the subnode
		 * has no pio-handle
		 */
		par_io_of_config_node(dev, ofn);
	}
}

static int par_io_pinctrl_probe(struct udevice *dev)
{
	config_qe_ioports(dev);

	return 0;
}

static int par_io_pinctrl_set_state(struct udevice *dev, struct udevice *config)
{
	return 0;
}

const struct pinctrl_ops par_io_pinctrl_ops = {
	.set_state = par_io_pinctrl_set_state,
};

static const struct udevice_id par_io_pinctrl_match[] = {
	{ .compatible = "fsl,mpc8360-par_io"},
	{ /* sentinel */ }
};

U_BOOT_DRIVER(par_io_pinctrl) = {
	.name = "par-io-pinctrl",
	.id = UCLASS_PINCTRL,
	.of_match = of_match_ptr(par_io_pinctrl_match),
	.probe = par_io_pinctrl_probe,
	.of_to_plat = qe_io_of_to_plat,
	.plat_auto	= sizeof(struct qe_io_plat),
	.ops = &par_io_pinctrl_ops,
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
	.flags	= DM_FLAG_PRE_RELOC,
#endif
};
#endif