diff options
author | Peter Robinson <pbrobinson@gmail.com> | 2013-09-04 02:43:18 +0100 |
---|---|---|
committer | Peter Robinson <pbrobinson@gmail.com> | 2013-09-04 02:43:18 +0100 |
commit | bad69a54fc999f7ed3871b472a31c1a760ed1e81 (patch) | |
tree | 16a0df217b495c859746080ca7f3cc4e1ff26366 /0001-reset-Add-driver-for-gpio-controlled-reset-pins.patch | |
parent | 7ad7e4c4014b96bb176b000b8be71063cf5fc60f (diff) | |
download | kernel-bad69a54fc999f7ed3871b472a31c1a760ed1e81.tar.gz kernel-bad69a54fc999f7ed3871b472a31c1a760ed1e81.tar.xz kernel-bad69a54fc999f7ed3871b472a31c1a760ed1e81.zip |
Add patch set to fix MMC on AM33xx, Add basic support for BeagleBone Black
Diffstat (limited to '0001-reset-Add-driver-for-gpio-controlled-reset-pins.patch')
-rw-r--r-- | 0001-reset-Add-driver-for-gpio-controlled-reset-pins.patch | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/0001-reset-Add-driver-for-gpio-controlled-reset-pins.patch b/0001-reset-Add-driver-for-gpio-controlled-reset-pins.patch new file mode 100644 index 000000000..e5661aef1 --- /dev/null +++ b/0001-reset-Add-driver-for-gpio-controlled-reset-pins.patch @@ -0,0 +1,265 @@ +From 31bacc8256b3ddb19269a3a1c74b0ba3851d1e19 Mon Sep 17 00:00:00 2001 +From: Philipp Zabel <p.zabel@pengutronix.de> +Date: Tue, 28 May 2013 17:06:15 +0200 +Subject: [PATCH] reset: Add driver for gpio-controlled reset pins + +This driver implements a reset controller device that toggle a gpio +connected to a reset pin of a peripheral IC. The delay between assertion +and de-assertion of the reset signal can be configured via device tree. + +Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> +Reviewed-by: Stephen Warren <swarren@nvidia.com> +--- + .../devicetree/bindings/reset/gpio-reset.txt | 35 +++++ + drivers/reset/Kconfig | 11 ++ + drivers/reset/Makefile | 1 + + drivers/reset/gpio-reset.c | 169 +++++++++++++++++++++ + 4 files changed, 216 insertions(+) + create mode 100644 Documentation/devicetree/bindings/reset/gpio-reset.txt + create mode 100644 drivers/reset/gpio-reset.c + +diff --git a/Documentation/devicetree/bindings/reset/gpio-reset.txt b/Documentation/devicetree/bindings/reset/gpio-reset.txt +new file mode 100644 +index 0000000..bca5348 +--- /dev/null ++++ b/Documentation/devicetree/bindings/reset/gpio-reset.txt +@@ -0,0 +1,35 @@ ++GPIO reset controller ++===================== ++ ++A GPIO reset controller controls a single GPIO that is connected to the reset ++pin of a peripheral IC. Please also refer to reset.txt in this directory for ++common reset controller binding usage. ++ ++Required properties: ++- compatible: Should be "gpio-reset" ++- reset-gpios: A gpio used as reset line. The gpio specifier for this property ++ depends on the gpio controller that provides the gpio. ++- #reset-cells: 0, see below ++ ++Optional properties: ++- reset-delay-us: delay in microseconds. The gpio reset line will be asserted for ++ this duration to reset. ++- initially-in-reset: boolean. If not set, the initial state should be a ++ deasserted reset line. If this property exists, the ++ reset line should be kept in reset. ++ ++example: ++ ++sii902x_reset: gpio-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <10000>; ++ initially-in-reset; ++ #reset-cells = <0>; ++}; ++ ++/* Device with nRESET pin connected to GPIO5_0 */ ++sii902x@39 { ++ /* ... */ ++ resets = <&sii902x_reset>; /* active-low GPIO5_0, 10 ms delay */ ++}; +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +index c9d04f7..1a862df 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -11,3 +11,14 @@ menuconfig RESET_CONTROLLER + via GPIOs or SoC-internal reset controller modules. + + If unsure, say no. ++ ++if RESET_CONTROLLER ++ ++config RESET_GPIO ++ tristate "GPIO reset controller support" ++ depends on GPIOLIB && OF ++ help ++ This driver provides support for reset lines that are controlled ++ directly by GPIOs. ++ ++endif +diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile +index 1e2d83f..b854f20 100644 +--- a/drivers/reset/Makefile ++++ b/drivers/reset/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_RESET_CONTROLLER) += core.o ++obj-$(CONFIG_RESET_GPIO) += gpio-reset.o +diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c +new file mode 100644 +index 0000000..acc1076 +--- /dev/null ++++ b/drivers/reset/gpio-reset.c +@@ -0,0 +1,169 @@ ++/* ++ * GPIO Reset Controller driver ++ * ++ * Copyright 2013 Philipp Zabel, Pengutronix ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++#include <linux/delay.h> ++#include <linux/err.h> ++#include <linux/gpio.h> ++#include <linux/module.h> ++#include <linux/of_gpio.h> ++#include <linux/platform_device.h> ++#include <linux/reset-controller.h> ++ ++struct gpio_reset_data { ++ struct reset_controller_dev rcdev; ++ unsigned int gpio; ++ bool active_low; ++ u32 delay_us; ++}; ++ ++static void __gpio_reset_set(struct reset_controller_dev *rcdev, int asserted) ++{ ++ struct gpio_reset_data *drvdata = container_of(rcdev, ++ struct gpio_reset_data, rcdev); ++ int value = asserted; ++ ++ if (drvdata->active_low) ++ value = !value; ++ ++ gpio_set_value(drvdata->gpio, value); ++} ++ ++static int gpio_reset(struct reset_controller_dev *rcdev, unsigned long id) ++{ ++ struct gpio_reset_data *drvdata = container_of(rcdev, ++ struct gpio_reset_data, rcdev); ++ ++ if (drvdata->delay_us < 0) ++ return -ENOSYS; ++ ++ __gpio_reset_set(rcdev, 1); ++ udelay(drvdata->delay_us); ++ __gpio_reset_set(rcdev, 0); ++ ++ return 0; ++} ++ ++static int gpio_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ __gpio_reset_set(rcdev, 1); ++ ++ return 0; ++} ++ ++static int gpio_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ __gpio_reset_set(rcdev, 0); ++ ++ return 0; ++} ++ ++static struct reset_control_ops gpio_reset_ops = { ++ .reset = gpio_reset, ++ .assert = gpio_reset_assert, ++ .deassert = gpio_reset_deassert, ++}; ++ ++static int of_gpio_reset_xlate(struct reset_controller_dev *rcdev, ++ const struct of_phandle_args *reset_spec) ++{ ++ if (WARN_ON(reset_spec->args_count != 0)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int gpio_reset_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct gpio_reset_data *drvdata; ++ enum of_gpio_flags flags; ++ unsigned long gpio_flags; ++ bool initially_in_reset; ++ int ret; ++ ++ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); ++ if (drvdata == NULL) ++ return -ENOMEM; ++ ++ if (of_gpio_named_count(np, "reset-gpios") != 1) ++ return -EINVAL; ++ ++ drvdata->gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags); ++ if (drvdata->gpio == -EPROBE_DEFER) { ++ return drvdata->gpio; ++ } else if (!gpio_is_valid(drvdata->gpio)) { ++ dev_err(&pdev->dev, "invalid reset gpio: %d\n", drvdata->gpio); ++ return drvdata->gpio; ++ } ++ ++ drvdata->active_low = flags & OF_GPIO_ACTIVE_LOW; ++ ++ ret = of_property_read_u32(np, "reset-delay-us", &drvdata->delay_us); ++ if (ret < 0) ++ return ret; ++ ++ initially_in_reset = of_property_read_bool(np, "initially-in-reset"); ++ if (drvdata->active_low ^ initially_in_reset) ++ gpio_flags = GPIOF_OUT_INIT_HIGH; ++ else ++ gpio_flags = GPIOF_OUT_INIT_LOW; ++ ++ ret = devm_gpio_request_one(&pdev->dev, drvdata->gpio, gpio_flags, NULL); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request gpio %d: %d\n", ++ drvdata->gpio, ret); ++ return ret; ++ } ++ ++ drvdata->rcdev.of_node = np; ++ drvdata->rcdev.owner = THIS_MODULE; ++ drvdata->rcdev.nr_resets = 1; ++ drvdata->rcdev.ops = &gpio_reset_ops; ++ drvdata->rcdev.of_xlate = of_gpio_reset_xlate; ++ reset_controller_register(&drvdata->rcdev); ++ ++ platform_set_drvdata(pdev, drvdata); ++ ++ return 0; ++} ++ ++static int gpio_reset_remove(struct platform_device *pdev) ++{ ++ struct gpio_reset_data *drvdata = platform_get_drvdata(pdev); ++ ++ reset_controller_unregister(&drvdata->rcdev); ++ ++ return 0; ++} ++ ++static struct of_device_id gpio_reset_dt_ids[] = { ++ { .compatible = "gpio-reset" }, ++ { } ++}; ++ ++static struct platform_driver gpio_reset_driver = { ++ .probe = gpio_reset_probe, ++ .remove = gpio_reset_remove, ++ .driver = { ++ .name = "gpio-reset", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(gpio_reset_dt_ids), ++ }, ++}; ++ ++module_platform_driver(gpio_reset_driver); ++ ++MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>"); ++MODULE_DESCRIPTION("gpio reset controller"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:gpio-reset"); ++MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids); +-- +1.8.2.1 + |