Commit fb4c3158 authored by Jerome Brunet's avatar Jerome Brunet Committed by Philipp Zabel
Browse files

reset: amlogic: add auxiliary reset driver support



Add support for the reset controller present in the audio clock
controller of the g12 and sm1 SoC families, using the auxiliary bus.

This is expected to replace the driver currently present directly
within the related clock driver.

Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
Reviewed-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-9-60be62635d3e@baylibre.com


Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
parent c38ae95c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -11,6 +11,14 @@ config RESET_MESON
	help
	  This enables the reset driver for Amlogic SoCs.

config RESET_MESON_AUX
	tristate "Meson Reset Auxiliary Driver"
	depends on ARCH_MESON || COMPILE_TEST
	select AUXILIARY_BUS
	select RESET_MESON_COMMON
	help
	  This enables the reset auxiliary driver for Amlogic SoCs.

config RESET_MESON_AUDIO_ARB
	tristate "Meson Audio Memory Arbiter Reset Driver"
	depends on ARCH_MESON || COMPILE_TEST
+1 −0
Original line number Diff line number Diff line
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_MESON_AUX) += reset-meson-aux.o
obj-$(CONFIG_RESET_MESON_COMMON) += reset-meson-common.o
obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
+136 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
 * Amlogic Meson Reset Auxiliary driver
 *
 * Copyright (c) 2024 BayLibre, SAS.
 * Author: Jerome Brunet <jbrunet@baylibre.com>
 */

#include <linux/err.h>
#include <linux/module.h>
#include <linux/auxiliary_bus.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>

#include "reset-meson.h"
#include <soc/amlogic/reset-meson-aux.h>

static DEFINE_IDA(meson_rst_aux_ida);

struct meson_reset_adev {
	struct auxiliary_device adev;
	struct regmap *map;
};

#define to_meson_reset_adev(_adev) \
	container_of((_adev), struct meson_reset_adev, adev)

static const struct meson_reset_param meson_g12a_audio_param = {
	.reset_ops	= &meson_reset_toggle_ops,
	.reset_num	= 26,
	.level_offset	= 0x24,
};

static const struct meson_reset_param meson_sm1_audio_param = {
	.reset_ops	= &meson_reset_toggle_ops,
	.reset_num	= 39,
	.level_offset	= 0x28,
};

static const struct auxiliary_device_id meson_reset_aux_ids[] = {
	{
		.name = "axg-audio-clkc.rst-g12a",
		.driver_data = (kernel_ulong_t)&meson_g12a_audio_param,
	}, {
		.name = "axg-audio-clkc.rst-sm1",
		.driver_data = (kernel_ulong_t)&meson_sm1_audio_param,
	}, {}
};
MODULE_DEVICE_TABLE(auxiliary, meson_reset_aux_ids);

static int meson_reset_aux_probe(struct auxiliary_device *adev,
				 const struct auxiliary_device_id *id)
{
	const struct meson_reset_param *param =
		(const struct meson_reset_param *)(id->driver_data);
	struct meson_reset_adev *raux =
		to_meson_reset_adev(adev);

	return meson_reset_controller_register(&adev->dev, raux->map, param);
}

static struct auxiliary_driver meson_reset_aux_driver = {
	.probe		= meson_reset_aux_probe,
	.id_table	= meson_reset_aux_ids,
};
module_auxiliary_driver(meson_reset_aux_driver);

static void meson_rst_aux_release(struct device *dev)
{
	struct auxiliary_device *adev = to_auxiliary_dev(dev);
	struct meson_reset_adev *raux =
		to_meson_reset_adev(adev);

	ida_free(&meson_rst_aux_ida, adev->id);
	kfree(raux);
}

static void meson_rst_aux_unregister_adev(void *_adev)
{
	struct auxiliary_device *adev = _adev;

	auxiliary_device_delete(adev);
	auxiliary_device_uninit(adev);
}

