File Index
Files and directories
Sign in
FILE

reset.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/mediatek/reset.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2014 MediaTek Inc.
  4 */
  5
  6#include <linux/mfd/syscon.h>
  7#include <linux/module.h>
  8#include <linux/of.h>
  9#include <linux/platform_device.h>
 10#include <linux/regmap.h>
 11#include <linux/slab.h>
 12
 13#include "reset.h"
 14
 15static inline struct mtk_clk_rst_data *to_mtk_clk_rst_data(struct reset_controller_dev *rcdev)
 16{
 17	return container_of(rcdev, struct mtk_clk_rst_data, rcdev);
 18}
 19
 20static int mtk_reset_update(struct reset_controller_dev *rcdev,
 21			    unsigned long id, bool deassert)
 22{
 23	struct mtk_clk_rst_data *data = to_mtk_clk_rst_data(rcdev);
 24	unsigned int val = deassert ? 0 : ~0;
 25
 26	return regmap_update_bits(data->regmap,
 27				  data->desc->rst_bank_ofs[id / RST_NR_PER_BANK],
 28				  BIT(id % RST_NR_PER_BANK), val);
 29}
 30
 31static int mtk_reset_assert(struct reset_controller_dev *rcdev,
 32			    unsigned long id)
 33{
 34	return mtk_reset_update(rcdev, id, false);
 35}
 36
 37static int mtk_reset_deassert(struct reset_controller_dev *rcdev,
 38			      unsigned long id)
 39{
 40	return mtk_reset_update(rcdev, id, true);
 41}
 42
 43static int mtk_reset(struct reset_controller_dev *rcdev, unsigned long id)
 44{
 45	int ret;
 46
 47	ret = mtk_reset_assert(rcdev, id);
 48	if (ret)
 49		return ret;
 50
 51	return mtk_reset_deassert(rcdev, id);
 52}
 53
 54static int mtk_reset_update_set_clr(struct reset_controller_dev *rcdev,
 55				    unsigned long id, bool deassert)
 56{
 57	struct mtk_clk_rst_data *data = to_mtk_clk_rst_data(rcdev);
 58	unsigned int deassert_ofs = deassert ? 0x4 : 0;
 59
 60	return regmap_write(data->regmap,
 61			    data->desc->rst_bank_ofs[id / RST_NR_PER_BANK] +
 62			    deassert_ofs,
 63			    BIT(id % RST_NR_PER_BANK));
 64}
 65
 66static int mtk_reset_assert_set_clr(struct reset_controller_dev *rcdev,
 67				    unsigned long id)
 68{
 69	return mtk_reset_update_set_clr(rcdev, id, false);
 70}
 71
 72static int mtk_reset_deassert_set_clr(struct reset_controller_dev *rcdev,
 73				      unsigned long id)
 74{
 75	return mtk_reset_update_set_clr(rcdev, id, true);
 76}
 77
 78static int mtk_reset_set_clr(struct reset_controller_dev *rcdev,
 79			     unsigned long id)
 80{
 81	int ret;
 82
 83	ret = mtk_reset_assert_set_clr(rcdev, id);
 84	if (ret)
 85		return ret;
 86	return mtk_reset_deassert_set_clr(rcdev, id);
 87}
 88
 89static const struct reset_control_ops mtk_reset_ops = {
 90	.assert = mtk_reset_assert,
 91	.deassert = mtk_reset_deassert,
 92	.reset = mtk_reset,
 93};
 94
 95static const struct reset_control_ops mtk_reset_ops_set_clr = {
 96	.assert = mtk_reset_assert_set_clr,
 97	.deassert = mtk_reset_deassert_set_clr,
 98	.reset = mtk_reset_set_clr,
 99};
100
101static int reset_xlate(struct reset_controller_dev *rcdev,
102		       const struct of_phandle_args *reset_spec)
103{
104	struct mtk_clk_rst_data *data = to_mtk_clk_rst_data(rcdev);
105
106	if (reset_spec->args[0] >= rcdev->nr_resets ||
107	    reset_spec->args[0] >= data->desc->rst_idx_map_nr)
108		return -EINVAL;
109
110	return data->desc->rst_idx_map[reset_spec->args[0]];
111}
112
113int mtk_register_reset_controller_with_dev(struct device *dev,
114					   const struct mtk_clk_rst_desc *desc)
115{
116	struct device_node *np = dev->of_node;
117	struct regmap *regmap;
118	const struct reset_control_ops *rcops = NULL;
119	struct mtk_clk_rst_data *data;
120	int ret;
121
122	if (!desc) {
123		dev_err(dev, "mtk clock reset desc is NULL\n");
124		return -EINVAL;
125	}
126
127	switch (desc->version) {
128	case MTK_RST_SIMPLE:
129		rcops = &mtk_reset_ops;
130		break;
131	case MTK_RST_SET_CLR:
132		rcops = &mtk_reset_ops_set_clr;
133		break;
134	default:
135		dev_err(dev, "Unknown reset version %d\n", desc->version);
136		return -EINVAL;
137	}
138
139	regmap = device_node_to_regmap(np);
140	if (IS_ERR(regmap)) {
141		dev_err(dev, "Cannot find regmap %pe\n", regmap);
142		return PTR_ERR(regmap);
143	}
144
145	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
146	if (!data)
147		return -ENOMEM;
148
149	data->desc = desc;
150	data->regmap = regmap;
151	data->rcdev.owner = THIS_MODULE;
152	data->rcdev.ops = rcops;
153	data->rcdev.of_node = np;
154	data->rcdev.dev = dev;
155
156	if (data->desc->rst_idx_map_nr > 0) {
157		data->rcdev.of_reset_n_cells = 1;
158		data->rcdev.nr_resets = desc->rst_idx_map_nr;
159		data->rcdev.of_xlate = reset_xlate;
160	} else {
161		data->rcdev.nr_resets = desc->rst_bank_nr * RST_NR_PER_BANK;
162	}
163
164	ret = devm_reset_controller_register(dev, &data->rcdev);
165	if (ret) {
166		dev_err(dev, "could not register reset controller: %d\n", ret);
167		return ret;
168	}
169
170	return 0;
171}
172EXPORT_SYMBOL_GPL(mtk_register_reset_controller_with_dev);
173
174MODULE_LICENSE("GPL");
~/ Read-only file preview.