diff options
author | Jassi Brar <jaswinder.singh@linaro.org> | 2015-01-19 05:35:53 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2015-01-20 05:23:18 -0500 |
commit | 0da094d82c2741c58eb298d13386a95c7ab92dc7 (patch) | |
tree | a7ab70ad10a0925c89567a5ab3e56744d34c97e2 | |
parent | 98686d9a52eeeab83a33fca5c19448954d109458 (diff) |
gpio: Add Fujitsu MB86S7x GPIO driver
Driver for Fujitsu MB86S7x SoCs that have a memory mapped GPIO controller.
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Signed-off-by: Andy Green <andy.green@linaro.org>
Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
Signed-off-by: Tetsuya Nuriya <nuriya.tetsuya@jp.fujitsu.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt | 20 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 6 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-mb86s7x.c | 232 |
4 files changed, 259 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt new file mode 100644 index 000000000000..bef353f370d8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fujitsu,mb86s70-gpio.txt | |||
@@ -0,0 +1,20 @@ | |||
1 | Fujitsu MB86S7x GPIO Controller | ||
2 | ------------------------------- | ||
3 | |||
4 | Required properties: | ||
5 | - compatible: Should be "fujitsu,mb86s70-gpio" | ||
6 | - reg: Base address and length of register space | ||
7 | - clocks: Specify the clock | ||
8 | - gpio-controller: Marks the device node as a gpio controller. | ||
9 | - #gpio-cells: Should be <2>. The first cell is the pin number and the | ||
10 | second cell is used to specify optional parameters: | ||
11 | - bit 0 specifies polarity (0 for normal, 1 for inverted). | ||
12 | |||
13 | Examples: | ||
14 | gpio0: gpio@31000000 { | ||
15 | compatible = "fujitsu,mb86s70-gpio"; | ||
16 | reg = <0 0x31000000 0x10000>; | ||
17 | gpio-controller; | ||
18 | #gpio-cells = <2>; | ||
19 | clocks = <&clk 0 2 1>; | ||
20 | }; | ||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 22b46567b3bb..ae5cb4d517c6 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -197,6 +197,12 @@ config GPIO_F7188X | |||
197 | To compile this driver as a module, choose M here: the module will | 197 | To compile this driver as a module, choose M here: the module will |
198 | be called f7188x-gpio. | 198 | be called f7188x-gpio. |
199 | 199 | ||
200 | config GPIO_MB86S7X | ||
201 | bool "GPIO support for Fujitsu MB86S7x Platforms" | ||
202 | depends on ARCH_MB86S7X | ||
203 | help | ||
204 | Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs. | ||
205 | |||
200 | config GPIO_MOXART | 206 | config GPIO_MOXART |
201 | bool "MOXART GPIO support" | 207 | bool "MOXART GPIO support" |
202 | depends on ARCH_MOXART | 208 | depends on ARCH_MOXART |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 3031b19f06ba..bdda6a94d2cd 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -48,6 +48,7 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o | |||
48 | obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o | 48 | obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o |
49 | obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o | 49 | obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o |
50 | obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o | 50 | obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o |
51 | obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o | ||
51 | obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o | 52 | obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o |
52 | obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o | 53 | obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o |
53 | obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o | 54 | obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o |
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c new file mode 100644 index 000000000000..21b1ce5abdfe --- /dev/null +++ b/drivers/gpio/gpio-mb86s7x.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * linux/drivers/gpio/gpio-mb86s7x.c | ||
3 | * | ||
4 | * Copyright (C) 2015 Fujitsu Semiconductor Limited | ||
5 | * Copyright (C) 2015 Linaro Ltd. | ||
6 | * | ||
7 | * This program is free software: you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/io.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/clk.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/of_device.h> | ||
25 | #include <linux/gpio/driver.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/slab.h> | ||
29 | |||
30 | /* | ||
31 | * Only first 8bits of a register correspond to each pin, | ||
32 | * so there are 4 registers for 32 pins. | ||
33 | */ | ||
34 | #define PDR(x) (0x0 + x / 8 * 4) | ||
35 | #define DDR(x) (0x10 + x / 8 * 4) | ||
36 | #define PFR(x) (0x20 + x / 8 * 4) | ||
37 | |||
38 | #define OFFSET(x) BIT((x) % 8) | ||
39 | |||
40 | struct mb86s70_gpio_chip { | ||
41 | struct gpio_chip gc; | ||
42 | void __iomem *base; | ||
43 | struct clk *clk; | ||
44 | spinlock_t lock; | ||
45 | }; | ||
46 | |||
47 | static inline struct mb86s70_gpio_chip *chip_to_mb86s70(struct gpio_chip *gc) | ||
48 | { | ||
49 | return container_of(gc, struct mb86s70_gpio_chip, gc); | ||
50 | } | ||
51 | |||
52 | static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio) | ||
53 | { | ||
54 | struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); | ||
55 | unsigned long flags; | ||
56 | u32 val; | ||
57 | |||
58 | spin_lock_irqsave(&gchip->lock, flags); | ||
59 | |||
60 | val = readl(gchip->base + PFR(gpio)); | ||
61 | val &= ~OFFSET(gpio); | ||
62 | writel(val, gchip->base + PFR(gpio)); | ||
63 | |||
64 | spin_unlock_irqrestore(&gchip->lock, flags); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio) | ||
70 | { | ||
71 | struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); | ||
72 | unsigned long flags; | ||
73 | u32 val; | ||
74 | |||
75 | spin_lock_irqsave(&gchip->lock, flags); | ||
76 | |||
77 | val = readl(gchip->base + PFR(gpio)); | ||
78 | val |= OFFSET(gpio); | ||
79 | writel(val, gchip->base + PFR(gpio)); | ||
80 | |||
81 | spin_unlock_irqrestore(&gchip->lock, flags); | ||
82 | } | ||
83 | |||
84 | static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) | ||
85 | { | ||
86 | struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); | ||
87 | unsigned long flags; | ||
88 | unsigned char val; | ||
89 | |||
90 | spin_lock_irqsave(&gchip->lock, flags); | ||
91 | |||
92 | val = readl(gchip->base + DDR(gpio)); | ||
93 | val &= ~OFFSET(gpio); | ||
94 | writel(val, gchip->base + DDR(gpio)); | ||
95 | |||
96 | spin_unlock_irqrestore(&gchip->lock, flags); | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int mb86s70_gpio_direction_output(struct gpio_chip *gc, | ||
102 | unsigned gpio, int value) | ||
103 | { | ||
104 | struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); | ||
105 | unsigned long flags; | ||
106 | unsigned char val; | ||
107 | |||
108 | spin_lock_irqsave(&gchip->lock, flags); | ||
109 | |||
110 | val = readl(gchip->base + PDR(gpio)); | ||
111 | if (value) | ||
112 | val |= OFFSET(gpio); | ||
113 | else | ||
114 | val &= ~OFFSET(gpio); | ||
115 | writel(val, gchip->base + PDR(gpio)); | ||
116 | |||
117 | val = readl(gchip->base + DDR(gpio)); | ||
118 | val |= OFFSET(gpio); | ||
119 | writel(val, gchip->base + DDR(gpio)); | ||
120 | |||
121 | spin_unlock_irqrestore(&gchip->lock, flags); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio) | ||
127 | { | ||
128 | struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); | ||
129 | |||
130 | return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio)); | ||
131 | } | ||
132 | |||
133 | static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value) | ||
134 | { | ||
135 | struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc); | ||
136 | unsigned long flags; | ||
137 | unsigned char val; | ||
138 | |||
139 | spin_lock_irqsave(&gchip->lock, flags); | ||
140 | |||
141 | val = readl(gchip->base + PDR(gpio)); | ||
142 | if (value) | ||
143 | val |= OFFSET(gpio); | ||
144 | else | ||
145 | val &= ~OFFSET(gpio); | ||
146 | writel(val, gchip->base + PDR(gpio)); | ||
147 | |||
148 | spin_unlock_irqrestore(&gchip->lock, flags); | ||
149 | } | ||
150 | |||
151 | static int mb86s70_gpio_probe(struct platform_device *pdev) | ||
152 | { | ||
153 | struct mb86s70_gpio_chip *gchip; | ||
154 | struct resource *res; | ||
155 | int ret; | ||
156 | |||
157 | gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL); | ||
158 | if (gchip == NULL) | ||
159 | return -ENOMEM; | ||
160 | |||
161 | platform_set_drvdata(pdev, gchip); | ||
162 | |||
163 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
164 | gchip->base = devm_ioremap_resource(&pdev->dev, res); | ||
165 | if (IS_ERR(gchip->base)) | ||
166 | return PTR_ERR(gchip->base); | ||
167 | |||
168 | gchip->clk = devm_clk_get(&pdev->dev, NULL); | ||
169 | if (IS_ERR(gchip->clk)) | ||
170 | return PTR_ERR(gchip->clk); | ||
171 | |||
172 | clk_prepare_enable(gchip->clk); | ||
173 | |||
174 | spin_lock_init(&gchip->lock); | ||
175 | |||
176 | gchip->gc.direction_output = mb86s70_gpio_direction_output; | ||
177 | gchip->gc.direction_input = mb86s70_gpio_direction_input; | ||
178 | gchip->gc.request = mb86s70_gpio_request; | ||
179 | gchip->gc.free = mb86s70_gpio_free; | ||
180 | gchip->gc.get = mb86s70_gpio_get; | ||
181 | gchip->gc.set = mb86s70_gpio_set; | ||
182 | gchip->gc.label = dev_name(&pdev->dev); | ||
183 | gchip->gc.ngpio = 32; | ||
184 | gchip->gc.owner = THIS_MODULE; | ||
185 | gchip->gc.dev = &pdev->dev; | ||
186 | gchip->gc.base = -1; | ||
187 | |||
188 | platform_set_drvdata(pdev, gchip); | ||
189 | |||
190 | ret = gpiochip_add(&gchip->gc); | ||
191 | if (ret) { | ||
192 | dev_err(&pdev->dev, "couldn't register gpio driver\n"); | ||
193 | clk_disable_unprepare(gchip->clk); | ||
194 | } | ||
195 | |||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | static int mb86s70_gpio_remove(struct platform_device *pdev) | ||
200 | { | ||
201 | struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); | ||
202 | |||
203 | gpiochip_remove(&gchip->gc); | ||
204 | clk_disable_unprepare(gchip->clk); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static const struct of_device_id mb86s70_gpio_dt_ids[] = { | ||
210 | { .compatible = "fujitsu,mb86s70-gpio" }, | ||
211 | { /* sentinel */ } | ||
212 | }; | ||
213 | MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); | ||
214 | |||
215 | static struct platform_driver mb86s70_gpio_driver = { | ||
216 | .driver = { | ||
217 | .name = "mb86s70-gpio", | ||
218 | .of_match_table = mb86s70_gpio_dt_ids, | ||
219 | }, | ||
220 | .probe = mb86s70_gpio_probe, | ||
221 | .remove = mb86s70_gpio_remove, | ||
222 | }; | ||
223 | |||
224 | static int __init mb86s70_gpio_init(void) | ||
225 | { | ||
226 | return platform_driver_register(&mb86s70_gpio_driver); | ||
227 | } | ||
228 | module_init(mb86s70_gpio_init); | ||
229 | |||
230 | MODULE_DESCRIPTION("MB86S7x GPIO Driver"); | ||
231 | MODULE_ALIAS("platform:mb86s70-gpio"); | ||
232 | MODULE_LICENSE("GPL"); | ||