diff options
author | A.s. Dong <aisheng.dong@nxp.com> | 2018-11-10 09:21:18 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2018-11-16 17:09:39 -0500 |
commit | 91393622bca33cac70175e0fdc5a3ec8f9efe08b (patch) | |
tree | c04bb3f91e960630f59a65e69517954f69847458 /drivers/gpio/gpio-vf610.c | |
parent | 1a5287a3dbc34cd0c02c8f64c9131bd23cdfe2bb (diff) |
gpio: vf610: add optional clock support
Some SoCs need the gpio clock to be enabled before accessing
HW registers. This patch add the optional clock handling.
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Stefan Agner <stefan@agner.ch>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: linux-gpio@vger.kernel.org
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-vf610.c')
-rw-r--r-- | drivers/gpio/gpio-vf610.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 5960396c8d9a..1b79ebcfce3e 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Author: Stefan Agner <stefan@agner.ch>. | 7 | * Author: Stefan Agner <stefan@agner.ch>. |
8 | */ | 8 | */ |
9 | #include <linux/bitops.h> | 9 | #include <linux/bitops.h> |
10 | #include <linux/clk.h> | ||
10 | #include <linux/err.h> | 11 | #include <linux/err.h> |
11 | #include <linux/gpio/driver.h> | 12 | #include <linux/gpio/driver.h> |
12 | #include <linux/init.h> | 13 | #include <linux/init.h> |
@@ -32,6 +33,8 @@ struct vf610_gpio_port { | |||
32 | void __iomem *gpio_base; | 33 | void __iomem *gpio_base; |
33 | const struct fsl_gpio_soc_data *sdata; | 34 | const struct fsl_gpio_soc_data *sdata; |
34 | u8 irqc[VF610_GPIO_PER_PORT]; | 35 | u8 irqc[VF610_GPIO_PER_PORT]; |
36 | struct clk *clk_port; | ||
37 | struct clk *clk_gpio; | ||
35 | int irq; | 38 | int irq; |
36 | }; | 39 | }; |
37 | 40 | ||
@@ -271,6 +274,33 @@ static int vf610_gpio_probe(struct platform_device *pdev) | |||
271 | if (port->irq < 0) | 274 | if (port->irq < 0) |
272 | return port->irq; | 275 | return port->irq; |
273 | 276 | ||
277 | port->clk_port = devm_clk_get(&pdev->dev, "port"); | ||
278 | if (!IS_ERR(port->clk_port)) { | ||
279 | ret = clk_prepare_enable(port->clk_port); | ||
280 | if (ret) | ||
281 | return ret; | ||
282 | } else if (port->clk_port == ERR_PTR(-EPROBE_DEFER)) { | ||
283 | /* | ||
284 | * Percolate deferrals, for anything else, | ||
285 | * just live without the clocking. | ||
286 | */ | ||
287 | return PTR_ERR(port->clk_port); | ||
288 | } | ||
289 | |||
290 | port->clk_gpio = devm_clk_get(&pdev->dev, "gpio"); | ||
291 | if (!IS_ERR(port->clk_gpio)) { | ||
292 | ret = clk_prepare_enable(port->clk_gpio); | ||
293 | if (ret) { | ||
294 | clk_disable_unprepare(port->clk_port); | ||
295 | return ret; | ||
296 | } | ||
297 | } else if (port->clk_gpio == ERR_PTR(-EPROBE_DEFER)) { | ||
298 | clk_disable_unprepare(port->clk_port); | ||
299 | return PTR_ERR(port->clk_gpio); | ||
300 | } | ||
301 | |||
302 | platform_set_drvdata(pdev, port); | ||
303 | |||
274 | gc = &port->gc; | 304 | gc = &port->gc; |
275 | gc->of_node = np; | 305 | gc->of_node = np; |
276 | gc->parent = dev; | 306 | gc->parent = dev; |
@@ -305,12 +335,26 @@ static int vf610_gpio_probe(struct platform_device *pdev) | |||
305 | return 0; | 335 | return 0; |
306 | } | 336 | } |
307 | 337 | ||
338 | static int vf610_gpio_remove(struct platform_device *pdev) | ||
339 | { | ||
340 | struct vf610_gpio_port *port = platform_get_drvdata(pdev); | ||
341 | |||
342 | gpiochip_remove(&port->gc); | ||
343 | if (!IS_ERR(port->clk_port)) | ||
344 | clk_disable_unprepare(port->clk_port); | ||
345 | if (!IS_ERR(port->clk_gpio)) | ||
346 | clk_disable_unprepare(port->clk_gpio); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
308 | static struct platform_driver vf610_gpio_driver = { | 351 | static struct platform_driver vf610_gpio_driver = { |
309 | .driver = { | 352 | .driver = { |
310 | .name = "gpio-vf610", | 353 | .name = "gpio-vf610", |
311 | .of_match_table = vf610_gpio_dt_ids, | 354 | .of_match_table = vf610_gpio_dt_ids, |
312 | }, | 355 | }, |
313 | .probe = vf610_gpio_probe, | 356 | .probe = vf610_gpio_probe, |
357 | .remove = vf610_gpio_remove, | ||
314 | }; | 358 | }; |
315 | 359 | ||
316 | builtin_platform_driver(vf610_gpio_driver); | 360 | builtin_platform_driver(vf610_gpio_driver); |