Commit e517030e authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'reset-for-4.14' of git://git.pengutronix.de/git/pza/linux into next/drivers

Pull "Reset controller changes for v4.14" from Philipp Zabel:

- constify zx2967 reset_ops
- add a convenience API to manage an array of resets
- let deassert report success and let assert report success for shared resets
  if the reset controller driver does not implement (de)assert.
- add HSDKv1 reset driver
- remove Gemini reset controller, the driver is made obsolete
  by a combined clock/reset driver in drivers/clk
- fix the total number of reset lines in the sunxi driver
- various uniphier updates and fixes:
  - remove sLD3 SoC support
  - simplify system reset register and bit definitions
  - add audio systems, video input subsystem, and analog amplifiers reset
    controls

* tag 'reset-for-4.14' of git://git.pengutronix.de/git/pza/linux:
  reset: uniphier: add analog amplifiers reset control
  reset: uniphier: add video input subsystem reset control
  reset: uniphier: add audio systems reset control
  reset: sunxi: fix number of reset lines
  reset: uniphier: do not use per-SoC macro for system reset block
  reset: uniphier: remove sLD3 SoC support
  Revert "reset: Add a Gemini reset controller"
  ARC: reset: introduce HSDKv1 reset driver
  reset: make (de)assert report success for self-deasserting reset drivers
  reset: Add APIs to manage array of resets
  reset: zx2967: constify zx2967_reset_ops.
parents 03f89359 ac0c735a
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@ System reset

Required properties:
- compatible: should be one of the following:
    "socionext,uniphier-sld3-reset" - for sLD3 SoC
    "socionext,uniphier-ld4-reset"  - for LD4 SoC
    "socionext,uniphier-pro4-reset" - for Pro4 SoC
    "socionext,uniphier-sld8-reset" - for sLD8 SoC
@@ -37,7 +36,6 @@ Media I/O (MIO) reset, SD reset

Required properties:
- compatible: should be one of the following:
    "socionext,uniphier-sld3-mio-reset" - for sLD3 SoC
    "socionext,uniphier-ld4-mio-reset"  - for LD4 SoC
    "socionext,uniphier-pro4-mio-reset" - for Pro4 SoC
    "socionext,uniphier-sld8-mio-reset" - for sLD8 SoC
@@ -92,3 +90,28 @@ Example:

		other nodes ...
	};


Analog signal amplifier reset
-----------------------------

Required properties:
- compatible: should be one of the following:
    "socionext,uniphier-ld11-adamv-reset" - for LD11 SoC
    "socionext,uniphier-ld20-adamv-reset" - for LD20 SoC
- #reset-cells: should be 1.

Example:

	adamv@57920000 {
		compatible = "socionext,uniphier-ld11-adamv",
			     "simple-mfd", "syscon";
		reg = <0x57920000 0x1000>;

		adamv_rst: reset {
			compatible = "socionext,uniphier-ld11-adamv-reset";
			#reset-cells = <1>;
		};

		other nodes ...
	};
+7 −0
Original line number Diff line number Diff line
@@ -12643,6 +12643,13 @@ L: linux-mmc@vger.kernel.org
S:	Maintained
F:	drivers/mmc/host/dw_mmc*

SYNOPSYS HSDK RESET CONTROLLER DRIVER
M:	Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
S:	Supported
F:	drivers/reset/reset-hsdk-v1.c
F:	include/dt-bindings/reset/snps,hsdk-v1-reset.h
F:	Documentation/devicetree/bindings/reset/snps,hsdk-v1-reset.txt

SYSTEM CONFIGURATION (SYSCON)
M:	Lee Jones <lee.jones@linaro.org>
M:	Arnd Bergmann <arnd@arndb.de>
+4 −5
Original line number Diff line number Diff line
@@ -34,12 +34,11 @@ config RESET_BERLIN
	help
	  This enables the reset controller driver for Marvell Berlin SoCs.

config RESET_GEMINI
	bool "Gemini Reset Driver" if COMPILE_TEST
	default ARCH_GEMINI
	select MFD_SYSCON
config RESET_HSDK_V1
	bool "HSDK v1 Reset Driver"
	default n
	help
	  This enables the reset controller driver for Cortina Systems Gemini.
	  This enables the reset controller driver for HSDK v1.

config RESET_IMX7
	bool "i.MX7 Reset Driver" if COMPILE_TEST
