reset-hi3660.c (3209B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2016-2017 Linaro Ltd. 4 * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd. 5 */ 6#include <linux/kernel.h> 7#include <linux/mfd/syscon.h> 8#include <linux/module.h> 9#include <linux/of_device.h> 10#include <linux/platform_device.h> 11#include <linux/regmap.h> 12#include <linux/reset-controller.h> 13 14struct hi3660_reset_controller { 15 struct reset_controller_dev rst; 16 struct regmap *map; 17}; 18 19#define to_hi3660_reset_controller(_rst) \ 20 container_of(_rst, struct hi3660_reset_controller, rst) 21 22static int hi3660_reset_program_hw(struct reset_controller_dev *rcdev, 23 unsigned long idx, bool assert) 24{ 25 struct hi3660_reset_controller *rc = to_hi3660_reset_controller(rcdev); 26 unsigned int offset = idx >> 8; 27 unsigned int mask = BIT(idx & 0x1f); 28 29 if (assert) 30 return regmap_write(rc->map, offset, mask); 31 else 32 return regmap_write(rc->map, offset + 4, mask); 33} 34 35static int hi3660_reset_assert(struct reset_controller_dev *rcdev, 36 unsigned long idx) 37{ 38 return hi3660_reset_program_hw(rcdev, idx, true); 39} 40 41static int hi3660_reset_deassert(struct reset_controller_dev *rcdev, 42 unsigned long idx) 43{ 44 return hi3660_reset_program_hw(rcdev, idx, false); 45} 46 47static int hi3660_reset_dev(struct reset_controller_dev *rcdev, 48 unsigned long idx) 49{ 50 int err; 51 52 err = hi3660_reset_assert(rcdev, idx); 53 if (err) 54 return err; 55 56 return hi3660_reset_deassert(rcdev, idx); 57} 58 59static const struct reset_control_ops hi3660_reset_ops = { 60 .reset = hi3660_reset_dev, 61 .assert = hi3660_reset_assert, 62 .deassert = hi3660_reset_deassert, 63}; 64 65static int hi3660_reset_xlate(struct reset_controller_dev *rcdev, 66 const struct of_phandle_args *reset_spec) 67{ 68 unsigned int offset, bit; 69 70 offset = reset_spec->args[0]; 71 bit = reset_spec->args[1]; 72 73 return (offset << 8) | bit; 74} 75 76static int hi3660_reset_probe(struct platform_device *pdev) 77{ 78 struct hi3660_reset_controller *rc; 79 struct device_node *np = pdev->dev.of_node; 80 struct device *dev = &pdev->dev; 81 82 rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL); 83 if (!rc) 84 return -ENOMEM; 85 86 rc->map = syscon_regmap_lookup_by_phandle(np, "hisilicon,rst-syscon"); 87 if (rc->map == ERR_PTR(-ENODEV)) { 88 /* fall back to the deprecated compatible */ 89 rc->map = syscon_regmap_lookup_by_phandle(np, 90 "hisi,rst-syscon"); 91 } 92 if (IS_ERR(rc->map)) { 93 dev_err(dev, "failed to get hisilicon,rst-syscon\n"); 94 return PTR_ERR(rc->map); 95 } 96 97 rc->rst.ops = &hi3660_reset_ops, 98 rc->rst.of_node = np; 99 rc->rst.of_reset_n_cells = 2; 100 rc->rst.of_xlate = hi3660_reset_xlate; 101 102 return reset_controller_register(&rc->rst); 103} 104 105static const struct of_device_id hi3660_reset_match[] = { 106 { .compatible = "hisilicon,hi3660-reset", }, 107 {}, 108}; 109MODULE_DEVICE_TABLE(of, hi3660_reset_match); 110 111static struct platform_driver hi3660_reset_driver = { 112 .probe = hi3660_reset_probe, 113 .driver = { 114 .name = "hi3660-reset", 115 .of_match_table = hi3660_reset_match, 116 }, 117}; 118 119static int __init hi3660_reset_init(void) 120{ 121 return platform_driver_register(&hi3660_reset_driver); 122} 123arch_initcall(hi3660_reset_init); 124 125MODULE_LICENSE("GPL"); 126MODULE_ALIAS("platform:hi3660-reset"); 127MODULE_DESCRIPTION("HiSilicon Hi3660 Reset Driver");