1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 MediaTek Inc.
4 *
5 * Author: Ryder Lee <ryder.lee@mediatek.com>
6 *	   Weijie Gao <weijie.gao@mediatek.com>
7 */
8
9#include <common.h>
10#include <dm.h>
11#include <log.h>
12#include <malloc.h>
13#include <dm/lists.h>
14#include <regmap.h>
15#include <reset-uclass.h>
16#include <syscon.h>
17#include <dm/device-internal.h>
18#include <linux/bitops.h>
19#include <linux/err.h>
20
21struct mediatek_reset_priv {
22	struct regmap *regmap;
23	u32 regofs;
24	u32 nr_resets;
25};
26
27static int mediatek_reset_assert(struct reset_ctl *reset_ctl)
28{
29	struct mediatek_reset_priv *priv = dev_get_priv(reset_ctl->dev);
30	int id = reset_ctl->id;
31
32	if (id >= priv->nr_resets)
33		return -EINVAL;
34
35	return regmap_update_bits(priv->regmap,
36		priv->regofs + ((id / 32) << 2), BIT(id % 32), BIT(id % 32));
37}
38
39static int mediatek_reset_deassert(struct reset_ctl *reset_ctl)
40{
41	struct mediatek_reset_priv *priv = dev_get_priv(reset_ctl->dev);
42	int id = reset_ctl->id;
43
44	if (id >= priv->nr_resets)
45		return -EINVAL;
46
47	return regmap_update_bits(priv->regmap,
48		priv->regofs + ((id / 32) << 2), BIT(id % 32), 0);
49}
50
51struct reset_ops mediatek_reset_ops = {
52	.rst_assert = mediatek_reset_assert,
53	.rst_deassert = mediatek_reset_deassert,
54};
55
56static int mediatek_reset_probe(struct udevice *dev)
57{
58	struct mediatek_reset_priv *priv = dev_get_priv(dev);
59
60	if (!priv->regofs && !priv->nr_resets)
61		return -EINVAL;
62
63	priv->regmap = syscon_node_to_regmap(dev_ofnode(dev));
64	if (IS_ERR(priv->regmap))
65		return PTR_ERR(priv->regmap);
66
67	return 0;
68}
69
70int mediatek_reset_bind(struct udevice *pdev, u32 regofs, u32 num_regs)
71{
72	struct udevice *rst_dev;
73	struct mediatek_reset_priv *priv;
74	int ret;
75
76	ret = device_bind_driver_to_node(pdev, "mediatek_reset", "reset",
77					 dev_ofnode(pdev), &rst_dev);
78	if (ret)
79		return ret;
80
81	priv = malloc(sizeof(struct mediatek_reset_priv));
82	if (!priv)
83		return -ENOMEM;
84
85	priv->regofs = regofs;
86	priv->nr_resets = num_regs * 32;
87	dev_set_priv(rst_dev, priv);
88
89	return 0;
90}
91
92U_BOOT_DRIVER(mediatek_reset) = {
93	.name = "mediatek_reset",
94	.id = UCLASS_RESET,
95	.probe = mediatek_reset_probe,
96	.ops = &mediatek_reset_ops,
97	.priv_auto	= sizeof(struct mediatek_reset_priv),
98};
99