+1 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o
obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
obj-$(CONFIG_RESET_GEMINI) += reset-gemini.o
obj-$(CONFIG_RESET_HSDK_V1) += reset-hsdk-v1.o
obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
+233 −5
Original line number Diff line number Diff line
@@ -43,10 +43,23 @@ struct reset_control {
	unsigned int id;
	struct kref refcnt;
	bool shared;
	bool array;
	atomic_t deassert_count;
	atomic_t triggered_count;
};

/**
 * struct reset_control_array - an array of reset controls
 * @base: reset control for compatibility with reset control API functions
 * @num_rstcs: number of reset controls
 * @rstc: array of reset controls
 */
struct reset_control_array {
	struct reset_control base;
	unsigned int num_rstcs;
	struct reset_control *rstc[];
};

/**
 * of_reset_simple_xlate - translate reset_spec to the reset line number
 * @rcdev: a pointer to the reset controller device
@@ -135,6 +148,65 @@ int devm_reset_controller_register(struct device *dev,
}
EXPORT_SYMBOL_GPL(devm_reset_controller_register);

static inline struct reset_control_array *
rstc_to_array(struct reset_control *rstc) {
	return container_of(rstc, struct reset_control_array, base);
}

static int reset_control_array_reset(struct reset_control_array *resets)
{
	int ret, i;

	for (i = 0; i < resets->num_rstcs; i++) {
		ret = reset_control_reset(resets->rstc[i]);
		if (ret)
			return ret;
	}

	return 0;
}

static int reset_control_array_assert(struct reset_control_array *resets)
{
	int ret, i;

	for (i = 0; i < resets->num_rstcs; i++) {
		ret = reset_control_assert(resets->rstc[i]);
		if (ret)
			goto err;
	}

	return 0;

err:
	while (i--)
		reset_control_deassert(resets->rstc[i]);
	return ret;
}

static int reset_control_array_deassert(struct reset_control_array *resets)
{
	int ret, i;

	for (i = 0; i < resets->num_rstcs; i++) {
		ret = reset_control_deassert(resets->rstc[i]);
		if (ret)
			goto err;
	}

	return 0;

err:
	while (i--)
		reset_control_assert(resets->rstc[i]);
	return ret;
}

static inline bool reset_control_is_array(struct reset_control *rstc)
{
	return rstc->array;
}

/**
 * reset_control_reset - reset the controlled device
 * @rstc: reset controller
@@ -158,6 +230,9 @@ int reset_control_reset(struct reset_control *rstc)
	if (WARN_ON(IS_ERR(rstc)))
		return -EINVAL;

	if (reset_control_is_array(rstc))
		return reset_control_array_reset(rstc_to_array(rstc));

	if (!rstc->rcdev->ops->reset)
		return -ENOTSUPP;

@@ -202,8 +277,8 @@ int reset_control_assert(struct reset_control *rstc)
	if (WARN_ON(IS_ERR(rstc)))
		return -EINVAL;

	if (!rstc->rcdev->ops->assert)
		return -ENOTSUPP;
	if (reset_control_is_array(rstc))
		return reset_control_array_assert(rstc_to_array(rstc));

	if (rstc->shared) {
		if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
@@ -214,6 +289,21 @@ int reset_control_assert(struct reset_control *rstc)

		if (atomic_dec_return(&rstc->deassert_count) != 0)
			return 0;

		/*
		 * Shared reset controls allow the reset line to be in any state
		 * after this call, so doing nothing is a valid option.
		 */
		if (!rstc->rcdev->ops->assert)
			return 0;
	} else {
		/*
		 * If the reset controller does not implement .assert(), there
		 * is no way to guarantee that the reset line is asserted after
		 * this call.
		 */
		if (!rstc->rcdev->ops->assert)
			return -ENOTSUPP;
	}

	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
@@ -240,8 +330,8 @@ int reset_control_deassert(struct reset_control *rstc)
	if (WARN_ON(IS_ERR(rstc)))
		return -EINVAL;

	if (!rstc->rcdev->ops->deassert)
		return -ENOTSUPP;
	if (reset_control_is_array(rstc))
		return reset_control_array_deassert(rstc_to_array(rstc));

	if (rstc->shared) {
		if (WARN_ON(atomic_read(&rstc->triggered_count) != 0))
@@ -251,6 +341,16 @@ int reset_control_deassert(struct reset_control *rstc)
			return 0;
	}

	/*
	 * If the reset controller does not implement .deassert(), we assume
	 * that it handles self-deasserting reset lines via .reset(). In that
	 * case, the reset lines are deasserted by default. If that is not the
	 * case, the reset controller driver should implement .deassert() and
	 * return -ENOTSUPP.
	 */
	if (!rstc->rcdev->ops->deassert)
		return 0;

	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
}
EXPORT_SYMBOL_GPL(reset_control_deassert);
@@ -266,7 +366,7 @@ int reset_control_status(struct reset_control *rstc)
	if (!rstc)
		return 0;

	if (WARN_ON(IS_ERR(rstc)))
	if (WARN_ON(IS_ERR(rstc)) || reset_control_is_array(rstc))
		return -EINVAL;

	if (rstc->rcdev->ops->status)
