xref: /rk3399_rockchip-uboot/drivers/gpio/sandbox.c (revision 699ea9606ca8e4227c8be607197733d348cd12c4)
18d30fcd9SSimon Glass /*
28d30fcd9SSimon Glass  * Copyright (c) 2011 The Chromium OS Authors.
31a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
48d30fcd9SSimon Glass  */
58d30fcd9SSimon Glass 
68d30fcd9SSimon Glass #include <common.h>
7e2d8a714SSimon Glass #include <dm.h>
8e2d8a714SSimon Glass #include <fdtdec.h>
9e2d8a714SSimon Glass #include <malloc.h>
108d30fcd9SSimon Glass #include <asm/gpio.h>
118d30fcd9SSimon Glass 
12e2d8a714SSimon Glass DECLARE_GLOBAL_DATA_PTR;
13e2d8a714SSimon Glass 
148d30fcd9SSimon Glass /* Flags for each GPIO */
158d30fcd9SSimon Glass #define GPIOF_OUTPUT	(1 << 0)	/* Currently set as an output */
168d30fcd9SSimon Glass #define GPIOF_HIGH	(1 << 1)	/* Currently set high */
178d30fcd9SSimon Glass #define GPIOF_RESERVED	(1 << 2)	/* Is in use / requested */
188d30fcd9SSimon Glass 
198d30fcd9SSimon Glass struct gpio_state {
208d30fcd9SSimon Glass 	const char *label;	/* label given by requester */
218d30fcd9SSimon Glass 	u8 flags;		/* flags (GPIOF_...) */
228d30fcd9SSimon Glass };
238d30fcd9SSimon Glass 
248d30fcd9SSimon Glass /* Access routines for GPIO state */
2554c5d08aSHeiko Schocher static u8 *get_gpio_flags(struct udevice *dev, unsigned offset)
268d30fcd9SSimon Glass {
27e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
28e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
29e2d8a714SSimon Glass 
30e2d8a714SSimon Glass 	if (offset >= uc_priv->gpio_count) {
318d30fcd9SSimon Glass 		static u8 invalid_flags;
32e2d8a714SSimon Glass 		printf("sandbox_gpio: error: invalid gpio %u\n", offset);
338d30fcd9SSimon Glass 		return &invalid_flags;
348d30fcd9SSimon Glass 	}
358d30fcd9SSimon Glass 
36e2d8a714SSimon Glass 	return &state[offset].flags;
378d30fcd9SSimon Glass }
388d30fcd9SSimon Glass 
3954c5d08aSHeiko Schocher static int get_gpio_flag(struct udevice *dev, unsigned offset, int flag)
408d30fcd9SSimon Glass {
41e2d8a714SSimon Glass 	return (*get_gpio_flags(dev, offset) & flag) != 0;
428d30fcd9SSimon Glass }
438d30fcd9SSimon Glass 
4454c5d08aSHeiko Schocher static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag,
45e2d8a714SSimon Glass 			 int value)
468d30fcd9SSimon Glass {
47e2d8a714SSimon Glass 	u8 *gpio = get_gpio_flags(dev, offset);
488d30fcd9SSimon Glass 
498d30fcd9SSimon Glass 	if (value)
508d30fcd9SSimon Glass 		*gpio |= flag;
518d30fcd9SSimon Glass 	else
528d30fcd9SSimon Glass 		*gpio &= ~flag;
538d30fcd9SSimon Glass 
548d30fcd9SSimon Glass 	return 0;
558d30fcd9SSimon Glass }
568d30fcd9SSimon Glass 
5754c5d08aSHeiko Schocher static int check_reserved(struct udevice *dev, unsigned offset,
58e2d8a714SSimon Glass 			  const char *func)
598d30fcd9SSimon Glass {
60e2d8a714SSimon Glass 	if (!get_gpio_flag(dev, offset, GPIOF_RESERVED)) {
61e2d8a714SSimon Glass 		printf("sandbox_gpio: %s: error: offset %u not reserved\n",
62e2d8a714SSimon Glass 		       func, offset);
638d30fcd9SSimon Glass 		return -1;
648d30fcd9SSimon Glass 	}
658d30fcd9SSimon Glass 
668d30fcd9SSimon Glass 	return 0;
678d30fcd9SSimon Glass }
688d30fcd9SSimon Glass 
698d30fcd9SSimon Glass /*
708d30fcd9SSimon Glass  * Back-channel sandbox-internal-only access to GPIO state
718d30fcd9SSimon Glass  */
728d30fcd9SSimon Glass 
7354c5d08aSHeiko Schocher int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
748d30fcd9SSimon Glass {
75e2d8a714SSimon Glass 	if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
76e2d8a714SSimon Glass 		debug("sandbox_gpio: get_value on output gpio %u\n", offset);
77e2d8a714SSimon Glass 	return get_gpio_flag(dev, offset, GPIOF_HIGH);
788d30fcd9SSimon Glass }
798d30fcd9SSimon Glass 
8054c5d08aSHeiko Schocher int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
818d30fcd9SSimon Glass {
82e2d8a714SSimon Glass 	return set_gpio_flag(dev, offset, GPIOF_HIGH, value);
838d30fcd9SSimon Glass }
848d30fcd9SSimon Glass 
8554c5d08aSHeiko Schocher int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
868d30fcd9SSimon Glass {
87e2d8a714SSimon Glass 	return get_gpio_flag(dev, offset, GPIOF_OUTPUT);
888d30fcd9SSimon Glass }
898d30fcd9SSimon Glass 
9054c5d08aSHeiko Schocher int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
918d30fcd9SSimon Glass {
92e2d8a714SSimon Glass 	return set_gpio_flag(dev, offset, GPIOF_OUTPUT, output);
938d30fcd9SSimon Glass }
948d30fcd9SSimon Glass 
958d30fcd9SSimon Glass /*
968d30fcd9SSimon Glass  * These functions implement the public interface within U-Boot
978d30fcd9SSimon Glass  */
988d30fcd9SSimon Glass 
99e2d8a714SSimon Glass /* set GPIO port 'offset' as an input */
10054c5d08aSHeiko Schocher static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
1018d30fcd9SSimon Glass {
102e2d8a714SSimon Glass 	debug("%s: offset:%u\n", __func__, offset);
1038d30fcd9SSimon Glass 
104e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1058d30fcd9SSimon Glass 		return -1;
1068d30fcd9SSimon Glass 
107e2d8a714SSimon Glass 	return sandbox_gpio_set_direction(dev, offset, 0);
1088d30fcd9SSimon Glass }
1098d30fcd9SSimon Glass 
110e2d8a714SSimon Glass /* set GPIO port 'offset' as an output, with polarity 'value' */
11154c5d08aSHeiko Schocher static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
112e2d8a714SSimon Glass 				    int value)
1138d30fcd9SSimon Glass {
114e2d8a714SSimon Glass 	debug("%s: offset:%u, value = %d\n", __func__, offset, value);
1158d30fcd9SSimon Glass 
116e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1178d30fcd9SSimon Glass 		return -1;
1188d30fcd9SSimon Glass 
119e2d8a714SSimon Glass 	return sandbox_gpio_set_direction(dev, offset, 1) |
120e2d8a714SSimon Glass 		sandbox_gpio_set_value(dev, offset, value);
1218d30fcd9SSimon Glass }
1228d30fcd9SSimon Glass 
123e2d8a714SSimon Glass /* read GPIO IN value of port 'offset' */
12454c5d08aSHeiko Schocher static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
1258d30fcd9SSimon Glass {
126e2d8a714SSimon Glass 	debug("%s: offset:%u\n", __func__, offset);
1278d30fcd9SSimon Glass 
128e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1298d30fcd9SSimon Glass 		return -1;
1308d30fcd9SSimon Glass 
131e2d8a714SSimon Glass 	return sandbox_gpio_get_value(dev, offset);
1328d30fcd9SSimon Glass }
1338d30fcd9SSimon Glass 
134e2d8a714SSimon Glass /* write GPIO OUT value to port 'offset' */
13554c5d08aSHeiko Schocher static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
1368d30fcd9SSimon Glass {
137e2d8a714SSimon Glass 	debug("%s: offset:%u, value = %d\n", __func__, offset, value);
1388d30fcd9SSimon Glass 
139e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1408d30fcd9SSimon Glass 		return -1;
1418d30fcd9SSimon Glass 
142e2d8a714SSimon Glass 	if (!sandbox_gpio_get_direction(dev, offset)) {
143e2d8a714SSimon Glass 		printf("sandbox_gpio: error: set_value on input gpio %u\n",
144e2d8a714SSimon Glass 		       offset);
1458d30fcd9SSimon Glass 		return -1;
1468d30fcd9SSimon Glass 	}
1478d30fcd9SSimon Glass 
148e2d8a714SSimon Glass 	return sandbox_gpio_set_value(dev, offset, value);
1498d30fcd9SSimon Glass }
1508d30fcd9SSimon Glass 
15154c5d08aSHeiko Schocher static int sb_gpio_request(struct udevice *dev, unsigned offset,
152e2d8a714SSimon Glass 			   const char *label)
1538d30fcd9SSimon Glass {
154e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
155e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
1568d30fcd9SSimon Glass 
157e2d8a714SSimon Glass 	debug("%s: offset:%u, label:%s\n", __func__, offset, label);
158e2d8a714SSimon Glass 
159e2d8a714SSimon Glass 	if (offset >= uc_priv->gpio_count) {
160e2d8a714SSimon Glass 		printf("sandbox_gpio: error: invalid gpio %u\n", offset);
1618d30fcd9SSimon Glass 		return -1;
1628d30fcd9SSimon Glass 	}
1638d30fcd9SSimon Glass 
164e2d8a714SSimon Glass 	if (get_gpio_flag(dev, offset, GPIOF_RESERVED)) {
165e2d8a714SSimon Glass 		printf("sandbox_gpio: error: gpio %u already reserved\n",
166e2d8a714SSimon Glass 		       offset);
1678d30fcd9SSimon Glass 		return -1;
1688d30fcd9SSimon Glass 	}
1698d30fcd9SSimon Glass 
170e2d8a714SSimon Glass 	state[offset].label = label;
171e2d8a714SSimon Glass 	return set_gpio_flag(dev, offset, GPIOF_RESERVED, 1);
1728d30fcd9SSimon Glass }
1738d30fcd9SSimon Glass 
17454c5d08aSHeiko Schocher static int sb_gpio_free(struct udevice *dev, unsigned offset)
1758d30fcd9SSimon Glass {
176e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
1778d30fcd9SSimon Glass 
178e2d8a714SSimon Glass 	debug("%s: offset:%u\n", __func__, offset);
179e2d8a714SSimon Glass 
180e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1818d30fcd9SSimon Glass 		return -1;
1828d30fcd9SSimon Glass 
183e2d8a714SSimon Glass 	state[offset].label = NULL;
184e2d8a714SSimon Glass 	return set_gpio_flag(dev, offset, GPIOF_RESERVED, 0);
1858d30fcd9SSimon Glass }
1868d30fcd9SSimon Glass 
18754c5d08aSHeiko Schocher static int sb_gpio_get_state(struct udevice *dev, unsigned int offset,
188e2d8a714SSimon Glass 			     char *buf, int bufsize)
1898d30fcd9SSimon Glass {
190e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
191e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
192e2d8a714SSimon Glass 	const char *label;
1938d30fcd9SSimon Glass 
194e2d8a714SSimon Glass 	label = state[offset].label;
195e2d8a714SSimon Glass 	snprintf(buf, bufsize, "%s%d: %s: %d [%c]%s%s",
196e2d8a714SSimon Glass 		 uc_priv->bank_name ? uc_priv->bank_name : "", offset,
197e2d8a714SSimon Glass 		 sandbox_gpio_get_direction(dev, offset) ? "out" : " in",
198e2d8a714SSimon Glass 		 sandbox_gpio_get_value(dev, offset),
199e2d8a714SSimon Glass 		 get_gpio_flag(dev, offset, GPIOF_RESERVED) ? 'x' : ' ',
200e2d8a714SSimon Glass 		 label ? " " : "",
2018d30fcd9SSimon Glass 		 label ? label : "");
202e2d8a714SSimon Glass 
203e2d8a714SSimon Glass 	return 0;
2048d30fcd9SSimon Glass }
205e2d8a714SSimon Glass 
206*699ea960SSimon Glass static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
207*699ea960SSimon Glass {
208*699ea960SSimon Glass 	if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
209*699ea960SSimon Glass 		return GPIOF_OUTPUT;
210*699ea960SSimon Glass 	return GPIOF_INPUT;
211*699ea960SSimon Glass }
212*699ea960SSimon Glass 
213e2d8a714SSimon Glass static const struct dm_gpio_ops gpio_sandbox_ops = {
214e2d8a714SSimon Glass 	.request		= sb_gpio_request,
215e2d8a714SSimon Glass 	.free			= sb_gpio_free,
216e2d8a714SSimon Glass 	.direction_input	= sb_gpio_direction_input,
217e2d8a714SSimon Glass 	.direction_output	= sb_gpio_direction_output,
218e2d8a714SSimon Glass 	.get_value		= sb_gpio_get_value,
219e2d8a714SSimon Glass 	.set_value		= sb_gpio_set_value,
220*699ea960SSimon Glass 	.get_function		= sb_gpio_get_function,
221e2d8a714SSimon Glass };
222e2d8a714SSimon Glass 
22354c5d08aSHeiko Schocher static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
224e2d8a714SSimon Glass {
225e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
226e2d8a714SSimon Glass 
227e2d8a714SSimon Glass 	uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
228e2d8a714SSimon Glass 					     "num-gpios", 0);
229e2d8a714SSimon Glass 	uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset,
230e2d8a714SSimon Glass 					 "gpio-bank-name", NULL);
231e2d8a714SSimon Glass 
232e2d8a714SSimon Glass 	return 0;
2338d30fcd9SSimon Glass }
234e2d8a714SSimon Glass 
23554c5d08aSHeiko Schocher static int gpio_sandbox_probe(struct udevice *dev)
236e2d8a714SSimon Glass {
237e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
238e2d8a714SSimon Glass 
239e2d8a714SSimon Glass 	if (dev->of_offset == -1) {
240e2d8a714SSimon Glass 		/* Tell the uclass how many GPIOs we have */
241e2d8a714SSimon Glass 		uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
242e2d8a714SSimon Glass 	}
243e2d8a714SSimon Glass 
244e2d8a714SSimon Glass 	dev->priv = calloc(sizeof(struct gpio_state), uc_priv->gpio_count);
245e2d8a714SSimon Glass 
246e2d8a714SSimon Glass 	return 0;
247e2d8a714SSimon Glass }
248e2d8a714SSimon Glass 
249ae7f4513SSimon Glass static const struct udevice_id sandbox_gpio_ids[] = {
250e2d8a714SSimon Glass 	{ .compatible = "sandbox,gpio" },
251e2d8a714SSimon Glass 	{ }
252e2d8a714SSimon Glass };
253e2d8a714SSimon Glass 
254e2d8a714SSimon Glass U_BOOT_DRIVER(gpio_sandbox) = {
255e2d8a714SSimon Glass 	.name	= "gpio_sandbox",
256e2d8a714SSimon Glass 	.id	= UCLASS_GPIO,
257e2d8a714SSimon Glass 	.of_match = sandbox_gpio_ids,
258e2d8a714SSimon Glass 	.ofdata_to_platdata = sandbox_gpio_ofdata_to_platdata,
259e2d8a714SSimon Glass 	.probe	= gpio_sandbox_probe,
260e2d8a714SSimon Glass 	.ops	= &gpio_sandbox_ops,
261e2d8a714SSimon Glass };
262