Reset controller updates for v6.9
Enable support for the Sophgo SG2042 reset controller via reset-simple, add a GPIO-based reset controller criver for shared GPIO resets, extract an of_phandle_args_equal() helper function out of cpufreq, and use it in reset-gpio. Based on v6.8-rc5 because reset-gpio depends on commits in the gpio-driver-h-stubs-for-v6.8-rc5 tag. -----BEGIN PGP SIGNATURE----- iI0EABYIADUWIQRRO6F6WdpH1R0vGibVhaclGDdiwAUCZeG3iBcccC56YWJlbEBw ZW5ndXRyb25peC5kZQAKCRDVhaclGDdiwDaFAP49U+xyhlQgl60NUfCBqZnFOKWo gJ0X1odJGGCwYC2JKwD8DcYgr0JjANF2WomlkgvyRHRWKe/1bPM087T4Ds1oYwk= =q8fL -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmXl+QMACgkQYKtH/8kJ UifOJg//civZQJ5QK2kYAr4Hzn0F0pQ9yFqIB7ZCpRvmghbvd2pCQ71qWVZd1JDh 0zk0As6izc3dSiSpmJgtL6XEg7FP+lRUsWDXimGXgRqRNQuVLiEq3XJlklu1HjQP Ozwv9i2mcP6wN9uwyM+jnoN3ArNDzpx5eVqX7XaD+qkLOgys3sVN1UYSZ+bWqsy/ 4ND7C5044uN6msXx+Yq4aw7+ogIQsFaTwQ2JYRIcDDmt449JkC7uD0KLxTK0dFuP +cMcYCv2vDDyC5Fr+mtIUhdJqttdRft3s5aO3lAO22noKr1qBGiZjennbB3dD3zA 9Ll/HlohoYWaPwJN5pVeBQppKvi2C4xxAoUhLYGO4JwmQNBz0rHaNjqy2GCJKLZZ 7DveW0h0Qpyu3gYfWjQHGFoKy4/HGp8c6C4emMBtqzkxaMj8H4ZueUtwG1qC7eGL y/yzz4lO47nMeISExdgDhe3CPrjomd72jPSJOB0Q8nTt9m7/iLzVMkcg1toSj8Kt eX+ajWv0I+02Dh2jLqOMHTvE+a18ieodl8SAvSXGmkmUbQ203kvx4giWxNIb46Iz dlLkh/xdUoNIqMDuKpz04doraQ0QkNRZU+js30quVD31ouQfTD9K9/kr5Gjb2D6o ZdAnOq0ONIxHvlp27qX2VylXiXilsDEBnSyvRHFY0CwNwcGBBxo= =oSDS -----END PGP SIGNATURE----- Merge tag 'reset-for-v6.9' of git://git.pengutronix.de/pza/linux into soc/late Reset controller updates for v6.9 Enable support for the Sophgo SG2042 reset controller via reset-simple, add a GPIO-based reset controller criver for shared GPIO resets, extract an of_phandle_args_equal() helper function out of cpufreq, and use it in reset-gpio. Based on v6.8-rc5 because reset-gpio depends on commits in the gpio-driver-h-stubs-for-v6.8-rc5 tag. * tag 'reset-for-v6.9' of git://git.pengutronix.de/pza/linux: reset: Instantiate reset GPIO controller for shared reset-gpios reset: gpio: Add GPIO-based reset controller cpufreq: do not open-code of_phandle_args_equal() of: Add of_phandle_args_equal() helper reset: simple: add support for Sophgo SG2042 dt-bindings: reset: sophgo: support SG2042 Link: https://lore.kernel.org/r/20240301111300.4038207-1-p.zabel@pengutronix.de Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
724ad89f83
@ -0,0 +1,35 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/reset/sophgo,sg2042-reset.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Sophgo SG2042 SoC Reset Controller
|
||||
|
||||
maintainers:
|
||||
- Chen Wang <unicorn_wang@outlook.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sophgo,sg2042-reset
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#reset-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
rstgen: reset-controller@c00 {
|
||||
compatible = "sophgo,sg2042-reset";
|
||||
reg = <0xc00 0xc>;
|
||||
#reset-cells = <1>;
|
||||
};
|
@ -8911,6 +8911,11 @@ F: Documentation/i2c/muxes/i2c-mux-gpio.rst
|
||||
F: drivers/i2c/muxes/i2c-mux-gpio.c
|
||||
F: include/linux/platform_data/i2c-mux-gpio.h
|
||||
|
||||
GENERIC GPIO RESET DRIVER
|
||||
M: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||
S: Maintained
|
||||
F: drivers/reset/reset-gpio.c
|
||||
|
||||
GENERIC HDLC (WAN) DRIVERS
|
||||
M: Krzysztof Halasa <khc@pm.waw.pl>
|
||||
S: Maintained
|
||||
|
@ -66,6 +66,15 @@ config RESET_BRCMSTB_RESCAL
|
||||
This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on
|
||||
BCM7216.
|
||||
|
||||
config RESET_GPIO
|
||||
tristate "GPIO reset controller"
|
||||
help
|
||||
This enables a generic reset controller for resets attached via
|
||||
GPIOs. Typically for OF platforms this driver expects "reset-gpios"
|
||||
property.
|
||||
|
||||
If compiled as module, it will be called reset-gpio.
|
||||
|
||||
config RESET_HSDK
|
||||
bool "Synopsys HSDK Reset Driver"
|
||||
depends on HAS_IOMEM
|
||||
@ -213,7 +222,7 @@ config RESET_SCMI
|
||||
|
||||
config RESET_SIMPLE
|
||||
bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT
|
||||
default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
|
||||
default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_SOPHGO || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
This enables a simple reset controller driver for reset lines that
|
||||
@ -228,6 +237,7 @@ config RESET_SIMPLE
|
||||
- RCC reset controller in STM32 MCUs
|
||||
- Allwinner SoCs
|
||||
- SiFive FU740 SoCs
|
||||
- Sophgo SoCs
|
||||
|
||||
config RESET_SOCFPGA
|
||||
bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA)
|
||||
|
@ -11,6 +11,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
|
||||
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
|
||||
obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o
|
||||
obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
|
||||
obj-$(CONFIG_RESET_GPIO) += reset-gpio.o
|
||||
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
|
||||
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
|
||||
obj-$(CONFIG_RESET_INTEL_GW) += reset-intel-gw.o
|
||||
|
@ -5,14 +5,19 @@
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*/
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
@ -23,6 +28,11 @@ static LIST_HEAD(reset_controller_list);
|
||||
static DEFINE_MUTEX(reset_lookup_mutex);
|
||||
static LIST_HEAD(reset_lookup_list);
|
||||
|
||||
/* Protects reset_gpio_lookup_list */
|
||||
static DEFINE_MUTEX(reset_gpio_lookup_mutex);
|
||||
static LIST_HEAD(reset_gpio_lookup_list);
|
||||
static DEFINE_IDA(reset_gpio_ida);
|
||||
|
||||
/**
|
||||
* struct reset_control - a reset control
|
||||
* @rcdev: a pointer to the reset controller device
|
||||
@ -63,6 +73,16 @@ struct reset_control_array {
|
||||
struct reset_control *rstc[] __counted_by(num_rstcs);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct reset_gpio_lookup - lookup key for ad-hoc created reset-gpio devices
|
||||
* @of_args: phandle to the reset controller with all the args like GPIO number
|
||||
* @list: list entry for the reset_gpio_lookup_list
|
||||
*/
|
||||
struct reset_gpio_lookup {
|
||||
struct of_phandle_args of_args;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static const char *rcdev_name(struct reset_controller_dev *rcdev)
|
||||
{
|
||||
if (rcdev->dev)
|
||||
@ -71,6 +91,9 @@ static const char *rcdev_name(struct reset_controller_dev *rcdev)
|
||||
if (rcdev->of_node)
|
||||
return rcdev->of_node->full_name;
|
||||
|
||||
if (rcdev->of_args)
|
||||
return rcdev->of_args->np->full_name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -99,6 +122,9 @@ static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
|
||||
*/
|
||||
int reset_controller_register(struct reset_controller_dev *rcdev)
|
||||
{
|
||||
if (rcdev->of_node && rcdev->of_args)
|
||||
return -EINVAL;
|
||||
|
||||
if (!rcdev->of_xlate) {
|
||||
rcdev->of_reset_n_cells = 1;
|
||||
rcdev->of_xlate = of_reset_simple_xlate;
|
||||
@ -813,12 +839,171 @@ static void __reset_control_put_internal(struct reset_control *rstc)
|
||||
kref_put(&rstc->refcnt, __reset_control_release);
|
||||
}
|
||||
|
||||
static int __reset_add_reset_gpio_lookup(int id, struct device_node *np,
|
||||
unsigned int gpio,
|
||||
unsigned int of_flags)
|
||||
{
|
||||
const struct fwnode_handle *fwnode = of_fwnode_handle(np);
|
||||
unsigned int lookup_flags;
|
||||
const char *label_tmp;
|
||||
|
||||
/*
|
||||
* Later we map GPIO flags between OF and Linux, however not all
|
||||
* constants from include/dt-bindings/gpio/gpio.h and
|
||||
* include/linux/gpio/machine.h match each other.
|
||||
*/
|
||||
if (of_flags > GPIO_ACTIVE_LOW) {
|
||||
pr_err("reset-gpio code does not support GPIO flags %u for GPIO %u\n",
|
||||
of_flags, gpio);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct gpio_device *gdev __free(gpio_device_put) = gpio_device_find_by_fwnode(fwnode);
|
||||
if (!gdev)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
label_tmp = gpio_device_get_label(gdev);
|
||||
if (!label_tmp)
|
||||
return -EINVAL;
|
||||
|
||||
char *label __free(kfree) = kstrdup(label_tmp, GFP_KERNEL);
|
||||
if (!label)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Size: one lookup entry plus sentinel */
|
||||
struct gpiod_lookup_table *lookup __free(kfree) = kzalloc(struct_size(lookup, table, 2),
|
||||
GFP_KERNEL);
|
||||
if (!lookup)
|
||||
return -ENOMEM;
|
||||
|
||||
lookup->dev_id = kasprintf(GFP_KERNEL, "reset-gpio.%d", id);
|
||||
if (!lookup->dev_id)
|
||||
return -ENOMEM;
|
||||
|
||||
lookup_flags = GPIO_PERSISTENT;
|
||||
lookup_flags |= of_flags & GPIO_ACTIVE_LOW;
|
||||
lookup->table[0] = GPIO_LOOKUP(no_free_ptr(label), gpio, "reset",
|
||||
lookup_flags);
|
||||
|
||||
/* Not freed on success, because it is persisent subsystem data. */
|
||||
gpiod_add_lookup_table(no_free_ptr(lookup));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @args: phandle to the GPIO provider with all the args like GPIO number
|
||||
*/
|
||||
static int __reset_add_reset_gpio_device(const struct of_phandle_args *args)
|
||||
{
|
||||
struct reset_gpio_lookup *rgpio_dev;
|
||||
struct platform_device *pdev;
|
||||
int id, ret;
|
||||
|
||||
/*
|
||||
* Currently only #gpio-cells=2 is supported with the meaning of:
|
||||
* args[0]: GPIO number
|
||||
* args[1]: GPIO flags
|
||||
* TODO: Handle other cases.
|
||||
*/
|
||||
if (args->args_count != 2)
|
||||
return -ENOENT;
|
||||
|
||||
/*
|
||||
* Registering reset-gpio device might cause immediate
|
||||
* bind, resulting in its probe() registering new reset controller thus
|
||||
* taking reset_list_mutex lock via reset_controller_register().
|
||||
*/
|
||||
lockdep_assert_not_held(&reset_list_mutex);
|
||||
|
||||
mutex_lock(&reset_gpio_lookup_mutex);
|
||||
|
||||
list_for_each_entry(rgpio_dev, &reset_gpio_lookup_list, list) {
|
||||
if (args->np == rgpio_dev->of_args.np) {
|
||||
if (of_phandle_args_equal(args, &rgpio_dev->of_args))
|
||||
goto out; /* Already on the list, done */
|
||||
}
|
||||
}
|
||||
|
||||
id = ida_alloc(&reset_gpio_ida, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
ret = id;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
/* Not freed on success, because it is persisent subsystem data. */
|
||||
rgpio_dev = kzalloc(sizeof(*rgpio_dev), GFP_KERNEL);
|
||||
if (!rgpio_dev) {
|
||||
ret = -ENOMEM;
|
||||
goto err_ida_free;
|
||||
}
|
||||
|
||||
ret = __reset_add_reset_gpio_lookup(id, args->np, args->args[0],
|
||||
args->args[1]);
|
||||
if (ret < 0)
|
||||
goto err_kfree;
|
||||
|
||||
rgpio_dev->of_args = *args;
|
||||
/*
|
||||
* We keep the device_node reference, but of_args.np is put at the end
|
||||
* of __of_reset_control_get(), so get it one more time.
|
||||
* Hold reference as long as rgpio_dev memory is valid.
|
||||
*/
|
||||
of_node_get(rgpio_dev->of_args.np);
|
||||
pdev = platform_device_register_data(NULL, "reset-gpio", id,
|
||||
&rgpio_dev->of_args,
|
||||
sizeof(rgpio_dev->of_args));
|
||||
ret = PTR_ERR_OR_ZERO(pdev);
|
||||
if (ret)
|
||||
goto err_put;
|
||||
|
||||
list_add(&rgpio_dev->list, &reset_gpio_lookup_list);
|
||||
|
||||
out:
|
||||
mutex_unlock(&reset_gpio_lookup_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_put:
|
||||
of_node_put(rgpio_dev->of_args.np);
|
||||
err_kfree:
|
||||
kfree(rgpio_dev);
|
||||
err_ida_free:
|
||||
ida_free(&reset_gpio_ida, id);
|
||||
err_unlock:
|
||||
mutex_unlock(&reset_gpio_lookup_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct reset_controller_dev *__reset_find_rcdev(const struct of_phandle_args *args,
|
||||
bool gpio_fallback)
|
||||
{
|
||||
struct reset_controller_dev *rcdev;
|
||||
|
||||
lockdep_assert_held(&reset_list_mutex);
|
||||
|
||||
list_for_each_entry(rcdev, &reset_controller_list, list) {
|
||||
if (gpio_fallback) {
|
||||
if (rcdev->of_args && of_phandle_args_equal(args,
|
||||
rcdev->of_args))
|
||||
return rcdev;
|
||||
} else {
|
||||
if (args->np == rcdev->of_node)
|
||||
return rcdev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct reset_control *
|
||||
__of_reset_control_get(struct device_node *node, const char *id, int index,
|
||||
bool shared, bool optional, bool acquired)
|
||||
{
|
||||
bool gpio_fallback = false;
|
||||
struct reset_control *rstc;
|
||||
struct reset_controller_dev *r, *rcdev;
|
||||
struct reset_controller_dev *rcdev;
|
||||
struct of_phandle_args args;
|
||||
int rstc_id;
|
||||
int ret;
|
||||
@ -839,39 +1024,52 @@ __of_reset_control_get(struct device_node *node, const char *id, int index,
|
||||
index, &args);
|
||||
if (ret == -EINVAL)
|
||||
return ERR_PTR(ret);
|
||||
if (ret)
|
||||
return optional ? NULL : ERR_PTR(ret);
|
||||
if (ret) {
|
||||
if (!IS_ENABLED(CONFIG_RESET_GPIO))
|
||||
return optional ? NULL : ERR_PTR(ret);
|
||||
|
||||
mutex_lock(&reset_list_mutex);
|
||||
rcdev = NULL;
|
||||
list_for_each_entry(r, &reset_controller_list, list) {
|
||||
if (args.np == r->of_node) {
|
||||
rcdev = r;
|
||||
break;
|
||||
/*
|
||||
* There can be only one reset-gpio for regular devices, so
|
||||
* don't bother with the "reset-gpios" phandle index.
|
||||
*/
|
||||
ret = of_parse_phandle_with_args(node, "reset-gpios", "#gpio-cells",
|
||||
0, &args);
|
||||
if (ret)
|
||||
return optional ? NULL : ERR_PTR(ret);
|
||||
|
||||
gpio_fallback = true;
|
||||
|
||||
ret = __reset_add_reset_gpio_device(&args);
|
||||
if (ret) {
|
||||
rstc = ERR_PTR(ret);
|
||||
goto out_put;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&reset_list_mutex);
|
||||
rcdev = __reset_find_rcdev(&args, gpio_fallback);
|
||||
if (!rcdev) {
|
||||
rstc = ERR_PTR(-EPROBE_DEFER);
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
|
||||
rstc = ERR_PTR(-EINVAL);
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
rstc_id = rcdev->of_xlate(rcdev, &args);
|
||||
if (rstc_id < 0) {
|
||||
rstc = ERR_PTR(rstc_id);
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* reset_list_mutex also protects the rcdev's reset_control list */
|
||||
rstc = __reset_control_get_internal(rcdev, rstc_id, shared, acquired);
|
||||
|
||||
out:
|
||||
out_unlock:
|
||||
mutex_unlock(&reset_list_mutex);
|
||||
out_put:
|
||||
of_node_put(args.np);
|
||||
|
||||
return rstc;
|
||||
|
119
drivers/reset/reset-gpio.c
Normal file
119
drivers/reset/reset-gpio.c
Normal file
@ -0,0 +1,119 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
|
||||
struct reset_gpio_priv {
|
||||
struct reset_controller_dev rc;
|
||||
struct gpio_desc *reset;
|
||||
};
|
||||
|
||||
static inline struct reset_gpio_priv
|
||||
*rc_to_reset_gpio(struct reset_controller_dev *rc)
|
||||
{
|
||||
return container_of(rc, struct reset_gpio_priv, rc);
|
||||
}
|
||||
|
||||
static int reset_gpio_assert(struct reset_controller_dev *rc, unsigned long id)
|
||||
{
|
||||
struct reset_gpio_priv *priv = rc_to_reset_gpio(rc);
|
||||
|
||||
gpiod_set_value_cansleep(priv->reset, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_gpio_deassert(struct reset_controller_dev *rc,
|
||||
unsigned long id)
|
||||
{
|
||||
struct reset_gpio_priv *priv = rc_to_reset_gpio(rc);
|
||||
|
||||
gpiod_set_value_cansleep(priv->reset, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset_gpio_status(struct reset_controller_dev *rc, unsigned long id)
|
||||
{
|
||||
struct reset_gpio_priv *priv = rc_to_reset_gpio(rc);
|
||||
|
||||
return gpiod_get_value_cansleep(priv->reset);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops reset_gpio_ops = {
|
||||
.assert = reset_gpio_assert,
|
||||
.deassert = reset_gpio_deassert,
|
||||
.status = reset_gpio_status,
|
||||
};
|
||||
|
||||
static int reset_gpio_of_xlate(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec)
|
||||
{
|
||||
return reset_spec->args[0];
|
||||
}
|
||||
|
||||
static void reset_gpio_of_node_put(void *data)
|
||||
{
|
||||
of_node_put(data);
|
||||
}
|
||||
|
||||
static int reset_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct of_phandle_args *platdata = dev_get_platdata(dev);
|
||||
struct reset_gpio_priv *priv;
|
||||
int ret;
|
||||
|
||||
if (!platdata)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, &priv->rc);
|
||||
|
||||
priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->reset))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->reset),
|
||||
"Could not get reset gpios\n");
|
||||
|
||||
priv->rc.ops = &reset_gpio_ops;
|
||||
priv->rc.owner = THIS_MODULE;
|
||||
priv->rc.dev = dev;
|
||||
priv->rc.of_args = platdata;
|
||||
ret = devm_add_action_or_reset(dev, reset_gpio_of_node_put,
|
||||
priv->rc.of_node);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Cells to match GPIO specifier, but it's not really used */
|
||||
priv->rc.of_reset_n_cells = 2;
|
||||
priv->rc.of_xlate = reset_gpio_of_xlate;
|
||||
priv->rc.nr_resets = 1;
|
||||
|
||||
return devm_reset_controller_register(dev, &priv->rc);
|
||||
}
|
||||
|
||||
static const struct platform_device_id reset_gpio_ids[] = {
|
||||
{ .name = "reset-gpio", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, reset_gpio_ids);
|
||||
|
||||
static struct platform_driver reset_gpio_driver = {
|
||||
.probe = reset_gpio_probe,
|
||||
.id_table = reset_gpio_ids,
|
||||
.driver = {
|
||||
.name = "reset-gpio",
|
||||
},
|
||||
};
|
||||
module_platform_driver(reset_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
|
||||
MODULE_DESCRIPTION("Generic GPIO reset driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -151,6 +151,8 @@ static const struct of_device_id reset_simple_dt_ids[] = {
|
||||
{ .compatible = "snps,dw-high-reset" },
|
||||
{ .compatible = "snps,dw-low-reset",
|
||||
.data = &reset_simple_active_low },
|
||||
{ .compatible = "sophgo,sg2042-reset",
|
||||
.data = &reset_simple_active_low },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
|
87
include/dt-bindings/reset/sophgo,sg2042-reset.h
Normal file
87
include/dt-bindings/reset/sophgo,sg2042-reset.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
|
||||
/*
|
||||
* Copyright (C) 2023 Sophgo Technology Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __DT_BINDINGS_RESET_SOPHGO_SG2042_H_
|
||||
#define __DT_BINDINGS_RESET_SOPHGO_SG2042_H_
|
||||
|
||||
#define RST_MAIN_AP 0
|
||||
#define RST_RISCV_CPU 1
|
||||
#define RST_RISCV_LOW_SPEED_LOGIC 2
|
||||
#define RST_RISCV_CMN 3
|
||||
#define RST_HSDMA 4
|
||||
#define RST_SYSDMA 5
|
||||
#define RST_EFUSE0 6
|
||||
#define RST_EFUSE1 7
|
||||
#define RST_RTC 8
|
||||
#define RST_TIMER 9
|
||||
#define RST_WDT 10
|
||||
#define RST_AHB_ROM0 11
|
||||
#define RST_AHB_ROM1 12
|
||||
#define RST_I2C0 13
|
||||
#define RST_I2C1 14
|
||||
#define RST_I2C2 15
|
||||
#define RST_I2C3 16
|
||||
#define RST_GPIO0 17
|
||||
#define RST_GPIO1 18
|
||||
#define RST_GPIO2 19
|
||||
#define RST_PWM 20
|
||||
#define RST_AXI_SRAM0 21
|
||||
#define RST_AXI_SRAM1 22
|
||||
#define RST_SF0 23
|
||||
#define RST_SF1 24
|
||||
#define RST_LPC 25
|
||||
#define RST_ETH0 26
|
||||
#define RST_EMMC 27
|
||||
#define RST_SD 28
|
||||
#define RST_UART0 29
|
||||
#define RST_UART1 30
|
||||
#define RST_UART2 31
|
||||
#define RST_UART3 32
|
||||
#define RST_SPI0 33
|
||||
#define RST_SPI1 34
|
||||
#define RST_DBG_I2C 35
|
||||
#define RST_PCIE0 36
|
||||
#define RST_PCIE1 37
|
||||
#define RST_DDR0 38
|
||||
#define RST_DDR1 39
|
||||
#define RST_DDR2 40
|
||||
#define RST_DDR3 41
|
||||
#define RST_FAU0 42
|
||||
#define RST_FAU1 43
|
||||
#define RST_FAU2 44
|
||||
#define RST_RXU0 45
|
||||
#define RST_RXU1 46
|
||||
#define RST_RXU2 47
|
||||
#define RST_RXU3 48
|
||||
#define RST_RXU4 49
|
||||
#define RST_RXU5 50
|
||||
#define RST_RXU6 51
|
||||
#define RST_RXU7 52
|
||||
#define RST_RXU8 53
|
||||
#define RST_RXU9 54
|
||||
#define RST_RXU10 55
|
||||
#define RST_RXU11 56
|
||||
#define RST_RXU12 57
|
||||
#define RST_RXU13 58
|
||||
#define RST_RXU14 59
|
||||
#define RST_RXU15 60
|
||||
#define RST_RXU16 61
|
||||
#define RST_RXU17 62
|
||||
#define RST_RXU18 63
|
||||
#define RST_RXU19 64
|
||||
#define RST_RXU20 65
|
||||
#define RST_RXU21 66
|
||||
#define RST_RXU22 67
|
||||
#define RST_RXU23 68
|
||||
#define RST_RXU24 69
|
||||
#define RST_RXU25 70
|
||||
#define RST_RXU26 71
|
||||
#define RST_RXU27 72
|
||||
#define RST_RXU28 73
|
||||
#define RST_RXU29 74
|
||||
#define RST_RXU30 75
|
||||
#define RST_RXU31 76
|
||||
|
||||
#endif /* __DT_BINDINGS_RESET_SOPHGO_SG2042_H_ */
|
@ -1149,8 +1149,7 @@ static inline int of_perf_domain_get_sharing_cpumask(int pcpu, const char *list_
|
||||
if (ret < 0)
|
||||
continue;
|
||||
|
||||
if (pargs->np == args.np && pargs->args_count == args.args_count &&
|
||||
!memcmp(pargs->args, args.args, sizeof(args.args[0]) * args.args_count))
|
||||
if (of_phandle_args_equal(pargs, &args))
|
||||
cpumask_set_cpu(cpu, cpumask);
|
||||
|
||||
of_node_put(args.np);
|
||||
|
@ -1065,6 +1065,22 @@ static inline int of_parse_phandle_with_optional_args(const struct device_node *
|
||||
0, index, out_args);
|
||||
}
|
||||
|
||||
/**
|
||||
* of_phandle_args_equal() - Compare two of_phandle_args
|
||||
* @a1: First of_phandle_args to compare
|
||||
* @a2: Second of_phandle_args to compare
|
||||
*
|
||||
* Return: True if a1 and a2 are the same (same node pointer, same phandle
|
||||
* args), false otherwise.
|
||||
*/
|
||||
static inline bool of_phandle_args_equal(const struct of_phandle_args *a1,
|
||||
const struct of_phandle_args *a2)
|
||||
{
|
||||
return a1->np == a2->np &&
|
||||
a1->args_count == a2->args_count &&
|
||||
!memcmp(a1->args, a2->args, sizeof(a1->args[0]) * a1->args_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* of_property_count_u8_elems - Count the number of u8 elements in a property
|
||||
*
|
||||
|
@ -60,6 +60,9 @@ struct reset_control_lookup {
|
||||
* @reset_control_head: head of internal list of requested reset controls
|
||||
* @dev: corresponding driver model device struct
|
||||
* @of_node: corresponding device tree node as phandle target
|
||||
* @of_args: for reset-gpios controllers: corresponding phandle args with
|
||||
* of_node and GPIO number complementing of_node; either this or
|
||||
* of_node should be present
|
||||
* @of_reset_n_cells: number of cells in reset line specifiers
|
||||
* @of_xlate: translation function to translate from specifier as found in the
|
||||
* device tree to id as given to the reset control ops, defaults
|
||||
@ -73,6 +76,7 @@ struct reset_controller_dev {
|
||||
struct list_head reset_control_head;
|
||||
struct device *dev;
|
||||
struct device_node *of_node;
|
||||
const struct of_phandle_args *of_args;
|
||||
int of_reset_n_cells;
|
||||
int (*of_xlate)(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec);
|
||||
|
Loading…
x
Reference in New Issue
Block a user