@@ -404,6 +504,16 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id,
}
EXPORT_SYMBOL_GPL(__reset_control_get);

static void reset_control_array_put(struct reset_control_array *resets)
{
	int i;

	mutex_lock(&reset_list_mutex);
	for (i = 0; i < resets->num_rstcs; i++)
		__reset_control_put_internal(resets->rstc[i]);
	mutex_unlock(&reset_list_mutex);
}

/**
 * reset_control_put - free the reset controller
 * @rstc: reset controller
@@ -413,6 +523,11 @@ void reset_control_put(struct reset_control *rstc)
	if (IS_ERR_OR_NULL(rstc))
		return;

	if (reset_control_is_array(rstc)) {
		reset_control_array_put(rstc_to_array(rstc));
		return;
	}

	mutex_lock(&reset_list_mutex);
	__reset_control_put_internal(rstc);
	mutex_unlock(&reset_list_mutex);
@@ -472,3 +587,116 @@ int device_reset(struct device *dev)
	return ret;
}
EXPORT_SYMBOL_GPL(device_reset);

/**
 * APIs to manage an array of reset controls.
 */
/**
 * of_reset_control_get_count - Count number of resets available with a device
 *
 * @node: device node that contains 'resets'.
 *
 * Returns positive reset count on success, or error number on failure and
 * on count being zero.
 */
static int of_reset_control_get_count(struct device_node *node)
{
	int count;

	if (!node)
		return -EINVAL;

	count = of_count_phandle_with_args(node, "resets", "#reset-cells");
	if (count == 0)
		count = -ENOENT;

	return count;
}

/**
 * of_reset_control_array_get - Get a list of reset controls using
 *				device node.
 *
 * @np: device node for the device that requests the reset controls array
 * @shared: whether reset controls are shared or not
 * @optional: whether it is optional to get the reset controls
 *
 * Returns pointer to allocated reset_control_array on success or
 * error on failure
 */
struct reset_control *
of_reset_control_array_get(struct device_node *np, bool shared, bool optional)
{
	struct reset_control_array *resets;
	struct reset_control *rstc;
	int num, i;

	num = of_reset_control_get_count(np);
	if (num < 0)
		return optional ? NULL : ERR_PTR(num);

	resets = kzalloc(sizeof(*resets) + sizeof(resets->rstc[0]) * num,
			 GFP_KERNEL);
	if (!resets)
		return ERR_PTR(-ENOMEM);

	for (i = 0; i < num; i++) {
		rstc = __of_reset_control_get(np, NULL, i, shared, optional);
		if (IS_ERR(rstc))
			goto err_rst;
		resets->rstc[i] = rstc;
	}
	resets->num_rstcs = num;
	resets->base.array = true;

	return &resets->base;

err_rst:
	mutex_lock(&reset_list_mutex);
	while (--i >= 0)
		__reset_control_put_internal(resets->rstc[i]);
	mutex_unlock(&reset_list_mutex);

	kfree(resets);

	return rstc;
}
EXPORT_SYMBOL_GPL(of_reset_control_array_get);

/**
 * devm_reset_control_array_get - Resource managed reset control array get
 *
 * @dev: device that requests the list of reset controls
 * @shared: whether reset controls are shared or not
 * @optional: whether it is optional to get the reset controls
 *
 * The reset control array APIs are intended for a list of resets
 * that just have to be asserted or deasserted, without any
 * requirements on the order.
 *
 * Returns pointer to allocated reset_control_array on success or
 * error on failure
 */
struct reset_control *
devm_reset_control_array_get(struct device *dev, bool shared, bool optional)
{
	struct reset_control **devres;
	struct reset_control *rstc;

	devres = devres_alloc(devm_reset_control_release, sizeof(*devres),
			      GFP_KERNEL);
	if (!devres)
		return ERR_PTR(-ENOMEM);

	rstc = of_reset_control_array_get(dev->of_node, shared, optional);
	if (IS_ERR(rstc)) {
		devres_free(devres);
		return rstc;
	}

	*devres = rstc;
	devres_add(dev, devres);

	return rstc;
}
EXPORT_SYMBOL_GPL(devm_reset_control_array_get);
Loading