diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 12 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpio/gpio-clps711x.c | 236 | ||||
-rw-r--r-- | drivers/gpio/gpio-rcar.c | 28 |
4 files changed, 102 insertions, 176 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 573c449c49b9..ec1dcdca5b8a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -109,8 +109,11 @@ config GPIO_MAX730X | |||
109 | comment "Memory mapped GPIO drivers:" | 109 | comment "Memory mapped GPIO drivers:" |
110 | 110 | ||
111 | config GPIO_CLPS711X | 111 | config GPIO_CLPS711X |
112 | def_bool y | 112 | tristate "CLPS711X GPIO support" |
113 | depends on ARCH_CLPS711X | 113 | depends on ARCH_CLPS711X |
114 | select GPIO_GENERIC | ||
115 | help | ||
116 | Say yes here to support GPIO on CLPS711X SoCs. | ||
114 | 117 | ||
115 | config GPIO_GENERIC_PLATFORM | 118 | config GPIO_GENERIC_PLATFORM |
116 | tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" | 119 | tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" |
@@ -209,6 +212,13 @@ config GPIO_RCAR | |||
209 | help | 212 | help |
210 | Say yes here to support GPIO on Renesas R-Car SoCs. | 213 | Say yes here to support GPIO on Renesas R-Car SoCs. |
211 | 214 | ||
215 | config GPIO_SAMSUNG | ||
216 | bool | ||
217 | depends on PLAT_SAMSUNG | ||
218 | help | ||
219 | Legacy GPIO support. Use only for platforms without support for | ||
220 | pinctrl. | ||
221 | |||
212 | config GPIO_SPEAR_SPICS | 222 | config GPIO_SPEAR_SPICS |
213 | bool "ST SPEAr13xx SPI Chip Select as GPIO support" | 223 | bool "ST SPEAr13xx SPI Chip Select as GPIO support" |
214 | depends on PLAT_SPEAR | 224 | depends on PLAT_SPEAR |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 0cb2d656ad16..ef3e983a2f1e 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -59,7 +59,7 @@ obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o | |||
59 | obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o | 59 | obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o |
60 | obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o | 60 | obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o |
61 | obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o | 61 | obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o |
62 | obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o | 62 | obj-$(CONFIG_GPIO_SAMSUNG) += gpio-samsung.o |
63 | obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o | 63 | obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o |
64 | obj-$(CONFIG_GPIO_SCH) += gpio-sch.o | 64 | obj-$(CONFIG_GPIO_SCH) += gpio-sch.o |
65 | obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o | 65 | obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o |
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index ce63b75b13f5..0edaf2ce9266 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * CLPS711X GPIO driver | 2 | * CLPS711X GPIO driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> | 4 | * Copyright (C) 2012,2013 Alexander Shiyan <shc_work@mail.ru> |
5 | * | 5 | * |
6 | * 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 |
7 | * 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 |
@@ -9,191 +9,91 @@ | |||
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/io.h> | 12 | #include <linux/err.h> |
13 | #include <linux/slab.h> | ||
14 | #include <linux/gpio.h> | 13 | #include <linux/gpio.h> |
15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
16 | #include <linux/spinlock.h> | 15 | #include <linux/basic_mmio_gpio.h> |
17 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
18 | 17 | ||
19 | #include <mach/hardware.h> | 18 | static int clps711x_gpio_probe(struct platform_device *pdev) |
20 | |||
21 | #define CLPS711X_GPIO_PORTS 5 | ||
22 | #define CLPS711X_GPIO_NAME "gpio-clps711x" | ||
23 | |||
24 | struct clps711x_gpio { | ||
25 | struct gpio_chip chip[CLPS711X_GPIO_PORTS]; | ||
26 | spinlock_t lock; | ||
27 | }; | ||
28 | |||
29 | static void __iomem *clps711x_ports[] = { | ||
30 | CLPS711X_VIRT_BASE + PADR, | ||
31 | CLPS711X_VIRT_BASE + PBDR, | ||
32 | CLPS711X_VIRT_BASE + PCDR, | ||
33 | CLPS711X_VIRT_BASE + PDDR, | ||
34 | CLPS711X_VIRT_BASE + PEDR, | ||
35 | }; | ||
36 | |||
37 | static void __iomem *clps711x_pdirs[] = { | ||
38 | CLPS711X_VIRT_BASE + PADDR, | ||
39 | CLPS711X_VIRT_BASE + PBDDR, | ||
40 | CLPS711X_VIRT_BASE + PCDDR, | ||
41 | CLPS711X_VIRT_BASE + PDDDR, | ||
42 | CLPS711X_VIRT_BASE + PEDDR, | ||
43 | }; | ||
44 | |||
45 | #define clps711x_port(x) clps711x_ports[x->base / 8] | ||
46 | #define clps711x_pdir(x) clps711x_pdirs[x->base / 8] | ||
47 | |||
48 | static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) | ||
49 | { | 19 | { |
50 | return !!(readb(clps711x_port(chip)) & (1 << offset)); | 20 | struct device_node *np = pdev->dev.of_node; |
51 | } | 21 | void __iomem *dat, *dir; |
22 | struct bgpio_chip *bgc; | ||
23 | struct resource *res; | ||
24 | int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id; | ||
52 | 25 | ||
53 | static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, | 26 | if ((id < 0) || (id > 4)) |
54 | int value) | 27 | return -ENODEV; |
55 | { | ||
56 | int tmp; | ||
57 | unsigned long flags; | ||
58 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
59 | |||
60 | spin_lock_irqsave(&gpio->lock, flags); | ||
61 | tmp = readb(clps711x_port(chip)) & ~(1 << offset); | ||
62 | if (value) | ||
63 | tmp |= 1 << offset; | ||
64 | writeb(tmp, clps711x_port(chip)); | ||
65 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
66 | } | ||
67 | |||
68 | static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset) | ||
69 | { | ||
70 | int tmp; | ||
71 | unsigned long flags; | ||
72 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
73 | 28 | ||
74 | spin_lock_irqsave(&gpio->lock, flags); | 29 | bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL); |
75 | tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); | 30 | if (!bgc) |
76 | writeb(tmp, clps711x_pdir(chip)); | 31 | return -ENOMEM; |
77 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
78 | 32 | ||
79 | return 0; | 33 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
80 | } | 34 | dat = devm_ioremap_resource(&pdev->dev, res); |
35 | if (IS_ERR(dat)) | ||
36 | return PTR_ERR(dat); | ||
37 | |||
38 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
39 | dir = devm_ioremap_resource(&pdev->dev, res); | ||
40 | if (IS_ERR(dir)) | ||
41 | return PTR_ERR(dir); | ||
42 | |||
43 | switch (id) { | ||
44 | case 3: | ||
45 | /* PORTD is inverted logic for direction register */ | ||
46 | err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL, | ||
47 | NULL, dir, 0); | ||
48 | break; | ||
49 | default: | ||
50 | err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL, | ||
51 | dir, NULL, 0); | ||
52 | break; | ||
53 | } | ||
81 | 54 | ||
82 | static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset, | 55 | if (err) |
83 | int value) | 56 | return err; |
84 | { | ||
85 | int tmp; | ||
86 | unsigned long flags; | ||
87 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | ||
88 | |||
89 | spin_lock_irqsave(&gpio->lock, flags); | ||
90 | tmp = readb(clps711x_pdir(chip)) | (1 << offset); | ||
91 | writeb(tmp, clps711x_pdir(chip)); | ||
92 | tmp = readb(clps711x_port(chip)) & ~(1 << offset); | ||
93 | if (value) | ||
94 | tmp |= 1 << offset; | ||
95 | writeb(tmp, clps711x_port(chip)); | ||
96 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | 57 | ||
101 | static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset) | 58 | switch (id) { |
102 | { | 59 | case 4: |
103 | int tmp; | 60 | /* PORTE is 3 lines only */ |
104 | unsigned long flags; | 61 | bgc->gc.ngpio = 3; |
105 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 62 | break; |
63 | default: | ||
64 | break; | ||
65 | } | ||
106 | 66 | ||
107 | spin_lock_irqsave(&gpio->lock, flags); | 67 | bgc->gc.base = id * 8; |
108 | tmp = readb(clps711x_pdir(chip)) | (1 << offset); | 68 | platform_set_drvdata(pdev, bgc); |
109 | writeb(tmp, clps711x_pdir(chip)); | ||
110 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
111 | 69 | ||
112 | return 0; | 70 | return gpiochip_add(&bgc->gc); |
113 | } | 71 | } |
114 | 72 | ||
115 | static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset, | 73 | static int clps711x_gpio_remove(struct platform_device *pdev) |
116 | int value) | ||
117 | { | 74 | { |
118 | int tmp; | 75 | struct bgpio_chip *bgc = platform_get_drvdata(pdev); |
119 | unsigned long flags; | 76 | |
120 | struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); | 77 | return bgpio_remove(bgc); |
121 | |||
122 | spin_lock_irqsave(&gpio->lock, flags); | ||
123 | tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); | ||
124 | writeb(tmp, clps711x_pdir(chip)); | ||
125 | tmp = readb(clps711x_port(chip)) & ~(1 << offset); | ||
126 | if (value) | ||
127 | tmp |= 1 << offset; | ||
128 | writeb(tmp, clps711x_port(chip)); | ||
129 | spin_unlock_irqrestore(&gpio->lock, flags); | ||
130 | |||
131 | return 0; | ||
132 | } | 78 | } |
133 | 79 | ||
134 | static struct { | 80 | static const struct of_device_id clps711x_gpio_ids[] = { |
135 | char *name; | 81 | { .compatible = "cirrus,clps711x-gpio" }, |
136 | int nr; | 82 | { } |
137 | int inv_dir; | ||
138 | } clps711x_gpio_ports[] __initconst = { | ||
139 | { "PORTA", 8, 0, }, | ||
140 | { "PORTB", 8, 0, }, | ||
141 | { "PORTC", 8, 0, }, | ||
142 | { "PORTD", 8, 1, }, | ||
143 | { "PORTE", 3, 0, }, | ||
144 | }; | 83 | }; |
84 | MODULE_DEVICE_TABLE(of, clps711x_gpio_ids); | ||
85 | |||
86 | static struct platform_driver clps711x_gpio_driver = { | ||
87 | .driver = { | ||
88 | .name = "clps711x-gpio", | ||
89 | .owner = THIS_MODULE, | ||
90 | .of_match_table = of_match_ptr(clps711x_gpio_ids), | ||
91 | }, | ||
92 | .probe = clps711x_gpio_probe, | ||
93 | .remove = clps711x_gpio_remove, | ||
94 | }; | ||
95 | module_platform_driver(clps711x_gpio_driver); | ||
145 | 96 | ||
146 | static int __init gpio_clps711x_init(void) | 97 | MODULE_LICENSE("GPL"); |
147 | { | ||
148 | int i; | ||
149 | struct platform_device *pdev; | ||
150 | struct clps711x_gpio *gpio; | ||
151 | |||
152 | pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0); | ||
153 | if (!pdev) { | ||
154 | pr_err("Cannot create platform device: %s\n", | ||
155 | CLPS711X_GPIO_NAME); | ||
156 | return -ENOMEM; | ||
157 | } | ||
158 | |||
159 | platform_device_add(pdev); | ||
160 | |||
161 | gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio), | ||
162 | GFP_KERNEL); | ||
163 | if (!gpio) { | ||
164 | dev_err(&pdev->dev, "GPIO allocating memory error\n"); | ||
165 | platform_device_unregister(pdev); | ||
166 | return -ENOMEM; | ||
167 | } | ||
168 | |||
169 | platform_set_drvdata(pdev, gpio); | ||
170 | |||
171 | spin_lock_init(&gpio->lock); | ||
172 | |||
173 | for (i = 0; i < CLPS711X_GPIO_PORTS; i++) { | ||
174 | gpio->chip[i].owner = THIS_MODULE; | ||
175 | gpio->chip[i].dev = &pdev->dev; | ||
176 | gpio->chip[i].label = clps711x_gpio_ports[i].name; | ||
177 | gpio->chip[i].base = i * 8; | ||
178 | gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; | ||
179 | gpio->chip[i].get = gpio_clps711x_get; | ||
180 | gpio->chip[i].set = gpio_clps711x_set; | ||
181 | if (!clps711x_gpio_ports[i].inv_dir) { | ||
182 | gpio->chip[i].direction_input = gpio_clps711x_dir_in; | ||
183 | gpio->chip[i].direction_output = gpio_clps711x_dir_out; | ||
184 | } else { | ||
185 | gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv; | ||
186 | gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv; | ||
187 | } | ||
188 | WARN_ON(gpiochip_add(&gpio->chip[i])); | ||
189 | } | ||
190 | |||
191 | dev_info(&pdev->dev, "GPIO driver initialized\n"); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | arch_initcall(gpio_clps711x_init); | ||
196 | |||
197 | MODULE_LICENSE("GPL v2"); | ||
198 | MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); | 98 | MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); |
199 | MODULE_DESCRIPTION("CLPS711X GPIO driver"); | 99 | MODULE_DESCRIPTION("CLPS711X GPIO driver"); |
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index b4ca450947b8..d173d56dbb8c 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c | |||
@@ -49,6 +49,7 @@ 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 | ||
52 | 53 | ||
53 | static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs) | 54 | static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs) |
54 | { | 55 | { |
@@ -91,7 +92,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, | 92 | static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, |
92 | unsigned int hwirq, | 93 | unsigned int hwirq, |
93 | bool active_high_rising_edge, | 94 | bool active_high_rising_edge, |
94 | bool level_trigger) | 95 | bool level_trigger, |
96 | bool both) | ||
95 | { | 97 | { |
96 | unsigned long flags; | 98 | unsigned long flags; |
97 | 99 | ||
@@ -108,6 +110,10 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p, | |||
108 | /* Configure edge or level trigger in EDGLEVEL */ | 110 | /* Configure edge or level trigger in EDGLEVEL */ |
109 | gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger); | 111 | gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger); |
110 | 112 | ||
113 | /* Select one edge or both edges in BOTHEDGE */ | ||
114 | if (p->config.has_both_edge_trigger) | ||
115 | gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both); | ||
116 | |||
111 | /* Select "Interrupt Input Mode" in IOINTSEL */ | 117 | /* Select "Interrupt Input Mode" in IOINTSEL */ |
112 | gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true); | 118 | gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true); |
113 | 119 | ||
@@ -127,16 +133,26 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type) | |||
127 | 133 | ||
128 | switch (type & IRQ_TYPE_SENSE_MASK) { | 134 | switch (type & IRQ_TYPE_SENSE_MASK) { |
129 | case IRQ_TYPE_LEVEL_HIGH: | 135 | case IRQ_TYPE_LEVEL_HIGH: |
130 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true); | 136 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true, |
137 | false); | ||
131 | break; | 138 | break; |
132 | case IRQ_TYPE_LEVEL_LOW: | 139 | case IRQ_TYPE_LEVEL_LOW: |
133 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true); | 140 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true, |
141 | false); | ||
134 | break; | 142 | break; |
135 | case IRQ_TYPE_EDGE_RISING: | 143 | case IRQ_TYPE_EDGE_RISING: |
136 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false); | 144 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false, |
145 | false); | ||
137 | break; | 146 | break; |
138 | case IRQ_TYPE_EDGE_FALLING: | 147 | case IRQ_TYPE_EDGE_FALLING: |
139 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false); | 148 | gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false, |
149 | false); | ||
150 | break; | ||
151 | case IRQ_TYPE_EDGE_BOTH: | ||
152 | if (!p->config.has_both_edge_trigger) | ||
153 | return -EINVAL; | ||
154 | gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false, | ||
155 | true); | ||
140 | break; | 156 | break; |
141 | default: | 157 | default: |
142 | return -EINVAL; | 158 | return -EINVAL; |
@@ -333,7 +349,7 @@ static int gpio_rcar_probe(struct platform_device *pdev) | |||
333 | } | 349 | } |
334 | 350 | ||
335 | if (devm_request_irq(&pdev->dev, irq->start, | 351 | if (devm_request_irq(&pdev->dev, irq->start, |
336 | gpio_rcar_irq_handler, 0, name, p)) { | 352 | gpio_rcar_irq_handler, IRQF_SHARED, name, p)) { |
337 | dev_err(&pdev->dev, "failed to request IRQ\n"); | 353 | dev_err(&pdev->dev, "failed to request IRQ\n"); |
338 | ret = -ENOENT; | 354 | ret = -ENOENT; |
339 | goto err1; | 355 | goto err1; |