Revert "This driver allows GPIO lines to be used as reset signals."

This reverts commit be455a5216.

Change-Id: Iec06e26d4eb0406e8021ef5c9d5944c58d517d83
This commit is contained in:
Chris
2023-05-16 17:14:51 +09:00
parent 844f341f6b
commit 910fc996da
5 changed files with 0 additions and 539 deletions

View File

@@ -1,18 +0,0 @@
In the descriptions below <line-name> is the name of the device tree node
describing the reset line.
What: /sys/bus/platform/devices/gpio-reset.<ID>/<line-name>/duration_ms
Date: February 2014
Contact: Martin Fuzzey <mfuzzey@parkeon.com>
Description: Allows reset duration to be configured
Read: returns reset duration in ms (decimal)
Write: sets new resst duration in ms (decimal)
What: /sys/bus/platform/devices/gpio-reset.<ID>/<line-name>/control
Date: February 2014
Contact: Martin Fuzzey <mfuzzey@parkeon.com>
Description: Allows reset line state to be controlled
Write only accepting the following strings:
"reset" : Line will be asserted during the reset duration then deasserted
"assert" : Line will be asserted until next write operation
"deassert" : Line will be deasserted until the next write operation

View File

@@ -1,44 +0,0 @@
Generic GPIO based Reset Controller
======================================
Please also refer to reset.txt in this directory for common reset
controller binding usage.
The parent node only needs a compatible property "linux,gpio-reset".
Eaach reset line is described by a child node with the following properties:
Required properties:
- gpios : phandle of the GPIO line to use
Optional properties:
- asserted-state: 0 => line low to reset, 1 => line high to reset. Defalut 0
- duration-ms : Number of ms the line should be asserted while resetting (default 1)
- auto : boolean property - if present a reset will be done on boot
- #reset-cells: 0 if drivers can trigger reset via phandle
example:
gpio-reset {
compatible = "linux,gpio-reset";
wifi {
gpios = <&gpio2 1 0>;
asserted-state = <0>;
duration-ms = <100>;
auto;
};
ethernet_phy_reset:ethernet_phy {
#reset-cells = <0>;
gpios = <&gpio7 6 0>;
asserted-state = <0>;
duration-ms = <100>;
};
};
Note that, although this controller may be used as part of the reset
framework, meaning that a device driver may request the reset using the
child node's phandle it (ethernet example above) it can also be used
in a standalone mode where the reset is performed automatically at boot
or from userspace by sysfs. This is particularly for devices that require
reset but are on discoverable busses (eg SDIO, USB).

View File

@@ -14,19 +14,6 @@ menuconfig RESET_CONTROLLER
if RESET_CONTROLLER
config GPIO_RESET_CONTROLLER
tristate "GPIO reset controller"
help
Reset controller using GPIO lines
There are two main methods of using this controller:
* As a reset controller within the reset framework allowing device
drivers to request a hardware reset of their devices.
* As a standalone driver performing reset at boot or upon userspace
request (via sysfs)
The second method is suitable for devices on discoverable busses
(SDIO, USB)
config RESET_ATH79
bool "AR71xx Reset Driver" if COMPILE_TEST
default ATH79

View File

@@ -13,4 +13,3 @@ obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
obj-$(CONFIG_GPIO_RESET_CONTROLLER) += gpio-reset.o

View File

