diff options
author | Thomas Abraham <thomas.abraham@linaro.org> | 2011-11-06 14:32:21 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2011-12-22 20:06:54 -0500 |
commit | 659d73ada5d6869dc18838c9125731a750389019 (patch) | |
tree | 1c46b7ee38c09391942f8ded59a16614e166499c | |
parent | f983575aa90ceeb2cc7923223882dcf1debf5aa2 (diff) |
gpio/samsung: Add device tree support for EXYNOS4
As gpio chips get registered, a device tree node which represents the
gpio chip is searched and attached to it. A translate function is also
provided to convert the gpio specifier into actual platform settings
for pin function selection, pull up/down and driver strength settings.
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
[kgene.kim@samsung.com: fixed build error]
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r-- | Documentation/devicetree/bindings/gpio/gpio-samsung.txt | 40 | ||||
-rw-r--r-- | drivers/gpio/gpio-samsung.c | 72 |
2 files changed, 112 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-samsung.txt b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt new file mode 100644 index 000000000000..8f50fe5e6c42 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-samsung.txt | |||
@@ -0,0 +1,40 @@ | |||
1 | Samsung Exynos4 GPIO Controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: Compatible property value should be "samsung,exynos4-gpio>". | ||
5 | |||
6 | - reg: Physical base address of the controller and length of memory mapped | ||
7 | region. | ||
8 | |||
9 | - #gpio-cells: Should be 4. The syntax of the gpio specifier used by client nodes | ||
10 | should be the following with values derived from the SoC user manual. | ||
11 | <[phandle of the gpio controller node] | ||
12 | [pin number within the gpio controller] | ||
13 | [mux function] | ||
14 | [pull up/down] | ||
15 | [drive strength]> | ||
16 | |||
17 | Values for gpio specifier: | ||
18 | - Pin number: is a value between 0 to 7. | ||
19 | - Pull Up/Down: 0 - Pull Up/Down Disabled. | ||
20 | 1 - Pull Down Enabled. | ||
21 | 3 - Pull Up Enabled. | ||
22 | - Drive Strength: 0 - 1x, | ||
23 | 1 - 3x, | ||
24 | 2 - 2x, | ||
25 | 3 - 4x | ||
26 | |||
27 | - gpio-controller: Specifies that the node is a gpio controller. | ||
28 | - #address-cells: should be 1. | ||
29 | - #size-cells: should be 1. | ||
30 | |||
31 | Example: | ||
32 | |||
33 | gpa0: gpio-controller@11400000 { | ||
34 | #address-cells = <1>; | ||
35 | #size-cells = <1>; | ||
36 | compatible = "samsung,exynos4-gpio"; | ||
37 | reg = <0x11400000 0x20>; | ||
38 | #gpio-cells = <4>; | ||
39 | gpio-controller; | ||
40 | }; | ||
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 866251852719..6b4d23fd158e 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c | |||
@@ -24,6 +24,9 @@ | |||
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/sysdev.h> | 25 | #include <linux/sysdev.h> |
26 | #include <linux/ioport.h> | 26 | #include <linux/ioport.h> |
27 | #include <linux/of.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/of_address.h> | ||
27 | 30 | ||
28 | #include <asm/irq.h> | 31 | #include <asm/irq.h> |
29 | 32 | ||
@@ -2374,6 +2377,63 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { | |||
2374 | #endif | 2377 | #endif |
2375 | }; | 2378 | }; |
2376 | 2379 | ||
2380 | #if defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) | ||
2381 | static int exynos4_gpio_xlate(struct gpio_chip *gc, struct device_node *np, | ||
2382 | const void *gpio_spec, u32 *flags) | ||
2383 | { | ||
2384 | const __be32 *gpio = gpio_spec; | ||
2385 | const u32 n = be32_to_cpup(gpio); | ||
2386 | unsigned int pin = gc->base + be32_to_cpu(gpio[0]); | ||
2387 | |||
2388 | if (WARN_ON(gc->of_gpio_n_cells < 4)) | ||
2389 | return -EINVAL; | ||
2390 | |||
2391 | if (n > gc->ngpio) | ||
2392 | return -EINVAL; | ||
2393 | |||
2394 | if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(be32_to_cpu(gpio[1])))) | ||
2395 | pr_warn("gpio_xlate: failed to set pin function\n"); | ||
2396 | if (s3c_gpio_setpull(pin, be32_to_cpu(gpio[2]))) | ||
2397 | pr_warn("gpio_xlate: failed to set pin pull up/down\n"); | ||
2398 | if (s5p_gpio_set_drvstr(pin, be32_to_cpu(gpio[3]))) | ||
2399 | pr_warn("gpio_xlate: failed to set pin drive strength\n"); | ||
2400 | |||
2401 | return n; | ||
2402 | } | ||
2403 | |||
2404 | static const struct of_device_id exynos4_gpio_dt_match[] __initdata = { | ||
2405 | { .compatible = "samsung,exynos4-gpio", }, | ||
2406 | {} | ||
2407 | }; | ||
2408 | |||
2409 | static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, | ||
2410 | u64 base, u64 offset) | ||
2411 | { | ||
2412 | struct gpio_chip *gc = &chip->chip; | ||
2413 | u64 address; | ||
2414 | |||
2415 | if (!of_have_populated_dt()) | ||
2416 | return; | ||
2417 | |||
2418 | address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset; | ||
2419 | gc->of_node = of_find_matching_node_by_address(NULL, | ||
2420 | exynos4_gpio_dt_match, address); | ||
2421 | if (!gc->of_node) { | ||
2422 | pr_info("gpio: device tree node not found for gpio controller" | ||
2423 | " with base address %08llx\n", address); | ||
2424 | return; | ||
2425 | } | ||
2426 | gc->of_gpio_n_cells = 4; | ||
2427 | gc->of_xlate = exynos4_gpio_xlate; | ||
2428 | } | ||
2429 | #elif defined(CONFIG_ARCH_EXYNOS4) | ||
2430 | static __init void exynos4_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip, | ||
2431 | u64 base, u64 offset) | ||
2432 | { | ||
2433 | return; | ||
2434 | } | ||
2435 | #endif /* defined(CONFIG_ARCH_EXYNOS4) && defined(CONFIG_OF) */ | ||
2436 | |||
2377 | /* TODO: cleanup soc_is_* */ | 2437 | /* TODO: cleanup soc_is_* */ |
2378 | static __init int samsung_gpiolib_init(void) | 2438 | static __init int samsung_gpiolib_init(void) |
2379 | { | 2439 | { |
@@ -2455,6 +2515,10 @@ static __init int samsung_gpiolib_init(void) | |||
2455 | chip->config = &exynos4_gpio_cfg; | 2515 | chip->config = &exynos4_gpio_cfg; |
2456 | chip->group = group++; | 2516 | chip->group = group++; |
2457 | } | 2517 | } |
2518 | #ifdef CONFIG_CPU_EXYNOS4210 | ||
2519 | exynos4_gpiolib_attach_ofnode(chip, | ||
2520 | EXYNOS4_PA_GPIO1, i * 0x20); | ||
2521 | #endif | ||
2458 | } | 2522 | } |
2459 | samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1); | 2523 | samsung_gpiolib_add_4bit_chips(exynos4_gpios_1, nr_chips, S5P_VA_GPIO1); |
2460 | 2524 | ||
@@ -2467,6 +2531,10 @@ static __init int samsung_gpiolib_init(void) | |||
2467 | chip->config = &exynos4_gpio_cfg; | 2531 | chip->config = &exynos4_gpio_cfg; |
2468 | chip->group = group++; | 2532 | chip->group = group++; |
2469 | } | 2533 | } |
2534 | #ifdef CONFIG_CPU_EXYNOS4210 | ||
2535 | exynos4_gpiolib_attach_ofnode(chip, | ||
2536 | EXYNOS4_PA_GPIO2, i * 0x20); | ||
2537 | #endif | ||
2470 | } | 2538 | } |
2471 | samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2); | 2539 | samsung_gpiolib_add_4bit_chips(exynos4_gpios_2, nr_chips, S5P_VA_GPIO2); |
2472 | 2540 | ||
@@ -2479,6 +2547,10 @@ static __init int samsung_gpiolib_init(void) | |||
2479 | chip->config = &exynos4_gpio_cfg; | 2547 | chip->config = &exynos4_gpio_cfg; |
2480 | chip->group = group++; | 2548 | chip->group = group++; |
2481 | } | 2549 | } |
2550 | #ifdef CONFIG_CPU_EXYNOS4210 | ||
2551 | exynos4_gpiolib_attach_ofnode(chip, | ||
2552 | EXYNOS4_PA_GPIO3, i * 0x20); | ||
2553 | #endif | ||
2482 | } | 2554 | } |
2483 | samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3); | 2555 | samsung_gpiolib_add_4bit_chips(exynos4_gpios_3, nr_chips, S5P_VA_GPIO3); |
2484 | 2556 | ||