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