@@ -1,463 +0,0 @@
/*
* Copyright 2014 Parkeon
* Martin Fuzzey <mfuzzey@parkeon.com>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*
* Driver allowing arbitrary hardware to be reset by GPIO signals.
* The reset may be triggered in several ways:
* At boot time (if configured in DT)
* On userspace request via sysfs
* By a driver using the reset controller framework
*
* The first two methods are supplied for devices on discoverable busses
* needing an external reset (eg some SDIO modules, USB hub chips)
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
struct gpio_reset_priv;
struct gpio_reset_line {
struct kobject kobj;
struct gpio_reset_priv *priv;
const char *name;
int gpio;
uint32_t asserted_value;
uint32_t duration_ms;
#ifdef CONFIG_RESET_CONTROLLER
struct reset_controller_dev rcdev;
#endif
};
#define kobj_to_gpio_reset_line(x) container_of(x, struct gpio_reset_line, kobj)
struct gpio_reset_priv {
struct kref refcount;
struct device *dev;
int num_lines;
struct gpio_reset_line lines[];
};
struct gpio_reset_attribute {
struct attribute attr;
ssize_t (*show)(struct gpio_reset_line *line,
struct gpio_reset_attribute *attr, char *buf);
ssize_t (*store)(struct gpio_reset_line *line,
struct gpio_reset_attribute *attr,
const char *buf, size_t count);
};
#define to_gpio_reset_attr(x) container_of(x, struct gpio_reset_attribute, attr)
static void gpio_reset_assert(struct gpio_reset_line *line)
{
gpio_set_value(line->gpio, line->asserted_value);
}
static void gpio_reset_deassert(struct gpio_reset_line *line)
{
gpio_set_value(line->gpio, !line->asserted_value);
}
static void gpio_reset_reset(struct gpio_reset_line *line)
{
dev_info(line->priv->dev, "Resetting '%s' (%dms)",
line->name, line->duration_ms);
gpio_reset_assert(line);
msleep(line->duration_ms);
gpio_reset_deassert(line);
}
static void gpio_reset_free_priv(struct kref *ref)
{
struct gpio_reset_priv *priv = container_of(ref,
struct gpio_reset_priv, refcount);
kfree(priv);
}
static void gpio_reset_release_kobj(struct kobject *kobj)
{
struct gpio_reset_line *line;
line = kobj_to_gpio_reset_line(kobj);
kref_put(&line->priv->refcount, gpio_reset_free_priv);
}
#ifdef CONFIG_SYSFS
static ssize_t gpio_reset_attr_show(struct kobject *kobj,
struct attribute *attr,
char *buf)
{
struct gpio_reset_attribute *attribute;
struct gpio_reset_line *line;
attribute = to_gpio_reset_attr(attr);
line = kobj_to_gpio_reset_line(kobj);
if (!attribute->show)
return -EIO;
return attribute->show(line, attribute, buf);
}
static ssize_t gpio_reset_attr_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t len)
{
struct gpio_reset_attribute *attribute;
struct gpio_reset_line *line;
attribute = to_gpio_reset_attr(attr);
line = kobj_to_gpio_reset_line(kobj);
if (!attribute->store)
return -EIO;
return attribute->store(line, attribute, buf, len);
}
static ssize_t control_store(struct gpio_reset_line *line,
struct gpio_reset_attribute *attr, const char *buf, size_t count)
{
char action[10];
char *eol;
strncpy(action, buf, min(count, sizeof(action)));
action[sizeof(action) - 1] = '\0';
eol = strrchr(action, '\n');
if (eol)
*eol = '\0';
if (!strcmp("reset", action))
gpio_reset_reset(line);
else if (!strcmp("assert", action))
gpio_reset_assert(line);
else if (!strcmp("deassert", action))
gpio_reset_deassert(line);
else
return -EINVAL;
return count;
}
static ssize_t duration_ms_show(struct gpio_reset_line *line,
struct gpio_reset_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", line->duration_ms);
}
static ssize_t duration_ms_store(struct gpio_reset_line *line,
struct gpio_reset_attribute *attr, const char *buf, size_t count)
{
int ret;
ret = kstrtouint(buf, 0, &line->duration_ms);
if (ret != 1)
return -EINVAL;
return count;
}
static struct gpio_reset_attribute control_attribute = __ATTR_WO(control);
static struct gpio_reset_attribute duration_attribute = __ATTR_RW(duration_ms);
static struct attribute *gpio_reset_attrs[] = {
&control_attribute.attr,
&duration_attribute.attr,
NULL
};
static const struct sysfs_ops gpio_reset_sysfs_ops = {
.show = gpio_reset_attr_show,
.store = gpio_reset_attr_store,
};
static struct kobj_type gpio_reset_ktype = {
.release = gpio_reset_release_kobj,
.sysfs_ops = &gpio_reset_sysfs_ops,
.default_attrs = gpio_reset_attrs,
};
static int gpio_reset_create_sysfs(struct gpio_reset_line *line)
{
int ret;
ret = kobject_init_and_add(&line->kobj, &gpio_reset_ktype,
&line->priv->dev->kobj, "reset-%s", line->name);
kref_get(&line->priv->refcount); /* kobject part of private structure */
if (ret) {
kobject_put(&line->kobj);
return ret;
}
kobject_uevent(&line->kobj, KOBJ_ADD);
return 0;
}
static void gpio_reset_destroy_sysfs(struct gpio_reset_line *line)
{
kobject_put(&line->kobj);
}
#else
static int gpio_reset_create_sysfs(struct gpio_reset_line *line)
{
return 0;
}
static void gpio_reset_destroy_sysfs(struct gpio_reset_line *line)
{
}
#endif /* CONFIG_SYSFS */
#ifdef CONFIG_RESET_CONTROLLER
#define rcdev_to_gpio_reset_line(x) \
container_of(x, struct gpio_reset_line, rcdev)
static int gpio_reset_controller_assert(struct reset_controller_dev *rcdev,
unsigned long sw_reset_idx)
{
struct gpio_reset_line *line = rcdev_to_gpio_reset_line(rcdev);
gpio_reset_assert(line);
return 0;
}
static int gpio_reset_controller_deassert(struct reset_controller_dev *rcdev,
unsigned long sw_reset_idx)
{
struct gpio_reset_line *line = rcdev_to_gpio_reset_line(rcdev);
gpio_reset_deassert(line);
return 0;
}
static int gpio_reset_controller_reset(struct reset_controller_dev *rcdev,
unsigned long sw_reset_idx)
{
struct gpio_reset_line *line = rcdev_to_gpio_reset_line(rcdev);
gpio_reset_reset(line);
return 0;
}
static struct reset_control_ops gpio_reset_ops = {
.assert = gpio_reset_controller_assert,
.deassert = gpio_reset_controller_deassert,
.reset = gpio_reset_controller_reset,
};
int gpio_reset_nooarg_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;
}
/* We register one controller per line rather than a single
* global controller so that drivers my directly reference the
* phandle of the gpio_reset subnode rather than having to know
* the index.
*/
static int gpio_reset_register_controller(
struct device_node *np,
struct gpio_reset_line *line)
{
line->rcdev.of_node = np;
line->rcdev.nr_resets = 1;
line->rcdev.ops = &gpio_reset_ops;
line->rcdev.of_xlate = gpio_reset_nooarg_xlate;
return reset_controller_register(&line->rcdev);
}
static void gpio_reset_unregister_controller(struct gpio_reset_line *line)
{
if (line->rcdev.nr_resets)
reset_controller_unregister(&line->rcdev);
}
#else
static int gpio_reset_register_controller(
struct device_node *np,
struct gpio_reset_line *line)
{
return 0;
}
static void gpio_reset_unregister_controller(struct gpio_reset_line *line)
{
}
#endif /* CONFIG_RESET_CONTROLLER */
static int gpio_reset_init_line(
struct device_node *np,
struct gpio_reset_line *line)
{
int ret;
struct device *dev = line->priv->dev;
line->name = np->name;
line->gpio = of_get_gpio(np, 0);
if (!gpio_is_valid(line->gpio)) {
dev_warn(dev, "Invalid reset gpio for '%s'", np->name);
return 0;
}
line->duration_ms = 1;
of_property_read_u32(np, "asserted-state", &line->asserted_value);
of_property_read_u32(np, "duration-ms", &line->duration_ms);
ret = devm_gpio_request_one(dev, line->gpio,
line->asserted_value ? GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
line->name);
if (ret)
return ret;
ret = gpio_reset_create_sysfs(line);
if (ret)
return ret;
ret = gpio_reset_register_controller(np, line);
if (ret)
return ret;
if (of_property_read_bool(np, "auto"))
gpio_reset_reset(line);
return 0;
}
static void gpio_reset_free_line(struct gpio_reset_line *line)
{
gpio_reset_destroy_sysfs(line);
gpio_reset_unregister_controller(line);
}
static int gpio_reset_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node, *child;
struct gpio_reset_priv *priv;
struct gpio_reset_line *line;
int num_lines;
int ret;
num_lines = of_get_available_child_count(np);
if (!num_lines)
return -ENODEV;
for_each_available_child_of_node(np, child) {
ret = of_get_gpio(child, 0);
if (ret == -EPROBE_DEFER)
return ret;
}
priv = kzalloc(sizeof(*priv) + sizeof(*line) * num_lines, GFP_KERNEL);
if (!priv)
return -ENOMEM;
kref_init(&priv->refcount);
priv->dev = &pdev->dev;
priv->num_lines = num_lines;
line = priv->lines;
for_each_available_child_of_node(np, child) {
line->priv = priv;
ret = gpio_reset_init_line(child, line);
if (ret)
goto rollback;
line++;
}
platform_set_drvdata(pdev, priv);
return 0;
rollback:
while (line >= priv->lines)
gpio_reset_free_line(line--);
kref_put(&priv->refcount, gpio_reset_free_priv);
return ret;
}
static int gpio_reset_remove(struct platform_device *pdev)
{
struct gpio_reset_priv *priv = platform_get_drvdata(pdev);
int i;
for (i = 0; i < priv->num_lines; i++)
gpio_reset_free_line(&priv->lines[i]);
kref_put(&priv->refcount, gpio_reset_free_priv);
return 0;
}
static const struct of_device_id gpio_reset_dt_ids[] = {
{ .compatible = "linux,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 = gpio_reset_dt_ids,
},
};
static int __init gpio_reset_init(void)
{
return platform_driver_register(&gpio_reset_driver);
}
subsys_initcall(gpio_reset_init);
static void __exit gpio_reset_exit(void)
{
platform_driver_unregister(&gpio_reset_driver);
}
module_exit(gpio_reset_exit);
MODULE_AUTHOR("Martin Fuzzey <mfuzzey@parkeon.com>");
MODULE_DESCRIPTION("GPIO reset controller");
MODULE_LICENSE("GPL");