blob: c273c2c8a40d0866bc7d56f9d3f7087ad64c3b6e [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +02002/*
3 * (C) Copyright 2016
Mario Sixb4893582018-03-06 08:04:58 +01004 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +02005 *
6 * based on arch/powerpc/include/asm/mpc85xx_gpio.h, which is
7 *
8 * Copyright 2010 eXMeritus, A Boeing Company
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +02009 */
10
11#include <common.h>
12#include <dm.h>
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020013#include <mapmem.h>
Mario Sixd7c6f712018-01-15 11:07:49 +010014#include <asm/gpio.h>
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020015
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020016struct ccsr_gpio {
17 u32 gpdir;
18 u32 gpodr;
19 u32 gpdat;
20 u32 gpier;
21 u32 gpimr;
22 u32 gpicr;
23};
24
Mario Sixd006f682018-01-15 11:07:48 +010025struct mpc8xxx_gpio_data {
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020026 /* 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
Mario Sixcc94b172018-01-15 11:07:46 +010034 * for output pins
35 */
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020036 u32 dat_shadow;
Mario Sixd7c6f712018-01-15 11:07:49 +010037 ulong type;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020038};
39
Mario Sixd7c6f712018-01-15 11:07:49 +010040enum {
41 MPC8XXX_GPIO_TYPE,
42 MPC5121_GPIO_TYPE,
43};
44
Mario Sixcc94b172018-01-15 11:07:46 +010045inline u32 gpio_mask(uint gpio)
46{
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020047 return (1U << (31 - (gpio)));
48}
49
Mario Sixd006f682018-01-15 11:07:48 +010050static inline u32 mpc8xxx_gpio_get_val(struct ccsr_gpio *base, u32 mask)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020051{
52 return in_be32(&base->gpdat) & mask;
53}
54
Mario Sixd006f682018-01-15 11:07:48 +010055static inline u32 mpc8xxx_gpio_get_dir(struct ccsr_gpio *base, u32 mask)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020056{
57 return in_be32(&base->gpdir) & mask;
58}
59
Mario Sixd006f682018-01-15 11:07:48 +010060static inline void mpc8xxx_gpio_set_in(struct ccsr_gpio *base, u32 gpios)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020061{
62 clrbits_be32(&base->gpdat, gpios);
63 /* GPDIR register 0 -> input */
64 clrbits_be32(&base->gpdir, gpios);
65}
66
Mario Sixd006f682018-01-15 11:07:48 +010067static inline void mpc8xxx_gpio_set_low(struct ccsr_gpio *base, u32 gpios)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020068{
69 clrbits_be32(&base->gpdat, gpios);
70 /* GPDIR register 1 -> output */
71 setbits_be32(&base->gpdir, gpios);
72}
73
Mario Sixd006f682018-01-15 11:07:48 +010074static inline void mpc8xxx_gpio_set_high(struct ccsr_gpio *base, u32 gpios)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +020075{
76 setbits_be32(&base->gpdat, gpios);
77 /* GPDIR register 1 -> output */
78 setbits_be32(&base->gpdir, gpios);
79}
80
Mario Sixd006f682018-01-15 11:07:48 +010081static inline int mpc8xxx_gpio_open_drain_val(struct ccsr_gpio *base, u32 mask)
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020082{
83 return in_be32(&base->gpodr) & mask;
84}
85
Mario Sixd006f682018-01-15 11:07:48 +010086static inline void mpc8xxx_gpio_open_drain_on(struct ccsr_gpio *base, u32
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020087 gpios)
88{
89 /* GPODR register 1 -> open drain on */
90 setbits_be32(&base->gpodr, gpios);
91}
92
Mario Sixd006f682018-01-15 11:07:48 +010093static inline void mpc8xxx_gpio_open_drain_off(struct ccsr_gpio *base,
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +020094 u32 gpios)
95{
96 /* GPODR register 0 -> open drain off (actively driven) */
97 clrbits_be32(&base->gpodr, gpios);
98}
99
Mario Sixd006f682018-01-15 11:07:48 +0100100static int mpc8xxx_gpio_direction_input(struct udevice *dev, uint gpio)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200101{
Mario Sixd006f682018-01-15 11:07:48 +0100102 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200103
Mario Sixd006f682018-01-15 11:07:48 +0100104 mpc8xxx_gpio_set_in(data->base, gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200105 return 0;
106}
107
Mario Sixd006f682018-01-15 11:07:48 +0100108static int mpc8xxx_gpio_set_value(struct udevice *dev, uint gpio, int value)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200109{
Mario Sixd006f682018-01-15 11:07:48 +0100110 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200111
112 if (value) {
113 data->dat_shadow |= gpio_mask(gpio);
Mario Sixd006f682018-01-15 11:07:48 +0100114 mpc8xxx_gpio_set_high(data->base, gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200115 } else {
116 data->dat_shadow &= ~gpio_mask(gpio);
Mario Sixd006f682018-01-15 11:07:48 +0100117 mpc8xxx_gpio_set_low(data->base, gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200118 }
119 return 0;
120}
121
Mario Sixd006f682018-01-15 11:07:48 +0100122static int mpc8xxx_gpio_direction_output(struct udevice *dev, uint gpio,
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200123 int value)
124{
Mario Sixd7c6f712018-01-15 11:07:49 +0100125 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
Mario Sixd006f682018-01-15 11:07:48 +0100131 return mpc8xxx_gpio_set_value(dev, gpio, value);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200132}
133
Mario Sixd006f682018-01-15 11:07:48 +0100134static int mpc8xxx_gpio_get_value(struct udevice *dev, uint gpio)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200135{
Mario Sixd006f682018-01-15 11:07:48 +0100136 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200137
Mario Sixd006f682018-01-15 11:07:48 +0100138 if (!!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio))) {
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200139 /* Output -> use shadowed value */
140 return !!(data->dat_shadow & gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200141 }
Mario Sixcc94b172018-01-15 11:07:46 +0100142
143 /* Input -> read value from GPDAT register */
Mario Sixd006f682018-01-15 11:07:48 +0100144 return !!mpc8xxx_gpio_get_val(data->base, gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200145}
146
Mario Sixd006f682018-01-15 11:07:48 +0100147static int mpc8xxx_gpio_get_open_drain(struct udevice *dev, uint gpio)
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +0200148{
Mario Sixd006f682018-01-15 11:07:48 +0100149 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +0200150
Mario Sixd006f682018-01-15 11:07:48 +0100151 return !!mpc8xxx_gpio_open_drain_val(data->base, gpio_mask(gpio));
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +0200152}
153
Mario Sixd006f682018-01-15 11:07:48 +0100154static int mpc8xxx_gpio_set_open_drain(struct udevice *dev, uint gpio,
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +0200155 int value)
156{
Mario Sixd006f682018-01-15 11:07:48 +0100157 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +0200158
Mario Sixcc94b172018-01-15 11:07:46 +0100159 if (value)
Mario Sixd006f682018-01-15 11:07:48 +0100160 mpc8xxx_gpio_open_drain_on(data->base, gpio_mask(gpio));
Mario Sixcc94b172018-01-15 11:07:46 +0100161 else
Mario Sixd006f682018-01-15 11:07:48 +0100162 mpc8xxx_gpio_open_drain_off(data->base, gpio_mask(gpio));
Mario Sixcc94b172018-01-15 11:07:46 +0100163
mario.six@gdsys.cc7b4cf8b2016-05-25 15:15:22 +0200164 return 0;
165}
166
Mario Sixd006f682018-01-15 11:07:48 +0100167static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200168{
Mario Sixd006f682018-01-15 11:07:48 +0100169 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200170 int dir;
171
Mario Sixd006f682018-01-15 11:07:48 +0100172 dir = !!mpc8xxx_gpio_get_dir(data->base, gpio_mask(gpio));
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200173 return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
174}
175
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200176#if CONFIG_IS_ENABLED(OF_CONTROL)
Mario Sixd006f682018-01-15 11:07:48 +0100177static int mpc8xxx_gpio_ofdata_to_platdata(struct udevice *dev)
Mario Sixcc94b172018-01-15 11:07:46 +0100178{
Mario Sixd006f682018-01-15 11:07:48 +0100179 struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200180 fdt_addr_t addr;
Mario Sixf99b6bf2018-01-15 11:07:50 +0100181 u32 reg[2];
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200182
Mario Sixf99b6bf2018-01-15 11:07:50 +0100183 dev_read_u32_array(dev, "reg", reg, 2);
184 addr = dev_translate_address(dev, reg);
185
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200186 plat->addr = addr;
Mario Sixf99b6bf2018-01-15 11:07:50 +0100187 plat->size = reg[1];
188 plat->ngpios = dev_read_u32_default(dev, "ngpios", 32);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200189
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200190 return 0;
191}
192#endif
193
Mario Sixd006f682018-01-15 11:07:48 +0100194static int mpc8xxx_gpio_platdata_to_priv(struct udevice *dev)
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200195{
Mario Sixd006f682018-01-15 11:07:48 +0100196 struct mpc8xxx_gpio_data *priv = dev_get_priv(dev);
197 struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200198 unsigned long size = plat->size;
Mario Sixd7c6f712018-01-15 11:07:49 +0100199 ulong driver_data = dev_get_driver_data(dev);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200200
201 if (size == 0)
202 size = 0x100;
203
204 priv->addr = plat->addr;
Mario Sixf99b6bf2018-01-15 11:07:50 +0100205 priv->base = map_sysmem(plat->addr, size);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200206
207 if (!priv->base)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200208 return -ENOMEM;
209
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200210 priv->gpio_count = plat->ngpios;
211 priv->dat_shadow = 0;
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200212
Mario Sixd006f682018-01-15 11:07:48 +0100213 priv->type = driver_data;
214
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200215 return 0;
216}
217
Mario Sixd006f682018-01-15 11:07:48 +0100218static int mpc8xxx_gpio_probe(struct udevice *dev)
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200219{
220 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
Mario Sixd006f682018-01-15 11:07:48 +0100221 struct mpc8xxx_gpio_data *data = dev_get_priv(dev);
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200222 char name[32], *str;
223
Mario Sixd006f682018-01-15 11:07:48 +0100224 mpc8xxx_gpio_platdata_to_priv(dev);
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200225
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200226 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
Mario Sixd006f682018-01-15 11:07:48 +0100238static 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,
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200246};
247
Mario Sixd006f682018-01-15 11:07:48 +0100248static const struct udevice_id mpc8xxx_gpio_ids[] = {
Mario Sixd7c6f712018-01-15 11:07:49 +0100249 { .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 },
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200256 { /* sentinel */ }
257};
258
Mario Sixd006f682018-01-15 11:07:48 +0100259U_BOOT_DRIVER(gpio_mpc8xxx) = {
260 .name = "gpio_mpc8xxx",
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200261 .id = UCLASS_GPIO,
Mario Sixd006f682018-01-15 11:07:48 +0100262 .ops = &gpio_mpc8xxx_ops,
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200263#if CONFIG_IS_ENABLED(OF_CONTROL)
Mario Sixd006f682018-01-15 11:07:48 +0100264 .ofdata_to_platdata = mpc8xxx_gpio_ofdata_to_platdata,
265 .platdata_auto_alloc_size = sizeof(struct mpc8xxx_gpio_plat),
266 .of_match = mpc8xxx_gpio_ids,
Hamish Martin47ca9fc2016-06-14 10:17:05 +1200267#endif
Mario Sixd006f682018-01-15 11:07:48 +0100268 .probe = mpc8xxx_gpio_probe,
269 .priv_auto_alloc_size = sizeof(struct mpc8xxx_gpio_data),
mario.six@gdsys.cc5b59a352016-05-25 15:15:20 +0200270};