131 lines · 2.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Copyright (c) 2020 Western Digital Corporation or its affiliates. */#include <linux/of.h>#include <linux/platform_device.h>#include <linux/reset-controller.h>#include <linux/delay.h>#include <linux/mfd/syscon.h>#include <linux/regmap.h>#include <soc/canaan/k210-sysctl.h> #include <dt-bindings/reset/k210-rst.h> #define K210_RST_MASK	0x27FFFFFF struct k210_rst {	struct regmap *map;	struct reset_controller_dev rcdev;}; static inline struct k210_rst *to_k210_rst(struct reset_controller_dev *rcdev){	return container_of(rcdev, struct k210_rst, rcdev);} static inline int k210_rst_assert(struct reset_controller_dev *rcdev,				  unsigned long id){	struct k210_rst *ksr = to_k210_rst(rcdev); 	return regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, BIT(id), 1);} static inline int k210_rst_deassert(struct reset_controller_dev *rcdev,				    unsigned long id){	struct k210_rst *ksr = to_k210_rst(rcdev); 	return regmap_update_bits(ksr->map, K210_SYSCTL_PERI_RESET, BIT(id), 0);} static int k210_rst_reset(struct reset_controller_dev *rcdev,			  unsigned long id){	int ret; 	ret = k210_rst_assert(rcdev, id);	if (ret == 0) {		udelay(10);		ret = k210_rst_deassert(rcdev, id);	} 	return ret;} static int k210_rst_status(struct reset_controller_dev *rcdev,			   unsigned long id){	struct k210_rst *ksr = to_k210_rst(rcdev);	u32 reg, bit = BIT(id);	int ret; 	ret = regmap_read(ksr->map, K210_SYSCTL_PERI_RESET, &reg);	if (ret)		return ret; 	return reg & bit;} static int k210_rst_xlate(struct reset_controller_dev *rcdev,			  const struct of_phandle_args *reset_spec){	unsigned long id = reset_spec->args[0]; 	if (!(BIT(id) & K210_RST_MASK))		return -EINVAL; 	return id;} static const struct reset_control_ops k210_rst_ops = {	.assert		= k210_rst_assert,	.deassert	= k210_rst_deassert,	.reset		= k210_rst_reset,	.status		= k210_rst_status,}; static int k210_rst_probe(struct platform_device *pdev){	struct device *dev = &pdev->dev;	struct device_node *parent_np;	struct k210_rst *ksr; 	dev_info(dev, "K210 reset controller\n"); 	ksr = devm_kzalloc(dev, sizeof(*ksr), GFP_KERNEL);	if (!ksr)		return -ENOMEM; 	parent_np = of_get_parent(dev->of_node);	ksr->map = syscon_node_to_regmap(parent_np);	of_node_put(parent_np);	if (IS_ERR(ksr->map))		return PTR_ERR(ksr->map); 	ksr->rcdev.owner = THIS_MODULE;	ksr->rcdev.dev = dev;	ksr->rcdev.of_node = dev->of_node;	ksr->rcdev.ops = &k210_rst_ops;	ksr->rcdev.nr_resets = fls(K210_RST_MASK);	ksr->rcdev.of_reset_n_cells = 1;	ksr->rcdev.of_xlate = k210_rst_xlate; 	return devm_reset_controller_register(dev, &ksr->rcdev);} static const struct of_device_id k210_rst_dt_ids[] = {	{ .compatible = "canaan,k210-rst" },	{ /* sentinel */ },}; static struct platform_driver k210_rst_driver = {	.probe	= k210_rst_probe,	.driver = {		.name		= "k210-rst",		.of_match_table	= k210_rst_dt_ids,	},};builtin_platform_driver(k210_rst_driver);