]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
reset: amlogic: add auxiliary reset driver support
authorJerome Brunet <jbrunet@baylibre.com>
Tue, 10 Sep 2024 16:32:51 +0000 (18:32 +0200)
committerPhilipp Zabel <p.zabel@pengutronix.de>
Tue, 1 Oct 2024 08:40:32 +0000 (10:40 +0200)
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: Jerome Brunet <jbrunet@baylibre.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-9-60be62635d3e@baylibre.com
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
drivers/reset/amlogic/Kconfig
drivers/reset/amlogic/Makefile
drivers/reset/amlogic/reset-meson-aux.c [new file with mode: 0644]
drivers/reset/amlogic/reset-meson-common.c
drivers/reset/amlogic/reset-meson.c
drivers/reset/amlogic/reset-meson.h
include/soc/amlogic/reset-meson-aux.h [new file with mode: 0644]

index 1d77987088f43871b8122f0335bff68c92286b8f..3bee9fd6026942921695049ffb87d684900c79d1 100644 (file)
@@ -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
index 74aaa2fb5e13e7ffb56edd1888a6adda2989bedd..ca99a691282c2f810a992c6843884b645251fe85 100644 (file)
@@ -1,3 +1,4 @@
 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
diff --git a/drivers/reset/amlogic/reset-meson-aux.c b/drivers/reset/amlogic/reset-meson-aux.c
new file mode 100644 (file)
index 0000000..dd84530
--- /dev/null
@@ -0,0 +1,136 @@
+// 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);
index d57544801ae90fb9077921723aea5129c4fcf599..a7b1b250a64dbf94530d06138f4270fff8f56d7a 100644 (file)
@@ -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);
index feb19bf6da77b8dab3a3dd043e696ed2e132a059..6ae4ed6b7f8ba35e891b3cc784657fc97386dfa3 100644 (file)
@@ -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,
index 4e1dbd7569c59ab6e95ee98f0ae430946824bbe6..2051e126dc3a2e1526ac9f82d12e49d8b245b0ab 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/reset-controller.h>
 
 struct meson_reset_param {
+       const struct reset_control_ops *reset_ops;
        unsigned int reset_num;
        unsigned int reset_offset;
        unsigned int level_offset;
@@ -21,4 +22,7 @@ struct meson_reset_param {
 int meson_reset_controller_register(struct device *dev, struct regmap *map,
                                    const struct meson_reset_param *param);
 
+extern const struct reset_control_ops meson_reset_ops;
+extern const struct reset_control_ops meson_reset_toggle_ops;
+
 #endif /* __MESON_RESET_H */
diff --git a/include/soc/amlogic/reset-meson-aux.h b/include/soc/amlogic/reset-meson-aux.h
new file mode 100644 (file)
index 0000000..d8a15d4
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __SOC_RESET_MESON_AUX_H
+#define __SOC_RESET_MESON_AUX_H
+
+#include <linux/err.h>
+
+struct device;
+struct regmap;
+
+#if IS_ENABLED(CONFIG_RESET_MESON_AUX)
+int devm_meson_rst_aux_register(struct device *dev,
+                               struct regmap *map,
+                               const char *adev_name);
+#else
+static inline int devm_meson_rst_aux_register(struct device *dev,
+                                             struct regmap *map,
+                                             const char *adev_name)
+{
+       return 0;
+}
+#endif
+
+#endif /* __SOC_RESET_MESON_AUX_H */