int devm_meson_rst_aux_register(struct device *dev,
				struct regmap *map,
				const char *adev_name)
{
	struct meson_reset_adev *raux;
	struct auxiliary_device *adev;
	int ret;

	raux = kzalloc(sizeof(*raux), GFP_KERNEL);
	if (!raux)
		return -ENOMEM;

	ret = ida_alloc(&meson_rst_aux_ida, GFP_KERNEL);
	if (ret < 0)
		goto raux_free;

	raux->map = map;

	adev = &raux->adev;
	adev->id = ret;
	adev->name = adev_name;
	adev->dev.parent = dev;
	adev->dev.release = meson_rst_aux_release;
	device_set_of_node_from_dev(&adev->dev, dev);

	ret = auxiliary_device_init(adev);
	if (ret)
		goto ida_free;

	ret = __auxiliary_device_add(adev, dev->driver->name);
	if (ret) {
		auxiliary_device_uninit(adev);
		return ret;
	}

	return devm_add_action_or_reset(dev, meson_rst_aux_unregister_adev,
					adev);

ida_free:
	ida_free(&meson_rst_aux_ida, adev->id);
raux_free:
	kfree(raux);
	return ret;
}
EXPORT_SYMBOL_GPL(devm_meson_rst_aux_register);

MODULE_DESCRIPTION("Amlogic Meson Reset Auxiliary driver");
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(MESON_RESET);
+23 −2
Original line number Diff line number Diff line
@@ -87,12 +87,33 @@ static int meson_reset_deassert(struct reset_controller_dev *rcdev,
	return meson_reset_level(rcdev, id, false);
}

static const struct reset_control_ops meson_reset_ops = {
static int meson_reset_level_toggle(struct reset_controller_dev *rcdev,
				    unsigned long id)
{
	int ret;

	ret = meson_reset_assert(rcdev, id);
	if (ret)
		return ret;

	return meson_reset_deassert(rcdev, id);
}

const struct reset_control_ops meson_reset_ops = {
	.reset		= meson_reset_reset,
	.assert		= meson_reset_assert,
	.deassert	= meson_reset_deassert,
	.status		= meson_reset_status,
};
EXPORT_SYMBOL_NS_GPL(meson_reset_ops, MESON_RESET);

const struct reset_control_ops meson_reset_toggle_ops = {
	.reset		= meson_reset_level_toggle,
	.assert		= meson_reset_assert,
	.deassert	= meson_reset_deassert,
	.status		= meson_reset_status,
};
EXPORT_SYMBOL_NS_GPL(meson_reset_toggle_ops, MESON_RESET);

int meson_reset_controller_register(struct device *dev, struct regmap *map,
				    const struct meson_reset_param *param)
@@ -107,7 +128,7 @@ int meson_reset_controller_register(struct device *dev, struct regmap *map,
	data->map = map;
	data->rcdev.owner = dev->driver->owner;
	data->rcdev.nr_resets = param->reset_num;
	data->rcdev.ops = &meson_reset_ops;
	data->rcdev.ops = data->param->reset_ops;
	data->rcdev.of_node = dev->of_node;

	return devm_reset_controller_register(dev, &data->rcdev);
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include "reset-meson.h"

static const struct meson_reset_param meson8b_param = {
	.reset_ops	= &meson_reset_ops,
	.reset_num	= 256,
	.reset_offset	= 0x0,
	.level_offset	= 0x7c,
@@ -25,6 +26,7 @@ static const struct meson_reset_param meson8b_param = {
};

static const struct meson_reset_param meson_a1_param = {
	.reset_ops	= &meson_reset_ops,
	.reset_num	= 96,
	.reset_offset	= 0x0,
	.level_offset	= 0x40,
@@ -32,6 +34,7 @@ static const struct meson_reset_param meson_a1_param = {
};

static const struct meson_reset_param meson_s4_param = {
	.reset_ops	= &meson_reset_ops,
	.reset_num	= 192,
	.reset_offset	= 0x0,
	.level_offset	= 0x40,
Loading