1 /* 2 * Copyright (C) 2014 Marvell Technology Group Ltd. 3 * 4 * Antoine Tenart <antoine.tenart@free-electrons.com> 5 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 6 * 7 * This file is licensed under the terms of the GNU General Public 8 * License version 2. This program is licensed "as is" without any 9 * warranty of any kind, whether express or implied. 10 */ 11 12 #include <linux/delay.h> 13 #include <linux/io.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/of_address.h> 17 #include <linux/platform_device.h> 18 #include <linux/reset-controller.h> 19 #include <linux/slab.h> 20 #include <linux/types.h> 21 22 #define BERLIN_MAX_RESETS 32 23 24 #define to_berlin_reset_priv(p) \ 25 container_of((p), struct berlin_reset_priv, rcdev) 26 27 struct berlin_reset_priv { 28 void __iomem *base; 29 unsigned int size; 30 struct reset_controller_dev rcdev; 31 }; 32 33 static int berlin_reset_reset(struct reset_controller_dev *rcdev, 34 unsigned long id) 35 { 36 struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev); 37 int offset = id >> 8; 38 int mask = BIT(id & 0x1f); 39 40 writel(mask, priv->base + offset); 41 42 /* let the reset be effective */ 43 udelay(10); 44 45 return 0; 46 } 47 48 static struct reset_control_ops berlin_reset_ops = { 49 .reset = berlin_reset_reset, 50 }; 51 52 static int berlin_reset_xlate(struct reset_controller_dev *rcdev, 53 const struct of_phandle_args *reset_spec) 54 { 55 struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev); 56 unsigned offset, bit; 57 58 if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells)) 59 return -EINVAL; 60 61 offset = reset_spec->args[0]; 62 bit = reset_spec->args[1]; 63 64 if (offset >= priv->size) 65 return -EINVAL; 66 67 if (bit >= BERLIN_MAX_RESETS) 68 return -EINVAL; 69 70 return (offset << 8) | bit; 71 } 72 73 static int __berlin_reset_init(struct device_node *np) 74 { 75 struct berlin_reset_priv *priv; 76 struct resource res; 77 resource_size_t size; 78 int ret; 79 80 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 81 if (!priv) 82 return -ENOMEM; 83 84 ret = of_address_to_resource(np, 0, &res); 85 if (ret) 86 goto err; 87 88 size = resource_size(&res); 89 priv->base = ioremap(res.start, size); 90 if (!priv->base) { 91 ret = -ENOMEM; 92 goto err; 93 } 94 priv->size = size; 95 96 priv->rcdev.owner = THIS_MODULE; 97 priv->rcdev.ops = &berlin_reset_ops; 98 priv->rcdev.of_node = np; 99 priv->rcdev.of_reset_n_cells = 2; 100 priv->rcdev.of_xlate = berlin_reset_xlate; 101 102 reset_controller_register(&priv->rcdev); 103 104 return 0; 105 106 err: 107 kfree(priv); 108 return ret; 109 } 110 111 static const struct of_device_id berlin_reset_of_match[] __initconst = { 112 { .compatible = "marvell,berlin2-chip-ctrl" }, 113 { .compatible = "marvell,berlin2cd-chip-ctrl" }, 114 { .compatible = "marvell,berlin2q-chip-ctrl" }, 115 { }, 116 }; 117 118 static int __init berlin_reset_init(void) 119 { 120 struct device_node *np; 121 int ret; 122 123 for_each_matching_node(np, berlin_reset_of_match) { 124 ret = __berlin_reset_init(np); 125 if (ret) 126 return ret; 127 } 128 129 return 0; 130 } 131 arch_initcall(berlin_reset_init); 132