blob: 93ecd8c8bed70040477c255b6147ff67fe0a1fcf [file] [log] [blame]
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +05301/*
2 * Arche Platform driver to enable Unipro link.
3 *
4 * Copyright 2014-2015 Google Inc.
5 * Copyright 2014-2015 Linaro Ltd.
6 *
7 * Released under the GPLv2 only.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/irq.h>
14#include <linux/sched.h>
15#include <linux/pm.h>
16#include <linux/delay.h>
17#include <linux/platform_device.h>
18#include <linux/gpio.h>
19#include <linux/clk.h>
20#include <linux/of_platform.h>
21#include <linux/of_gpio.h>
22#include <linux/of_irq.h>
23#include <linux/spinlock.h>
24#include <linux/regulator/consumer.h>
25#include <linux/pinctrl/consumer.h>
Greg Kroah-Hartman1e5dd1f2015-12-30 13:38:33 -080026#include "arche_platform.h"
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +053027
28struct arche_platform_drvdata {
29 /* Control GPIO signals to and from AP <=> SVC */
30 int svc_reset_gpio;
31 bool is_reset_act_hi;
32 int svc_sysboot_gpio;
33
34 unsigned int svc_refclk_req;
35 struct clk *svc_ref_clk;
36
37 struct pinctrl *pinctrl;
38 struct pinctrl_state *pin_default;
39
40 int num_apbs;
41};
42
43static inline void svc_reset_onoff(unsigned int gpio, bool onoff)
44{
45 gpio_set_value(gpio, onoff);
46}
47
Vaibhav Hiremath6da86df2016-01-06 11:31:20 +053048/* Export gpio's to user space */
49static void export_gpios(struct arche_platform_drvdata *arche_pdata)
50{
51 gpio_export(arche_pdata->svc_reset_gpio, false);
52 gpio_export(arche_pdata->svc_sysboot_gpio, false);
53}
54
55static void unexport_gpios(struct arche_platform_drvdata *arche_pdata)
56{
57 gpio_unexport(arche_pdata->svc_reset_gpio);
58 gpio_unexport(arche_pdata->svc_sysboot_gpio);
59}
60
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +053061static void arche_platform_cleanup(struct arche_platform_drvdata *arche_pdata)
62{
63 /* As part of exit, put APB back in reset state */
Viresh Kumar140741e2016-01-11 11:29:06 +053064 svc_reset_onoff(arche_pdata->svc_reset_gpio,
65 arche_pdata->is_reset_act_hi);
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +053066}
67
68static int arche_platform_probe(struct platform_device *pdev)
69{
70 struct arche_platform_drvdata *arche_pdata;
71 struct device *dev = &pdev->dev;
72 struct device_node *np = dev->of_node;
73 int ret;
74
75 arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata), GFP_KERNEL);
76 if (!arche_pdata)
77 return -ENOMEM;
78
79 /* setup svc reset gpio */
80 arche_pdata->is_reset_act_hi = of_property_read_bool(np,
81 "svc,reset-active-high");
82 arche_pdata->svc_reset_gpio = of_get_named_gpio(np, "svc,reset-gpio", 0);
83 if (arche_pdata->svc_reset_gpio < 0) {
84 dev_err(dev, "failed to get reset-gpio\n");
85 return -ENODEV;
86 }
87 ret = devm_gpio_request(dev, arche_pdata->svc_reset_gpio, "svc-reset");
88 if (ret) {
89 dev_err(dev, "failed to request svc-reset gpio:%d\n", ret);
90 return ret;
91 }
92 ret = gpio_direction_output(arche_pdata->svc_reset_gpio,
93 arche_pdata->is_reset_act_hi);
94 if (ret) {
95 dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
96 return ret;
97 }
98
99 arche_pdata->svc_sysboot_gpio = of_get_named_gpio(np,
100 "svc,sysboot-gpio", 0);
101 if (arche_pdata->svc_sysboot_gpio < 0) {
102 dev_err(dev, "failed to get sysboot gpio\n");
103 return -ENODEV;
104 }
105 ret = devm_gpio_request(dev, arche_pdata->svc_sysboot_gpio, "sysboot0");
106 if (ret) {
107 dev_err(dev, "failed to request sysboot0 gpio:%d\n", ret);
108 return ret;
109 }
110 ret = gpio_direction_output(arche_pdata->svc_sysboot_gpio, 0);
111 if (ret) {
112 dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
113 return ret;
114 }
115
116 /* setup the clock request gpio first */
117 arche_pdata->svc_refclk_req = of_get_named_gpio(np,
118 "svc,refclk-req-gpio", 0);
119 if (arche_pdata->svc_refclk_req < 0) {
120 dev_err(dev, "failed to get svc clock-req gpio\n");
121 return -ENODEV;
122 }
123 ret = devm_gpio_request(dev, arche_pdata->svc_refclk_req, "svc-clk-req");
124 if (ret) {
125 dev_err(dev, "failed to request svc-clk-req gpio: %d\n", ret);
126 return ret;
127 }
128 ret = gpio_direction_input(arche_pdata->svc_refclk_req);
129 if (ret) {
130 dev_err(dev, "failed to set svc-clk-req gpio dir :%d\n", ret);
131 return ret;
132 }
133
134 /* setup refclk2 to follow the pin */
135 arche_pdata->svc_ref_clk = devm_clk_get(dev, "svc_ref_clk");
136 if (IS_ERR(arche_pdata->svc_ref_clk)) {
137 ret = PTR_ERR(arche_pdata->svc_ref_clk);
138 dev_err(dev, "failed to get svc_ref_clk: %d\n", ret);
139 return ret;
140 }
141 ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
142 if (ret) {
143 dev_err(dev, "failed to enable svc_ref_clk: %d\n", ret);
144 return ret;
145 }
146
147 platform_set_drvdata(pdev, arche_pdata);
148
149 /* bring SVC out of reset */
150 svc_reset_onoff(arche_pdata->svc_reset_gpio,
151 !arche_pdata->is_reset_act_hi);
152
153 arche_pdata->num_apbs = of_get_child_count(np);
154 dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs);
155
156 /* probe all childs here */
157 ret = of_platform_populate(np, NULL, NULL, dev);
Viresh Kumar72a8c242016-01-11 11:29:05 +0530158 if (ret) {
159 arche_platform_cleanup(arche_pdata);
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530160 dev_err(dev, "no child node found\n");
Viresh Kumar72a8c242016-01-11 11:29:05 +0530161 return ret;
162 }
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530163
Viresh Kumar8adf71d2016-01-11 11:29:04 +0530164 export_gpios(arche_pdata);
165
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530166 dev_info(dev, "Device registered successfully\n");
Viresh Kumar72a8c242016-01-11 11:29:05 +0530167 return 0;
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530168}
169
Vaibhav Hiremathbc142bb2015-12-28 20:06:32 +0530170static int arche_remove_child(struct device *dev, void *unused)
171{
172 struct platform_device *pdev = to_platform_device(dev);
173
174 platform_device_unregister(pdev);
175
176 return 0;
177}
178
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530179static int arche_platform_remove(struct platform_device *pdev)
180{
181 struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
182
Vaibhav Hiremathbc142bb2015-12-28 20:06:32 +0530183 device_for_each_child(&pdev->dev, NULL, arche_remove_child);
Viresh Kumar73658f22016-01-11 11:29:03 +0530184 arche_platform_cleanup(arche_pdata);
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530185 platform_set_drvdata(pdev, NULL);
Vaibhav Hiremath6da86df2016-01-06 11:31:20 +0530186 unexport_gpios(arche_pdata);
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530187
188 return 0;
189}
190
191static int arche_platform_suspend(struct device *dev)
192{
193 /*
194 * If timing profile premits, we may shutdown bridge
195 * completely
196 *
197 * TODO: sequence ??
198 *
199 * Also, need to make sure we meet precondition for unipro suspend
200 * Precondition: Definition ???
201 */
202 return 0;
203}
204
205static int arche_platform_resume(struct device *dev)
206{
207 /*
208 * Atleast for ES2 we have to meet the delay requirement between
209 * unipro switch and AP bridge init, depending on whether bridge is in
210 * OFF state or standby state.
211 *
212 * Based on whether bridge is in standby or OFF state we may have to
213 * assert multiple signals. Please refer to WDM spec, for more info.
214 *
215 */
216 return 0;
217}
218
219static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops,
220 arche_platform_suspend,
221 arche_platform_resume);
222
223static struct of_device_id arche_platform_of_match[] = {
224 { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */
225 { },
226};
Greg Kroah-Hartman1e5dd1f2015-12-30 13:38:33 -0800227
228static struct of_device_id arche_apb_ctrl_of_match[] = {
229 { .compatible = "usbffff,2", },
230 { },
231};
232
233static struct of_device_id arche_combined_id[] = {
234 { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */
235 { .compatible = "usbffff,2", },
236 { },
237};
238MODULE_DEVICE_TABLE(of, arche_combined_id);
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530239
240static struct platform_driver arche_platform_device_driver = {
241 .probe = arche_platform_probe,
242 .remove = arche_platform_remove,
243 .driver = {
244 .name = "arche-platform-ctrl",
245 .pm = &arche_platform_pm_ops,
Greg Kroah-Hartman1e5dd1f2015-12-30 13:38:33 -0800246 .of_match_table = arche_platform_of_match,
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530247 }
248};
249
Greg Kroah-Hartman1e5dd1f2015-12-30 13:38:33 -0800250static struct platform_driver arche_apb_ctrl_device_driver = {
251 .probe = arche_apb_ctrl_probe,
252 .remove = arche_apb_ctrl_remove,
253 .driver = {
254 .name = "arche-apb-ctrl",
255 .pm = &arche_apb_ctrl_pm_ops,
256 .of_match_table = arche_apb_ctrl_of_match,
257 }
258};
259
260static int __init arche_init(void)
261{
262 int retval;
263
264 retval = platform_driver_register(&arche_platform_device_driver);
265 if (retval)
266 return retval;
267
268 retval = platform_driver_register(&arche_apb_ctrl_device_driver);
269 if (retval)
270 platform_driver_unregister(&arche_platform_device_driver);
271
272 return retval;
273}
274module_init(arche_init);
275
276static void __exit arche_exit(void)
277{
278 platform_driver_unregister(&arche_apb_ctrl_device_driver);
279 platform_driver_unregister(&arche_platform_device_driver);
280}
281module_exit(arche_exit);
Vaibhav Hiremath7fa60652015-12-16 16:29:18 +0530282
283MODULE_LICENSE("GPL");
284MODULE_AUTHOR("Vaibhav Hiremath <vaibhav.hiremath@linaro.org>");
285MODULE_DESCRIPTION("Arche Platform Driver");