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 14 struct 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 22 static 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 35 static 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 41 static 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 47 static 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 59 static 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 65 static 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 76 static 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, "hisi,rst-syscon"); 87 if (IS_ERR(rc->map)) { 88 dev_err(dev, "failed to get hi3660,rst-syscon\n"); 89 return PTR_ERR(rc->map); 90 } 91 92 rc->rst.ops = &hi3660_reset_ops, 93 rc->rst.of_node = np; 94 rc->rst.of_reset_n_cells = 2; 95 rc->rst.of_xlate = hi3660_reset_xlate; 96 97 return reset_controller_register(&rc->rst); 98 } 99 100 static const struct of_device_id hi3660_reset_match[] = { 101 { .compatible = "hisilicon,hi3660-reset", }, 102 {}, 103 }; 104 MODULE_DEVICE_TABLE(of, hi3660_reset_match); 105 106 static struct platform_driver hi3660_reset_driver = { 107 .probe = hi3660_reset_probe, 108 .driver = { 109 .name = "hi3660-reset", 110 .of_match_table = hi3660_reset_match, 111 }, 112 }; 113 114 static int __init hi3660_reset_init(void) 115 { 116 return platform_driver_register(&hi3660_reset_driver); 117 } 118 arch_initcall(hi3660_reset_init); 119 120 MODULE_LICENSE("GPL"); 121 MODULE_ALIAS("platform:hi3660-reset"); 122 MODULE_DESCRIPTION("HiSilicon Hi3660 Reset Driver"); 123