xref: /wlan-driver/qcacld-3.0/core/pld/src/pld_usb.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include "pld_usb.h"
21*5113495bSYour Name #include "pld_internal.h"
22*5113495bSYour Name 
23*5113495bSYour Name #include <linux/atomic.h>
24*5113495bSYour Name #include <linux/usb.h>
25*5113495bSYour Name #include <linux/slab.h>
26*5113495bSYour Name #include <linux/platform_device.h>
27*5113495bSYour Name #include <linux/err.h>
28*5113495bSYour Name #include <linux/list.h>
29*5113495bSYour Name #include "osif_psoc_sync.h"
30*5113495bSYour Name 
31*5113495bSYour Name #ifdef CONFIG_PLD_USB_CNSS
32*5113495bSYour Name #include <net/cnss2.h>
33*5113495bSYour Name #endif
34*5113495bSYour Name 
35*5113495bSYour Name 
36*5113495bSYour Name #define VENDOR_ATHR             0x0CF3
37*5113495bSYour Name static struct usb_device_id pld_usb_id_table[] = {
38*5113495bSYour Name 	{USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ATHR, 0x9378, 0xFF, 0xFF, 0xFF)},
39*5113495bSYour Name 	{USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ATHR, 0x9379, 0xFF, 0xFF, 0xFF)},
40*5113495bSYour Name 	{}			/* Terminating entry */
41*5113495bSYour Name };
42*5113495bSYour Name 
43*5113495bSYour Name atomic_t pld_usb_reg_done;
44*5113495bSYour Name 
45*5113495bSYour Name /**
46*5113495bSYour Name  * pld_usb_probe() - pld_usb_probe
47*5113495bSYour Name  * @interface: pointer to usb_interface structure
48*5113495bSYour Name  * @id: pointer to usb_device_id obtained from the enumerated device
49*5113495bSYour Name  *
50*5113495bSYour Name  * Return: int 0 on success and errno on failure.
51*5113495bSYour Name  */
pld_usb_probe(struct usb_interface * interface,const struct usb_device_id * id)52*5113495bSYour Name static int pld_usb_probe(struct usb_interface *interface,
53*5113495bSYour Name 					const struct usb_device_id *id)
54*5113495bSYour Name {
55*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
56*5113495bSYour Name 	struct pld_context *pld_context;
57*5113495bSYour Name 	int ret = 0;
58*5113495bSYour Name 
59*5113495bSYour Name 	pld_context = pld_get_global_context();
60*5113495bSYour Name 	if (!pld_context) {
61*5113495bSYour Name 		ret = -ENODEV;
62*5113495bSYour Name 		goto out;
63*5113495bSYour Name 	}
64*5113495bSYour Name 
65*5113495bSYour Name 	ret = pld_add_dev(pld_context, &pdev->dev, &interface->dev,
66*5113495bSYour Name 			  PLD_BUS_TYPE_USB);
67*5113495bSYour Name 	if (ret)
68*5113495bSYour Name 		goto out;
69*5113495bSYour Name 
70*5113495bSYour Name 	ret = pld_context->ops->probe(&pdev->dev,
71*5113495bSYour Name 				      PLD_BUS_TYPE_USB, interface, (void *)id);
72*5113495bSYour Name 	if (ret != 0) {
73*5113495bSYour Name 		pr_err("%s, probe returned %d", __func__, ret);
74*5113495bSYour Name 		atomic_set(&pld_usb_reg_done, false);
75*5113495bSYour Name 	} else {
76*5113495bSYour Name 		atomic_set(&pld_usb_reg_done, true);
77*5113495bSYour Name 	}
78*5113495bSYour Name 
79*5113495bSYour Name out:
80*5113495bSYour Name 	return ret;
81*5113495bSYour Name }
82*5113495bSYour Name 
83*5113495bSYour Name /**
84*5113495bSYour Name  * pld_usb_remove() - Remove function for USB device
85*5113495bSYour Name  * @interface: pointer to usb_interface for the usb device being removed
86*5113495bSYour Name  *
87*5113495bSYour Name  * Return: void
88*5113495bSYour Name  */
pld_usb_remove(struct usb_interface * interface)89*5113495bSYour Name static void pld_usb_remove(struct usb_interface *interface)
90*5113495bSYour Name {
91*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
92*5113495bSYour Name 	struct pld_context *pld_context;
93*5113495bSYour Name 	int errno;
94*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
95*5113495bSYour Name 
96*5113495bSYour Name 	errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync);
97*5113495bSYour Name 	if (errno)
98*5113495bSYour Name 		return;
99*5113495bSYour Name 
100*5113495bSYour Name 	osif_psoc_sync_unregister(&pdev->dev);
101*5113495bSYour Name 	osif_psoc_sync_wait_for_ops(psoc_sync);
102*5113495bSYour Name 
103*5113495bSYour Name 	pld_context = pld_get_global_context();
104*5113495bSYour Name 
105*5113495bSYour Name 	if (!pld_context)
106*5113495bSYour Name 		goto out;
107*5113495bSYour Name 
108*5113495bSYour Name 	if (atomic_read(&pld_usb_reg_done) != true) {
109*5113495bSYour Name 		pr_info("%s: already de-registered!\n", __func__);
110*5113495bSYour Name 		goto out;
111*5113495bSYour Name 	}
112*5113495bSYour Name 
113*5113495bSYour Name 	pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_USB);
114*5113495bSYour Name 
115*5113495bSYour Name 	pld_del_dev(pld_context, &pdev->dev);
116*5113495bSYour Name 
117*5113495bSYour Name 	atomic_set(&pld_usb_reg_done, false);
118*5113495bSYour Name out:
119*5113495bSYour Name 	osif_psoc_sync_trans_stop(psoc_sync);
120*5113495bSYour Name 	osif_psoc_sync_destroy(psoc_sync);
121*5113495bSYour Name 
122*5113495bSYour Name 	pr_info("%s: done!\n", __func__);
123*5113495bSYour Name }
124*5113495bSYour Name 
125*5113495bSYour Name /**
126*5113495bSYour Name  * pld_usb_suspend() - Suspend callback function for power management
127*5113495bSYour Name  * @interface: pointer to usb_interface for the usb device
128*5113495bSYour Name  * @state: power state
129*5113495bSYour Name  *
130*5113495bSYour Name  * This function is to suspend the PCIE device when power management is
131*5113495bSYour Name  * enabled.
132*5113495bSYour Name  *
133*5113495bSYour Name  * Return: void
134*5113495bSYour Name  */
pld_usb_suspend(struct usb_interface * interface,pm_message_t state)135*5113495bSYour Name static int pld_usb_suspend(struct usb_interface *interface,
136*5113495bSYour Name 						pm_message_t state)
137*5113495bSYour Name {
138*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
139*5113495bSYour Name 	struct pld_context *pld_context;
140*5113495bSYour Name 
141*5113495bSYour Name 	pld_context = pld_get_global_context();
142*5113495bSYour Name 	return pld_context->ops->suspend(&pdev->dev, PLD_BUS_TYPE_USB, state);
143*5113495bSYour Name }
144*5113495bSYour Name 
145*5113495bSYour Name /**
146*5113495bSYour Name  * pld_usb_resume() - Resume callback function for power management
147*5113495bSYour Name  * @interface: pointer to usb_interface for the usb device
148*5113495bSYour Name  *
149*5113495bSYour Name  * This function is to resume the USB device when power management is
150*5113495bSYour Name  * enabled.
151*5113495bSYour Name  *
152*5113495bSYour Name  * Return: void
153*5113495bSYour Name  */
pld_usb_resume(struct usb_interface * interface)154*5113495bSYour Name static int pld_usb_resume(struct usb_interface *interface)
155*5113495bSYour Name {
156*5113495bSYour Name 	struct pld_context *pld_context;
157*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
158*5113495bSYour Name 
159*5113495bSYour Name 	pld_context = pld_get_global_context();
160*5113495bSYour Name 	return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_USB);
161*5113495bSYour Name }
162*5113495bSYour Name 
163*5113495bSYour Name /**
164*5113495bSYour Name  * pld_usb_reset_resume() - pld_usb_reset_resume
165*5113495bSYour Name  * @interface: pointer to usb_interface for the usb device
166*5113495bSYour Name  *
167*5113495bSYour Name  * Return: void
168*5113495bSYour Name  */
pld_usb_reset_resume(struct usb_interface * interface)169*5113495bSYour Name static int pld_usb_reset_resume(struct usb_interface *interface)
170*5113495bSYour Name {
171*5113495bSYour Name 	struct pld_context *pld_context;
172*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
173*5113495bSYour Name 
174*5113495bSYour Name 	pld_context = pld_get_global_context();
175*5113495bSYour Name 	return pld_context->ops->reset_resume(&pdev->dev, PLD_BUS_TYPE_USB);
176*5113495bSYour Name }
177*5113495bSYour Name 
178*5113495bSYour Name #ifdef CONFIG_PLD_USB_CNSS
179*5113495bSYour Name /**
180*5113495bSYour Name  * pld_usb_reinit() - SSR re-initialize function for USB device
181*5113495bSYour Name  * @interface: Pointer to struct usb_interface
182*5113495bSYour Name  * @id: Pointer to USB device ID
183*5113495bSYour Name  *
184*5113495bSYour Name  * Return: int
185*5113495bSYour Name  */
pld_usb_reinit(struct usb_interface * interface,const struct usb_device_id * id)186*5113495bSYour Name static int pld_usb_reinit(struct usb_interface *interface,
187*5113495bSYour Name 			  const struct usb_device_id *id)
188*5113495bSYour Name {
189*5113495bSYour Name 	struct pld_context *pld_context;
190*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
191*5113495bSYour Name 
192*5113495bSYour Name 	pld_context = pld_get_global_context();
193*5113495bSYour Name 	if (pld_context->ops->reinit)
194*5113495bSYour Name 		return pld_context->ops->reinit(&pdev->dev, PLD_BUS_TYPE_USB,
195*5113495bSYour Name 						interface, (void *)id);
196*5113495bSYour Name 
197*5113495bSYour Name 	return -ENODEV;
198*5113495bSYour Name }
199*5113495bSYour Name 
200*5113495bSYour Name /**
201*5113495bSYour Name  * pld_usb_shutdown() - SSR shutdown function for USB device
202*5113495bSYour Name  * @interface: Pointer to struct usb_interface
203*5113495bSYour Name  *
204*5113495bSYour Name  * Return: void
205*5113495bSYour Name  */
pld_usb_shutdown(struct usb_interface * interface)206*5113495bSYour Name static void pld_usb_shutdown(struct usb_interface *interface)
207*5113495bSYour Name {
208*5113495bSYour Name 	struct pld_context *pld_context;
209*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
210*5113495bSYour Name 
211*5113495bSYour Name 	pld_context = pld_get_global_context();
212*5113495bSYour Name 	if (pld_context->ops->shutdown)
213*5113495bSYour Name 		pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_USB);
214*5113495bSYour Name }
215*5113495bSYour Name 
216*5113495bSYour Name /**
217*5113495bSYour Name  * pld_usb_uevent() - update wlan driver status callback function
218*5113495bSYour Name  * @interface: USB interface
219*5113495bSYour Name  * @status: driver uevent status
220*5113495bSYour Name  *
221*5113495bSYour Name  * This function will be called when platform driver wants to update wlan
222*5113495bSYour Name  * driver's status.
223*5113495bSYour Name  *
224*5113495bSYour Name  * Return: void
225*5113495bSYour Name  */
pld_usb_uevent(struct usb_interface * interface,uint32_t status)226*5113495bSYour Name static void pld_usb_uevent(struct usb_interface *interface, uint32_t status)
227*5113495bSYour Name {
228*5113495bSYour Name 	struct pld_context *pld_context;
229*5113495bSYour Name 	struct pld_uevent_data data = {0};
230*5113495bSYour Name 	struct usb_device *pdev = interface_to_usbdev(interface);
231*5113495bSYour Name 
232*5113495bSYour Name 	pld_context = pld_get_global_context();
233*5113495bSYour Name 	if (!pld_context)
234*5113495bSYour Name 		return;
235*5113495bSYour Name 
236*5113495bSYour Name 	switch (status) {
237*5113495bSYour Name 	case CNSS_RECOVERY:
238*5113495bSYour Name 		data.uevent = PLD_FW_RECOVERY_START;
239*5113495bSYour Name 		break;
240*5113495bSYour Name 	case CNSS_FW_DOWN:
241*5113495bSYour Name 		data.uevent = PLD_FW_DOWN;
242*5113495bSYour Name 		break;
243*5113495bSYour Name 	default:
244*5113495bSYour Name 		goto out;
245*5113495bSYour Name 	}
246*5113495bSYour Name 
247*5113495bSYour Name 	if (pld_context->ops->uevent)
248*5113495bSYour Name 		pld_context->ops->uevent(&pdev->dev, &data);
249*5113495bSYour Name 
250*5113495bSYour Name out:
251*5113495bSYour Name 	return;
252*5113495bSYour Name }
253*5113495bSYour Name struct cnss_usb_wlan_driver pld_usb_ops = {
254*5113495bSYour Name 	.name = "pld_usb_cnss",
255*5113495bSYour Name 	.id_table = pld_usb_id_table,
256*5113495bSYour Name 	.probe = pld_usb_probe,
257*5113495bSYour Name 	.remove = pld_usb_remove,
258*5113495bSYour Name 	.shutdown = pld_usb_shutdown,
259*5113495bSYour Name 	.reinit = pld_usb_reinit,
260*5113495bSYour Name 	.update_status  = pld_usb_uevent,
261*5113495bSYour Name #ifdef CONFIG_PM
262*5113495bSYour Name 	.suspend = pld_usb_suspend,
263*5113495bSYour Name 	.resume = pld_usb_resume,
264*5113495bSYour Name 	.reset_resume = pld_usb_reset_resume,
265*5113495bSYour Name #endif
266*5113495bSYour Name };
267*5113495bSYour Name 
pld_usb_register_driver(void)268*5113495bSYour Name int pld_usb_register_driver(void)
269*5113495bSYour Name {
270*5113495bSYour Name 	pr_info("%s usb_register\n", __func__);
271*5113495bSYour Name 	return cnss_usb_wlan_register_driver(&pld_usb_ops);
272*5113495bSYour Name }
273*5113495bSYour Name 
pld_usb_unregister_driver(void)274*5113495bSYour Name void pld_usb_unregister_driver(void)
275*5113495bSYour Name {
276*5113495bSYour Name 	cnss_usb_wlan_unregister_driver(&pld_usb_ops);
277*5113495bSYour Name 	pr_info("%s usb_deregister done!\n", __func__);
278*5113495bSYour Name }
279*5113495bSYour Name 
pld_usb_wlan_enable(struct device * dev,struct pld_wlan_enable_cfg * config,enum pld_driver_mode mode,const char * host_version)280*5113495bSYour Name int pld_usb_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
281*5113495bSYour Name 			enum pld_driver_mode mode, const char *host_version)
282*5113495bSYour Name {
283*5113495bSYour Name 	struct cnss_wlan_enable_cfg cfg;
284*5113495bSYour Name 	enum cnss_driver_mode cnss_mode;
285*5113495bSYour Name 
286*5113495bSYour Name 	switch (mode) {
287*5113495bSYour Name 	case PLD_FTM:
288*5113495bSYour Name 		cnss_mode = CNSS_FTM;
289*5113495bSYour Name 		break;
290*5113495bSYour Name 	case PLD_EPPING:
291*5113495bSYour Name 		cnss_mode = CNSS_EPPING;
292*5113495bSYour Name 		break;
293*5113495bSYour Name 	default:
294*5113495bSYour Name 		cnss_mode = CNSS_MISSION;
295*5113495bSYour Name 		break;
296*5113495bSYour Name 	}
297*5113495bSYour Name 	return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version);
298*5113495bSYour Name }
299*5113495bSYour Name 
pld_usb_is_fw_down(struct device * dev)300*5113495bSYour Name int pld_usb_is_fw_down(struct device *dev)
301*5113495bSYour Name {
302*5113495bSYour Name 	return cnss_usb_is_device_down(dev);
303*5113495bSYour Name }
304*5113495bSYour Name 
pld_usb_athdiag_read(struct device * dev,uint32_t offset,uint32_t memtype,uint32_t datalen,uint8_t * output)305*5113495bSYour Name int pld_usb_athdiag_read(struct device *dev, uint32_t offset,
306*5113495bSYour Name 			 uint32_t memtype, uint32_t datalen,
307*5113495bSYour Name 			 uint8_t *output)
308*5113495bSYour Name {
309*5113495bSYour Name 	return cnss_athdiag_read(dev, offset, memtype, datalen, output);
310*5113495bSYour Name }
311*5113495bSYour Name 
pld_usb_athdiag_write(struct device * dev,uint32_t offset,uint32_t memtype,uint32_t datalen,uint8_t * input)312*5113495bSYour Name int pld_usb_athdiag_write(struct device *dev, uint32_t offset,
313*5113495bSYour Name 			  uint32_t memtype, uint32_t datalen,
314*5113495bSYour Name 			  uint8_t *input)
315*5113495bSYour Name {
316*5113495bSYour Name 	return cnss_athdiag_write(dev, offset, memtype, datalen, input);
317*5113495bSYour Name }
318*5113495bSYour Name 
319*5113495bSYour Name #else /* CONFIG_PLD_USB_CNSS */
320*5113495bSYour Name 
321*5113495bSYour Name struct usb_driver pld_usb_ops = {
322*5113495bSYour Name 	.name = "pld_usb",
323*5113495bSYour Name 	.id_table = pld_usb_id_table,
324*5113495bSYour Name 	.probe = pld_usb_probe,
325*5113495bSYour Name 	.disconnect = pld_usb_remove,
326*5113495bSYour Name #ifdef CONFIG_PM
327*5113495bSYour Name 	.suspend = pld_usb_suspend,
328*5113495bSYour Name 	.resume = pld_usb_resume,
329*5113495bSYour Name 	.reset_resume = pld_usb_reset_resume,
330*5113495bSYour Name #endif
331*5113495bSYour Name 	.supports_autosuspend = true,
332*5113495bSYour Name };
333*5113495bSYour Name 
pld_usb_register_driver(void)334*5113495bSYour Name int pld_usb_register_driver(void)
335*5113495bSYour Name {
336*5113495bSYour Name 	int status;
337*5113495bSYour Name 
338*5113495bSYour Name 	usb_register(&pld_usb_ops);
339*5113495bSYour Name 
340*5113495bSYour Name 	if (atomic_read(&pld_usb_reg_done) == true) {
341*5113495bSYour Name 		status = 0;
342*5113495bSYour Name 	} else {
343*5113495bSYour Name 		usb_deregister(&pld_usb_ops);
344*5113495bSYour Name 		status = -1;
345*5113495bSYour Name 	}
346*5113495bSYour Name 
347*5113495bSYour Name 	pr_info("%s usb_register %s, status %d\n", __func__,
348*5113495bSYour Name 		(status == 0) ? "done" : "failed", status);
349*5113495bSYour Name 
350*5113495bSYour Name 	return status;
351*5113495bSYour Name }
352*5113495bSYour Name 
pld_usb_unregister_driver(void)353*5113495bSYour Name void pld_usb_unregister_driver(void)
354*5113495bSYour Name {
355*5113495bSYour Name 	struct pld_context *pld_context;
356*5113495bSYour Name 
357*5113495bSYour Name 	pld_context = pld_get_global_context();
358*5113495bSYour Name 	if (atomic_read(&pld_usb_reg_done) == false)
359*5113495bSYour Name 		return;
360*5113495bSYour Name 
361*5113495bSYour Name 	pld_context->ops->remove(NULL, PLD_BUS_TYPE_USB);
362*5113495bSYour Name 
363*5113495bSYour Name 	atomic_set(&pld_usb_reg_done, false);
364*5113495bSYour Name 	usb_deregister(&pld_usb_ops);
365*5113495bSYour Name 	pr_info("%s usb_deregister done!\n", __func__);
366*5113495bSYour Name }
367*5113495bSYour Name 
pld_usb_wlan_enable(struct device * dev,struct pld_wlan_enable_cfg * config,enum pld_driver_mode mode,const char * host_version)368*5113495bSYour Name int pld_usb_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
369*5113495bSYour Name 			enum pld_driver_mode mode, const char *host_version)
370*5113495bSYour Name {
371*5113495bSYour Name 	return 0;
372*5113495bSYour Name }
373*5113495bSYour Name 
pld_usb_is_fw_down(struct device * dev)374*5113495bSYour Name int pld_usb_is_fw_down(struct device *dev)
375*5113495bSYour Name {
376*5113495bSYour Name 	return 0;
377*5113495bSYour Name }
378*5113495bSYour Name 
pld_usb_athdiag_read(struct device * dev,uint32_t offset,uint32_t memtype,uint32_t datalen,uint8_t * output)379*5113495bSYour Name int pld_usb_athdiag_read(struct device *dev, uint32_t offset,
380*5113495bSYour Name 			 uint32_t memtype, uint32_t datalen,
381*5113495bSYour Name 			 uint8_t *output)
382*5113495bSYour Name {
383*5113495bSYour Name 	return 0;
384*5113495bSYour Name }
385*5113495bSYour Name 
pld_usb_athdiag_write(struct device * dev,uint32_t offset,uint32_t memtype,uint32_t datalen,uint8_t * input)386*5113495bSYour Name int pld_usb_athdiag_write(struct device *dev, uint32_t offset,
387*5113495bSYour Name 			  uint32_t memtype, uint32_t datalen,
388*5113495bSYour Name 			  uint8_t *input)
389*5113495bSYour Name {
390*5113495bSYour Name 	return 0;
391*5113495bSYour Name }
392*5113495bSYour Name 
393*5113495bSYour Name #endif /* CONFIG_PLD_USB_CNSS */
394