diff options
Diffstat (limited to 'arch/mips/ar7/gpio.c')
-rw-r--r-- | arch/mips/ar7/gpio.c | 113 |
1 files changed, 98 insertions, 15 deletions
diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c index 74e14a3dbf4a..c32fbb57441a 100644 --- a/arch/mips/ar7/gpio.c +++ b/arch/mips/ar7/gpio.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> | 2 | * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> |
3 | * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> | 3 | * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> |
4 | * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org> | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -18,31 +19,113 @@ | |||
18 | */ | 19 | */ |
19 | 20 | ||
20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/gpio.h> | ||
21 | 23 | ||
22 | #include <asm/mach-ar7/gpio.h> | 24 | #include <asm/mach-ar7/gpio.h> |
23 | 25 | ||
24 | static const char *ar7_gpio_list[AR7_GPIO_MAX]; | 26 | struct ar7_gpio_chip { |
27 | void __iomem *regs; | ||
28 | struct gpio_chip chip; | ||
29 | }; | ||
25 | 30 | ||
26 | int gpio_request(unsigned gpio, const char *label) | 31 | static int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio) |
27 | { | 32 | { |
28 | if (gpio >= AR7_GPIO_MAX) | 33 | struct ar7_gpio_chip *gpch = |
29 | return -EINVAL; | 34 | container_of(chip, struct ar7_gpio_chip, chip); |
35 | void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT; | ||
30 | 36 | ||
31 | if (ar7_gpio_list[gpio]) | 37 | return readl(gpio_in) & (1 << gpio); |
32 | return -EBUSY; | 38 | } |
39 | |||
40 | static void ar7_gpio_set_value(struct gpio_chip *chip, | ||
41 | unsigned gpio, int value) | ||
42 | { | ||
43 | struct ar7_gpio_chip *gpch = | ||
44 | container_of(chip, struct ar7_gpio_chip, chip); | ||
45 | void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT; | ||
46 | unsigned tmp; | ||
47 | |||
48 | tmp = readl(gpio_out) & ~(1 << gpio); | ||
49 | if (value) | ||
50 | tmp |= 1 << gpio; | ||
51 | writel(tmp, gpio_out); | ||
52 | } | ||
53 | |||
54 | static int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) | ||
55 | { | ||
56 | struct ar7_gpio_chip *gpch = | ||
57 | container_of(chip, struct ar7_gpio_chip, chip); | ||
58 | void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; | ||
33 | 59 | ||
34 | if (label) | 60 | writel(readl(gpio_dir) | (1 << gpio), gpio_dir); |
35 | ar7_gpio_list[gpio] = label; | ||
36 | else | ||
37 | ar7_gpio_list[gpio] = "busy"; | ||
38 | 61 | ||
39 | return 0; | 62 | return 0; |
40 | } | 63 | } |
41 | EXPORT_SYMBOL(gpio_request); | ||
42 | 64 | ||
43 | void gpio_free(unsigned gpio) | 65 | static int ar7_gpio_direction_output(struct gpio_chip *chip, |
66 | unsigned gpio, int value) | ||
44 | { | 67 | { |
45 | BUG_ON(!ar7_gpio_list[gpio]); | 68 | struct ar7_gpio_chip *gpch = |
46 | ar7_gpio_list[gpio] = NULL; | 69 | container_of(chip, struct ar7_gpio_chip, chip); |
70 | void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; | ||
71 | |||
72 | ar7_gpio_set_value(chip, gpio, value); | ||
73 | writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static struct ar7_gpio_chip ar7_gpio_chip = { | ||
79 | .chip = { | ||
80 | .label = "ar7-gpio", | ||
81 | .direction_input = ar7_gpio_direction_input, | ||
82 | .direction_output = ar7_gpio_direction_output, | ||
83 | .set = ar7_gpio_set_value, | ||
84 | .get = ar7_gpio_get_value, | ||
85 | .base = 0, | ||
86 | .ngpio = AR7_GPIO_MAX, | ||
87 | } | ||
88 | }; | ||
89 | |||
90 | int ar7_gpio_enable(unsigned gpio) | ||
91 | { | ||
92 | void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; | ||
93 | |||
94 | writel(readl(gpio_en) | (1 << gpio), gpio_en); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | EXPORT_SYMBOL(ar7_gpio_enable); | ||
99 | |||
100 | int ar7_gpio_disable(unsigned gpio) | ||
101 | { | ||
102 | void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; | ||
103 | |||
104 | writel(readl(gpio_en) & ~(1 << gpio), gpio_en); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | EXPORT_SYMBOL(ar7_gpio_disable); | ||
109 | |||
110 | static int __init ar7_gpio_init(void) | ||
111 | { | ||
112 | int ret; | ||
113 | |||
114 | ar7_gpio_chip.regs = ioremap_nocache(AR7_REGS_GPIO, | ||
115 | AR7_REGS_GPIO + 0x10); | ||
116 | |||
117 | if (!ar7_gpio_chip.regs) { | ||
118 | printk(KERN_ERR "ar7-gpio: failed to ioremap regs\n"); | ||
119 | return -ENOMEM; | ||
120 | } | ||
121 | |||
122 | ret = gpiochip_add(&ar7_gpio_chip.chip); | ||
123 | if (ret) { | ||
124 | printk(KERN_ERR "ar7-gpio: failed to add gpiochip\n"); | ||
125 | return ret; | ||
126 | } | ||
127 | printk(KERN_INFO "ar7-gpio: registered %d GPIOs\n", | ||
128 | ar7_gpio_chip.chip.ngpio); | ||
129 | return ret; | ||
47 | } | 130 | } |
48 | EXPORT_SYMBOL(gpio_free); | 131 | arch_initcall(ar7_gpio_init); |