]> git.sur5r.net Git - u-boot/blob - drivers/gpio/mpc8xxx_gpio.c
Merge git://git.denx.de/u-boot-rockchip
[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 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 };