xref: /openbmc/u-boot/drivers/gpio/altera_pio.c (revision ae485b54)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015  Thomas Chou <thomas@wytron.com.tw>
4  * Copyright (C) 2011  Missing Link Electronics
5  *                     Joachim Foerster <joachim@missinglinkelectronics.com>
6  */
7 #include <common.h>
8 #include <dm.h>
9 #include <errno.h>
10 #include <malloc.h>
11 #include <fdtdec.h>
12 #include <asm/io.h>
13 #include <asm/gpio.h>
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 struct altera_pio_regs {
18 	u32	data;			/* Data register */
19 	u32	direction;		/* Direction register */
20 };
21 
22 struct altera_pio_platdata {
23 	struct altera_pio_regs *regs;
24 	int gpio_count;
25 	const char *bank_name;
26 };
27 
28 static int altera_pio_direction_input(struct udevice *dev, unsigned pin)
29 {
30 	struct altera_pio_platdata *plat = dev_get_platdata(dev);
31 	struct altera_pio_regs *const regs = plat->regs;
32 
33 	clrbits_le32(&regs->direction, 1 << pin);
34 
35 	return 0;
36 }
37 
38 static int altera_pio_direction_output(struct udevice *dev, unsigned pin,
39 				     int val)
40 {
41 	struct altera_pio_platdata *plat = dev_get_platdata(dev);
42 	struct altera_pio_regs *const regs = plat->regs;
43 
44 	if (val)
45 		setbits_le32(&regs->data, 1 << pin);
46 	else
47 		clrbits_le32(&regs->data, 1 << pin);
48 	/* change the data first, then the direction. to avoid glitch */
49 	setbits_le32(&regs->direction, 1 << pin);
50 
51 	return 0;
52 }
53 
54 static int altera_pio_get_value(struct udevice *dev, unsigned pin)
55 {
56 	struct altera_pio_platdata *plat = dev_get_platdata(dev);
57 	struct altera_pio_regs *const regs = plat->regs;
58 
59 	return readl(&regs->data) & (1 << pin);
60 }
61 
62 
63 static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val)
64 {
65 	struct altera_pio_platdata *plat = dev_get_platdata(dev);
66 	struct altera_pio_regs *const regs = plat->regs;
67 
68 	if (val)
69 		setbits_le32(&regs->data, 1 << pin);
70 	else
71 		clrbits_le32(&regs->data, 1 << pin);
72 
73 	return 0;
74 }
75 
76 static int altera_pio_probe(struct udevice *dev)
77 {
78 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
79 	struct altera_pio_platdata *plat = dev_get_platdata(dev);
80 
81 	uc_priv->gpio_count = plat->gpio_count;
82 	uc_priv->bank_name = plat->bank_name;
83 
84 	return 0;
85 }
86 
87 static int altera_pio_ofdata_to_platdata(struct udevice *dev)
88 {
89 	struct altera_pio_platdata *plat = dev_get_platdata(dev);
90 
91 	plat->regs = map_physmem(devfdt_get_addr(dev),
92 				 sizeof(struct altera_pio_regs),
93 				 MAP_NOCACHE);
94 	plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
95 		"altr,gpio-bank-width", 32);
96 	plat->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
97 		"gpio-bank-name", NULL);
98 
99 	return 0;
100 }
101 
102 static const struct dm_gpio_ops altera_pio_ops = {
103 	.direction_input	= altera_pio_direction_input,
104 	.direction_output	= altera_pio_direction_output,
105 	.get_value		= altera_pio_get_value,
106 	.set_value		= altera_pio_set_value,
107 };
108 
109 static const struct udevice_id altera_pio_ids[] = {
110 	{ .compatible = "altr,pio-1.0" },
111 	{ }
112 };
113 
114 U_BOOT_DRIVER(altera_pio) = {
115 	.name		= "altera_pio",
116 	.id		= UCLASS_GPIO,
117 	.of_match	= altera_pio_ids,
118 	.ops		= &altera_pio_ops,
119 	.ofdata_to_platdata = altera_pio_ofdata_to_platdata,
120 	.platdata_auto_alloc_size = sizeof(struct altera_pio_platdata),
121 	.probe		= altera_pio_probe,
122 };
123