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