]> git.sur5r.net Git - u-boot/blob - drivers/gpio/mpc8xxx_gpio.c
dm: core: Add logging of some common errors
[u-boot] / drivers / gpio / mpc8xxx_gpio.c
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
45 inline u32 gpio_mask(uint gpio)
46 {
47         return (1U << (31 - (gpio)));
48 }
49
50 static inline u32 mpc8xxx_gpio_get_val(struct ccsr_gpio *base, u32 mask)
51 {
52         return in_be32(&base->gpdat) & mask;
53 }
54
55 static inline u32 mpc8xxx_gpio_get_dir(struct ccsr_gpio *base, u32 mask)
56 {
57         return in_be32(&base->gpdir) & mask;
58 }
59
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
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
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
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
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
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
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
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
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
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
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
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
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)
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
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
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 };