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