blob: 8a024aa86352004a32ce3e751e801d0c864ba6e7 [file] [log] [blame]
Yue Ma0317e4a2018-01-10 11:48:32 -08001/* Copyright (c) 2016-2018, The Linux Foundation. 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/delay.h>
14#include <linux/jiffies.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_device.h>
18#include <linux/pm_wakeup.h>
19#include <linux/rwsem.h>
20#include <linux/suspend.h>
21#include <linux/timer.h>
22#include <soc/qcom/ramdump.h>
23#include <soc/qcom/subsystem_notif.h>
24
25#include "main.h"
Yue Mafcf60422018-05-01 16:59:56 -070026#include "bus.h"
Yue Ma0317e4a2018-01-10 11:48:32 -080027#include "debug.h"
Yue Ma0317e4a2018-01-10 11:48:32 -080028
29#define CNSS_DUMP_FORMAT_VER 0x11
30#define CNSS_DUMP_FORMAT_VER_V2 0x22
31#define CNSS_DUMP_MAGIC_VER_V2 0x42445953
32#define CNSS_DUMP_NAME "CNSS_WLAN"
33#define CNSS_DUMP_DESC_SIZE 0x1000
34#define CNSS_DUMP_SEG_VER 0x1
35#define WLAN_RECOVERY_DELAY 1000
36#define FILE_SYSTEM_READY 1
37#define FW_READY_TIMEOUT 20000
38#define FW_ASSERT_TIMEOUT 5000
39#define CNSS_EVENT_PENDING 2989
Yue Ma0317e4a2018-01-10 11:48:32 -080040
41static struct cnss_plat_data *plat_env;
42
43static DECLARE_RWSEM(cnss_pm_sem);
44
45static bool qmi_bypass;
46#ifdef CONFIG_CNSS2_DEBUG
47module_param(qmi_bypass, bool, 0600);
48MODULE_PARM_DESC(qmi_bypass, "Bypass QMI from platform driver");
49#endif
50
51static bool enable_waltest;
52#ifdef CONFIG_CNSS2_DEBUG
53module_param(enable_waltest, bool, 0600);
54MODULE_PARM_DESC(enable_waltest, "Enable to handle firmware waltest");
55#endif
56
Yue Ma0317e4a2018-01-10 11:48:32 -080057unsigned long quirks;
58#ifdef CONFIG_CNSS2_DEBUG
59module_param(quirks, ulong, 0600);
60MODULE_PARM_DESC(quirks, "Debug quirks for the driver");
61#endif
62
63static struct cnss_fw_files FW_FILES_QCA6174_FW_3_0 = {
64 "qwlan30.bin", "bdwlan30.bin", "otp30.bin", "utf30.bin",
65 "utfbd30.bin", "epping30.bin", "evicted30.bin"
66};
67
68static struct cnss_fw_files FW_FILES_DEFAULT = {
69 "qwlan.bin", "bdwlan.bin", "otp.bin", "utf.bin",
70 "utfbd.bin", "epping.bin", "evicted.bin"
71};
72
73struct cnss_driver_event {
74 struct list_head list;
75 enum cnss_driver_event_type type;
76 bool sync;
77 struct completion complete;
78 int ret;
79 void *data;
80};
81
Yue Ma0317e4a2018-01-10 11:48:32 -080082static void cnss_set_plat_priv(struct platform_device *plat_dev,
83 struct cnss_plat_data *plat_priv)
84{
85 plat_env = plat_priv;
86}
87
Yue Mae83a0eff2018-05-04 14:15:54 -070088struct cnss_plat_data *cnss_get_plat_priv(struct platform_device *plat_dev)
Yue Ma0317e4a2018-01-10 11:48:32 -080089{
90 return plat_env;
91}
92
Yue Ma0317e4a2018-01-10 11:48:32 -080093static int cnss_pm_notify(struct notifier_block *b,
94 unsigned long event, void *p)
95{
96 switch (event) {
97 case PM_SUSPEND_PREPARE:
98 down_write(&cnss_pm_sem);
99 break;
100 case PM_POST_SUSPEND:
101 up_write(&cnss_pm_sem);
102 break;
103 }
104
105 return NOTIFY_DONE;
106}
107
108static struct notifier_block cnss_pm_notifier = {
109 .notifier_call = cnss_pm_notify,
110};
111
112static void cnss_pm_stay_awake(struct cnss_plat_data *plat_priv)
113{
114 if (atomic_inc_return(&plat_priv->pm_count) != 1)
115 return;
116
117 cnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n",
118 plat_priv->driver_state,
119 atomic_read(&plat_priv->pm_count));
120 pm_stay_awake(&plat_priv->plat_dev->dev);
121}
122
123static void cnss_pm_relax(struct cnss_plat_data *plat_priv)
124{
125 int r = atomic_dec_return(&plat_priv->pm_count);
126
127 WARN_ON(r < 0);
128
129 if (r != 0)
130 return;
131
132 cnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n",
133 plat_priv->driver_state,
134 atomic_read(&plat_priv->pm_count));
135 pm_relax(&plat_priv->plat_dev->dev);
136}
137
138void cnss_lock_pm_sem(struct device *dev)
139{
140 down_read(&cnss_pm_sem);
141}
142EXPORT_SYMBOL(cnss_lock_pm_sem);
143
144void cnss_release_pm_sem(struct device *dev)
145{
146 up_read(&cnss_pm_sem);
147}
148EXPORT_SYMBOL(cnss_release_pm_sem);
149
150int cnss_get_fw_files_for_target(struct device *dev,
151 struct cnss_fw_files *pfw_files,
152 u32 target_type, u32 target_version)
153{
154 if (!pfw_files)
155 return -ENODEV;
156
157 switch (target_version) {
158 case QCA6174_REV3_VERSION:
159 case QCA6174_REV3_2_VERSION:
160 memcpy(pfw_files, &FW_FILES_QCA6174_FW_3_0, sizeof(*pfw_files));
161 break;
162 default:
163 memcpy(pfw_files, &FW_FILES_DEFAULT, sizeof(*pfw_files));
164 cnss_pr_err("Unknown target version, type: 0x%X, version: 0x%X",
165 target_type, target_version);
166 break;
167 }
168
169 return 0;
170}
171EXPORT_SYMBOL(cnss_get_fw_files_for_target);
172
173int cnss_request_bus_bandwidth(struct device *dev, int bandwidth)
174{
175 int ret = 0;
176 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
177 struct cnss_bus_bw_info *bus_bw_info;
178
179 if (!plat_priv)
180 return -ENODEV;
181
182 bus_bw_info = &plat_priv->bus_bw_info;
183 if (!bus_bw_info->bus_client)
184 return -EINVAL;
185
186 switch (bandwidth) {
187 case CNSS_BUS_WIDTH_NONE:
188 case CNSS_BUS_WIDTH_LOW:
189 case CNSS_BUS_WIDTH_MEDIUM:
190 case CNSS_BUS_WIDTH_HIGH:
191 ret = msm_bus_scale_client_update_request(
192 bus_bw_info->bus_client, bandwidth);
193 if (!ret)
194 bus_bw_info->current_bw_vote = bandwidth;
195 else
196 cnss_pr_err("Could not set bus bandwidth: %d, err = %d\n",
197 bandwidth, ret);
198 break;
199 default:
200 cnss_pr_err("Invalid bus bandwidth: %d", bandwidth);
201 ret = -EINVAL;
202 }
203
204 return ret;
205}
206EXPORT_SYMBOL(cnss_request_bus_bandwidth);
207
208int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap)
209{
210 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
211
212 if (!plat_priv)
213 return -ENODEV;
214
215 if (cap)
216 *cap = plat_priv->cap;
217
218 return 0;
219}
220EXPORT_SYMBOL(cnss_get_platform_cap);
221
Yue Ma0317e4a2018-01-10 11:48:32 -0800222void cnss_request_pm_qos(struct device *dev, u32 qos_val)
223{
224 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
225
226 if (!plat_priv)
227 return;
228
229 pm_qos_add_request(&plat_priv->qos_request, PM_QOS_CPU_DMA_LATENCY,
230 qos_val);
231}
232EXPORT_SYMBOL(cnss_request_pm_qos);
233
234void cnss_remove_pm_qos(struct device *dev)
235{
236 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
237
238 if (!plat_priv)
239 return;
240
241 pm_qos_remove_request(&plat_priv->qos_request);
242}
243EXPORT_SYMBOL(cnss_remove_pm_qos);
244
245int cnss_wlan_enable(struct device *dev,
246 struct cnss_wlan_enable_cfg *config,
247 enum cnss_driver_mode mode,
248 const char *host_version)
249{
250 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
Yue Ma0317e4a2018-01-10 11:48:32 -0800251 int ret = 0;
252
253 if (plat_priv->device_id == QCA6174_DEVICE_ID)
254 return 0;
255
256 if (qmi_bypass)
257 return 0;
258
259 if (!config || !host_version) {
260 cnss_pr_err("Invalid config or host_version pointer\n");
261 return -EINVAL;
262 }
263
264 cnss_pr_dbg("Mode: %d, config: %pK, host_version: %s\n",
265 mode, config, host_version);
266
267 if (mode == CNSS_WALTEST || mode == CNSS_CCPM)
268 goto skip_cfg;
269
Yue Mab79d4862018-07-11 12:32:12 -0700270 ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, config, host_version);
Yue Ma0317e4a2018-01-10 11:48:32 -0800271 if (ret)
272 goto out;
273
274skip_cfg:
275 ret = cnss_wlfw_wlan_mode_send_sync(plat_priv, mode);
276out:
277 return ret;
278}
279EXPORT_SYMBOL(cnss_wlan_enable);
280
281int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
282{
283 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
284
285 if (plat_priv->device_id == QCA6174_DEVICE_ID)
286 return 0;
287
288 if (qmi_bypass)
289 return 0;
290
Yue Mab79d4862018-07-11 12:32:12 -0700291 return cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
Yue Ma0317e4a2018-01-10 11:48:32 -0800292}
293EXPORT_SYMBOL(cnss_wlan_disable);
294
295#ifdef CONFIG_CNSS2_DEBUG
296int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
297 u32 data_len, u8 *output)
298{
299 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
300 int ret = 0;
301
302 if (!plat_priv) {
303 cnss_pr_err("plat_priv is NULL!\n");
304 return -EINVAL;
305 }
306
307 if (plat_priv->device_id == QCA6174_DEVICE_ID)
308 return 0;
309
Yue Ma0317e4a2018-01-10 11:48:32 -0800310 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
311 cnss_pr_err("Invalid state for athdiag read: 0x%lx\n",
312 plat_priv->driver_state);
313 ret = -EINVAL;
314 goto out;
315 }
316
317 ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, offset, mem_type,
318 data_len, output);
319
320out:
321 return ret;
322}
323EXPORT_SYMBOL(cnss_athdiag_read);
324
325int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
326 u32 data_len, u8 *input)
327{
328 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
329 int ret = 0;
330
331 if (!plat_priv) {
332 cnss_pr_err("plat_priv is NULL!\n");
333 return -EINVAL;
334 }
335
336 if (plat_priv->device_id == QCA6174_DEVICE_ID)
337 return 0;
338
Yue Ma0317e4a2018-01-10 11:48:32 -0800339 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
340 cnss_pr_err("Invalid state for athdiag write: 0x%lx\n",
341 plat_priv->driver_state);
342 ret = -EINVAL;
343 goto out;
344 }
345
346 ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, offset, mem_type,
347 data_len, input);
348
349out:
350 return ret;
351}
352EXPORT_SYMBOL(cnss_athdiag_write);
353#else
354int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
355 u32 data_len, u8 *output)
356{
357 return -EPERM;
358}
359EXPORT_SYMBOL(cnss_athdiag_read);
360
361int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
362 u32 data_len, u8 *input)
363{
364 return -EPERM;
365}
366EXPORT_SYMBOL(cnss_athdiag_write);
367#endif
368
369int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
370{
371 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
372
373 if (plat_priv->device_id == QCA6174_DEVICE_ID)
374 return 0;
375
376 return cnss_wlfw_ini_send_sync(plat_priv, fw_log_mode);
377}
378EXPORT_SYMBOL(cnss_set_fw_log_mode);
379
Yue Mae83a0eff2018-05-04 14:15:54 -0700380bool *cnss_get_qmi_bypass(void)
381{
382 return &qmi_bypass;
383}
384
385unsigned long *cnss_get_debug_quirks(void)
386{
387 return &quirks;
388}
389
Yue Ma0317e4a2018-01-10 11:48:32 -0800390static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
391{
392 int ret = 0;
393
394 if (!plat_priv)
395 return -ENODEV;
396
397 set_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
398
399 ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
400 if (ret)
401 goto out;
402
403 ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
404 if (ret)
405 goto out;
406
Yue Mafcf60422018-05-01 16:59:56 -0700407 ret = cnss_bus_load_m3(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800408 if (ret)
409 goto out;
410
411 ret = cnss_wlfw_m3_dnld_send_sync(plat_priv);
412 if (ret)
413 goto out;
414
415 return 0;
416out:
417 return ret;
418}
419
Yue Ma0317e4a2018-01-10 11:48:32 -0800420static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
421{
422 int ret = 0;
423
424 if (!plat_priv)
425 return -ENODEV;
426
427 del_timer(&plat_priv->fw_boot_timer);
428 set_bit(CNSS_FW_READY, &plat_priv->driver_state);
Yue Ma6d0d8442018-10-24 12:41:41 -0700429 clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
Yue Ma0317e4a2018-01-10 11:48:32 -0800430
431 if (test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state)) {
432 clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
433 clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
434 }
435
436 if (enable_waltest) {
437 ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
Yue Mab79d4862018-07-11 12:32:12 -0700438 CNSS_WALTEST);
Yue Ma0317e4a2018-01-10 11:48:32 -0800439 } else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
440 ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
Yue Mab79d4862018-07-11 12:32:12 -0700441 CNSS_CALIBRATION);
Yue Ma0317e4a2018-01-10 11:48:32 -0800442 } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
443 test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
Yue Mae83a0eff2018-05-04 14:15:54 -0700444 ret = cnss_bus_call_driver_probe(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800445 } else {
446 complete(&plat_priv->power_up_complete);
447 }
448
Yue Ma8bead6d2018-02-01 12:25:47 -0800449 if (ret && test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
450 goto out;
451 else if (ret)
Yue Ma0317e4a2018-01-10 11:48:32 -0800452 goto shutdown;
453
454 return 0;
455
456shutdown:
Yue Mae83a0eff2018-05-04 14:15:54 -0700457 cnss_bus_dev_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800458
Yue Ma8bead6d2018-02-01 12:25:47 -0800459 clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
460 clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
461
462out:
Yue Ma0317e4a2018-01-10 11:48:32 -0800463 return ret;
464}
465
Rajasekaran Kalidossff080602018-06-06 09:05:41 +0530466static int cnss_cal_update_hdlr(struct cnss_plat_data *plat_priv)
467{
468 /* QCN7605 store the cal data sent by FW to calDB memory area
469 * get out of this after complete data is uploaded. FW is expected
470 * to send cal done
471 */
472 return 0;
473}
474
Yue Ma0317e4a2018-01-10 11:48:32 -0800475static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
476{
477 switch (type) {
478 case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
479 return "SERVER_ARRIVE";
480 case CNSS_DRIVER_EVENT_SERVER_EXIT:
481 return "SERVER_EXIT";
482 case CNSS_DRIVER_EVENT_REQUEST_MEM:
483 return "REQUEST_MEM";
484 case CNSS_DRIVER_EVENT_FW_MEM_READY:
485 return "FW_MEM_READY";
486 case CNSS_DRIVER_EVENT_FW_READY:
487 return "FW_READY";
488 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
489 return "COLD_BOOT_CAL_START";
490 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
491 return "COLD_BOOT_CAL_DONE";
Rajasekaran Kalidossff080602018-06-06 09:05:41 +0530492 case CNSS_DRIVER_EVENT_CAL_UPDATE:
493 return "COLD_BOOT_CAL_DATA_UPDATE";
494 case CNSS_DRIVER_EVENT_CAL_DOWNLOAD:
495 return "COLD_BOOT_CAL_DATA_DOWNLOAD";
Yue Ma0317e4a2018-01-10 11:48:32 -0800496 case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
497 return "REGISTER_DRIVER";
498 case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
499 return "UNREGISTER_DRIVER";
500 case CNSS_DRIVER_EVENT_RECOVERY:
501 return "RECOVERY";
502 case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
503 return "FORCE_FW_ASSERT";
504 case CNSS_DRIVER_EVENT_POWER_UP:
505 return "POWER_UP";
506 case CNSS_DRIVER_EVENT_POWER_DOWN:
507 return "POWER_DOWN";
508 case CNSS_DRIVER_EVENT_MAX:
509 return "EVENT_MAX";
510 }
511
512 return "UNKNOWN";
513};
514
515int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
516 enum cnss_driver_event_type type,
517 u32 flags, void *data)
518{
519 struct cnss_driver_event *event;
520 unsigned long irq_flags;
521 int gfp = GFP_KERNEL;
522 int ret = 0;
523
524 if (!plat_priv)
525 return -ENODEV;
526
527 cnss_pr_dbg("Posting event: %s(%d)%s, state: 0x%lx flags: 0x%0x\n",
528 cnss_driver_event_to_str(type), type,
529 flags ? "-sync" : "", plat_priv->driver_state, flags);
530
531 if (type >= CNSS_DRIVER_EVENT_MAX) {
532 cnss_pr_err("Invalid Event type: %d, can't post", type);
533 return -EINVAL;
534 }
535
536 if (in_interrupt() || irqs_disabled())
537 gfp = GFP_ATOMIC;
538
539 event = kzalloc(sizeof(*event), gfp);
540 if (!event)
541 return -ENOMEM;
542
543 cnss_pm_stay_awake(plat_priv);
544
545 event->type = type;
546 event->data = data;
547 init_completion(&event->complete);
548 event->ret = CNSS_EVENT_PENDING;
549 event->sync = !!(flags & CNSS_EVENT_SYNC);
550
551 spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
552 list_add_tail(&event->list, &plat_priv->event_list);
553 spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
554
555 queue_work(plat_priv->event_wq, &plat_priv->event_work);
556
557 if (!(flags & CNSS_EVENT_SYNC))
558 goto out;
559
560 if (flags & CNSS_EVENT_UNINTERRUPTIBLE)
561 wait_for_completion(&event->complete);
562 else
563 ret = wait_for_completion_interruptible(&event->complete);
564
565 cnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
566 cnss_driver_event_to_str(type), type,
567 plat_priv->driver_state, ret, event->ret);
568 spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
569 if (ret == -ERESTARTSYS && event->ret == CNSS_EVENT_PENDING) {
570 event->sync = false;
571 spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
572 ret = -EINTR;
573 goto out;
574 }
575 spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
576
577 ret = event->ret;
578 kfree(event);
579
580out:
581 cnss_pm_relax(plat_priv);
582 return ret;
583}
584
Yue Mab79d4862018-07-11 12:32:12 -0700585unsigned int cnss_get_boot_timeout(struct device *dev)
586{
587 return cnss_get_qmi_timeout();
588}
589EXPORT_SYMBOL(cnss_get_boot_timeout);
590
Yue Ma0317e4a2018-01-10 11:48:32 -0800591int cnss_power_up(struct device *dev)
592{
593 int ret = 0;
594 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
595 unsigned int timeout;
596
597 if (!plat_priv) {
598 cnss_pr_err("plat_priv is NULL\n");
599 return -ENODEV;
600 }
601
602 cnss_pr_dbg("Powering up device\n");
603
604 ret = cnss_driver_event_post(plat_priv,
605 CNSS_DRIVER_EVENT_POWER_UP,
606 CNSS_EVENT_SYNC, NULL);
607 if (ret)
608 goto out;
609
610 if (plat_priv->device_id == QCA6174_DEVICE_ID)
611 goto out;
612
Yue Mab79d4862018-07-11 12:32:12 -0700613 timeout = cnss_get_boot_timeout(dev);
Yue Ma0317e4a2018-01-10 11:48:32 -0800614
615 reinit_completion(&plat_priv->power_up_complete);
616 ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
617 msecs_to_jiffies(timeout) << 2);
618 if (!ret) {
619 cnss_pr_err("Timeout waiting for power up to complete\n");
620 ret = -EAGAIN;
621 goto out;
622 }
623
624 return 0;
625
626out:
627 return ret;
628}
629EXPORT_SYMBOL(cnss_power_up);
630
631int cnss_power_down(struct device *dev)
632{
633 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
634
635 if (!plat_priv) {
636 cnss_pr_err("plat_priv is NULL\n");
637 return -ENODEV;
638 }
639
640 cnss_pr_dbg("Powering down device\n");
641
642 return cnss_driver_event_post(plat_priv,
643 CNSS_DRIVER_EVENT_POWER_DOWN,
644 CNSS_EVENT_SYNC, NULL);
645}
646EXPORT_SYMBOL(cnss_power_down);
647
Yue Ma2ebdf5c2019-05-02 15:35:16 -0700648int cnss_idle_restart(struct device *dev)
649{
650 return 0;
651}
652EXPORT_SYMBOL(cnss_idle_restart);
653
654int cnss_idle_shutdown(struct device *dev)
655{
656 return 0;
657}
658EXPORT_SYMBOL(cnss_idle_shutdown);
659
Yue Ma0317e4a2018-01-10 11:48:32 -0800660static int cnss_get_resources(struct cnss_plat_data *plat_priv)
661{
662 int ret = 0;
663
664 ret = cnss_get_vreg(plat_priv);
665 if (ret) {
666 cnss_pr_err("Failed to get vreg, err = %d\n", ret);
667 goto out;
668 }
669
670 ret = cnss_get_pinctrl(plat_priv);
671 if (ret) {
672 cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
673 goto out;
674 }
675
676 return 0;
677out:
678 return ret;
679}
680
681static void cnss_put_resources(struct cnss_plat_data *plat_priv)
682{
683}
684
685static int cnss_modem_notifier_nb(struct notifier_block *nb,
686 unsigned long code,
687 void *ss_handle)
688{
689 struct cnss_plat_data *plat_priv =
690 container_of(nb, struct cnss_plat_data, modem_nb);
Yue Ma0317e4a2018-01-10 11:48:32 -0800691 struct cnss_esoc_info *esoc_info;
Yue Ma0317e4a2018-01-10 11:48:32 -0800692
693 cnss_pr_dbg("Modem notifier: event %lu\n", code);
694
Yue Mae83a0eff2018-05-04 14:15:54 -0700695 if (!plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -0800696 return NOTIFY_DONE;
697
698 esoc_info = &plat_priv->esoc_info;
699
700 if (code == SUBSYS_AFTER_POWERUP)
701 esoc_info->modem_current_status = 1;
702 else if (code == SUBSYS_BEFORE_SHUTDOWN)
703 esoc_info->modem_current_status = 0;
704 else
705 return NOTIFY_DONE;
706
Yue Mae83a0eff2018-05-04 14:15:54 -0700707 if (!cnss_bus_call_driver_modem_status(plat_priv,
708 esoc_info->modem_current_status))
Yue Ma0317e4a2018-01-10 11:48:32 -0800709 return NOTIFY_DONE;
710
Yue Ma0317e4a2018-01-10 11:48:32 -0800711 return NOTIFY_OK;
712}
713
714static int cnss_register_esoc(struct cnss_plat_data *plat_priv)
715{
716 int ret = 0;
717 struct device *dev;
718 struct cnss_esoc_info *esoc_info;
719 struct esoc_desc *esoc_desc;
720 const char *client_desc;
721
722 dev = &plat_priv->plat_dev->dev;
723 esoc_info = &plat_priv->esoc_info;
724
725 esoc_info->notify_modem_status =
726 of_property_read_bool(dev->of_node,
727 "qcom,notify-modem-status");
728
Yue Ma3eb55622018-02-22 12:14:00 -0800729 if (!esoc_info->notify_modem_status)
Yue Ma0317e4a2018-01-10 11:48:32 -0800730 goto out;
731
732 ret = of_property_read_string_index(dev->of_node, "esoc-names", 0,
733 &client_desc);
734 if (ret) {
735 cnss_pr_dbg("esoc-names is not defined in DT, skip!\n");
736 } else {
737 esoc_desc = devm_register_esoc_client(dev, client_desc);
738 if (IS_ERR_OR_NULL(esoc_desc)) {
739 ret = PTR_RET(esoc_desc);
740 cnss_pr_err("Failed to register esoc_desc, err = %d\n",
741 ret);
742 goto out;
743 }
744 esoc_info->esoc_desc = esoc_desc;
745 }
746
747 plat_priv->modem_nb.notifier_call = cnss_modem_notifier_nb;
748 esoc_info->modem_current_status = 0;
749 esoc_info->modem_notify_handler =
750 subsys_notif_register_notifier(esoc_info->esoc_desc ?
751 esoc_info->esoc_desc->name :
752 "modem", &plat_priv->modem_nb);
753 if (IS_ERR(esoc_info->modem_notify_handler)) {
754 ret = PTR_ERR(esoc_info->modem_notify_handler);
755 cnss_pr_err("Failed to register esoc notifier, err = %d\n",
756 ret);
757 goto unreg_esoc;
758 }
759
760 return 0;
761unreg_esoc:
762 if (esoc_info->esoc_desc)
763 devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
764out:
765 return ret;
766}
767
768static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
769{
770 struct device *dev;
771 struct cnss_esoc_info *esoc_info;
772
773 dev = &plat_priv->plat_dev->dev;
774 esoc_info = &plat_priv->esoc_info;
775
776 if (esoc_info->notify_modem_status)
777 subsys_notif_unregister_notifier(esoc_info->
778 modem_notify_handler,
779 &plat_priv->modem_nb);
780 if (esoc_info->esoc_desc)
781 devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
782}
783
Yue Ma0317e4a2018-01-10 11:48:32 -0800784static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
785{
786 struct cnss_plat_data *plat_priv;
787
788 if (!subsys_desc->dev) {
789 cnss_pr_err("dev from subsys_desc is NULL\n");
790 return -ENODEV;
791 }
792
793 plat_priv = dev_get_drvdata(subsys_desc->dev);
794 if (!plat_priv) {
795 cnss_pr_err("plat_priv is NULL\n");
796 return -ENODEV;
797 }
798
799 if (!plat_priv->driver_state) {
800 cnss_pr_dbg("Powerup is ignored\n");
801 return 0;
802 }
803
Yue Mae83a0eff2018-05-04 14:15:54 -0700804 return cnss_bus_dev_powerup(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800805}
806
807static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
808 bool force_stop)
809{
810 struct cnss_plat_data *plat_priv;
811
812 if (!subsys_desc->dev) {
813 cnss_pr_err("dev from subsys_desc is NULL\n");
814 return -ENODEV;
815 }
816
817 plat_priv = dev_get_drvdata(subsys_desc->dev);
818 if (!plat_priv) {
819 cnss_pr_err("plat_priv is NULL\n");
820 return -ENODEV;
821 }
822
823 if (!plat_priv->driver_state) {
824 cnss_pr_dbg("shutdown is ignored\n");
825 return 0;
826 }
827
Yue Mae83a0eff2018-05-04 14:15:54 -0700828 return cnss_bus_dev_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800829}
830
Yue Ma0317e4a2018-01-10 11:48:32 -0800831void cnss_device_crashed(struct device *dev)
832{
833 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
834 struct cnss_subsys_info *subsys_info;
835
836 if (!plat_priv)
837 return;
838
839 subsys_info = &plat_priv->subsys_info;
840 if (subsys_info->subsys_device) {
841 set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
842 subsys_set_crash_status(subsys_info->subsys_device, true);
843 subsystem_restart_dev(subsys_info->subsys_device);
844 }
845}
846EXPORT_SYMBOL(cnss_device_crashed);
847
848static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
849{
850 struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
851
852 if (!plat_priv) {
Yue Mae83a0eff2018-05-04 14:15:54 -0700853 cnss_pr_err("plat_priv is NULL\n");
Yue Ma0317e4a2018-01-10 11:48:32 -0800854 return;
855 }
856
Yue Mae83a0eff2018-05-04 14:15:54 -0700857 cnss_bus_dev_crash_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800858}
859
Yue Mae83a0eff2018-05-04 14:15:54 -0700860static int cnss_subsys_ramdump(int enable,
861 const struct subsys_desc *subsys_desc)
862{
863 struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
864
865 if (!plat_priv) {
866 cnss_pr_err("plat_priv is NULL\n");
867 return -ENODEV;
868 }
869
870 if (!enable)
871 return 0;
872
873 return cnss_bus_dev_ramdump(plat_priv);
874}
875
876void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
877{
878 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
879 struct cnss_ramdump_info *ramdump_info;
880
881 if (!plat_priv)
882 return NULL;
883
884 ramdump_info = &plat_priv->ramdump_info;
885 *size = ramdump_info->ramdump_size;
886
887 return ramdump_info->ramdump_va;
888}
889EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
890
Yue Ma0317e4a2018-01-10 11:48:32 -0800891static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
892{
893 switch (reason) {
894 case CNSS_REASON_DEFAULT:
895 return "DEFAULT";
896 case CNSS_REASON_LINK_DOWN:
897 return "LINK_DOWN";
898 case CNSS_REASON_RDDM:
899 return "RDDM";
900 case CNSS_REASON_TIMEOUT:
901 return "TIMEOUT";
902 }
903
904 return "UNKNOWN";
905};
906
907static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
908 enum cnss_recovery_reason reason)
909{
Yue Ma0317e4a2018-01-10 11:48:32 -0800910 struct cnss_subsys_info *subsys_info =
911 &plat_priv->subsys_info;
Yue Ma0317e4a2018-01-10 11:48:32 -0800912
913 plat_priv->recovery_count++;
914
915 if (plat_priv->device_id == QCA6174_DEVICE_ID)
916 goto self_recovery;
917
Yue Ma0317e4a2018-01-10 11:48:32 -0800918 if (test_bit(SKIP_RECOVERY, &quirks)) {
919 cnss_pr_dbg("Skip device recovery\n");
920 return 0;
921 }
922
923 switch (reason) {
924 case CNSS_REASON_LINK_DOWN:
925 if (test_bit(LINK_DOWN_SELF_RECOVERY, &quirks))
926 goto self_recovery;
927 break;
928 case CNSS_REASON_RDDM:
Yue Mafcf60422018-05-01 16:59:56 -0700929 cnss_bus_collect_dump_info(plat_priv, false);
Yue Ma0317e4a2018-01-10 11:48:32 -0800930 break;
931 case CNSS_REASON_DEFAULT:
932 case CNSS_REASON_TIMEOUT:
933 break;
934 default:
935 cnss_pr_err("Unsupported recovery reason: %s(%d)\n",
936 cnss_recovery_reason_to_str(reason), reason);
937 break;
938 }
939
940 if (!subsys_info->subsys_device)
941 return 0;
942
943 subsys_set_crash_status(subsys_info->subsys_device, true);
944 subsystem_restart_dev(subsys_info->subsys_device);
945
946 return 0;
947
948self_recovery:
Yue Mae83a0eff2018-05-04 14:15:54 -0700949 cnss_bus_dev_shutdown(plat_priv);
950 cnss_bus_dev_powerup(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800951
952 return 0;
953}
954
955static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv,
956 void *data)
957{
958 struct cnss_recovery_data *recovery_data = data;
959 int ret = 0;
960
961 cnss_pr_dbg("Driver recovery is triggered with reason: %s(%d)\n",
962 cnss_recovery_reason_to_str(recovery_data->reason),
963 recovery_data->reason);
964
965 if (!plat_priv->driver_state) {
966 cnss_pr_err("Improper driver state, ignore recovery\n");
967 ret = -EINVAL;
968 goto out;
969 }
970
971 if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
972 cnss_pr_err("Recovery is already in progress\n");
973 ret = -EINVAL;
974 goto out;
975 }
976
977 if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
978 cnss_pr_err("Driver unload is in progress, ignore recovery\n");
979 ret = -EINVAL;
980 goto out;
981 }
982
983 switch (plat_priv->device_id) {
984 case QCA6174_DEVICE_ID:
985 if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
986 cnss_pr_err("Driver load is in progress, ignore recovery\n");
987 ret = -EINVAL;
988 goto out;
989 }
990 break;
991 default:
992 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
993 set_bit(CNSS_FW_BOOT_RECOVERY,
994 &plat_priv->driver_state);
Yue Ma0317e4a2018-01-10 11:48:32 -0800995 }
996 break;
997 }
998
999 set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
1000 ret = cnss_do_recovery(plat_priv, recovery_data->reason);
1001
1002out:
1003 kfree(data);
1004 return ret;
1005}
1006
1007int cnss_self_recovery(struct device *dev,
1008 enum cnss_recovery_reason reason)
1009{
1010 cnss_schedule_recovery(dev, reason);
1011 return 0;
1012}
1013EXPORT_SYMBOL(cnss_self_recovery);
1014
1015void cnss_schedule_recovery(struct device *dev,
1016 enum cnss_recovery_reason reason)
1017{
1018 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
1019 struct cnss_recovery_data *data;
1020 int gfp = GFP_KERNEL;
1021
Yue Ma7de72832018-10-30 16:04:25 -07001022 cnss_bus_update_status(plat_priv, CNSS_FW_DOWN);
1023
Yue Ma0317e4a2018-01-10 11:48:32 -08001024 if (in_interrupt() || irqs_disabled())
1025 gfp = GFP_ATOMIC;
1026
1027 data = kzalloc(sizeof(*data), gfp);
1028 if (!data)
1029 return;
1030
1031 data->reason = reason;
1032 cnss_driver_event_post(plat_priv,
1033 CNSS_DRIVER_EVENT_RECOVERY,
1034 0, data);
1035}
1036EXPORT_SYMBOL(cnss_schedule_recovery);
1037
Yue Ma0317e4a2018-01-10 11:48:32 -08001038int cnss_force_fw_assert(struct device *dev)
1039{
1040 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
1041
1042 if (!plat_priv) {
1043 cnss_pr_err("plat_priv is NULL\n");
1044 return -ENODEV;
1045 }
1046
1047 if (plat_priv->device_id == QCA6174_DEVICE_ID) {
1048 cnss_pr_info("Forced FW assert is not supported\n");
1049 return -EOPNOTSUPP;
1050 }
1051
1052 if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
1053 cnss_pr_info("Recovery is already in progress, ignore forced FW assert\n");
1054 return 0;
1055 }
1056
1057 cnss_driver_event_post(plat_priv,
1058 CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
1059 0, NULL);
1060
1061 return 0;
1062}
1063EXPORT_SYMBOL(cnss_force_fw_assert);
1064
Yuanyuan Liu22184182018-12-03 15:29:44 -08001065int cnss_force_collect_rddm(struct device *dev)
1066{
1067 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
1068 int ret = 0;
1069
1070 if (!plat_priv) {
1071 cnss_pr_err("plat_priv is NULL\n");
1072 return -ENODEV;
1073 }
1074
1075 if (plat_priv->device_id == QCA6174_DEVICE_ID) {
1076 cnss_pr_info("Force collect rddm is not supported\n");
1077 return -EOPNOTSUPP;
1078 }
1079
1080 if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
1081 cnss_pr_info("Recovery is already in progress, ignore forced collect rddm\n");
1082 return 0;
1083 }
1084
1085 cnss_driver_event_post(plat_priv,
1086 CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
1087 0, NULL);
1088
1089 reinit_completion(&plat_priv->rddm_complete);
1090 ret = wait_for_completion_timeout
1091 (&plat_priv->rddm_complete,
1092 msecs_to_jiffies(CNSS_RDDM_TIMEOUT_MS));
1093 if (!ret)
1094 ret = -ETIMEDOUT;
1095
1096 return ret;
1097}
1098EXPORT_SYMBOL(cnss_force_collect_rddm);
1099
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301100static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv)
1101{
1102 int ret;
1103
1104 ret = cnss_wlfw_server_arrive(plat_priv);
1105 if (ret)
1106 goto out;
1107
1108 if (!cnss_bus_req_mem_ind_valid(plat_priv)) {
1109 ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
1110 if (ret)
1111 goto out;
1112
1113 ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
1114 if (ret)
1115 goto out;
1116 /*cnss driver sends meta data report and waits for FW_READY*/
1117 if (cnss_bus_dev_cal_rep_valid(plat_priv))
1118 ret = cnss_wlfw_cal_report_send_sync(plat_priv);
1119 }
1120out:
1121 return ret;
1122}
1123
Yue Ma0317e4a2018-01-10 11:48:32 -08001124static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
1125{
1126 int ret = 0;
1127
Yue Ma41e978d2018-10-17 15:50:21 -07001128 if (test_bit(CNSS_FW_READY, &plat_priv->driver_state) ||
1129 test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
1130 test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
1131 cnss_pr_dbg("Device is already active, ignore calibration\n");
1132 goto out;
1133 }
Yue Ma0317e4a2018-01-10 11:48:32 -08001134
Yue Ma41e978d2018-10-17 15:50:21 -07001135 set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
1136 reinit_completion(&plat_priv->cal_complete);
1137 ret = cnss_bus_dev_powerup(plat_priv);
1138 if (ret) {
1139 complete(&plat_priv->cal_complete);
1140 clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
1141 }
1142
1143out:
Yue Ma0317e4a2018-01-10 11:48:32 -08001144 return ret;
1145}
1146
1147static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
1148{
Yue Ma41e978d2018-10-17 15:50:21 -07001149 if (!test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state))
1150 return 0;
1151
Yue Maa3e15032018-02-15 15:56:12 -08001152 plat_priv->cal_done = true;
Yue Mab79d4862018-07-11 12:32:12 -07001153 cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
Yue Mae83a0eff2018-05-04 14:15:54 -07001154 cnss_bus_dev_shutdown(plat_priv);
Yue Ma41e978d2018-10-17 15:50:21 -07001155 complete(&plat_priv->cal_complete);
Yue Ma0317e4a2018-01-10 11:48:32 -08001156 clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
1157
1158 return 0;
1159}
1160
1161static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
1162{
Yue Mae83a0eff2018-05-04 14:15:54 -07001163 return cnss_bus_dev_powerup(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001164}
1165
1166static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
1167{
Yue Mae83a0eff2018-05-04 14:15:54 -07001168 cnss_bus_dev_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001169
1170 return 0;
1171}
1172
1173static void cnss_driver_event_work(struct work_struct *work)
1174{
1175 struct cnss_plat_data *plat_priv =
1176 container_of(work, struct cnss_plat_data, event_work);
1177 struct cnss_driver_event *event;
1178 unsigned long flags;
1179 int ret = 0;
1180
1181 if (!plat_priv) {
1182 cnss_pr_err("plat_priv is NULL!\n");
1183 return;
1184 }
1185
1186 cnss_pm_stay_awake(plat_priv);
1187
1188 spin_lock_irqsave(&plat_priv->event_lock, flags);
1189
1190 while (!list_empty(&plat_priv->event_list)) {
1191 event = list_first_entry(&plat_priv->event_list,
1192 struct cnss_driver_event, list);
1193 list_del(&event->list);
1194 spin_unlock_irqrestore(&plat_priv->event_lock, flags);
1195
1196 cnss_pr_dbg("Processing driver event: %s%s(%d), state: 0x%lx\n",
1197 cnss_driver_event_to_str(event->type),
1198 event->sync ? "-sync" : "", event->type,
1199 plat_priv->driver_state);
1200
1201 switch (event->type) {
1202 case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301203 ret = cnss_wlfw_server_arrive_hdlr(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001204 break;
1205 case CNSS_DRIVER_EVENT_SERVER_EXIT:
1206 ret = cnss_wlfw_server_exit(plat_priv);
1207 break;
1208 case CNSS_DRIVER_EVENT_REQUEST_MEM:
Yue Mafcf60422018-05-01 16:59:56 -07001209 ret = cnss_bus_alloc_fw_mem(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001210 if (ret)
1211 break;
1212 ret = cnss_wlfw_respond_mem_send_sync(plat_priv);
1213 break;
1214 case CNSS_DRIVER_EVENT_FW_MEM_READY:
1215 ret = cnss_fw_mem_ready_hdlr(plat_priv);
1216 break;
1217 case CNSS_DRIVER_EVENT_FW_READY:
1218 ret = cnss_fw_ready_hdlr(plat_priv);
1219 break;
1220 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
1221 ret = cnss_cold_boot_cal_start_hdlr(plat_priv);
1222 break;
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301223 case CNSS_DRIVER_EVENT_CAL_UPDATE:
1224 ret = cnss_cal_update_hdlr(plat_priv);
1225 break;
Yue Ma0317e4a2018-01-10 11:48:32 -08001226 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
1227 ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
1228 break;
1229 case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
Yue Mae83a0eff2018-05-04 14:15:54 -07001230 ret = cnss_bus_register_driver_hdlr(plat_priv,
1231 event->data);
Yue Ma0317e4a2018-01-10 11:48:32 -08001232 break;
1233 case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
Yue Mae83a0eff2018-05-04 14:15:54 -07001234 ret = cnss_bus_unregister_driver_hdlr(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001235 break;
1236 case CNSS_DRIVER_EVENT_RECOVERY:
1237 ret = cnss_driver_recovery_hdlr(plat_priv,
1238 event->data);
1239 break;
1240 case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
Yue Mafcf60422018-05-01 16:59:56 -07001241 ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001242 break;
1243 case CNSS_DRIVER_EVENT_POWER_UP:
1244 ret = cnss_power_up_hdlr(plat_priv);
1245 break;
1246 case CNSS_DRIVER_EVENT_POWER_DOWN:
1247 ret = cnss_power_down_hdlr(plat_priv);
1248 break;
1249 default:
1250 cnss_pr_err("Invalid driver event type: %d",
1251 event->type);
1252 kfree(event);
1253 spin_lock_irqsave(&plat_priv->event_lock, flags);
1254 continue;
1255 }
1256
1257 spin_lock_irqsave(&plat_priv->event_lock, flags);
1258 if (event->sync) {
1259 event->ret = ret;
1260 complete(&event->complete);
1261 continue;
1262 }
1263 spin_unlock_irqrestore(&plat_priv->event_lock, flags);
1264
1265 kfree(event);
1266
1267 spin_lock_irqsave(&plat_priv->event_lock, flags);
1268 }
1269 spin_unlock_irqrestore(&plat_priv->event_lock, flags);
1270
1271 cnss_pm_relax(plat_priv);
1272}
1273
1274int cnss_register_subsys(struct cnss_plat_data *plat_priv)
1275{
1276 int ret = 0;
1277 struct cnss_subsys_info *subsys_info;
1278
1279 subsys_info = &plat_priv->subsys_info;
1280
Yue Ma922b0352018-04-19 14:03:29 -07001281 subsys_info->subsys_desc.name = "wlan";
Yue Ma0317e4a2018-01-10 11:48:32 -08001282 subsys_info->subsys_desc.owner = THIS_MODULE;
1283 subsys_info->subsys_desc.powerup = cnss_subsys_powerup;
1284 subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown;
1285 subsys_info->subsys_desc.ramdump = cnss_subsys_ramdump;
1286 subsys_info->subsys_desc.crash_shutdown = cnss_subsys_crash_shutdown;
1287 subsys_info->subsys_desc.dev = &plat_priv->plat_dev->dev;
1288
1289 subsys_info->subsys_device = subsys_register(&subsys_info->subsys_desc);
1290 if (IS_ERR(subsys_info->subsys_device)) {
1291 ret = PTR_ERR(subsys_info->subsys_device);
1292 cnss_pr_err("Failed to register subsys, err = %d\n", ret);
1293 goto out;
1294 }
1295
1296 subsys_info->subsys_handle =
1297 subsystem_get(subsys_info->subsys_desc.name);
1298 if (!subsys_info->subsys_handle) {
1299 cnss_pr_err("Failed to get subsys_handle!\n");
1300 ret = -EINVAL;
1301 goto unregister_subsys;
1302 } else if (IS_ERR(subsys_info->subsys_handle)) {
1303 ret = PTR_ERR(subsys_info->subsys_handle);
1304 cnss_pr_err("Failed to do subsystem_get, err = %d\n", ret);
1305 goto unregister_subsys;
1306 }
1307
1308 return 0;
1309
1310unregister_subsys:
1311 subsys_unregister(subsys_info->subsys_device);
1312out:
1313 return ret;
1314}
1315
1316void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
1317{
1318 struct cnss_subsys_info *subsys_info;
1319
1320 subsys_info = &plat_priv->subsys_info;
1321 subsystem_put(subsys_info->subsys_handle);
1322 subsys_unregister(subsys_info->subsys_device);
1323}
1324
1325static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv)
1326{
1327 struct cnss_ramdump_info *ramdump_info;
1328 struct msm_dump_entry dump_entry;
1329
1330 ramdump_info = &plat_priv->ramdump_info;
1331 ramdump_info->dump_data.addr = ramdump_info->ramdump_pa;
1332 ramdump_info->dump_data.len = ramdump_info->ramdump_size;
1333 ramdump_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
1334 ramdump_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
1335 strlcpy(ramdump_info->dump_data.name, CNSS_DUMP_NAME,
1336 sizeof(ramdump_info->dump_data.name));
1337 dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
1338 dump_entry.addr = virt_to_phys(&ramdump_info->dump_data);
1339
1340 return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
1341}
1342
Yue Ma2ad23282018-06-13 18:38:50 -07001343static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001344{
1345 int ret = 0;
1346 struct device *dev;
1347 struct cnss_subsys_info *subsys_info;
1348 struct cnss_ramdump_info *ramdump_info;
1349 u32 ramdump_size = 0;
1350
1351 dev = &plat_priv->plat_dev->dev;
1352 subsys_info = &plat_priv->subsys_info;
1353 ramdump_info = &plat_priv->ramdump_info;
1354
1355 if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
1356 &ramdump_size) == 0) {
1357 ramdump_info->ramdump_va = dma_alloc_coherent(dev, ramdump_size,
1358 &ramdump_info->ramdump_pa, GFP_KERNEL);
1359
1360 if (ramdump_info->ramdump_va)
1361 ramdump_info->ramdump_size = ramdump_size;
1362 }
1363
1364 cnss_pr_dbg("ramdump va: %pK, pa: %pa\n",
1365 ramdump_info->ramdump_va, &ramdump_info->ramdump_pa);
1366
1367 if (ramdump_info->ramdump_size == 0) {
1368 cnss_pr_info("Ramdump will not be collected");
1369 goto out;
1370 }
1371
1372 ret = cnss_init_dump_entry(plat_priv);
1373 if (ret) {
1374 cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
1375 goto free_ramdump;
1376 }
1377
1378 ramdump_info->ramdump_dev = create_ramdump_device(
1379 subsys_info->subsys_desc.name, subsys_info->subsys_desc.dev);
1380 if (!ramdump_info->ramdump_dev) {
1381 cnss_pr_err("Failed to create ramdump device!");
1382 ret = -ENOMEM;
1383 goto free_ramdump;
1384 }
1385
1386 return 0;
1387free_ramdump:
1388 dma_free_coherent(dev, ramdump_info->ramdump_size,
1389 ramdump_info->ramdump_va, ramdump_info->ramdump_pa);
1390out:
1391 return ret;
1392}
1393
Yue Ma2ad23282018-06-13 18:38:50 -07001394static void cnss_unregister_ramdump_v1(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001395{
1396 struct device *dev;
1397 struct cnss_ramdump_info *ramdump_info;
1398
1399 dev = &plat_priv->plat_dev->dev;
1400 ramdump_info = &plat_priv->ramdump_info;
1401
1402 if (ramdump_info->ramdump_dev)
1403 destroy_ramdump_device(ramdump_info->ramdump_dev);
1404
1405 if (ramdump_info->ramdump_va)
1406 dma_free_coherent(dev, ramdump_info->ramdump_size,
1407 ramdump_info->ramdump_va,
1408 ramdump_info->ramdump_pa);
1409}
1410
Yue Ma2ad23282018-06-13 18:38:50 -07001411static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001412{
1413 int ret = 0;
1414 struct cnss_subsys_info *subsys_info;
1415 struct cnss_ramdump_info_v2 *info_v2;
1416 struct cnss_dump_data *dump_data;
1417 struct msm_dump_entry dump_entry;
1418 struct device *dev = &plat_priv->plat_dev->dev;
1419 u32 ramdump_size = 0;
1420
1421 subsys_info = &plat_priv->subsys_info;
1422 info_v2 = &plat_priv->ramdump_info_v2;
1423 dump_data = &info_v2->dump_data;
1424
1425 if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
1426 &ramdump_size) == 0)
1427 info_v2->ramdump_size = ramdump_size;
1428
1429 cnss_pr_dbg("Ramdump size 0x%lx\n", info_v2->ramdump_size);
1430
1431 info_v2->dump_data_vaddr = kzalloc(CNSS_DUMP_DESC_SIZE, GFP_KERNEL);
1432 if (!info_v2->dump_data_vaddr)
1433 return -ENOMEM;
1434
1435 dump_data->paddr = virt_to_phys(info_v2->dump_data_vaddr);
1436 dump_data->version = CNSS_DUMP_FORMAT_VER_V2;
1437 dump_data->magic = CNSS_DUMP_MAGIC_VER_V2;
1438 dump_data->seg_version = CNSS_DUMP_SEG_VER;
1439 strlcpy(dump_data->name, CNSS_DUMP_NAME,
1440 sizeof(dump_data->name));
1441 dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
1442 dump_entry.addr = virt_to_phys(dump_data);
1443
1444 ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
1445 if (ret) {
1446 cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
1447 goto free_ramdump;
1448 }
1449
1450 info_v2->ramdump_dev =
1451 create_ramdump_device(subsys_info->subsys_desc.name,
1452 subsys_info->subsys_desc.dev);
1453 if (!info_v2->ramdump_dev) {
1454 cnss_pr_err("Failed to create ramdump device!\n");
1455 ret = -ENOMEM;
1456 goto free_ramdump;
1457 }
1458
1459 return 0;
1460
1461free_ramdump:
1462 kfree(info_v2->dump_data_vaddr);
1463 info_v2->dump_data_vaddr = NULL;
1464 return ret;
1465}
1466
Yue Ma2ad23282018-06-13 18:38:50 -07001467static void cnss_unregister_ramdump_v2(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001468{
1469 struct cnss_ramdump_info_v2 *info_v2;
1470
1471 info_v2 = &plat_priv->ramdump_info_v2;
1472
1473 if (info_v2->ramdump_dev)
1474 destroy_ramdump_device(info_v2->ramdump_dev);
1475
1476 kfree(info_v2->dump_data_vaddr);
1477 info_v2->dump_data_vaddr = NULL;
1478 info_v2->dump_data_valid = false;
1479}
1480
1481int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
1482{
1483 int ret = 0;
1484
1485 switch (plat_priv->device_id) {
1486 case QCA6174_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001487 ret = cnss_register_ramdump_v1(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001488 break;
1489 case QCA6290_EMULATION_DEVICE_ID:
1490 case QCA6290_DEVICE_ID:
Yue Mab74e6f32018-06-13 18:39:58 -07001491 case QCA6390_EMULATION_DEVICE_ID:
1492 case QCA6390_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001493 ret = cnss_register_ramdump_v2(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001494 break;
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301495 case QCN7605_COMPOSITE_DEVICE_ID:
1496 case QCN7605_STANDALONE_DEVICE_ID:
1497 break;
1498
Yue Ma0317e4a2018-01-10 11:48:32 -08001499 default:
1500 cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
1501 ret = -ENODEV;
1502 break;
1503 }
1504 return ret;
1505}
1506
1507void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
1508{
1509 switch (plat_priv->device_id) {
1510 case QCA6174_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001511 cnss_unregister_ramdump_v1(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001512 break;
1513 case QCA6290_EMULATION_DEVICE_ID:
1514 case QCA6290_DEVICE_ID:
Yue Mab74e6f32018-06-13 18:39:58 -07001515 case QCA6390_EMULATION_DEVICE_ID:
1516 case QCA6390_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001517 cnss_unregister_ramdump_v2(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001518 break;
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301519 case QCN7605_COMPOSITE_DEVICE_ID:
1520 case QCN7605_STANDALONE_DEVICE_ID:
1521 break;
Yue Ma0317e4a2018-01-10 11:48:32 -08001522 default:
1523 cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
1524 break;
1525 }
1526}
1527
1528static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
1529{
1530 int ret = 0;
1531 struct cnss_bus_bw_info *bus_bw_info;
1532
1533 bus_bw_info = &plat_priv->bus_bw_info;
1534
1535 bus_bw_info->bus_scale_table =
1536 msm_bus_cl_get_pdata(plat_priv->plat_dev);
1537 if (bus_bw_info->bus_scale_table) {
1538 bus_bw_info->bus_client =
1539 msm_bus_scale_register_client(
1540 bus_bw_info->bus_scale_table);
1541 if (!bus_bw_info->bus_client) {
1542 cnss_pr_err("Failed to register bus scale client!\n");
1543 ret = -EINVAL;
1544 goto out;
1545 }
1546 }
1547
1548 return 0;
1549out:
1550 return ret;
1551}
1552
1553static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv)
1554{
1555 struct cnss_bus_bw_info *bus_bw_info;
1556
1557 bus_bw_info = &plat_priv->bus_bw_info;
1558
1559 if (bus_bw_info->bus_client)
1560 msm_bus_scale_unregister_client(bus_bw_info->bus_client);
1561}
1562
1563static ssize_t cnss_fs_ready_store(struct device *dev,
1564 struct device_attribute *attr,
1565 const char *buf,
1566 size_t count)
1567{
1568 int fs_ready = 0;
1569 struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
1570
1571 if (sscanf(buf, "%du", &fs_ready) != 1)
1572 return -EINVAL;
1573
1574 cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n",
1575 fs_ready, count);
1576
1577 if (qmi_bypass) {
1578 cnss_pr_dbg("QMI is bypassed.\n");
1579 return count;
1580 }
1581
1582 if (!plat_priv) {
1583 cnss_pr_err("plat_priv is NULL!\n");
1584 return count;
1585 }
1586
1587 switch (plat_priv->device_id) {
1588 case QCA6290_EMULATION_DEVICE_ID:
1589 case QCA6290_DEVICE_ID:
Yue Mab74e6f32018-06-13 18:39:58 -07001590 case QCA6390_EMULATION_DEVICE_ID:
1591 case QCA6390_DEVICE_ID:
Yue Ma0317e4a2018-01-10 11:48:32 -08001592 break;
1593 default:
1594 cnss_pr_err("Not supported for device ID 0x%lx\n",
1595 plat_priv->device_id);
1596 return count;
1597 }
1598
1599 if (fs_ready == FILE_SYSTEM_READY) {
1600 cnss_driver_event_post(plat_priv,
1601 CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
1602 CNSS_EVENT_SYNC, NULL);
1603 }
1604
1605 return count;
1606}
1607
1608static DEVICE_ATTR(fs_ready, 0220, NULL, cnss_fs_ready_store);
1609
1610static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)
1611{
1612 int ret = 0;
1613
1614 ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
1615 if (ret) {
1616 cnss_pr_err("Failed to create device file, err = %d\n", ret);
1617 goto out;
1618 }
1619
1620 return 0;
1621out:
1622 return ret;
1623}
1624
1625static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv)
1626{
1627 device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
1628}
1629
1630static int cnss_event_work_init(struct cnss_plat_data *plat_priv)
1631{
1632 spin_lock_init(&plat_priv->event_lock);
1633 plat_priv->event_wq = alloc_workqueue("cnss_driver_event",
1634 WQ_UNBOUND, 1);
1635 if (!plat_priv->event_wq) {
1636 cnss_pr_err("Failed to create event workqueue!\n");
1637 return -EFAULT;
1638 }
1639
1640 INIT_WORK(&plat_priv->event_work, cnss_driver_event_work);
1641 INIT_LIST_HEAD(&plat_priv->event_list);
1642
1643 return 0;
1644}
1645
1646static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv)
1647{
1648 destroy_workqueue(plat_priv->event_wq);
1649}
1650
Yue Mab0747ec2018-10-18 11:50:45 -07001651static int cnss_misc_init(struct cnss_plat_data *plat_priv)
1652{
1653 int ret;
1654
1655 setup_timer(&plat_priv->fw_boot_timer, cnss_bus_fw_boot_timeout_hdlr,
1656 (unsigned long)plat_priv);
1657
1658 register_pm_notifier(&cnss_pm_notifier);
1659
1660 ret = device_init_wakeup(&plat_priv->plat_dev->dev, true);
1661 if (ret)
1662 cnss_pr_err("Failed to init platform device wakeup source, err = %d\n",
1663 ret);
1664
1665 init_completion(&plat_priv->power_up_complete);
1666 init_completion(&plat_priv->cal_complete);
Yuanyuan Liu4a903d62018-12-12 12:12:48 -08001667 init_completion(&plat_priv->rddm_complete);
Yue Mab0747ec2018-10-18 11:50:45 -07001668 mutex_init(&plat_priv->dev_lock);
1669
1670 return 0;
1671}
1672
1673static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
1674{
Yuanyuan Liu4a903d62018-12-12 12:12:48 -08001675 complete_all(&plat_priv->rddm_complete);
Yue Mab0747ec2018-10-18 11:50:45 -07001676 complete_all(&plat_priv->cal_complete);
1677 complete_all(&plat_priv->power_up_complete);
1678 device_init_wakeup(&plat_priv->plat_dev->dev, false);
1679 unregister_pm_notifier(&cnss_pm_notifier);
1680 del_timer(&plat_priv->fw_boot_timer);
1681}
1682
Yue Ma0317e4a2018-01-10 11:48:32 -08001683static const struct platform_device_id cnss_platform_id_table[] = {
1684 { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
1685 { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
Yue Mab74e6f32018-06-13 18:39:58 -07001686 { .name = "qca6390", .driver_data = QCA6390_DEVICE_ID, },
Yue Ma0317e4a2018-01-10 11:48:32 -08001687};
1688
1689static const struct of_device_id cnss_of_match_table[] = {
1690 {
1691 .compatible = "qcom,cnss",
1692 .data = (void *)&cnss_platform_id_table[0]},
1693 {
1694 .compatible = "qcom,cnss-qca6290",
1695 .data = (void *)&cnss_platform_id_table[1]},
Yue Mab74e6f32018-06-13 18:39:58 -07001696 {
1697 .compatible = "qcom,cnss-qca6390",
1698 .data = (void *)&cnss_platform_id_table[2]},
Yue Ma0317e4a2018-01-10 11:48:32 -08001699 { },
1700};
1701MODULE_DEVICE_TABLE(of, cnss_of_match_table);
1702
1703static int cnss_probe(struct platform_device *plat_dev)
1704{
1705 int ret = 0;
1706 struct cnss_plat_data *plat_priv;
1707 const struct of_device_id *of_id;
1708 const struct platform_device_id *device_id;
1709
1710 if (cnss_get_plat_priv(plat_dev)) {
1711 cnss_pr_err("Driver is already initialized!\n");
1712 ret = -EEXIST;
1713 goto out;
1714 }
1715
1716 of_id = of_match_device(cnss_of_match_table, &plat_dev->dev);
1717 if (!of_id || !of_id->data) {
1718 cnss_pr_err("Failed to find of match device!\n");
1719 ret = -ENODEV;
1720 goto out;
1721 }
1722
1723 device_id = of_id->data;
1724
1725 plat_priv = devm_kzalloc(&plat_dev->dev, sizeof(*plat_priv),
1726 GFP_KERNEL);
1727 if (!plat_priv) {
1728 ret = -ENOMEM;
1729 goto out;
1730 }
1731
1732 plat_priv->plat_dev = plat_dev;
1733 plat_priv->device_id = device_id->driver_data;
Yue Mafcf60422018-05-01 16:59:56 -07001734 plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id);
Yue Ma0317e4a2018-01-10 11:48:32 -08001735 cnss_set_plat_priv(plat_dev, plat_priv);
1736 platform_set_drvdata(plat_dev, plat_priv);
1737
1738 ret = cnss_get_resources(plat_priv);
1739 if (ret)
1740 goto reset_ctx;
1741
1742 if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) {
1743 ret = cnss_power_on_device(plat_priv);
1744 if (ret)
1745 goto free_res;
1746
Yue Mafcf60422018-05-01 16:59:56 -07001747 ret = cnss_bus_init(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001748 if (ret)
1749 goto power_off;
1750 }
1751
1752 ret = cnss_register_esoc(plat_priv);
1753 if (ret)
Yue Mafcf60422018-05-01 16:59:56 -07001754 goto deinit_bus;
Yue Ma0317e4a2018-01-10 11:48:32 -08001755
1756 ret = cnss_register_bus_scale(plat_priv);
1757 if (ret)
1758 goto unreg_esoc;
1759
1760 ret = cnss_create_sysfs(plat_priv);
1761 if (ret)
1762 goto unreg_bus_scale;
1763
1764 ret = cnss_event_work_init(plat_priv);
1765 if (ret)
1766 goto remove_sysfs;
1767
1768 ret = cnss_qmi_init(plat_priv);
1769 if (ret)
1770 goto deinit_event_work;
1771
1772 ret = cnss_debugfs_create(plat_priv);
1773 if (ret)
1774 goto deinit_qmi;
1775
Yue Mab0747ec2018-10-18 11:50:45 -07001776 ret = cnss_misc_init(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001777 if (ret)
Yue Mab0747ec2018-10-18 11:50:45 -07001778 goto destroy_debugfs;
Yue Ma0317e4a2018-01-10 11:48:32 -08001779
1780 cnss_pr_info("Platform driver probed successfully.\n");
1781
1782 return 0;
1783
Yue Mab0747ec2018-10-18 11:50:45 -07001784destroy_debugfs:
1785 cnss_debugfs_destroy(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001786deinit_qmi:
1787 cnss_qmi_deinit(plat_priv);
1788deinit_event_work:
1789 cnss_event_work_deinit(plat_priv);
1790remove_sysfs:
1791 cnss_remove_sysfs(plat_priv);
1792unreg_bus_scale:
1793 cnss_unregister_bus_scale(plat_priv);
1794unreg_esoc:
1795 cnss_unregister_esoc(plat_priv);
Yue Mafcf60422018-05-01 16:59:56 -07001796deinit_bus:
Yue Ma0317e4a2018-01-10 11:48:32 -08001797 if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
Yue Mafcf60422018-05-01 16:59:56 -07001798 cnss_bus_deinit(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001799power_off:
1800 if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
1801 cnss_power_off_device(plat_priv);
1802free_res:
1803 cnss_put_resources(plat_priv);
1804reset_ctx:
1805 platform_set_drvdata(plat_dev, NULL);
1806 cnss_set_plat_priv(plat_dev, NULL);
1807out:
1808 return ret;
1809}
1810
1811static int cnss_remove(struct platform_device *plat_dev)
1812{
1813 struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
1814
Yue Mab0747ec2018-10-18 11:50:45 -07001815 cnss_misc_deinit(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001816 cnss_debugfs_destroy(plat_priv);
1817 cnss_qmi_deinit(plat_priv);
1818 cnss_event_work_deinit(plat_priv);
1819 cnss_remove_sysfs(plat_priv);
1820 cnss_unregister_bus_scale(plat_priv);
1821 cnss_unregister_esoc(plat_priv);
Yue Mafcf60422018-05-01 16:59:56 -07001822 cnss_bus_deinit(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001823 cnss_put_resources(plat_priv);
1824 platform_set_drvdata(plat_dev, NULL);
1825 plat_env = NULL;
1826
1827 return 0;
1828}
1829
1830static struct platform_driver cnss_platform_driver = {
1831 .probe = cnss_probe,
1832 .remove = cnss_remove,
1833 .driver = {
1834 .name = "cnss2",
1835 .owner = THIS_MODULE,
1836 .of_match_table = cnss_of_match_table,
1837#ifdef CONFIG_CNSS_ASYNC
1838 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
1839#endif
1840 },
1841};
1842
1843static int __init cnss_initialize(void)
1844{
1845 int ret = 0;
1846
1847 cnss_debug_init();
1848 ret = platform_driver_register(&cnss_platform_driver);
1849 if (ret)
1850 cnss_debug_deinit();
1851
1852 return ret;
1853}
1854
1855static void __exit cnss_exit(void)
1856{
1857 platform_driver_unregister(&cnss_platform_driver);
1858 cnss_debug_deinit();
1859}
1860
1861module_init(cnss_initialize);
1862module_exit(cnss_exit);
1863
1864MODULE_LICENSE("GPL v2");
1865MODULE_DESCRIPTION("CNSS2 Platform Driver");