blob: 9c89f2db4616200acec3bf8843bb8be7808d0887 [file] [log] [blame]
Tianyi Gouc1e049f82011-11-23 14:20:16 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/err.h>
15#include <linux/io.h>
Tianyi Gouc1e049f82011-11-23 14:20:16 -080016#include <linux/delay.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19#include <linux/platform_device.h>
20#include <linux/clk.h>
21#include <linux/iopoll.h>
22#include <linux/of.h>
23#include <linux/regulator/consumer.h>
Stephen Boyd581fe852012-06-13 12:05:35 -070024#include <linux/interrupt.h>
25#include <linux/jiffies.h>
26#include <linux/workqueue.h>
27#include <linux/wcnss_wlan.h>
28
29#include <mach/subsystem_restart.h>
Stephen Boyd581fe852012-06-13 12:05:35 -070030#include <mach/msm_smsm.h>
Tianyi Gouc1e049f82011-11-23 14:20:16 -080031
32#include "peripheral-loader.h"
33#include "scm-pas.h"
Sameer Thalappilb7488b22012-11-09 16:40:12 -080034#include "ramdump.h"
Tianyi Gouc1e049f82011-11-23 14:20:16 -080035
36#define PRONTO_PMU_COMMON_GDSCR 0x24
37#define PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE BIT(0)
38#define CLK_DIS_WAIT 12
39#define EN_FEW_WAIT 16
40#define EN_REST_WAIT 20
41
42#define PRONTO_PMU_COMMON_CPU_CBCR 0x30
43#define PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN BIT(0)
44#define PRONTO_PMU_COMMON_CPU_CLK_OFF BIT(31)
45
46#define PRONTO_PMU_COMMON_AHB_CBCR 0x34
47#define PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN BIT(0)
48#define PRONTO_PMU_COMMON_AHB_CLK_OFF BIT(31)
49
50#define PRONTO_PMU_COMMON_CSR 0x1040
51#define PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN BIT(0)
52
53#define PRONTO_PMU_SOFT_RESET 0x104C
54#define PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET BIT(10)
55
56#define PRONTO_PMU_CCPU_CTL 0x2000
57#define PRONTO_PMU_CCPU_CTL_REMAP_EN BIT(2)
58#define PRONTO_PMU_CCPU_CTL_HIGH_IVT BIT(0)
59
60#define PRONTO_PMU_CCPU_BOOT_REMAP_ADDR 0x2004
61
62#define CLK_CTL_WCNSS_RESTART_BIT BIT(0)
63
64#define AXI_HALTREQ 0x0
65#define AXI_HALTACK 0x4
66#define AXI_IDLE 0x8
67
68#define HALT_ACK_TIMEOUT_US 500000
69#define CLK_UPDATE_TIMEOUT_US 500000
70
71struct pronto_data {
72 void __iomem *base;
73 void __iomem *reset_base;
74 void __iomem *axi_halt_base;
Tianyi Gouc1e049f82011-11-23 14:20:16 -080075 struct pil_device *pil;
Stephen Boyd3e4e9752012-06-27 12:46:32 -070076 struct pil_desc desc;
Stephen Boyd581fe852012-06-13 12:05:35 -070077 struct subsys_device *subsys;
78 struct subsys_desc subsys_desc;
Tianyi Gouc1e049f82011-11-23 14:20:16 -080079 struct clk *cxo;
80 struct regulator *vreg;
Stephen Boyd581fe852012-06-13 12:05:35 -070081 bool restart_inprogress;
82 bool crash;
83 struct delayed_work cancel_vote_work;
84 int irq;
Sameer Thalappilb7488b22012-11-09 16:40:12 -080085 struct ramdump_device *ramdump_dev;
Tianyi Gouc1e049f82011-11-23 14:20:16 -080086};
87
88static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
89{
90 struct pronto_data *drv = dev_get_drvdata(pil->dev);
91 int ret;
92
93 ret = regulator_enable(drv->vreg);
94 if (ret) {
95 dev_err(pil->dev, "failed to enable pll supply\n");
96 goto err;
97 }
98 ret = clk_prepare_enable(drv->cxo);
99 if (ret) {
100 dev_err(pil->dev, "failed to enable cxo\n");
101 goto err_clk;
102 }
103 return 0;
104err_clk:
105 regulator_disable(drv->vreg);
106err:
107 return ret;
108}
109
110static void pil_pronto_remove_proxy_vote(struct pil_desc *pil)
111{
112 struct pronto_data *drv = dev_get_drvdata(pil->dev);
113 regulator_disable(drv->vreg);
114 clk_disable_unprepare(drv->cxo);
115}
116
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800117static int pil_pronto_reset(struct pil_desc *pil)
118{
119 u32 reg;
120 int rc;
121 struct pronto_data *drv = dev_get_drvdata(pil->dev);
122 void __iomem *base = drv->base;
Stephen Boyd3030c252012-08-08 17:24:05 -0700123 unsigned long start_addr = pil_get_entry_addr(pil);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800124
Matt Wagantall33c2ec72012-07-26 20:26:57 -0700125 /* Deassert reset to subsystem and wait for propagation */
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800126 reg = readl_relaxed(drv->reset_base);
127 reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
128 writel_relaxed(reg, drv->reset_base);
129 mb();
Matt Wagantall33c2ec72012-07-26 20:26:57 -0700130 udelay(2);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800131
132 /* Configure boot address */
133 writel_relaxed(start_addr >> 16, base +
134 PRONTO_PMU_CCPU_BOOT_REMAP_ADDR);
135
136 /* Use the high vector table */
137 reg = readl_relaxed(base + PRONTO_PMU_CCPU_CTL);
138 reg |= PRONTO_PMU_CCPU_CTL_REMAP_EN | PRONTO_PMU_CCPU_CTL_HIGH_IVT;
139 writel_relaxed(reg, base + PRONTO_PMU_CCPU_CTL);
140
141 /* Turn on AHB clock of common_ss */
142 reg = readl_relaxed(base + PRONTO_PMU_COMMON_AHB_CBCR);
143 reg |= PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN;
144 writel_relaxed(reg, base + PRONTO_PMU_COMMON_AHB_CBCR);
145
146 /* Turn on CPU clock of common_ss */
147 reg = readl_relaxed(base + PRONTO_PMU_COMMON_CPU_CBCR);
148 reg |= PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN;
149 writel_relaxed(reg, base + PRONTO_PMU_COMMON_CPU_CBCR);
150
151 /* Enable A2XB bridge */
152 reg = readl_relaxed(base + PRONTO_PMU_COMMON_CSR);
153 reg |= PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN;
154 writel_relaxed(reg, base + PRONTO_PMU_COMMON_CSR);
155
156 /* Enable common_ss power */
157 reg = readl_relaxed(base + PRONTO_PMU_COMMON_GDSCR);
158 reg &= ~PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
159 writel_relaxed(reg, base + PRONTO_PMU_COMMON_GDSCR);
160
161 /* Wait for AHB clock to be on */
162 rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_AHB_CBCR,
163 reg,
164 !(reg & PRONTO_PMU_COMMON_AHB_CLK_OFF),
165 CLK_UPDATE_TIMEOUT_US);
166 if (rc) {
167 dev_err(pil->dev, "pronto common ahb clk enable timeout\n");
168 return rc;
169 }
170
171 /* Wait for CPU clock to be on */
172 rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_CPU_CBCR,
173 reg,
174 !(reg & PRONTO_PMU_COMMON_CPU_CLK_OFF),
175 CLK_UPDATE_TIMEOUT_US);
176 if (rc) {
177 dev_err(pil->dev, "pronto common cpu clk enable timeout\n");
178 return rc;
179 }
180
181 /* Deassert ARM9 software reset */
182 reg = readl_relaxed(base + PRONTO_PMU_SOFT_RESET);
183 reg &= ~PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET;
184 writel_relaxed(reg, base + PRONTO_PMU_SOFT_RESET);
185
186 return 0;
187}
188
189static int pil_pronto_shutdown(struct pil_desc *pil)
190{
191 struct pronto_data *drv = dev_get_drvdata(pil->dev);
192 int ret;
193 u32 reg, status;
194
195 /* Halt A2XB */
196 writel_relaxed(1, drv->axi_halt_base + AXI_HALTREQ);
197 ret = readl_poll_timeout(drv->axi_halt_base + AXI_HALTACK,
198 status, status, 50, HALT_ACK_TIMEOUT_US);
199 if (ret)
200 dev_err(pil->dev, "Port halt timeout\n");
201 else if (!readl_relaxed(drv->axi_halt_base + AXI_IDLE))
202 dev_err(pil->dev, "Port halt failed\n");
203
204 writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
205
206 /* Assert reset to Pronto */
207 reg = readl_relaxed(drv->reset_base);
208 reg |= CLK_CTL_WCNSS_RESTART_BIT;
209 writel_relaxed(reg, drv->reset_base);
210
211 /* Wait for reset to complete */
212 mb();
213 usleep_range(1000, 2000);
214
Matt Wagantall44131df2012-08-03 18:29:47 -0700215 /* Deassert reset to subsystem and wait for propagation */
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800216 reg = readl_relaxed(drv->reset_base);
217 reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
218 writel_relaxed(reg, drv->reset_base);
219 mb();
Matt Wagantall44131df2012-08-03 18:29:47 -0700220 udelay(2);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800221
222 return 0;
223}
224
225static struct pil_reset_ops pil_pronto_ops = {
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800226 .auth_and_reset = pil_pronto_reset,
227 .shutdown = pil_pronto_shutdown,
228 .proxy_vote = pil_pronto_make_proxy_vote,
229 .proxy_unvote = pil_pronto_remove_proxy_vote,
230};
231
Tianyi Gou13d85b92012-11-12 18:04:07 -0800232static int pil_pronto_init_image_trusted(struct pil_desc *pil,
233 const u8 *metadata, size_t size)
234{
235 return pas_init_image(PAS_WCNSS, metadata, size);
236}
237
Stephen Boydc8c5db92012-12-03 11:13:20 -0800238static int pil_pronto_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
239 size_t size)
240{
241 return pas_mem_setup(PAS_WCNSS, addr, size);
242}
243
Tianyi Gou13d85b92012-11-12 18:04:07 -0800244static int pil_pronto_reset_trusted(struct pil_desc *pil)
245{
246 return pas_auth_and_reset(PAS_WCNSS);
247}
248
249static int pil_pronto_shutdown_trusted(struct pil_desc *pil)
250{
251 return pas_shutdown(PAS_WCNSS);
252}
253
254static struct pil_reset_ops pil_pronto_ops_trusted = {
255 .init_image = pil_pronto_init_image_trusted,
Stephen Boydc8c5db92012-12-03 11:13:20 -0800256 .mem_setup = pil_pronto_mem_setup_trusted,
Tianyi Gou13d85b92012-11-12 18:04:07 -0800257 .auth_and_reset = pil_pronto_reset_trusted,
258 .shutdown = pil_pronto_shutdown_trusted,
259 .proxy_vote = pil_pronto_make_proxy_vote,
260 .proxy_unvote = pil_pronto_remove_proxy_vote,
261};
262
Stephen Boyd581fe852012-06-13 12:05:35 -0700263#define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
264
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700265static int pronto_start(const struct subsys_desc *desc)
266{
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700267 struct pronto_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700268 return pil_boot(&drv->desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700269}
270
271static void pronto_stop(const struct subsys_desc *desc)
272{
273 struct pronto_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700274 pil_shutdown(&drv->desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700275}
276
Stephen Boyd581fe852012-06-13 12:05:35 -0700277static void log_wcnss_sfr(void)
278{
279 char *smem_reset_reason;
280 unsigned smem_reset_size;
281
282 smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
283 &smem_reset_size);
284
285 if (!smem_reset_reason || !smem_reset_size) {
286 pr_err("wcnss subsystem failure reason:\n"
287 "(unknown, smem_get_entry failed)");
288 } else if (!smem_reset_reason[0]) {
289 pr_err("wcnss subsystem failure reason:\n"
290 "(unknown, init string found)");
291 } else {
292 pr_err("wcnss subsystem failure reason: %.81s\n",
293 smem_reset_reason);
294 memset(smem_reset_reason, 0, smem_reset_size);
295 wmb();
296 }
297}
298
299static void restart_wcnss(struct pronto_data *drv)
300{
301 log_wcnss_sfr();
302 subsystem_restart_dev(drv->subsys);
303}
304
305static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
306 uint32_t new_state)
307{
308 struct pronto_data *drv = data;
309
310 drv->crash = true;
311
312 pr_err("wcnss smsm state changed\n");
313
314 if (!(new_state & SMSM_RESET))
315 return;
316
317 if (drv->restart_inprogress) {
318 pr_err("wcnss: Ignoring smsm reset req, restart in progress\n");
319 return;
320 }
321
322 drv->restart_inprogress = true;
323 restart_wcnss(drv);
324}
325
326static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
327{
328 struct pronto_data *drv = dev_id;
329
330 drv->crash = true;
331
332 if (drv->restart_inprogress) {
333 pr_err("Ignoring wcnss bite irq, restart in progress\n");
334 return IRQ_HANDLED;
335 }
336
Sameer Thalappil480892c2012-11-14 13:56:13 -0800337 disable_irq_nosync(drv->irq);
Stephen Boyd581fe852012-06-13 12:05:35 -0700338 drv->restart_inprogress = true;
Sameer Thalappil1b3e6112012-12-14 15:16:07 -0800339 wcnss_pronto_log_debug_regs();
Stephen Boyd581fe852012-06-13 12:05:35 -0700340 restart_wcnss(drv);
341
342 return IRQ_HANDLED;
343}
344
345static void wcnss_post_bootup(struct work_struct *work)
346{
347 struct platform_device *pdev = wcnss_get_platform_device();
348 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
349
350 wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF);
351}
352
353static int wcnss_shutdown(const struct subsys_desc *subsys)
354{
355 struct pronto_data *drv = subsys_to_drv(subsys);
356
Stephen Boyde83a0a22012-06-29 13:51:27 -0700357 pil_shutdown(&drv->desc);
Stephen Boyd581fe852012-06-13 12:05:35 -0700358 flush_delayed_work(&drv->cancel_vote_work);
359 wcnss_flush_delayed_boot_votes();
Stephen Boyd581fe852012-06-13 12:05:35 -0700360
361 return 0;
362}
363
364static int wcnss_powerup(const struct subsys_desc *subsys)
365{
366 struct pronto_data *drv = subsys_to_drv(subsys);
367 struct platform_device *pdev = wcnss_get_platform_device();
368 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
369 int ret = -1;
370
371 if (pdev && pwlanconfig)
372 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
373 WCNSS_WLAN_SWITCH_ON);
374 if (!ret) {
375 msleep(1000);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700376 ret = pil_boot(&drv->desc);
377 if (ret)
378 return ret;
Stephen Boyd581fe852012-06-13 12:05:35 -0700379 }
380 drv->restart_inprogress = false;
381 enable_irq(drv->irq);
382 schedule_delayed_work(&drv->cancel_vote_work, msecs_to_jiffies(5000));
383
384 return 0;
385}
386
387static void crash_shutdown(const struct subsys_desc *subsys)
388{
389 struct pronto_data *drv = subsys_to_drv(subsys);
390
391 pr_err("wcnss crash shutdown %d\n", drv->crash);
392 if (!drv->crash)
393 smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
394}
395
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800396static int wcnss_ramdump(int enable, const struct subsys_desc *subsys)
Stephen Boyd581fe852012-06-13 12:05:35 -0700397{
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800398 struct pronto_data *drv = subsys_to_drv(subsys);
399
Stephen Boyd5eb17ce2012-11-29 15:34:21 -0800400 if (!enable)
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800401 return 0;
Stephen Boyd5eb17ce2012-11-29 15:34:21 -0800402
403 return pil_do_ramdump(&drv->desc, drv->ramdump_dev);
Stephen Boyd581fe852012-06-13 12:05:35 -0700404}
405
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800406static int __devinit pil_pronto_probe(struct platform_device *pdev)
407{
408 struct pronto_data *drv;
409 struct resource *res;
410 struct pil_desc *desc;
411 int ret;
412 uint32_t regval;
413
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800414 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
415 if (!drv)
416 return -ENOMEM;
417 platform_set_drvdata(pdev, drv);
418
Stephen Boyd581fe852012-06-13 12:05:35 -0700419 drv->irq = platform_get_irq(pdev, 0);
420 if (drv->irq < 0)
421 return drv->irq;
422
Stephen Boydf8f89282012-07-16 18:05:48 -0700423 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
424 drv->base = devm_request_and_ioremap(&pdev->dev, res);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800425 if (!drv->base)
426 return -ENOMEM;
427
Matt Wagantall1f168152012-09-25 13:26:47 -0700428 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
Stephen Boydf8f89282012-07-16 18:05:48 -0700429 drv->reset_base = devm_request_and_ioremap(&pdev->dev, res);
430 if (!drv->reset_base)
431 return -ENOMEM;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800432
Matt Wagantall1f168152012-09-25 13:26:47 -0700433 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
Stephen Boydf8f89282012-07-16 18:05:48 -0700434 drv->axi_halt_base = devm_request_and_ioremap(&pdev->dev, res);
435 if (!drv->axi_halt_base)
436 return -ENOMEM;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800437
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700438 desc = &drv->desc;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800439 ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
440 &desc->name);
441 if (ret)
442 return ret;
443
444 desc->dev = &pdev->dev;
445 desc->owner = THIS_MODULE;
446 desc->proxy_timeout = 10000;
447
Tianyi Gou13d85b92012-11-12 18:04:07 -0800448 if (pas_supported(PAS_WCNSS) > 0) {
449 desc->ops = &pil_pronto_ops_trusted;
450 dev_info(&pdev->dev, "using secure boot\n");
451 } else {
452 desc->ops = &pil_pronto_ops;
453 dev_info(&pdev->dev, "using non-secure boot\n");
454 }
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800455
456 drv->vreg = devm_regulator_get(&pdev->dev, "vdd_pronto_pll");
457 if (IS_ERR(drv->vreg)) {
458 dev_err(&pdev->dev, "failed to get pronto pll supply");
459 return PTR_ERR(drv->vreg);
460 }
461
462 ret = regulator_set_voltage(drv->vreg, 1800000, 1800000);
463 if (ret) {
464 dev_err(&pdev->dev, "failed to set pll supply voltage\n");
465 return ret;
466 }
467
468 ret = regulator_set_optimum_mode(drv->vreg, 18000);
469 if (ret < 0) {
470 dev_err(&pdev->dev, "failed to set pll supply mode\n");
471 return ret;
472 }
473
474 drv->cxo = devm_clk_get(&pdev->dev, "xo");
475 if (IS_ERR(drv->cxo))
476 return PTR_ERR(drv->cxo);
477
Stephen Boyde83a0a22012-06-29 13:51:27 -0700478 ret = pil_desc_init(desc);
479 if (ret)
480 return ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800481
Stephen Boyd581fe852012-06-13 12:05:35 -0700482 ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
483 smsm_state_cb_hdlr, drv);
484 if (ret < 0)
485 goto err_smsm;
486
487 drv->subsys_desc.name = desc->name;
488 drv->subsys_desc.dev = &pdev->dev;
489 drv->subsys_desc.owner = THIS_MODULE;
490 drv->subsys_desc.shutdown = wcnss_shutdown;
491 drv->subsys_desc.powerup = wcnss_powerup;
492 drv->subsys_desc.ramdump = wcnss_ramdump;
493 drv->subsys_desc.crash_shutdown = crash_shutdown;
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700494 drv->subsys_desc.start = pronto_start;
495 drv->subsys_desc.stop = pronto_stop;
Stephen Boyd581fe852012-06-13 12:05:35 -0700496
497 INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
498
499 drv->subsys = subsys_register(&drv->subsys_desc);
500 if (IS_ERR(drv->subsys)) {
501 ret = PTR_ERR(drv->subsys);
502 goto err_subsys;
503 }
504
505 ret = devm_request_irq(&pdev->dev, drv->irq, wcnss_wdog_bite_irq_hdlr,
506 IRQF_TRIGGER_HIGH, "wcnss_wdog", drv);
507 if (ret < 0)
508 goto err_irq;
509
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800510 drv->ramdump_dev = create_ramdump_device("pronto", &pdev->dev);
511 if (!drv->ramdump_dev) {
512 ret = -ENOMEM;
513 goto err_irq;
514 }
515
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800516 /* Initialize common_ss GDSCR to wait 4 cycles between states */
517 regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
518 & PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
519 regval |= (2 << EN_REST_WAIT) | (2 << EN_FEW_WAIT)
520 | (2 << CLK_DIS_WAIT);
521 writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
522
523 return 0;
Stephen Boyd581fe852012-06-13 12:05:35 -0700524err_irq:
525 subsys_unregister(drv->subsys);
526err_subsys:
527 smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
528 smsm_state_cb_hdlr, drv);
529err_smsm:
Stephen Boyde83a0a22012-06-29 13:51:27 -0700530 pil_desc_release(desc);
Stephen Boyd581fe852012-06-13 12:05:35 -0700531 return ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800532}
533
534static int __devexit pil_pronto_remove(struct platform_device *pdev)
535{
536 struct pronto_data *drv = platform_get_drvdata(pdev);
Stephen Boyd581fe852012-06-13 12:05:35 -0700537 subsys_unregister(drv->subsys);
538 smsm_state_cb_deregister(SMSM_WCNSS_STATE, SMSM_RESET,
539 smsm_state_cb_hdlr, drv);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700540 pil_desc_release(&drv->desc);
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800541 destroy_ramdump_device(drv->ramdump_dev);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800542 return 0;
543}
544
545static struct of_device_id msm_pil_pronto_match[] = {
546 {.compatible = "qcom,pil-pronto"},
547 {}
548};
549
550static struct platform_driver pil_pronto_driver = {
551 .probe = pil_pronto_probe,
552 .remove = __devexit_p(pil_pronto_remove),
553 .driver = {
554 .name = "pil_pronto",
555 .owner = THIS_MODULE,
556 .of_match_table = msm_pil_pronto_match,
557 },
558};
559
560static int __init pil_pronto_init(void)
561{
562 return platform_driver_register(&pil_pronto_driver);
563}
564module_init(pil_pronto_init);
565
566static void __exit pil_pronto_exit(void)
567{
568 platform_driver_unregister(&pil_pronto_driver);
569}
570module_exit(pil_pronto_exit);
571
572MODULE_DESCRIPTION("Support for booting PRONTO (WCNSS) processors");
573MODULE_LICENSE("GPL v2");