1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2016 Freescale Semiconductor, Inc.
4  *
5  * RGPIO2P driver for the Freescale i.MX7ULP.
6  */
7 
8 #include <common.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <fdtdec.h>
12 #include <asm/gpio.h>
13 #include <asm/io.h>
14 #include <dm/device-internal.h>
15 #include <malloc.h>
16 
17 enum imx_rgpio2p_direction {
18 	IMX_RGPIO2P_DIRECTION_IN,
19 	IMX_RGPIO2P_DIRECTION_OUT,
20 };
21 
22 #define GPIO_PER_BANK			32
23 
24 struct imx_rgpio2p_data {
25 	struct gpio_regs *regs;
26 };
27 
28 struct imx_rgpio2p_plat {
29 	int bank_index;
30 	struct gpio_regs *regs;
31 };
32 
imx_rgpio2p_is_output(struct gpio_regs * regs,int offset)33 static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset)
34 {
35 	u32 val;
36 
37 	val = readl(&regs->gpio_pddr);
38 
39 	return val & (1 << offset) ? 1 : 0;
40 }
41 
imx_rgpio2p_bank_get_direction(struct gpio_regs * regs,int offset)42 static int imx_rgpio2p_bank_get_direction(struct gpio_regs *regs, int offset)
43 {
44 	if ((readl(&regs->gpio_pddr) >> offset) & 0x01)
45 		return IMX_RGPIO2P_DIRECTION_OUT;
46 
47 	return IMX_RGPIO2P_DIRECTION_IN;
48 }
49 
imx_rgpio2p_bank_direction(struct gpio_regs * regs,int offset,enum imx_rgpio2p_direction direction)50 static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset,
51 				    enum imx_rgpio2p_direction direction)
52 {
53 	u32 l;
54 
55 	l = readl(&regs->gpio_pddr);
56 
57 	switch (direction) {
58 	case IMX_RGPIO2P_DIRECTION_OUT:
59 		l |= 1 << offset;
60 		break;
61 	case IMX_RGPIO2P_DIRECTION_IN:
62 		l &= ~(1 << offset);
63 	}
64 	writel(l, &regs->gpio_pddr);
65 }
66 
imx_rgpio2p_bank_set_value(struct gpio_regs * regs,int offset,int value)67 static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset,
68 				    int value)
69 {
70 	if (value)
71 		writel((1 << offset), &regs->gpio_psor);
72 	else
73 		writel((1 << offset), &regs->gpio_pcor);
74 }
75 
imx_rgpio2p_bank_get_value(struct gpio_regs * regs,int offset)76 static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset)
77 {
78 	if (imx_rgpio2p_bank_get_direction(regs, offset) ==
79 	    IMX_RGPIO2P_DIRECTION_IN)
80 		return (readl(&regs->gpio_pdir) >> offset) & 0x01;
81 
82 	return (readl(&regs->gpio_pdor) >> offset) & 0x01;
83 }
84 
imx_rgpio2p_direction_input(struct udevice * dev,unsigned offset)85 static int  imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset)
86 {
87 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
88 
89 	/* Configure GPIO direction as input. */
90 	imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN);
91 
92 	return 0;
93 }
94 
imx_rgpio2p_direction_output(struct udevice * dev,unsigned offset,int value)95 static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset,
96 				       int value)
97 {
98 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
99 
100 	/* Configure GPIO output value. */
101 	imx_rgpio2p_bank_set_value(bank->regs, offset, value);
102 
103 	/* Configure GPIO direction as output. */
104 	imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT);
105 
106 	return 0;
107 }
108 
imx_rgpio2p_get_value(struct udevice * dev,unsigned offset)109 static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset)
110 {
111 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
112 
113 	return imx_rgpio2p_bank_get_value(bank->regs, offset);
114 }
115 
imx_rgpio2p_set_value(struct udevice * dev,unsigned offset,int value)116 static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset,
117 				 int value)
118 {
119 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
120 
121 	imx_rgpio2p_bank_set_value(bank->regs, offset, value);
122 
123 	return 0;
124 }
125 
imx_rgpio2p_get_function(struct udevice * dev,unsigned offset)126 static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset)
127 {
128 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
129 
130 	/* GPIOF_FUNC is not implemented yet */
131 	if (imx_rgpio2p_is_output(bank->regs, offset))
132 		return GPIOF_OUTPUT;
133 	else
134 		return GPIOF_INPUT;
135 }
136 
137 static const struct dm_gpio_ops imx_rgpio2p_ops = {
138 	.direction_input	= imx_rgpio2p_direction_input,
139 	.direction_output	= imx_rgpio2p_direction_output,
140 	.get_value		= imx_rgpio2p_get_value,
141 	.set_value		= imx_rgpio2p_set_value,
142 	.get_function		= imx_rgpio2p_get_function,
143 };
144 
imx_rgpio2p_probe(struct udevice * dev)145 static int imx_rgpio2p_probe(struct udevice *dev)
146 {
147 	struct imx_rgpio2p_data *bank = dev_get_priv(dev);
148 	struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
149 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
150 	int banknum;
151 	char name[18], *str;
152 
153 	banknum = plat->bank_index;
154 	sprintf(name, "GPIO%d_", banknum + 1);
155 	str = strdup(name);
156 	if (!str)
157 		return -ENOMEM;
158 	uc_priv->bank_name = str;
159 	uc_priv->gpio_count = GPIO_PER_BANK;
160 	bank->regs = plat->regs;
161 
162 	return 0;
163 }
164 
imx_rgpio2p_bind(struct udevice * dev)165 static int imx_rgpio2p_bind(struct udevice *dev)
166 {
167 	struct imx_rgpio2p_plat *plat = dev_get_plat(dev);
168 	fdt_addr_t addr;
169 
170 	/*
171 	 * If plat already exsits, directly return.
172 	 * Actually only when DT is not supported, plat
173 	 * is statically initialized in U_BOOT_DRVINFOS.Here
174 	 * will return.
175 	 */
176 	if (plat)
177 		return 0;
178 
179 	addr = devfdt_get_addr_index(dev, 1);
180 	if (addr == FDT_ADDR_T_NONE)
181 		return -EINVAL;
182 
183 	/*
184 	 * TODO:
185 	 * When every board is converted to driver model and DT is supported,
186 	 * this can be done by auto-alloc feature, but not using calloc
187 	 * to alloc memory for plat.
188 	 *
189 	 * For example imx_rgpio2p_plat uses platform data rather than device
190 	 * tree.
191 	 *
192 	 * NOTE: DO NOT COPY this code if you are using device tree.
193 	 */
194 	plat = calloc(1, sizeof(*plat));
195 	if (!plat)
196 		return -ENOMEM;
197 
198 	plat->regs = (struct gpio_regs *)addr;
199 	plat->bank_index = dev_seq(dev);
200 	dev_set_plat(dev, plat);
201 
202 	return 0;
203 }
204 
205 
206 static const struct udevice_id imx_rgpio2p_ids[] = {
207 	{ .compatible = "fsl,imx7ulp-gpio" },
208 	{ }
209 };
210 
211 U_BOOT_DRIVER(imx_rgpio2p) = {
212 	.name	= "imx_rgpio2p",
213 	.id	= UCLASS_GPIO,
214 	.ops	= &imx_rgpio2p_ops,
215 	.probe	= imx_rgpio2p_probe,
216 	.priv_auto	= sizeof(struct imx_rgpio2p_plat),
217 	.of_match = imx_rgpio2p_ids,
218 	.bind	= imx_rgpio2p_bind,
219 };
220 
221 #if !CONFIG_IS_ENABLED(OF_CONTROL)
222 static const struct imx_rgpio2p_plat imx_plat[] = {
223 	{ 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR },
224 	{ 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR },
225 	{ 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR },
226 	{ 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR },
227 	{ 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR },
228 	{ 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR },
229 };
230 
231 U_BOOT_DRVINFOS(imx_rgpio2ps) = {
232 	{ "imx_rgpio2p", &imx_plat[0] },
233 	{ "imx_rgpio2p", &imx_plat[1] },
234 	{ "imx_rgpio2p", &imx_plat[2] },
235 	{ "imx_rgpio2p", &imx_plat[3] },
236 	{ "imx_rgpio2p", &imx_plat[4] },
237 	{ "imx_rgpio2p", &imx_plat[5] },
238 };
239 #endif
240