diff options
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/Kconfig | 5 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos.c | 477 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos.h | 170 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos5440.c | 919 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 207 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.h | 30 |
7 files changed, 1408 insertions, 401 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 390ab69ea569..c31aeb01bb00 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -190,6 +190,11 @@ config PINCTRL_EXYNOS4 | |||
190 | depends on OF && GPIOLIB | 190 | depends on OF && GPIOLIB |
191 | select PINCTRL_SAMSUNG | 191 | select PINCTRL_SAMSUNG |
192 | 192 | ||
193 | config PINCTRL_EXYNOS5440 | ||
194 | bool "Samsung EXYNOS5440 SoC pinctrl driver" | ||
195 | select PINMUX | ||
196 | select PINCONF | ||
197 | |||
193 | source "drivers/pinctrl/mvebu/Kconfig" | 198 | source "drivers/pinctrl/mvebu/Kconfig" |
194 | 199 | ||
195 | source "drivers/pinctrl/spear/Kconfig" | 200 | source "drivers/pinctrl/spear/Kconfig" |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f95f5ed923be..fc4606f27dc7 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -37,6 +37,7 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o | |||
37 | obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o | 37 | obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o |
38 | obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o | 38 | obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o |
39 | obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o | 39 | obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o |
40 | obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o | ||
40 | obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o | 41 | obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o |
41 | obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o | 42 | obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o |
42 | 43 | ||
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 6ff665209a4c..538b9ddaadf7 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c | |||
@@ -41,46 +41,46 @@ static const struct of_device_id exynos_wkup_irq_ids[] = { | |||
41 | 41 | ||
42 | static void exynos_gpio_irq_unmask(struct irq_data *irqd) | 42 | static void exynos_gpio_irq_unmask(struct irq_data *irqd) |
43 | { | 43 | { |
44 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | 44 | struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); |
45 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | 45 | struct samsung_pinctrl_drv_data *d = bank->drvdata; |
46 | unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; | 46 | unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; |
47 | unsigned long mask; | 47 | unsigned long mask; |
48 | 48 | ||
49 | mask = readl(d->virt_base + reg_mask); | 49 | mask = readl(d->virt_base + reg_mask); |
50 | mask &= ~(1 << edata->pin); | 50 | mask &= ~(1 << irqd->hwirq); |
51 | writel(mask, d->virt_base + reg_mask); | 51 | writel(mask, d->virt_base + reg_mask); |
52 | } | 52 | } |
53 | 53 | ||
54 | static void exynos_gpio_irq_mask(struct irq_data *irqd) | 54 | static void exynos_gpio_irq_mask(struct irq_data *irqd) |
55 | { | 55 | { |
56 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | 56 | struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); |
57 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | 57 | struct samsung_pinctrl_drv_data *d = bank->drvdata; |
58 | unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; | 58 | unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset; |
59 | unsigned long mask; | 59 | unsigned long mask; |
60 | 60 | ||
61 | mask = readl(d->virt_base + reg_mask); | 61 | mask = readl(d->virt_base + reg_mask); |
62 | mask |= 1 << edata->pin; | 62 | mask |= 1 << irqd->hwirq; |
63 | writel(mask, d->virt_base + reg_mask); | 63 | writel(mask, d->virt_base + reg_mask); |
64 | } | 64 | } |
65 | 65 | ||
66 | static void exynos_gpio_irq_ack(struct irq_data *irqd) | 66 | static void exynos_gpio_irq_ack(struct irq_data *irqd) |
67 | { | 67 | { |
68 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | 68 | struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); |
69 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | 69 | struct samsung_pinctrl_drv_data *d = bank->drvdata; |
70 | unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; | 70 | unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset; |
71 | 71 | ||
72 | writel(1 << edata->pin, d->virt_base + reg_pend); | 72 | writel(1 << irqd->hwirq, d->virt_base + reg_pend); |
73 | } | 73 | } |
74 | 74 | ||
75 | static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) | 75 | static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) |
76 | { | 76 | { |
77 | struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; | 77 | struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); |
78 | struct samsung_pinctrl_drv_data *d = bank->drvdata; | ||
78 | struct samsung_pin_ctrl *ctrl = d->ctrl; | 79 | struct samsung_pin_ctrl *ctrl = d->ctrl; |
79 | struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); | 80 | unsigned int pin = irqd->hwirq; |
80 | struct samsung_pin_bank *bank = edata->bank; | 81 | unsigned int shift = EXYNOS_EINT_CON_LEN * pin; |
81 | unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin; | ||
82 | unsigned int con, trig_type; | 82 | unsigned int con, trig_type; |
83 | unsigned long reg_con = ctrl->geint_con + edata->eint_offset; | 83 | unsigned long reg_con = ctrl->geint_con + bank->eint_offset; |
84 | unsigned int mask; | 84 | unsigned int mask; |
85 | 85 | ||
86 | switch (type) { | 86 | switch (type) { |
@@ -115,7 +115,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) | |||
115 | writel(con, d->virt_base + reg_con); | 115 | writel(con, d->virt_base + reg_con); |
116 | 116 | ||
117 | reg_con = bank->pctl_offset; | 117 | reg_con = bank->pctl_offset; |
118 | shift = edata->pin * bank->func_width; | 118 | shift = pin * bank->func_width; |
119 | mask = (1 << bank->func_width) - 1; | 119 | mask = (1 << bank->func_width) - 1; |
120 | 120 | ||
121 | con = readl(d->virt_base + reg_con); | 121 | con = readl(d->virt_base + reg_con); |
@@ -137,82 +137,23 @@ static struct irq_chip exynos_gpio_irq_chip = { | |||
137 | .irq_set_type = exynos_gpio_irq_set_type, | 137 | .irq_set_type = exynos_gpio_irq_set_type, |
138 | }; | 138 | }; |
139 | 139 | ||
140 | /* | ||
141 | * given a controller-local external gpio interrupt number, prepare the handler | ||
142 | * data for it. | ||
143 | */ | ||
144 | static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw, | ||
145 | struct samsung_pinctrl_drv_data *d) | ||
146 | { | ||
147 | struct samsung_pin_bank *bank = d->ctrl->pin_banks; | ||
148 | struct exynos_geint_data *eint_data; | ||
149 | unsigned int nr_banks = d->ctrl->nr_banks, idx; | ||
150 | unsigned int irq_base = 0, eint_offset = 0; | ||
151 | |||
152 | if (hw >= d->ctrl->nr_gint) { | ||
153 | dev_err(d->dev, "unsupported ext-gpio interrupt\n"); | ||
154 | return NULL; | ||
155 | } | ||
156 | |||
157 | for (idx = 0; idx < nr_banks; idx++, bank++) { | ||
158 | if (bank->eint_type != EINT_TYPE_GPIO) | ||
159 | continue; | ||
160 | if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins))) | ||
161 | break; | ||
162 | irq_base += bank->nr_pins; | ||
163 | eint_offset += 4; | ||
164 | } | ||
165 | |||
166 | if (idx == nr_banks) { | ||
167 | dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n"); | ||
168 | return NULL; | ||
169 | } | ||
170 | |||
171 | eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL); | ||
172 | if (!eint_data) { | ||
173 | dev_err(d->dev, "no memory for eint-gpio data\n"); | ||
174 | return NULL; | ||
175 | } | ||
176 | |||
177 | eint_data->bank = bank; | ||
178 | eint_data->pin = hw - irq_base; | ||
179 | eint_data->eint_offset = eint_offset; | ||
180 | return eint_data; | ||
181 | } | ||
182 | |||
183 | static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, | 140 | static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, |
184 | irq_hw_number_t hw) | 141 | irq_hw_number_t hw) |
185 | { | 142 | { |
186 | struct samsung_pinctrl_drv_data *d = h->host_data; | 143 | struct samsung_pin_bank *b = h->host_data; |
187 | struct exynos_geint_data *eint_data; | ||
188 | |||
189 | eint_data = exynos_get_eint_data(hw, d); | ||
190 | if (!eint_data) | ||
191 | return -EINVAL; | ||
192 | 144 | ||
193 | irq_set_handler_data(virq, eint_data); | 145 | irq_set_chip_data(virq, b); |
194 | irq_set_chip_data(virq, h->host_data); | ||
195 | irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, | 146 | irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, |
196 | handle_level_irq); | 147 | handle_level_irq); |
197 | set_irq_flags(virq, IRQF_VALID); | 148 | set_irq_flags(virq, IRQF_VALID); |
198 | return 0; | 149 | return 0; |
199 | } | 150 | } |
200 | 151 | ||
201 | static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq) | ||
202 | { | ||
203 | struct samsung_pinctrl_drv_data *d = h->host_data; | ||
204 | struct exynos_geint_data *eint_data; | ||
205 | |||
206 | eint_data = irq_get_handler_data(virq); | ||
207 | devm_kfree(d->dev, eint_data); | ||
208 | } | ||
209 | |||
210 | /* | 152 | /* |
211 | * irq domain callbacks for external gpio interrupt controller. | 153 | * irq domain callbacks for external gpio interrupt controller. |
212 | */ | 154 | */ |
213 | static const struct irq_domain_ops exynos_gpio_irqd_ops = { | 155 | static const struct irq_domain_ops exynos_gpio_irqd_ops = { |
214 | .map = exynos_gpio_irq_map, | 156 | .map = exynos_gpio_irq_map, |
215 | .unmap = exynos_gpio_irq_unmap, | ||
216 | .xlate = irq_domain_xlate_twocell, | 157 | .xlate = irq_domain_xlate_twocell, |
217 | }; | 158 | }; |
218 | 159 | ||
@@ -231,7 +172,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) | |||
231 | return IRQ_HANDLED; | 172 | return IRQ_HANDLED; |
232 | bank += (group - 1); | 173 | bank += (group - 1); |
233 | 174 | ||
234 | virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); | 175 | virq = irq_linear_revmap(bank->irq_domain, pin); |
235 | if (!virq) | 176 | if (!virq) |
236 | return IRQ_NONE; | 177 | return IRQ_NONE; |
237 | generic_handle_irq(virq); | 178 | generic_handle_irq(virq); |
@@ -244,8 +185,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) | |||
244 | */ | 185 | */ |
245 | static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) | 186 | static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) |
246 | { | 187 | { |
188 | struct samsung_pin_bank *bank; | ||
247 | struct device *dev = d->dev; | 189 | struct device *dev = d->dev; |
248 | unsigned int ret; | 190 | unsigned int ret; |
191 | unsigned int i; | ||
249 | 192 | ||
250 | if (!d->irq) { | 193 | if (!d->irq) { |
251 | dev_err(dev, "irq number not available\n"); | 194 | dev_err(dev, "irq number not available\n"); |
@@ -259,11 +202,16 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) | |||
259 | return -ENXIO; | 202 | return -ENXIO; |
260 | } | 203 | } |
261 | 204 | ||
262 | d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, | 205 | bank = d->ctrl->pin_banks; |
263 | &exynos_gpio_irqd_ops, d); | 206 | for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { |
264 | if (!d->gpio_irqd) { | 207 | if (bank->eint_type != EINT_TYPE_GPIO) |
265 | dev_err(dev, "gpio irq domain allocation failed\n"); | 208 | continue; |
266 | return -ENXIO; | 209 | bank->irq_domain = irq_domain_add_linear(bank->of_node, |
210 | bank->nr_pins, &exynos_gpio_irqd_ops, bank); | ||
211 | if (!bank->irq_domain) { | ||
212 | dev_err(dev, "gpio irq domain add failed\n"); | ||
213 | return -ENXIO; | ||
214 | } | ||
267 | } | 215 | } |
268 | 216 | ||
269 | return 0; | 217 | return 0; |
@@ -271,48 +219,46 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) | |||
271 | 219 | ||
272 | static void exynos_wkup_irq_unmask(struct irq_data *irqd) | 220 | static void exynos_wkup_irq_unmask(struct irq_data *irqd) |
273 | { | 221 | { |
274 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | 222 | struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); |
275 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | 223 | struct samsung_pinctrl_drv_data *d = b->drvdata; |
276 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | 224 | unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; |
277 | unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); | ||
278 | unsigned long mask; | 225 | unsigned long mask; |
279 | 226 | ||
280 | mask = readl(d->virt_base + reg_mask); | 227 | mask = readl(d->virt_base + reg_mask); |
281 | mask &= ~(1 << pin); | 228 | mask &= ~(1 << irqd->hwirq); |
282 | writel(mask, d->virt_base + reg_mask); | 229 | writel(mask, d->virt_base + reg_mask); |
283 | } | 230 | } |
284 | 231 | ||
285 | static void exynos_wkup_irq_mask(struct irq_data *irqd) | 232 | static void exynos_wkup_irq_mask(struct irq_data *irqd) |
286 | { | 233 | { |
287 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | 234 | struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); |
288 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | 235 | struct samsung_pinctrl_drv_data *d = b->drvdata; |
289 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | 236 | unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset; |
290 | unsigned long reg_mask = d->ctrl->weint_mask + (bank << 2); | ||
291 | unsigned long mask; | 237 | unsigned long mask; |
292 | 238 | ||
293 | mask = readl(d->virt_base + reg_mask); | 239 | mask = readl(d->virt_base + reg_mask); |
294 | mask |= 1 << pin; | 240 | mask |= 1 << irqd->hwirq; |
295 | writel(mask, d->virt_base + reg_mask); | 241 | writel(mask, d->virt_base + reg_mask); |
296 | } | 242 | } |
297 | 243 | ||
298 | static void exynos_wkup_irq_ack(struct irq_data *irqd) | 244 | static void exynos_wkup_irq_ack(struct irq_data *irqd) |
299 | { | 245 | { |
300 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | 246 | struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd); |
301 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | 247 | struct samsung_pinctrl_drv_data *d = b->drvdata; |
302 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | 248 | unsigned long pend = d->ctrl->weint_pend + b->eint_offset; |
303 | unsigned long pend = d->ctrl->weint_pend + (bank << 2); | ||
304 | 249 | ||
305 | writel(1 << pin, d->virt_base + pend); | 250 | writel(1 << irqd->hwirq, d->virt_base + pend); |
306 | } | 251 | } |
307 | 252 | ||
308 | static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) | 253 | static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) |
309 | { | 254 | { |
310 | struct samsung_pinctrl_drv_data *d = irq_data_get_irq_chip_data(irqd); | 255 | struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); |
311 | unsigned int bank = irqd->hwirq / EXYNOS_EINT_MAX_PER_BANK; | 256 | struct samsung_pinctrl_drv_data *d = bank->drvdata; |
312 | unsigned int pin = irqd->hwirq & (EXYNOS_EINT_MAX_PER_BANK - 1); | 257 | unsigned int pin = irqd->hwirq; |
313 | unsigned long reg_con = d->ctrl->weint_con + (bank << 2); | 258 | unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset; |
314 | unsigned long shift = EXYNOS_EINT_CON_LEN * pin; | 259 | unsigned long shift = EXYNOS_EINT_CON_LEN * pin; |
315 | unsigned long con, trig_type; | 260 | unsigned long con, trig_type; |
261 | unsigned int mask; | ||
316 | 262 | ||
317 | switch (type) { | 263 | switch (type) { |
318 | case IRQ_TYPE_EDGE_RISING: | 264 | case IRQ_TYPE_EDGE_RISING: |
@@ -344,6 +290,16 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) | |||
344 | con &= ~(EXYNOS_EINT_CON_MASK << shift); | 290 | con &= ~(EXYNOS_EINT_CON_MASK << shift); |
345 | con |= trig_type << shift; | 291 | con |= trig_type << shift; |
346 | writel(con, d->virt_base + reg_con); | 292 | writel(con, d->virt_base + reg_con); |
293 | |||
294 | reg_con = bank->pctl_offset; | ||
295 | shift = pin * bank->func_width; | ||
296 | mask = (1 << bank->func_width) - 1; | ||
297 | |||
298 | con = readl(d->virt_base + reg_con); | ||
299 | con &= ~(mask << shift); | ||
300 | con |= EXYNOS_EINT_FUNC << shift; | ||
301 | writel(con, d->virt_base + reg_con); | ||
302 | |||
347 | return 0; | 303 | return 0; |
348 | } | 304 | } |
349 | 305 | ||
@@ -362,6 +318,7 @@ static struct irq_chip exynos_wkup_irq_chip = { | |||
362 | static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) | 318 | static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) |
363 | { | 319 | { |
364 | struct exynos_weint_data *eintd = irq_get_handler_data(irq); | 320 | struct exynos_weint_data *eintd = irq_get_handler_data(irq); |
321 | struct samsung_pin_bank *bank = eintd->bank; | ||
365 | struct irq_chip *chip = irq_get_chip(irq); | 322 | struct irq_chip *chip = irq_get_chip(irq); |
366 | int eint_irq; | 323 | int eint_irq; |
367 | 324 | ||
@@ -371,20 +328,20 @@ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) | |||
371 | if (chip->irq_ack) | 328 | if (chip->irq_ack) |
372 | chip->irq_ack(&desc->irq_data); | 329 | chip->irq_ack(&desc->irq_data); |
373 | 330 | ||
374 | eint_irq = irq_linear_revmap(eintd->domain, eintd->irq); | 331 | eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq); |
375 | generic_handle_irq(eint_irq); | 332 | generic_handle_irq(eint_irq); |
376 | chip->irq_unmask(&desc->irq_data); | 333 | chip->irq_unmask(&desc->irq_data); |
377 | chained_irq_exit(chip, desc); | 334 | chained_irq_exit(chip, desc); |
378 | } | 335 | } |
379 | 336 | ||
380 | static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, | 337 | static inline void exynos_irq_demux_eint(unsigned long pend, |
381 | struct irq_domain *domain) | 338 | struct irq_domain *domain) |
382 | { | 339 | { |
383 | unsigned int irq; | 340 | unsigned int irq; |
384 | 341 | ||
385 | while (pend) { | 342 | while (pend) { |
386 | irq = fls(pend) - 1; | 343 | irq = fls(pend) - 1; |
387 | generic_handle_irq(irq_find_mapping(domain, irq_base + irq)); | 344 | generic_handle_irq(irq_find_mapping(domain, irq)); |
388 | pend &= ~(1 << irq); | 345 | pend &= ~(1 << irq); |
389 | } | 346 | } |
390 | } | 347 | } |
@@ -393,18 +350,22 @@ static inline void exynos_irq_demux_eint(int irq_base, unsigned long pend, | |||
393 | static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) | 350 | static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) |
394 | { | 351 | { |
395 | struct irq_chip *chip = irq_get_chip(irq); | 352 | struct irq_chip *chip = irq_get_chip(irq); |
396 | struct exynos_weint_data *eintd = irq_get_handler_data(irq); | 353 | struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq); |
397 | struct samsung_pinctrl_drv_data *d = eintd->domain->host_data; | 354 | struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata; |
355 | struct samsung_pin_ctrl *ctrl = d->ctrl; | ||
398 | unsigned long pend; | 356 | unsigned long pend; |
399 | unsigned long mask; | 357 | unsigned long mask; |
358 | int i; | ||
400 | 359 | ||
401 | chained_irq_enter(chip, desc); | 360 | chained_irq_enter(chip, desc); |
402 | pend = readl(d->virt_base + d->ctrl->weint_pend + 0x8); | 361 | |
403 | mask = readl(d->virt_base + d->ctrl->weint_mask + 0x8); | 362 | for (i = 0; i < eintd->nr_banks; ++i) { |
404 | exynos_irq_demux_eint(16, pend & ~mask, eintd->domain); | 363 | struct samsung_pin_bank *b = eintd->banks[i]; |
405 | pend = readl(d->virt_base + d->ctrl->weint_pend + 0xC); | 364 | pend = readl(d->virt_base + ctrl->weint_pend + b->eint_offset); |
406 | mask = readl(d->virt_base + d->ctrl->weint_mask + 0xC); | 365 | mask = readl(d->virt_base + ctrl->weint_mask + b->eint_offset); |
407 | exynos_irq_demux_eint(24, pend & ~mask, eintd->domain); | 366 | exynos_irq_demux_eint(pend & ~mask, b->irq_domain); |
367 | } | ||
368 | |||
408 | chained_irq_exit(chip, desc); | 369 | chained_irq_exit(chip, desc); |
409 | } | 370 | } |
410 | 371 | ||
@@ -434,7 +395,11 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) | |||
434 | struct device *dev = d->dev; | 395 | struct device *dev = d->dev; |
435 | struct device_node *wkup_np = NULL; | 396 | struct device_node *wkup_np = NULL; |
436 | struct device_node *np; | 397 | struct device_node *np; |
398 | struct samsung_pin_bank *bank; | ||
437 | struct exynos_weint_data *weint_data; | 399 | struct exynos_weint_data *weint_data; |
400 | struct exynos_muxed_weint_data *muxed_data; | ||
401 | unsigned int muxed_banks = 0; | ||
402 | unsigned int i; | ||
438 | int idx, irq; | 403 | int idx, irq; |
439 | 404 | ||
440 | for_each_child_of_node(dev->of_node, np) { | 405 | for_each_child_of_node(dev->of_node, np) { |
@@ -446,90 +411,124 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) | |||
446 | if (!wkup_np) | 411 | if (!wkup_np) |
447 | return -ENODEV; | 412 | return -ENODEV; |
448 | 413 | ||
449 | d->wkup_irqd = irq_domain_add_linear(wkup_np, d->ctrl->nr_wint, | 414 | bank = d->ctrl->pin_banks; |
450 | &exynos_wkup_irqd_ops, d); | 415 | for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { |
451 | if (!d->wkup_irqd) { | 416 | if (bank->eint_type != EINT_TYPE_WKUP) |
452 | dev_err(dev, "wakeup irq domain allocation failed\n"); | 417 | continue; |
453 | return -ENXIO; | ||
454 | } | ||
455 | 418 | ||
456 | weint_data = devm_kzalloc(dev, sizeof(*weint_data) * 17, GFP_KERNEL); | 419 | bank->irq_domain = irq_domain_add_linear(bank->of_node, |
457 | if (!weint_data) { | 420 | bank->nr_pins, &exynos_wkup_irqd_ops, bank); |
458 | dev_err(dev, "could not allocate memory for weint_data\n"); | 421 | if (!bank->irq_domain) { |
459 | return -ENOMEM; | 422 | dev_err(dev, "wkup irq domain add failed\n"); |
460 | } | 423 | return -ENXIO; |
424 | } | ||
461 | 425 | ||
462 | irq = irq_of_parse_and_map(wkup_np, 16); | 426 | if (!of_find_property(bank->of_node, "interrupts", NULL)) { |
463 | if (irq) { | 427 | bank->eint_type = EINT_TYPE_WKUP_MUX; |
464 | weint_data[16].domain = d->wkup_irqd; | 428 | ++muxed_banks; |
465 | irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); | 429 | continue; |
466 | irq_set_handler_data(irq, &weint_data[16]); | 430 | } |
467 | } else { | ||
468 | dev_err(dev, "irq number for EINT16-32 not found\n"); | ||
469 | } | ||
470 | 431 | ||
471 | for (idx = 0; idx < 16; idx++) { | 432 | weint_data = devm_kzalloc(dev, bank->nr_pins |
472 | weint_data[idx].domain = d->wkup_irqd; | 433 | * sizeof(*weint_data), GFP_KERNEL); |
473 | weint_data[idx].irq = idx; | 434 | if (!weint_data) { |
435 | dev_err(dev, "could not allocate memory for weint_data\n"); | ||
436 | return -ENOMEM; | ||
437 | } | ||
474 | 438 | ||
475 | irq = irq_of_parse_and_map(wkup_np, idx); | 439 | for (idx = 0; idx < bank->nr_pins; ++idx) { |
476 | if (irq) { | 440 | irq = irq_of_parse_and_map(bank->of_node, idx); |
441 | if (!irq) { | ||
442 | dev_err(dev, "irq number for eint-%s-%d not found\n", | ||
443 | bank->name, idx); | ||
444 | continue; | ||
445 | } | ||
446 | weint_data[idx].irq = idx; | ||
447 | weint_data[idx].bank = bank; | ||
477 | irq_set_handler_data(irq, &weint_data[idx]); | 448 | irq_set_handler_data(irq, &weint_data[idx]); |
478 | irq_set_chained_handler(irq, exynos_irq_eint0_15); | 449 | irq_set_chained_handler(irq, exynos_irq_eint0_15); |
479 | } else { | ||
480 | dev_err(dev, "irq number for eint-%x not found\n", idx); | ||
481 | } | 450 | } |
482 | } | 451 | } |
452 | |||
453 | if (!muxed_banks) | ||
454 | return 0; | ||
455 | |||
456 | irq = irq_of_parse_and_map(wkup_np, 0); | ||
457 | if (!irq) { | ||
458 | dev_err(dev, "irq number for muxed EINTs not found\n"); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | muxed_data = devm_kzalloc(dev, sizeof(*muxed_data) | ||
463 | + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL); | ||
464 | if (!muxed_data) { | ||
465 | dev_err(dev, "could not allocate memory for muxed_data\n"); | ||
466 | return -ENOMEM; | ||
467 | } | ||
468 | |||
469 | irq_set_chained_handler(irq, exynos_irq_demux_eint16_31); | ||
470 | irq_set_handler_data(irq, muxed_data); | ||
471 | |||
472 | bank = d->ctrl->pin_banks; | ||
473 | idx = 0; | ||
474 | for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) { | ||
475 | if (bank->eint_type != EINT_TYPE_WKUP_MUX) | ||
476 | continue; | ||
477 | |||
478 | muxed_data->banks[idx++] = bank; | ||
479 | } | ||
480 | muxed_data->nr_banks = muxed_banks; | ||
481 | |||
483 | return 0; | 482 | return 0; |
484 | } | 483 | } |
485 | 484 | ||
486 | /* pin banks of exynos4210 pin-controller 0 */ | 485 | /* pin banks of exynos4210 pin-controller 0 */ |
487 | static struct samsung_pin_bank exynos4210_pin_banks0[] = { | 486 | static struct samsung_pin_bank exynos4210_pin_banks0[] = { |
488 | EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_A0, "gpa0"), | 487 | EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), |
489 | EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_A1, "gpa1"), | 488 | EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), |
490 | EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_B, "gpb"), | 489 | EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), |
491 | EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_C0, "gpc0"), | 490 | EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), |
492 | EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_C1, "gpc1"), | 491 | EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), |
493 | EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_D0, "gpd0"), | 492 | EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), |
494 | EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_D1, "gpd1"), | 493 | EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18), |
495 | EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_E0, "gpe0"), | 494 | EXYNOS_PIN_BANK_EINTG(5, 0x0E0, "gpe0", 0x1c), |
496 | EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_E1, "gpe1"), | 495 | EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpe1", 0x20), |
497 | EXYNOS_PIN_BANK_EINTG(0x120, EXYNOS4210_GPIO_E2, "gpe2"), | 496 | EXYNOS_PIN_BANK_EINTG(6, 0x120, "gpe2", 0x24), |
498 | EXYNOS_PIN_BANK_EINTG(0x140, EXYNOS4210_GPIO_E3, "gpe3"), | 497 | EXYNOS_PIN_BANK_EINTG(8, 0x140, "gpe3", 0x28), |
499 | EXYNOS_PIN_BANK_EINTG(0x160, EXYNOS4210_GPIO_E4, "gpe4"), | 498 | EXYNOS_PIN_BANK_EINTG(8, 0x160, "gpe4", 0x2c), |
500 | EXYNOS_PIN_BANK_EINTG(0x180, EXYNOS4210_GPIO_F0, "gpf0"), | 499 | EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30), |
501 | EXYNOS_PIN_BANK_EINTG(0x1A0, EXYNOS4210_GPIO_F1, "gpf1"), | 500 | EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34), |
502 | EXYNOS_PIN_BANK_EINTG(0x1C0, EXYNOS4210_GPIO_F2, "gpf2"), | 501 | EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38), |
503 | EXYNOS_PIN_BANK_EINTG(0x1E0, EXYNOS4210_GPIO_F3, "gpf3"), | 502 | EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c), |
504 | }; | 503 | }; |
505 | 504 | ||
506 | /* pin banks of exynos4210 pin-controller 1 */ | 505 | /* pin banks of exynos4210 pin-controller 1 */ |
507 | static struct samsung_pin_bank exynos4210_pin_banks1[] = { | 506 | static struct samsung_pin_bank exynos4210_pin_banks1[] = { |
508 | EXYNOS_PIN_BANK_EINTG(0x000, EXYNOS4210_GPIO_J0, "gpj0"), | 507 | EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00), |
509 | EXYNOS_PIN_BANK_EINTG(0x020, EXYNOS4210_GPIO_J1, "gpj1"), | 508 | EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04), |
510 | EXYNOS_PIN_BANK_EINTG(0x040, EXYNOS4210_GPIO_K0, "gpk0"), | 509 | EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08), |
511 | EXYNOS_PIN_BANK_EINTG(0x060, EXYNOS4210_GPIO_K1, "gpk1"), | 510 | EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), |
512 | EXYNOS_PIN_BANK_EINTG(0x080, EXYNOS4210_GPIO_K2, "gpk2"), | 511 | EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), |
513 | EXYNOS_PIN_BANK_EINTG(0x0A0, EXYNOS4210_GPIO_K3, "gpk3"), | 512 | EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14), |
514 | EXYNOS_PIN_BANK_EINTG(0x0C0, EXYNOS4210_GPIO_L0, "gpl0"), | 513 | EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpl0", 0x18), |
515 | EXYNOS_PIN_BANK_EINTG(0x0E0, EXYNOS4210_GPIO_L1, "gpl1"), | 514 | EXYNOS_PIN_BANK_EINTG(3, 0x0E0, "gpl1", 0x1c), |
516 | EXYNOS_PIN_BANK_EINTG(0x100, EXYNOS4210_GPIO_L2, "gpl2"), | 515 | EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20), |
517 | EXYNOS_PIN_BANK_EINTN(0x120, EXYNOS4210_GPIO_Y0, "gpy0"), | 516 | EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"), |
518 | EXYNOS_PIN_BANK_EINTN(0x140, EXYNOS4210_GPIO_Y1, "gpy1"), | 517 | EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"), |
519 | EXYNOS_PIN_BANK_EINTN(0x160, EXYNOS4210_GPIO_Y2, "gpy2"), | 518 | EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"), |
520 | EXYNOS_PIN_BANK_EINTN(0x180, EXYNOS4210_GPIO_Y3, "gpy3"), | 519 | EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"), |
521 | EXYNOS_PIN_BANK_EINTN(0x1A0, EXYNOS4210_GPIO_Y4, "gpy4"), | 520 | EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"), |
522 | EXYNOS_PIN_BANK_EINTN(0x1C0, EXYNOS4210_GPIO_Y5, "gpy5"), | 521 | EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"), |
523 | EXYNOS_PIN_BANK_EINTN(0x1E0, EXYNOS4210_GPIO_Y6, "gpy6"), | 522 | EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"), |
524 | EXYNOS_PIN_BANK_EINTN(0xC00, EXYNOS4210_GPIO_X0, "gpx0"), | 523 | EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), |
525 | EXYNOS_PIN_BANK_EINTN(0xC20, EXYNOS4210_GPIO_X1, "gpx1"), | 524 | EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), |
526 | EXYNOS_PIN_BANK_EINTN(0xC40, EXYNOS4210_GPIO_X2, "gpx2"), | 525 | EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), |
527 | EXYNOS_PIN_BANK_EINTN(0xC60, EXYNOS4210_GPIO_X3, "gpx3"), | 526 | EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), |
528 | }; | 527 | }; |
529 | 528 | ||
530 | /* pin banks of exynos4210 pin-controller 2 */ | 529 | /* pin banks of exynos4210 pin-controller 2 */ |
531 | static struct samsung_pin_bank exynos4210_pin_banks2[] = { | 530 | static struct samsung_pin_bank exynos4210_pin_banks2[] = { |
532 | EXYNOS_PIN_BANK_EINTN(0x000, EXYNOS4210_GPIO_Z, "gpz"), | 531 | EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"), |
533 | }; | 532 | }; |
534 | 533 | ||
535 | /* | 534 | /* |
@@ -541,9 +540,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { | |||
541 | /* pin-controller instance 0 data */ | 540 | /* pin-controller instance 0 data */ |
542 | .pin_banks = exynos4210_pin_banks0, | 541 | .pin_banks = exynos4210_pin_banks0, |
543 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0), | 542 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks0), |
544 | .base = EXYNOS4210_GPIO_A0_START, | ||
545 | .nr_pins = EXYNOS4210_GPIOA_NR_PINS, | ||
546 | .nr_gint = EXYNOS4210_GPIOA_NR_GINT, | ||
547 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | 543 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, |
548 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | 544 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, |
549 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | 545 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, |
@@ -554,10 +550,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { | |||
554 | /* pin-controller instance 1 data */ | 550 | /* pin-controller instance 1 data */ |
555 | .pin_banks = exynos4210_pin_banks1, | 551 | .pin_banks = exynos4210_pin_banks1, |
556 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), | 552 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks1), |
557 | .base = EXYNOS4210_GPIOA_NR_PINS, | ||
558 | .nr_pins = EXYNOS4210_GPIOB_NR_PINS, | ||
559 | .nr_gint = EXYNOS4210_GPIOB_NR_GINT, | ||
560 | .nr_wint = 32, | ||
561 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | 553 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, |
562 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | 554 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, |
563 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | 555 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, |
@@ -572,9 +564,116 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { | |||
572 | /* pin-controller instance 2 data */ | 564 | /* pin-controller instance 2 data */ |
573 | .pin_banks = exynos4210_pin_banks2, | 565 | .pin_banks = exynos4210_pin_banks2, |
574 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), | 566 | .nr_banks = ARRAY_SIZE(exynos4210_pin_banks2), |
575 | .base = EXYNOS4210_GPIOA_NR_PINS + | ||
576 | EXYNOS4210_GPIOB_NR_PINS, | ||
577 | .nr_pins = EXYNOS4210_GPIOC_NR_PINS, | ||
578 | .label = "exynos4210-gpio-ctrl2", | 567 | .label = "exynos4210-gpio-ctrl2", |
579 | }, | 568 | }, |
580 | }; | 569 | }; |
570 | |||
571 | /* pin banks of exynos4x12 pin-controller 0 */ | ||
572 | static struct samsung_pin_bank exynos4x12_pin_banks0[] = { | ||
573 | EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), | ||
574 | EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04), | ||
575 | EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08), | ||
576 | EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c), | ||
577 | EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10), | ||
578 | EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14), | ||
579 | EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18), | ||
580 | EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30), | ||
581 | EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34), | ||
582 | EXYNOS_PIN_BANK_EINTG(8, 0x1C0, "gpf2", 0x38), | ||
583 | EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf3", 0x3c), | ||
584 | EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpj0", 0x40), | ||
585 | EXYNOS_PIN_BANK_EINTG(5, 0x260, "gpj1", 0x44), | ||
586 | }; | ||
587 | |||
588 | /* pin banks of exynos4x12 pin-controller 1 */ | ||
589 | static struct samsung_pin_bank exynos4x12_pin_banks1[] = { | ||
590 | EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08), | ||
591 | EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c), | ||
592 | EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10), | ||
593 | EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14), | ||
594 | EXYNOS_PIN_BANK_EINTG(7, 0x0C0, "gpl0", 0x18), | ||
595 | EXYNOS_PIN_BANK_EINTG(2, 0x0E0, "gpl1", 0x1c), | ||
596 | EXYNOS_PIN_BANK_EINTG(8, 0x100, "gpl2", 0x20), | ||
597 | EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24), | ||
598 | EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28), | ||
599 | EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c), | ||
600 | EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30), | ||
601 | EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34), | ||
602 | EXYNOS_PIN_BANK_EINTN(6, 0x120, "gpy0"), | ||
603 | EXYNOS_PIN_BANK_EINTN(4, 0x140, "gpy1"), | ||
604 | EXYNOS_PIN_BANK_EINTN(6, 0x160, "gpy2"), | ||
605 | EXYNOS_PIN_BANK_EINTN(8, 0x180, "gpy3"), | ||
606 | EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "gpy4"), | ||
607 | EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "gpy5"), | ||
608 | EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "gpy6"), | ||
609 | EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00), | ||
610 | EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04), | ||
611 | EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08), | ||
612 | EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c), | ||
613 | }; | ||
614 | |||
615 | /* pin banks of exynos4x12 pin-controller 2 */ | ||
616 | static struct samsung_pin_bank exynos4x12_pin_banks2[] = { | ||
617 | EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00), | ||
618 | }; | ||
619 | |||
620 | /* pin banks of exynos4x12 pin-controller 3 */ | ||
621 | static struct samsung_pin_bank exynos4x12_pin_banks3[] = { | ||
622 | EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00), | ||
623 | EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04), | ||
624 | EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpv2", 0x08), | ||
625 | EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv3", 0x0c), | ||
626 | EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpv4", 0x10), | ||
627 | }; | ||
628 | |||
629 | /* | ||
630 | * Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes | ||
631 | * four gpio/pin-mux/pinconfig controllers. | ||
632 | */ | ||
633 | struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { | ||
634 | { | ||
635 | /* pin-controller instance 0 data */ | ||
636 | .pin_banks = exynos4x12_pin_banks0, | ||
637 | .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks0), | ||
638 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
639 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
640 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
641 | .svc = EXYNOS_SVC_OFFSET, | ||
642 | .eint_gpio_init = exynos_eint_gpio_init, | ||
643 | .label = "exynos4x12-gpio-ctrl0", | ||
644 | }, { | ||
645 | /* pin-controller instance 1 data */ | ||
646 | .pin_banks = exynos4x12_pin_banks1, | ||
647 | .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks1), | ||
648 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
649 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
650 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
651 | .weint_con = EXYNOS_WKUP_ECON_OFFSET, | ||
652 | .weint_mask = EXYNOS_WKUP_EMASK_OFFSET, | ||
653 | .weint_pend = EXYNOS_WKUP_EPEND_OFFSET, | ||
654 | .svc = EXYNOS_SVC_OFFSET, | ||
655 | .eint_gpio_init = exynos_eint_gpio_init, | ||
656 | .eint_wkup_init = exynos_eint_wkup_init, | ||
657 | .label = "exynos4x12-gpio-ctrl1", | ||
658 | }, { | ||
659 | /* pin-controller instance 2 data */ | ||
660 | .pin_banks = exynos4x12_pin_banks2, | ||
661 | .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks2), | ||
662 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
663 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
664 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
665 | .svc = EXYNOS_SVC_OFFSET, | ||
666 | .eint_gpio_init = exynos_eint_gpio_init, | ||
667 | .label = "exynos4x12-gpio-ctrl2", | ||
668 | }, { | ||
669 | /* pin-controller instance 3 data */ | ||
670 | .pin_banks = exynos4x12_pin_banks3, | ||
671 | .nr_banks = ARRAY_SIZE(exynos4x12_pin_banks3), | ||
672 | .geint_con = EXYNOS_GPIO_ECON_OFFSET, | ||
673 | .geint_mask = EXYNOS_GPIO_EMASK_OFFSET, | ||
674 | .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, | ||
675 | .svc = EXYNOS_SVC_OFFSET, | ||
676 | .eint_gpio_init = exynos_eint_gpio_init, | ||
677 | .label = "exynos4x12-gpio-ctrl3", | ||
678 | }, | ||
679 | }; | ||
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h index 31d0a06174e4..0a708890d8b4 100644 --- a/drivers/pinctrl/pinctrl-exynos.h +++ b/drivers/pinctrl/pinctrl-exynos.h | |||
@@ -17,125 +17,6 @@ | |||
17 | * (at your option) any later version. | 17 | * (at your option) any later version. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #define EXYNOS_GPIO_START(__gpio) ((__gpio##_START) + (__gpio##_NR)) | ||
21 | |||
22 | #define EXYNOS4210_GPIO_A0_NR (8) | ||
23 | #define EXYNOS4210_GPIO_A1_NR (6) | ||
24 | #define EXYNOS4210_GPIO_B_NR (8) | ||
25 | #define EXYNOS4210_GPIO_C0_NR (5) | ||
26 | #define EXYNOS4210_GPIO_C1_NR (5) | ||
27 | #define EXYNOS4210_GPIO_D0_NR (4) | ||
28 | #define EXYNOS4210_GPIO_D1_NR (4) | ||
29 | #define EXYNOS4210_GPIO_E0_NR (5) | ||
30 | #define EXYNOS4210_GPIO_E1_NR (8) | ||
31 | #define EXYNOS4210_GPIO_E2_NR (6) | ||
32 | #define EXYNOS4210_GPIO_E3_NR (8) | ||
33 | #define EXYNOS4210_GPIO_E4_NR (8) | ||
34 | #define EXYNOS4210_GPIO_F0_NR (8) | ||
35 | #define EXYNOS4210_GPIO_F1_NR (8) | ||
36 | #define EXYNOS4210_GPIO_F2_NR (8) | ||
37 | #define EXYNOS4210_GPIO_F3_NR (6) | ||
38 | #define EXYNOS4210_GPIO_J0_NR (8) | ||
39 | #define EXYNOS4210_GPIO_J1_NR (5) | ||
40 | #define EXYNOS4210_GPIO_K0_NR (7) | ||
41 | #define EXYNOS4210_GPIO_K1_NR (7) | ||
42 | #define EXYNOS4210_GPIO_K2_NR (7) | ||
43 | #define EXYNOS4210_GPIO_K3_NR (7) | ||
44 | #define EXYNOS4210_GPIO_L0_NR (8) | ||
45 | #define EXYNOS4210_GPIO_L1_NR (3) | ||
46 | #define EXYNOS4210_GPIO_L2_NR (8) | ||
47 | #define EXYNOS4210_GPIO_Y0_NR (6) | ||
48 | #define EXYNOS4210_GPIO_Y1_NR (4) | ||
49 | #define EXYNOS4210_GPIO_Y2_NR (6) | ||
50 | #define EXYNOS4210_GPIO_Y3_NR (8) | ||
51 | #define EXYNOS4210_GPIO_Y4_NR (8) | ||
52 | #define EXYNOS4210_GPIO_Y5_NR (8) | ||
53 | #define EXYNOS4210_GPIO_Y6_NR (8) | ||
54 | #define EXYNOS4210_GPIO_X0_NR (8) | ||
55 | #define EXYNOS4210_GPIO_X1_NR (8) | ||
56 | #define EXYNOS4210_GPIO_X2_NR (8) | ||
57 | #define EXYNOS4210_GPIO_X3_NR (8) | ||
58 | #define EXYNOS4210_GPIO_Z_NR (7) | ||
59 | |||
60 | enum exynos4210_gpio_xa_start { | ||
61 | EXYNOS4210_GPIO_A0_START = 0, | ||
62 | EXYNOS4210_GPIO_A1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A0), | ||
63 | EXYNOS4210_GPIO_B_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_A1), | ||
64 | EXYNOS4210_GPIO_C0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_B), | ||
65 | EXYNOS4210_GPIO_C1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C0), | ||
66 | EXYNOS4210_GPIO_D0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_C1), | ||
67 | EXYNOS4210_GPIO_D1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D0), | ||
68 | EXYNOS4210_GPIO_E0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_D1), | ||
69 | EXYNOS4210_GPIO_E1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E0), | ||
70 | EXYNOS4210_GPIO_E2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E1), | ||
71 | EXYNOS4210_GPIO_E3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E2), | ||
72 | EXYNOS4210_GPIO_E4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E3), | ||
73 | EXYNOS4210_GPIO_F0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_E4), | ||
74 | EXYNOS4210_GPIO_F1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F0), | ||
75 | EXYNOS4210_GPIO_F2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F1), | ||
76 | EXYNOS4210_GPIO_F3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_F2), | ||
77 | }; | ||
78 | |||
79 | enum exynos4210_gpio_xb_start { | ||
80 | EXYNOS4210_GPIO_J0_START = 0, | ||
81 | EXYNOS4210_GPIO_J1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J0), | ||
82 | EXYNOS4210_GPIO_K0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_J1), | ||
83 | EXYNOS4210_GPIO_K1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K0), | ||
84 | EXYNOS4210_GPIO_K2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K1), | ||
85 | EXYNOS4210_GPIO_K3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K2), | ||
86 | EXYNOS4210_GPIO_L0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_K3), | ||
87 | EXYNOS4210_GPIO_L1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L0), | ||
88 | EXYNOS4210_GPIO_L2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L1), | ||
89 | EXYNOS4210_GPIO_Y0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2), | ||
90 | EXYNOS4210_GPIO_Y1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y0), | ||
91 | EXYNOS4210_GPIO_Y2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y1), | ||
92 | EXYNOS4210_GPIO_Y3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y2), | ||
93 | EXYNOS4210_GPIO_Y4_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y3), | ||
94 | EXYNOS4210_GPIO_Y5_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y4), | ||
95 | EXYNOS4210_GPIO_Y6_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y5), | ||
96 | EXYNOS4210_GPIO_X0_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_Y6), | ||
97 | EXYNOS4210_GPIO_X1_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X0), | ||
98 | EXYNOS4210_GPIO_X2_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X1), | ||
99 | EXYNOS4210_GPIO_X3_START = EXYNOS_GPIO_START(EXYNOS4210_GPIO_X2), | ||
100 | }; | ||
101 | |||
102 | enum exynos4210_gpio_xc_start { | ||
103 | EXYNOS4210_GPIO_Z_START = 0, | ||
104 | }; | ||
105 | |||
106 | #define EXYNOS4210_GPIO_A0_IRQ EXYNOS4210_GPIO_A0_START | ||
107 | #define EXYNOS4210_GPIO_A1_IRQ EXYNOS4210_GPIO_A1_START | ||
108 | #define EXYNOS4210_GPIO_B_IRQ EXYNOS4210_GPIO_B_START | ||
109 | #define EXYNOS4210_GPIO_C0_IRQ EXYNOS4210_GPIO_C0_START | ||
110 | #define EXYNOS4210_GPIO_C1_IRQ EXYNOS4210_GPIO_C1_START | ||
111 | #define EXYNOS4210_GPIO_D0_IRQ EXYNOS4210_GPIO_D0_START | ||
112 | #define EXYNOS4210_GPIO_D1_IRQ EXYNOS4210_GPIO_D1_START | ||
113 | #define EXYNOS4210_GPIO_E0_IRQ EXYNOS4210_GPIO_E0_START | ||
114 | #define EXYNOS4210_GPIO_E1_IRQ EXYNOS4210_GPIO_E1_START | ||
115 | #define EXYNOS4210_GPIO_E2_IRQ EXYNOS4210_GPIO_E2_START | ||
116 | #define EXYNOS4210_GPIO_E3_IRQ EXYNOS4210_GPIO_E3_START | ||
117 | #define EXYNOS4210_GPIO_E4_IRQ EXYNOS4210_GPIO_E4_START | ||
118 | #define EXYNOS4210_GPIO_F0_IRQ EXYNOS4210_GPIO_F0_START | ||
119 | #define EXYNOS4210_GPIO_F1_IRQ EXYNOS4210_GPIO_F1_START | ||
120 | #define EXYNOS4210_GPIO_F2_IRQ EXYNOS4210_GPIO_F2_START | ||
121 | #define EXYNOS4210_GPIO_F3_IRQ EXYNOS4210_GPIO_F3_START | ||
122 | #define EXYNOS4210_GPIO_J0_IRQ EXYNOS4210_GPIO_J0_START | ||
123 | #define EXYNOS4210_GPIO_J1_IRQ EXYNOS4210_GPIO_J1_START | ||
124 | #define EXYNOS4210_GPIO_K0_IRQ EXYNOS4210_GPIO_K0_START | ||
125 | #define EXYNOS4210_GPIO_K1_IRQ EXYNOS4210_GPIO_K1_START | ||
126 | #define EXYNOS4210_GPIO_K2_IRQ EXYNOS4210_GPIO_K2_START | ||
127 | #define EXYNOS4210_GPIO_K3_IRQ EXYNOS4210_GPIO_K3_START | ||
128 | #define EXYNOS4210_GPIO_L0_IRQ EXYNOS4210_GPIO_L0_START | ||
129 | #define EXYNOS4210_GPIO_L1_IRQ EXYNOS4210_GPIO_L1_START | ||
130 | #define EXYNOS4210_GPIO_L2_IRQ EXYNOS4210_GPIO_L2_START | ||
131 | #define EXYNOS4210_GPIO_Z_IRQ EXYNOS4210_GPIO_Z_START | ||
132 | |||
133 | #define EXYNOS4210_GPIOA_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) | ||
134 | #define EXYNOS4210_GPIOA_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_F3) | ||
135 | #define EXYNOS4210_GPIOB_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_X3) | ||
136 | #define EXYNOS4210_GPIOB_NR_GINT EXYNOS_GPIO_START(EXYNOS4210_GPIO_L2) | ||
137 | #define EXYNOS4210_GPIOC_NR_PINS EXYNOS_GPIO_START(EXYNOS4210_GPIO_Z) | ||
138 | |||
139 | /* External GPIO and wakeup interrupt related definitions */ | 20 | /* External GPIO and wakeup interrupt related definitions */ |
140 | #define EXYNOS_GPIO_ECON_OFFSET 0x700 | 21 | #define EXYNOS_GPIO_ECON_OFFSET 0x700 |
141 | #define EXYNOS_GPIO_EMASK_OFFSET 0x900 | 22 | #define EXYNOS_GPIO_EMASK_OFFSET 0x900 |
@@ -165,11 +46,10 @@ enum exynos4210_gpio_xc_start { | |||
165 | #define EXYNOS_EINT_MAX_PER_BANK 8 | 46 | #define EXYNOS_EINT_MAX_PER_BANK 8 |
166 | #define EXYNOS_EINT_NR_WKUP_EINT | 47 | #define EXYNOS_EINT_NR_WKUP_EINT |
167 | 48 | ||
168 | #define EXYNOS_PIN_BANK_EINTN(reg, __gpio, id) \ | 49 | #define EXYNOS_PIN_BANK_EINTN(pins, reg, id) \ |
169 | { \ | 50 | { \ |
170 | .pctl_offset = reg, \ | 51 | .pctl_offset = reg, \ |
171 | .pin_base = (__gpio##_START), \ | 52 | .nr_pins = pins, \ |
172 | .nr_pins = (__gpio##_NR), \ | ||
173 | .func_width = 4, \ | 53 | .func_width = 4, \ |
174 | .pud_width = 2, \ | 54 | .pud_width = 2, \ |
175 | .drv_width = 2, \ | 55 | .drv_width = 2, \ |
@@ -179,40 +59,50 @@ enum exynos4210_gpio_xc_start { | |||
179 | .name = id \ | 59 | .name = id \ |
180 | } | 60 | } |
181 | 61 | ||
182 | #define EXYNOS_PIN_BANK_EINTG(reg, __gpio, id) \ | 62 | #define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs) \ |
183 | { \ | 63 | { \ |
184 | .pctl_offset = reg, \ | 64 | .pctl_offset = reg, \ |
185 | .pin_base = (__gpio##_START), \ | 65 | .nr_pins = pins, \ |
186 | .nr_pins = (__gpio##_NR), \ | ||
187 | .func_width = 4, \ | 66 | .func_width = 4, \ |
188 | .pud_width = 2, \ | 67 | .pud_width = 2, \ |
189 | .drv_width = 2, \ | 68 | .drv_width = 2, \ |
190 | .conpdn_width = 2, \ | 69 | .conpdn_width = 2, \ |
191 | .pudpdn_width = 2, \ | 70 | .pudpdn_width = 2, \ |
192 | .eint_type = EINT_TYPE_GPIO, \ | 71 | .eint_type = EINT_TYPE_GPIO, \ |
193 | .irq_base = (__gpio##_IRQ), \ | 72 | .eint_offset = offs, \ |
194 | .name = id \ | 73 | .name = id \ |
195 | } | 74 | } |
196 | 75 | ||
197 | /** | 76 | #define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs) \ |
198 | * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks. | 77 | { \ |
199 | * @bank: pin bank from which this gpio interrupt originates. | 78 | .pctl_offset = reg, \ |
200 | * @pin: pin number within the bank. | 79 | .nr_pins = pins, \ |
201 | * @eint_offset: offset to be added to the con/pend/mask register bank base. | 80 | .func_width = 4, \ |
202 | */ | 81 | .pud_width = 2, \ |
203 | struct exynos_geint_data { | 82 | .drv_width = 2, \ |
204 | struct samsung_pin_bank *bank; | 83 | .eint_type = EINT_TYPE_WKUP, \ |
205 | u32 pin; | 84 | .eint_offset = offs, \ |
206 | u32 eint_offset; | 85 | .name = id \ |
207 | }; | 86 | } |
208 | 87 | ||
209 | /** | 88 | /** |
210 | * struct exynos_weint_data: irq specific data for all the wakeup interrupts | 89 | * struct exynos_weint_data: irq specific data for all the wakeup interrupts |
211 | * generated by the external wakeup interrupt controller. | 90 | * generated by the external wakeup interrupt controller. |
212 | * @domain: irq domain representing the external wakeup interrupts | ||
213 | * @irq: interrupt number within the domain. | 91 | * @irq: interrupt number within the domain. |
92 | * @bank: bank responsible for this interrupt | ||
214 | */ | 93 | */ |
215 | struct exynos_weint_data { | 94 | struct exynos_weint_data { |
216 | struct irq_domain *domain; | 95 | unsigned int irq; |
217 | u32 irq; | 96 | struct samsung_pin_bank *bank; |
97 | }; | ||
98 | |||
99 | /** | ||
100 | * struct exynos_muxed_weint_data: irq specific data for muxed wakeup interrupts | ||
101 | * generated by the external wakeup interrupt controller. | ||
102 | * @nr_banks: count of banks being part of the mux | ||
103 | * @banks: array of banks being part of the mux | ||
104 | */ | ||
105 | struct exynos_muxed_weint_data { | ||
106 | unsigned int nr_banks; | ||
107 | struct samsung_pin_bank *banks[]; | ||
218 | }; | 108 | }; |
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c new file mode 100644 index 000000000000..b8635f634e91 --- /dev/null +++ b/drivers/pinctrl/pinctrl-exynos5440.c | |||
@@ -0,0 +1,919 @@ | |||
1 | /* | ||
2 | * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC. | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/pinctrl/pinctrl.h> | ||
21 | #include <linux/pinctrl/pinmux.h> | ||
22 | #include <linux/pinctrl/pinconf.h> | ||
23 | #include "core.h" | ||
24 | |||
25 | /* EXYNOS5440 GPIO and Pinctrl register offsets */ | ||
26 | #define GPIO_MUX 0x00 | ||
27 | #define GPIO_IE 0x04 | ||
28 | #define GPIO_INT 0x08 | ||
29 | #define GPIO_TYPE 0x0C | ||
30 | #define GPIO_VAL 0x10 | ||
31 | #define GPIO_OE 0x14 | ||
32 | #define GPIO_IN 0x18 | ||
33 | #define GPIO_PE 0x1C | ||
34 | #define GPIO_PS 0x20 | ||
35 | #define GPIO_SR 0x24 | ||
36 | #define GPIO_DS0 0x28 | ||
37 | #define GPIO_DS1 0x2C | ||
38 | |||
39 | #define EXYNOS5440_MAX_PINS 23 | ||
40 | #define PIN_NAME_LENGTH 10 | ||
41 | |||
42 | #define GROUP_SUFFIX "-grp" | ||
43 | #define GSUFFIX_LEN sizeof(GROUP_SUFFIX) | ||
44 | #define FUNCTION_SUFFIX "-mux" | ||
45 | #define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) | ||
46 | |||
47 | /* | ||
48 | * pin configuration type and its value are packed together into a 16-bits. | ||
49 | * The upper 8-bits represent the configuration type and the lower 8-bits | ||
50 | * hold the value of the configuration type. | ||
51 | */ | ||
52 | #define PINCFG_TYPE_MASK 0xFF | ||
53 | #define PINCFG_VALUE_SHIFT 8 | ||
54 | #define PINCFG_VALUE_MASK (0xFF << PINCFG_VALUE_SHIFT) | ||
55 | #define PINCFG_PACK(type, value) (((value) << PINCFG_VALUE_SHIFT) | type) | ||
56 | #define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK) | ||
57 | #define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \ | ||
58 | PINCFG_VALUE_SHIFT) | ||
59 | |||
60 | /** | ||
61 | * enum pincfg_type - possible pin configuration types supported. | ||
62 | * @PINCFG_TYPE_PUD: Pull up/down configuration. | ||
63 | * @PINCFG_TYPE_DRV: Drive strength configuration. | ||
64 | * @PINCFG_TYPE_SKEW_RATE: Skew rate configuration. | ||
65 | * @PINCFG_TYPE_INPUT_TYPE: Pin input type configuration. | ||
66 | */ | ||
67 | enum pincfg_type { | ||
68 | PINCFG_TYPE_PUD, | ||
69 | PINCFG_TYPE_DRV, | ||
70 | PINCFG_TYPE_SKEW_RATE, | ||
71 | PINCFG_TYPE_INPUT_TYPE | ||
72 | }; | ||
73 | |||
74 | /** | ||
75 | * struct exynos5440_pin_group: represent group of pins for pincfg setting. | ||
76 | * @name: name of the pin group, used to lookup the group. | ||
77 | * @pins: the pins included in this group. | ||
78 | * @num_pins: number of pins included in this group. | ||
79 | */ | ||
80 | struct exynos5440_pin_group { | ||
81 | const char *name; | ||
82 | const unsigned int *pins; | ||
83 | u8 num_pins; | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * struct exynos5440_pmx_func: represent a pin function. | ||
88 | * @name: name of the pin function, used to lookup the function. | ||
89 | * @groups: one or more names of pin groups that provide this function. | ||
90 | * @num_groups: number of groups included in @groups. | ||
91 | * @function: the function number to be programmed when selected. | ||
92 | */ | ||
93 | struct exynos5440_pmx_func { | ||
94 | const char *name; | ||
95 | const char **groups; | ||
96 | u8 num_groups; | ||
97 | unsigned long function; | ||
98 | }; | ||
99 | |||
100 | /** | ||
101 | * struct exynos5440_pinctrl_priv_data: driver's private runtime data. | ||
102 | * @reg_base: ioremapped based address of the register space. | ||
103 | * @gc: gpio chip registered with gpiolib. | ||
104 | * @pin_groups: list of pin groups parsed from device tree. | ||
105 | * @nr_groups: number of pin groups available. | ||
106 | * @pmx_functions: list of pin functions parsed from device tree. | ||
107 | * @nr_functions: number of pin functions available. | ||
108 | */ | ||
109 | struct exynos5440_pinctrl_priv_data { | ||
110 | void __iomem *reg_base; | ||
111 | struct gpio_chip *gc; | ||
112 | |||
113 | const struct exynos5440_pin_group *pin_groups; | ||
114 | unsigned int nr_groups; | ||
115 | const struct exynos5440_pmx_func *pmx_functions; | ||
116 | unsigned int nr_functions; | ||
117 | }; | ||
118 | |||
119 | /* list of all possible config options supported */ | ||
120 | struct pin_config { | ||
121 | char *prop_cfg; | ||
122 | unsigned int cfg_type; | ||
123 | } pcfgs[] = { | ||
124 | { "samsung,exynos5440-pin-pud", PINCFG_TYPE_PUD }, | ||
125 | { "samsung,exynos5440-pin-drv", PINCFG_TYPE_DRV }, | ||
126 | { "samsung,exynos5440-pin-skew-rate", PINCFG_TYPE_SKEW_RATE }, | ||
127 | { "samsung,exynos5440-pin-input-type", PINCFG_TYPE_INPUT_TYPE }, | ||
128 | }; | ||
129 | |||
130 | /* check if the selector is a valid pin group selector */ | ||
131 | static int exynos5440_get_group_count(struct pinctrl_dev *pctldev) | ||
132 | { | ||
133 | struct exynos5440_pinctrl_priv_data *priv; | ||
134 | |||
135 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
136 | return priv->nr_groups; | ||
137 | } | ||
138 | |||
139 | /* return the name of the group selected by the group selector */ | ||
140 | static const char *exynos5440_get_group_name(struct pinctrl_dev *pctldev, | ||
141 | unsigned selector) | ||
142 | { | ||
143 | struct exynos5440_pinctrl_priv_data *priv; | ||
144 | |||
145 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
146 | return priv->pin_groups[selector].name; | ||
147 | } | ||
148 | |||
149 | /* return the pin numbers associated with the specified group */ | ||
150 | static int exynos5440_get_group_pins(struct pinctrl_dev *pctldev, | ||
151 | unsigned selector, const unsigned **pins, unsigned *num_pins) | ||
152 | { | ||
153 | struct exynos5440_pinctrl_priv_data *priv; | ||
154 | |||
155 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
156 | *pins = priv->pin_groups[selector].pins; | ||
157 | *num_pins = priv->pin_groups[selector].num_pins; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | /* create pinctrl_map entries by parsing device tree nodes */ | ||
162 | static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
163 | struct device_node *np, struct pinctrl_map **maps, | ||
164 | unsigned *nmaps) | ||
165 | { | ||
166 | struct device *dev = pctldev->dev; | ||
167 | struct pinctrl_map *map; | ||
168 | unsigned long *cfg = NULL; | ||
169 | char *gname, *fname; | ||
170 | int cfg_cnt = 0, map_cnt = 0, idx = 0; | ||
171 | |||
172 | /* count the number of config options specfied in the node */ | ||
173 | for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) | ||
174 | if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) | ||
175 | cfg_cnt++; | ||
176 | |||
177 | /* | ||
178 | * Find out the number of map entries to create. All the config options | ||
179 | * can be accomadated into a single config map entry. | ||
180 | */ | ||
181 | if (cfg_cnt) | ||
182 | map_cnt = 1; | ||
183 | if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) | ||
184 | map_cnt++; | ||
185 | if (!map_cnt) { | ||
186 | dev_err(dev, "node %s does not have either config or function " | ||
187 | "configurations\n", np->name); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | /* Allocate memory for pin-map entries */ | ||
192 | map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); | ||
193 | if (!map) { | ||
194 | dev_err(dev, "could not alloc memory for pin-maps\n"); | ||
195 | return -ENOMEM; | ||
196 | } | ||
197 | *nmaps = 0; | ||
198 | |||
199 | /* | ||
200 | * Allocate memory for pin group name. The pin group name is derived | ||
201 | * from the node name from which these map entries are be created. | ||
202 | */ | ||
203 | gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); | ||
204 | if (!gname) { | ||
205 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
206 | goto free_map; | ||
207 | } | ||
208 | sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); | ||
209 | |||
210 | /* | ||
211 | * don't have config options? then skip over to creating function | ||
212 | * map entries. | ||
213 | */ | ||
214 | if (!cfg_cnt) | ||
215 | goto skip_cfgs; | ||
216 | |||
217 | /* Allocate memory for config entries */ | ||
218 | cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); | ||
219 | if (!cfg) { | ||
220 | dev_err(dev, "failed to alloc memory for configs\n"); | ||
221 | goto free_gname; | ||
222 | } | ||
223 | |||
224 | /* Prepare a list of config settings */ | ||
225 | for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
226 | u32 value; | ||
227 | if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) | ||
228 | cfg[cfg_cnt++] = | ||
229 | PINCFG_PACK(pcfgs[idx].cfg_type, value); | ||
230 | } | ||
231 | |||
232 | /* create the config map entry */ | ||
233 | map[*nmaps].data.configs.group_or_pin = gname; | ||
234 | map[*nmaps].data.configs.configs = cfg; | ||
235 | map[*nmaps].data.configs.num_configs = cfg_cnt; | ||
236 | map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; | ||
237 | *nmaps += 1; | ||
238 | |||
239 | skip_cfgs: | ||
240 | /* create the function map entry */ | ||
241 | if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) { | ||
242 | fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); | ||
243 | if (!fname) { | ||
244 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
245 | goto free_cfg; | ||
246 | } | ||
247 | sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); | ||
248 | |||
249 | map[*nmaps].data.mux.group = gname; | ||
250 | map[*nmaps].data.mux.function = fname; | ||
251 | map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; | ||
252 | *nmaps += 1; | ||
253 | } | ||
254 | |||
255 | *maps = map; | ||
256 | return 0; | ||
257 | |||
258 | free_cfg: | ||
259 | kfree(cfg); | ||
260 | free_gname: | ||
261 | kfree(gname); | ||
262 | free_map: | ||
263 | kfree(map); | ||
264 | return -ENOMEM; | ||
265 | } | ||
266 | |||
267 | /* free the memory allocated to hold the pin-map table */ | ||
268 | static void exynos5440_dt_free_map(struct pinctrl_dev *pctldev, | ||
269 | struct pinctrl_map *map, unsigned num_maps) | ||
270 | { | ||
271 | int idx; | ||
272 | |||
273 | for (idx = 0; idx < num_maps; idx++) { | ||
274 | if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { | ||
275 | kfree(map[idx].data.mux.function); | ||
276 | if (!idx) | ||
277 | kfree(map[idx].data.mux.group); | ||
278 | } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { | ||
279 | kfree(map[idx].data.configs.configs); | ||
280 | if (!idx) | ||
281 | kfree(map[idx].data.configs.group_or_pin); | ||
282 | } | ||
283 | }; | ||
284 | |||
285 | kfree(map); | ||
286 | } | ||
287 | |||
288 | /* list of pinctrl callbacks for the pinctrl core */ | ||
289 | static struct pinctrl_ops exynos5440_pctrl_ops = { | ||
290 | .get_groups_count = exynos5440_get_group_count, | ||
291 | .get_group_name = exynos5440_get_group_name, | ||
292 | .get_group_pins = exynos5440_get_group_pins, | ||
293 | .dt_node_to_map = exynos5440_dt_node_to_map, | ||
294 | .dt_free_map = exynos5440_dt_free_map, | ||
295 | }; | ||
296 | |||
297 | /* check if the selector is a valid pin function selector */ | ||
298 | static int exynos5440_get_functions_count(struct pinctrl_dev *pctldev) | ||
299 | { | ||
300 | struct exynos5440_pinctrl_priv_data *priv; | ||
301 | |||
302 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
303 | return priv->nr_functions; | ||
304 | } | ||
305 | |||
306 | /* return the name of the pin function specified */ | ||
307 | static const char *exynos5440_pinmux_get_fname(struct pinctrl_dev *pctldev, | ||
308 | unsigned selector) | ||
309 | { | ||
310 | struct exynos5440_pinctrl_priv_data *priv; | ||
311 | |||
312 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
313 | return priv->pmx_functions[selector].name; | ||
314 | } | ||
315 | |||
316 | /* return the groups associated for the specified function selector */ | ||
317 | static int exynos5440_pinmux_get_groups(struct pinctrl_dev *pctldev, | ||
318 | unsigned selector, const char * const **groups, | ||
319 | unsigned * const num_groups) | ||
320 | { | ||
321 | struct exynos5440_pinctrl_priv_data *priv; | ||
322 | |||
323 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
324 | *groups = priv->pmx_functions[selector].groups; | ||
325 | *num_groups = priv->pmx_functions[selector].num_groups; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* enable or disable a pinmux function */ | ||
330 | static void exynos5440_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | ||
331 | unsigned group, bool enable) | ||
332 | { | ||
333 | struct exynos5440_pinctrl_priv_data *priv; | ||
334 | void __iomem *base; | ||
335 | u32 function; | ||
336 | u32 data; | ||
337 | |||
338 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
339 | base = priv->reg_base; | ||
340 | function = priv->pmx_functions[selector].function; | ||
341 | |||
342 | data = readl(base + GPIO_MUX); | ||
343 | if (enable) | ||
344 | data |= (1 << function); | ||
345 | else | ||
346 | data &= ~(1 << function); | ||
347 | writel(data, base + GPIO_MUX); | ||
348 | } | ||
349 | |||
350 | /* enable a specified pinmux by writing to registers */ | ||
351 | static int exynos5440_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, | ||
352 | unsigned group) | ||
353 | { | ||
354 | exynos5440_pinmux_setup(pctldev, selector, group, true); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | /* disable a specified pinmux by writing to registers */ | ||
359 | static void exynos5440_pinmux_disable(struct pinctrl_dev *pctldev, | ||
360 | unsigned selector, unsigned group) | ||
361 | { | ||
362 | exynos5440_pinmux_setup(pctldev, selector, group, false); | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * The calls to gpio_direction_output() and gpio_direction_input() | ||
367 | * leads to this function call (via the pinctrl_gpio_direction_{input|output}() | ||
368 | * function called from the gpiolib interface). | ||
369 | */ | ||
370 | static int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
371 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | ||
372 | { | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ | ||
377 | static struct pinmux_ops exynos5440_pinmux_ops = { | ||
378 | .get_functions_count = exynos5440_get_functions_count, | ||
379 | .get_function_name = exynos5440_pinmux_get_fname, | ||
380 | .get_function_groups = exynos5440_pinmux_get_groups, | ||
381 | .enable = exynos5440_pinmux_enable, | ||
382 | .disable = exynos5440_pinmux_disable, | ||
383 | .gpio_set_direction = exynos5440_pinmux_gpio_set_direction, | ||
384 | }; | ||
385 | |||
386 | /* set the pin config settings for a specified pin */ | ||
387 | static int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
388 | unsigned long config) | ||
389 | { | ||
390 | struct exynos5440_pinctrl_priv_data *priv; | ||
391 | void __iomem *base; | ||
392 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(config); | ||
393 | u32 cfg_value = PINCFG_UNPACK_VALUE(config); | ||
394 | u32 data; | ||
395 | |||
396 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
397 | base = priv->reg_base; | ||
398 | |||
399 | switch (cfg_type) { | ||
400 | case PINCFG_TYPE_PUD: | ||
401 | /* first set pull enable/disable bit */ | ||
402 | data = readl(base + GPIO_PE); | ||
403 | data &= ~(1 << pin); | ||
404 | if (cfg_value) | ||
405 | data |= (1 << pin); | ||
406 | writel(data, base + GPIO_PE); | ||
407 | |||
408 | /* then set pull up/down bit */ | ||
409 | data = readl(base + GPIO_PS); | ||
410 | data &= ~(1 << pin); | ||
411 | if (cfg_value == 2) | ||
412 | data |= (1 << pin); | ||
413 | writel(data, base + GPIO_PS); | ||
414 | break; | ||
415 | |||
416 | case PINCFG_TYPE_DRV: | ||
417 | /* set the first bit of the drive strength */ | ||
418 | data = readl(base + GPIO_DS0); | ||
419 | data &= ~(1 << pin); | ||
420 | data |= ((cfg_value & 1) << pin); | ||
421 | writel(data, base + GPIO_DS0); | ||
422 | cfg_value >>= 1; | ||
423 | |||
424 | /* set the second bit of the driver strength */ | ||
425 | data = readl(base + GPIO_DS1); | ||
426 | data &= ~(1 << pin); | ||
427 | data |= ((cfg_value & 1) << pin); | ||
428 | writel(data, base + GPIO_DS1); | ||
429 | break; | ||
430 | case PINCFG_TYPE_SKEW_RATE: | ||
431 | data = readl(base + GPIO_SR); | ||
432 | data &= ~(1 << pin); | ||
433 | data |= ((cfg_value & 1) << pin); | ||
434 | writel(data, base + GPIO_SR); | ||
435 | break; | ||
436 | case PINCFG_TYPE_INPUT_TYPE: | ||
437 | data = readl(base + GPIO_TYPE); | ||
438 | data &= ~(1 << pin); | ||
439 | data |= ((cfg_value & 1) << pin); | ||
440 | writel(data, base + GPIO_TYPE); | ||
441 | break; | ||
442 | default: | ||
443 | WARN_ON(1); | ||
444 | return -EINVAL; | ||
445 | } | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | /* get the pin config settings for a specified pin */ | ||
451 | static int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, | ||
452 | unsigned long *config) | ||
453 | { | ||
454 | struct exynos5440_pinctrl_priv_data *priv; | ||
455 | void __iomem *base; | ||
456 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); | ||
457 | u32 data; | ||
458 | |||
459 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
460 | base = priv->reg_base; | ||
461 | |||
462 | switch (cfg_type) { | ||
463 | case PINCFG_TYPE_PUD: | ||
464 | data = readl(base + GPIO_PE); | ||
465 | data = (data >> pin) & 1; | ||
466 | if (!data) | ||
467 | *config = 0; | ||
468 | else | ||
469 | *config = ((readl(base + GPIO_PS) >> pin) & 1) + 1; | ||
470 | break; | ||
471 | case PINCFG_TYPE_DRV: | ||
472 | data = readl(base + GPIO_DS0); | ||
473 | data = (data >> pin) & 1; | ||
474 | *config = data; | ||
475 | data = readl(base + GPIO_DS1); | ||
476 | data = (data >> pin) & 1; | ||
477 | *config |= (data << 1); | ||
478 | break; | ||
479 | case PINCFG_TYPE_SKEW_RATE: | ||
480 | data = readl(base + GPIO_SR); | ||
481 | *config = (data >> pin) & 1; | ||
482 | break; | ||
483 | case PINCFG_TYPE_INPUT_TYPE: | ||
484 | data = readl(base + GPIO_TYPE); | ||
485 | *config = (data >> pin) & 1; | ||
486 | break; | ||
487 | default: | ||
488 | WARN_ON(1); | ||
489 | return -EINVAL; | ||
490 | } | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /* set the pin config settings for a specified pin group */ | ||
496 | static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev, | ||
497 | unsigned group, unsigned long config) | ||
498 | { | ||
499 | struct exynos5440_pinctrl_priv_data *priv; | ||
500 | const unsigned int *pins; | ||
501 | unsigned int cnt; | ||
502 | |||
503 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
504 | pins = priv->pin_groups[group].pins; | ||
505 | |||
506 | for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++) | ||
507 | exynos5440_pinconf_set(pctldev, pins[cnt], config); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | /* get the pin config settings for a specified pin group */ | ||
513 | static int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev, | ||
514 | unsigned int group, unsigned long *config) | ||
515 | { | ||
516 | struct exynos5440_pinctrl_priv_data *priv; | ||
517 | const unsigned int *pins; | ||
518 | |||
519 | priv = pinctrl_dev_get_drvdata(pctldev); | ||
520 | pins = priv->pin_groups[group].pins; | ||
521 | exynos5440_pinconf_get(pctldev, pins[0], config); | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | /* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ | ||
526 | static struct pinconf_ops exynos5440_pinconf_ops = { | ||
527 | .pin_config_get = exynos5440_pinconf_get, | ||
528 | .pin_config_set = exynos5440_pinconf_set, | ||
529 | .pin_config_group_get = exynos5440_pinconf_group_get, | ||
530 | .pin_config_group_set = exynos5440_pinconf_group_set, | ||
531 | }; | ||
532 | |||
533 | /* gpiolib gpio_set callback function */ | ||
534 | static void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | ||
535 | { | ||
536 | struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); | ||
537 | void __iomem *base = priv->reg_base; | ||
538 | u32 data; | ||
539 | |||
540 | data = readl(base + GPIO_VAL); | ||
541 | data &= ~(1 << offset); | ||
542 | if (value) | ||
543 | data |= 1 << offset; | ||
544 | writel(data, base + GPIO_VAL); | ||
545 | } | ||
546 | |||
547 | /* gpiolib gpio_get callback function */ | ||
548 | static int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset) | ||
549 | { | ||
550 | struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); | ||
551 | void __iomem *base = priv->reg_base; | ||
552 | u32 data; | ||
553 | |||
554 | data = readl(base + GPIO_IN); | ||
555 | data >>= offset; | ||
556 | data &= 1; | ||
557 | return data; | ||
558 | } | ||
559 | |||
560 | /* gpiolib gpio_direction_input callback function */ | ||
561 | static int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset) | ||
562 | { | ||
563 | struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); | ||
564 | void __iomem *base = priv->reg_base; | ||
565 | u32 data; | ||
566 | |||
567 | /* first disable the data output enable on this pin */ | ||
568 | data = readl(base + GPIO_OE); | ||
569 | data &= ~(1 << offset); | ||
570 | writel(data, base + GPIO_OE); | ||
571 | |||
572 | /* now enable input on this pin */ | ||
573 | data = readl(base + GPIO_IE); | ||
574 | data |= 1 << offset; | ||
575 | writel(data, base + GPIO_IE); | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | /* gpiolib gpio_direction_output callback function */ | ||
580 | static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | ||
581 | int value) | ||
582 | { | ||
583 | struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); | ||
584 | void __iomem *base = priv->reg_base; | ||
585 | u32 data; | ||
586 | |||
587 | exynos5440_gpio_set(gc, offset, value); | ||
588 | |||
589 | /* first disable the data input enable on this pin */ | ||
590 | data = readl(base + GPIO_IE); | ||
591 | data &= ~(1 << offset); | ||
592 | writel(data, base + GPIO_IE); | ||
593 | |||
594 | /* now enable output on this pin */ | ||
595 | data = readl(base + GPIO_OE); | ||
596 | data |= 1 << offset; | ||
597 | writel(data, base + GPIO_OE); | ||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | /* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */ | ||
602 | static int __init exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, | ||
603 | struct device_node *cfg_np, unsigned int **pin_list, | ||
604 | unsigned int *npins) | ||
605 | { | ||
606 | struct device *dev = &pdev->dev; | ||
607 | struct property *prop; | ||
608 | |||
609 | prop = of_find_property(cfg_np, "samsung,exynos5440-pins", NULL); | ||
610 | if (!prop) | ||
611 | return -ENOENT; | ||
612 | |||
613 | *npins = prop->length / sizeof(unsigned long); | ||
614 | if (!*npins) { | ||
615 | dev_err(dev, "invalid pin list in %s node", cfg_np->name); | ||
616 | return -EINVAL; | ||
617 | } | ||
618 | |||
619 | *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); | ||
620 | if (!*pin_list) { | ||
621 | dev_err(dev, "failed to allocate memory for pin list\n"); | ||
622 | return -ENOMEM; | ||
623 | } | ||
624 | |||
625 | return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins", | ||
626 | *pin_list, *npins); | ||
627 | } | ||
628 | |||
629 | /* | ||
630 | * Parse the information about all the available pin groups and pin functions | ||
631 | * from device node of the pin-controller. | ||
632 | */ | ||
633 | static int __init exynos5440_pinctrl_parse_dt(struct platform_device *pdev, | ||
634 | struct exynos5440_pinctrl_priv_data *priv) | ||
635 | { | ||
636 | struct device *dev = &pdev->dev; | ||
637 | struct device_node *dev_np = dev->of_node; | ||
638 | struct device_node *cfg_np; | ||
639 | struct exynos5440_pin_group *groups, *grp; | ||
640 | struct exynos5440_pmx_func *functions, *func; | ||
641 | unsigned *pin_list; | ||
642 | unsigned int npins, grp_cnt, func_idx = 0; | ||
643 | char *gname, *fname; | ||
644 | int ret; | ||
645 | |||
646 | grp_cnt = of_get_child_count(dev_np); | ||
647 | if (!grp_cnt) | ||
648 | return -EINVAL; | ||
649 | |||
650 | groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); | ||
651 | if (!groups) { | ||
652 | dev_err(dev, "failed allocate memory for ping group list\n"); | ||
653 | return -EINVAL; | ||
654 | } | ||
655 | grp = groups; | ||
656 | |||
657 | functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); | ||
658 | if (!functions) { | ||
659 | dev_err(dev, "failed to allocate memory for function list\n"); | ||
660 | return -EINVAL; | ||
661 | } | ||
662 | func = functions; | ||
663 | |||
664 | /* | ||
665 | * Iterate over all the child nodes of the pin controller node | ||
666 | * and create pin groups and pin function lists. | ||
667 | */ | ||
668 | for_each_child_of_node(dev_np, cfg_np) { | ||
669 | u32 function; | ||
670 | |||
671 | ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np, | ||
672 | &pin_list, &npins); | ||
673 | if (ret) | ||
674 | return ret; | ||
675 | |||
676 | /* derive pin group name from the node name */ | ||
677 | gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, | ||
678 | GFP_KERNEL); | ||
679 | if (!gname) { | ||
680 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
681 | return -ENOMEM; | ||
682 | } | ||
683 | sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); | ||
684 | |||
685 | grp->name = gname; | ||
686 | grp->pins = pin_list; | ||
687 | grp->num_pins = npins; | ||
688 | grp++; | ||
689 | |||
690 | ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function", | ||
691 | &function); | ||
692 | if (ret) | ||
693 | continue; | ||
694 | |||
695 | /* derive function name from the node name */ | ||
696 | fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, | ||
697 | GFP_KERNEL); | ||
698 | if (!fname) { | ||
699 | dev_err(dev, "failed to alloc memory for func name\n"); | ||
700 | return -ENOMEM; | ||
701 | } | ||
702 | sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); | ||
703 | |||
704 | func->name = fname; | ||
705 | func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); | ||
706 | if (!func->groups) { | ||
707 | dev_err(dev, "failed to alloc memory for group list " | ||
708 | "in pin function"); | ||
709 | return -ENOMEM; | ||
710 | } | ||
711 | func->groups[0] = gname; | ||
712 | func->num_groups = 1; | ||
713 | func->function = function; | ||
714 | func++; | ||
715 | func_idx++; | ||
716 | } | ||
717 | |||
718 | priv->pin_groups = groups; | ||
719 | priv->nr_groups = grp_cnt; | ||
720 | priv->pmx_functions = functions; | ||
721 | priv->nr_functions = func_idx; | ||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | /* register the pinctrl interface with the pinctrl subsystem */ | ||
726 | static int __init exynos5440_pinctrl_register(struct platform_device *pdev, | ||
727 | struct exynos5440_pinctrl_priv_data *priv) | ||
728 | { | ||
729 | struct device *dev = &pdev->dev; | ||
730 | struct pinctrl_desc *ctrldesc; | ||
731 | struct pinctrl_dev *pctl_dev; | ||
732 | struct pinctrl_pin_desc *pindesc, *pdesc; | ||
733 | struct pinctrl_gpio_range grange; | ||
734 | char *pin_names; | ||
735 | int pin, ret; | ||
736 | |||
737 | ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL); | ||
738 | if (!ctrldesc) { | ||
739 | dev_err(dev, "could not allocate memory for pinctrl desc\n"); | ||
740 | return -ENOMEM; | ||
741 | } | ||
742 | |||
743 | ctrldesc->name = "exynos5440-pinctrl"; | ||
744 | ctrldesc->owner = THIS_MODULE; | ||
745 | ctrldesc->pctlops = &exynos5440_pctrl_ops; | ||
746 | ctrldesc->pmxops = &exynos5440_pinmux_ops; | ||
747 | ctrldesc->confops = &exynos5440_pinconf_ops; | ||
748 | |||
749 | pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * | ||
750 | EXYNOS5440_MAX_PINS, GFP_KERNEL); | ||
751 | if (!pindesc) { | ||
752 | dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); | ||
753 | return -ENOMEM; | ||
754 | } | ||
755 | ctrldesc->pins = pindesc; | ||
756 | ctrldesc->npins = EXYNOS5440_MAX_PINS; | ||
757 | |||
758 | /* dynamically populate the pin number and pin name for pindesc */ | ||
759 | for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) | ||
760 | pdesc->number = pin; | ||
761 | |||
762 | /* | ||
763 | * allocate space for storing the dynamically generated names for all | ||
764 | * the pins which belong to this pin-controller. | ||
765 | */ | ||
766 | pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * | ||
767 | ctrldesc->npins, GFP_KERNEL); | ||
768 | if (!pin_names) { | ||
769 | dev_err(&pdev->dev, "mem alloc for pin names failed\n"); | ||
770 | return -ENOMEM; | ||
771 | } | ||
772 | |||
773 | /* for each pin, set the name of the pin */ | ||
774 | for (pin = 0; pin < ctrldesc->npins; pin++) { | ||
775 | sprintf(pin_names, "gpio%02d", pin); | ||
776 | pdesc = pindesc + pin; | ||
777 | pdesc->name = pin_names; | ||
778 | pin_names += PIN_NAME_LENGTH; | ||
779 | } | ||
780 | |||
781 | ret = exynos5440_pinctrl_parse_dt(pdev, priv); | ||
782 | if (ret) | ||
783 | return ret; | ||
784 | |||
785 | pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, priv); | ||
786 | if (!pctl_dev) { | ||
787 | dev_err(&pdev->dev, "could not register pinctrl driver\n"); | ||
788 | return -EINVAL; | ||
789 | } | ||
790 | |||
791 | grange.name = "exynos5440-pctrl-gpio-range"; | ||
792 | grange.id = 0; | ||
793 | grange.base = 0; | ||
794 | grange.npins = EXYNOS5440_MAX_PINS; | ||
795 | grange.gc = priv->gc; | ||
796 | pinctrl_add_gpio_range(pctl_dev, &grange); | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | /* register the gpiolib interface with the gpiolib subsystem */ | ||
801 | static int __init exynos5440_gpiolib_register(struct platform_device *pdev, | ||
802 | struct exynos5440_pinctrl_priv_data *priv) | ||
803 | { | ||
804 | struct gpio_chip *gc; | ||
805 | int ret; | ||
806 | |||
807 | gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); | ||
808 | if (!gc) { | ||
809 | dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); | ||
810 | return -ENOMEM; | ||
811 | } | ||
812 | |||
813 | priv->gc = gc; | ||
814 | gc->base = 0; | ||
815 | gc->ngpio = EXYNOS5440_MAX_PINS; | ||
816 | gc->dev = &pdev->dev; | ||
817 | gc->set = exynos5440_gpio_set; | ||
818 | gc->get = exynos5440_gpio_get; | ||
819 | gc->direction_input = exynos5440_gpio_direction_input; | ||
820 | gc->direction_output = exynos5440_gpio_direction_output; | ||
821 | gc->label = "gpiolib-exynos5440"; | ||
822 | gc->owner = THIS_MODULE; | ||
823 | ret = gpiochip_add(gc); | ||
824 | if (ret) { | ||
825 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error " | ||
826 | "code: %d\n", gc->label, ret); | ||
827 | return ret; | ||
828 | } | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | /* unregister the gpiolib interface with the gpiolib subsystem */ | ||
834 | static int __init exynos5440_gpiolib_unregister(struct platform_device *pdev, | ||
835 | struct exynos5440_pinctrl_priv_data *priv) | ||
836 | { | ||
837 | int ret = gpiochip_remove(priv->gc); | ||
838 | if (ret) { | ||
839 | dev_err(&pdev->dev, "gpio chip remove failed\n"); | ||
840 | return ret; | ||
841 | } | ||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | static int __devinit exynos5440_pinctrl_probe(struct platform_device *pdev) | ||
846 | { | ||
847 | struct device *dev = &pdev->dev; | ||
848 | struct exynos5440_pinctrl_priv_data *priv; | ||
849 | struct resource *res; | ||
850 | int ret; | ||
851 | |||
852 | if (!dev->of_node) { | ||
853 | dev_err(dev, "device tree node not found\n"); | ||
854 | return -ENODEV; | ||
855 | } | ||
856 | |||
857 | priv = devm_kzalloc(dev, sizeof(priv), GFP_KERNEL); | ||
858 | if (!priv) { | ||
859 | dev_err(dev, "could not allocate memory for private data\n"); | ||
860 | return -ENOMEM; | ||
861 | } | ||
862 | |||
863 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
864 | if (!res) { | ||
865 | dev_err(dev, "cannot find IO resource\n"); | ||
866 | return -ENOENT; | ||
867 | } | ||
868 | |||
869 | priv->reg_base = devm_request_and_ioremap(&pdev->dev, res); | ||
870 | if (!priv->reg_base) { | ||
871 | dev_err(dev, "ioremap failed\n"); | ||
872 | return -ENODEV; | ||
873 | } | ||
874 | |||
875 | ret = exynos5440_gpiolib_register(pdev, priv); | ||
876 | if (ret) | ||
877 | return ret; | ||
878 | |||
879 | ret = exynos5440_pinctrl_register(pdev, priv); | ||
880 | if (ret) { | ||
881 | exynos5440_gpiolib_unregister(pdev, priv); | ||
882 | return ret; | ||
883 | } | ||
884 | |||
885 | platform_set_drvdata(pdev, priv); | ||
886 | dev_info(dev, "EXYNOS5440 pinctrl driver registered\n"); | ||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static const struct of_device_id exynos5440_pinctrl_dt_match[] = { | ||
891 | { .compatible = "samsung,exynos5440-pinctrl" }, | ||
892 | {}, | ||
893 | }; | ||
894 | MODULE_DEVICE_TABLE(of, exynos5440_pinctrl_dt_match); | ||
895 | |||
896 | static struct platform_driver exynos5440_pinctrl_driver = { | ||
897 | .probe = exynos5440_pinctrl_probe, | ||
898 | .driver = { | ||
899 | .name = "exynos5440-pinctrl", | ||
900 | .owner = THIS_MODULE, | ||
901 | .of_match_table = of_match_ptr(exynos5440_pinctrl_dt_match), | ||
902 | }, | ||
903 | }; | ||
904 | |||
905 | static int __init exynos5440_pinctrl_drv_register(void) | ||
906 | { | ||
907 | return platform_driver_register(&exynos5440_pinctrl_driver); | ||
908 | } | ||
909 | postcore_initcall(exynos5440_pinctrl_drv_register); | ||
910 | |||
911 | static void __exit exynos5440_pinctrl_drv_unregister(void) | ||
912 | { | ||
913 | platform_driver_unregister(&exynos5440_pinctrl_driver); | ||
914 | } | ||
915 | module_exit(exynos5440_pinctrl_drv_unregister); | ||
916 | |||
917 | MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); | ||
918 | MODULE_DESCRIPTION("Samsung EXYNOS5440 SoC pinctrl driver"); | ||
919 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 861cd5f04d5e..8f31b656c4e9 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/gpio.h> | 28 | #include <linux/gpio.h> |
29 | #include <linux/irqdomain.h> | ||
29 | 30 | ||
30 | #include "core.h" | 31 | #include "core.h" |
31 | #include "pinctrl-samsung.h" | 32 | #include "pinctrl-samsung.h" |
@@ -46,6 +47,13 @@ struct pin_config { | |||
46 | { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, | 47 | { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, |
47 | }; | 48 | }; |
48 | 49 | ||
50 | static unsigned int pin_base; | ||
51 | |||
52 | static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) | ||
53 | { | ||
54 | return container_of(gc, struct samsung_pin_bank, gpio_chip); | ||
55 | } | ||
56 | |||
49 | /* check if the selector is a valid pin group selector */ | 57 | /* check if the selector is a valid pin group selector */ |
50 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) | 58 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) |
51 | { | 59 | { |
@@ -250,14 +258,12 @@ static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, | |||
250 | * given a pin number that is local to a pin controller, find out the pin bank | 258 | * given a pin number that is local to a pin controller, find out the pin bank |
251 | * and the register base of the pin bank. | 259 | * and the register base of the pin bank. |
252 | */ | 260 | */ |
253 | static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, | 261 | static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, |
254 | void __iomem **reg, u32 *offset, | 262 | unsigned pin, void __iomem **reg, u32 *offset, |
255 | struct samsung_pin_bank **bank) | 263 | struct samsung_pin_bank **bank) |
256 | { | 264 | { |
257 | struct samsung_pinctrl_drv_data *drvdata; | ||
258 | struct samsung_pin_bank *b; | 265 | struct samsung_pin_bank *b; |
259 | 266 | ||
260 | drvdata = dev_get_drvdata(gc->dev); | ||
261 | b = drvdata->ctrl->pin_banks; | 267 | b = drvdata->ctrl->pin_banks; |
262 | 268 | ||
263 | while ((pin >= b->pin_base) && | 269 | while ((pin >= b->pin_base) && |
@@ -292,7 +298,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | |||
292 | * pin function number in the config register. | 298 | * pin function number in the config register. |
293 | */ | 299 | */ |
294 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { | 300 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { |
295 | pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, | 301 | pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base, |
296 | ®, &pin_offset, &bank); | 302 | ®, &pin_offset, &bank); |
297 | mask = (1 << bank->func_width) - 1; | 303 | mask = (1 << bank->func_width) - 1; |
298 | shift = pin_offset * bank->func_width; | 304 | shift = pin_offset * bank->func_width; |
@@ -329,10 +335,16 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | |||
329 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | 335 | struct pinctrl_gpio_range *range, unsigned offset, bool input) |
330 | { | 336 | { |
331 | struct samsung_pin_bank *bank; | 337 | struct samsung_pin_bank *bank; |
338 | struct samsung_pinctrl_drv_data *drvdata; | ||
332 | void __iomem *reg; | 339 | void __iomem *reg; |
333 | u32 data, pin_offset, mask, shift; | 340 | u32 data, pin_offset, mask, shift; |
334 | 341 | ||
335 | pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); | 342 | bank = gc_to_pin_bank(range->gc); |
343 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
344 | |||
345 | pin_offset = offset - bank->pin_base; | ||
346 | reg = drvdata->virt_base + bank->pctl_offset; | ||
347 | |||
336 | mask = (1 << bank->func_width) - 1; | 348 | mask = (1 << bank->func_width) - 1; |
337 | shift = pin_offset * bank->func_width; | 349 | shift = pin_offset * bank->func_width; |
338 | 350 | ||
@@ -366,7 +378,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | |||
366 | u32 cfg_value, cfg_reg; | 378 | u32 cfg_value, cfg_reg; |
367 | 379 | ||
368 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 380 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
369 | pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, | 381 | pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, |
370 | &pin_offset, &bank); | 382 | &pin_offset, &bank); |
371 | 383 | ||
372 | switch (cfg_type) { | 384 | switch (cfg_type) { |
@@ -391,6 +403,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | |||
391 | return -EINVAL; | 403 | return -EINVAL; |
392 | } | 404 | } |
393 | 405 | ||
406 | if (!width) | ||
407 | return -EINVAL; | ||
408 | |||
394 | mask = (1 << width) - 1; | 409 | mask = (1 << width) - 1; |
395 | shift = pin_offset * width; | 410 | shift = pin_offset * width; |
396 | data = readl(reg_base + cfg_reg); | 411 | data = readl(reg_base + cfg_reg); |
@@ -463,14 +478,16 @@ static struct pinconf_ops samsung_pinconf_ops = { | |||
463 | /* gpiolib gpio_set callback function */ | 478 | /* gpiolib gpio_set callback function */ |
464 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | 479 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) |
465 | { | 480 | { |
481 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
466 | void __iomem *reg; | 482 | void __iomem *reg; |
467 | u32 pin_offset, data; | 483 | u32 data; |
484 | |||
485 | reg = bank->drvdata->virt_base + bank->pctl_offset; | ||
468 | 486 | ||
469 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
470 | data = readl(reg + DAT_REG); | 487 | data = readl(reg + DAT_REG); |
471 | data &= ~(1 << pin_offset); | 488 | data &= ~(1 << offset); |
472 | if (value) | 489 | if (value) |
473 | data |= 1 << pin_offset; | 490 | data |= 1 << offset; |
474 | writel(data, reg + DAT_REG); | 491 | writel(data, reg + DAT_REG); |
475 | } | 492 | } |
476 | 493 | ||
@@ -478,11 +495,13 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | |||
478 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | 495 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) |
479 | { | 496 | { |
480 | void __iomem *reg; | 497 | void __iomem *reg; |
481 | u32 pin_offset, data; | 498 | u32 data; |
499 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
500 | |||
501 | reg = bank->drvdata->virt_base + bank->pctl_offset; | ||
482 | 502 | ||
483 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
484 | data = readl(reg + DAT_REG); | 503 | data = readl(reg + DAT_REG); |
485 | data >>= pin_offset; | 504 | data >>= offset; |
486 | data &= 1; | 505 | data &= 1; |
487 | return data; | 506 | return data; |
488 | } | 507 | } |
@@ -510,6 +529,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | |||
510 | } | 529 | } |
511 | 530 | ||
512 | /* | 531 | /* |
532 | * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin | ||
533 | * and a virtual IRQ, if not already present. | ||
534 | */ | ||
535 | static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | ||
536 | { | ||
537 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
538 | unsigned int virq; | ||
539 | |||
540 | if (!bank->irq_domain) | ||
541 | return -ENXIO; | ||
542 | |||
543 | virq = irq_create_mapping(bank->irq_domain, offset); | ||
544 | |||
545 | return (virq) ? : -ENXIO; | ||
546 | } | ||
547 | |||
548 | /* | ||
513 | * Parse the pin names listed in the 'samsung,pins' property and convert it | 549 | * Parse the pin names listed in the 'samsung,pins' property and convert it |
514 | * into a list of gpio numbers are create a pin group from it. | 550 | * into a list of gpio numbers are create a pin group from it. |
515 | */ | 551 | */ |
@@ -524,7 +560,7 @@ static int __devinit samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, | |||
524 | const char *pin_name; | 560 | const char *pin_name; |
525 | 561 | ||
526 | *npins = of_property_count_strings(cfg_np, "samsung,pins"); | 562 | *npins = of_property_count_strings(cfg_np, "samsung,pins"); |
527 | if (*npins < 0) { | 563 | if (IS_ERR_VALUE(*npins)) { |
528 | dev_err(dev, "invalid pin list in %s node", cfg_np->name); | 564 | dev_err(dev, "invalid pin list in %s node", cfg_np->name); |
529 | return -EINVAL; | 565 | return -EINVAL; |
530 | } | 566 | } |
@@ -597,7 +633,7 @@ static int __devinit samsung_pinctrl_parse_dt(struct platform_device *pdev, | |||
597 | */ | 633 | */ |
598 | for_each_child_of_node(dev_np, cfg_np) { | 634 | for_each_child_of_node(dev_np, cfg_np) { |
599 | u32 function; | 635 | u32 function; |
600 | if (of_find_property(cfg_np, "interrupt-controller", NULL)) | 636 | if (!of_find_property(cfg_np, "samsung,pins", NULL)) |
601 | continue; | 637 | continue; |
602 | 638 | ||
603 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, | 639 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, |
@@ -712,12 +748,16 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev, | |||
712 | return -EINVAL; | 748 | return -EINVAL; |
713 | } | 749 | } |
714 | 750 | ||
715 | drvdata->grange.name = "samsung-pctrl-gpio-range"; | 751 | for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) { |
716 | drvdata->grange.id = 0; | 752 | pin_bank = &drvdata->ctrl->pin_banks[bank]; |
717 | drvdata->grange.base = drvdata->ctrl->base; | 753 | pin_bank->grange.name = pin_bank->name; |
718 | drvdata->grange.npins = drvdata->ctrl->nr_pins; | 754 | pin_bank->grange.id = bank; |
719 | drvdata->grange.gc = drvdata->gc; | 755 | pin_bank->grange.pin_base = pin_bank->pin_base; |
720 | pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); | 756 | pin_bank->grange.base = pin_bank->gpio_chip.base; |
757 | pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; | ||
758 | pin_bank->grange.gc = &pin_bank->gpio_chip; | ||
759 | pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); | ||
760 | } | ||
721 | 761 | ||
722 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); | 762 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); |
723 | if (ret) { | 763 | if (ret) { |
@@ -728,68 +768,117 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev, | |||
728 | return 0; | 768 | return 0; |
729 | } | 769 | } |
730 | 770 | ||
771 | static const struct gpio_chip samsung_gpiolib_chip = { | ||
772 | .set = samsung_gpio_set, | ||
773 | .get = samsung_gpio_get, | ||
774 | .direction_input = samsung_gpio_direction_input, | ||
775 | .direction_output = samsung_gpio_direction_output, | ||
776 | .to_irq = samsung_gpio_to_irq, | ||
777 | .owner = THIS_MODULE, | ||
778 | }; | ||
779 | |||
731 | /* register the gpiolib interface with the gpiolib subsystem */ | 780 | /* register the gpiolib interface with the gpiolib subsystem */ |
732 | static int __devinit samsung_gpiolib_register(struct platform_device *pdev, | 781 | static int __devinit samsung_gpiolib_register(struct platform_device *pdev, |
733 | struct samsung_pinctrl_drv_data *drvdata) | 782 | struct samsung_pinctrl_drv_data *drvdata) |
734 | { | 783 | { |
784 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; | ||
785 | struct samsung_pin_bank *bank = ctrl->pin_banks; | ||
735 | struct gpio_chip *gc; | 786 | struct gpio_chip *gc; |
736 | int ret; | 787 | int ret; |
737 | 788 | int i; | |
738 | gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); | 789 | |
739 | if (!gc) { | 790 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { |
740 | dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); | 791 | bank->gpio_chip = samsung_gpiolib_chip; |
741 | return -ENOMEM; | 792 | |
742 | } | 793 | gc = &bank->gpio_chip; |
743 | 794 | gc->base = ctrl->base + bank->pin_base; | |
744 | drvdata->gc = gc; | 795 | gc->ngpio = bank->nr_pins; |
745 | gc->base = drvdata->ctrl->base; | 796 | gc->dev = &pdev->dev; |
746 | gc->ngpio = drvdata->ctrl->nr_pins; | 797 | gc->of_node = bank->of_node; |
747 | gc->dev = &pdev->dev; | 798 | gc->label = bank->name; |
748 | gc->set = samsung_gpio_set; | 799 | |
749 | gc->get = samsung_gpio_get; | 800 | ret = gpiochip_add(gc); |
750 | gc->direction_input = samsung_gpio_direction_input; | 801 | if (ret) { |
751 | gc->direction_output = samsung_gpio_direction_output; | 802 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", |
752 | gc->label = drvdata->ctrl->label; | 803 | gc->label, ret); |
753 | gc->owner = THIS_MODULE; | 804 | goto fail; |
754 | ret = gpiochip_add(gc); | 805 | } |
755 | if (ret) { | ||
756 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error " | ||
757 | "code: %d\n", gc->label, ret); | ||
758 | return ret; | ||
759 | } | 806 | } |
760 | 807 | ||
761 | return 0; | 808 | return 0; |
809 | |||
810 | fail: | ||
811 | for (--i, --bank; i >= 0; --i, --bank) | ||
812 | if (gpiochip_remove(&bank->gpio_chip)) | ||
813 | dev_err(&pdev->dev, "gpio chip %s remove failed\n", | ||
814 | bank->gpio_chip.label); | ||
815 | return ret; | ||
762 | } | 816 | } |
763 | 817 | ||
764 | /* unregister the gpiolib interface with the gpiolib subsystem */ | 818 | /* unregister the gpiolib interface with the gpiolib subsystem */ |
765 | static int __devinit samsung_gpiolib_unregister(struct platform_device *pdev, | 819 | static int __devinit samsung_gpiolib_unregister(struct platform_device *pdev, |
766 | struct samsung_pinctrl_drv_data *drvdata) | 820 | struct samsung_pinctrl_drv_data *drvdata) |
767 | { | 821 | { |
768 | int ret = gpiochip_remove(drvdata->gc); | 822 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; |
769 | if (ret) { | 823 | struct samsung_pin_bank *bank = ctrl->pin_banks; |
824 | int ret = 0; | ||
825 | int i; | ||
826 | |||
827 | for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) | ||
828 | ret = gpiochip_remove(&bank->gpio_chip); | ||
829 | |||
830 | if (ret) | ||
770 | dev_err(&pdev->dev, "gpio chip remove failed\n"); | 831 | dev_err(&pdev->dev, "gpio chip remove failed\n"); |
771 | return ret; | 832 | |
772 | } | 833 | return ret; |
773 | return 0; | ||
774 | } | 834 | } |
775 | 835 | ||
776 | static const struct of_device_id samsung_pinctrl_dt_match[]; | 836 | static const struct of_device_id samsung_pinctrl_dt_match[]; |
777 | 837 | ||
778 | /* retrieve the soc specific data */ | 838 | /* retrieve the soc specific data */ |
779 | static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( | 839 | static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( |
840 | struct samsung_pinctrl_drv_data *d, | ||
780 | struct platform_device *pdev) | 841 | struct platform_device *pdev) |
781 | { | 842 | { |
782 | int id; | 843 | int id; |
783 | const struct of_device_id *match; | 844 | const struct of_device_id *match; |
784 | const struct device_node *node = pdev->dev.of_node; | 845 | struct device_node *node = pdev->dev.of_node; |
846 | struct device_node *np; | ||
847 | struct samsung_pin_ctrl *ctrl; | ||
848 | struct samsung_pin_bank *bank; | ||
849 | int i; | ||
785 | 850 | ||
786 | id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); | 851 | id = of_alias_get_id(node, "pinctrl"); |
787 | if (id < 0) { | 852 | if (id < 0) { |
788 | dev_err(&pdev->dev, "failed to get alias id\n"); | 853 | dev_err(&pdev->dev, "failed to get alias id\n"); |
789 | return NULL; | 854 | return NULL; |
790 | } | 855 | } |
791 | match = of_match_node(samsung_pinctrl_dt_match, node); | 856 | match = of_match_node(samsung_pinctrl_dt_match, node); |
792 | return (struct samsung_pin_ctrl *)match->data + id; | 857 | ctrl = (struct samsung_pin_ctrl *)match->data + id; |
858 | |||
859 | bank = ctrl->pin_banks; | ||
860 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | ||
861 | bank->drvdata = d; | ||
862 | bank->pin_base = ctrl->nr_pins; | ||
863 | ctrl->nr_pins += bank->nr_pins; | ||
864 | } | ||
865 | |||
866 | for_each_child_of_node(node, np) { | ||
867 | if (!of_find_property(np, "gpio-controller", NULL)) | ||
868 | continue; | ||
869 | bank = ctrl->pin_banks; | ||
870 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | ||
871 | if (!strcmp(bank->name, np->name)) { | ||
872 | bank->of_node = np; | ||
873 | break; | ||
874 | } | ||
875 | } | ||
876 | } | ||
877 | |||
878 | ctrl->base = pin_base; | ||
879 | pin_base += ctrl->nr_pins; | ||
880 | |||
881 | return ctrl; | ||
793 | } | 882 | } |
794 | 883 | ||
795 | static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) | 884 | static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) |
@@ -805,18 +894,18 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) | |||
805 | return -ENODEV; | 894 | return -ENODEV; |
806 | } | 895 | } |
807 | 896 | ||
808 | ctrl = samsung_pinctrl_get_soc_data(pdev); | ||
809 | if (!ctrl) { | ||
810 | dev_err(&pdev->dev, "driver data not available\n"); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | 897 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
815 | if (!drvdata) { | 898 | if (!drvdata) { |
816 | dev_err(dev, "failed to allocate memory for driver's " | 899 | dev_err(dev, "failed to allocate memory for driver's " |
817 | "private data\n"); | 900 | "private data\n"); |
818 | return -ENOMEM; | 901 | return -ENOMEM; |
819 | } | 902 | } |
903 | |||
904 | ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev); | ||
905 | if (!ctrl) { | ||
906 | dev_err(&pdev->dev, "driver data not available\n"); | ||
907 | return -EINVAL; | ||
908 | } | ||
820 | drvdata->ctrl = ctrl; | 909 | drvdata->ctrl = ctrl; |
821 | drvdata->dev = dev; | 910 | drvdata->dev = dev; |
822 | 911 | ||
@@ -858,6 +947,8 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) | |||
858 | static const struct of_device_id samsung_pinctrl_dt_match[] = { | 947 | static const struct of_device_id samsung_pinctrl_dt_match[] = { |
859 | { .compatible = "samsung,pinctrl-exynos4210", | 948 | { .compatible = "samsung,pinctrl-exynos4210", |
860 | .data = (void *)exynos4210_pin_ctrl }, | 949 | .data = (void *)exynos4210_pin_ctrl }, |
950 | { .compatible = "samsung,pinctrl-exynos4x12", | ||
951 | .data = (void *)exynos4x12_pin_ctrl }, | ||
861 | {}, | 952 | {}, |
862 | }; | 953 | }; |
863 | MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); | 954 | MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match); |
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index b8956934cda6..5addfd16e3cc 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/pinctrl/consumer.h> | 23 | #include <linux/pinctrl/consumer.h> |
24 | #include <linux/pinctrl/machine.h> | 24 | #include <linux/pinctrl/machine.h> |
25 | 25 | ||
26 | #include <linux/gpio.h> | ||
27 | |||
26 | /* register offsets within a pin bank */ | 28 | /* register offsets within a pin bank */ |
27 | #define DAT_REG 0x4 | 29 | #define DAT_REG 0x4 |
28 | #define PUD_REG 0x8 | 30 | #define PUD_REG 0x8 |
@@ -64,6 +66,7 @@ enum pincfg_type { | |||
64 | * @EINT_TYPE_NONE: bank does not support external interrupts | 66 | * @EINT_TYPE_NONE: bank does not support external interrupts |
65 | * @EINT_TYPE_GPIO: bank supportes external gpio interrupts | 67 | * @EINT_TYPE_GPIO: bank supportes external gpio interrupts |
66 | * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts | 68 | * @EINT_TYPE_WKUP: bank supportes external wakeup interrupts |
69 | * @EINT_TYPE_WKUP_MUX: bank supports multiplexed external wakeup interrupts | ||
67 | * | 70 | * |
68 | * Samsung GPIO controller groups all the available pins into banks. The pins | 71 | * Samsung GPIO controller groups all the available pins into banks. The pins |
69 | * in a pin bank can support external gpio interrupts or external wakeup | 72 | * in a pin bank can support external gpio interrupts or external wakeup |
@@ -76,6 +79,7 @@ enum eint_type { | |||
76 | EINT_TYPE_NONE, | 79 | EINT_TYPE_NONE, |
77 | EINT_TYPE_GPIO, | 80 | EINT_TYPE_GPIO, |
78 | EINT_TYPE_WKUP, | 81 | EINT_TYPE_WKUP, |
82 | EINT_TYPE_WKUP_MUX, | ||
79 | }; | 83 | }; |
80 | 84 | ||
81 | /* maximum length of a pin in pin descriptor (example: "gpa0-0") */ | 85 | /* maximum length of a pin in pin descriptor (example: "gpa0-0") */ |
@@ -109,8 +113,12 @@ struct samsung_pinctrl_drv_data; | |||
109 | * @conpdn_width: width of the sleep mode function selector bin field. | 113 | * @conpdn_width: width of the sleep mode function selector bin field. |
110 | * @pudpdn_width: width of the sleep mode pull up/down selector bit field. | 114 | * @pudpdn_width: width of the sleep mode pull up/down selector bit field. |
111 | * @eint_type: type of the external interrupt supported by the bank. | 115 | * @eint_type: type of the external interrupt supported by the bank. |
112 | * @irq_base: starting controller local irq number of the bank. | ||
113 | * @name: name to be prefixed for each pin in this pin bank. | 116 | * @name: name to be prefixed for each pin in this pin bank. |
117 | * @of_node: OF node of the bank. | ||
118 | * @drvdata: link to controller driver data | ||
119 | * @irq_domain: IRQ domain of the bank. | ||
120 | * @gpio_chip: GPIO chip of the bank. | ||
121 | * @grange: linux gpio pin range supported by this bank. | ||
114 | */ | 122 | */ |
115 | struct samsung_pin_bank { | 123 | struct samsung_pin_bank { |
116 | u32 pctl_offset; | 124 | u32 pctl_offset; |
@@ -122,8 +130,13 @@ struct samsung_pin_bank { | |||
122 | u8 conpdn_width; | 130 | u8 conpdn_width; |
123 | u8 pudpdn_width; | 131 | u8 pudpdn_width; |
124 | enum eint_type eint_type; | 132 | enum eint_type eint_type; |
125 | u32 irq_base; | 133 | u32 eint_offset; |
126 | char *name; | 134 | char *name; |
135 | struct device_node *of_node; | ||
136 | struct samsung_pinctrl_drv_data *drvdata; | ||
137 | struct irq_domain *irq_domain; | ||
138 | struct gpio_chip gpio_chip; | ||
139 | struct pinctrl_gpio_range grange; | ||
127 | }; | 140 | }; |
128 | 141 | ||
129 | /** | 142 | /** |
@@ -132,8 +145,6 @@ struct samsung_pin_bank { | |||
132 | * @nr_banks: number of pin banks. | 145 | * @nr_banks: number of pin banks. |
133 | * @base: starting system wide pin number. | 146 | * @base: starting system wide pin number. |
134 | * @nr_pins: number of pins supported by the controller. | 147 | * @nr_pins: number of pins supported by the controller. |
135 | * @nr_gint: number of external gpio interrupts supported. | ||
136 | * @nr_wint: number of external wakeup interrupts supported. | ||
137 | * @geint_con: offset of the ext-gpio controller registers. | 148 | * @geint_con: offset of the ext-gpio controller registers. |
138 | * @geint_mask: offset of the ext-gpio interrupt mask registers. | 149 | * @geint_mask: offset of the ext-gpio interrupt mask registers. |
139 | * @geint_pend: offset of the ext-gpio interrupt pending registers. | 150 | * @geint_pend: offset of the ext-gpio interrupt pending registers. |
@@ -153,8 +164,6 @@ struct samsung_pin_ctrl { | |||
153 | 164 | ||
154 | u32 base; | 165 | u32 base; |
155 | u32 nr_pins; | 166 | u32 nr_pins; |
156 | u32 nr_gint; | ||
157 | u32 nr_wint; | ||
158 | 167 | ||
159 | u32 geint_con; | 168 | u32 geint_con; |
160 | u32 geint_mask; | 169 | u32 geint_mask; |
@@ -183,8 +192,6 @@ struct samsung_pin_ctrl { | |||
183 | * @nr_groups: number of such pin groups. | 192 | * @nr_groups: number of such pin groups. |
184 | * @pmx_functions: list of pin functions available to the driver. | 193 | * @pmx_functions: list of pin functions available to the driver. |
185 | * @nr_function: number of such pin functions. | 194 | * @nr_function: number of such pin functions. |
186 | * @gc: gpio_chip instance registered with gpiolib. | ||
187 | * @grange: linux gpio pin range supported by this controller. | ||
188 | */ | 195 | */ |
189 | struct samsung_pinctrl_drv_data { | 196 | struct samsung_pinctrl_drv_data { |
190 | void __iomem *virt_base; | 197 | void __iomem *virt_base; |
@@ -199,12 +206,6 @@ struct samsung_pinctrl_drv_data { | |||
199 | unsigned int nr_groups; | 206 | unsigned int nr_groups; |
200 | const struct samsung_pmx_func *pmx_functions; | 207 | const struct samsung_pmx_func *pmx_functions; |
201 | unsigned int nr_functions; | 208 | unsigned int nr_functions; |
202 | |||
203 | struct irq_domain *gpio_irqd; | ||
204 | struct irq_domain *wkup_irqd; | ||
205 | |||
206 | struct gpio_chip *gc; | ||
207 | struct pinctrl_gpio_range grange; | ||
208 | }; | 209 | }; |
209 | 210 | ||
210 | /** | 211 | /** |
@@ -235,5 +236,6 @@ struct samsung_pmx_func { | |||
235 | 236 | ||
236 | /* list of all exported SoC specific data */ | 237 | /* list of all exported SoC specific data */ |
237 | extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; | 238 | extern struct samsung_pin_ctrl exynos4210_pin_ctrl[]; |
239 | extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[]; | ||
238 | 240 | ||
239 | #endif /* __PINCTRL_SAMSUNG_H */ | 241 | #endif /* __PINCTRL_SAMSUNG_H */ |