diff options
author | Olof Johansson <olof@lixom.net> | 2013-06-14 20:45:39 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-06-14 20:45:39 -0400 |
commit | 38d77ff90a47d198d2fd3ebd766ee84eaa71a0d2 (patch) | |
tree | 7adc209e84f7c45fba521d3430350d8a70ac4a75 /drivers/gpio | |
parent | 2c3165ebb641e0ff3faf1c87ed1c8fbd85871da0 (diff) | |
parent | 159f8a0209aff155af7f6fcdedd4a4484dd19c23 (diff) |
Merge tag 'renesas-gpio-rcar-for-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas into next/drivers
From Simon Horman:
Renesas ARM based SoC GPIO R-Car updates for v3.11
DT support to GPIO R-Car driver by Laurent Pinchart.
* tag 'renesas-gpio-rcar-for-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/horms/renesas: (131 commits)
gpio-rcar: Add DT support
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-rcar.c | 94 |
1 files changed, 78 insertions, 16 deletions
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index b4ca450947b8..5a693dd0ac7a 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c | |||
@@ -49,6 +49,9 @@ struct gpio_rcar_priv { | |||
49 | #define POSNEG 0x20 | 49 | #define POSNEG 0x20 |
50 | #define EDGLEVEL 0x24 | 50 | #define EDGLEVEL 0x24 |
51 | #define FILONOFF 0x28 | 51 | #define FILONOFF 0x28 |
52 | #define BOTHEDGE 0x4c | ||
53 | |||
54 | #define RCAR_MAX_GPIO_PER_BANK 32 | ||
52 | 55 | ||
53 | static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs) | 56 | static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs) |
54 | { | 57 | { |
@@ -91,7 +94,8 @@ static void gpio_rcar_irq_enable(struct irq_data *d) | |||
91 | static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, | 94 | static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, |
92 | unsigned int hwirq, | 95 | unsigned int hwirq, |
93 | bool active_high_rising_edge, | 96 | bool active_high_rising_edge, |
94 | bool level_trigger) | 97 | bool level_trigger, |
98 | bool both) | ||
95 | { | 99 | { |
96 | unsigned long flags; | 100 | unsigned long flags; |
97 | 101 | ||
@@ -108,6 +112,10 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, | |||
108 | /* Configure edge or level trigger in EDGLEVEL */ | 112 | /* Configure edge or level trigger in EDGLEVEL */ |
109 | gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger); | 113 | gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger); |
110 | 114 | ||
115 | /* Select one edge or both edges in BOTHEDGE */ | ||
116 | if (p->config.has_both_edge_trigger) | ||
117 | gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both); | ||
118 | |||
111 | /* Select "Interrupt Input Mode" in IOINTSEL */ | 119 | /* Select "Interrupt Input Mode" in IOINTSEL */ |
112 | gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true); | 120 | gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true); |
113 | 121 | ||
@@ -127,16 +135,26 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) | |||
127 | 135 | ||
128 | switch (type & IRQ_TYPE_SENSE_MASK) { | 136 | switch (type & IRQ_TYPE_SENSE_MASK) { |
129 | case IRQ_TYPE_LEVEL_HIGH: | 137 | case IRQ_TYPE_LEVEL_HIGH: |
130 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true); | 138 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true, |
139 | false); | ||
131 | break; | 140 | break; |
132 | case IRQ_TYPE_LEVEL_LOW: | 141 | case IRQ_TYPE_LEVEL_LOW: |
133 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true); | 142 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true, |
143 | false); | ||
134 | break; | 144 | break; |
135 | case IRQ_TYPE_EDGE_RISING: | 145 | case IRQ_TYPE_EDGE_RISING: |
136 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false); | 146 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false, |
147 | false); | ||
137 | break; | 148 | break; |
138 | case IRQ_TYPE_EDGE_FALLING: | 149 | case IRQ_TYPE_EDGE_FALLING: |
139 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false); | 150 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false, |
151 | false); | ||
152 | break; | ||
153 | case IRQ_TYPE_EDGE_BOTH: | ||
154 | if (!p->config.has_both_edge_trigger) | ||
155 | return -EINVAL; | ||
156 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false, | ||
157 | true); | ||
140 | break; | 158 | break; |
141 | default: | 159 | default: |
142 | return -EINVAL; | 160 | return -EINVAL; |
@@ -258,9 +276,39 @@ static struct irq_domain_ops gpio_rcar_irq_domain_ops = { | |||
258 | .map = gpio_rcar_irq_domain_map, | 276 | .map = gpio_rcar_irq_domain_map, |
259 | }; | 277 | }; |
260 | 278 | ||
279 | static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p) | ||
280 | { | ||
281 | struct gpio_rcar_config *pdata = p->pdev->dev.platform_data; | ||
282 | #ifdef CONFIG_OF | ||
283 | struct device_node *np = p->pdev->dev.of_node; | ||
284 | struct of_phandle_args args; | ||
285 | int ret; | ||
286 | #endif | ||
287 | |||
288 | if (pdata) | ||
289 | p->config = *pdata; | ||
290 | #ifdef CONFIG_OF | ||
291 | else if (np) { | ||
292 | ret = of_parse_phandle_with_args(np, "gpio-ranges", | ||
293 | "#gpio-range-cells", 0, &args); | ||
294 | p->config.number_of_pins = ret == 0 && args.args_count == 3 | ||
295 | ? args.args[2] | ||
296 | : RCAR_MAX_GPIO_PER_BANK; | ||
297 | p->config.gpio_base = -1; | ||
298 | } | ||
299 | #endif | ||
300 | |||
301 | if (p->config.number_of_pins == 0 || | ||
302 | p->config.number_of_pins > RCAR_MAX_GPIO_PER_BANK) { | ||
303 | dev_warn(&p->pdev->dev, | ||
304 | "Invalid number of gpio lines %u, using %u\n", | ||
305 | p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK); | ||
306 | p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK; | ||
307 | } | ||
308 | } | ||
309 | |||
261 | static int gpio_rcar_probe(struct platform_device *pdev) | 310 | static int gpio_rcar_probe(struct platform_device *pdev) |
262 | { | 311 | { |
263 | struct gpio_rcar_config *pdata = pdev->dev.platform_data; | ||
264 | struct gpio_rcar_priv *p; | 312 | struct gpio_rcar_priv *p; |
265 | struct resource *io, *irq; | 313 | struct resource *io, *irq; |
266 | struct gpio_chip *gpio_chip; | 314 | struct gpio_chip *gpio_chip; |
@@ -275,14 +323,14 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
275 | goto err0; | 323 | goto err0; |
276 | } | 324 | } |
277 | 325 | ||
278 | /* deal with driver instance configuration */ | ||
279 | if (pdata) | ||
280 | p->config = *pdata; | ||
281 | |||
282 | p->pdev = pdev; | 326 | p->pdev = pdev; |
283 | platform_set_drvdata(pdev, p); | ||
284 | spin_lock_init(&p->lock); | 327 | spin_lock_init(&p->lock); |
285 | 328 | ||
329 | /* Get device configuration from DT node or platform data. */ | ||
330 | gpio_rcar_parse_pdata(p); | ||
331 | |||
332 | platform_set_drvdata(pdev, p); | ||
333 | |||
286 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 334 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
287 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 335 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
288 | 336 | ||
@@ -309,6 +357,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
309 | gpio_chip->set = gpio_rcar_set; | 357 | gpio_chip->set = gpio_rcar_set; |
310 | gpio_chip->to_irq = gpio_rcar_to_irq; | 358 | gpio_chip->to_irq = gpio_rcar_to_irq; |
311 | gpio_chip->label = name; | 359 | gpio_chip->label = name; |
360 | gpio_chip->dev = &pdev->dev; | ||
312 | gpio_chip->owner = THIS_MODULE; | 361 | gpio_chip->owner = THIS_MODULE; |
313 | gpio_chip->base = p->config.gpio_base; | 362 | gpio_chip->base = p->config.gpio_base; |
314 | gpio_chip->ngpio = p->config.number_of_pins; | 363 | gpio_chip->ngpio = p->config.number_of_pins; |
@@ -333,7 +382,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
333 | } | 382 | } |
334 | 383 | ||
335 | if (devm_request_irq(&pdev->dev, irq->start, | 384 | if (devm_request_irq(&pdev->dev, irq->start, |
336 | gpio_rcar_irq_handler, 0, name, p)) { | 385 | gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { |
337 | dev_err(&pdev->dev, "failed to request IRQ\n"); | 386 | dev_err(&pdev->dev, "failed to request IRQ\n"); |
338 | ret = -ENOENT; | 387 | ret = -ENOENT; |
339 | goto err1; | 388 | goto err1; |
@@ -355,10 +404,12 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
355 | p->config.irq_base, ret); | 404 | p->config.irq_base, ret); |
356 | } | 405 | } |
357 | 406 | ||
358 | ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0, | 407 | if (p->config.pctl_name) { |
359 | gpio_chip->base, gpio_chip->ngpio); | 408 | ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0, |
360 | if (ret < 0) | 409 | gpio_chip->base, gpio_chip->ngpio); |
361 | dev_warn(&pdev->dev, "failed to add pin range\n"); | 410 | if (ret < 0) |
411 | dev_warn(&pdev->dev, "failed to add pin range\n"); | ||
412 | } | ||
362 | 413 | ||
363 | return 0; | 414 | return 0; |
364 | 415 | ||
@@ -381,11 +432,22 @@ static int gpio_rcar_remove(struct platform_device *pdev) | |||
381 | return 0; | 432 | return 0; |
382 | } | 433 | } |
383 | 434 | ||
435 | #ifdef CONFIG_OF | ||
436 | static const struct of_device_id gpio_rcar_of_table[] = { | ||
437 | { | ||
438 | .compatible = "renesas,gpio-rcar", | ||
439 | }, | ||
440 | }; | ||
441 | |||
442 | MODULE_DEVICE_TABLE(of, gpio_rcar_of_table); | ||
443 | #endif | ||
444 | |||
384 | static struct platform_driver gpio_rcar_device_driver = { | 445 | static struct platform_driver gpio_rcar_device_driver = { |
385 | .probe = gpio_rcar_probe, | 446 | .probe = gpio_rcar_probe, |
386 | .remove = gpio_rcar_remove, | 447 | .remove = gpio_rcar_remove, |
387 | .driver = { | 448 | .driver = { |
388 | .name = "gpio_rcar", | 449 | .name = "gpio_rcar", |
450 | .of_match_table = of_match_ptr(gpio_rcar_of_table), | ||
389 | } | 451 | } |
390 | }; | 452 | }; |
391 | 453 | ||