1dad0d04fSFariya Fatima /** 2dad0d04fSFariya Fatima * Copyright (c) 2014 Redpine Signals Inc. 3dad0d04fSFariya Fatima * 4dad0d04fSFariya Fatima * Permission to use, copy, modify, and/or distribute this software for any 5dad0d04fSFariya Fatima * purpose with or without fee is hereby granted, provided that the above 6dad0d04fSFariya Fatima * copyright notice and this permission notice appear in all copies. 7dad0d04fSFariya Fatima * 8dad0d04fSFariya Fatima * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9dad0d04fSFariya Fatima * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10dad0d04fSFariya Fatima * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11dad0d04fSFariya Fatima * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12dad0d04fSFariya Fatima * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13dad0d04fSFariya Fatima * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14dad0d04fSFariya Fatima * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15dad0d04fSFariya Fatima * 16dad0d04fSFariya Fatima */ 17dad0d04fSFariya Fatima 18dad0d04fSFariya Fatima #include <linux/module.h> 192108df3cSPrameela Rani Garnepudi #include <net/rsi_91x.h> 20dad0d04fSFariya Fatima #include "rsi_usb.h" 21b78e91bcSPrameela Rani Garnepudi #include "rsi_hal.h" 222108df3cSPrameela Rani Garnepudi #include "rsi_coex.h" 23dad0d04fSFariya Fatima 24898b2553SPrameela Rani Garnepudi /* Default operating mode is wlan STA + BT */ 25898b2553SPrameela Rani Garnepudi static u16 dev_oper_mode = DEV_OPMODE_STA_BT_DUAL; 26898b2553SPrameela Rani Garnepudi module_param(dev_oper_mode, ushort, 0444); 27898b2553SPrameela Rani Garnepudi MODULE_PARM_DESC(dev_oper_mode, 28898b2553SPrameela Rani Garnepudi "1[Wi-Fi], 4[BT], 8[BT LE], 5[Wi-Fi STA + BT classic]\n" 29898b2553SPrameela Rani Garnepudi "9[Wi-Fi STA + BT LE], 13[Wi-Fi STA + BT classic + BT LE]\n" 30898b2553SPrameela Rani Garnepudi "6[AP + BT classic], 14[AP + BT classic + BT LE]"); 31898b2553SPrameela Rani Garnepudi 32a1854faeSPrameela Rani Garnepudi static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num); 33a1854faeSPrameela Rani Garnepudi 34dad0d04fSFariya Fatima /** 35dad0d04fSFariya Fatima * rsi_usb_card_write() - This function writes to the USB Card. 36dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 37dad0d04fSFariya Fatima * @buf: Pointer to the buffer from where the data has to be taken. 38dad0d04fSFariya Fatima * @len: Length to be written. 39dad0d04fSFariya Fatima * @endpoint: Type of endpoint. 40dad0d04fSFariya Fatima * 4150591c60SAlexey Khoroshilov * Return: status: 0 on success, a negative error code on failure. 42dad0d04fSFariya Fatima */ 43dad0d04fSFariya Fatima static int rsi_usb_card_write(struct rsi_hw *adapter, 44ed833be6SKarun Eagalapati u8 *buf, 45dad0d04fSFariya Fatima u16 len, 46dad0d04fSFariya Fatima u8 endpoint) 47dad0d04fSFariya Fatima { 48dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 49dad0d04fSFariya Fatima int status; 50ed833be6SKarun Eagalapati u8 *seg = dev->tx_buffer; 51ed833be6SKarun Eagalapati int transfer; 52ed833be6SKarun Eagalapati int ep = dev->bulkout_endpoint_addr[endpoint - 1]; 53dad0d04fSFariya Fatima 54ed833be6SKarun Eagalapati memset(seg, 0, len + RSI_USB_TX_HEAD_ROOM); 55ed833be6SKarun Eagalapati memcpy(seg + RSI_USB_TX_HEAD_ROOM, buf, len); 56ed833be6SKarun Eagalapati len += RSI_USB_TX_HEAD_ROOM; 57ed833be6SKarun Eagalapati transfer = len; 58dad0d04fSFariya Fatima status = usb_bulk_msg(dev->usbdev, 59ed833be6SKarun Eagalapati usb_sndbulkpipe(dev->usbdev, ep), 60ed833be6SKarun Eagalapati (void *)seg, 61ed833be6SKarun Eagalapati (int)len, 62dad0d04fSFariya Fatima &transfer, 63dad0d04fSFariya Fatima HZ * 5); 64dad0d04fSFariya Fatima 65dad0d04fSFariya Fatima if (status < 0) { 66dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, 67dad0d04fSFariya Fatima "Card write failed with error code :%10d\n", status); 68dad0d04fSFariya Fatima dev->write_fail = 1; 69dad0d04fSFariya Fatima } 70dad0d04fSFariya Fatima return status; 71dad0d04fSFariya Fatima } 72dad0d04fSFariya Fatima 73dad0d04fSFariya Fatima /** 74dad0d04fSFariya Fatima * rsi_write_multiple() - This function writes multiple bytes of information 75dad0d04fSFariya Fatima * to the USB card. 76dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 77dad0d04fSFariya Fatima * @addr: Address of the register. 78dad0d04fSFariya Fatima * @data: Pointer to the data that has to be written. 79dad0d04fSFariya Fatima * @count: Number of multiple bytes to be written. 80dad0d04fSFariya Fatima * 8150591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 82dad0d04fSFariya Fatima */ 83dad0d04fSFariya Fatima static int rsi_write_multiple(struct rsi_hw *adapter, 84dad0d04fSFariya Fatima u8 endpoint, 85dad0d04fSFariya Fatima u8 *data, 86dad0d04fSFariya Fatima u32 count) 87dad0d04fSFariya Fatima { 886508497cSColin Ian King struct rsi_91x_usbdev *dev; 89ed833be6SKarun Eagalapati 90ed833be6SKarun Eagalapati if (!adapter) 91ed833be6SKarun Eagalapati return -ENODEV; 92ed833be6SKarun Eagalapati 93ed833be6SKarun Eagalapati if (endpoint == 0) 94ed833be6SKarun Eagalapati return -EINVAL; 95dad0d04fSFariya Fatima 966508497cSColin Ian King dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 97dad0d04fSFariya Fatima if (dev->write_fail) 98ed833be6SKarun Eagalapati return -ENETDOWN; 99dad0d04fSFariya Fatima 100ed833be6SKarun Eagalapati return rsi_usb_card_write(adapter, data, count, endpoint); 101dad0d04fSFariya Fatima } 102dad0d04fSFariya Fatima 103dad0d04fSFariya Fatima /** 104dad0d04fSFariya Fatima * rsi_find_bulk_in_and_out_endpoints() - This function initializes the bulk 105dad0d04fSFariya Fatima * endpoints to the device. 106dad0d04fSFariya Fatima * @interface: Pointer to the USB interface structure. 107dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 108dad0d04fSFariya Fatima * 109dad0d04fSFariya Fatima * Return: ret_val: 0 on success, -ENOMEM on failure. 110dad0d04fSFariya Fatima */ 111dad0d04fSFariya Fatima static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, 112dad0d04fSFariya Fatima struct rsi_hw *adapter) 113dad0d04fSFariya Fatima { 114dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 115dad0d04fSFariya Fatima struct usb_host_interface *iface_desc; 116dad0d04fSFariya Fatima struct usb_endpoint_descriptor *endpoint; 117dad0d04fSFariya Fatima __le16 buffer_size; 118a4302bffSSiva Rebbagondla int ii, bin_found = 0, bout_found = 0; 119dad0d04fSFariya Fatima 120dad0d04fSFariya Fatima iface_desc = &(interface->altsetting[0]); 121dad0d04fSFariya Fatima 122dad0d04fSFariya Fatima for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) { 123dad0d04fSFariya Fatima endpoint = &(iface_desc->endpoint[ii].desc); 124dad0d04fSFariya Fatima 125a4302bffSSiva Rebbagondla if (!dev->bulkin_endpoint_addr[bin_found] && 126dad0d04fSFariya Fatima (endpoint->bEndpointAddress & USB_DIR_IN) && 127a4302bffSSiva Rebbagondla ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 128dad0d04fSFariya Fatima USB_ENDPOINT_XFER_BULK)) { 129dad0d04fSFariya Fatima buffer_size = endpoint->wMaxPacketSize; 130a4302bffSSiva Rebbagondla dev->bulkin_size[bin_found] = buffer_size; 131a4302bffSSiva Rebbagondla dev->bulkin_endpoint_addr[bin_found] = 132dad0d04fSFariya Fatima endpoint->bEndpointAddress; 133a4302bffSSiva Rebbagondla bin_found++; 134dad0d04fSFariya Fatima } 135dad0d04fSFariya Fatima 136a4302bffSSiva Rebbagondla if (!dev->bulkout_endpoint_addr[bout_found] && 137dad0d04fSFariya Fatima !(endpoint->bEndpointAddress & USB_DIR_IN) && 138dad0d04fSFariya Fatima ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 139dad0d04fSFariya Fatima USB_ENDPOINT_XFER_BULK)) { 140a4302bffSSiva Rebbagondla buffer_size = endpoint->wMaxPacketSize; 141a4302bffSSiva Rebbagondla dev->bulkout_endpoint_addr[bout_found] = 142dad0d04fSFariya Fatima endpoint->bEndpointAddress; 143a4302bffSSiva Rebbagondla dev->bulkout_size[bout_found] = buffer_size; 144a4302bffSSiva Rebbagondla bout_found++; 145dad0d04fSFariya Fatima } 146dad0d04fSFariya Fatima 147a4302bffSSiva Rebbagondla if (bin_found >= MAX_BULK_EP || bout_found >= MAX_BULK_EP) 148dad0d04fSFariya Fatima break; 149dad0d04fSFariya Fatima } 150dad0d04fSFariya Fatima 151a4302bffSSiva Rebbagondla if (!(dev->bulkin_endpoint_addr[0]) && 152a4302bffSSiva Rebbagondla dev->bulkout_endpoint_addr[0]) 153dad0d04fSFariya Fatima return -EINVAL; 154dad0d04fSFariya Fatima 155dad0d04fSFariya Fatima return 0; 156dad0d04fSFariya Fatima } 157dad0d04fSFariya Fatima 1584b1fc881SPrameela Rani Garnepudi #define RSI_USB_REQ_OUT (USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE) 1594b1fc881SPrameela Rani Garnepudi #define RSI_USB_REQ_IN (USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE) 1604b1fc881SPrameela Rani Garnepudi 161dad0d04fSFariya Fatima /* rsi_usb_reg_read() - This function reads data from given register address. 162dad0d04fSFariya Fatima * @usbdev: Pointer to the usb_device structure. 163dad0d04fSFariya Fatima * @reg: Address of the register to be read. 164dad0d04fSFariya Fatima * @value: Value to be read. 165dad0d04fSFariya Fatima * @len: length of data to be read. 166dad0d04fSFariya Fatima * 16750591c60SAlexey Khoroshilov * Return: status: 0 on success, a negative error code on failure. 168dad0d04fSFariya Fatima */ 169dad0d04fSFariya Fatima static int rsi_usb_reg_read(struct usb_device *usbdev, 170dad0d04fSFariya Fatima u32 reg, 171dad0d04fSFariya Fatima u16 *value, 172dad0d04fSFariya Fatima u16 len) 173dad0d04fSFariya Fatima { 174d453ba81SFariya Fatima u8 *buf; 175d453ba81SFariya Fatima int status = -ENOMEM; 176d453ba81SFariya Fatima 177d35ef8f8SColin Ian King if (len > RSI_USB_CTRL_BUF_SIZE) 178d35ef8f8SColin Ian King return -EINVAL; 179d35ef8f8SColin Ian King 180523b724aSAmitkumar Karwar buf = kmalloc(RSI_USB_CTRL_BUF_SIZE, GFP_KERNEL); 181d453ba81SFariya Fatima if (!buf) 182d453ba81SFariya Fatima return status; 183dad0d04fSFariya Fatima 184dad0d04fSFariya Fatima status = usb_control_msg(usbdev, 185dad0d04fSFariya Fatima usb_rcvctrlpipe(usbdev, 0), 186dad0d04fSFariya Fatima USB_VENDOR_REGISTER_READ, 1874b1fc881SPrameela Rani Garnepudi RSI_USB_REQ_IN, 188dad0d04fSFariya Fatima ((reg & 0xffff0000) >> 16), (reg & 0xffff), 189d453ba81SFariya Fatima (void *)buf, 190dad0d04fSFariya Fatima len, 1914b1fc881SPrameela Rani Garnepudi USB_CTRL_GET_TIMEOUT); 192dad0d04fSFariya Fatima 193d453ba81SFariya Fatima *value = (buf[0] | (buf[1] << 8)); 194dad0d04fSFariya Fatima if (status < 0) { 195dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, 196dad0d04fSFariya Fatima "%s: Reg read failed with error code :%d\n", 197dad0d04fSFariya Fatima __func__, status); 198dad0d04fSFariya Fatima } 199d453ba81SFariya Fatima kfree(buf); 200d453ba81SFariya Fatima 201dad0d04fSFariya Fatima return status; 202dad0d04fSFariya Fatima } 203dad0d04fSFariya Fatima 204dad0d04fSFariya Fatima /** 205dad0d04fSFariya Fatima * rsi_usb_reg_write() - This function writes the given data into the given 206dad0d04fSFariya Fatima * register address. 207dad0d04fSFariya Fatima * @usbdev: Pointer to the usb_device structure. 208dad0d04fSFariya Fatima * @reg: Address of the register. 209dad0d04fSFariya Fatima * @value: Value to write. 210dad0d04fSFariya Fatima * @len: Length of data to be written. 211dad0d04fSFariya Fatima * 21250591c60SAlexey Khoroshilov * Return: status: 0 on success, a negative error code on failure. 213dad0d04fSFariya Fatima */ 214dad0d04fSFariya Fatima static int rsi_usb_reg_write(struct usb_device *usbdev, 215dad0d04fSFariya Fatima u32 reg, 216dad0d04fSFariya Fatima u16 value, 217dad0d04fSFariya Fatima u16 len) 218dad0d04fSFariya Fatima { 219d453ba81SFariya Fatima u8 *usb_reg_buf; 220d453ba81SFariya Fatima int status = -ENOMEM; 221d453ba81SFariya Fatima 222d35ef8f8SColin Ian King if (len > RSI_USB_CTRL_BUF_SIZE) 223d35ef8f8SColin Ian King return -EINVAL; 224d35ef8f8SColin Ian King 225523b724aSAmitkumar Karwar usb_reg_buf = kmalloc(RSI_USB_CTRL_BUF_SIZE, GFP_KERNEL); 226d453ba81SFariya Fatima if (!usb_reg_buf) 227d453ba81SFariya Fatima return status; 228dad0d04fSFariya Fatima 229dad0d04fSFariya Fatima usb_reg_buf[0] = (value & 0x00ff); 230dad0d04fSFariya Fatima usb_reg_buf[1] = (value & 0xff00) >> 8; 231dad0d04fSFariya Fatima usb_reg_buf[2] = 0x0; 232dad0d04fSFariya Fatima usb_reg_buf[3] = 0x0; 233dad0d04fSFariya Fatima 234dad0d04fSFariya Fatima status = usb_control_msg(usbdev, 235dad0d04fSFariya Fatima usb_sndctrlpipe(usbdev, 0), 236dad0d04fSFariya Fatima USB_VENDOR_REGISTER_WRITE, 2374b1fc881SPrameela Rani Garnepudi RSI_USB_REQ_OUT, 238dad0d04fSFariya Fatima ((reg & 0xffff0000) >> 16), 239dad0d04fSFariya Fatima (reg & 0xffff), 240dad0d04fSFariya Fatima (void *)usb_reg_buf, 241dad0d04fSFariya Fatima len, 2424b1fc881SPrameela Rani Garnepudi USB_CTRL_SET_TIMEOUT); 243dad0d04fSFariya Fatima if (status < 0) { 244dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, 245dad0d04fSFariya Fatima "%s: Reg write failed with error code :%d\n", 246dad0d04fSFariya Fatima __func__, status); 247dad0d04fSFariya Fatima } 248d453ba81SFariya Fatima kfree(usb_reg_buf); 249d453ba81SFariya Fatima 250dad0d04fSFariya Fatima return status; 251dad0d04fSFariya Fatima } 252dad0d04fSFariya Fatima 253dad0d04fSFariya Fatima /** 254dad0d04fSFariya Fatima * rsi_rx_done_handler() - This function is called when a packet is received 255b9c767fdSSiva Rebbagondla * from USB stack. This is callback to receive done. 256dad0d04fSFariya Fatima * @urb: Received URB. 257dad0d04fSFariya Fatima * 258dad0d04fSFariya Fatima * Return: None. 259dad0d04fSFariya Fatima */ 260dad0d04fSFariya Fatima static void rsi_rx_done_handler(struct urb *urb) 261dad0d04fSFariya Fatima { 2621100f81bSPrameela Rani Garnepudi struct rx_usb_ctrl_block *rx_cb = urb->context; 2631100f81bSPrameela Rani Garnepudi struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)rx_cb->data; 264a1854faeSPrameela Rani Garnepudi int status = -EINVAL; 265dad0d04fSFariya Fatima 266dad0d04fSFariya Fatima if (urb->status) 267a1854faeSPrameela Rani Garnepudi goto out; 268dad0d04fSFariya Fatima 269baa8caf4SSiva Rebbagondla if (urb->actual_length <= 0 || 270baa8caf4SSiva Rebbagondla urb->actual_length > rx_cb->rx_skb->len) { 271baa8caf4SSiva Rebbagondla rsi_dbg(INFO_ZONE, "%s: Invalid packet length = %d\n", 272baa8caf4SSiva Rebbagondla __func__, urb->actual_length); 273a1854faeSPrameela Rani Garnepudi goto out; 274a1854faeSPrameela Rani Garnepudi } 275a1854faeSPrameela Rani Garnepudi if (skb_queue_len(&dev->rx_q) >= RSI_MAX_RX_PKTS) { 276a1854faeSPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, "Max RX packets reached\n"); 277a1854faeSPrameela Rani Garnepudi goto out; 278a1854faeSPrameela Rani Garnepudi } 279baa8caf4SSiva Rebbagondla skb_trim(rx_cb->rx_skb, urb->actual_length); 280a1854faeSPrameela Rani Garnepudi skb_queue_tail(&dev->rx_q, rx_cb->rx_skb); 281a1854faeSPrameela Rani Garnepudi 282dad0d04fSFariya Fatima rsi_set_event(&dev->rx_thread.event); 283a1854faeSPrameela Rani Garnepudi status = 0; 284a1854faeSPrameela Rani Garnepudi 285a1854faeSPrameela Rani Garnepudi out: 286a1854faeSPrameela Rani Garnepudi if (rsi_rx_urb_submit(dev->priv, rx_cb->ep_num)) 287a1854faeSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__); 288a1854faeSPrameela Rani Garnepudi 289a1854faeSPrameela Rani Garnepudi if (status) 290a1854faeSPrameela Rani Garnepudi dev_kfree_skb(rx_cb->rx_skb); 291dad0d04fSFariya Fatima } 292dad0d04fSFariya Fatima 293dad0d04fSFariya Fatima /** 294dad0d04fSFariya Fatima * rsi_rx_urb_submit() - This function submits the given URB to the USB stack. 295dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 296dad0d04fSFariya Fatima * 29750591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 298dad0d04fSFariya Fatima */ 2991100f81bSPrameela Rani Garnepudi static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num) 300dad0d04fSFariya Fatima { 301dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 3021100f81bSPrameela Rani Garnepudi struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1]; 3031100f81bSPrameela Rani Garnepudi struct urb *urb = rx_cb->rx_urb; 304dad0d04fSFariya Fatima int status; 305a1854faeSPrameela Rani Garnepudi struct sk_buff *skb; 306a1854faeSPrameela Rani Garnepudi u8 dword_align_bytes = 0; 307a1854faeSPrameela Rani Garnepudi 308a1854faeSPrameela Rani Garnepudi #define RSI_MAX_RX_USB_PKT_SIZE 3000 309a1854faeSPrameela Rani Garnepudi skb = dev_alloc_skb(RSI_MAX_RX_USB_PKT_SIZE); 310a1854faeSPrameela Rani Garnepudi if (!skb) 311a1854faeSPrameela Rani Garnepudi return -ENOMEM; 312a1854faeSPrameela Rani Garnepudi skb_reserve(skb, MAX_DWORD_ALIGN_BYTES); 313baa8caf4SSiva Rebbagondla skb_put(skb, RSI_MAX_RX_USB_PKT_SIZE - MAX_DWORD_ALIGN_BYTES); 314a1854faeSPrameela Rani Garnepudi dword_align_bytes = (unsigned long)skb->data & 0x3f; 315a1854faeSPrameela Rani Garnepudi if (dword_align_bytes > 0) 316a1854faeSPrameela Rani Garnepudi skb_push(skb, dword_align_bytes); 317a1854faeSPrameela Rani Garnepudi urb->transfer_buffer = skb->data; 318a1854faeSPrameela Rani Garnepudi rx_cb->rx_skb = skb; 319dad0d04fSFariya Fatima 320dad0d04fSFariya Fatima usb_fill_bulk_urb(urb, 321dad0d04fSFariya Fatima dev->usbdev, 322dad0d04fSFariya Fatima usb_rcvbulkpipe(dev->usbdev, 323a4302bffSSiva Rebbagondla dev->bulkin_endpoint_addr[ep_num - 1]), 324dad0d04fSFariya Fatima urb->transfer_buffer, 325baa8caf4SSiva Rebbagondla skb->len, 326dad0d04fSFariya Fatima rsi_rx_done_handler, 3271100f81bSPrameela Rani Garnepudi rx_cb); 328dad0d04fSFariya Fatima 329dad0d04fSFariya Fatima status = usb_submit_urb(urb, GFP_KERNEL); 330dad0d04fSFariya Fatima if (status) 331dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed in urb submission\n", __func__); 332dad0d04fSFariya Fatima 333dad0d04fSFariya Fatima return status; 334dad0d04fSFariya Fatima } 335dad0d04fSFariya Fatima 33688fa51e1SPrameela Rani Garnepudi static int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr, 33788fa51e1SPrameela Rani Garnepudi u8 *data, u16 count) 33888fa51e1SPrameela Rani Garnepudi { 33988fa51e1SPrameela Rani Garnepudi struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 34088fa51e1SPrameela Rani Garnepudi u8 *buf; 34188fa51e1SPrameela Rani Garnepudi u16 transfer; 34288fa51e1SPrameela Rani Garnepudi int status; 34388fa51e1SPrameela Rani Garnepudi 34488fa51e1SPrameela Rani Garnepudi if (!addr) 34588fa51e1SPrameela Rani Garnepudi return -EINVAL; 34688fa51e1SPrameela Rani Garnepudi 34788fa51e1SPrameela Rani Garnepudi buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); 34888fa51e1SPrameela Rani Garnepudi if (!buf) 34988fa51e1SPrameela Rani Garnepudi return -ENOMEM; 35088fa51e1SPrameela Rani Garnepudi 35188fa51e1SPrameela Rani Garnepudi while (count) { 35288fa51e1SPrameela Rani Garnepudi transfer = min_t(u16, count, RSI_USB_BUF_SIZE); 35388fa51e1SPrameela Rani Garnepudi status = usb_control_msg(dev->usbdev, 35488fa51e1SPrameela Rani Garnepudi usb_rcvctrlpipe(dev->usbdev, 0), 35588fa51e1SPrameela Rani Garnepudi USB_VENDOR_REGISTER_READ, 35688fa51e1SPrameela Rani Garnepudi RSI_USB_REQ_IN, 35788fa51e1SPrameela Rani Garnepudi ((addr & 0xffff0000) >> 16), 35888fa51e1SPrameela Rani Garnepudi (addr & 0xffff), (void *)buf, 35988fa51e1SPrameela Rani Garnepudi transfer, USB_CTRL_GET_TIMEOUT); 36088fa51e1SPrameela Rani Garnepudi if (status < 0) { 36188fa51e1SPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, 36288fa51e1SPrameela Rani Garnepudi "Reg read failed with error code :%d\n", 36388fa51e1SPrameela Rani Garnepudi status); 36488fa51e1SPrameela Rani Garnepudi kfree(buf); 36588fa51e1SPrameela Rani Garnepudi return status; 36688fa51e1SPrameela Rani Garnepudi } 36788fa51e1SPrameela Rani Garnepudi memcpy(data, buf, transfer); 36888fa51e1SPrameela Rani Garnepudi count -= transfer; 36988fa51e1SPrameela Rani Garnepudi data += transfer; 37088fa51e1SPrameela Rani Garnepudi addr += transfer; 37188fa51e1SPrameela Rani Garnepudi } 37288fa51e1SPrameela Rani Garnepudi kfree(buf); 37388fa51e1SPrameela Rani Garnepudi return 0; 37488fa51e1SPrameela Rani Garnepudi } 37588fa51e1SPrameela Rani Garnepudi 376dad0d04fSFariya Fatima /** 377dad0d04fSFariya Fatima * rsi_usb_write_register_multiple() - This function writes multiple bytes of 378dad0d04fSFariya Fatima * information to multiple registers. 379dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 380dad0d04fSFariya Fatima * @addr: Address of the register. 381dad0d04fSFariya Fatima * @data: Pointer to the data that has to be written. 382dad0d04fSFariya Fatima * @count: Number of multiple bytes to be written on to the registers. 383dad0d04fSFariya Fatima * 38450591c60SAlexey Khoroshilov * Return: status: 0 on success, a negative error code on failure. 385dad0d04fSFariya Fatima */ 3865578b1ffSPrameela Rani Garnepudi static int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, 3875578b1ffSPrameela Rani Garnepudi u8 *data, u16 count) 388dad0d04fSFariya Fatima { 389dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 390dad0d04fSFariya Fatima u8 *buf; 3912fbbe517SPrameela Rani Garnepudi u16 transfer; 392dad0d04fSFariya Fatima int status = 0; 393dad0d04fSFariya Fatima 3947bdead7aSamit karwar buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); 395dad0d04fSFariya Fatima if (!buf) 396dad0d04fSFariya Fatima return -ENOMEM; 397dad0d04fSFariya Fatima 398dad0d04fSFariya Fatima while (count) { 3992fbbe517SPrameela Rani Garnepudi transfer = min_t(u16, count, RSI_USB_BUF_SIZE); 400dad0d04fSFariya Fatima memcpy(buf, data, transfer); 401dad0d04fSFariya Fatima status = usb_control_msg(dev->usbdev, 402dad0d04fSFariya Fatima usb_sndctrlpipe(dev->usbdev, 0), 403dad0d04fSFariya Fatima USB_VENDOR_REGISTER_WRITE, 4044b1fc881SPrameela Rani Garnepudi RSI_USB_REQ_OUT, 405dad0d04fSFariya Fatima ((addr & 0xffff0000) >> 16), 406dad0d04fSFariya Fatima (addr & 0xffff), 407dad0d04fSFariya Fatima (void *)buf, 408dad0d04fSFariya Fatima transfer, 4094b1fc881SPrameela Rani Garnepudi USB_CTRL_SET_TIMEOUT); 410dad0d04fSFariya Fatima if (status < 0) { 411dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, 412dad0d04fSFariya Fatima "Reg write failed with error code :%d\n", 413dad0d04fSFariya Fatima status); 414ea3336acSPrameela Rani Garnepudi kfree(buf); 415ea3336acSPrameela Rani Garnepudi return status; 416ea3336acSPrameela Rani Garnepudi } 417dad0d04fSFariya Fatima count -= transfer; 418dad0d04fSFariya Fatima data += transfer; 419dad0d04fSFariya Fatima addr += transfer; 420dad0d04fSFariya Fatima } 421dad0d04fSFariya Fatima 422dad0d04fSFariya Fatima kfree(buf); 423dad0d04fSFariya Fatima return 0; 424dad0d04fSFariya Fatima } 425dad0d04fSFariya Fatima 426dad0d04fSFariya Fatima /** 427dad0d04fSFariya Fatima *rsi_usb_host_intf_write_pkt() - This function writes the packet to the 428dad0d04fSFariya Fatima * USB card. 429dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 430dad0d04fSFariya Fatima * @pkt: Pointer to the data to be written on to the card. 431dad0d04fSFariya Fatima * @len: Length of the data to be written on to the card. 432dad0d04fSFariya Fatima * 43350591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 434dad0d04fSFariya Fatima */ 435dad0d04fSFariya Fatima static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, 436dad0d04fSFariya Fatima u8 *pkt, 437dad0d04fSFariya Fatima u32 len) 438dad0d04fSFariya Fatima { 439ac6107caSAmitkumar Karwar u32 queueno = ((pkt[1] >> 4) & 0x7); 440dad0d04fSFariya Fatima u8 endpoint; 441dad0d04fSFariya Fatima 442d1f69e41SKarun Eagalapati endpoint = ((queueno == RSI_WIFI_MGMT_Q || queueno == RSI_WIFI_DATA_Q || 443d1f69e41SKarun Eagalapati queueno == RSI_COEX_Q) ? WLAN_EP : BT_EP); 444dad0d04fSFariya Fatima 445dad0d04fSFariya Fatima return rsi_write_multiple(adapter, 446dad0d04fSFariya Fatima endpoint, 447dad0d04fSFariya Fatima (u8 *)pkt, 448dad0d04fSFariya Fatima len); 449dad0d04fSFariya Fatima } 450dad0d04fSFariya Fatima 451b97e9b94SPrameela Rani Garnepudi static int rsi_usb_master_reg_read(struct rsi_hw *adapter, u32 reg, 452b97e9b94SPrameela Rani Garnepudi u32 *value, u16 len) 453b97e9b94SPrameela Rani Garnepudi { 454b97e9b94SPrameela Rani Garnepudi struct usb_device *usbdev = 455b97e9b94SPrameela Rani Garnepudi ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; 456e6249e15SAmitkumar Karwar u16 temp; 457e6249e15SAmitkumar Karwar int ret; 458b97e9b94SPrameela Rani Garnepudi 459e6249e15SAmitkumar Karwar ret = rsi_usb_reg_read(usbdev, reg, &temp, len); 460e6249e15SAmitkumar Karwar if (ret < 0) 461e6249e15SAmitkumar Karwar return ret; 462e6249e15SAmitkumar Karwar *value = temp; 463e6249e15SAmitkumar Karwar 464e6249e15SAmitkumar Karwar return 0; 465b97e9b94SPrameela Rani Garnepudi } 466b97e9b94SPrameela Rani Garnepudi 467b97e9b94SPrameela Rani Garnepudi static int rsi_usb_master_reg_write(struct rsi_hw *adapter, 468b97e9b94SPrameela Rani Garnepudi unsigned long reg, 469b97e9b94SPrameela Rani Garnepudi unsigned long value, u16 len) 470b97e9b94SPrameela Rani Garnepudi { 471b97e9b94SPrameela Rani Garnepudi struct usb_device *usbdev = 472b97e9b94SPrameela Rani Garnepudi ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; 473b97e9b94SPrameela Rani Garnepudi 474b97e9b94SPrameela Rani Garnepudi return rsi_usb_reg_write(usbdev, reg, value, len); 475b97e9b94SPrameela Rani Garnepudi } 476b97e9b94SPrameela Rani Garnepudi 477b97e9b94SPrameela Rani Garnepudi static int rsi_usb_load_data_master_write(struct rsi_hw *adapter, 478b97e9b94SPrameela Rani Garnepudi u32 base_address, 479b97e9b94SPrameela Rani Garnepudi u32 instructions_sz, u16 block_size, 480b97e9b94SPrameela Rani Garnepudi u8 *ta_firmware) 481b97e9b94SPrameela Rani Garnepudi { 482b97e9b94SPrameela Rani Garnepudi u16 num_blocks; 483b97e9b94SPrameela Rani Garnepudi u32 cur_indx, i; 484b97e9b94SPrameela Rani Garnepudi u8 temp_buf[256]; 485b97e9b94SPrameela Rani Garnepudi int status; 486b97e9b94SPrameela Rani Garnepudi 487b97e9b94SPrameela Rani Garnepudi num_blocks = instructions_sz / block_size; 488b97e9b94SPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, "num_blocks: %d\n", num_blocks); 489b97e9b94SPrameela Rani Garnepudi 490b97e9b94SPrameela Rani Garnepudi for (cur_indx = 0, i = 0; i < num_blocks; i++, cur_indx += block_size) { 491b97e9b94SPrameela Rani Garnepudi memcpy(temp_buf, ta_firmware + cur_indx, block_size); 492b97e9b94SPrameela Rani Garnepudi status = rsi_usb_write_register_multiple(adapter, base_address, 493b97e9b94SPrameela Rani Garnepudi (u8 *)(temp_buf), 494b97e9b94SPrameela Rani Garnepudi block_size); 495b97e9b94SPrameela Rani Garnepudi if (status < 0) 496b97e9b94SPrameela Rani Garnepudi return status; 497b97e9b94SPrameela Rani Garnepudi 498b97e9b94SPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); 499b97e9b94SPrameela Rani Garnepudi base_address += block_size; 500b97e9b94SPrameela Rani Garnepudi } 501b97e9b94SPrameela Rani Garnepudi 502b97e9b94SPrameela Rani Garnepudi if (instructions_sz % block_size) { 503b97e9b94SPrameela Rani Garnepudi memset(temp_buf, 0, block_size); 504b97e9b94SPrameela Rani Garnepudi memcpy(temp_buf, ta_firmware + cur_indx, 505b97e9b94SPrameela Rani Garnepudi instructions_sz % block_size); 506b97e9b94SPrameela Rani Garnepudi status = rsi_usb_write_register_multiple 507b97e9b94SPrameela Rani Garnepudi (adapter, base_address, 508b97e9b94SPrameela Rani Garnepudi (u8 *)temp_buf, 509b97e9b94SPrameela Rani Garnepudi instructions_sz % block_size); 510b97e9b94SPrameela Rani Garnepudi if (status < 0) 511b97e9b94SPrameela Rani Garnepudi return status; 512b97e9b94SPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, 513b97e9b94SPrameela Rani Garnepudi "Written Last Block in Address 0x%x Successfully\n", 514b97e9b94SPrameela Rani Garnepudi cur_indx); 515b97e9b94SPrameela Rani Garnepudi } 516b97e9b94SPrameela Rani Garnepudi return 0; 517b97e9b94SPrameela Rani Garnepudi } 518b97e9b94SPrameela Rani Garnepudi 519a2ce952cSPrameela Rani Garnepudi static struct rsi_host_intf_ops usb_host_intf_ops = { 520a2ce952cSPrameela Rani Garnepudi .write_pkt = rsi_usb_host_intf_write_pkt, 521a2ce952cSPrameela Rani Garnepudi .read_reg_multiple = rsi_usb_read_register_multiple, 522a2ce952cSPrameela Rani Garnepudi .write_reg_multiple = rsi_usb_write_register_multiple, 523b97e9b94SPrameela Rani Garnepudi .master_reg_read = rsi_usb_master_reg_read, 524b97e9b94SPrameela Rani Garnepudi .master_reg_write = rsi_usb_master_reg_write, 525b97e9b94SPrameela Rani Garnepudi .load_data_master_write = rsi_usb_load_data_master_write, 526a2ce952cSPrameela Rani Garnepudi }; 527a2ce952cSPrameela Rani Garnepudi 528dad0d04fSFariya Fatima /** 529dad0d04fSFariya Fatima * rsi_deinit_usb_interface() - This function deinitializes the usb interface. 530dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 531dad0d04fSFariya Fatima * 532dad0d04fSFariya Fatima * Return: None. 533dad0d04fSFariya Fatima */ 534dad0d04fSFariya Fatima static void rsi_deinit_usb_interface(struct rsi_hw *adapter) 535dad0d04fSFariya Fatima { 536dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 537dad0d04fSFariya Fatima 538dad0d04fSFariya Fatima rsi_kill_thread(&dev->rx_thread); 5391100f81bSPrameela Rani Garnepudi 5408809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[0].rx_urb); 541a1854faeSPrameela Rani Garnepudi if (adapter->priv->coex_mode > 1) 5428809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[1].rx_urb); 5431100f81bSPrameela Rani Garnepudi 544dad0d04fSFariya Fatima kfree(dev->tx_buffer); 545dad0d04fSFariya Fatima } 546dad0d04fSFariya Fatima 5471100f81bSPrameela Rani Garnepudi static int rsi_usb_init_rx(struct rsi_hw *adapter) 5481100f81bSPrameela Rani Garnepudi { 5491100f81bSPrameela Rani Garnepudi struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 5501100f81bSPrameela Rani Garnepudi struct rx_usb_ctrl_block *rx_cb; 5518809f08cSPrameela Rani Garnepudi u8 idx, num_rx_cb; 5521100f81bSPrameela Rani Garnepudi 5538809f08cSPrameela Rani Garnepudi num_rx_cb = (adapter->priv->coex_mode > 1 ? 2 : 1); 5548809f08cSPrameela Rani Garnepudi 5558809f08cSPrameela Rani Garnepudi for (idx = 0; idx < num_rx_cb; idx++) { 5561100f81bSPrameela Rani Garnepudi rx_cb = &dev->rx_cb[idx]; 5571100f81bSPrameela Rani Garnepudi 5581100f81bSPrameela Rani Garnepudi rx_cb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 5591100f81bSPrameela Rani Garnepudi if (!rx_cb->rx_urb) { 5601100f81bSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "Failed alloc rx urb[%d]\n", idx); 5611100f81bSPrameela Rani Garnepudi goto err; 5621100f81bSPrameela Rani Garnepudi } 5631100f81bSPrameela Rani Garnepudi rx_cb->ep_num = idx + 1; 5641100f81bSPrameela Rani Garnepudi rx_cb->data = (void *)dev; 5651100f81bSPrameela Rani Garnepudi } 566a1854faeSPrameela Rani Garnepudi skb_queue_head_init(&dev->rx_q); 567a1854faeSPrameela Rani Garnepudi rsi_init_event(&dev->rx_thread.event); 568a1854faeSPrameela Rani Garnepudi if (rsi_create_kthread(adapter->priv, &dev->rx_thread, 569a1854faeSPrameela Rani Garnepudi rsi_usb_rx_thread, "RX-Thread")) { 570a1854faeSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); 571a1854faeSPrameela Rani Garnepudi goto err; 572a1854faeSPrameela Rani Garnepudi } 573a1854faeSPrameela Rani Garnepudi 5741100f81bSPrameela Rani Garnepudi return 0; 5751100f81bSPrameela Rani Garnepudi 5761100f81bSPrameela Rani Garnepudi err: 5778809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[0].rx_urb); 578a1854faeSPrameela Rani Garnepudi if (adapter->priv->coex_mode > 1) 5798809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[1].rx_urb); 580a1854faeSPrameela Rani Garnepudi 5811100f81bSPrameela Rani Garnepudi return -1; 5821100f81bSPrameela Rani Garnepudi } 5831100f81bSPrameela Rani Garnepudi 584dad0d04fSFariya Fatima /** 585dad0d04fSFariya Fatima * rsi_init_usb_interface() - This function initializes the usb interface. 586dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 587dad0d04fSFariya Fatima * @pfunction: Pointer to USB interface structure. 588dad0d04fSFariya Fatima * 58950591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 590dad0d04fSFariya Fatima */ 591dad0d04fSFariya Fatima static int rsi_init_usb_interface(struct rsi_hw *adapter, 592dad0d04fSFariya Fatima struct usb_interface *pfunction) 593dad0d04fSFariya Fatima { 594dad0d04fSFariya Fatima struct rsi_91x_usbdev *rsi_dev; 5958809f08cSPrameela Rani Garnepudi int status; 596dad0d04fSFariya Fatima 597dad0d04fSFariya Fatima rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL); 598dad0d04fSFariya Fatima if (!rsi_dev) 599dad0d04fSFariya Fatima return -ENOMEM; 600dad0d04fSFariya Fatima 601dad0d04fSFariya Fatima adapter->rsi_dev = rsi_dev; 602dad0d04fSFariya Fatima rsi_dev->usbdev = interface_to_usbdev(pfunction); 603a1854faeSPrameela Rani Garnepudi rsi_dev->priv = (void *)adapter; 604dad0d04fSFariya Fatima 605a1854faeSPrameela Rani Garnepudi if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter)) { 606a1854faeSPrameela Rani Garnepudi status = -EINVAL; 607a1854faeSPrameela Rani Garnepudi goto fail_eps; 608a1854faeSPrameela Rani Garnepudi } 609dad0d04fSFariya Fatima 610dad0d04fSFariya Fatima adapter->device = &pfunction->dev; 611dad0d04fSFariya Fatima usb_set_intfdata(pfunction, adapter); 612dad0d04fSFariya Fatima 6135bc5ca85SAlexey Khoroshilov rsi_dev->tx_buffer = kmalloc(2048, GFP_KERNEL); 61450591c60SAlexey Khoroshilov if (!rsi_dev->tx_buffer) { 61550591c60SAlexey Khoroshilov status = -ENOMEM; 616a1854faeSPrameela Rani Garnepudi goto fail_eps; 61750591c60SAlexey Khoroshilov } 6181100f81bSPrameela Rani Garnepudi 6191100f81bSPrameela Rani Garnepudi if (rsi_usb_init_rx(adapter)) { 6201100f81bSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "Failed to init RX handle\n"); 621a1854faeSPrameela Rani Garnepudi status = -ENOMEM; 622a1854faeSPrameela Rani Garnepudi goto fail_rx; 62350591c60SAlexey Khoroshilov } 6241100f81bSPrameela Rani Garnepudi 625dad0d04fSFariya Fatima rsi_dev->tx_blk_size = 252; 626b78e91bcSPrameela Rani Garnepudi adapter->block_size = rsi_dev->tx_blk_size; 627dad0d04fSFariya Fatima 628dad0d04fSFariya Fatima /* Initializing function callbacks */ 629dad0d04fSFariya Fatima adapter->check_hw_queue_status = rsi_usb_check_queue_status; 630dad0d04fSFariya Fatima adapter->determine_event_timeout = rsi_usb_event_timeout; 631a2ce952cSPrameela Rani Garnepudi adapter->rsi_host_intf = RSI_HOST_INTF_USB; 632a2ce952cSPrameela Rani Garnepudi adapter->host_intf_ops = &usb_host_intf_ops; 633dad0d04fSFariya Fatima 634dad0d04fSFariya Fatima #ifdef CONFIG_RSI_DEBUGFS 635dad0d04fSFariya Fatima /* In USB, one less than the MAX_DEBUGFS_ENTRIES entries is required */ 636dad0d04fSFariya Fatima adapter->num_debugfs_entries = (MAX_DEBUGFS_ENTRIES - 1); 637dad0d04fSFariya Fatima #endif 638dad0d04fSFariya Fatima 639dad0d04fSFariya Fatima rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__); 640dad0d04fSFariya Fatima return 0; 641dad0d04fSFariya Fatima 642a1854faeSPrameela Rani Garnepudi fail_rx: 643a1854faeSPrameela Rani Garnepudi kfree(rsi_dev->tx_buffer); 644a1854faeSPrameela Rani Garnepudi 645a1854faeSPrameela Rani Garnepudi fail_eps: 646a1854faeSPrameela Rani Garnepudi kfree(rsi_dev); 647a1854faeSPrameela Rani Garnepudi 648dad0d04fSFariya Fatima return status; 649dad0d04fSFariya Fatima } 650dad0d04fSFariya Fatima 651ea0676c4SKarun Eagalapati static int usb_ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, 652ea0676c4SKarun Eagalapati u16 len_in_bits) 653ea0676c4SKarun Eagalapati { 654ea0676c4SKarun Eagalapati int ret; 655ea0676c4SKarun Eagalapati 656ea0676c4SKarun Eagalapati ret = rsi_usb_master_reg_write 657ea0676c4SKarun Eagalapati (adapter, RSI_GSPI_DATA_REG1, 658ea0676c4SKarun Eagalapati ((addr << 6) | ((data >> 16) & 0xffff)), 2); 659ea0676c4SKarun Eagalapati if (ret < 0) 660ea0676c4SKarun Eagalapati return ret; 661ea0676c4SKarun Eagalapati 662ea0676c4SKarun Eagalapati ret = rsi_usb_master_reg_write(adapter, RSI_GSPI_DATA_REG0, 663ea0676c4SKarun Eagalapati (data & 0xffff), 2); 664ea0676c4SKarun Eagalapati if (ret < 0) 665ea0676c4SKarun Eagalapati return ret; 666ea0676c4SKarun Eagalapati 667ea0676c4SKarun Eagalapati /* Initializing GSPI for ULP read/writes */ 668ea0676c4SKarun Eagalapati rsi_usb_master_reg_write(adapter, RSI_GSPI_CTRL_REG0, 669ea0676c4SKarun Eagalapati RSI_GSPI_CTRL_REG0_VALUE, 2); 670ea0676c4SKarun Eagalapati 671ea0676c4SKarun Eagalapati ret = rsi_usb_master_reg_write(adapter, RSI_GSPI_CTRL_REG1, 672ea0676c4SKarun Eagalapati ((len_in_bits - 1) | RSI_GSPI_TRIG), 2); 673ea0676c4SKarun Eagalapati if (ret < 0) 674ea0676c4SKarun Eagalapati return ret; 675ea0676c4SKarun Eagalapati 676ea0676c4SKarun Eagalapati msleep(20); 677ea0676c4SKarun Eagalapati 678ea0676c4SKarun Eagalapati return 0; 679ea0676c4SKarun Eagalapati } 680ea0676c4SKarun Eagalapati 681ea0676c4SKarun Eagalapati static int rsi_reset_card(struct rsi_hw *adapter) 682ea0676c4SKarun Eagalapati { 683ea0676c4SKarun Eagalapati int ret; 684ea0676c4SKarun Eagalapati 685ea0676c4SKarun Eagalapati rsi_dbg(INFO_ZONE, "Resetting Card...\n"); 686ea0676c4SKarun Eagalapati rsi_usb_master_reg_write(adapter, RSI_TA_HOLD_REG, 0xE, 4); 687ea0676c4SKarun Eagalapati 688ea0676c4SKarun Eagalapati /* This msleep will ensure Thread-Arch processor to go to hold 689ea0676c4SKarun Eagalapati * and any pending dma transfers to rf in device to finish. 690ea0676c4SKarun Eagalapati */ 691ea0676c4SKarun Eagalapati msleep(100); 692ea0676c4SKarun Eagalapati 69348c6b5c9SGustavo A. R. Silva ret = rsi_usb_master_reg_write(adapter, SWBL_REGOUT, 69416d3bb7bSAmitkumar Karwar RSI_FW_WDT_DISABLE_REQ, 69548c6b5c9SGustavo A. R. Silva RSI_COMMON_REG_SIZE); 69648c6b5c9SGustavo A. R. Silva if (ret < 0) { 69716d3bb7bSAmitkumar Karwar rsi_dbg(ERR_ZONE, "Disabling firmware watchdog timer failed\n"); 69816d3bb7bSAmitkumar Karwar goto fail; 69916d3bb7bSAmitkumar Karwar } 70016d3bb7bSAmitkumar Karwar 701ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_1, 702ea0676c4SKarun Eagalapati RSI_ULP_WRITE_2, 32); 703ea0676c4SKarun Eagalapati if (ret < 0) 704ea0676c4SKarun Eagalapati goto fail; 705ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_2, 706ea0676c4SKarun Eagalapati RSI_ULP_WRITE_0, 32); 707ea0676c4SKarun Eagalapati if (ret < 0) 708ea0676c4SKarun Eagalapati goto fail; 709ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_1, 710ea0676c4SKarun Eagalapati RSI_ULP_WRITE_50, 32); 711ea0676c4SKarun Eagalapati if (ret < 0) 712ea0676c4SKarun Eagalapati goto fail; 713ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_2, 714ea0676c4SKarun Eagalapati RSI_ULP_WRITE_0, 32); 715ea0676c4SKarun Eagalapati if (ret < 0) 716ea0676c4SKarun Eagalapati goto fail; 717ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_ENABLE, 718ea0676c4SKarun Eagalapati RSI_ULP_TIMER_ENABLE, 32); 719ea0676c4SKarun Eagalapati if (ret < 0) 720ea0676c4SKarun Eagalapati goto fail; 721ea0676c4SKarun Eagalapati 722ea0676c4SKarun Eagalapati rsi_dbg(INFO_ZONE, "Reset card done\n"); 723ea0676c4SKarun Eagalapati return ret; 724ea0676c4SKarun Eagalapati 725ea0676c4SKarun Eagalapati fail: 726ea0676c4SKarun Eagalapati rsi_dbg(ERR_ZONE, "Reset card failed\n"); 727ea0676c4SKarun Eagalapati return ret; 728ea0676c4SKarun Eagalapati } 729ea0676c4SKarun Eagalapati 730dad0d04fSFariya Fatima /** 731dad0d04fSFariya Fatima * rsi_probe() - This function is called by kernel when the driver provided 732dad0d04fSFariya Fatima * Vendor and device IDs are matched. All the initialization 733dad0d04fSFariya Fatima * work is done here. 734dad0d04fSFariya Fatima * @pfunction: Pointer to the USB interface structure. 735dad0d04fSFariya Fatima * @id: Pointer to the usb_device_id structure. 736dad0d04fSFariya Fatima * 73750591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 738dad0d04fSFariya Fatima */ 739dad0d04fSFariya Fatima static int rsi_probe(struct usb_interface *pfunction, 740dad0d04fSFariya Fatima const struct usb_device_id *id) 741dad0d04fSFariya Fatima { 742dad0d04fSFariya Fatima struct rsi_hw *adapter; 743dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev; 744dad0d04fSFariya Fatima u16 fw_status; 74550591c60SAlexey Khoroshilov int status; 746dad0d04fSFariya Fatima 747dad0d04fSFariya Fatima rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); 748dad0d04fSFariya Fatima 749898b2553SPrameela Rani Garnepudi adapter = rsi_91x_init(dev_oper_mode); 750dad0d04fSFariya Fatima if (!adapter) { 751dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", 752dad0d04fSFariya Fatima __func__); 75350591c60SAlexey Khoroshilov return -ENOMEM; 754dad0d04fSFariya Fatima } 755b78e91bcSPrameela Rani Garnepudi adapter->rsi_host_intf = RSI_HOST_INTF_USB; 756dad0d04fSFariya Fatima 75750591c60SAlexey Khoroshilov status = rsi_init_usb_interface(adapter, pfunction); 75850591c60SAlexey Khoroshilov if (status) { 759dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed to init usb interface\n", 760dad0d04fSFariya Fatima __func__); 761dad0d04fSFariya Fatima goto err; 762dad0d04fSFariya Fatima } 763dad0d04fSFariya Fatima 764dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Initialized os intf ops\n", __func__); 765dad0d04fSFariya Fatima 766dad0d04fSFariya Fatima dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 767dad0d04fSFariya Fatima 76850591c60SAlexey Khoroshilov status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2); 769b78e91bcSPrameela Rani Garnepudi if (status < 0) 770dad0d04fSFariya Fatima goto err1; 771dad0d04fSFariya Fatima else 772dad0d04fSFariya Fatima fw_status &= 1; 773dad0d04fSFariya Fatima 774dad0d04fSFariya Fatima if (!fw_status) { 775b78e91bcSPrameela Rani Garnepudi rsi_dbg(INIT_ZONE, "Loading firmware...\n"); 776b78e91bcSPrameela Rani Garnepudi status = rsi_hal_device_init(adapter); 77750591c60SAlexey Khoroshilov if (status) { 778dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", 779dad0d04fSFariya Fatima __func__); 780dad0d04fSFariya Fatima goto err1; 781dad0d04fSFariya Fatima } 782b78e91bcSPrameela Rani Garnepudi rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__); 783dad0d04fSFariya Fatima } 784dad0d04fSFariya Fatima 7851100f81bSPrameela Rani Garnepudi status = rsi_rx_urb_submit(adapter, WLAN_EP); 78650591c60SAlexey Khoroshilov if (status) 787dad0d04fSFariya Fatima goto err1; 788dad0d04fSFariya Fatima 789a4302bffSSiva Rebbagondla if (adapter->priv->coex_mode > 1) { 790a4302bffSSiva Rebbagondla status = rsi_rx_urb_submit(adapter, BT_EP); 791a4302bffSSiva Rebbagondla if (status) 792a4302bffSSiva Rebbagondla goto err1; 793a4302bffSSiva Rebbagondla } 794a4302bffSSiva Rebbagondla 795dad0d04fSFariya Fatima return 0; 796dad0d04fSFariya Fatima err1: 797dad0d04fSFariya Fatima rsi_deinit_usb_interface(adapter); 798dad0d04fSFariya Fatima err: 799dad0d04fSFariya Fatima rsi_91x_deinit(adapter); 800dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); 80150591c60SAlexey Khoroshilov return status; 802dad0d04fSFariya Fatima } 803dad0d04fSFariya Fatima 804dad0d04fSFariya Fatima /** 805dad0d04fSFariya Fatima * rsi_disconnect() - This function performs the reverse of the probe function, 8061cce2000SMasahiro Yamada * it deinitialize the driver structure. 807dad0d04fSFariya Fatima * @pfunction: Pointer to the USB interface structure. 808dad0d04fSFariya Fatima * 809dad0d04fSFariya Fatima * Return: None. 810dad0d04fSFariya Fatima */ 811dad0d04fSFariya Fatima static void rsi_disconnect(struct usb_interface *pfunction) 812dad0d04fSFariya Fatima { 813dad0d04fSFariya Fatima struct rsi_hw *adapter = usb_get_intfdata(pfunction); 814dad0d04fSFariya Fatima 815dad0d04fSFariya Fatima if (!adapter) 816dad0d04fSFariya Fatima return; 817dad0d04fSFariya Fatima 818dad0d04fSFariya Fatima rsi_mac80211_detach(adapter); 819cbde979bSSiva Rebbagondla 820cbde979bSSiva Rebbagondla if (IS_ENABLED(CONFIG_RSI_COEX) && adapter->priv->coex_mode > 1 && 821cbde979bSSiva Rebbagondla adapter->priv->bt_adapter) { 822cbde979bSSiva Rebbagondla rsi_bt_ops.detach(adapter->priv->bt_adapter); 823cbde979bSSiva Rebbagondla adapter->priv->bt_adapter = NULL; 824cbde979bSSiva Rebbagondla } 825cbde979bSSiva Rebbagondla 826ea0676c4SKarun Eagalapati rsi_reset_card(adapter); 827dad0d04fSFariya Fatima rsi_deinit_usb_interface(adapter); 828dad0d04fSFariya Fatima rsi_91x_deinit(adapter); 829dad0d04fSFariya Fatima 830dad0d04fSFariya Fatima rsi_dbg(INFO_ZONE, "%s: Deinitialization completed\n", __func__); 831dad0d04fSFariya Fatima } 832dad0d04fSFariya Fatima 833dad0d04fSFariya Fatima #ifdef CONFIG_PM 834dad0d04fSFariya Fatima static int rsi_suspend(struct usb_interface *intf, pm_message_t message) 835dad0d04fSFariya Fatima { 836dad0d04fSFariya Fatima /* Not yet implemented */ 837dad0d04fSFariya Fatima return -ENOSYS; 838dad0d04fSFariya Fatima } 839dad0d04fSFariya Fatima 840dad0d04fSFariya Fatima static int rsi_resume(struct usb_interface *intf) 841dad0d04fSFariya Fatima { 842dad0d04fSFariya Fatima /* Not yet implemented */ 843dad0d04fSFariya Fatima return -ENOSYS; 844dad0d04fSFariya Fatima } 845dad0d04fSFariya Fatima #endif 846dad0d04fSFariya Fatima 847dad0d04fSFariya Fatima static const struct usb_device_id rsi_dev_table[] = { 8485850874cSSiva Rebbagondla { USB_DEVICE(RSI_USB_VID_9113, RSI_USB_PID_9113) }, 849dad0d04fSFariya Fatima { /* Blank */}, 850dad0d04fSFariya Fatima }; 851dad0d04fSFariya Fatima 852dad0d04fSFariya Fatima static struct usb_driver rsi_driver = { 853dad0d04fSFariya Fatima .name = "RSI-USB WLAN", 854dad0d04fSFariya Fatima .probe = rsi_probe, 855dad0d04fSFariya Fatima .disconnect = rsi_disconnect, 856dad0d04fSFariya Fatima .id_table = rsi_dev_table, 857dad0d04fSFariya Fatima #ifdef CONFIG_PM 858dad0d04fSFariya Fatima .suspend = rsi_suspend, 859dad0d04fSFariya Fatima .resume = rsi_resume, 860dad0d04fSFariya Fatima #endif 861dad0d04fSFariya Fatima }; 862dad0d04fSFariya Fatima 863b101426aSAlexey Khoroshilov module_usb_driver(rsi_driver); 864dad0d04fSFariya Fatima 865dad0d04fSFariya Fatima MODULE_AUTHOR("Redpine Signals Inc"); 866dad0d04fSFariya Fatima MODULE_DESCRIPTION("Common USB layer for RSI drivers"); 867dad0d04fSFariya Fatima MODULE_SUPPORTED_DEVICE("RSI-91x"); 868dad0d04fSFariya Fatima MODULE_DEVICE_TABLE(usb, rsi_dev_table); 869dad0d04fSFariya Fatima MODULE_FIRMWARE(FIRMWARE_RSI9113); 870dad0d04fSFariya Fatima MODULE_VERSION("0.1"); 871dad0d04fSFariya Fatima MODULE_LICENSE("Dual BSD/GPL"); 872