xref: /rk3399_rockchip-uboot/drivers/gpio/sandbox.c (revision e2d8a714a7e6047124581b93d1cfe9c7702cedd4)
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>
7*e2d8a714SSimon Glass #include <dm.h>
8*e2d8a714SSimon Glass #include <fdtdec.h>
9*e2d8a714SSimon Glass #include <malloc.h>
108d30fcd9SSimon Glass #include <asm/gpio.h>
118d30fcd9SSimon Glass 
12*e2d8a714SSimon Glass DECLARE_GLOBAL_DATA_PTR;
13*e2d8a714SSimon 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 */
25*e2d8a714SSimon Glass static u8 *get_gpio_flags(struct device *dev, unsigned offset)
268d30fcd9SSimon Glass {
27*e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
28*e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
29*e2d8a714SSimon Glass 
30*e2d8a714SSimon Glass 	if (offset >= uc_priv->gpio_count) {
318d30fcd9SSimon Glass 		static u8 invalid_flags;
32*e2d8a714SSimon Glass 		printf("sandbox_gpio: error: invalid gpio %u\n", offset);
338d30fcd9SSimon Glass 		return &invalid_flags;
348d30fcd9SSimon Glass 	}
358d30fcd9SSimon Glass 
36*e2d8a714SSimon Glass 	return &state[offset].flags;
378d30fcd9SSimon Glass }
388d30fcd9SSimon Glass 
39*e2d8a714SSimon Glass static int get_gpio_flag(struct device *dev, unsigned offset, int flag)
408d30fcd9SSimon Glass {
41*e2d8a714SSimon Glass 	return (*get_gpio_flags(dev, offset) & flag) != 0;
428d30fcd9SSimon Glass }
438d30fcd9SSimon Glass 
44*e2d8a714SSimon Glass static int set_gpio_flag(struct device *dev, unsigned offset, int flag,
45*e2d8a714SSimon Glass 			 int value)
468d30fcd9SSimon Glass {
47*e2d8a714SSimon 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 
57*e2d8a714SSimon Glass static int check_reserved(struct device *dev, unsigned offset,
58*e2d8a714SSimon Glass 			  const char *func)
598d30fcd9SSimon Glass {
60*e2d8a714SSimon Glass 	if (!get_gpio_flag(dev, offset, GPIOF_RESERVED)) {
61*e2d8a714SSimon Glass 		printf("sandbox_gpio: %s: error: offset %u not reserved\n",
62*e2d8a714SSimon 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 
73*e2d8a714SSimon Glass int sandbox_gpio_get_value(struct device *dev, unsigned offset)
748d30fcd9SSimon Glass {
75*e2d8a714SSimon Glass 	if (get_gpio_flag(dev, offset, GPIOF_OUTPUT))
76*e2d8a714SSimon Glass 		debug("sandbox_gpio: get_value on output gpio %u\n", offset);
77*e2d8a714SSimon Glass 	return get_gpio_flag(dev, offset, GPIOF_HIGH);
788d30fcd9SSimon Glass }
798d30fcd9SSimon Glass 
80*e2d8a714SSimon Glass int sandbox_gpio_set_value(struct device *dev, unsigned offset, int value)
818d30fcd9SSimon Glass {
82*e2d8a714SSimon Glass 	return set_gpio_flag(dev, offset, GPIOF_HIGH, value);
838d30fcd9SSimon Glass }
848d30fcd9SSimon Glass 
85*e2d8a714SSimon Glass int sandbox_gpio_get_direction(struct device *dev, unsigned offset)
868d30fcd9SSimon Glass {
87*e2d8a714SSimon Glass 	return get_gpio_flag(dev, offset, GPIOF_OUTPUT);
888d30fcd9SSimon Glass }
898d30fcd9SSimon Glass 
90*e2d8a714SSimon Glass int sandbox_gpio_set_direction(struct device *dev, unsigned offset, int output)
918d30fcd9SSimon Glass {
92*e2d8a714SSimon 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 
99*e2d8a714SSimon Glass /* set GPIO port 'offset' as an input */
100*e2d8a714SSimon Glass static int sb_gpio_direction_input(struct device *dev, unsigned offset)
1018d30fcd9SSimon Glass {
102*e2d8a714SSimon Glass 	debug("%s: offset:%u\n", __func__, offset);
1038d30fcd9SSimon Glass 
104*e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1058d30fcd9SSimon Glass 		return -1;
1068d30fcd9SSimon Glass 
107*e2d8a714SSimon Glass 	return sandbox_gpio_set_direction(dev, offset, 0);
1088d30fcd9SSimon Glass }
1098d30fcd9SSimon Glass 
110*e2d8a714SSimon Glass /* set GPIO port 'offset' as an output, with polarity 'value' */
111*e2d8a714SSimon Glass static int sb_gpio_direction_output(struct device *dev, unsigned offset,
112*e2d8a714SSimon Glass 				    int value)
1138d30fcd9SSimon Glass {
114*e2d8a714SSimon Glass 	debug("%s: offset:%u, value = %d\n", __func__, offset, value);
1158d30fcd9SSimon Glass 
116*e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1178d30fcd9SSimon Glass 		return -1;
1188d30fcd9SSimon Glass 
119*e2d8a714SSimon Glass 	return sandbox_gpio_set_direction(dev, offset, 1) |
120*e2d8a714SSimon Glass 		sandbox_gpio_set_value(dev, offset, value);
1218d30fcd9SSimon Glass }
1228d30fcd9SSimon Glass 
123*e2d8a714SSimon Glass /* read GPIO IN value of port 'offset' */
124*e2d8a714SSimon Glass static int sb_gpio_get_value(struct device *dev, unsigned offset)
1258d30fcd9SSimon Glass {
126*e2d8a714SSimon Glass 	debug("%s: offset:%u\n", __func__, offset);
1278d30fcd9SSimon Glass 
128*e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1298d30fcd9SSimon Glass 		return -1;
1308d30fcd9SSimon Glass 
131*e2d8a714SSimon Glass 	return sandbox_gpio_get_value(dev, offset);
1328d30fcd9SSimon Glass }
1338d30fcd9SSimon Glass 
134*e2d8a714SSimon Glass /* write GPIO OUT value to port 'offset' */
135*e2d8a714SSimon Glass static int sb_gpio_set_value(struct device *dev, unsigned offset, int value)
1368d30fcd9SSimon Glass {
137*e2d8a714SSimon Glass 	debug("%s: offset:%u, value = %d\n", __func__, offset, value);
1388d30fcd9SSimon Glass 
139*e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1408d30fcd9SSimon Glass 		return -1;
1418d30fcd9SSimon Glass 
142*e2d8a714SSimon Glass 	if (!sandbox_gpio_get_direction(dev, offset)) {
143*e2d8a714SSimon Glass 		printf("sandbox_gpio: error: set_value on input gpio %u\n",
144*e2d8a714SSimon Glass 		       offset);
1458d30fcd9SSimon Glass 		return -1;
1468d30fcd9SSimon Glass 	}
1478d30fcd9SSimon Glass 
148*e2d8a714SSimon Glass 	return sandbox_gpio_set_value(dev, offset, value);
1498d30fcd9SSimon Glass }
1508d30fcd9SSimon Glass 
151*e2d8a714SSimon Glass static int sb_gpio_request(struct device *dev, unsigned offset,
152*e2d8a714SSimon Glass 			   const char *label)
1538d30fcd9SSimon Glass {
154*e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
155*e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
1568d30fcd9SSimon Glass 
157*e2d8a714SSimon Glass 	debug("%s: offset:%u, label:%s\n", __func__, offset, label);
158*e2d8a714SSimon Glass 
159*e2d8a714SSimon Glass 	if (offset >= uc_priv->gpio_count) {
160*e2d8a714SSimon Glass 		printf("sandbox_gpio: error: invalid gpio %u\n", offset);
1618d30fcd9SSimon Glass 		return -1;
1628d30fcd9SSimon Glass 	}
1638d30fcd9SSimon Glass 
164*e2d8a714SSimon Glass 	if (get_gpio_flag(dev, offset, GPIOF_RESERVED)) {
165*e2d8a714SSimon Glass 		printf("sandbox_gpio: error: gpio %u already reserved\n",
166*e2d8a714SSimon Glass 		       offset);
1678d30fcd9SSimon Glass 		return -1;
1688d30fcd9SSimon Glass 	}
1698d30fcd9SSimon Glass 
170*e2d8a714SSimon Glass 	state[offset].label = label;
171*e2d8a714SSimon Glass 	return set_gpio_flag(dev, offset, GPIOF_RESERVED, 1);
1728d30fcd9SSimon Glass }
1738d30fcd9SSimon Glass 
174*e2d8a714SSimon Glass static int sb_gpio_free(struct device *dev, unsigned offset)
1758d30fcd9SSimon Glass {
176*e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
1778d30fcd9SSimon Glass 
178*e2d8a714SSimon Glass 	debug("%s: offset:%u\n", __func__, offset);
179*e2d8a714SSimon Glass 
180*e2d8a714SSimon Glass 	if (check_reserved(dev, offset, __func__))
1818d30fcd9SSimon Glass 		return -1;
1828d30fcd9SSimon Glass 
183*e2d8a714SSimon Glass 	state[offset].label = NULL;
184*e2d8a714SSimon Glass 	return set_gpio_flag(dev, offset, GPIOF_RESERVED, 0);
1858d30fcd9SSimon Glass }
1868d30fcd9SSimon Glass 
187*e2d8a714SSimon Glass static int sb_gpio_get_state(struct device *dev, unsigned int offset,
188*e2d8a714SSimon Glass 			     char *buf, int bufsize)
1898d30fcd9SSimon Glass {
190*e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
191*e2d8a714SSimon Glass 	struct gpio_state *state = dev_get_priv(dev);
192*e2d8a714SSimon Glass 	const char *label;
1938d30fcd9SSimon Glass 
194*e2d8a714SSimon Glass 	label = state[offset].label;
195*e2d8a714SSimon Glass 	snprintf(buf, bufsize, "%s%d: %s: %d [%c]%s%s",
196*e2d8a714SSimon Glass 		 uc_priv->bank_name ? uc_priv->bank_name : "", offset,
197*e2d8a714SSimon Glass 		 sandbox_gpio_get_direction(dev, offset) ? "out" : " in",
198*e2d8a714SSimon Glass 		 sandbox_gpio_get_value(dev, offset),
199*e2d8a714SSimon Glass 		 get_gpio_flag(dev, offset, GPIOF_RESERVED) ? 'x' : ' ',
200*e2d8a714SSimon Glass 		 label ? " " : "",
2018d30fcd9SSimon Glass 		 label ? label : "");
202*e2d8a714SSimon Glass 
203*e2d8a714SSimon Glass 	return 0;
2048d30fcd9SSimon Glass }
205*e2d8a714SSimon Glass 
206*e2d8a714SSimon Glass static const struct dm_gpio_ops gpio_sandbox_ops = {
207*e2d8a714SSimon Glass 	.request		= sb_gpio_request,
208*e2d8a714SSimon Glass 	.free			= sb_gpio_free,
209*e2d8a714SSimon Glass 	.direction_input	= sb_gpio_direction_input,
210*e2d8a714SSimon Glass 	.direction_output	= sb_gpio_direction_output,
211*e2d8a714SSimon Glass 	.get_value		= sb_gpio_get_value,
212*e2d8a714SSimon Glass 	.set_value		= sb_gpio_set_value,
213*e2d8a714SSimon Glass 	.get_state		= sb_gpio_get_state,
214*e2d8a714SSimon Glass };
215*e2d8a714SSimon Glass 
216*e2d8a714SSimon Glass static int sandbox_gpio_ofdata_to_platdata(struct device *dev)
217*e2d8a714SSimon Glass {
218*e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
219*e2d8a714SSimon Glass 
220*e2d8a714SSimon Glass 	uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
221*e2d8a714SSimon Glass 					     "num-gpios", 0);
222*e2d8a714SSimon Glass 	uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset,
223*e2d8a714SSimon Glass 					 "gpio-bank-name", NULL);
224*e2d8a714SSimon Glass 
225*e2d8a714SSimon Glass 	return 0;
2268d30fcd9SSimon Glass }
227*e2d8a714SSimon Glass 
228*e2d8a714SSimon Glass static int gpio_sandbox_probe(struct device *dev)
229*e2d8a714SSimon Glass {
230*e2d8a714SSimon Glass 	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
231*e2d8a714SSimon Glass 
232*e2d8a714SSimon Glass 	if (dev->of_offset == -1) {
233*e2d8a714SSimon Glass 		/* Tell the uclass how many GPIOs we have */
234*e2d8a714SSimon Glass 		uc_priv->gpio_count = CONFIG_SANDBOX_GPIO_COUNT;
235*e2d8a714SSimon Glass 	}
236*e2d8a714SSimon Glass 
237*e2d8a714SSimon Glass 	dev->priv = calloc(sizeof(struct gpio_state), uc_priv->gpio_count);
238*e2d8a714SSimon Glass 
239*e2d8a714SSimon Glass 	return 0;
240*e2d8a714SSimon Glass }
241*e2d8a714SSimon Glass 
242*e2d8a714SSimon Glass static const struct device_id sandbox_gpio_ids[] = {
243*e2d8a714SSimon Glass 	{ .compatible = "sandbox,gpio" },
244*e2d8a714SSimon Glass 	{ }
245*e2d8a714SSimon Glass };
246*e2d8a714SSimon Glass 
247*e2d8a714SSimon Glass U_BOOT_DRIVER(gpio_sandbox) = {
248*e2d8a714SSimon Glass 	.name	= "gpio_sandbox",
249*e2d8a714SSimon Glass 	.id	= UCLASS_GPIO,
250*e2d8a714SSimon Glass 	.of_match = sandbox_gpio_ids,
251*e2d8a714SSimon Glass 	.ofdata_to_platdata = sandbox_gpio_ofdata_to_platdata,
252*e2d8a714SSimon Glass 	.probe	= gpio_sandbox_probe,
253*e2d8a714SSimon Glass 	.ops	= &gpio_sandbox_ops,
254*e2d8a714SSimon Glass };
255