162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Hisilicon Reset Controller Driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015-2016 HiSilicon Technologies Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/of_address.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <linux/reset-controller.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci#include "reset.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define	HISI_RESET_BIT_MASK	0x1f
1762306a36Sopenharmony_ci#define	HISI_RESET_OFFSET_SHIFT	8
1862306a36Sopenharmony_ci#define	HISI_RESET_OFFSET_MASK	0xffff00
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct hisi_reset_controller {
2162306a36Sopenharmony_ci	spinlock_t	lock;
2262306a36Sopenharmony_ci	void __iomem	*membase;
2362306a36Sopenharmony_ci	struct reset_controller_dev	rcdev;
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define to_hisi_reset_controller(rcdev)  \
2862306a36Sopenharmony_ci	container_of(rcdev, struct hisi_reset_controller, rcdev)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic int hisi_reset_of_xlate(struct reset_controller_dev *rcdev,
3162306a36Sopenharmony_ci			const struct of_phandle_args *reset_spec)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	u32 offset;
3462306a36Sopenharmony_ci	u8 bit;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	offset = (reset_spec->args[0] << HISI_RESET_OFFSET_SHIFT)
3762306a36Sopenharmony_ci		& HISI_RESET_OFFSET_MASK;
3862306a36Sopenharmony_ci	bit = reset_spec->args[1] & HISI_RESET_BIT_MASK;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return (offset | bit);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic int hisi_reset_assert(struct reset_controller_dev *rcdev,
4462306a36Sopenharmony_ci			      unsigned long id)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev);
4762306a36Sopenharmony_ci	unsigned long flags;
4862306a36Sopenharmony_ci	u32 offset, reg;
4962306a36Sopenharmony_ci	u8 bit;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	offset = (id & HISI_RESET_OFFSET_MASK) >> HISI_RESET_OFFSET_SHIFT;
5262306a36Sopenharmony_ci	bit = id & HISI_RESET_BIT_MASK;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	spin_lock_irqsave(&rstc->lock, flags);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	reg = readl(rstc->membase + offset);
5762306a36Sopenharmony_ci	writel(reg | BIT(bit), rstc->membase + offset);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	spin_unlock_irqrestore(&rstc->lock, flags);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return 0;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic int hisi_reset_deassert(struct reset_controller_dev *rcdev,
6562306a36Sopenharmony_ci				unsigned long id)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct hisi_reset_controller *rstc = to_hisi_reset_controller(rcdev);
6862306a36Sopenharmony_ci	unsigned long flags;
6962306a36Sopenharmony_ci	u32 offset, reg;
7062306a36Sopenharmony_ci	u8 bit;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	offset = (id & HISI_RESET_OFFSET_MASK) >> HISI_RESET_OFFSET_SHIFT;
7362306a36Sopenharmony_ci	bit = id & HISI_RESET_BIT_MASK;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	spin_lock_irqsave(&rstc->lock, flags);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	reg = readl(rstc->membase + offset);
7862306a36Sopenharmony_ci	writel(reg & ~BIT(bit), rstc->membase + offset);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	spin_unlock_irqrestore(&rstc->lock, flags);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic const struct reset_control_ops hisi_reset_ops = {
8662306a36Sopenharmony_ci	.assert		= hisi_reset_assert,
8762306a36Sopenharmony_ci	.deassert	= hisi_reset_deassert,
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct hisi_reset_controller *rstc;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	rstc = devm_kmalloc(&pdev->dev, sizeof(*rstc), GFP_KERNEL);
9562306a36Sopenharmony_ci	if (!rstc)
9662306a36Sopenharmony_ci		return NULL;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	rstc->membase = devm_platform_ioremap_resource(pdev, 0);
9962306a36Sopenharmony_ci	if (IS_ERR(rstc->membase))
10062306a36Sopenharmony_ci		return NULL;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	spin_lock_init(&rstc->lock);
10362306a36Sopenharmony_ci	rstc->rcdev.owner = THIS_MODULE;
10462306a36Sopenharmony_ci	rstc->rcdev.ops = &hisi_reset_ops;
10562306a36Sopenharmony_ci	rstc->rcdev.of_node = pdev->dev.of_node;
10662306a36Sopenharmony_ci	rstc->rcdev.of_reset_n_cells = 2;
10762306a36Sopenharmony_ci	rstc->rcdev.of_xlate = hisi_reset_of_xlate;
10862306a36Sopenharmony_ci	reset_controller_register(&rstc->rcdev);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return rstc;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_reset_init);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_civoid hisi_reset_exit(struct hisi_reset_controller *rstc)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	reset_controller_unregister(&rstc->rcdev);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_reset_exit);
119