1c38ae95cSJerome Brunet // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2c38ae95cSJerome Brunet /* 3c38ae95cSJerome Brunet * Amlogic Meson Reset core functions 4c38ae95cSJerome Brunet * 5c38ae95cSJerome Brunet * Copyright (c) 2016-2024 BayLibre, SAS. 6c38ae95cSJerome Brunet * Authors: Neil Armstrong <narmstrong@baylibre.com> 7c38ae95cSJerome Brunet * Jerome Brunet <jbrunet@baylibre.com> 8c38ae95cSJerome Brunet */ 9c38ae95cSJerome Brunet 10c38ae95cSJerome Brunet #include <linux/device.h> 11c38ae95cSJerome Brunet #include <linux/module.h> 12c38ae95cSJerome Brunet #include <linux/regmap.h> 13c38ae95cSJerome Brunet #include <linux/reset-controller.h> 14c38ae95cSJerome Brunet 15c38ae95cSJerome Brunet #include "reset-meson.h" 16c38ae95cSJerome Brunet 17c38ae95cSJerome Brunet struct meson_reset { 18c38ae95cSJerome Brunet const struct meson_reset_param *param; 19c38ae95cSJerome Brunet struct reset_controller_dev rcdev; 20c38ae95cSJerome Brunet struct regmap *map; 21c38ae95cSJerome Brunet }; 22c38ae95cSJerome Brunet 23c38ae95cSJerome Brunet static void meson_reset_offset_and_bit(struct meson_reset *data, 24c38ae95cSJerome Brunet unsigned long id, 25c38ae95cSJerome Brunet unsigned int *offset, 26c38ae95cSJerome Brunet unsigned int *bit) 27c38ae95cSJerome Brunet { 28c38ae95cSJerome Brunet unsigned int stride = regmap_get_reg_stride(data->map); 29c38ae95cSJerome Brunet 30c38ae95cSJerome Brunet *offset = (id / (stride * BITS_PER_BYTE)) * stride; 31c38ae95cSJerome Brunet *bit = id % (stride * BITS_PER_BYTE); 32c38ae95cSJerome Brunet } 33c38ae95cSJerome Brunet 34c38ae95cSJerome Brunet static int meson_reset_reset(struct reset_controller_dev *rcdev, 35c38ae95cSJerome Brunet unsigned long id) 36c38ae95cSJerome Brunet { 37c38ae95cSJerome Brunet struct meson_reset *data = 38c38ae95cSJerome Brunet container_of(rcdev, struct meson_reset, rcdev); 39c38ae95cSJerome Brunet unsigned int offset, bit; 40c38ae95cSJerome Brunet 41c38ae95cSJerome Brunet meson_reset_offset_and_bit(data, id, &offset, &bit); 42c38ae95cSJerome Brunet offset += data->param->reset_offset; 43c38ae95cSJerome Brunet 44c38ae95cSJerome Brunet return regmap_write(data->map, offset, BIT(bit)); 45c38ae95cSJerome Brunet } 46c38ae95cSJerome Brunet 47c38ae95cSJerome Brunet static int meson_reset_level(struct reset_controller_dev *rcdev, 48c38ae95cSJerome Brunet unsigned long id, bool assert) 49c38ae95cSJerome Brunet { 50c38ae95cSJerome Brunet struct meson_reset *data = 51c38ae95cSJerome Brunet container_of(rcdev, struct meson_reset, rcdev); 52c38ae95cSJerome Brunet unsigned int offset, bit; 53c38ae95cSJerome Brunet 54c38ae95cSJerome Brunet meson_reset_offset_and_bit(data, id, &offset, &bit); 55c38ae95cSJerome Brunet offset += data->param->level_offset; 56c38ae95cSJerome Brunet assert ^= data->param->level_low_reset; 57c38ae95cSJerome Brunet 58c38ae95cSJerome Brunet return regmap_update_bits(data->map, offset, 59c38ae95cSJerome Brunet BIT(bit), assert ? BIT(bit) : 0); 60c38ae95cSJerome Brunet } 61c38ae95cSJerome Brunet 62c38ae95cSJerome Brunet static int meson_reset_status(struct reset_controller_dev *rcdev, 63c38ae95cSJerome Brunet unsigned long id) 64c38ae95cSJerome Brunet { 65c38ae95cSJerome Brunet struct meson_reset *data = 66c38ae95cSJerome Brunet container_of(rcdev, struct meson_reset, rcdev); 67c38ae95cSJerome Brunet unsigned int val, offset, bit; 68c38ae95cSJerome Brunet 69c38ae95cSJerome Brunet meson_reset_offset_and_bit(data, id, &offset, &bit); 70c38ae95cSJerome Brunet offset += data->param->level_offset; 71c38ae95cSJerome Brunet 72c38ae95cSJerome Brunet regmap_read(data->map, offset, &val); 73c38ae95cSJerome Brunet val = !!(BIT(bit) & val); 74c38ae95cSJerome Brunet 75c38ae95cSJerome Brunet return val ^ data->param->level_low_reset; 76c38ae95cSJerome Brunet } 77c38ae95cSJerome Brunet 78c38ae95cSJerome Brunet static int meson_reset_assert(struct reset_controller_dev *rcdev, 79c38ae95cSJerome Brunet unsigned long id) 80c38ae95cSJerome Brunet { 81c38ae95cSJerome Brunet return meson_reset_level(rcdev, id, true); 82c38ae95cSJerome Brunet } 83c38ae95cSJerome Brunet 84c38ae95cSJerome Brunet static int meson_reset_deassert(struct reset_controller_dev *rcdev, 85c38ae95cSJerome Brunet unsigned long id) 86c38ae95cSJerome Brunet { 87c38ae95cSJerome Brunet return meson_reset_level(rcdev, id, false); 88c38ae95cSJerome Brunet } 89c38ae95cSJerome Brunet 90*fb4c3158SJerome Brunet static int meson_reset_level_toggle(struct reset_controller_dev *rcdev, 91*fb4c3158SJerome Brunet unsigned long id) 92*fb4c3158SJerome Brunet { 93*fb4c3158SJerome Brunet int ret; 94*fb4c3158SJerome Brunet 95*fb4c3158SJerome Brunet ret = meson_reset_assert(rcdev, id); 96*fb4c3158SJerome Brunet if (ret) 97*fb4c3158SJerome Brunet return ret; 98*fb4c3158SJerome Brunet 99*fb4c3158SJerome Brunet return meson_reset_deassert(rcdev, id); 100*fb4c3158SJerome Brunet } 101*fb4c3158SJerome Brunet 102*fb4c3158SJerome Brunet const struct reset_control_ops meson_reset_ops = { 103c38ae95cSJerome Brunet .reset = meson_reset_reset, 104c38ae95cSJerome Brunet .assert = meson_reset_assert, 105c38ae95cSJerome Brunet .deassert = meson_reset_deassert, 106c38ae95cSJerome Brunet .status = meson_reset_status, 107c38ae95cSJerome Brunet }; 108*fb4c3158SJerome Brunet EXPORT_SYMBOL_NS_GPL(meson_reset_ops, MESON_RESET); 109*fb4c3158SJerome Brunet 110*fb4c3158SJerome Brunet const struct reset_control_ops meson_reset_toggle_ops = { 111*fb4c3158SJerome Brunet .reset = meson_reset_level_toggle, 112*fb4c3158SJerome Brunet .assert = meson_reset_assert, 113*fb4c3158SJerome Brunet .deassert = meson_reset_deassert, 114*fb4c3158SJerome Brunet .status = meson_reset_status, 115*fb4c3158SJerome Brunet }; 116*fb4c3158SJerome Brunet EXPORT_SYMBOL_NS_GPL(meson_reset_toggle_ops, MESON_RESET); 117c38ae95cSJerome Brunet 118c38ae95cSJerome Brunet int meson_reset_controller_register(struct device *dev, struct regmap *map, 119c38ae95cSJerome Brunet const struct meson_reset_param *param) 120c38ae95cSJerome Brunet { 121c38ae95cSJerome Brunet struct meson_reset *data; 122c38ae95cSJerome Brunet 123c38ae95cSJerome Brunet data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 124c38ae95cSJerome Brunet if (!data) 125c38ae95cSJerome Brunet return -ENOMEM; 126c38ae95cSJerome Brunet 127c38ae95cSJerome Brunet data->param = param; 128c38ae95cSJerome Brunet data->map = map; 129c38ae95cSJerome Brunet data->rcdev.owner = dev->driver->owner; 130c38ae95cSJerome Brunet data->rcdev.nr_resets = param->reset_num; 131*fb4c3158SJerome Brunet data->rcdev.ops = data->param->reset_ops; 132c38ae95cSJerome Brunet data->rcdev.of_node = dev->of_node; 133c38ae95cSJerome Brunet 134c38ae95cSJerome Brunet return devm_reset_controller_register(dev, &data->rcdev); 135c38ae95cSJerome Brunet } 136c38ae95cSJerome Brunet EXPORT_SYMBOL_NS_GPL(meson_reset_controller_register, MESON_RESET); 137c38ae95cSJerome Brunet 138c38ae95cSJerome Brunet MODULE_DESCRIPTION("Amlogic Meson Reset Core function"); 139c38ae95cSJerome Brunet MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 140c38ae95cSJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 141c38ae95cSJerome Brunet MODULE_LICENSE("Dual BSD/GPL"); 142c38ae95cSJerome Brunet MODULE_IMPORT_NS(MESON_RESET); 143