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 }; 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 static int hi6220_reset_probe(struct platform_device *pdev) 96 { 97 struct device_node *np = pdev->dev.of_node; 98 struct device *dev = &pdev->dev; 99 enum hi6220_reset_ctrl_type type; 100 struct hi6220_reset_data *data; 101 struct regmap *regmap; 102 103 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 104 if (!data) 105 return -ENOMEM; 106 107 type = (enum hi6220_reset_ctrl_type)of_device_get_match_data(dev); 108 109 regmap = syscon_node_to_regmap(np); 110 if (IS_ERR(regmap)) { 111 dev_err(dev, "failed to get reset controller regmap\n"); 112 return PTR_ERR(regmap); 113 } 114 115 data->regmap = regmap; 116 data->rc_dev.of_node = np; 117 if (type == MEDIA) { 118 data->rc_dev.ops = &hi6220_media_reset_ops; 119 data->rc_dev.nr_resets = MEDIA_MAX_INDEX; 120 } else { 121 data->rc_dev.ops = &hi6220_peripheral_reset_ops; 122 data->rc_dev.nr_resets = PERIPH_MAX_INDEX; 123 } 124 125 return reset_controller_register(&data->rc_dev); 126 } 127 128 static const struct of_device_id hi6220_reset_match[] = { 129 { 130 .compatible = "hisilicon,hi6220-sysctrl", 131 .data = (void *)PERIPHERAL, 132 }, 133 { 134 .compatible = "hisilicon,hi6220-mediactrl", 135 .data = (void *)MEDIA, 136 }, 137 { /* sentinel */ }, 138 }; 139 MODULE_DEVICE_TABLE(of, hi6220_reset_match); 140 141 static struct platform_driver hi6220_reset_driver = { 142 .probe = hi6220_reset_probe, 143 .driver = { 144 .name = "reset-hi6220", 145 .of_match_table = hi6220_reset_match, 146 }, 147 }; 148 149 static int __init hi6220_reset_init(void) 150 { 151 return platform_driver_register(&hi6220_reset_driver); 152 } 153 154 postcore_initcall(hi6220_reset_init); 155 156 MODULE_LICENSE("GPL v2"); 157