1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Hisilicon Hi6220 reset controller driver 4 * 5 * Copyright (c) 2016 Linaro Limited. 6 * Copyright (c) 2015-2016 HiSilicon Limited. 7 * 8 * Author: Feng Chen <puck.chen@hisilicon.com> 9 */ 10 11 #include <linux/io.h> 12 #include <linux/init.h> 13 #include <linux/module.h> 14 #include <linux/bitops.h> 15 #include <linux/of.h> 16 #include <linux/regmap.h> 17 #include <linux/mfd/syscon.h> 18 #include <linux/reset-controller.h> 19 #include <linux/reset.h> 20 #include <linux/platform_device.h> 21 22 #define PERIPH_ASSERT_OFFSET 0x300 23 #define PERIPH_DEASSERT_OFFSET 0x304 24 #define PERIPH_MAX_INDEX 0x509 25 26 #define SC_MEDIA_RSTEN 0x052C 27 #define SC_MEDIA_RSTDIS 0x0530 28 #define MEDIA_MAX_INDEX 8 29 30 #define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev) 31 32 enum hi6220_reset_ctrl_type { 33 PERIPHERAL, 34 MEDIA, 35 AO, 36 }; 37 38 struct hi6220_reset_data { 39 struct reset_controller_dev rc_dev; 40 struct regmap *regmap; 41 }; 42 43 static int hi6220_peripheral_assert(struct reset_controller_dev *rc_dev, 44 unsigned long idx) 45 { 46 struct hi6220_reset_data *data = to_reset_data(rc_dev); 47 struct regmap *regmap = data->regmap; 48 u32 bank = idx >> 8; 49 u32 offset = idx & 0xff; 50 u32 reg = PERIPH_ASSERT_OFFSET + bank * 0x10; 51 52 return regmap_write(regmap, reg, BIT(offset)); 53 } 54 55 static int hi6220_peripheral_deassert(struct reset_controller_dev *rc_dev, 56 unsigned long idx) 57 { 58 struct hi6220_reset_data *data = to_reset_data(rc_dev); 59 struct regmap *regmap = data->regmap; 60 u32 bank = idx >> 8; 61 u32 offset = idx & 0xff; 62 u32 reg = PERIPH_DEASSERT_OFFSET + bank * 0x10; 63 64 return regmap_write(regmap, reg, BIT(offset)); 65 } 66 67 static const struct reset_control_ops hi6220_peripheral_reset_ops = { 68 .assert = hi6220_peripheral_assert, 69 .deassert = hi6220_peripheral_deassert, 70 }; 71 72 static int hi6220_media_assert(struct reset_controller_dev *rc_dev, 73 unsigned long idx) 74 { 75 struct hi6220_reset_data *data = to_reset_data(rc_dev); 76 struct regmap *regmap = data->regmap; 77 78 return regmap_write(regmap, SC_MEDIA_RSTEN, BIT(idx)); 79 } 80 81 static int hi6220_media_deassert(struct reset_controller_dev *rc_dev, 82 unsigned long idx) 83 { 84 struct hi6220_reset_data *data = to_reset_data(rc_dev); 85 struct regmap *regmap = data->regmap; 86 87 return regmap_write(regmap, SC_MEDIA_RSTDIS, BIT(idx)); 88 } 89 90 static const struct reset_control_ops hi6220_media_reset_ops = { 91 .assert = hi6220_media_assert, 92 .deassert = hi6220_media_deassert, 93 }; 94 95 #define AO_SCTRL_SC_PW_CLKEN0 0x800 96 #define AO_SCTRL_SC_PW_CLKDIS0 0x804 97 98 #define AO_SCTRL_SC_PW_RSTEN0 0x810 99 #define AO_SCTRL_SC_PW_RSTDIS0 0x814 100 101 #define AO_SCTRL_SC_PW_ISOEN0 0x820 102 #define AO_SCTRL_SC_PW_ISODIS0 0x824 103 #define AO_MAX_INDEX 12 104 105 static int hi6220_ao_assert(struct reset_controller_dev *rc_dev, 106 unsigned long idx) 107 { 108 struct hi6220_reset_data *data = to_reset_data(rc_dev); 109 struct regmap *regmap = data->regmap; 110 int ret; 111 112 ret = regmap_write(regmap, AO_SCTRL_SC_PW_RSTEN0, BIT(idx)); 113 if (ret) 114 return ret; 115 116 ret = regmap_write(regmap, AO_SCTRL_SC_PW_ISOEN0, BIT(idx)); 117 if (ret) 118 return ret; 119 120 ret = regmap_write(regmap, AO_SCTRL_SC_PW_CLKDIS0, BIT(idx)); 121 return ret; 122 } 123 124 static int hi6220_ao_deassert(struct reset_controller_dev *rc_dev, 125 unsigned long idx) 126 { 127 struct hi6220_reset_data *data = to_reset_data(rc_dev); 128 struct regmap *regmap = data->regmap; 129 int ret; 130 131 /* 132 * It was suggested to disable isolation before enabling 133 * the clocks and deasserting reset, to avoid glitches. 134 * But this order is preserved to keep it matching the 135 * vendor code. 136 */ 137 ret = regmap_write(regmap, AO_SCTRL_SC_PW_RSTDIS0, BIT(idx)); 138 if (ret) 139 return ret; 140 141 ret = regmap_write(regmap, AO_SCTRL_SC_PW_ISODIS0, BIT(idx)); 142 if (ret) 143 return ret; 144 145 ret = regmap_write(regmap, AO_SCTRL_SC_PW_CLKEN0, BIT(idx)); 146 return ret; 147 } 148 149 static const struct reset_control_ops hi6220_ao_reset_ops = { 150 .assert = hi6220_ao_assert, 151 .deassert = hi6220_ao_deassert, 152 }; 153 154 static int hi6220_reset_probe(struct platform_device *pdev) 155 { 156 struct device_node *np = pdev->dev.of_node; 157 struct device *dev = &pdev->dev; 158 enum hi6220_reset_ctrl_type type; 159 struct hi6220_reset_data *data; 160 struct regmap *regmap; 161 162 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 163 if (!data) 164 return -ENOMEM; 165 166 type = (uintptr_t)of_device_get_match_data(dev); 167 168 regmap = syscon_node_to_regmap(np); 169 if (IS_ERR(regmap)) { 170 dev_err(dev, "failed to get reset controller regmap\n"); 171 return PTR_ERR(regmap); 172 } 173 174 data->regmap = regmap; 175 data->rc_dev.of_node = np; 176 if (type == MEDIA) { 177 data->rc_dev.ops = &hi6220_media_reset_ops; 178 data->rc_dev.nr_resets = MEDIA_MAX_INDEX; 179 } else if (type == PERIPHERAL) { 180 data->rc_dev.ops = &hi6220_peripheral_reset_ops; 181 data->rc_dev.nr_resets = PERIPH_MAX_INDEX; 182 } else { 183 data->rc_dev.ops = &hi6220_ao_reset_ops; 184 data->rc_dev.nr_resets = AO_MAX_INDEX; 185 } 186 187 return reset_controller_register(&data->rc_dev); 188 } 189 190 static const struct of_device_id hi6220_reset_match[] = { 191 { 192 .compatible = "hisilicon,hi6220-sysctrl", 193 .data = (void *)PERIPHERAL, 194 }, 195 { 196 .compatible = "hisilicon,hi6220-mediactrl", 197 .data = (void *)MEDIA, 198 }, 199 { 200 .compatible = "hisilicon,hi6220-aoctrl", 201 .data = (void *)AO, 202 }, 203 { /* sentinel */ }, 204 }; 205 MODULE_DEVICE_TABLE(of, hi6220_reset_match); 206 207 static struct platform_driver hi6220_reset_driver = { 208 .probe = hi6220_reset_probe, 209 .driver = { 210 .name = "reset-hi6220", 211 .of_match_table = hi6220_reset_match, 212 }, 213 }; 214 215 static int __init hi6220_reset_init(void) 216 { 217 return platform_driver_register(&hi6220_reset_driver); 218 } 219 220 postcore_initcall(hi6220_reset_init); 221 222 MODULE_LICENSE("GPL v2"); 223