]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
f5f69594 MV |
2 | /* |
3 | * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com> | |
f5f69594 MV |
4 | */ |
5 | ||
6 | #include <common.h> | |
7 | #include <clk.h> | |
8 | #include <dm.h> | |
9 | #include <errno.h> | |
10 | #include <asm/gpio.h> | |
11 | #include <asm/io.h> | |
52c8034b | 12 | #include "../pinctrl/renesas/sh_pfc.h" |
f5f69594 MV |
13 | |
14 | #define GPIO_IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ | |
15 | #define GPIO_INOUTSEL 0x04 /* General Input/Output Switching Register */ | |
16 | #define GPIO_OUTDT 0x08 /* General Output Register */ | |
17 | #define GPIO_INDT 0x0c /* General Input Register */ | |
18 | #define GPIO_INTDT 0x10 /* Interrupt Display Register */ | |
19 | #define GPIO_INTCLR 0x14 /* Interrupt Clear Register */ | |
20 | #define GPIO_INTMSK 0x18 /* Interrupt Mask Register */ | |
21 | #define GPIO_MSKCLR 0x1c /* Interrupt Mask Clear Register */ | |
22 | #define GPIO_POSNEG 0x20 /* Positive/Negative Logic Select Register */ | |
23 | #define GPIO_EDGLEVEL 0x24 /* Edge/level Select Register */ | |
24 | #define GPIO_FILONOFF 0x28 /* Chattering Prevention On/Off Register */ | |
25 | #define GPIO_BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ | |
26 | ||
27 | #define RCAR_MAX_GPIO_PER_BANK 32 | |
28 | ||
29 | DECLARE_GLOBAL_DATA_PTR; | |
30 | ||
31 | struct rcar_gpio_priv { | |
52c8034b MV |
32 | void __iomem *regs; |
33 | int pfc_offset; | |
f5f69594 MV |
34 | }; |
35 | ||
36 | static int rcar_gpio_get_value(struct udevice *dev, unsigned offset) | |
37 | { | |
38 | struct rcar_gpio_priv *priv = dev_get_priv(dev); | |
39 | const u32 bit = BIT(offset); | |
40 | ||
41 | /* | |
42 | * Testing on r8a7790 shows that INDT does not show correct pin state | |
43 | * when configured as output, so use OUTDT in case of output pins. | |
44 | */ | |
45 | if (readl(priv->regs + GPIO_INOUTSEL) & bit) | |
46 | return !!(readl(priv->regs + GPIO_OUTDT) & bit); | |
47 | else | |
48 | return !!(readl(priv->regs + GPIO_INDT) & bit); | |
49 | } | |
50 | ||
51 | static int rcar_gpio_set_value(struct udevice *dev, unsigned offset, | |
52 | int value) | |
53 | { | |
54 | struct rcar_gpio_priv *priv = dev_get_priv(dev); | |
55 | ||
56 | if (value) | |
57 | setbits_le32(priv->regs + GPIO_OUTDT, BIT(offset)); | |
58 | else | |
59 | clrbits_le32(priv->regs + GPIO_OUTDT, BIT(offset)); | |
60 | ||
61 | return 0; | |
62 | } | |
63 | ||
64 | static void rcar_gpio_set_direction(void __iomem *regs, unsigned offset, | |
65 | bool output) | |
66 | { | |
67 | /* | |
68 | * follow steps in the GPIO documentation for | |
69 | * "Setting General Output Mode" and | |
70 | * "Setting General Input Mode" | |
71 | */ | |
72 | ||
73 | /* Configure postive logic in POSNEG */ | |
74 | clrbits_le32(regs + GPIO_POSNEG, BIT(offset)); | |
75 | ||
76 | /* Select "General Input/Output Mode" in IOINTSEL */ | |
77 | clrbits_le32(regs + GPIO_IOINTSEL, BIT(offset)); | |
78 | ||
79 | /* Select Input Mode or Output Mode in INOUTSEL */ | |
80 | if (output) | |
81 | setbits_le32(regs + GPIO_INOUTSEL, BIT(offset)); | |
82 | else | |
83 | clrbits_le32(regs + GPIO_INOUTSEL, BIT(offset)); | |
84 | } | |
85 | ||
86 | static int rcar_gpio_direction_input(struct udevice *dev, unsigned offset) | |
87 | { | |
88 | struct rcar_gpio_priv *priv = dev_get_priv(dev); | |
89 | ||
90 | rcar_gpio_set_direction(priv->regs, offset, false); | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | static int rcar_gpio_direction_output(struct udevice *dev, unsigned offset, | |
96 | int value) | |
97 | { | |
98 | struct rcar_gpio_priv *priv = dev_get_priv(dev); | |
99 | ||
100 | /* write GPIO value to output before selecting output mode of pin */ | |
101 | rcar_gpio_set_value(dev, offset, value); | |
102 | rcar_gpio_set_direction(priv->regs, offset, true); | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | static int rcar_gpio_get_function(struct udevice *dev, unsigned offset) | |
108 | { | |
109 | struct rcar_gpio_priv *priv = dev_get_priv(dev); | |
110 | ||
111 | if (readl(priv->regs + GPIO_INOUTSEL) & BIT(offset)) | |
112 | return GPIOF_OUTPUT; | |
113 | else | |
114 | return GPIOF_INPUT; | |
115 | } | |
116 | ||
52c8034b MV |
117 | static int rcar_gpio_request(struct udevice *dev, unsigned offset, |
118 | const char *label) | |
119 | { | |
120 | struct rcar_gpio_priv *priv = dev_get_priv(dev); | |
121 | struct udevice *pctldev; | |
122 | int ret; | |
123 | ||
124 | ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev); | |
125 | if (ret) | |
126 | return ret; | |
127 | ||
128 | return sh_pfc_config_mux_for_gpio(pctldev, priv->pfc_offset + offset); | |
129 | } | |
130 | ||
f5f69594 | 131 | static const struct dm_gpio_ops rcar_gpio_ops = { |
52c8034b | 132 | .request = rcar_gpio_request, |
f5f69594 MV |
133 | .direction_input = rcar_gpio_direction_input, |
134 | .direction_output = rcar_gpio_direction_output, | |
135 | .get_value = rcar_gpio_get_value, | |
136 | .set_value = rcar_gpio_set_value, | |
137 | .get_function = rcar_gpio_get_function, | |
138 | }; | |
139 | ||
140 | static int rcar_gpio_probe(struct udevice *dev) | |
141 | { | |
142 | struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
143 | struct rcar_gpio_priv *priv = dev_get_priv(dev); | |
144 | struct fdtdec_phandle_args args; | |
145 | struct clk clk; | |
146 | int node = dev_of_offset(dev); | |
147 | int ret; | |
148 | ||
149 | priv->regs = (void __iomem *)devfdt_get_addr(dev); | |
150 | uc_priv->bank_name = dev->name; | |
151 | ||
152 | ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges", | |
153 | NULL, 3, 0, &args); | |
52c8034b | 154 | priv->pfc_offset = ret == 0 ? args.args[1] : -1; |
f5f69594 MV |
155 | uc_priv->gpio_count = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; |
156 | ||
157 | ret = clk_get_by_index(dev, 0, &clk); | |
158 | if (ret < 0) { | |
159 | dev_err(dev, "Failed to get GPIO bank clock\n"); | |
160 | return ret; | |
161 | } | |
162 | ||
163 | ret = clk_enable(&clk); | |
164 | clk_free(&clk); | |
165 | if (ret) { | |
166 | dev_err(dev, "Failed to enable GPIO bank clock\n"); | |
167 | return ret; | |
168 | } | |
169 | ||
170 | return 0; | |
171 | } | |
172 | ||
173 | static const struct udevice_id rcar_gpio_ids[] = { | |
174 | { .compatible = "renesas,gpio-r8a7795" }, | |
175 | { .compatible = "renesas,gpio-r8a7796" }, | |
76ed8f05 | 176 | { .compatible = "renesas,gpio-r8a77965" }, |
0f2f0d89 | 177 | { .compatible = "renesas,gpio-r8a77970" }, |
60ae40c2 | 178 | { .compatible = "renesas,gpio-r8a77990" }, |
f122c13b | 179 | { .compatible = "renesas,gpio-r8a77995" }, |
8b05436f | 180 | { .compatible = "renesas,rcar-gen2-gpio" }, |
e3ab4248 | 181 | { .compatible = "renesas,rcar-gen3-gpio" }, |
f5f69594 MV |
182 | { /* sentinel */ } |
183 | }; | |
184 | ||
185 | U_BOOT_DRIVER(rcar_gpio) = { | |
186 | .name = "rcar-gpio", | |
187 | .id = UCLASS_GPIO, | |
188 | .of_match = rcar_gpio_ids, | |
189 | .ops = &rcar_gpio_ops, | |
190 | .priv_auto_alloc_size = sizeof(struct rcar_gpio_priv), | |
191 | .probe = rcar_gpio_probe, | |
192 | }; |