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