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