blob: 69df3ae73716368022ca7c1505a9bd9f5bbc8c51 [file] [log] [blame]
Sameer Thalappil4ca0d0f2013-02-16 07:12:36 -08001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Tianyi Gouc1e049f82011-11-23 14:20:16 -08002 *
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>
Sameer Thalappilcbabf072013-03-28 13:51:41 -070028#include <linux/of_gpio.h>
Stephen Boyd581fe852012-06-13 12:05:35 -070029
30#include <mach/subsystem_restart.h>
Stephen Boyd581fe852012-06-13 12:05:35 -070031#include <mach/msm_smsm.h>
Seemanta Dutta4e2d49c2013-04-05 16:28:11 -070032#include <mach/ramdump.h>
Jeff Hugo5ba15fe2013-05-06 14:24:24 -060033#include <mach/msm_smem.h>
Deepak Katragadda4118ccc2013-07-05 10:01:19 -070034#include <mach/msm_bus_board.h>
Tianyi Gouc1e049f82011-11-23 14:20:16 -080035
36#include "peripheral-loader.h"
37#include "scm-pas.h"
38
39#define PRONTO_PMU_COMMON_GDSCR 0x24
40#define PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE BIT(0)
41#define CLK_DIS_WAIT 12
42#define EN_FEW_WAIT 16
43#define EN_REST_WAIT 20
44
45#define PRONTO_PMU_COMMON_CPU_CBCR 0x30
46#define PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN BIT(0)
47#define PRONTO_PMU_COMMON_CPU_CLK_OFF BIT(31)
48
49#define PRONTO_PMU_COMMON_AHB_CBCR 0x34
50#define PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN BIT(0)
51#define PRONTO_PMU_COMMON_AHB_CLK_OFF BIT(31)
52
53#define PRONTO_PMU_COMMON_CSR 0x1040
54#define PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN BIT(0)
55
56#define PRONTO_PMU_SOFT_RESET 0x104C
57#define PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET BIT(10)
58
59#define PRONTO_PMU_CCPU_CTL 0x2000
60#define PRONTO_PMU_CCPU_CTL_REMAP_EN BIT(2)
61#define PRONTO_PMU_CCPU_CTL_HIGH_IVT BIT(0)
62
63#define PRONTO_PMU_CCPU_BOOT_REMAP_ADDR 0x2004
64
65#define CLK_CTL_WCNSS_RESTART_BIT BIT(0)
66
67#define AXI_HALTREQ 0x0
68#define AXI_HALTACK 0x4
69#define AXI_IDLE 0x8
70
71#define HALT_ACK_TIMEOUT_US 500000
72#define CLK_UPDATE_TIMEOUT_US 500000
73
74struct pronto_data {
75 void __iomem *base;
76 void __iomem *reset_base;
77 void __iomem *axi_halt_base;
Tianyi Gouc1e049f82011-11-23 14:20:16 -080078 struct pil_device *pil;
Stephen Boyd3e4e9752012-06-27 12:46:32 -070079 struct pil_desc desc;
Stephen Boyd581fe852012-06-13 12:05:35 -070080 struct subsys_device *subsys;
81 struct subsys_desc subsys_desc;
Tianyi Gouc1e049f82011-11-23 14:20:16 -080082 struct clk *cxo;
83 struct regulator *vreg;
Stephen Boyd581fe852012-06-13 12:05:35 -070084 bool restart_inprogress;
85 bool crash;
86 struct delayed_work cancel_vote_work;
Sameer Thalappilb7488b22012-11-09 16:40:12 -080087 struct ramdump_device *ramdump_dev;
Tianyi Gouc1e049f82011-11-23 14:20:16 -080088};
89
90static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
91{
92 struct pronto_data *drv = dev_get_drvdata(pil->dev);
93 int ret;
94
95 ret = regulator_enable(drv->vreg);
96 if (ret) {
97 dev_err(pil->dev, "failed to enable pll supply\n");
98 goto err;
99 }
100 ret = clk_prepare_enable(drv->cxo);
101 if (ret) {
102 dev_err(pil->dev, "failed to enable cxo\n");
103 goto err_clk;
104 }
105 return 0;
106err_clk:
107 regulator_disable(drv->vreg);
108err:
109 return ret;
110}
111
112static void pil_pronto_remove_proxy_vote(struct pil_desc *pil)
113{
114 struct pronto_data *drv = dev_get_drvdata(pil->dev);
115 regulator_disable(drv->vreg);
116 clk_disable_unprepare(drv->cxo);
117}
118
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800119static int pil_pronto_reset(struct pil_desc *pil)
120{
121 u32 reg;
122 int rc;
123 struct pronto_data *drv = dev_get_drvdata(pil->dev);
124 void __iomem *base = drv->base;
Tianyi Gou819851e2013-04-16 16:05:56 -0700125 phys_addr_t start_addr = pil_get_entry_addr(pil);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800126
Matt Wagantall33c2ec72012-07-26 20:26:57 -0700127 /* Deassert reset to subsystem and wait for propagation */
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800128 reg = readl_relaxed(drv->reset_base);
129 reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
130 writel_relaxed(reg, drv->reset_base);
131 mb();
Matt Wagantall33c2ec72012-07-26 20:26:57 -0700132 udelay(2);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800133
134 /* Configure boot address */
135 writel_relaxed(start_addr >> 16, base +
136 PRONTO_PMU_CCPU_BOOT_REMAP_ADDR);
137
138 /* Use the high vector table */
139 reg = readl_relaxed(base + PRONTO_PMU_CCPU_CTL);
140 reg |= PRONTO_PMU_CCPU_CTL_REMAP_EN | PRONTO_PMU_CCPU_CTL_HIGH_IVT;
141 writel_relaxed(reg, base + PRONTO_PMU_CCPU_CTL);
142
143 /* Turn on AHB clock of common_ss */
144 reg = readl_relaxed(base + PRONTO_PMU_COMMON_AHB_CBCR);
145 reg |= PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN;
146 writel_relaxed(reg, base + PRONTO_PMU_COMMON_AHB_CBCR);
147
148 /* Turn on CPU clock of common_ss */
149 reg = readl_relaxed(base + PRONTO_PMU_COMMON_CPU_CBCR);
150 reg |= PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN;
151 writel_relaxed(reg, base + PRONTO_PMU_COMMON_CPU_CBCR);
152
153 /* Enable A2XB bridge */
154 reg = readl_relaxed(base + PRONTO_PMU_COMMON_CSR);
155 reg |= PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN;
156 writel_relaxed(reg, base + PRONTO_PMU_COMMON_CSR);
157
158 /* Enable common_ss power */
159 reg = readl_relaxed(base + PRONTO_PMU_COMMON_GDSCR);
160 reg &= ~PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
161 writel_relaxed(reg, base + PRONTO_PMU_COMMON_GDSCR);
162
163 /* Wait for AHB clock to be on */
164 rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_AHB_CBCR,
165 reg,
166 !(reg & PRONTO_PMU_COMMON_AHB_CLK_OFF),
167 CLK_UPDATE_TIMEOUT_US);
168 if (rc) {
169 dev_err(pil->dev, "pronto common ahb clk enable timeout\n");
170 return rc;
171 }
172
173 /* Wait for CPU clock to be on */
174 rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_CPU_CBCR,
175 reg,
176 !(reg & PRONTO_PMU_COMMON_CPU_CLK_OFF),
177 CLK_UPDATE_TIMEOUT_US);
178 if (rc) {
179 dev_err(pil->dev, "pronto common cpu clk enable timeout\n");
180 return rc;
181 }
182
183 /* Deassert ARM9 software reset */
184 reg = readl_relaxed(base + PRONTO_PMU_SOFT_RESET);
185 reg &= ~PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET;
186 writel_relaxed(reg, base + PRONTO_PMU_SOFT_RESET);
187
188 return 0;
189}
190
191static int pil_pronto_shutdown(struct pil_desc *pil)
192{
193 struct pronto_data *drv = dev_get_drvdata(pil->dev);
194 int ret;
195 u32 reg, status;
196
197 /* Halt A2XB */
198 writel_relaxed(1, drv->axi_halt_base + AXI_HALTREQ);
199 ret = readl_poll_timeout(drv->axi_halt_base + AXI_HALTACK,
200 status, status, 50, HALT_ACK_TIMEOUT_US);
201 if (ret)
202 dev_err(pil->dev, "Port halt timeout\n");
203 else if (!readl_relaxed(drv->axi_halt_base + AXI_IDLE))
204 dev_err(pil->dev, "Port halt failed\n");
205
206 writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
207
208 /* Assert reset to Pronto */
209 reg = readl_relaxed(drv->reset_base);
210 reg |= CLK_CTL_WCNSS_RESTART_BIT;
211 writel_relaxed(reg, drv->reset_base);
212
213 /* Wait for reset to complete */
214 mb();
215 usleep_range(1000, 2000);
216
Matt Wagantall44131df2012-08-03 18:29:47 -0700217 /* Deassert reset to subsystem and wait for propagation */
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800218 reg = readl_relaxed(drv->reset_base);
219 reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
220 writel_relaxed(reg, drv->reset_base);
221 mb();
Matt Wagantall44131df2012-08-03 18:29:47 -0700222 udelay(2);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800223
224 return 0;
225}
226
227static struct pil_reset_ops pil_pronto_ops = {
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800228 .auth_and_reset = pil_pronto_reset,
229 .shutdown = pil_pronto_shutdown,
230 .proxy_vote = pil_pronto_make_proxy_vote,
231 .proxy_unvote = pil_pronto_remove_proxy_vote,
232};
233
Tianyi Gou13d85b92012-11-12 18:04:07 -0800234static int pil_pronto_init_image_trusted(struct pil_desc *pil,
235 const u8 *metadata, size_t size)
236{
237 return pas_init_image(PAS_WCNSS, metadata, size);
238}
239
Stephen Boydc8c5db92012-12-03 11:13:20 -0800240static int pil_pronto_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
241 size_t size)
242{
243 return pas_mem_setup(PAS_WCNSS, addr, size);
244}
245
Tianyi Gou13d85b92012-11-12 18:04:07 -0800246static int pil_pronto_reset_trusted(struct pil_desc *pil)
247{
248 return pas_auth_and_reset(PAS_WCNSS);
249}
250
251static int pil_pronto_shutdown_trusted(struct pil_desc *pil)
252{
253 return pas_shutdown(PAS_WCNSS);
254}
255
256static struct pil_reset_ops pil_pronto_ops_trusted = {
257 .init_image = pil_pronto_init_image_trusted,
Stephen Boydc8c5db92012-12-03 11:13:20 -0800258 .mem_setup = pil_pronto_mem_setup_trusted,
Tianyi Gou13d85b92012-11-12 18:04:07 -0800259 .auth_and_reset = pil_pronto_reset_trusted,
260 .shutdown = pil_pronto_shutdown_trusted,
261 .proxy_vote = pil_pronto_make_proxy_vote,
262 .proxy_unvote = pil_pronto_remove_proxy_vote,
263};
264
Stephen Boyd581fe852012-06-13 12:05:35 -0700265#define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
266
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700267static int pronto_start(const struct subsys_desc *desc)
268{
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700269 struct pronto_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700270 return pil_boot(&drv->desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700271}
272
273static void pronto_stop(const struct subsys_desc *desc)
274{
275 struct pronto_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700276 pil_shutdown(&drv->desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700277}
278
Stephen Boyd581fe852012-06-13 12:05:35 -0700279static void log_wcnss_sfr(void)
280{
281 char *smem_reset_reason;
282 unsigned smem_reset_size;
283
284 smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
285 &smem_reset_size);
286
287 if (!smem_reset_reason || !smem_reset_size) {
288 pr_err("wcnss subsystem failure reason:\n"
289 "(unknown, smem_get_entry failed)");
290 } else if (!smem_reset_reason[0]) {
291 pr_err("wcnss subsystem failure reason:\n"
292 "(unknown, init string found)");
293 } else {
294 pr_err("wcnss subsystem failure reason: %.81s\n",
295 smem_reset_reason);
296 memset(smem_reset_reason, 0, smem_reset_size);
297 wmb();
298 }
299}
300
301static void restart_wcnss(struct pronto_data *drv)
302{
303 log_wcnss_sfr();
304 subsystem_restart_dev(drv->subsys);
305}
306
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700307static irqreturn_t wcnss_err_fatal_intr_handler(int irq, void *dev_id)
Stephen Boyd581fe852012-06-13 12:05:35 -0700308{
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700309 struct pronto_data *drv = subsys_to_drv(dev_id);
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700310
311 pr_err("Fatal error on the wcnss.\n");
Stephen Boyd581fe852012-06-13 12:05:35 -0700312
313 drv->crash = true;
Stephen Boyd581fe852012-06-13 12:05:35 -0700314 if (drv->restart_inprogress) {
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700315 pr_err("wcnss: Ignoring error fatal, restart in progress\n");
316 return IRQ_HANDLED;
Stephen Boyd581fe852012-06-13 12:05:35 -0700317 }
318
319 drv->restart_inprogress = true;
320 restart_wcnss(drv);
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700321
322 return IRQ_HANDLED;
Stephen Boyd581fe852012-06-13 12:05:35 -0700323}
324
325static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
326{
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700327 struct pronto_data *drv = subsys_to_drv(dev_id);
Stephen Boyd581fe852012-06-13 12:05:35 -0700328
329 drv->crash = true;
330
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700331 disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
Sameer Thalappil6287b562013-05-14 09:23:08 -0700332
Stephen Boyd581fe852012-06-13 12:05:35 -0700333 if (drv->restart_inprogress) {
334 pr_err("Ignoring wcnss bite irq, restart in progress\n");
335 return IRQ_HANDLED;
336 }
Sameer Thalappil36f7a1a2013-10-09 18:32:38 -0700337 wcnss_log_debug_regs_on_bite();
Stephen Boyd581fe852012-06-13 12:05:35 -0700338
339 drv->restart_inprogress = true;
340 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
Sameer Thalappil1d69b8022013-06-10 19:10:07 -0700350 wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF, NULL);
Stephen Boyd581fe852012-06-13 12:05:35 -0700351}
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,
Sameer Thalappil1d69b8022013-06-10 19:10:07 -0700373 WCNSS_WLAN_SWITCH_ON, NULL);
Stephen Boyd581fe852012-06-13 12:05:35 -0700374 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;
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700381 enable_irq(drv->subsys_desc.wdog_bite_irq);
Stephen Boyd581fe852012-06-13 12:05:35 -0700382 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)
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700393 gpio_set_value(subsys->force_stop_gpio, 1);
Stephen Boyd581fe852012-06-13 12:05:35 -0700394}
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;
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700411 int ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800412 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 Boydf8f89282012-07-16 18:05:48 -0700419 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
420 drv->base = devm_request_and_ioremap(&pdev->dev, res);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800421 if (!drv->base)
422 return -ENOMEM;
423
Matt Wagantall1f168152012-09-25 13:26:47 -0700424 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
Stephen Boydf8f89282012-07-16 18:05:48 -0700425 drv->reset_base = devm_request_and_ioremap(&pdev->dev, res);
426 if (!drv->reset_base)
427 return -ENOMEM;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800428
Matt Wagantall1f168152012-09-25 13:26:47 -0700429 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
Stephen Boydf8f89282012-07-16 18:05:48 -0700430 drv->axi_halt_base = devm_request_and_ioremap(&pdev->dev, res);
431 if (!drv->axi_halt_base)
432 return -ENOMEM;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800433
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700434 desc = &drv->desc;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800435 ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
436 &desc->name);
437 if (ret)
438 return ret;
439
440 desc->dev = &pdev->dev;
441 desc->owner = THIS_MODULE;
442 desc->proxy_timeout = 10000;
443
Tianyi Gou13d85b92012-11-12 18:04:07 -0800444 if (pas_supported(PAS_WCNSS) > 0) {
445 desc->ops = &pil_pronto_ops_trusted;
446 dev_info(&pdev->dev, "using secure boot\n");
447 } else {
448 desc->ops = &pil_pronto_ops;
449 dev_info(&pdev->dev, "using non-secure boot\n");
450 }
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800451
452 drv->vreg = devm_regulator_get(&pdev->dev, "vdd_pronto_pll");
453 if (IS_ERR(drv->vreg)) {
454 dev_err(&pdev->dev, "failed to get pronto pll supply");
455 return PTR_ERR(drv->vreg);
456 }
457
458 ret = regulator_set_voltage(drv->vreg, 1800000, 1800000);
459 if (ret) {
460 dev_err(&pdev->dev, "failed to set pll supply voltage\n");
461 return ret;
462 }
463
464 ret = regulator_set_optimum_mode(drv->vreg, 18000);
465 if (ret < 0) {
466 dev_err(&pdev->dev, "failed to set pll supply mode\n");
467 return ret;
468 }
469
470 drv->cxo = devm_clk_get(&pdev->dev, "xo");
471 if (IS_ERR(drv->cxo))
472 return PTR_ERR(drv->cxo);
473
Deepak Katragadda4118ccc2013-07-05 10:01:19 -0700474 scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE0);
475
Stephen Boyde83a0a22012-06-29 13:51:27 -0700476 ret = pil_desc_init(desc);
477 if (ret)
478 return ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800479
Stephen Boyd581fe852012-06-13 12:05:35 -0700480 drv->subsys_desc.name = desc->name;
481 drv->subsys_desc.dev = &pdev->dev;
482 drv->subsys_desc.owner = THIS_MODULE;
483 drv->subsys_desc.shutdown = wcnss_shutdown;
484 drv->subsys_desc.powerup = wcnss_powerup;
485 drv->subsys_desc.ramdump = wcnss_ramdump;
486 drv->subsys_desc.crash_shutdown = crash_shutdown;
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700487 drv->subsys_desc.start = pronto_start;
488 drv->subsys_desc.stop = pronto_stop;
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700489 drv->subsys_desc.err_fatal_handler = wcnss_err_fatal_intr_handler;
490 drv->subsys_desc.wdog_bite_handler = wcnss_wdog_bite_irq_hdlr;
Sameer Thalappilb1e03c02013-04-29 14:52:00 -0700491
Stephen Boyd581fe852012-06-13 12:05:35 -0700492 INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
493
494 drv->subsys = subsys_register(&drv->subsys_desc);
495 if (IS_ERR(drv->subsys)) {
496 ret = PTR_ERR(drv->subsys);
497 goto err_subsys;
498 }
499
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800500 drv->ramdump_dev = create_ramdump_device("pronto", &pdev->dev);
501 if (!drv->ramdump_dev) {
502 ret = -ENOMEM;
503 goto err_irq;
504 }
505
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800506 /* Initialize common_ss GDSCR to wait 4 cycles between states */
507 regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
508 & PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
509 regval |= (2 << EN_REST_WAIT) | (2 << EN_FEW_WAIT)
510 | (2 << CLK_DIS_WAIT);
511 writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
512
513 return 0;
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700514
Stephen Boyd581fe852012-06-13 12:05:35 -0700515err_irq:
516 subsys_unregister(drv->subsys);
517err_subsys:
Stephen Boyde83a0a22012-06-29 13:51:27 -0700518 pil_desc_release(desc);
Stephen Boyd581fe852012-06-13 12:05:35 -0700519 return ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800520}
521
522static int __devexit pil_pronto_remove(struct platform_device *pdev)
523{
524 struct pronto_data *drv = platform_get_drvdata(pdev);
Stephen Boyd581fe852012-06-13 12:05:35 -0700525 subsys_unregister(drv->subsys);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700526 pil_desc_release(&drv->desc);
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800527 destroy_ramdump_device(drv->ramdump_dev);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800528 return 0;
529}
530
531static struct of_device_id msm_pil_pronto_match[] = {
532 {.compatible = "qcom,pil-pronto"},
533 {}
534};
535
536static struct platform_driver pil_pronto_driver = {
537 .probe = pil_pronto_probe,
538 .remove = __devexit_p(pil_pronto_remove),
539 .driver = {
540 .name = "pil_pronto",
541 .owner = THIS_MODULE,
542 .of_match_table = msm_pil_pronto_match,
543 },
544};
545
546static int __init pil_pronto_init(void)
547{
548 return platform_driver_register(&pil_pronto_driver);
549}
550module_init(pil_pronto_init);
551
552static void __exit pil_pronto_exit(void)
553{
554 platform_driver_unregister(&pil_pronto_driver);
555}
556module_exit(pil_pronto_exit);
557
558MODULE_DESCRIPTION("Support for booting PRONTO (WCNSS) processors");
559MODULE_LICENSE("GPL v2");