gpio-rcar: Add DT support

Add DT bindings for the gpio-rcar driver and read the device
configuration from the DT node at probe time if available.

Cc: devicetree-discuss@lists.ozlabs.org
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
This commit is contained in:
Laurent Pinchart 2013-05-21 13:40:06 +02:00 committed by Simon Horman
parent 5fcf4a3c3a
commit 159f8a0209
2 changed files with 108 additions and 10 deletions

View File

@ -0,0 +1,52 @@
* Renesas R-Car GPIO Controller
Required Properties:
- compatible: should be one of the following.
- "renesas,gpio-r8a7778": for R8A7778 (R-Mobile M1) compatible GPIO controller.
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
- "renesas,gpio-rcar": for generic R-Car GPIO controller.
- reg: Base address and length of each memory resource used by the GPIO
controller hardware module.
- interrupt-parent: phandle of the parent interrupt controller.
- interrupts: Interrupt specifier for the controllers interrupt.
- gpio-controller: Marks the device node as a gpio controller.
- #gpio-cells: Should be 2. The first cell is the GPIO number and the second
cell is used to specify optional parameters as bit flags. Only the GPIO
active low flag (bit 0) is currently supported.
- gpio-ranges: Range of pins managed by the GPIO controller as a 4-cells
tuple using the following syntax.
<[phandle of the pin controller node]
0
[index of the first pin]
[number of pins]>
Please refer to gpio.txt in this directory for details of the common GPIO
bindings used by client devices.
Example: R8A7779 (R-Car H1) GPIO controller nodes
gpio0: gpio@ffc40000 {
compatible = "renesas,gpio-r8a7779", "renesas,gpio-rcar";
reg = <0xffc40000 0x2c>;
interrupt-parent = <&gic>;
interrupts = <0 141 0x4>;
#gpio-cells = <2>;
gpio-controller;
gpio-ranges = <&pfc 0 0 32>;
};
...
gpio6: gpio@ffc46000 {
compatible = "renesas,gpio-r8a7779", "renesas,gpio-rcar";
reg = <0xffc46000 0x2c>;
interrupt-parent = <&gic>;
interrupts = <0 147 0x4>;
#gpio-cells = <2>;
gpio-controller;
gpio-ranges = <&pfc 0 192 9>;
};

View File

@ -51,6 +51,8 @@ struct gpio_rcar_priv {
#define FILONOFF 0x28 #define FILONOFF 0x28
#define BOTHEDGE 0x4c #define BOTHEDGE 0x4c
#define RCAR_MAX_GPIO_PER_BANK 32
static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs) static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)
{ {
return ioread32(p->base + offs); return ioread32(p->base + offs);
@ -274,9 +276,39 @@ static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
.map = gpio_rcar_irq_domain_map, .map = gpio_rcar_irq_domain_map,
}; };
static void gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
{
struct gpio_rcar_config *pdata = p->pdev->dev.platform_data;
#ifdef CONFIG_OF
struct device_node *np = p->pdev->dev.of_node;
struct of_phandle_args args;
int ret;
#endif
if (pdata)
p->config = *pdata;
#ifdef CONFIG_OF
else if (np) {
ret = of_parse_phandle_with_args(np, "gpio-ranges",
"#gpio-range-cells", 0, &args);
p->config.number_of_pins = ret == 0 && args.args_count == 3
? args.args[2]
: RCAR_MAX_GPIO_PER_BANK;
p->config.gpio_base = -1;
}
#endif
if (p->config.number_of_pins == 0 ||
p->config.number_of_pins > RCAR_MAX_GPIO_PER_BANK) {
dev_warn(&p->pdev->dev,
"Invalid number of gpio lines %u, using %u\n",
p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK);
p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK;
}
}
static int gpio_rcar_probe(struct platform_device *pdev) static int gpio_rcar_probe(struct platform_device *pdev)
{ {
struct gpio_rcar_config *pdata = pdev->dev.platform_data;
struct gpio_rcar_priv *p; struct gpio_rcar_priv *p;
struct resource *io, *irq; struct resource *io, *irq;
struct gpio_chip *gpio_chip; struct gpio_chip *gpio_chip;
@ -291,14 +323,14 @@ static int gpio_rcar_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
/* deal with driver instance configuration */
if (pdata)
p->config = *pdata;
p->pdev = pdev; p->pdev = pdev;
platform_set_drvdata(pdev, p);
spin_lock_init(&p->lock); spin_lock_init(&p->lock);
/* Get device configuration from DT node or platform data. */
gpio_rcar_parse_pdata(p);
platform_set_drvdata(pdev, p);
io = platform_get_resource(pdev, IORESOURCE_MEM, 0); io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@ -325,6 +357,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
gpio_chip->set = gpio_rcar_set; gpio_chip->set = gpio_rcar_set;
gpio_chip->to_irq = gpio_rcar_to_irq; gpio_chip->to_irq = gpio_rcar_to_irq;
gpio_chip->label = name; gpio_chip->label = name;
gpio_chip->dev = &pdev->dev;
gpio_chip->owner = THIS_MODULE; gpio_chip->owner = THIS_MODULE;
gpio_chip->base = p->config.gpio_base; gpio_chip->base = p->config.gpio_base;
gpio_chip->ngpio = p->config.number_of_pins; gpio_chip->ngpio = p->config.number_of_pins;
@ -371,10 +404,12 @@ static int gpio_rcar_probe(struct platform_device *pdev)
p->config.irq_base, ret); p->config.irq_base, ret);
} }
ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0, if (p->config.pctl_name) {
gpio_chip->base, gpio_chip->ngpio); ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
if (ret < 0) gpio_chip->base, gpio_chip->ngpio);
dev_warn(&pdev->dev, "failed to add pin range\n"); if (ret < 0)
dev_warn(&pdev->dev, "failed to add pin range\n");
}
return 0; return 0;
@ -397,11 +432,22 @@ static int gpio_rcar_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_OF
static const struct of_device_id gpio_rcar_of_table[] = {
{
.compatible = "renesas,gpio-rcar",
},
};
MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
#endif
static struct platform_driver gpio_rcar_device_driver = { static struct platform_driver gpio_rcar_device_driver = {
.probe = gpio_rcar_probe, .probe = gpio_rcar_probe,
.remove = gpio_rcar_remove, .remove = gpio_rcar_remove,
.driver = { .driver = {
.name = "gpio_rcar", .name = "gpio_rcar",
.of_match_table = of_match_ptr(gpio_rcar_of_table),
} }
}; };