Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

reset: add the Berlin reset controller driver

Add a reset controller for Marvell Berlin SoCs which is used by the
USB PHYs drivers (for now).

Signed-off-by: Antoine Ténart <antoine.tenart@free-electrons.com>
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>

authored by

Antoine Ténart and committed by
Sebastian Hesselbarth
bd13251f f114040e

+132
+1
drivers/reset/Makefile
··· 1 1 obj-$(CONFIG_RESET_CONTROLLER) += core.o 2 2 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o 3 + obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o 3 4 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o 4 5 obj-$(CONFIG_ARCH_STI) += sti/
+131
drivers/reset/reset-berlin.c
··· 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);