xref: /openbmc/linux/drivers/reset/reset-berlin.c (revision 34d6f206a88c2651d216bd3487ac956a40b2ba8e)
1bd13251fSAntoine Ténart /*
2bd13251fSAntoine Ténart  * Copyright (C) 2014 Marvell Technology Group Ltd.
3bd13251fSAntoine Ténart  *
4ed4dba99SPaul Gortmaker  * Marvell Berlin reset driver
5ed4dba99SPaul Gortmaker  *
6bd13251fSAntoine Ténart  * Antoine Tenart <antoine.tenart@free-electrons.com>
7bd13251fSAntoine Ténart  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
8bd13251fSAntoine Ténart  *
9bd13251fSAntoine Ténart  * This file is licensed under the terms of the GNU General Public
10bd13251fSAntoine Ténart  * License version 2. This program is licensed "as is" without any
11bd13251fSAntoine Ténart  * warranty of any kind, whether express or implied.
12bd13251fSAntoine Ténart  */
13bd13251fSAntoine Ténart 
14bd13251fSAntoine Ténart #include <linux/delay.h>
15bd13251fSAntoine Ténart #include <linux/io.h>
16aed6f3caSAntoine Tenart #include <linux/mfd/syscon.h>
175e787cdfSJisheng Zhang #include <linux/module.h>
18bd13251fSAntoine Ténart #include <linux/of.h>
19bd13251fSAntoine Ténart #include <linux/of_address.h>
20bd13251fSAntoine Ténart #include <linux/platform_device.h>
21aed6f3caSAntoine Tenart #include <linux/regmap.h>
22bd13251fSAntoine Ténart #include <linux/reset-controller.h>
23bd13251fSAntoine Ténart #include <linux/slab.h>
24bd13251fSAntoine Ténart #include <linux/types.h>
25bd13251fSAntoine Ténart 
26bd13251fSAntoine Ténart #define BERLIN_MAX_RESETS	32
27bd13251fSAntoine Ténart 
28bd13251fSAntoine Ténart #define to_berlin_reset_priv(p)		\
29bd13251fSAntoine Ténart 	container_of((p), struct berlin_reset_priv, rcdev)
30bd13251fSAntoine Ténart 
31bd13251fSAntoine Ténart struct berlin_reset_priv {
32aed6f3caSAntoine Tenart 	struct regmap			*regmap;
33bd13251fSAntoine Ténart 	struct reset_controller_dev	rcdev;
34bd13251fSAntoine Ténart };
35bd13251fSAntoine Ténart 
berlin_reset_reset(struct reset_controller_dev * rcdev,unsigned long id)36bd13251fSAntoine Ténart static int berlin_reset_reset(struct reset_controller_dev *rcdev,
37bd13251fSAntoine Ténart 			      unsigned long id)
38bd13251fSAntoine Ténart {
39bd13251fSAntoine Ténart 	struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev);
40bd13251fSAntoine Ténart 	int offset = id >> 8;
41bd13251fSAntoine Ténart 	int mask = BIT(id & 0x1f);
42bd13251fSAntoine Ténart 
43aed6f3caSAntoine Tenart 	regmap_write(priv->regmap, offset, mask);
44bd13251fSAntoine Ténart 
45bd13251fSAntoine Ténart 	/* let the reset be effective */
46bd13251fSAntoine Ténart 	udelay(10);
47bd13251fSAntoine Ténart 
48bd13251fSAntoine Ténart 	return 0;
49bd13251fSAntoine Ténart }
50bd13251fSAntoine Ténart 
51b7a90075SPhilipp Zabel static const struct reset_control_ops berlin_reset_ops = {
52bd13251fSAntoine Ténart 	.reset	= berlin_reset_reset,
53bd13251fSAntoine Ténart };
54bd13251fSAntoine Ténart 
berlin_reset_xlate(struct reset_controller_dev * rcdev,const struct of_phandle_args * reset_spec)55bd13251fSAntoine Ténart static int berlin_reset_xlate(struct reset_controller_dev *rcdev,
56bd13251fSAntoine Ténart 			      const struct of_phandle_args *reset_spec)
57bd13251fSAntoine Ténart {
58534d3fa2SPhilipp Zabel 	unsigned int offset, bit;
59bd13251fSAntoine Ténart 
60bd13251fSAntoine Ténart 	offset = reset_spec->args[0];
61bd13251fSAntoine Ténart 	bit = reset_spec->args[1];
62bd13251fSAntoine Ténart 
63bd13251fSAntoine Ténart 	if (bit >= BERLIN_MAX_RESETS)
64bd13251fSAntoine Ténart 		return -EINVAL;
65bd13251fSAntoine Ténart 
66bd13251fSAntoine Ténart 	return (offset << 8) | bit;
67bd13251fSAntoine Ténart }
68bd13251fSAntoine Ténart 
berlin2_reset_probe(struct platform_device * pdev)69aed6f3caSAntoine Tenart static int berlin2_reset_probe(struct platform_device *pdev)
70aed6f3caSAntoine Tenart {
71*cfbf049dSKrzysztof Kozlowski 	struct device_node *parent_np;
72aed6f3caSAntoine Tenart 	struct berlin_reset_priv *priv;
73aed6f3caSAntoine Tenart 
74aed6f3caSAntoine Tenart 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
75aed6f3caSAntoine Tenart 	if (!priv)
76aed6f3caSAntoine Tenart 		return -ENOMEM;
77aed6f3caSAntoine Tenart 
78*cfbf049dSKrzysztof Kozlowski 	parent_np = of_get_parent(pdev->dev.of_node);
79aed6f3caSAntoine Tenart 	priv->regmap = syscon_node_to_regmap(parent_np);
80aed6f3caSAntoine Tenart 	of_node_put(parent_np);
81aed6f3caSAntoine Tenart 	if (IS_ERR(priv->regmap))
82aed6f3caSAntoine Tenart 		return PTR_ERR(priv->regmap);
83aed6f3caSAntoine Tenart 
84aed6f3caSAntoine Tenart 	priv->rcdev.owner = THIS_MODULE;
85aed6f3caSAntoine Tenart 	priv->rcdev.ops = &berlin_reset_ops;
86aed6f3caSAntoine Tenart 	priv->rcdev.of_node = pdev->dev.of_node;
87aed6f3caSAntoine Tenart 	priv->rcdev.of_reset_n_cells = 2;
88aed6f3caSAntoine Tenart 	priv->rcdev.of_xlate = berlin_reset_xlate;
89aed6f3caSAntoine Tenart 
90d1f15aa0SMasahiro Yamada 	return reset_controller_register(&priv->rcdev);
91aed6f3caSAntoine Tenart }
92aed6f3caSAntoine Tenart 
93aed6f3caSAntoine Tenart static const struct of_device_id berlin_reset_dt_match[] = {
94aed6f3caSAntoine Tenart 	{ .compatible = "marvell,berlin2-reset" },
95aed6f3caSAntoine Tenart 	{ },
96aed6f3caSAntoine Tenart };
975e787cdfSJisheng Zhang MODULE_DEVICE_TABLE(of, berlin_reset_dt_match);
98aed6f3caSAntoine Tenart 
99aed6f3caSAntoine Tenart static struct platform_driver berlin_reset_driver = {
100aed6f3caSAntoine Tenart 	.probe	= berlin2_reset_probe,
101aed6f3caSAntoine Tenart 	.driver	= {
102aed6f3caSAntoine Tenart 		.name = "berlin2-reset",
103aed6f3caSAntoine Tenart 		.of_match_table = berlin_reset_dt_match,
104aed6f3caSAntoine Tenart 	},
105aed6f3caSAntoine Tenart };
1065e787cdfSJisheng Zhang module_platform_driver(berlin_reset_driver);
1075e787cdfSJisheng Zhang 
1085e787cdfSJisheng Zhang MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
1095e787cdfSJisheng Zhang MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>");
1105e787cdfSJisheng Zhang MODULE_DESCRIPTION("Synaptics Berlin reset controller");
1115e787cdfSJisheng Zhang MODULE_LICENSE("GPL");
112