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