1*fb4c3158SJerome Brunet // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2*fb4c3158SJerome Brunet /* 3*fb4c3158SJerome Brunet * Amlogic Meson Reset Auxiliary driver 4*fb4c3158SJerome Brunet * 5*fb4c3158SJerome Brunet * Copyright (c) 2024 BayLibre, SAS. 6*fb4c3158SJerome Brunet * Author: Jerome Brunet <jbrunet@baylibre.com> 7*fb4c3158SJerome Brunet */ 8*fb4c3158SJerome Brunet 9*fb4c3158SJerome Brunet #include <linux/err.h> 10*fb4c3158SJerome Brunet #include <linux/module.h> 11*fb4c3158SJerome Brunet #include <linux/auxiliary_bus.h> 12*fb4c3158SJerome Brunet #include <linux/regmap.h> 13*fb4c3158SJerome Brunet #include <linux/reset-controller.h> 14*fb4c3158SJerome Brunet #include <linux/slab.h> 15*fb4c3158SJerome Brunet 16*fb4c3158SJerome Brunet #include "reset-meson.h" 17*fb4c3158SJerome Brunet #include <soc/amlogic/reset-meson-aux.h> 18*fb4c3158SJerome Brunet 19*fb4c3158SJerome Brunet static DEFINE_IDA(meson_rst_aux_ida); 20*fb4c3158SJerome Brunet 21*fb4c3158SJerome Brunet struct meson_reset_adev { 22*fb4c3158SJerome Brunet struct auxiliary_device adev; 23*fb4c3158SJerome Brunet struct regmap *map; 24*fb4c3158SJerome Brunet }; 25*fb4c3158SJerome Brunet 26*fb4c3158SJerome Brunet #define to_meson_reset_adev(_adev) \ 27*fb4c3158SJerome Brunet container_of((_adev), struct meson_reset_adev, adev) 28*fb4c3158SJerome Brunet 29*fb4c3158SJerome Brunet static const struct meson_reset_param meson_g12a_audio_param = { 30*fb4c3158SJerome Brunet .reset_ops = &meson_reset_toggle_ops, 31*fb4c3158SJerome Brunet .reset_num = 26, 32*fb4c3158SJerome Brunet .level_offset = 0x24, 33*fb4c3158SJerome Brunet }; 34*fb4c3158SJerome Brunet 35*fb4c3158SJerome Brunet static const struct meson_reset_param meson_sm1_audio_param = { 36*fb4c3158SJerome Brunet .reset_ops = &meson_reset_toggle_ops, 37*fb4c3158SJerome Brunet .reset_num = 39, 38*fb4c3158SJerome Brunet .level_offset = 0x28, 39*fb4c3158SJerome Brunet }; 40*fb4c3158SJerome Brunet 41*fb4c3158SJerome Brunet static const struct auxiliary_device_id meson_reset_aux_ids[] = { 42*fb4c3158SJerome Brunet { 43*fb4c3158SJerome Brunet .name = "axg-audio-clkc.rst-g12a", 44*fb4c3158SJerome Brunet .driver_data = (kernel_ulong_t)&meson_g12a_audio_param, 45*fb4c3158SJerome Brunet }, { 46*fb4c3158SJerome Brunet .name = "axg-audio-clkc.rst-sm1", 47*fb4c3158SJerome Brunet .driver_data = (kernel_ulong_t)&meson_sm1_audio_param, 48*fb4c3158SJerome Brunet }, {} 49*fb4c3158SJerome Brunet }; 50*fb4c3158SJerome Brunet MODULE_DEVICE_TABLE(auxiliary, meson_reset_aux_ids); 51*fb4c3158SJerome Brunet 52*fb4c3158SJerome Brunet static int meson_reset_aux_probe(struct auxiliary_device *adev, 53*fb4c3158SJerome Brunet const struct auxiliary_device_id *id) 54*fb4c3158SJerome Brunet { 55*fb4c3158SJerome Brunet const struct meson_reset_param *param = 56*fb4c3158SJerome Brunet (const struct meson_reset_param *)(id->driver_data); 57*fb4c3158SJerome Brunet struct meson_reset_adev *raux = 58*fb4c3158SJerome Brunet to_meson_reset_adev(adev); 59*fb4c3158SJerome Brunet 60*fb4c3158SJerome Brunet return meson_reset_controller_register(&adev->dev, raux->map, param); 61*fb4c3158SJerome Brunet } 62*fb4c3158SJerome Brunet 63*fb4c3158SJerome Brunet static struct auxiliary_driver meson_reset_aux_driver = { 64*fb4c3158SJerome Brunet .probe = meson_reset_aux_probe, 65*fb4c3158SJerome Brunet .id_table = meson_reset_aux_ids, 66*fb4c3158SJerome Brunet }; 67*fb4c3158SJerome Brunet module_auxiliary_driver(meson_reset_aux_driver); 68*fb4c3158SJerome Brunet 69*fb4c3158SJerome Brunet static void meson_rst_aux_release(struct device *dev) 70*fb4c3158SJerome Brunet { 71*fb4c3158SJerome Brunet struct auxiliary_device *adev = to_auxiliary_dev(dev); 72*fb4c3158SJerome Brunet struct meson_reset_adev *raux = 73*fb4c3158SJerome Brunet to_meson_reset_adev(adev); 74*fb4c3158SJerome Brunet 75*fb4c3158SJerome Brunet ida_free(&meson_rst_aux_ida, adev->id); 76*fb4c3158SJerome Brunet kfree(raux); 77*fb4c3158SJerome Brunet } 78*fb4c3158SJerome Brunet 79*fb4c3158SJerome Brunet static void meson_rst_aux_unregister_adev(void *_adev) 80*fb4c3158SJerome Brunet { 81*fb4c3158SJerome Brunet struct auxiliary_device *adev = _adev; 82*fb4c3158SJerome Brunet 83*fb4c3158SJerome Brunet auxiliary_device_delete(adev); 84*fb4c3158SJerome Brunet auxiliary_device_uninit(adev); 85*fb4c3158SJerome Brunet } 86*fb4c3158SJerome Brunet 87*fb4c3158SJerome Brunet int devm_meson_rst_aux_register(struct device *dev, 88*fb4c3158SJerome Brunet struct regmap *map, 89*fb4c3158SJerome Brunet const char *adev_name) 90*fb4c3158SJerome Brunet { 91*fb4c3158SJerome Brunet struct meson_reset_adev *raux; 92*fb4c3158SJerome Brunet struct auxiliary_device *adev; 93*fb4c3158SJerome Brunet int ret; 94*fb4c3158SJerome Brunet 95*fb4c3158SJerome Brunet raux = kzalloc(sizeof(*raux), GFP_KERNEL); 96*fb4c3158SJerome Brunet if (!raux) 97*fb4c3158SJerome Brunet return -ENOMEM; 98*fb4c3158SJerome Brunet 99*fb4c3158SJerome Brunet ret = ida_alloc(&meson_rst_aux_ida, GFP_KERNEL); 100*fb4c3158SJerome Brunet if (ret < 0) 101*fb4c3158SJerome Brunet goto raux_free; 102*fb4c3158SJerome Brunet 103*fb4c3158SJerome Brunet raux->map = map; 104*fb4c3158SJerome Brunet 105*fb4c3158SJerome Brunet adev = &raux->adev; 106*fb4c3158SJerome Brunet adev->id = ret; 107*fb4c3158SJerome Brunet adev->name = adev_name; 108*fb4c3158SJerome Brunet adev->dev.parent = dev; 109*fb4c3158SJerome Brunet adev->dev.release = meson_rst_aux_release; 110*fb4c3158SJerome Brunet device_set_of_node_from_dev(&adev->dev, dev); 111*fb4c3158SJerome Brunet 112*fb4c3158SJerome Brunet ret = auxiliary_device_init(adev); 113*fb4c3158SJerome Brunet if (ret) 114*fb4c3158SJerome Brunet goto ida_free; 115*fb4c3158SJerome Brunet 116*fb4c3158SJerome Brunet ret = __auxiliary_device_add(adev, dev->driver->name); 117*fb4c3158SJerome Brunet if (ret) { 118*fb4c3158SJerome Brunet auxiliary_device_uninit(adev); 119*fb4c3158SJerome Brunet return ret; 120*fb4c3158SJerome Brunet } 121*fb4c3158SJerome Brunet 122*fb4c3158SJerome Brunet return devm_add_action_or_reset(dev, meson_rst_aux_unregister_adev, 123*fb4c3158SJerome Brunet adev); 124*fb4c3158SJerome Brunet 125*fb4c3158SJerome Brunet ida_free: 126*fb4c3158SJerome Brunet ida_free(&meson_rst_aux_ida, adev->id); 127*fb4c3158SJerome Brunet raux_free: 128*fb4c3158SJerome Brunet kfree(raux); 129*fb4c3158SJerome Brunet return ret; 130*fb4c3158SJerome Brunet } 131*fb4c3158SJerome Brunet EXPORT_SYMBOL_GPL(devm_meson_rst_aux_register); 132*fb4c3158SJerome Brunet 133*fb4c3158SJerome Brunet MODULE_DESCRIPTION("Amlogic Meson Reset Auxiliary driver"); 134*fb4c3158SJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 135*fb4c3158SJerome Brunet MODULE_LICENSE("Dual BSD/GPL"); 136*fb4c3158SJerome Brunet MODULE_IMPORT_NS(MESON_RESET); 137