1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2011 The Chromium OS Authors.
3*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <common.h>
7*4882a593Smuzhiyun #include <dm.h>
8*4882a593Smuzhiyun #include <fdtdec.h>
9*4882a593Smuzhiyun #include <malloc.h>
10*4882a593Smuzhiyun #include <asm/gpio.h>
11*4882a593Smuzhiyun #include <dm/of.h>
12*4882a593Smuzhiyun #include <dt-bindings/gpio/gpio.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun /* Flags for each GPIO */
17*4882a593Smuzhiyun #define GPIOF_OUTPUT (1 << 0) /* Currently set as an output */
18*4882a593Smuzhiyun #define GPIOF_HIGH (1 << 1) /* Currently set high */
19*4882a593Smuzhiyun #define GPIOF_ODR (1 << 2) /* Currently set to open drain mode */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun struct gpio_state {
22*4882a593Smuzhiyun const char *label; /* label given by requester */
23*4882a593Smuzhiyun u8 flags; /* flags (GPIOF_...) */
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* Access routines for GPIO state */
get_gpio_flags(struct udevice * dev,unsigned offset)27*4882a593Smuzhiyun static u8 *get_gpio_flags(struct udevice *dev, unsigned offset)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
30*4882a593Smuzhiyun struct gpio_state *state = dev_get_priv(dev);
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun if (offset >= uc_priv->gpio_count) {
33*4882a593Smuzhiyun static u8 invalid_flags;
34*4882a593Smuzhiyun printf("sandbox_gpio: error: invalid gpio %u\n", offset);
35*4882a593Smuzhiyun return &invalid_flags;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun return &state[offset].flags;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
get_gpio_flag(struct udevice * dev,unsigned offset,int flag)41*4882a593Smuzhiyun static int get_gpio_flag(struct udevice *dev, unsigned offset, int flag)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun return (*get_gpio_flags(dev, offset) & flag) != 0;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
set_gpio_flag(struct udevice * dev,unsigned offset,int flag,int value)46*4882a593Smuzhiyun static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag,
47*4882a593Smuzhiyun int value)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun u8 *gpio = get_gpio_flags(dev, offset);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (value)
52*4882a593Smuzhiyun *gpio |= flag;
53*4882a593Smuzhiyun else
54*4882a593Smuzhiyun *gpio &= ~flag;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return 0;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /*
60*4882a593Smuzhiyun * Back-channel sandbox-internal-only access to GPIO state
61*4882a593Smuzhiyun */
62*4882a593Smuzhiyun
sandbox_gpio_get_value(struct udevice * dev,unsigned offset)63*4882a593Smuzhiyun int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
66*4882a593Smuzhiyun debug("sandbox_gpio: get_value on output gpio %u\n", offset);
67*4882a593Smuzhiyun return get_gpio_flag(dev, offset, GPIOF_HIGH);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
sandbox_gpio_set_value(struct udevice * dev,unsigned offset,int value)70*4882a593Smuzhiyun int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun return set_gpio_flag(dev, offset, GPIOF_HIGH, value);
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
sandbox_gpio_get_open_drain(struct udevice * dev,unsigned offset)75*4882a593Smuzhiyun int sandbox_gpio_get_open_drain(struct udevice *dev, unsigned offset)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun return get_gpio_flag(dev, offset, GPIOF_ODR);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
sandbox_gpio_set_open_drain(struct udevice * dev,unsigned offset,int value)80*4882a593Smuzhiyun int sandbox_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun return set_gpio_flag(dev, offset, GPIOF_ODR, value);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
sandbox_gpio_get_direction(struct udevice * dev,unsigned offset)85*4882a593Smuzhiyun int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun return get_gpio_flag(dev, offset, GPIOF_OUTPUT);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
sandbox_gpio_set_direction(struct udevice * dev,unsigned offset,int output)90*4882a593Smuzhiyun int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun return set_gpio_flag(dev, offset, GPIOF_OUTPUT, output);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /*
96*4882a593Smuzhiyun * These functions implement the public interface within U-Boot
97*4882a593Smuzhiyun */
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* set GPIO port 'offset' as an input */
sb_gpio_direction_input(struct udevice * dev,unsigned offset)100*4882a593Smuzhiyun static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun debug("%s: offset:%u\n", __func__, offset);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun return sandbox_gpio_set_direction(dev, offset, 0);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun /* set GPIO port 'offset' as an output, with polarity 'value' */
sb_gpio_direction_output(struct udevice * dev,unsigned offset,int value)108*4882a593Smuzhiyun static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
109*4882a593Smuzhiyun int value)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun debug("%s: offset:%u, value = %d\n", __func__, offset, value);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun return sandbox_gpio_set_direction(dev, offset, 1) |
114*4882a593Smuzhiyun sandbox_gpio_set_value(dev, offset, value);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* read GPIO IN value of port 'offset' */
sb_gpio_get_value(struct udevice * dev,unsigned offset)118*4882a593Smuzhiyun static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun debug("%s: offset:%u\n", __func__, offset);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun return sandbox_gpio_get_value(dev, offset);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* write GPIO OUT value to port 'offset' */
sb_gpio_set_value(struct udevice * dev,unsigned offset,int value)126*4882a593Smuzhiyun static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun debug("%s: offset:%u, value = %d\n", __func__, offset, value);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun if (!sandbox_gpio_get_direction(dev, offset)) {
131*4882a593Smuzhiyun printf("sandbox_gpio: error: set_value on input gpio %u\n",
132*4882a593Smuzhiyun offset);
133*4882a593Smuzhiyun return -1;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun return sandbox_gpio_set_value(dev, offset, value);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* read GPIO ODR value of port 'offset' */
sb_gpio_get_open_drain(struct udevice * dev,unsigned offset)140*4882a593Smuzhiyun static int sb_gpio_get_open_drain(struct udevice *dev, unsigned offset)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun debug("%s: offset:%u\n", __func__, offset);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun return sandbox_gpio_get_open_drain(dev, offset);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun /* write GPIO ODR value to port 'offset' */
sb_gpio_set_open_drain(struct udevice * dev,unsigned offset,int value)148*4882a593Smuzhiyun static int sb_gpio_set_open_drain(struct udevice *dev, unsigned offset, int value)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun debug("%s: offset:%u, value = %d\n", __func__, offset, value);
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (!sandbox_gpio_get_direction(dev, offset)) {
153*4882a593Smuzhiyun printf("sandbox_gpio: error: set_open_drain on input gpio %u\n",
154*4882a593Smuzhiyun offset);
155*4882a593Smuzhiyun return -1;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return sandbox_gpio_set_open_drain(dev, offset, value);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
sb_gpio_get_function(struct udevice * dev,unsigned offset)161*4882a593Smuzhiyun static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
164*4882a593Smuzhiyun return GPIOF_OUTPUT;
165*4882a593Smuzhiyun return GPIOF_INPUT;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
sb_gpio_xlate(struct udevice * dev,struct gpio_desc * desc,struct ofnode_phandle_args * args)168*4882a593Smuzhiyun static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
169*4882a593Smuzhiyun struct ofnode_phandle_args *args)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun desc->offset = args->args[0];
172*4882a593Smuzhiyun if (args->args_count < 2)
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun if (args->args[1] & GPIO_ACTIVE_LOW)
175*4882a593Smuzhiyun desc->flags |= GPIOD_ACTIVE_LOW;
176*4882a593Smuzhiyun if (args->args[1] & 2)
177*4882a593Smuzhiyun desc->flags |= GPIOD_IS_IN;
178*4882a593Smuzhiyun if (args->args[1] & 4)
179*4882a593Smuzhiyun desc->flags |= GPIOD_IS_OUT;
180*4882a593Smuzhiyun if (args->args[1] & 8)
181*4882a593Smuzhiyun desc->flags |= GPIOD_IS_OUT_ACTIVE;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun return 0;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun static const struct dm_gpio_ops gpio_sandbox_ops = {
187*4882a593Smuzhiyun .direction_input = sb_gpio_direction_input,
188*4882a593Smuzhiyun .direction_output = sb_gpio_direction_output,
189*4882a593Smuzhiyun .get_value = sb_gpio_get_value,
190*4882a593Smuzhiyun .set_value = sb_gpio_set_value,
191*4882a593Smuzhiyun .get_open_drain = sb_gpio_get_open_drain,
192*4882a593Smuzhiyun .set_open_drain = sb_gpio_set_open_drain,
193*4882a593Smuzhiyun .get_function = sb_gpio_get_function,
194*4882a593Smuzhiyun .xlate = sb_gpio_xlate,
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun
sandbox_gpio_ofdata_to_platdata(struct udevice * dev)197*4882a593Smuzhiyun static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun uc_priv->gpio_count = dev_read_u32_default(dev, "num-gpios", 0);
202*4882a593Smuzhiyun uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name");
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun return 0;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
gpio_sandbox_probe(struct udevice * dev)207*4882a593Smuzhiyun static int gpio_sandbox_probe(struct udevice *dev)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (!dev_of_valid(dev))
212*4882a593Smuzhiyun /* Tell the uclass how many GPIOs we have */
213*4882a593Smuzhiyun uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun dev->priv = calloc(sizeof(struct gpio_state), uc_priv->gpio_count);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
gpio_sandbox_remove(struct udevice * dev)220*4882a593Smuzhiyun static int gpio_sandbox_remove(struct udevice *dev)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun free(dev->priv);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun return 0;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun static const struct udevice_id sandbox_gpio_ids[] = {
228*4882a593Smuzhiyun { .compatible = "sandbox,gpio" },
229*4882a593Smuzhiyun { }
230*4882a593Smuzhiyun };
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun U_BOOT_DRIVER(gpio_sandbox) = {
233*4882a593Smuzhiyun .name = "gpio_sandbox",
234*4882a593Smuzhiyun .id = UCLASS_GPIO,
235*4882a593Smuzhiyun .of_match = sandbox_gpio_ids,
236*4882a593Smuzhiyun .ofdata_to_platdata = sandbox_gpio_ofdata_to_platdata,
237*4882a593Smuzhiyun .probe = gpio_sandbox_probe,
238*4882a593Smuzhiyun .remove = gpio_sandbox_remove,
239*4882a593Smuzhiyun .ops = &gpio_sandbox_ops,
240*4882a593Smuzhiyun };
241