1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2016
4  * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5  *
6  * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
7  *
8  * Copyright 2010 eXMeritus, A Boeing Company
9  */
10 
11 #include <common.h>
12 #include <dm.h>
13 #include <mapmem.h>
14 #include <asm/gpio.h>
15 
16 struct ccsr_gpio {
17 	u32	gpdir;
18 	u32	gpodr;
19 	u32	gpdat;
20 	u32	gpier;
21 	u32	gpimr;
22 	u32	gpicr;
23 };
24 
25 struct mpc8xxx_gpio_data {
26 	/* The bank's register base in memory */
27 	struct ccsr_gpio __iomem *base;
28 	/* The address of the registers; used to identify the bank */
29 	ulong addr;
30 	/* The GPIO count of the bank */
31 	uint gpio_count;
32 	/* The GPDAT register cannot be used to determine the value of output
33 	 * pins on MPC8572/MPC8536, so we shadow it and use the shadowed value
34 	 * for output pins
35 	 */
36 	u32 dat_shadow;
37 	ulong type;
38 };
39 
40 enum {
41 	MPC8XXX_GPIO_TYPE,
42 	MPC5121_GPIO_TYPE,
43 };
44 
gpio_mask(uint gpio)45 inline u32 gpio_mask(uint gpio)
46 {
47 	return (1U << (31 - (gpio)));
48 }
49 
mpc8xxx_gpio_get_val(struct ccsr_gpio * base,u32 mask)50 static inline u32 mpc8xxx_gpio_get_val(struct ccsr_gpio *base, u32 mask)
51 {
52 	return in_be32(&base->gpdat) & mask;
53 }
54 
mpc8xxx_gpio_get_dir(struct ccsr_gpio * base,u32 mask)55 static inline u32 mpc8xxx_gpio_get_dir(struct ccsr_gpio *base, u32 mask)
56 {
57 	return in_be32(&base->gpdir) & mask;
58 }
59 
mpc8xxx_gpio_set_in(struct ccsr_gpio * base,u32 gpios)60 static inline void mpc8xxx_gpio_set_in(struct ccsr_gpio *base, u32 gpios)
61 {
62 	clrbits_be32(&base->gpdat, gpios);
63 	/* GPDIR register 0 -> input */
64 	clrbits_be32(&base->gpdir, gpios);
65 }
66 
mpc8xxx_gpio_set_low(struct ccsr_gpio * base,u32 gpios)67 static inline void mpc8xxx_gpio_set_low(struct ccsr_gpio *base, u32 gpios)
68 {
69 	clrbits_be32(&base->gpdat, gpios);
70 	/* GPDIR register 1 -> output */
71 	setbits_be32(&base->gpdir, gpios);
72 }
73 
mpc8xxx_gpio_set_high(struct ccsr_gpio * base,u32 gpios)74 static inline void mpc8xxx_gpio_set_high(struct ccsr_gpio *base, u32 gpios)
75 {
76 	setbits_be32(&base->gpdat, gpios);
77 	/* GPDIR register 1 -> output */
78 	setbits_be32(&base->gpdir, gpios);
79 }
80 
mpc8xxx_gpio_open_drain_val(struct ccsr_gpio * base,u32 mask)81 static inline int mpc8xxx_gpio_open_drain_val(struct ccsr_gpio *base, u32 mask)
82 {
83 	return in_be32(&base->gpodr) & mask;
84 }
85 
mpc8xxx_gpio_open_drain_on(struct ccsr_gpio * base,u32 gpios)86 static inline void mpc8xxx_gpio_open_drain_on(struct ccsr_gpio *base, u32
87 					      gpios)
88 {
89 	/* GPODR register 1 -> open drain on */
90 	setbits_be32(&base->gpodr, gpios);
91 }
92 
mpc8xxx_gpio_open_drain_off(struct ccsr_gpio * base,u32 gpios)93 static inline void mpc8xxx_gpio_open_drain_off(struct ccsr_gpio *base,
94 					       u32 gpios)
95 {
96 	/* GPODR register 0 -> open drain off (actively driven) */
97 	clrbits_be32(&base->gpodr, gpios);
98 }
99 
mpc8xxx_gpio_direction_input(struct udevice * dev,uint gpio)100 static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio)
101 {
102 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
103 
104 	mpc8xxx_gpio_set_in(data->base, gpio_mask(gpio));
105 	return 0;
106 }
107 
mpc8xxx_gpio_set_value(struct udevice * dev,uint gpio,int value)108 static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value)
109 {
110 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
111 
112 	if (value) {
113 		data->dat_shadow |= gpio_mask(gpio);
114 		mpc8xxx_gpio_set_high(data->base, gpio_mask(gpio));
115 	} else {
116 		data->dat_shadow &= ~gpio_mask(gpio);
117 		mpc8xxx_gpio_set_low(data->base, gpio_mask(gpio));
118 	}
119 	return 0;
120 }
121 
mpc8xxx_gpio_direction_output(struct udevice * dev,uint gpio,int value)122 static int mpc8xxx_gpio_direction_output(struct udevice *dev, uint gpio,
123 					 int value)
124 {
125 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
126 
127 	/* GPIO 28..31 are input only on MPC5121 */
128 	if (data->type == MPC5121_GPIO_TYPE && gpio >= 28)
129 		return -EINVAL;
130 
131 	return mpc8xxx_gpio_set_value(dev, gpio, value);
132 }
133 
mpc8xxx_gpio_get_value(struct udevice * dev,uint gpio)134 static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)
135 {
136 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
137 
138 	if (!!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio))) {
139 		/* Output -> use shadowed value */
140 		return !!(data->dat_shadow & gpio_mask(gpio));
141 	}
142 
143 	/* Input -> read value from GPDAT register */
144 	return !!mpc8xxx_gpio_get_val(data->base, gpio_mask(gpio));
145 }
146 
mpc8xxx_gpio_get_open_drain(struct udevice * dev,uint gpio)147 static int mpc8xxx_gpio_get_open_drain(struct udevice *dev, uint gpio)
148 {
149 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
150 
151 	return !!mpc8xxx_gpio_open_drain_val(data->base, gpio_mask(gpio));
152 }
153 
mpc8xxx_gpio_set_open_drain(struct udevice * dev,uint gpio,int value)154 static int mpc8xxx_gpio_set_open_drain(struct udevice *dev, uint gpio,
155 				       int value)
156 {
157 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
158 
159 	if (value)
160 		mpc8xxx_gpio_open_drain_on(data->base, gpio_mask(gpio));
161 	else
162 		mpc8xxx_gpio_open_drain_off(data->base, gpio_mask(gpio));
163 
164 	return 0;
165 }
166 
mpc8xxx_gpio_get_function(struct udevice * dev,uint gpio)167 static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)
168 {
169 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
170 	int dir;
171 
172 	dir = !!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio));
173 	return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
174 }
175 
176 #if CONFIG_IS_ENABLED(OF_CONTROL)
mpc8xxx_gpio_ofdata_to_platdata(struct udevice * dev)177 static int mpc8xxx_gpio_ofdata_to_platdata(struct udevice *dev)
178 {
179 	struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev);
180 	fdt_addr_t addr;
181 	u32 reg[2];
182 
183 	dev_read_u32_array(dev, "reg", reg, 2);
184 	addr = dev_translate_address(dev, reg);
185 
186 	plat->addr = addr;
187 	plat->size = reg[1];
188 	plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);
189 
190 	return 0;
191 }
192 #endif
193 
mpc8xxx_gpio_platdata_to_priv(struct udevice * dev)194 static int mpc8xxx_gpio_platdata_to_priv(struct udevice *dev)
195 {
196 	struct mpc8xxx_gpio_data *priv = dev_get_priv(dev);
197 	struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev);
198 	unsigned long size = plat->size;
199 	ulong driver_data = dev_get_driver_data(dev);
200 
201 	if (size == 0)
202 		size = 0x100;
203 
204 	priv->addr = plat->addr;
205 	priv->base = map_sysmem(plat->addr, size);
206 
207 	if (!priv->base)
208 		return -ENOMEM;
209 
210 	priv->gpio_count = plat->ngpios;
211 	priv->dat_shadow = 0;
212 
213 	priv->type = driver_data;
214 
215 	return 0;
216 }
217 
mpc8xxx_gpio_probe(struct udevice * dev)218 static int mpc8xxx_gpio_probe(struct udevice *dev)
219 {
220 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
221 	struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
222 	char name[32], *str;
223 
224 	mpc8xxx_gpio_platdata_to_priv(dev);
225 
226 	snprintf(name, sizeof(name), "MPC@%lx_", data->addr);
227 	str = strdup(name);
228 
229 	if (!str)
230 		return -ENOMEM;
231 
232 	uc_priv->bank_name = str;
233 	uc_priv->gpio_count = data->gpio_count;
234 
235 	return 0;
236 }
237 
238 static const struct dm_gpio_ops gpio_mpc8xxx_ops = {
239 	.direction_input	= mpc8xxx_gpio_direction_input,
240 	.direction_output	= mpc8xxx_gpio_direction_output,
241 	.get_value		= mpc8xxx_gpio_get_value,
242 	.set_value		= mpc8xxx_gpio_set_value,
243 	.get_open_drain		= mpc8xxx_gpio_get_open_drain,
244 	.set_open_drain		= mpc8xxx_gpio_set_open_drain,
245 	.get_function		= mpc8xxx_gpio_get_function,
246 };
247 
248 static const struct udevice_id mpc8xxx_gpio_ids[] = {
249 	{ .compatible = "fsl,pq3-gpio", .data = MPC8XXX_GPIO_TYPE },
250 	{ .compatible = "fsl,mpc8308-gpio", .data = MPC8XXX_GPIO_TYPE },
251 	{ .compatible = "fsl,mpc8349-gpio", .data = MPC8XXX_GPIO_TYPE },
252 	{ .compatible = "fsl,mpc8572-gpio", .data = MPC8XXX_GPIO_TYPE},
253 	{ .compatible = "fsl,mpc8610-gpio", .data = MPC8XXX_GPIO_TYPE},
254 	{ .compatible = "fsl,mpc5121-gpio", .data = MPC5121_GPIO_TYPE, },
255 	{ .compatible = "fsl,qoriq-gpio", .data = MPC8XXX_GPIO_TYPE },
256 	{ /* sentinel */ }
257 };
258 
259 U_BOOT_DRIVER(gpio_mpc8xxx) = {
260 	.name	= "gpio_mpc8xxx",
261 	.id	= UCLASS_GPIO,
262 	.ops	= &gpio_mpc8xxx_ops,
263 #if CONFIG_IS_ENABLED(OF_CONTROL)
264 	.ofdata_to_platdata = mpc8xxx_gpio_ofdata_to_platdata,
265 	.platdata_auto_alloc_size = sizeof(struct mpc8xxx_gpio_plat),
266 	.of_match = mpc8xxx_gpio_ids,
267 #endif
268 	.probe	= mpc8xxx_gpio_probe,
269 	.priv_auto_alloc_size = sizeof(struct mpc8xxx_gpio_data),
270 };
271