1 /* 2 * Copyright (c) 2014 MediaTek Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <linux/mfd/syscon.h> 15 #include <linux/module.h> 16 #include <linux/of.h> 17 #include <linux/platform_device.h> 18 #include <linux/regmap.h> 19 #include <linux/reset-controller.h> 20 #include <linux/slab.h> 21 22 #include "clk-mtk.h" 23 24 struct mtk_reset { 25 struct regmap *regmap; 26 int regofs; 27 struct reset_controller_dev rcdev; 28 }; 29 30 static int mtk_reset_assert(struct reset_controller_dev *rcdev, 31 unsigned long id) 32 { 33 struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev); 34 35 return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2), 36 BIT(id % 32), ~0); 37 } 38 39 static int mtk_reset_deassert(struct reset_controller_dev *rcdev, 40 unsigned long id) 41 { 42 struct mtk_reset *data = container_of(rcdev, struct mtk_reset, rcdev); 43 44 return regmap_update_bits(data->regmap, data->regofs + ((id / 32) << 2), 45 BIT(id % 32), 0); 46 } 47 48 static int mtk_reset(struct reset_controller_dev *rcdev, 49 unsigned long id) 50 { 51 int ret; 52 53 ret = mtk_reset_assert(rcdev, id); 54 if (ret) 55 return ret; 56 57 return mtk_reset_deassert(rcdev, id); 58 } 59 60 static const struct reset_control_ops mtk_reset_ops = { 61 .assert = mtk_reset_assert, 62 .deassert = mtk_reset_deassert, 63 .reset = mtk_reset, 64 }; 65 66 void mtk_register_reset_controller(struct device_node *np, 67 unsigned int num_regs, int regofs) 68 { 69 struct mtk_reset *data; 70 int ret; 71 struct regmap *regmap; 72 73 regmap = syscon_node_to_regmap(np); 74 if (IS_ERR(regmap)) { 75 pr_err("Cannot find regmap for %pOF: %ld\n", np, 76 PTR_ERR(regmap)); 77 return; 78 } 79 80 data = kzalloc(sizeof(*data), GFP_KERNEL); 81 if (!data) 82 return; 83 84 data->regmap = regmap; 85 data->regofs = regofs; 86 data->rcdev.owner = THIS_MODULE; 87 data->rcdev.nr_resets = num_regs * 32; 88 data->rcdev.ops = &mtk_reset_ops; 89 data->rcdev.of_node = np; 90 91 ret = reset_controller_register(&data->rcdev); 92 if (ret) { 93 pr_err("could not register reset controller: %d\n", ret); 94 kfree(data); 95 return; 96 } 97 } 98