162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (C) 2017 Synopsys.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Synopsys AXS10x reset driver.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
762306a36Sopenharmony_ci * License version 2. This program is licensed "as is" without any
862306a36Sopenharmony_ci * warranty of any kind, whether express or implied.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/reset-controller.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define to_axs10x_rst(p)	container_of((p), struct axs10x_rst, rcdev)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define AXS10X_MAX_RESETS	32
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct axs10x_rst {
2262306a36Sopenharmony_ci	void __iomem			*regs_rst;
2362306a36Sopenharmony_ci	spinlock_t			lock;
2462306a36Sopenharmony_ci	struct reset_controller_dev	rcdev;
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int axs10x_reset_reset(struct reset_controller_dev *rcdev,
2862306a36Sopenharmony_ci			      unsigned long id)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct axs10x_rst *rst = to_axs10x_rst(rcdev);
3162306a36Sopenharmony_ci	unsigned long flags;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	spin_lock_irqsave(&rst->lock, flags);
3462306a36Sopenharmony_ci	writel(BIT(id), rst->regs_rst);
3562306a36Sopenharmony_ci	spin_unlock_irqrestore(&rst->lock, flags);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	return 0;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic const struct reset_control_ops axs10x_reset_ops = {
4162306a36Sopenharmony_ci	.reset	= axs10x_reset_reset,
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int axs10x_reset_probe(struct platform_device *pdev)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct axs10x_rst *rst;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	rst = devm_kzalloc(&pdev->dev, sizeof(*rst), GFP_KERNEL);
4962306a36Sopenharmony_ci	if (!rst)
5062306a36Sopenharmony_ci		return -ENOMEM;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	rst->regs_rst = devm_platform_ioremap_resource(pdev, 0);
5362306a36Sopenharmony_ci	if (IS_ERR(rst->regs_rst))
5462306a36Sopenharmony_ci		return PTR_ERR(rst->regs_rst);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	spin_lock_init(&rst->lock);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	rst->rcdev.owner = THIS_MODULE;
5962306a36Sopenharmony_ci	rst->rcdev.ops = &axs10x_reset_ops;
6062306a36Sopenharmony_ci	rst->rcdev.of_node = pdev->dev.of_node;
6162306a36Sopenharmony_ci	rst->rcdev.nr_resets = AXS10X_MAX_RESETS;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return devm_reset_controller_register(&pdev->dev, &rst->rcdev);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic const struct of_device_id axs10x_reset_dt_match[] = {
6762306a36Sopenharmony_ci	{ .compatible = "snps,axs10x-reset" },
6862306a36Sopenharmony_ci	{ },
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic struct platform_driver axs10x_reset_driver = {
7262306a36Sopenharmony_ci	.probe	= axs10x_reset_probe,
7362306a36Sopenharmony_ci	.driver	= {
7462306a36Sopenharmony_ci		.name = "axs10x-reset",
7562306a36Sopenharmony_ci		.of_match_table = axs10x_reset_dt_match,
7662306a36Sopenharmony_ci	},
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_cibuiltin_platform_driver(axs10x_reset_driver);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciMODULE_AUTHOR("Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>");
8162306a36Sopenharmony_ciMODULE_DESCRIPTION("Synopsys AXS10x reset driver");
8262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
83