blob: 7d90f5dee1d3a3e135cbed7c67527d6f179b38b6 [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>
26
27struct arche_platform_drvdata {
28 /* Control GPIO signals to and from AP <=> SVC */
29 int svc_reset_gpio;
30 bool is_reset_act_hi;
31 int svc_sysboot_gpio;
32
33 unsigned int svc_refclk_req;
34 struct clk *svc_ref_clk;
35
36 struct pinctrl *pinctrl;
37 struct pinctrl_state *pin_default;
38
39 int num_apbs;
40};
41
42static inline void svc_reset_onoff(unsigned int gpio, bool onoff)
43{
44 gpio_set_value(gpio, onoff);
45}
46
47static void arche_platform_cleanup(struct arche_platform_drvdata *arche_pdata)
48{
49 /* As part of exit, put APB back in reset state */
50 if (gpio_is_valid(arche_pdata->svc_reset_gpio))
51 svc_reset_onoff(arche_pdata->svc_reset_gpio,
52 arche_pdata->is_reset_act_hi);
53}
54
55static int arche_platform_probe(struct platform_device *pdev)
56{
57 struct arche_platform_drvdata *arche_pdata;
58 struct device *dev = &pdev->dev;
59 struct device_node *np = dev->of_node;
60 int ret;
61
62 arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata), GFP_KERNEL);
63 if (!arche_pdata)
64 return -ENOMEM;
65
66 /* setup svc reset gpio */
67 arche_pdata->is_reset_act_hi = of_property_read_bool(np,
68 "svc,reset-active-high");
69 arche_pdata->svc_reset_gpio = of_get_named_gpio(np, "svc,reset-gpio", 0);
70 if (arche_pdata->svc_reset_gpio < 0) {
71 dev_err(dev, "failed to get reset-gpio\n");
72 return -ENODEV;
73 }
74 ret = devm_gpio_request(dev, arche_pdata->svc_reset_gpio, "svc-reset");
75 if (ret) {
76 dev_err(dev, "failed to request svc-reset gpio:%d\n", ret);
77 return ret;
78 }
79 ret = gpio_direction_output(arche_pdata->svc_reset_gpio,
80 arche_pdata->is_reset_act_hi);
81 if (ret) {
82 dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
83 return ret;
84 }
85
86 arche_pdata->svc_sysboot_gpio = of_get_named_gpio(np,
87 "svc,sysboot-gpio", 0);
88 if (arche_pdata->svc_sysboot_gpio < 0) {
89 dev_err(dev, "failed to get sysboot gpio\n");
90 return -ENODEV;
91 }
92 ret = devm_gpio_request(dev, arche_pdata->svc_sysboot_gpio, "sysboot0");
93 if (ret) {
94 dev_err(dev, "failed to request sysboot0 gpio:%d\n", ret);
95 return ret;
96 }
97 ret = gpio_direction_output(arche_pdata->svc_sysboot_gpio, 0);
98 if (ret) {
99 dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
100 return ret;
101 }
102
103 /* setup the clock request gpio first */
104 arche_pdata->svc_refclk_req = of_get_named_gpio(np,
105 "svc,refclk-req-gpio", 0);
106 if (arche_pdata->svc_refclk_req < 0) {
107 dev_err(dev, "failed to get svc clock-req gpio\n");
108 return -ENODEV;
109 }
110 ret = devm_gpio_request(dev, arche_pdata->svc_refclk_req, "svc-clk-req");
111 if (ret) {
112 dev_err(dev, "failed to request svc-clk-req gpio: %d\n", ret);
113 return ret;
114 }
115 ret = gpio_direction_input(arche_pdata->svc_refclk_req);
116 if (ret) {
117 dev_err(dev, "failed to set svc-clk-req gpio dir :%d\n", ret);
118 return ret;
119 }
120
121 /* setup refclk2 to follow the pin */
122 arche_pdata->svc_ref_clk = devm_clk_get(dev, "svc_ref_clk");
123 if (IS_ERR(arche_pdata->svc_ref_clk)) {
124 ret = PTR_ERR(arche_pdata->svc_ref_clk);
125 dev_err(dev, "failed to get svc_ref_clk: %d\n", ret);
126 return ret;
127 }
128 ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
129 if (ret) {
130 dev_err(dev, "failed to enable svc_ref_clk: %d\n", ret);
131 return ret;
132 }
133
134 platform_set_drvdata(pdev, arche_pdata);
135
136 /* bring SVC out of reset */
137 svc_reset_onoff(arche_pdata->svc_reset_gpio,
138 !arche_pdata->is_reset_act_hi);
139
140 arche_pdata->num_apbs = of_get_child_count(np);
141 dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs);
142
143 /* probe all childs here */
144 ret = of_platform_populate(np, NULL, NULL, dev);
145 if (ret)
146 dev_err(dev, "no child node found\n");
147
148 dev_info(dev, "Device registered successfully\n");
149 return ret;
150}
151
152static int arche_platform_remove(struct platform_device *pdev)
153{
154 struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
155
156 if (arche_pdata)
157 arche_platform_cleanup(arche_pdata);
158
159 platform_set_drvdata(pdev, NULL);
160
161 return 0;
162}
163
164static int arche_platform_suspend(struct device *dev)
165{
166 /*
167 * If timing profile premits, we may shutdown bridge
168 * completely
169 *
170 * TODO: sequence ??
171 *
172 * Also, need to make sure we meet precondition for unipro suspend
173 * Precondition: Definition ???
174 */
175 return 0;
176}
177
178static int arche_platform_resume(struct device *dev)
179{
180 /*
181 * Atleast for ES2 we have to meet the delay requirement between
182 * unipro switch and AP bridge init, depending on whether bridge is in
183 * OFF state or standby state.
184 *
185 * Based on whether bridge is in standby or OFF state we may have to
186 * assert multiple signals. Please refer to WDM spec, for more info.
187 *
188 */
189 return 0;
190}
191
192static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops,
193 arche_platform_suspend,
194 arche_platform_resume);
195
196static struct of_device_id arche_platform_of_match[] = {
197 { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */
198 { },
199};
200MODULE_DEVICE_TABLE(of, arche_platform_of_match);
201
202static struct platform_driver arche_platform_device_driver = {
203 .probe = arche_platform_probe,
204 .remove = arche_platform_remove,
205 .driver = {
206 .name = "arche-platform-ctrl",
207 .pm = &arche_platform_pm_ops,
208 .of_match_table = of_match_ptr(arche_platform_of_match),
209 }
210};
211
212module_platform_driver(arche_platform_device_driver);
213
214MODULE_LICENSE("GPL");
215MODULE_AUTHOR("Vaibhav Hiremath <vaibhav.hiremath@linaro.org>");
216MODULE_DESCRIPTION("Arche Platform Driver");