blob: c115a0ea3ebfb7f94fa99336a298c8e5ffce0034 [file] [log] [blame]
Ke Huang36644bb2020-04-29 17:14:45 +08001/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
Yue Ma0317e4a2018-01-10 11:48:32 -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/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;
Ke Huang36644bb2020-04-29 17:14:45 +0800252 if (!plat_priv)
253 return -ENODEV;
Yue Ma0317e4a2018-01-10 11:48:32 -0800254
255 if (plat_priv->device_id == QCA6174_DEVICE_ID)
256 return 0;
257
258 if (qmi_bypass)
259 return 0;
260
261 if (!config || !host_version) {
262 cnss_pr_err("Invalid config or host_version pointer\n");
263 return -EINVAL;
264 }
265
266 cnss_pr_dbg("Mode: %d, config: %pK, host_version: %s\n",
267 mode, config, host_version);
268
269 if (mode == CNSS_WALTEST || mode == CNSS_CCPM)
270 goto skip_cfg;
271
Yue Mab79d4862018-07-11 12:32:12 -0700272 ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, config, host_version);
Yue Ma0317e4a2018-01-10 11:48:32 -0800273 if (ret)
274 goto out;
275
276skip_cfg:
277 ret = cnss_wlfw_wlan_mode_send_sync(plat_priv, mode);
278out:
279 return ret;
280}
281EXPORT_SYMBOL(cnss_wlan_enable);
282
283int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode)
284{
285 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
Ke Huang36644bb2020-04-29 17:14:45 +0800286 if (!plat_priv)
287 return -ENODEV;
Yue Ma0317e4a2018-01-10 11:48:32 -0800288
289 if (plat_priv->device_id == QCA6174_DEVICE_ID)
290 return 0;
291
292 if (qmi_bypass)
293 return 0;
294
Yue Mab79d4862018-07-11 12:32:12 -0700295 return cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
Yue Ma0317e4a2018-01-10 11:48:32 -0800296}
297EXPORT_SYMBOL(cnss_wlan_disable);
298
299#ifdef CONFIG_CNSS2_DEBUG
300int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
301 u32 data_len, u8 *output)
302{
303 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
304 int ret = 0;
305
306 if (!plat_priv) {
307 cnss_pr_err("plat_priv is NULL!\n");
308 return -EINVAL;
309 }
310
311 if (plat_priv->device_id == QCA6174_DEVICE_ID)
312 return 0;
313
Yue Ma0317e4a2018-01-10 11:48:32 -0800314 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
315 cnss_pr_err("Invalid state for athdiag read: 0x%lx\n",
316 plat_priv->driver_state);
317 ret = -EINVAL;
318 goto out;
319 }
320
321 ret = cnss_wlfw_athdiag_read_send_sync(plat_priv, offset, mem_type,
322 data_len, output);
323
324out:
325 return ret;
326}
327EXPORT_SYMBOL(cnss_athdiag_read);
328
329int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
330 u32 data_len, u8 *input)
331{
332 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
333 int ret = 0;
334
335 if (!plat_priv) {
336 cnss_pr_err("plat_priv is NULL!\n");
337 return -EINVAL;
338 }
339
340 if (plat_priv->device_id == QCA6174_DEVICE_ID)
341 return 0;
342
Yue Ma0317e4a2018-01-10 11:48:32 -0800343 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
344 cnss_pr_err("Invalid state for athdiag write: 0x%lx\n",
345 plat_priv->driver_state);
346 ret = -EINVAL;
347 goto out;
348 }
349
350 ret = cnss_wlfw_athdiag_write_send_sync(plat_priv, offset, mem_type,
351 data_len, input);
352
353out:
354 return ret;
355}
356EXPORT_SYMBOL(cnss_athdiag_write);
357#else
358int cnss_athdiag_read(struct device *dev, u32 offset, u32 mem_type,
359 u32 data_len, u8 *output)
360{
361 return -EPERM;
362}
363EXPORT_SYMBOL(cnss_athdiag_read);
364
365int cnss_athdiag_write(struct device *dev, u32 offset, u32 mem_type,
366 u32 data_len, u8 *input)
367{
368 return -EPERM;
369}
370EXPORT_SYMBOL(cnss_athdiag_write);
371#endif
372
373int cnss_set_fw_log_mode(struct device *dev, u8 fw_log_mode)
374{
375 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
Ke Huang36644bb2020-04-29 17:14:45 +0800376 if (!plat_priv)
377 return -ENODEV;
Yue Ma0317e4a2018-01-10 11:48:32 -0800378
379 if (plat_priv->device_id == QCA6174_DEVICE_ID)
380 return 0;
381
382 return cnss_wlfw_ini_send_sync(plat_priv, fw_log_mode);
383}
384EXPORT_SYMBOL(cnss_set_fw_log_mode);
385
Yue Mae83a0eff2018-05-04 14:15:54 -0700386bool *cnss_get_qmi_bypass(void)
387{
388 return &qmi_bypass;
389}
390
391unsigned long *cnss_get_debug_quirks(void)
392{
393 return &quirks;
394}
395
Yue Ma0317e4a2018-01-10 11:48:32 -0800396static int cnss_fw_mem_ready_hdlr(struct cnss_plat_data *plat_priv)
397{
398 int ret = 0;
399
400 if (!plat_priv)
401 return -ENODEV;
402
403 set_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
404
405 ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
406 if (ret)
407 goto out;
408
409 ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
410 if (ret)
411 goto out;
412
Yue Mafcf60422018-05-01 16:59:56 -0700413 ret = cnss_bus_load_m3(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800414 if (ret)
415 goto out;
416
417 ret = cnss_wlfw_m3_dnld_send_sync(plat_priv);
418 if (ret)
419 goto out;
420
421 return 0;
422out:
423 return ret;
424}
425
Yue Ma0317e4a2018-01-10 11:48:32 -0800426static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
427{
428 int ret = 0;
429
430 if (!plat_priv)
431 return -ENODEV;
432
433 del_timer(&plat_priv->fw_boot_timer);
434 set_bit(CNSS_FW_READY, &plat_priv->driver_state);
Yue Ma6d0d8442018-10-24 12:41:41 -0700435 clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
Yue Ma0317e4a2018-01-10 11:48:32 -0800436
437 if (test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state)) {
438 clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state);
439 clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
440 }
441
442 if (enable_waltest) {
443 ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
Yue Mab79d4862018-07-11 12:32:12 -0700444 CNSS_WALTEST);
Yue Ma0317e4a2018-01-10 11:48:32 -0800445 } else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
446 ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
Yue Mab79d4862018-07-11 12:32:12 -0700447 CNSS_CALIBRATION);
Yue Ma0317e4a2018-01-10 11:48:32 -0800448 } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
449 test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
Yue Mae83a0eff2018-05-04 14:15:54 -0700450 ret = cnss_bus_call_driver_probe(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800451 } else {
452 complete(&plat_priv->power_up_complete);
453 }
454
Yue Ma8bead6d2018-02-01 12:25:47 -0800455 if (ret && test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
456 goto out;
457 else if (ret)
Yue Ma0317e4a2018-01-10 11:48:32 -0800458 goto shutdown;
459
460 return 0;
461
462shutdown:
Yue Mae83a0eff2018-05-04 14:15:54 -0700463 cnss_bus_dev_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800464
Yue Ma8bead6d2018-02-01 12:25:47 -0800465 clear_bit(CNSS_FW_READY, &plat_priv->driver_state);
466 clear_bit(CNSS_FW_MEM_READY, &plat_priv->driver_state);
467
468out:
Yue Ma0317e4a2018-01-10 11:48:32 -0800469 return ret;
470}
471
Rajasekaran Kalidossff080602018-06-06 09:05:41 +0530472static int cnss_cal_update_hdlr(struct cnss_plat_data *plat_priv)
473{
474 /* QCN7605 store the cal data sent by FW to calDB memory area
475 * get out of this after complete data is uploaded. FW is expected
476 * to send cal done
477 */
478 return 0;
479}
480
Yue Ma0317e4a2018-01-10 11:48:32 -0800481static char *cnss_driver_event_to_str(enum cnss_driver_event_type type)
482{
483 switch (type) {
484 case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
485 return "SERVER_ARRIVE";
486 case CNSS_DRIVER_EVENT_SERVER_EXIT:
487 return "SERVER_EXIT";
488 case CNSS_DRIVER_EVENT_REQUEST_MEM:
489 return "REQUEST_MEM";
490 case CNSS_DRIVER_EVENT_FW_MEM_READY:
491 return "FW_MEM_READY";
492 case CNSS_DRIVER_EVENT_FW_READY:
493 return "FW_READY";
494 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
495 return "COLD_BOOT_CAL_START";
496 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
497 return "COLD_BOOT_CAL_DONE";
Rajasekaran Kalidossff080602018-06-06 09:05:41 +0530498 case CNSS_DRIVER_EVENT_CAL_UPDATE:
499 return "COLD_BOOT_CAL_DATA_UPDATE";
500 case CNSS_DRIVER_EVENT_CAL_DOWNLOAD:
501 return "COLD_BOOT_CAL_DATA_DOWNLOAD";
Yue Ma0317e4a2018-01-10 11:48:32 -0800502 case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
503 return "REGISTER_DRIVER";
504 case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
505 return "UNREGISTER_DRIVER";
506 case CNSS_DRIVER_EVENT_RECOVERY:
507 return "RECOVERY";
508 case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
509 return "FORCE_FW_ASSERT";
510 case CNSS_DRIVER_EVENT_POWER_UP:
511 return "POWER_UP";
512 case CNSS_DRIVER_EVENT_POWER_DOWN:
513 return "POWER_DOWN";
514 case CNSS_DRIVER_EVENT_MAX:
515 return "EVENT_MAX";
516 }
517
518 return "UNKNOWN";
519};
520
521int cnss_driver_event_post(struct cnss_plat_data *plat_priv,
522 enum cnss_driver_event_type type,
523 u32 flags, void *data)
524{
525 struct cnss_driver_event *event;
526 unsigned long irq_flags;
527 int gfp = GFP_KERNEL;
528 int ret = 0;
529
530 if (!plat_priv)
531 return -ENODEV;
532
533 cnss_pr_dbg("Posting event: %s(%d)%s, state: 0x%lx flags: 0x%0x\n",
534 cnss_driver_event_to_str(type), type,
535 flags ? "-sync" : "", plat_priv->driver_state, flags);
536
537 if (type >= CNSS_DRIVER_EVENT_MAX) {
538 cnss_pr_err("Invalid Event type: %d, can't post", type);
539 return -EINVAL;
540 }
541
542 if (in_interrupt() || irqs_disabled())
543 gfp = GFP_ATOMIC;
544
545 event = kzalloc(sizeof(*event), gfp);
546 if (!event)
547 return -ENOMEM;
548
549 cnss_pm_stay_awake(plat_priv);
550
551 event->type = type;
552 event->data = data;
553 init_completion(&event->complete);
554 event->ret = CNSS_EVENT_PENDING;
555 event->sync = !!(flags & CNSS_EVENT_SYNC);
556
557 spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
558 list_add_tail(&event->list, &plat_priv->event_list);
559 spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
560
561 queue_work(plat_priv->event_wq, &plat_priv->event_work);
562
563 if (!(flags & CNSS_EVENT_SYNC))
564 goto out;
565
566 if (flags & CNSS_EVENT_UNINTERRUPTIBLE)
567 wait_for_completion(&event->complete);
568 else
569 ret = wait_for_completion_interruptible(&event->complete);
570
571 cnss_pr_dbg("Completed event: %s(%d), state: 0x%lx, ret: %d/%d\n",
572 cnss_driver_event_to_str(type), type,
573 plat_priv->driver_state, ret, event->ret);
574 spin_lock_irqsave(&plat_priv->event_lock, irq_flags);
575 if (ret == -ERESTARTSYS && event->ret == CNSS_EVENT_PENDING) {
576 event->sync = false;
577 spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
578 ret = -EINTR;
579 goto out;
580 }
581 spin_unlock_irqrestore(&plat_priv->event_lock, irq_flags);
582
583 ret = event->ret;
584 kfree(event);
585
586out:
587 cnss_pm_relax(plat_priv);
588 return ret;
589}
590
Yue Mab79d4862018-07-11 12:32:12 -0700591unsigned int cnss_get_boot_timeout(struct device *dev)
592{
593 return cnss_get_qmi_timeout();
594}
595EXPORT_SYMBOL(cnss_get_boot_timeout);
596
Yue Ma0317e4a2018-01-10 11:48:32 -0800597int cnss_power_up(struct device *dev)
598{
599 int ret = 0;
600 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
601 unsigned int timeout;
602
603 if (!plat_priv) {
604 cnss_pr_err("plat_priv is NULL\n");
605 return -ENODEV;
606 }
607
608 cnss_pr_dbg("Powering up device\n");
609
610 ret = cnss_driver_event_post(plat_priv,
611 CNSS_DRIVER_EVENT_POWER_UP,
612 CNSS_EVENT_SYNC, NULL);
613 if (ret)
614 goto out;
615
616 if (plat_priv->device_id == QCA6174_DEVICE_ID)
617 goto out;
618
Yue Mab79d4862018-07-11 12:32:12 -0700619 timeout = cnss_get_boot_timeout(dev);
Yue Ma0317e4a2018-01-10 11:48:32 -0800620
621 reinit_completion(&plat_priv->power_up_complete);
622 ret = wait_for_completion_timeout(&plat_priv->power_up_complete,
623 msecs_to_jiffies(timeout) << 2);
624 if (!ret) {
625 cnss_pr_err("Timeout waiting for power up to complete\n");
626 ret = -EAGAIN;
627 goto out;
628 }
629
630 return 0;
631
632out:
633 return ret;
634}
635EXPORT_SYMBOL(cnss_power_up);
636
637int cnss_power_down(struct device *dev)
638{
639 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
640
641 if (!plat_priv) {
642 cnss_pr_err("plat_priv is NULL\n");
643 return -ENODEV;
644 }
645
646 cnss_pr_dbg("Powering down device\n");
647
648 return cnss_driver_event_post(plat_priv,
649 CNSS_DRIVER_EVENT_POWER_DOWN,
650 CNSS_EVENT_SYNC, NULL);
651}
652EXPORT_SYMBOL(cnss_power_down);
653
Yue Ma2ebdf5c2019-05-02 15:35:16 -0700654int cnss_idle_restart(struct device *dev)
655{
656 return 0;
657}
658EXPORT_SYMBOL(cnss_idle_restart);
659
660int cnss_idle_shutdown(struct device *dev)
661{
662 return 0;
663}
664EXPORT_SYMBOL(cnss_idle_shutdown);
665
Yue Ma0317e4a2018-01-10 11:48:32 -0800666static int cnss_get_resources(struct cnss_plat_data *plat_priv)
667{
668 int ret = 0;
669
670 ret = cnss_get_vreg(plat_priv);
671 if (ret) {
672 cnss_pr_err("Failed to get vreg, err = %d\n", ret);
673 goto out;
674 }
675
676 ret = cnss_get_pinctrl(plat_priv);
677 if (ret) {
678 cnss_pr_err("Failed to get pinctrl, err = %d\n", ret);
679 goto out;
680 }
681
682 return 0;
683out:
684 return ret;
685}
686
687static void cnss_put_resources(struct cnss_plat_data *plat_priv)
688{
689}
690
691static int cnss_modem_notifier_nb(struct notifier_block *nb,
692 unsigned long code,
693 void *ss_handle)
694{
695 struct cnss_plat_data *plat_priv =
696 container_of(nb, struct cnss_plat_data, modem_nb);
Yue Ma0317e4a2018-01-10 11:48:32 -0800697 struct cnss_esoc_info *esoc_info;
Yue Ma0317e4a2018-01-10 11:48:32 -0800698
699 cnss_pr_dbg("Modem notifier: event %lu\n", code);
700
Yue Mae83a0eff2018-05-04 14:15:54 -0700701 if (!plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -0800702 return NOTIFY_DONE;
703
704 esoc_info = &plat_priv->esoc_info;
705
706 if (code == SUBSYS_AFTER_POWERUP)
707 esoc_info->modem_current_status = 1;
708 else if (code == SUBSYS_BEFORE_SHUTDOWN)
709 esoc_info->modem_current_status = 0;
710 else
711 return NOTIFY_DONE;
712
Yue Mae83a0eff2018-05-04 14:15:54 -0700713 if (!cnss_bus_call_driver_modem_status(plat_priv,
714 esoc_info->modem_current_status))
Yue Ma0317e4a2018-01-10 11:48:32 -0800715 return NOTIFY_DONE;
716
Yue Ma0317e4a2018-01-10 11:48:32 -0800717 return NOTIFY_OK;
718}
719
720static int cnss_register_esoc(struct cnss_plat_data *plat_priv)
721{
722 int ret = 0;
723 struct device *dev;
724 struct cnss_esoc_info *esoc_info;
725 struct esoc_desc *esoc_desc;
726 const char *client_desc;
727
728 dev = &plat_priv->plat_dev->dev;
729 esoc_info = &plat_priv->esoc_info;
730
731 esoc_info->notify_modem_status =
732 of_property_read_bool(dev->of_node,
733 "qcom,notify-modem-status");
734
Yue Ma3eb55622018-02-22 12:14:00 -0800735 if (!esoc_info->notify_modem_status)
Yue Ma0317e4a2018-01-10 11:48:32 -0800736 goto out;
737
738 ret = of_property_read_string_index(dev->of_node, "esoc-names", 0,
739 &client_desc);
740 if (ret) {
741 cnss_pr_dbg("esoc-names is not defined in DT, skip!\n");
742 } else {
743 esoc_desc = devm_register_esoc_client(dev, client_desc);
744 if (IS_ERR_OR_NULL(esoc_desc)) {
745 ret = PTR_RET(esoc_desc);
746 cnss_pr_err("Failed to register esoc_desc, err = %d\n",
747 ret);
748 goto out;
749 }
750 esoc_info->esoc_desc = esoc_desc;
751 }
752
753 plat_priv->modem_nb.notifier_call = cnss_modem_notifier_nb;
754 esoc_info->modem_current_status = 0;
755 esoc_info->modem_notify_handler =
756 subsys_notif_register_notifier(esoc_info->esoc_desc ?
757 esoc_info->esoc_desc->name :
758 "modem", &plat_priv->modem_nb);
759 if (IS_ERR(esoc_info->modem_notify_handler)) {
760 ret = PTR_ERR(esoc_info->modem_notify_handler);
761 cnss_pr_err("Failed to register esoc notifier, err = %d\n",
762 ret);
763 goto unreg_esoc;
764 }
765
766 return 0;
767unreg_esoc:
768 if (esoc_info->esoc_desc)
769 devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
770out:
771 return ret;
772}
773
774static void cnss_unregister_esoc(struct cnss_plat_data *plat_priv)
775{
776 struct device *dev;
777 struct cnss_esoc_info *esoc_info;
778
779 dev = &plat_priv->plat_dev->dev;
780 esoc_info = &plat_priv->esoc_info;
781
782 if (esoc_info->notify_modem_status)
783 subsys_notif_unregister_notifier(esoc_info->
784 modem_notify_handler,
785 &plat_priv->modem_nb);
786 if (esoc_info->esoc_desc)
787 devm_unregister_esoc_client(dev, esoc_info->esoc_desc);
788}
789
Yue Ma0317e4a2018-01-10 11:48:32 -0800790static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc)
791{
792 struct cnss_plat_data *plat_priv;
793
794 if (!subsys_desc->dev) {
795 cnss_pr_err("dev from subsys_desc is NULL\n");
796 return -ENODEV;
797 }
798
799 plat_priv = dev_get_drvdata(subsys_desc->dev);
800 if (!plat_priv) {
801 cnss_pr_err("plat_priv is NULL\n");
802 return -ENODEV;
803 }
804
805 if (!plat_priv->driver_state) {
806 cnss_pr_dbg("Powerup is ignored\n");
807 return 0;
808 }
809
Yue Mae83a0eff2018-05-04 14:15:54 -0700810 return cnss_bus_dev_powerup(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800811}
812
813static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc,
814 bool force_stop)
815{
816 struct cnss_plat_data *plat_priv;
817
818 if (!subsys_desc->dev) {
819 cnss_pr_err("dev from subsys_desc is NULL\n");
820 return -ENODEV;
821 }
822
823 plat_priv = dev_get_drvdata(subsys_desc->dev);
824 if (!plat_priv) {
825 cnss_pr_err("plat_priv is NULL\n");
826 return -ENODEV;
827 }
828
829 if (!plat_priv->driver_state) {
830 cnss_pr_dbg("shutdown is ignored\n");
831 return 0;
832 }
833
Yue Mae83a0eff2018-05-04 14:15:54 -0700834 return cnss_bus_dev_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800835}
836
Yue Ma0317e4a2018-01-10 11:48:32 -0800837void cnss_device_crashed(struct device *dev)
838{
839 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
840 struct cnss_subsys_info *subsys_info;
841
842 if (!plat_priv)
843 return;
844
845 subsys_info = &plat_priv->subsys_info;
846 if (subsys_info->subsys_device) {
847 set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
848 subsys_set_crash_status(subsys_info->subsys_device, true);
849 subsystem_restart_dev(subsys_info->subsys_device);
850 }
851}
852EXPORT_SYMBOL(cnss_device_crashed);
853
854static void cnss_subsys_crash_shutdown(const struct subsys_desc *subsys_desc)
855{
856 struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
857
858 if (!plat_priv) {
Yue Mae83a0eff2018-05-04 14:15:54 -0700859 cnss_pr_err("plat_priv is NULL\n");
Yue Ma0317e4a2018-01-10 11:48:32 -0800860 return;
861 }
862
Yue Mae83a0eff2018-05-04 14:15:54 -0700863 cnss_bus_dev_crash_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800864}
865
Yue Mae83a0eff2018-05-04 14:15:54 -0700866static int cnss_subsys_ramdump(int enable,
867 const struct subsys_desc *subsys_desc)
868{
869 struct cnss_plat_data *plat_priv = dev_get_drvdata(subsys_desc->dev);
870
871 if (!plat_priv) {
872 cnss_pr_err("plat_priv is NULL\n");
873 return -ENODEV;
874 }
875
876 if (!enable)
877 return 0;
878
879 return cnss_bus_dev_ramdump(plat_priv);
880}
881
882void *cnss_get_virt_ramdump_mem(struct device *dev, unsigned long *size)
883{
884 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
885 struct cnss_ramdump_info *ramdump_info;
886
887 if (!plat_priv)
888 return NULL;
889
890 ramdump_info = &plat_priv->ramdump_info;
891 *size = ramdump_info->ramdump_size;
892
893 return ramdump_info->ramdump_va;
894}
895EXPORT_SYMBOL(cnss_get_virt_ramdump_mem);
896
Yue Ma0317e4a2018-01-10 11:48:32 -0800897static const char *cnss_recovery_reason_to_str(enum cnss_recovery_reason reason)
898{
899 switch (reason) {
900 case CNSS_REASON_DEFAULT:
901 return "DEFAULT";
902 case CNSS_REASON_LINK_DOWN:
903 return "LINK_DOWN";
904 case CNSS_REASON_RDDM:
905 return "RDDM";
906 case CNSS_REASON_TIMEOUT:
907 return "TIMEOUT";
908 }
909
910 return "UNKNOWN";
911};
912
913static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
914 enum cnss_recovery_reason reason)
915{
Yue Ma0317e4a2018-01-10 11:48:32 -0800916 struct cnss_subsys_info *subsys_info =
917 &plat_priv->subsys_info;
Yue Ma0317e4a2018-01-10 11:48:32 -0800918
919 plat_priv->recovery_count++;
920
921 if (plat_priv->device_id == QCA6174_DEVICE_ID)
922 goto self_recovery;
923
Yue Ma0317e4a2018-01-10 11:48:32 -0800924 if (test_bit(SKIP_RECOVERY, &quirks)) {
925 cnss_pr_dbg("Skip device recovery\n");
926 return 0;
927 }
928
929 switch (reason) {
930 case CNSS_REASON_LINK_DOWN:
931 if (test_bit(LINK_DOWN_SELF_RECOVERY, &quirks))
932 goto self_recovery;
933 break;
934 case CNSS_REASON_RDDM:
Yue Mafcf60422018-05-01 16:59:56 -0700935 cnss_bus_collect_dump_info(plat_priv, false);
Yue Ma0317e4a2018-01-10 11:48:32 -0800936 break;
937 case CNSS_REASON_DEFAULT:
938 case CNSS_REASON_TIMEOUT:
939 break;
940 default:
941 cnss_pr_err("Unsupported recovery reason: %s(%d)\n",
942 cnss_recovery_reason_to_str(reason), reason);
943 break;
944 }
945
946 if (!subsys_info->subsys_device)
947 return 0;
948
949 subsys_set_crash_status(subsys_info->subsys_device, true);
950 subsystem_restart_dev(subsys_info->subsys_device);
951
952 return 0;
953
954self_recovery:
Yue Mae83a0eff2018-05-04 14:15:54 -0700955 cnss_bus_dev_shutdown(plat_priv);
956 cnss_bus_dev_powerup(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800957
958 return 0;
959}
960
961static int cnss_driver_recovery_hdlr(struct cnss_plat_data *plat_priv,
962 void *data)
963{
964 struct cnss_recovery_data *recovery_data = data;
965 int ret = 0;
966
967 cnss_pr_dbg("Driver recovery is triggered with reason: %s(%d)\n",
968 cnss_recovery_reason_to_str(recovery_data->reason),
969 recovery_data->reason);
970
971 if (!plat_priv->driver_state) {
972 cnss_pr_err("Improper driver state, ignore recovery\n");
973 ret = -EINVAL;
974 goto out;
975 }
976
977 if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
978 cnss_pr_err("Recovery is already in progress\n");
979 ret = -EINVAL;
980 goto out;
981 }
982
983 if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
984 cnss_pr_err("Driver unload is in progress, ignore recovery\n");
985 ret = -EINVAL;
986 goto out;
987 }
988
989 switch (plat_priv->device_id) {
990 case QCA6174_DEVICE_ID:
991 if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) {
992 cnss_pr_err("Driver load is in progress, ignore recovery\n");
993 ret = -EINVAL;
994 goto out;
995 }
996 break;
997 default:
998 if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
999 set_bit(CNSS_FW_BOOT_RECOVERY,
1000 &plat_priv->driver_state);
Yue Ma0317e4a2018-01-10 11:48:32 -08001001 }
1002 break;
1003 }
1004
1005 set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state);
1006 ret = cnss_do_recovery(plat_priv, recovery_data->reason);
1007
1008out:
1009 kfree(data);
1010 return ret;
1011}
1012
1013int cnss_self_recovery(struct device *dev,
1014 enum cnss_recovery_reason reason)
1015{
1016 cnss_schedule_recovery(dev, reason);
1017 return 0;
1018}
1019EXPORT_SYMBOL(cnss_self_recovery);
1020
1021void cnss_schedule_recovery(struct device *dev,
1022 enum cnss_recovery_reason reason)
1023{
1024 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
1025 struct cnss_recovery_data *data;
1026 int gfp = GFP_KERNEL;
1027
Yue Ma7de72832018-10-30 16:04:25 -07001028 cnss_bus_update_status(plat_priv, CNSS_FW_DOWN);
1029
Yue Ma0317e4a2018-01-10 11:48:32 -08001030 if (in_interrupt() || irqs_disabled())
1031 gfp = GFP_ATOMIC;
1032
1033 data = kzalloc(sizeof(*data), gfp);
1034 if (!data)
1035 return;
1036
1037 data->reason = reason;
1038 cnss_driver_event_post(plat_priv,
1039 CNSS_DRIVER_EVENT_RECOVERY,
1040 0, data);
1041}
1042EXPORT_SYMBOL(cnss_schedule_recovery);
1043
Yue Ma0317e4a2018-01-10 11:48:32 -08001044int cnss_force_fw_assert(struct device *dev)
1045{
1046 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
1047
1048 if (!plat_priv) {
1049 cnss_pr_err("plat_priv is NULL\n");
1050 return -ENODEV;
1051 }
1052
1053 if (plat_priv->device_id == QCA6174_DEVICE_ID) {
1054 cnss_pr_info("Forced FW assert is not supported\n");
1055 return -EOPNOTSUPP;
1056 }
1057
1058 if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
1059 cnss_pr_info("Recovery is already in progress, ignore forced FW assert\n");
1060 return 0;
1061 }
1062
1063 cnss_driver_event_post(plat_priv,
1064 CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
1065 0, NULL);
1066
1067 return 0;
1068}
1069EXPORT_SYMBOL(cnss_force_fw_assert);
1070
Yuanyuan Liu22184182018-12-03 15:29:44 -08001071int cnss_force_collect_rddm(struct device *dev)
1072{
1073 struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev);
1074 int ret = 0;
1075
1076 if (!plat_priv) {
1077 cnss_pr_err("plat_priv is NULL\n");
1078 return -ENODEV;
1079 }
1080
1081 if (plat_priv->device_id == QCA6174_DEVICE_ID) {
1082 cnss_pr_info("Force collect rddm is not supported\n");
1083 return -EOPNOTSUPP;
1084 }
1085
1086 if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
1087 cnss_pr_info("Recovery is already in progress, ignore forced collect rddm\n");
1088 return 0;
1089 }
1090
1091 cnss_driver_event_post(plat_priv,
1092 CNSS_DRIVER_EVENT_FORCE_FW_ASSERT,
1093 0, NULL);
1094
1095 reinit_completion(&plat_priv->rddm_complete);
1096 ret = wait_for_completion_timeout
1097 (&plat_priv->rddm_complete,
1098 msecs_to_jiffies(CNSS_RDDM_TIMEOUT_MS));
1099 if (!ret)
1100 ret = -ETIMEDOUT;
1101
1102 return ret;
1103}
1104EXPORT_SYMBOL(cnss_force_collect_rddm);
1105
Yue Mad7481ce2019-08-22 12:33:28 -07001106int cnss_qmi_send_get(struct device *dev)
1107{
1108 return 0;
1109}
1110EXPORT_SYMBOL(cnss_qmi_send_get);
1111
1112int cnss_qmi_send_put(struct device *dev)
1113{
1114 return 0;
1115}
1116EXPORT_SYMBOL(cnss_qmi_send_put);
1117
1118int cnss_qmi_send(struct device *dev, int type, void *cmd,
1119 int cmd_len, void *cb_ctx,
1120 int (*cb)(void *ctx, void *event, int event_len))
1121{
1122 return -EINVAL;
1123}
1124EXPORT_SYMBOL(cnss_qmi_send);
1125
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301126static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv)
1127{
1128 int ret;
1129
1130 ret = cnss_wlfw_server_arrive(plat_priv);
1131 if (ret)
1132 goto out;
1133
1134 if (!cnss_bus_req_mem_ind_valid(plat_priv)) {
1135 ret = cnss_wlfw_tgt_cap_send_sync(plat_priv);
1136 if (ret)
1137 goto out;
1138
1139 ret = cnss_wlfw_bdf_dnld_send_sync(plat_priv);
1140 if (ret)
1141 goto out;
1142 /*cnss driver sends meta data report and waits for FW_READY*/
1143 if (cnss_bus_dev_cal_rep_valid(plat_priv))
1144 ret = cnss_wlfw_cal_report_send_sync(plat_priv);
1145 }
1146out:
1147 return ret;
1148}
1149
Yue Ma0317e4a2018-01-10 11:48:32 -08001150static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
1151{
1152 int ret = 0;
1153
Yue Ma41e978d2018-10-17 15:50:21 -07001154 if (test_bit(CNSS_FW_READY, &plat_priv->driver_state) ||
1155 test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
1156 test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
1157 cnss_pr_dbg("Device is already active, ignore calibration\n");
1158 goto out;
1159 }
Yue Ma0317e4a2018-01-10 11:48:32 -08001160
Yue Ma41e978d2018-10-17 15:50:21 -07001161 set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
1162 reinit_completion(&plat_priv->cal_complete);
1163 ret = cnss_bus_dev_powerup(plat_priv);
1164 if (ret) {
1165 complete(&plat_priv->cal_complete);
1166 clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
1167 }
1168
1169out:
Yue Ma0317e4a2018-01-10 11:48:32 -08001170 return ret;
1171}
1172
1173static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
1174{
Yue Ma41e978d2018-10-17 15:50:21 -07001175 if (!test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state))
1176 return 0;
1177
Yue Maa3e15032018-02-15 15:56:12 -08001178 plat_priv->cal_done = true;
Yue Mab79d4862018-07-11 12:32:12 -07001179 cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
Yue Mae83a0eff2018-05-04 14:15:54 -07001180 cnss_bus_dev_shutdown(plat_priv);
Yue Ma41e978d2018-10-17 15:50:21 -07001181 complete(&plat_priv->cal_complete);
Yue Ma0317e4a2018-01-10 11:48:32 -08001182 clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
1183
1184 return 0;
1185}
1186
1187static int cnss_power_up_hdlr(struct cnss_plat_data *plat_priv)
1188{
Yue Mae83a0eff2018-05-04 14:15:54 -07001189 return cnss_bus_dev_powerup(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001190}
1191
1192static int cnss_power_down_hdlr(struct cnss_plat_data *plat_priv)
1193{
Yue Mae83a0eff2018-05-04 14:15:54 -07001194 cnss_bus_dev_shutdown(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001195
1196 return 0;
1197}
1198
1199static void cnss_driver_event_work(struct work_struct *work)
1200{
1201 struct cnss_plat_data *plat_priv =
1202 container_of(work, struct cnss_plat_data, event_work);
1203 struct cnss_driver_event *event;
1204 unsigned long flags;
1205 int ret = 0;
1206
1207 if (!plat_priv) {
1208 cnss_pr_err("plat_priv is NULL!\n");
1209 return;
1210 }
1211
1212 cnss_pm_stay_awake(plat_priv);
1213
1214 spin_lock_irqsave(&plat_priv->event_lock, flags);
1215
1216 while (!list_empty(&plat_priv->event_list)) {
1217 event = list_first_entry(&plat_priv->event_list,
1218 struct cnss_driver_event, list);
1219 list_del(&event->list);
1220 spin_unlock_irqrestore(&plat_priv->event_lock, flags);
1221
1222 cnss_pr_dbg("Processing driver event: %s%s(%d), state: 0x%lx\n",
1223 cnss_driver_event_to_str(event->type),
1224 event->sync ? "-sync" : "", event->type,
1225 plat_priv->driver_state);
1226
1227 switch (event->type) {
1228 case CNSS_DRIVER_EVENT_SERVER_ARRIVE:
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301229 ret = cnss_wlfw_server_arrive_hdlr(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001230 break;
1231 case CNSS_DRIVER_EVENT_SERVER_EXIT:
1232 ret = cnss_wlfw_server_exit(plat_priv);
1233 break;
1234 case CNSS_DRIVER_EVENT_REQUEST_MEM:
Yue Mafcf60422018-05-01 16:59:56 -07001235 ret = cnss_bus_alloc_fw_mem(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001236 if (ret)
1237 break;
1238 ret = cnss_wlfw_respond_mem_send_sync(plat_priv);
1239 break;
1240 case CNSS_DRIVER_EVENT_FW_MEM_READY:
1241 ret = cnss_fw_mem_ready_hdlr(plat_priv);
1242 break;
1243 case CNSS_DRIVER_EVENT_FW_READY:
1244 ret = cnss_fw_ready_hdlr(plat_priv);
1245 break;
1246 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START:
1247 ret = cnss_cold_boot_cal_start_hdlr(plat_priv);
1248 break;
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301249 case CNSS_DRIVER_EVENT_CAL_UPDATE:
1250 ret = cnss_cal_update_hdlr(plat_priv);
1251 break;
Yue Ma0317e4a2018-01-10 11:48:32 -08001252 case CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE:
1253 ret = cnss_cold_boot_cal_done_hdlr(plat_priv);
1254 break;
1255 case CNSS_DRIVER_EVENT_REGISTER_DRIVER:
Yue Mae83a0eff2018-05-04 14:15:54 -07001256 ret = cnss_bus_register_driver_hdlr(plat_priv,
1257 event->data);
Yue Ma0317e4a2018-01-10 11:48:32 -08001258 break;
1259 case CNSS_DRIVER_EVENT_UNREGISTER_DRIVER:
Yue Mae83a0eff2018-05-04 14:15:54 -07001260 ret = cnss_bus_unregister_driver_hdlr(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001261 break;
1262 case CNSS_DRIVER_EVENT_RECOVERY:
1263 ret = cnss_driver_recovery_hdlr(plat_priv,
1264 event->data);
1265 break;
1266 case CNSS_DRIVER_EVENT_FORCE_FW_ASSERT:
Yue Mafcf60422018-05-01 16:59:56 -07001267 ret = cnss_bus_force_fw_assert_hdlr(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001268 break;
1269 case CNSS_DRIVER_EVENT_POWER_UP:
1270 ret = cnss_power_up_hdlr(plat_priv);
1271 break;
1272 case CNSS_DRIVER_EVENT_POWER_DOWN:
1273 ret = cnss_power_down_hdlr(plat_priv);
1274 break;
1275 default:
1276 cnss_pr_err("Invalid driver event type: %d",
1277 event->type);
1278 kfree(event);
1279 spin_lock_irqsave(&plat_priv->event_lock, flags);
1280 continue;
1281 }
1282
1283 spin_lock_irqsave(&plat_priv->event_lock, flags);
1284 if (event->sync) {
1285 event->ret = ret;
1286 complete(&event->complete);
1287 continue;
1288 }
1289 spin_unlock_irqrestore(&plat_priv->event_lock, flags);
1290
1291 kfree(event);
1292
1293 spin_lock_irqsave(&plat_priv->event_lock, flags);
1294 }
1295 spin_unlock_irqrestore(&plat_priv->event_lock, flags);
1296
1297 cnss_pm_relax(plat_priv);
1298}
1299
1300int cnss_register_subsys(struct cnss_plat_data *plat_priv)
1301{
1302 int ret = 0;
1303 struct cnss_subsys_info *subsys_info;
1304
1305 subsys_info = &plat_priv->subsys_info;
1306
Yue Ma922b0352018-04-19 14:03:29 -07001307 subsys_info->subsys_desc.name = "wlan";
Yue Ma0317e4a2018-01-10 11:48:32 -08001308 subsys_info->subsys_desc.owner = THIS_MODULE;
1309 subsys_info->subsys_desc.powerup = cnss_subsys_powerup;
1310 subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown;
1311 subsys_info->subsys_desc.ramdump = cnss_subsys_ramdump;
1312 subsys_info->subsys_desc.crash_shutdown = cnss_subsys_crash_shutdown;
1313 subsys_info->subsys_desc.dev = &plat_priv->plat_dev->dev;
1314
1315 subsys_info->subsys_device = subsys_register(&subsys_info->subsys_desc);
1316 if (IS_ERR(subsys_info->subsys_device)) {
1317 ret = PTR_ERR(subsys_info->subsys_device);
1318 cnss_pr_err("Failed to register subsys, err = %d\n", ret);
1319 goto out;
1320 }
1321
1322 subsys_info->subsys_handle =
1323 subsystem_get(subsys_info->subsys_desc.name);
1324 if (!subsys_info->subsys_handle) {
1325 cnss_pr_err("Failed to get subsys_handle!\n");
1326 ret = -EINVAL;
1327 goto unregister_subsys;
1328 } else if (IS_ERR(subsys_info->subsys_handle)) {
1329 ret = PTR_ERR(subsys_info->subsys_handle);
1330 cnss_pr_err("Failed to do subsystem_get, err = %d\n", ret);
1331 goto unregister_subsys;
1332 }
1333
1334 return 0;
1335
1336unregister_subsys:
1337 subsys_unregister(subsys_info->subsys_device);
1338out:
1339 return ret;
1340}
1341
1342void cnss_unregister_subsys(struct cnss_plat_data *plat_priv)
1343{
1344 struct cnss_subsys_info *subsys_info;
1345
1346 subsys_info = &plat_priv->subsys_info;
1347 subsystem_put(subsys_info->subsys_handle);
1348 subsys_unregister(subsys_info->subsys_device);
1349}
1350
1351static int cnss_init_dump_entry(struct cnss_plat_data *plat_priv)
1352{
1353 struct cnss_ramdump_info *ramdump_info;
1354 struct msm_dump_entry dump_entry;
1355
1356 ramdump_info = &plat_priv->ramdump_info;
1357 ramdump_info->dump_data.addr = ramdump_info->ramdump_pa;
1358 ramdump_info->dump_data.len = ramdump_info->ramdump_size;
1359 ramdump_info->dump_data.version = CNSS_DUMP_FORMAT_VER;
1360 ramdump_info->dump_data.magic = CNSS_DUMP_MAGIC_VER_V2;
1361 strlcpy(ramdump_info->dump_data.name, CNSS_DUMP_NAME,
1362 sizeof(ramdump_info->dump_data.name));
1363 dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
1364 dump_entry.addr = virt_to_phys(&ramdump_info->dump_data);
1365
1366 return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
1367}
1368
Yue Ma2ad23282018-06-13 18:38:50 -07001369static int cnss_register_ramdump_v1(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001370{
1371 int ret = 0;
1372 struct device *dev;
1373 struct cnss_subsys_info *subsys_info;
1374 struct cnss_ramdump_info *ramdump_info;
1375 u32 ramdump_size = 0;
1376
1377 dev = &plat_priv->plat_dev->dev;
1378 subsys_info = &plat_priv->subsys_info;
1379 ramdump_info = &plat_priv->ramdump_info;
1380
1381 if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
1382 &ramdump_size) == 0) {
1383 ramdump_info->ramdump_va = dma_alloc_coherent(dev, ramdump_size,
1384 &ramdump_info->ramdump_pa, GFP_KERNEL);
1385
1386 if (ramdump_info->ramdump_va)
1387 ramdump_info->ramdump_size = ramdump_size;
1388 }
1389
1390 cnss_pr_dbg("ramdump va: %pK, pa: %pa\n",
1391 ramdump_info->ramdump_va, &ramdump_info->ramdump_pa);
1392
1393 if (ramdump_info->ramdump_size == 0) {
1394 cnss_pr_info("Ramdump will not be collected");
1395 goto out;
1396 }
1397
1398 ret = cnss_init_dump_entry(plat_priv);
1399 if (ret) {
1400 cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
1401 goto free_ramdump;
1402 }
1403
1404 ramdump_info->ramdump_dev = create_ramdump_device(
1405 subsys_info->subsys_desc.name, subsys_info->subsys_desc.dev);
1406 if (!ramdump_info->ramdump_dev) {
1407 cnss_pr_err("Failed to create ramdump device!");
1408 ret = -ENOMEM;
1409 goto free_ramdump;
1410 }
1411
1412 return 0;
1413free_ramdump:
1414 dma_free_coherent(dev, ramdump_info->ramdump_size,
1415 ramdump_info->ramdump_va, ramdump_info->ramdump_pa);
1416out:
1417 return ret;
1418}
1419
Yue Ma2ad23282018-06-13 18:38:50 -07001420static void cnss_unregister_ramdump_v1(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001421{
1422 struct device *dev;
1423 struct cnss_ramdump_info *ramdump_info;
1424
1425 dev = &plat_priv->plat_dev->dev;
1426 ramdump_info = &plat_priv->ramdump_info;
1427
1428 if (ramdump_info->ramdump_dev)
1429 destroy_ramdump_device(ramdump_info->ramdump_dev);
1430
1431 if (ramdump_info->ramdump_va)
1432 dma_free_coherent(dev, ramdump_info->ramdump_size,
1433 ramdump_info->ramdump_va,
1434 ramdump_info->ramdump_pa);
1435}
1436
Yue Ma2ad23282018-06-13 18:38:50 -07001437static int cnss_register_ramdump_v2(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001438{
1439 int ret = 0;
1440 struct cnss_subsys_info *subsys_info;
1441 struct cnss_ramdump_info_v2 *info_v2;
1442 struct cnss_dump_data *dump_data;
1443 struct msm_dump_entry dump_entry;
1444 struct device *dev = &plat_priv->plat_dev->dev;
1445 u32 ramdump_size = 0;
1446
1447 subsys_info = &plat_priv->subsys_info;
1448 info_v2 = &plat_priv->ramdump_info_v2;
1449 dump_data = &info_v2->dump_data;
1450
1451 if (of_property_read_u32(dev->of_node, "qcom,wlan-ramdump-dynamic",
1452 &ramdump_size) == 0)
1453 info_v2->ramdump_size = ramdump_size;
1454
1455 cnss_pr_dbg("Ramdump size 0x%lx\n", info_v2->ramdump_size);
1456
1457 info_v2->dump_data_vaddr = kzalloc(CNSS_DUMP_DESC_SIZE, GFP_KERNEL);
1458 if (!info_v2->dump_data_vaddr)
1459 return -ENOMEM;
1460
1461 dump_data->paddr = virt_to_phys(info_v2->dump_data_vaddr);
1462 dump_data->version = CNSS_DUMP_FORMAT_VER_V2;
1463 dump_data->magic = CNSS_DUMP_MAGIC_VER_V2;
1464 dump_data->seg_version = CNSS_DUMP_SEG_VER;
1465 strlcpy(dump_data->name, CNSS_DUMP_NAME,
1466 sizeof(dump_data->name));
1467 dump_entry.id = MSM_DUMP_DATA_CNSS_WLAN;
1468 dump_entry.addr = virt_to_phys(dump_data);
1469
1470 ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
1471 if (ret) {
1472 cnss_pr_err("Failed to setup dump table, err = %d\n", ret);
1473 goto free_ramdump;
1474 }
1475
1476 info_v2->ramdump_dev =
1477 create_ramdump_device(subsys_info->subsys_desc.name,
1478 subsys_info->subsys_desc.dev);
1479 if (!info_v2->ramdump_dev) {
1480 cnss_pr_err("Failed to create ramdump device!\n");
1481 ret = -ENOMEM;
1482 goto free_ramdump;
1483 }
1484
1485 return 0;
1486
1487free_ramdump:
1488 kfree(info_v2->dump_data_vaddr);
1489 info_v2->dump_data_vaddr = NULL;
1490 return ret;
1491}
1492
Yue Ma2ad23282018-06-13 18:38:50 -07001493static void cnss_unregister_ramdump_v2(struct cnss_plat_data *plat_priv)
Yue Ma0317e4a2018-01-10 11:48:32 -08001494{
1495 struct cnss_ramdump_info_v2 *info_v2;
1496
1497 info_v2 = &plat_priv->ramdump_info_v2;
1498
1499 if (info_v2->ramdump_dev)
1500 destroy_ramdump_device(info_v2->ramdump_dev);
1501
1502 kfree(info_v2->dump_data_vaddr);
1503 info_v2->dump_data_vaddr = NULL;
1504 info_v2->dump_data_valid = false;
1505}
1506
1507int cnss_register_ramdump(struct cnss_plat_data *plat_priv)
1508{
1509 int ret = 0;
1510
1511 switch (plat_priv->device_id) {
1512 case QCA6174_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001513 ret = cnss_register_ramdump_v1(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001514 break;
1515 case QCA6290_EMULATION_DEVICE_ID:
1516 case QCA6290_DEVICE_ID:
Yue Mab74e6f32018-06-13 18:39:58 -07001517 case QCA6390_EMULATION_DEVICE_ID:
1518 case QCA6390_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001519 ret = cnss_register_ramdump_v2(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001520 break;
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301521 case QCN7605_COMPOSITE_DEVICE_ID:
1522 case QCN7605_STANDALONE_DEVICE_ID:
1523 break;
1524
Yue Ma0317e4a2018-01-10 11:48:32 -08001525 default:
1526 cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
1527 ret = -ENODEV;
1528 break;
1529 }
1530 return ret;
1531}
1532
1533void cnss_unregister_ramdump(struct cnss_plat_data *plat_priv)
1534{
1535 switch (plat_priv->device_id) {
1536 case QCA6174_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001537 cnss_unregister_ramdump_v1(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001538 break;
1539 case QCA6290_EMULATION_DEVICE_ID:
1540 case QCA6290_DEVICE_ID:
Yue Mab74e6f32018-06-13 18:39:58 -07001541 case QCA6390_EMULATION_DEVICE_ID:
1542 case QCA6390_DEVICE_ID:
Yue Ma2ad23282018-06-13 18:38:50 -07001543 cnss_unregister_ramdump_v2(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001544 break;
Rajasekaran Kalidossff080602018-06-06 09:05:41 +05301545 case QCN7605_COMPOSITE_DEVICE_ID:
1546 case QCN7605_STANDALONE_DEVICE_ID:
1547 break;
Yue Ma0317e4a2018-01-10 11:48:32 -08001548 default:
1549 cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id);
1550 break;
1551 }
1552}
1553
1554static int cnss_register_bus_scale(struct cnss_plat_data *plat_priv)
1555{
1556 int ret = 0;
1557 struct cnss_bus_bw_info *bus_bw_info;
1558
1559 bus_bw_info = &plat_priv->bus_bw_info;
1560
1561 bus_bw_info->bus_scale_table =
1562 msm_bus_cl_get_pdata(plat_priv->plat_dev);
1563 if (bus_bw_info->bus_scale_table) {
1564 bus_bw_info->bus_client =
1565 msm_bus_scale_register_client(
1566 bus_bw_info->bus_scale_table);
1567 if (!bus_bw_info->bus_client) {
1568 cnss_pr_err("Failed to register bus scale client!\n");
1569 ret = -EINVAL;
1570 goto out;
1571 }
1572 }
1573
1574 return 0;
1575out:
1576 return ret;
1577}
1578
1579static void cnss_unregister_bus_scale(struct cnss_plat_data *plat_priv)
1580{
1581 struct cnss_bus_bw_info *bus_bw_info;
1582
1583 bus_bw_info = &plat_priv->bus_bw_info;
1584
1585 if (bus_bw_info->bus_client)
1586 msm_bus_scale_unregister_client(bus_bw_info->bus_client);
1587}
1588
1589static ssize_t cnss_fs_ready_store(struct device *dev,
1590 struct device_attribute *attr,
1591 const char *buf,
1592 size_t count)
1593{
1594 int fs_ready = 0;
1595 struct cnss_plat_data *plat_priv = dev_get_drvdata(dev);
1596
1597 if (sscanf(buf, "%du", &fs_ready) != 1)
1598 return -EINVAL;
1599
1600 cnss_pr_dbg("File system is ready, fs_ready is %d, count is %zu\n",
1601 fs_ready, count);
1602
1603 if (qmi_bypass) {
1604 cnss_pr_dbg("QMI is bypassed.\n");
1605 return count;
1606 }
1607
1608 if (!plat_priv) {
1609 cnss_pr_err("plat_priv is NULL!\n");
1610 return count;
1611 }
1612
1613 switch (plat_priv->device_id) {
1614 case QCA6290_EMULATION_DEVICE_ID:
1615 case QCA6290_DEVICE_ID:
Yue Mab74e6f32018-06-13 18:39:58 -07001616 case QCA6390_EMULATION_DEVICE_ID:
1617 case QCA6390_DEVICE_ID:
Yue Ma0317e4a2018-01-10 11:48:32 -08001618 break;
1619 default:
1620 cnss_pr_err("Not supported for device ID 0x%lx\n",
1621 plat_priv->device_id);
1622 return count;
1623 }
1624
1625 if (fs_ready == FILE_SYSTEM_READY) {
1626 cnss_driver_event_post(plat_priv,
1627 CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
1628 CNSS_EVENT_SYNC, NULL);
1629 }
1630
1631 return count;
1632}
1633
1634static DEVICE_ATTR(fs_ready, 0220, NULL, cnss_fs_ready_store);
1635
1636static int cnss_create_sysfs(struct cnss_plat_data *plat_priv)
1637{
1638 int ret = 0;
1639
1640 ret = device_create_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
1641 if (ret) {
1642 cnss_pr_err("Failed to create device file, err = %d\n", ret);
1643 goto out;
1644 }
1645
1646 return 0;
1647out:
1648 return ret;
1649}
1650
1651static void cnss_remove_sysfs(struct cnss_plat_data *plat_priv)
1652{
1653 device_remove_file(&plat_priv->plat_dev->dev, &dev_attr_fs_ready);
1654}
1655
1656static int cnss_event_work_init(struct cnss_plat_data *plat_priv)
1657{
1658 spin_lock_init(&plat_priv->event_lock);
1659 plat_priv->event_wq = alloc_workqueue("cnss_driver_event",
1660 WQ_UNBOUND, 1);
1661 if (!plat_priv->event_wq) {
1662 cnss_pr_err("Failed to create event workqueue!\n");
1663 return -EFAULT;
1664 }
1665
1666 INIT_WORK(&plat_priv->event_work, cnss_driver_event_work);
1667 INIT_LIST_HEAD(&plat_priv->event_list);
1668
1669 return 0;
1670}
1671
1672static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv)
1673{
1674 destroy_workqueue(plat_priv->event_wq);
1675}
1676
Yue Mab0747ec2018-10-18 11:50:45 -07001677static int cnss_misc_init(struct cnss_plat_data *plat_priv)
1678{
1679 int ret;
1680
1681 setup_timer(&plat_priv->fw_boot_timer, cnss_bus_fw_boot_timeout_hdlr,
1682 (unsigned long)plat_priv);
1683
1684 register_pm_notifier(&cnss_pm_notifier);
1685
1686 ret = device_init_wakeup(&plat_priv->plat_dev->dev, true);
1687 if (ret)
1688 cnss_pr_err("Failed to init platform device wakeup source, err = %d\n",
1689 ret);
1690
1691 init_completion(&plat_priv->power_up_complete);
1692 init_completion(&plat_priv->cal_complete);
Yuanyuan Liu4a903d62018-12-12 12:12:48 -08001693 init_completion(&plat_priv->rddm_complete);
Yue Mab0747ec2018-10-18 11:50:45 -07001694 mutex_init(&plat_priv->dev_lock);
1695
1696 return 0;
1697}
1698
1699static void cnss_misc_deinit(struct cnss_plat_data *plat_priv)
1700{
Yuanyuan Liu4a903d62018-12-12 12:12:48 -08001701 complete_all(&plat_priv->rddm_complete);
Yue Mab0747ec2018-10-18 11:50:45 -07001702 complete_all(&plat_priv->cal_complete);
1703 complete_all(&plat_priv->power_up_complete);
1704 device_init_wakeup(&plat_priv->plat_dev->dev, false);
1705 unregister_pm_notifier(&cnss_pm_notifier);
1706 del_timer(&plat_priv->fw_boot_timer);
1707}
1708
Yue Ma0317e4a2018-01-10 11:48:32 -08001709static const struct platform_device_id cnss_platform_id_table[] = {
1710 { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, },
1711 { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, },
Yue Mab74e6f32018-06-13 18:39:58 -07001712 { .name = "qca6390", .driver_data = QCA6390_DEVICE_ID, },
Yue Ma0317e4a2018-01-10 11:48:32 -08001713};
1714
1715static const struct of_device_id cnss_of_match_table[] = {
1716 {
1717 .compatible = "qcom,cnss",
1718 .data = (void *)&cnss_platform_id_table[0]},
1719 {
1720 .compatible = "qcom,cnss-qca6290",
1721 .data = (void *)&cnss_platform_id_table[1]},
Yue Mab74e6f32018-06-13 18:39:58 -07001722 {
1723 .compatible = "qcom,cnss-qca6390",
1724 .data = (void *)&cnss_platform_id_table[2]},
Yue Ma0317e4a2018-01-10 11:48:32 -08001725 { },
1726};
1727MODULE_DEVICE_TABLE(of, cnss_of_match_table);
1728
1729static int cnss_probe(struct platform_device *plat_dev)
1730{
1731 int ret = 0;
1732 struct cnss_plat_data *plat_priv;
1733 const struct of_device_id *of_id;
1734 const struct platform_device_id *device_id;
1735
1736 if (cnss_get_plat_priv(plat_dev)) {
1737 cnss_pr_err("Driver is already initialized!\n");
1738 ret = -EEXIST;
1739 goto out;
1740 }
1741
1742 of_id = of_match_device(cnss_of_match_table, &plat_dev->dev);
1743 if (!of_id || !of_id->data) {
1744 cnss_pr_err("Failed to find of match device!\n");
1745 ret = -ENODEV;
1746 goto out;
1747 }
1748
1749 device_id = of_id->data;
1750
1751 plat_priv = devm_kzalloc(&plat_dev->dev, sizeof(*plat_priv),
1752 GFP_KERNEL);
1753 if (!plat_priv) {
1754 ret = -ENOMEM;
1755 goto out;
1756 }
1757
1758 plat_priv->plat_dev = plat_dev;
1759 plat_priv->device_id = device_id->driver_data;
Yue Mafcf60422018-05-01 16:59:56 -07001760 plat_priv->bus_type = cnss_get_bus_type(plat_priv->device_id);
Yue Ma0317e4a2018-01-10 11:48:32 -08001761 cnss_set_plat_priv(plat_dev, plat_priv);
1762 platform_set_drvdata(plat_dev, plat_priv);
1763
1764 ret = cnss_get_resources(plat_priv);
1765 if (ret)
1766 goto reset_ctx;
1767
1768 if (!test_bit(SKIP_DEVICE_BOOT, &quirks)) {
1769 ret = cnss_power_on_device(plat_priv);
1770 if (ret)
1771 goto free_res;
1772
Yue Mafcf60422018-05-01 16:59:56 -07001773 ret = cnss_bus_init(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001774 if (ret)
1775 goto power_off;
1776 }
1777
1778 ret = cnss_register_esoc(plat_priv);
1779 if (ret)
Yue Mafcf60422018-05-01 16:59:56 -07001780 goto deinit_bus;
Yue Ma0317e4a2018-01-10 11:48:32 -08001781
1782 ret = cnss_register_bus_scale(plat_priv);
1783 if (ret)
1784 goto unreg_esoc;
1785
1786 ret = cnss_create_sysfs(plat_priv);
1787 if (ret)
1788 goto unreg_bus_scale;
1789
1790 ret = cnss_event_work_init(plat_priv);
1791 if (ret)
1792 goto remove_sysfs;
1793
1794 ret = cnss_qmi_init(plat_priv);
1795 if (ret)
1796 goto deinit_event_work;
1797
1798 ret = cnss_debugfs_create(plat_priv);
1799 if (ret)
1800 goto deinit_qmi;
1801
Yue Mab0747ec2018-10-18 11:50:45 -07001802 ret = cnss_misc_init(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001803 if (ret)
Yue Mab0747ec2018-10-18 11:50:45 -07001804 goto destroy_debugfs;
Yue Ma0317e4a2018-01-10 11:48:32 -08001805
1806 cnss_pr_info("Platform driver probed successfully.\n");
1807
1808 return 0;
1809
Yue Mab0747ec2018-10-18 11:50:45 -07001810destroy_debugfs:
1811 cnss_debugfs_destroy(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001812deinit_qmi:
1813 cnss_qmi_deinit(plat_priv);
1814deinit_event_work:
1815 cnss_event_work_deinit(plat_priv);
1816remove_sysfs:
1817 cnss_remove_sysfs(plat_priv);
1818unreg_bus_scale:
1819 cnss_unregister_bus_scale(plat_priv);
1820unreg_esoc:
1821 cnss_unregister_esoc(plat_priv);
Yue Mafcf60422018-05-01 16:59:56 -07001822deinit_bus:
Yue Ma0317e4a2018-01-10 11:48:32 -08001823 if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
Yue Mafcf60422018-05-01 16:59:56 -07001824 cnss_bus_deinit(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001825power_off:
1826 if (!test_bit(SKIP_DEVICE_BOOT, &quirks))
1827 cnss_power_off_device(plat_priv);
1828free_res:
1829 cnss_put_resources(plat_priv);
1830reset_ctx:
1831 platform_set_drvdata(plat_dev, NULL);
1832 cnss_set_plat_priv(plat_dev, NULL);
1833out:
1834 return ret;
1835}
1836
1837static int cnss_remove(struct platform_device *plat_dev)
1838{
1839 struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev);
1840
Yue Mab0747ec2018-10-18 11:50:45 -07001841 cnss_misc_deinit(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001842 cnss_debugfs_destroy(plat_priv);
1843 cnss_qmi_deinit(plat_priv);
1844 cnss_event_work_deinit(plat_priv);
1845 cnss_remove_sysfs(plat_priv);
1846 cnss_unregister_bus_scale(plat_priv);
1847 cnss_unregister_esoc(plat_priv);
Yue Mafcf60422018-05-01 16:59:56 -07001848 cnss_bus_deinit(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001849 cnss_put_resources(plat_priv);
1850 platform_set_drvdata(plat_dev, NULL);
1851 plat_env = NULL;
1852
1853 return 0;
1854}
1855
1856static struct platform_driver cnss_platform_driver = {
1857 .probe = cnss_probe,
1858 .remove = cnss_remove,
1859 .driver = {
1860 .name = "cnss2",
1861 .owner = THIS_MODULE,
1862 .of_match_table = cnss_of_match_table,
1863#ifdef CONFIG_CNSS_ASYNC
1864 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
1865#endif
1866 },
1867};
1868
1869static int __init cnss_initialize(void)
1870{
1871 int ret = 0;
1872
1873 cnss_debug_init();
1874 ret = platform_driver_register(&cnss_platform_driver);
1875 if (ret)
1876 cnss_debug_deinit();
1877
1878 return ret;
1879}
1880
1881static void __exit cnss_exit(void)
1882{
1883 platform_driver_unregister(&cnss_platform_driver);
1884 cnss_debug_deinit();
1885}
1886
1887module_init(cnss_initialize);
1888module_exit(cnss_exit);
1889
1890MODULE_LICENSE("GPL v2");
1891MODULE_DESCRIPTION("CNSS2 Platform Driver");