linux/drivers/reset/reset-th1520.c

136 lines
3.3 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2024 Samsung Electronics Co., Ltd.
* Author: Michal Wilczynski <m.wilczynski@samsung.com>
*/
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/regmap.h>
#include <dt-bindings/reset/thead,th1520-reset.h>
/* register offset in VOSYS_REGMAP */
#define TH1520_GPU_RST_CFG 0x0
#define TH1520_GPU_RST_CFG_MASK GENMASK(1, 0)
/* register values */
#define TH1520_GPU_SW_GPU_RST BIT(0)
#define TH1520_GPU_SW_CLKGEN_RST BIT(1)
struct th1520_reset_priv {
struct reset_controller_dev rcdev;
struct regmap *map;
};
struct th1520_reset_map {
u32 bit;
u32 reg;
};
static const struct th1520_reset_map th1520_resets[] = {
[TH1520_RESET_ID_GPU] = {
.bit = TH1520_GPU_SW_GPU_RST,
.reg = TH1520_GPU_RST_CFG,
},
[TH1520_RESET_ID_GPU_CLKGEN] = {
.bit = TH1520_GPU_SW_CLKGEN_RST,
.reg = TH1520_GPU_RST_CFG,
}
};
static inline struct th1520_reset_priv *
to_th1520_reset(struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct th1520_reset_priv, rcdev);
}
static int th1520_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct th1520_reset_priv *priv = to_th1520_reset(rcdev);
const struct th1520_reset_map *reset;
reset = &th1520_resets[id];
return regmap_update_bits(priv->map, reset->reg, reset->bit, 0);
}
static int th1520_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct th1520_reset_priv *priv = to_th1520_reset(rcdev);
const struct th1520_reset_map *reset;
reset = &th1520_resets[id];
return regmap_update_bits(priv->map, reset->reg, reset->bit,
reset->bit);
}
static const struct reset_control_ops th1520_reset_ops = {
.assert = th1520_reset_assert,
.deassert = th1520_reset_deassert,
};
static const struct regmap_config th1520_reset_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.fast_io = true,
};
static int th1520_reset_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct th1520_reset_priv *priv;
void __iomem *base;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
priv->map = devm_regmap_init_mmio(dev, base,
&th1520_reset_regmap_config);
if (IS_ERR(priv->map))
return PTR_ERR(priv->map);
/* Initialize GPU resets to asserted state */
ret = regmap_update_bits(priv->map, TH1520_GPU_RST_CFG,
TH1520_GPU_RST_CFG_MASK, 0);
if (ret)
return ret;
priv->rcdev.owner = THIS_MODULE;
priv->rcdev.nr_resets = ARRAY_SIZE(th1520_resets);
priv->rcdev.ops = &th1520_reset_ops;
priv->rcdev.of_node = dev->of_node;
return devm_reset_controller_register(dev, &priv->rcdev);
}
static const struct of_device_id th1520_reset_match[] = {
{ .compatible = "thead,th1520-reset" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, th1520_reset_match);
static struct platform_driver th1520_reset_driver = {
.driver = {
.name = "th1520-reset",
.of_match_table = th1520_reset_match,
},
.probe = th1520_reset_probe,
};
module_platform_driver(th1520_reset_driver);
MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>");
MODULE_DESCRIPTION("T-HEAD TH1520 SoC reset controller");
MODULE_LICENSE("GPL");