blob: a7fc204142e2cfe93e01a7401e67cca49c4d6117 [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;
Yue Ma63698142014-01-31 17:11:22 -080088 struct work_struct wcnss_wdog_bite_work;
Tianyi Gouc1e049f82011-11-23 14:20:16 -080089};
90
91static int pil_pronto_make_proxy_vote(struct pil_desc *pil)
92{
93 struct pronto_data *drv = dev_get_drvdata(pil->dev);
94 int ret;
95
96 ret = regulator_enable(drv->vreg);
97 if (ret) {
98 dev_err(pil->dev, "failed to enable pll supply\n");
99 goto err;
100 }
101 ret = clk_prepare_enable(drv->cxo);
102 if (ret) {
103 dev_err(pil->dev, "failed to enable cxo\n");
104 goto err_clk;
105 }
106 return 0;
107err_clk:
108 regulator_disable(drv->vreg);
109err:
110 return ret;
111}
112
113static void pil_pronto_remove_proxy_vote(struct pil_desc *pil)
114{
115 struct pronto_data *drv = dev_get_drvdata(pil->dev);
116 regulator_disable(drv->vreg);
117 clk_disable_unprepare(drv->cxo);
118}
119
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800120static int pil_pronto_reset(struct pil_desc *pil)
121{
122 u32 reg;
123 int rc;
124 struct pronto_data *drv = dev_get_drvdata(pil->dev);
125 void __iomem *base = drv->base;
Tianyi Gou819851e2013-04-16 16:05:56 -0700126 phys_addr_t start_addr = pil_get_entry_addr(pil);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800127
Matt Wagantall33c2ec72012-07-26 20:26:57 -0700128 /* Deassert reset to subsystem and wait for propagation */
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800129 reg = readl_relaxed(drv->reset_base);
130 reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
131 writel_relaxed(reg, drv->reset_base);
132 mb();
Matt Wagantall33c2ec72012-07-26 20:26:57 -0700133 udelay(2);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800134
135 /* Configure boot address */
136 writel_relaxed(start_addr >> 16, base +
137 PRONTO_PMU_CCPU_BOOT_REMAP_ADDR);
138
139 /* Use the high vector table */
140 reg = readl_relaxed(base + PRONTO_PMU_CCPU_CTL);
141 reg |= PRONTO_PMU_CCPU_CTL_REMAP_EN | PRONTO_PMU_CCPU_CTL_HIGH_IVT;
142 writel_relaxed(reg, base + PRONTO_PMU_CCPU_CTL);
143
144 /* Turn on AHB clock of common_ss */
145 reg = readl_relaxed(base + PRONTO_PMU_COMMON_AHB_CBCR);
146 reg |= PRONTO_PMU_COMMON_AHB_CBCR_CLK_EN;
147 writel_relaxed(reg, base + PRONTO_PMU_COMMON_AHB_CBCR);
148
149 /* Turn on CPU clock of common_ss */
150 reg = readl_relaxed(base + PRONTO_PMU_COMMON_CPU_CBCR);
151 reg |= PRONTO_PMU_COMMON_CPU_CBCR_CLK_EN;
152 writel_relaxed(reg, base + PRONTO_PMU_COMMON_CPU_CBCR);
153
154 /* Enable A2XB bridge */
155 reg = readl_relaxed(base + PRONTO_PMU_COMMON_CSR);
156 reg |= PRONTO_PMU_COMMON_CSR_A2XB_CFG_EN;
157 writel_relaxed(reg, base + PRONTO_PMU_COMMON_CSR);
158
159 /* Enable common_ss power */
160 reg = readl_relaxed(base + PRONTO_PMU_COMMON_GDSCR);
161 reg &= ~PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
162 writel_relaxed(reg, base + PRONTO_PMU_COMMON_GDSCR);
163
164 /* Wait for AHB clock to be on */
165 rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_AHB_CBCR,
166 reg,
167 !(reg & PRONTO_PMU_COMMON_AHB_CLK_OFF),
168 CLK_UPDATE_TIMEOUT_US);
169 if (rc) {
170 dev_err(pil->dev, "pronto common ahb clk enable timeout\n");
171 return rc;
172 }
173
174 /* Wait for CPU clock to be on */
175 rc = readl_tight_poll_timeout(base + PRONTO_PMU_COMMON_CPU_CBCR,
176 reg,
177 !(reg & PRONTO_PMU_COMMON_CPU_CLK_OFF),
178 CLK_UPDATE_TIMEOUT_US);
179 if (rc) {
180 dev_err(pil->dev, "pronto common cpu clk enable timeout\n");
181 return rc;
182 }
183
184 /* Deassert ARM9 software reset */
185 reg = readl_relaxed(base + PRONTO_PMU_SOFT_RESET);
186 reg &= ~PRONTO_PMU_SOFT_RESET_CRCM_CCPU_SOFT_RESET;
187 writel_relaxed(reg, base + PRONTO_PMU_SOFT_RESET);
188
189 return 0;
190}
191
192static int pil_pronto_shutdown(struct pil_desc *pil)
193{
194 struct pronto_data *drv = dev_get_drvdata(pil->dev);
195 int ret;
196 u32 reg, status;
197
198 /* Halt A2XB */
199 writel_relaxed(1, drv->axi_halt_base + AXI_HALTREQ);
200 ret = readl_poll_timeout(drv->axi_halt_base + AXI_HALTACK,
201 status, status, 50, HALT_ACK_TIMEOUT_US);
202 if (ret)
203 dev_err(pil->dev, "Port halt timeout\n");
204 else if (!readl_relaxed(drv->axi_halt_base + AXI_IDLE))
205 dev_err(pil->dev, "Port halt failed\n");
206
207 writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
208
209 /* Assert reset to Pronto */
210 reg = readl_relaxed(drv->reset_base);
211 reg |= CLK_CTL_WCNSS_RESTART_BIT;
212 writel_relaxed(reg, drv->reset_base);
213
214 /* Wait for reset to complete */
215 mb();
216 usleep_range(1000, 2000);
217
Matt Wagantall44131df2012-08-03 18:29:47 -0700218 /* Deassert reset to subsystem and wait for propagation */
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800219 reg = readl_relaxed(drv->reset_base);
220 reg &= ~CLK_CTL_WCNSS_RESTART_BIT;
221 writel_relaxed(reg, drv->reset_base);
222 mb();
Matt Wagantall44131df2012-08-03 18:29:47 -0700223 udelay(2);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800224
225 return 0;
226}
227
228static struct pil_reset_ops pil_pronto_ops = {
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800229 .auth_and_reset = pil_pronto_reset,
230 .shutdown = pil_pronto_shutdown,
231 .proxy_vote = pil_pronto_make_proxy_vote,
232 .proxy_unvote = pil_pronto_remove_proxy_vote,
233};
234
Tianyi Gou13d85b92012-11-12 18:04:07 -0800235static int pil_pronto_init_image_trusted(struct pil_desc *pil,
236 const u8 *metadata, size_t size)
237{
238 return pas_init_image(PAS_WCNSS, metadata, size);
239}
240
Stephen Boydc8c5db92012-12-03 11:13:20 -0800241static int pil_pronto_mem_setup_trusted(struct pil_desc *pil, phys_addr_t addr,
242 size_t size)
243{
244 return pas_mem_setup(PAS_WCNSS, addr, size);
245}
246
Tianyi Gou13d85b92012-11-12 18:04:07 -0800247static int pil_pronto_reset_trusted(struct pil_desc *pil)
248{
249 return pas_auth_and_reset(PAS_WCNSS);
250}
251
252static int pil_pronto_shutdown_trusted(struct pil_desc *pil)
253{
254 return pas_shutdown(PAS_WCNSS);
255}
256
257static struct pil_reset_ops pil_pronto_ops_trusted = {
258 .init_image = pil_pronto_init_image_trusted,
Stephen Boydc8c5db92012-12-03 11:13:20 -0800259 .mem_setup = pil_pronto_mem_setup_trusted,
Tianyi Gou13d85b92012-11-12 18:04:07 -0800260 .auth_and_reset = pil_pronto_reset_trusted,
261 .shutdown = pil_pronto_shutdown_trusted,
262 .proxy_vote = pil_pronto_make_proxy_vote,
263 .proxy_unvote = pil_pronto_remove_proxy_vote,
264};
265
Stephen Boyd581fe852012-06-13 12:05:35 -0700266#define subsys_to_drv(d) container_of(d, struct pronto_data, subsys_desc)
267
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700268static int pronto_start(const struct subsys_desc *desc)
269{
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700270 struct pronto_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700271 return pil_boot(&drv->desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700272}
273
274static void pronto_stop(const struct subsys_desc *desc)
275{
276 struct pronto_data *drv = subsys_to_drv(desc);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700277 pil_shutdown(&drv->desc);
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700278}
279
Stephen Boyd581fe852012-06-13 12:05:35 -0700280static void log_wcnss_sfr(void)
281{
282 char *smem_reset_reason;
283 unsigned smem_reset_size;
284
285 smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
286 &smem_reset_size);
287
288 if (!smem_reset_reason || !smem_reset_size) {
289 pr_err("wcnss subsystem failure reason:\n"
290 "(unknown, smem_get_entry failed)");
291 } else if (!smem_reset_reason[0]) {
292 pr_err("wcnss subsystem failure reason:\n"
293 "(unknown, init string found)");
294 } else {
295 pr_err("wcnss subsystem failure reason: %.81s\n",
296 smem_reset_reason);
297 memset(smem_reset_reason, 0, smem_reset_size);
298 wmb();
299 }
300}
301
302static void restart_wcnss(struct pronto_data *drv)
303{
304 log_wcnss_sfr();
305 subsystem_restart_dev(drv->subsys);
306}
307
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700308static irqreturn_t wcnss_err_fatal_intr_handler(int irq, void *dev_id)
Stephen Boyd581fe852012-06-13 12:05:35 -0700309{
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700310 struct pronto_data *drv = subsys_to_drv(dev_id);
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700311
312 pr_err("Fatal error on the wcnss.\n");
Stephen Boyd581fe852012-06-13 12:05:35 -0700313
314 drv->crash = true;
Stephen Boyd581fe852012-06-13 12:05:35 -0700315 if (drv->restart_inprogress) {
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700316 pr_err("wcnss: Ignoring error fatal, restart in progress\n");
317 return IRQ_HANDLED;
Stephen Boyd581fe852012-06-13 12:05:35 -0700318 }
319
320 drv->restart_inprogress = true;
321 restart_wcnss(drv);
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700322
323 return IRQ_HANDLED;
Stephen Boyd581fe852012-06-13 12:05:35 -0700324}
325
Yue Ma63698142014-01-31 17:11:22 -0800326static void wcnss_wdog_bite_work_hdlr(struct work_struct *wcnss_work)
327{
328 struct pronto_data *drv = container_of(wcnss_work, struct pronto_data,
329 wcnss_wdog_bite_work);
330
331 wcnss_log_debug_regs_on_bite();
332
333 restart_wcnss(drv);
334}
335
Stephen Boyd581fe852012-06-13 12:05:35 -0700336static irqreturn_t wcnss_wdog_bite_irq_hdlr(int irq, void *dev_id)
337{
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700338 struct pronto_data *drv = subsys_to_drv(dev_id);
Stephen Boyd581fe852012-06-13 12:05:35 -0700339
340 drv->crash = true;
341
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700342 disable_irq_nosync(drv->subsys_desc.wdog_bite_irq);
Sameer Thalappil6287b562013-05-14 09:23:08 -0700343
Stephen Boyd581fe852012-06-13 12:05:35 -0700344 if (drv->restart_inprogress) {
345 pr_err("Ignoring wcnss bite irq, restart in progress\n");
346 return IRQ_HANDLED;
347 }
348
349 drv->restart_inprogress = true;
Yue Ma63698142014-01-31 17:11:22 -0800350 schedule_work(&drv->wcnss_wdog_bite_work);
Stephen Boyd581fe852012-06-13 12:05:35 -0700351
352 return IRQ_HANDLED;
353}
354
355static void wcnss_post_bootup(struct work_struct *work)
356{
357 struct platform_device *pdev = wcnss_get_platform_device();
358 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
359
Sameer Thalappil1d69b8022013-06-10 19:10:07 -0700360 wcnss_wlan_power(&pdev->dev, pwlanconfig, WCNSS_WLAN_SWITCH_OFF, NULL);
Stephen Boyd581fe852012-06-13 12:05:35 -0700361}
362
363static int wcnss_shutdown(const struct subsys_desc *subsys)
364{
365 struct pronto_data *drv = subsys_to_drv(subsys);
366
Stephen Boyde83a0a22012-06-29 13:51:27 -0700367 pil_shutdown(&drv->desc);
Stephen Boyd581fe852012-06-13 12:05:35 -0700368 flush_delayed_work(&drv->cancel_vote_work);
369 wcnss_flush_delayed_boot_votes();
Stephen Boyd581fe852012-06-13 12:05:35 -0700370
371 return 0;
372}
373
374static int wcnss_powerup(const struct subsys_desc *subsys)
375{
376 struct pronto_data *drv = subsys_to_drv(subsys);
377 struct platform_device *pdev = wcnss_get_platform_device();
378 struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
379 int ret = -1;
380
381 if (pdev && pwlanconfig)
382 ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
Sameer Thalappil1d69b8022013-06-10 19:10:07 -0700383 WCNSS_WLAN_SWITCH_ON, NULL);
Stephen Boyd581fe852012-06-13 12:05:35 -0700384 if (!ret) {
385 msleep(1000);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700386 ret = pil_boot(&drv->desc);
387 if (ret)
388 return ret;
Stephen Boyd581fe852012-06-13 12:05:35 -0700389 }
390 drv->restart_inprogress = false;
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700391 enable_irq(drv->subsys_desc.wdog_bite_irq);
Stephen Boyd581fe852012-06-13 12:05:35 -0700392 schedule_delayed_work(&drv->cancel_vote_work, msecs_to_jiffies(5000));
393
394 return 0;
395}
396
397static void crash_shutdown(const struct subsys_desc *subsys)
398{
399 struct pronto_data *drv = subsys_to_drv(subsys);
400
401 pr_err("wcnss crash shutdown %d\n", drv->crash);
402 if (!drv->crash)
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700403 gpio_set_value(subsys->force_stop_gpio, 1);
Stephen Boyd581fe852012-06-13 12:05:35 -0700404}
405
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800406static int wcnss_ramdump(int enable, const struct subsys_desc *subsys)
Stephen Boyd581fe852012-06-13 12:05:35 -0700407{
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800408 struct pronto_data *drv = subsys_to_drv(subsys);
409
Stephen Boyd5eb17ce2012-11-29 15:34:21 -0800410 if (!enable)
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800411 return 0;
Stephen Boyd5eb17ce2012-11-29 15:34:21 -0800412
413 return pil_do_ramdump(&drv->desc, drv->ramdump_dev);
Stephen Boyd581fe852012-06-13 12:05:35 -0700414}
415
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800416static int __devinit pil_pronto_probe(struct platform_device *pdev)
417{
418 struct pronto_data *drv;
419 struct resource *res;
420 struct pil_desc *desc;
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700421 int ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800422 uint32_t regval;
423
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800424 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
425 if (!drv)
426 return -ENOMEM;
427 platform_set_drvdata(pdev, drv);
428
Stephen Boydf8f89282012-07-16 18:05:48 -0700429 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu_base");
430 drv->base = devm_request_and_ioremap(&pdev->dev, res);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800431 if (!drv->base)
432 return -ENOMEM;
433
Matt Wagantall1f168152012-09-25 13:26:47 -0700434 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
Stephen Boydf8f89282012-07-16 18:05:48 -0700435 drv->reset_base = devm_request_and_ioremap(&pdev->dev, res);
436 if (!drv->reset_base)
437 return -ENOMEM;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800438
Matt Wagantall1f168152012-09-25 13:26:47 -0700439 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
Stephen Boydf8f89282012-07-16 18:05:48 -0700440 drv->axi_halt_base = devm_request_and_ioremap(&pdev->dev, res);
441 if (!drv->axi_halt_base)
442 return -ENOMEM;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800443
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700444 desc = &drv->desc;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800445 ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
446 &desc->name);
447 if (ret)
448 return ret;
449
450 desc->dev = &pdev->dev;
451 desc->owner = THIS_MODULE;
452 desc->proxy_timeout = 10000;
453
Tianyi Gou13d85b92012-11-12 18:04:07 -0800454 if (pas_supported(PAS_WCNSS) > 0) {
455 desc->ops = &pil_pronto_ops_trusted;
456 dev_info(&pdev->dev, "using secure boot\n");
457 } else {
458 desc->ops = &pil_pronto_ops;
459 dev_info(&pdev->dev, "using non-secure boot\n");
460 }
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800461
462 drv->vreg = devm_regulator_get(&pdev->dev, "vdd_pronto_pll");
463 if (IS_ERR(drv->vreg)) {
464 dev_err(&pdev->dev, "failed to get pronto pll supply");
465 return PTR_ERR(drv->vreg);
466 }
467
468 ret = regulator_set_voltage(drv->vreg, 1800000, 1800000);
469 if (ret) {
470 dev_err(&pdev->dev, "failed to set pll supply voltage\n");
471 return ret;
472 }
473
474 ret = regulator_set_optimum_mode(drv->vreg, 18000);
475 if (ret < 0) {
476 dev_err(&pdev->dev, "failed to set pll supply mode\n");
477 return ret;
478 }
479
480 drv->cxo = devm_clk_get(&pdev->dev, "xo");
481 if (IS_ERR(drv->cxo))
482 return PTR_ERR(drv->cxo);
483
Deepak Katragadda4118ccc2013-07-05 10:01:19 -0700484 scm_pas_init(MSM_BUS_MASTER_CRYPTO_CORE0);
485
Stephen Boyde83a0a22012-06-29 13:51:27 -0700486 ret = pil_desc_init(desc);
487 if (ret)
488 return ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800489
Stephen Boyd581fe852012-06-13 12:05:35 -0700490 drv->subsys_desc.name = desc->name;
491 drv->subsys_desc.dev = &pdev->dev;
492 drv->subsys_desc.owner = THIS_MODULE;
493 drv->subsys_desc.shutdown = wcnss_shutdown;
494 drv->subsys_desc.powerup = wcnss_powerup;
495 drv->subsys_desc.ramdump = wcnss_ramdump;
496 drv->subsys_desc.crash_shutdown = crash_shutdown;
Stephen Boyd3e4e9752012-06-27 12:46:32 -0700497 drv->subsys_desc.start = pronto_start;
498 drv->subsys_desc.stop = pronto_stop;
Seemanta Dutta076d00e2013-06-17 17:58:18 -0700499 drv->subsys_desc.err_fatal_handler = wcnss_err_fatal_intr_handler;
500 drv->subsys_desc.wdog_bite_handler = wcnss_wdog_bite_irq_hdlr;
Sameer Thalappilb1e03c02013-04-29 14:52:00 -0700501
Stephen Boyd581fe852012-06-13 12:05:35 -0700502 INIT_DELAYED_WORK(&drv->cancel_vote_work, wcnss_post_bootup);
Yue Ma63698142014-01-31 17:11:22 -0800503 INIT_WORK(&drv->wcnss_wdog_bite_work, wcnss_wdog_bite_work_hdlr);
Stephen Boyd581fe852012-06-13 12:05:35 -0700504
505 drv->subsys = subsys_register(&drv->subsys_desc);
506 if (IS_ERR(drv->subsys)) {
507 ret = PTR_ERR(drv->subsys);
508 goto err_subsys;
509 }
510
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800511 drv->ramdump_dev = create_ramdump_device("pronto", &pdev->dev);
512 if (!drv->ramdump_dev) {
513 ret = -ENOMEM;
514 goto err_irq;
515 }
516
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800517 /* Initialize common_ss GDSCR to wait 4 cycles between states */
518 regval = readl_relaxed(drv->base + PRONTO_PMU_COMMON_GDSCR)
519 & PRONTO_PMU_COMMON_GDSCR_SW_COLLAPSE;
520 regval |= (2 << EN_REST_WAIT) | (2 << EN_FEW_WAIT)
521 | (2 << CLK_DIS_WAIT);
522 writel_relaxed(regval, drv->base + PRONTO_PMU_COMMON_GDSCR);
523
524 return 0;
Sameer Thalappilcbabf072013-03-28 13:51:41 -0700525
Stephen Boyd581fe852012-06-13 12:05:35 -0700526err_irq:
527 subsys_unregister(drv->subsys);
528err_subsys:
Stephen Boyde83a0a22012-06-29 13:51:27 -0700529 pil_desc_release(desc);
Stephen Boyd581fe852012-06-13 12:05:35 -0700530 return ret;
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800531}
532
533static int __devexit pil_pronto_remove(struct platform_device *pdev)
534{
535 struct pronto_data *drv = platform_get_drvdata(pdev);
Stephen Boyd581fe852012-06-13 12:05:35 -0700536 subsys_unregister(drv->subsys);
Stephen Boyde83a0a22012-06-29 13:51:27 -0700537 pil_desc_release(&drv->desc);
Sameer Thalappilb7488b22012-11-09 16:40:12 -0800538 destroy_ramdump_device(drv->ramdump_dev);
Tianyi Gouc1e049f82011-11-23 14:20:16 -0800539 return 0;
540}
541
542static struct of_device_id msm_pil_pronto_match[] = {
543 {.compatible = "qcom,pil-pronto"},
544 {}
545};
546
547static struct platform_driver pil_pronto_driver = {
548 .probe = pil_pronto_probe,
549 .remove = __devexit_p(pil_pronto_remove),
550 .driver = {
551 .name = "pil_pronto",
552 .owner = THIS_MODULE,
553 .of_match_table = msm_pil_pronto_match,
554 },
555};
556
557static int __init pil_pronto_init(void)
558{
559 return platform_driver_register(&pil_pronto_driver);
560}
561module_init(pil_pronto_init);
562
563static void __exit pil_pronto_exit(void)
564{
565 platform_driver_unregister(&pil_pronto_driver);
566}
567module_exit(pil_pronto_exit);
568
569MODULE_DESCRIPTION("Support for booting PRONTO (WCNSS) processors");
570MODULE_LICENSE("GPL v2");