xref: /openbmc/linux/drivers/irqchip/irq-gic-pm.c (revision bc5aa3a0)
1 /*
2  * Copyright (C) 2016 NVIDIA CORPORATION, All Rights Reserved.
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  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 #include <linux/module.h>
17 #include <linux/clk.h>
18 #include <linux/of_device.h>
19 #include <linux/of_irq.h>
20 #include <linux/irqchip/arm-gic.h>
21 #include <linux/platform_device.h>
22 #include <linux/pm_clock.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/slab.h>
25 
26 struct gic_clk_data {
27 	unsigned int num_clocks;
28 	const char *const *clocks;
29 };
30 
31 static int gic_runtime_resume(struct device *dev)
32 {
33 	struct gic_chip_data *gic = dev_get_drvdata(dev);
34 	int ret;
35 
36 	ret = pm_clk_resume(dev);
37 	if (ret)
38 		return ret;
39 
40 	/*
41 	 * On the very first resume, the pointer to the driver data
42 	 * will be NULL and this is intentional, because we do not
43 	 * want to restore the GIC on the very first resume. So if
44 	 * the pointer is not valid just return.
45 	 */
46 	if (!gic)
47 		return 0;
48 
49 	gic_dist_restore(gic);
50 	gic_cpu_restore(gic);
51 
52 	return 0;
53 }
54 
55 static int gic_runtime_suspend(struct device *dev)
56 {
57 	struct gic_chip_data *gic = dev_get_drvdata(dev);
58 
59 	gic_dist_save(gic);
60 	gic_cpu_save(gic);
61 
62 	return pm_clk_suspend(dev);
63 }
64 
65 static int gic_get_clocks(struct device *dev, const struct gic_clk_data *data)
66 {
67 	struct clk *clk;
68 	unsigned int i;
69 	int ret;
70 
71 	if (!dev || !data)
72 		return -EINVAL;
73 
74 	ret = pm_clk_create(dev);
75 	if (ret)
76 		return ret;
77 
78 	for (i = 0; i < data->num_clocks; i++) {
79 		clk = of_clk_get_by_name(dev->of_node, data->clocks[i]);
80 		if (IS_ERR(clk)) {
81 			dev_err(dev, "failed to get clock %s\n",
82 				data->clocks[i]);
83 			ret = PTR_ERR(clk);
84 			goto error;
85 		}
86 
87 		ret = pm_clk_add_clk(dev, clk);
88 		if (ret) {
89 			dev_err(dev, "failed to add clock at index %d\n", i);
90 			clk_put(clk);
91 			goto error;
92 		}
93 	}
94 
95 	return 0;
96 
97 error:
98 	pm_clk_destroy(dev);
99 
100 	return ret;
101 }
102 
103 static int gic_probe(struct platform_device *pdev)
104 {
105 	struct device *dev = &pdev->dev;
106 	const struct gic_clk_data *data;
107 	struct gic_chip_data *gic;
108 	int ret, irq;
109 
110 	data = of_device_get_match_data(&pdev->dev);
111 	if (!data) {
112 		dev_err(&pdev->dev, "no device match found\n");
113 		return -ENODEV;
114 	}
115 
116 	irq = irq_of_parse_and_map(dev->of_node, 0);
117 	if (!irq) {
118 		dev_err(dev, "no parent interrupt found!\n");
119 		return -EINVAL;
120 	}
121 
122 	ret = gic_get_clocks(dev, data);
123 	if (ret)
124 		goto irq_dispose;
125 
126 	pm_runtime_enable(dev);
127 
128 	ret = pm_runtime_get_sync(dev);
129 	if (ret < 0)
130 		goto rpm_disable;
131 
132 	ret = gic_of_init_child(dev, &gic, irq);
133 	if (ret)
134 		goto rpm_put;
135 
136 	platform_set_drvdata(pdev, gic);
137 
138 	pm_runtime_put(dev);
139 
140 	dev_info(dev, "GIC IRQ controller registered\n");
141 
142 	return 0;
143 
144 rpm_put:
145 	pm_runtime_put_sync(dev);
146 rpm_disable:
147 	pm_runtime_disable(dev);
148 	pm_clk_destroy(dev);
149 irq_dispose:
150 	irq_dispose_mapping(irq);
151 
152 	return ret;
153 }
154 
155 static const struct dev_pm_ops gic_pm_ops = {
156 	SET_RUNTIME_PM_OPS(gic_runtime_suspend,
157 			   gic_runtime_resume, NULL)
158 };
159 
160 static const char * const gic400_clocks[] = {
161 	"clk",
162 };
163 
164 static const struct gic_clk_data gic400_data = {
165 	.num_clocks = ARRAY_SIZE(gic400_clocks),
166 	.clocks = gic400_clocks,
167 };
168 
169 static const struct of_device_id gic_match[] = {
170 	{ .compatible = "nvidia,tegra210-agic",	.data = &gic400_data },
171 	{},
172 };
173 MODULE_DEVICE_TABLE(of, gic_match);
174 
175 static struct platform_driver gic_driver = {
176 	.probe		= gic_probe,
177 	.driver		= {
178 		.name	= "gic",
179 		.of_match_table	= gic_match,
180 		.pm	= &gic_pm_ops,
181 	}
182 };
183 
184 builtin_platform_driver(gic_driver);
185