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 255dad0d04fSFariya Fatima * from USB stack. This is callback to recieve 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 269a1854faeSPrameela Rani Garnepudi if (urb->actual_length <= 0) { 270a1854faeSPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, "%s: Zero length packet\n", __func__); 271a1854faeSPrameela Rani Garnepudi goto out; 272a1854faeSPrameela Rani Garnepudi } 273a1854faeSPrameela Rani Garnepudi if (skb_queue_len(&dev->rx_q) >= RSI_MAX_RX_PKTS) { 274a1854faeSPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, "Max RX packets reached\n"); 275a1854faeSPrameela Rani Garnepudi goto out; 276a1854faeSPrameela Rani Garnepudi } 277a1854faeSPrameela Rani Garnepudi skb_put(rx_cb->rx_skb, urb->actual_length); 278a1854faeSPrameela Rani Garnepudi skb_queue_tail(&dev->rx_q, rx_cb->rx_skb); 279a1854faeSPrameela Rani Garnepudi 280dad0d04fSFariya Fatima rsi_set_event(&dev->rx_thread.event); 281a1854faeSPrameela Rani Garnepudi status = 0; 282a1854faeSPrameela Rani Garnepudi 283a1854faeSPrameela Rani Garnepudi out: 284a1854faeSPrameela Rani Garnepudi if (rsi_rx_urb_submit(dev->priv, rx_cb->ep_num)) 285a1854faeSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "%s: Failed in urb submission", __func__); 286a1854faeSPrameela Rani Garnepudi 287a1854faeSPrameela Rani Garnepudi if (status) 288a1854faeSPrameela Rani Garnepudi dev_kfree_skb(rx_cb->rx_skb); 289dad0d04fSFariya Fatima } 290dad0d04fSFariya Fatima 291dad0d04fSFariya Fatima /** 292dad0d04fSFariya Fatima * rsi_rx_urb_submit() - This function submits the given URB to the USB stack. 293dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 294dad0d04fSFariya Fatima * 29550591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 296dad0d04fSFariya Fatima */ 2971100f81bSPrameela Rani Garnepudi static int rsi_rx_urb_submit(struct rsi_hw *adapter, u8 ep_num) 298dad0d04fSFariya Fatima { 299dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 3001100f81bSPrameela Rani Garnepudi struct rx_usb_ctrl_block *rx_cb = &dev->rx_cb[ep_num - 1]; 3011100f81bSPrameela Rani Garnepudi struct urb *urb = rx_cb->rx_urb; 302dad0d04fSFariya Fatima int status; 303a1854faeSPrameela Rani Garnepudi struct sk_buff *skb; 304a1854faeSPrameela Rani Garnepudi u8 dword_align_bytes = 0; 305a1854faeSPrameela Rani Garnepudi 306a1854faeSPrameela Rani Garnepudi #define RSI_MAX_RX_USB_PKT_SIZE 3000 307a1854faeSPrameela Rani Garnepudi skb = dev_alloc_skb(RSI_MAX_RX_USB_PKT_SIZE); 308a1854faeSPrameela Rani Garnepudi if (!skb) 309a1854faeSPrameela Rani Garnepudi return -ENOMEM; 310a1854faeSPrameela Rani Garnepudi skb_reserve(skb, MAX_DWORD_ALIGN_BYTES); 311a1854faeSPrameela Rani Garnepudi dword_align_bytes = (unsigned long)skb->data & 0x3f; 312a1854faeSPrameela Rani Garnepudi if (dword_align_bytes > 0) 313a1854faeSPrameela Rani Garnepudi skb_push(skb, dword_align_bytes); 314a1854faeSPrameela Rani Garnepudi urb->transfer_buffer = skb->data; 315a1854faeSPrameela Rani Garnepudi rx_cb->rx_skb = skb; 316dad0d04fSFariya Fatima 317dad0d04fSFariya Fatima usb_fill_bulk_urb(urb, 318dad0d04fSFariya Fatima dev->usbdev, 319dad0d04fSFariya Fatima usb_rcvbulkpipe(dev->usbdev, 320a4302bffSSiva Rebbagondla dev->bulkin_endpoint_addr[ep_num - 1]), 321dad0d04fSFariya Fatima urb->transfer_buffer, 322a1854faeSPrameela Rani Garnepudi RSI_MAX_RX_USB_PKT_SIZE, 323dad0d04fSFariya Fatima rsi_rx_done_handler, 3241100f81bSPrameela Rani Garnepudi rx_cb); 325dad0d04fSFariya Fatima 326dad0d04fSFariya Fatima status = usb_submit_urb(urb, GFP_KERNEL); 327dad0d04fSFariya Fatima if (status) 328dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed in urb submission\n", __func__); 329dad0d04fSFariya Fatima 330dad0d04fSFariya Fatima return status; 331dad0d04fSFariya Fatima } 332dad0d04fSFariya Fatima 33388fa51e1SPrameela Rani Garnepudi static int rsi_usb_read_register_multiple(struct rsi_hw *adapter, u32 addr, 33488fa51e1SPrameela Rani Garnepudi u8 *data, u16 count) 33588fa51e1SPrameela Rani Garnepudi { 33688fa51e1SPrameela Rani Garnepudi struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 33788fa51e1SPrameela Rani Garnepudi u8 *buf; 33888fa51e1SPrameela Rani Garnepudi u16 transfer; 33988fa51e1SPrameela Rani Garnepudi int status; 34088fa51e1SPrameela Rani Garnepudi 34188fa51e1SPrameela Rani Garnepudi if (!addr) 34288fa51e1SPrameela Rani Garnepudi return -EINVAL; 34388fa51e1SPrameela Rani Garnepudi 34488fa51e1SPrameela Rani Garnepudi buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); 34588fa51e1SPrameela Rani Garnepudi if (!buf) 34688fa51e1SPrameela Rani Garnepudi return -ENOMEM; 34788fa51e1SPrameela Rani Garnepudi 34888fa51e1SPrameela Rani Garnepudi while (count) { 34988fa51e1SPrameela Rani Garnepudi transfer = min_t(u16, count, RSI_USB_BUF_SIZE); 35088fa51e1SPrameela Rani Garnepudi status = usb_control_msg(dev->usbdev, 35188fa51e1SPrameela Rani Garnepudi usb_rcvctrlpipe(dev->usbdev, 0), 35288fa51e1SPrameela Rani Garnepudi USB_VENDOR_REGISTER_READ, 35388fa51e1SPrameela Rani Garnepudi RSI_USB_REQ_IN, 35488fa51e1SPrameela Rani Garnepudi ((addr & 0xffff0000) >> 16), 35588fa51e1SPrameela Rani Garnepudi (addr & 0xffff), (void *)buf, 35688fa51e1SPrameela Rani Garnepudi transfer, USB_CTRL_GET_TIMEOUT); 35788fa51e1SPrameela Rani Garnepudi if (status < 0) { 35888fa51e1SPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, 35988fa51e1SPrameela Rani Garnepudi "Reg read failed with error code :%d\n", 36088fa51e1SPrameela Rani Garnepudi status); 36188fa51e1SPrameela Rani Garnepudi kfree(buf); 36288fa51e1SPrameela Rani Garnepudi return status; 36388fa51e1SPrameela Rani Garnepudi } 36488fa51e1SPrameela Rani Garnepudi memcpy(data, buf, transfer); 36588fa51e1SPrameela Rani Garnepudi count -= transfer; 36688fa51e1SPrameela Rani Garnepudi data += transfer; 36788fa51e1SPrameela Rani Garnepudi addr += transfer; 36888fa51e1SPrameela Rani Garnepudi } 36988fa51e1SPrameela Rani Garnepudi kfree(buf); 37088fa51e1SPrameela Rani Garnepudi return 0; 37188fa51e1SPrameela Rani Garnepudi } 37288fa51e1SPrameela Rani Garnepudi 373dad0d04fSFariya Fatima /** 374dad0d04fSFariya Fatima * rsi_usb_write_register_multiple() - This function writes multiple bytes of 375dad0d04fSFariya Fatima * information to multiple registers. 376dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 377dad0d04fSFariya Fatima * @addr: Address of the register. 378dad0d04fSFariya Fatima * @data: Pointer to the data that has to be written. 379dad0d04fSFariya Fatima * @count: Number of multiple bytes to be written on to the registers. 380dad0d04fSFariya Fatima * 38150591c60SAlexey Khoroshilov * Return: status: 0 on success, a negative error code on failure. 382dad0d04fSFariya Fatima */ 3835578b1ffSPrameela Rani Garnepudi static int rsi_usb_write_register_multiple(struct rsi_hw *adapter, u32 addr, 3845578b1ffSPrameela Rani Garnepudi u8 *data, u16 count) 385dad0d04fSFariya Fatima { 386dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 387dad0d04fSFariya Fatima u8 *buf; 3882fbbe517SPrameela Rani Garnepudi u16 transfer; 389dad0d04fSFariya Fatima int status = 0; 390dad0d04fSFariya Fatima 3917bdead7aSamit karwar buf = kzalloc(RSI_USB_BUF_SIZE, GFP_KERNEL); 392dad0d04fSFariya Fatima if (!buf) 393dad0d04fSFariya Fatima return -ENOMEM; 394dad0d04fSFariya Fatima 395dad0d04fSFariya Fatima while (count) { 3962fbbe517SPrameela Rani Garnepudi transfer = min_t(u16, count, RSI_USB_BUF_SIZE); 397dad0d04fSFariya Fatima memcpy(buf, data, transfer); 398dad0d04fSFariya Fatima status = usb_control_msg(dev->usbdev, 399dad0d04fSFariya Fatima usb_sndctrlpipe(dev->usbdev, 0), 400dad0d04fSFariya Fatima USB_VENDOR_REGISTER_WRITE, 4014b1fc881SPrameela Rani Garnepudi RSI_USB_REQ_OUT, 402dad0d04fSFariya Fatima ((addr & 0xffff0000) >> 16), 403dad0d04fSFariya Fatima (addr & 0xffff), 404dad0d04fSFariya Fatima (void *)buf, 405dad0d04fSFariya Fatima transfer, 4064b1fc881SPrameela Rani Garnepudi USB_CTRL_SET_TIMEOUT); 407dad0d04fSFariya Fatima if (status < 0) { 408dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, 409dad0d04fSFariya Fatima "Reg write failed with error code :%d\n", 410dad0d04fSFariya Fatima status); 411ea3336acSPrameela Rani Garnepudi kfree(buf); 412ea3336acSPrameela Rani Garnepudi return status; 413ea3336acSPrameela Rani Garnepudi } 414dad0d04fSFariya Fatima count -= transfer; 415dad0d04fSFariya Fatima data += transfer; 416dad0d04fSFariya Fatima addr += transfer; 417dad0d04fSFariya Fatima } 418dad0d04fSFariya Fatima 419dad0d04fSFariya Fatima kfree(buf); 420dad0d04fSFariya Fatima return 0; 421dad0d04fSFariya Fatima } 422dad0d04fSFariya Fatima 423dad0d04fSFariya Fatima /** 424dad0d04fSFariya Fatima *rsi_usb_host_intf_write_pkt() - This function writes the packet to the 425dad0d04fSFariya Fatima * USB card. 426dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 427dad0d04fSFariya Fatima * @pkt: Pointer to the data to be written on to the card. 428dad0d04fSFariya Fatima * @len: Length of the data to be written on to the card. 429dad0d04fSFariya Fatima * 43050591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 431dad0d04fSFariya Fatima */ 432dad0d04fSFariya Fatima static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, 433dad0d04fSFariya Fatima u8 *pkt, 434dad0d04fSFariya Fatima u32 len) 435dad0d04fSFariya Fatima { 436ac6107caSAmitkumar Karwar u32 queueno = ((pkt[1] >> 4) & 0x7); 437dad0d04fSFariya Fatima u8 endpoint; 438dad0d04fSFariya Fatima 439d1f69e41SKarun Eagalapati endpoint = ((queueno == RSI_WIFI_MGMT_Q || queueno == RSI_WIFI_DATA_Q || 440d1f69e41SKarun Eagalapati queueno == RSI_COEX_Q) ? WLAN_EP : BT_EP); 441dad0d04fSFariya Fatima 442dad0d04fSFariya Fatima return rsi_write_multiple(adapter, 443dad0d04fSFariya Fatima endpoint, 444dad0d04fSFariya Fatima (u8 *)pkt, 445dad0d04fSFariya Fatima len); 446dad0d04fSFariya Fatima } 447dad0d04fSFariya Fatima 448b97e9b94SPrameela Rani Garnepudi static int rsi_usb_master_reg_read(struct rsi_hw *adapter, u32 reg, 449b97e9b94SPrameela Rani Garnepudi u32 *value, u16 len) 450b97e9b94SPrameela Rani Garnepudi { 451b97e9b94SPrameela Rani Garnepudi struct usb_device *usbdev = 452b97e9b94SPrameela Rani Garnepudi ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; 453e6249e15SAmitkumar Karwar u16 temp; 454e6249e15SAmitkumar Karwar int ret; 455b97e9b94SPrameela Rani Garnepudi 456e6249e15SAmitkumar Karwar ret = rsi_usb_reg_read(usbdev, reg, &temp, len); 457e6249e15SAmitkumar Karwar if (ret < 0) 458e6249e15SAmitkumar Karwar return ret; 459e6249e15SAmitkumar Karwar *value = temp; 460e6249e15SAmitkumar Karwar 461e6249e15SAmitkumar Karwar return 0; 462b97e9b94SPrameela Rani Garnepudi } 463b97e9b94SPrameela Rani Garnepudi 464b97e9b94SPrameela Rani Garnepudi static int rsi_usb_master_reg_write(struct rsi_hw *adapter, 465b97e9b94SPrameela Rani Garnepudi unsigned long reg, 466b97e9b94SPrameela Rani Garnepudi unsigned long value, u16 len) 467b97e9b94SPrameela Rani Garnepudi { 468b97e9b94SPrameela Rani Garnepudi struct usb_device *usbdev = 469b97e9b94SPrameela Rani Garnepudi ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; 470b97e9b94SPrameela Rani Garnepudi 471b97e9b94SPrameela Rani Garnepudi return rsi_usb_reg_write(usbdev, reg, value, len); 472b97e9b94SPrameela Rani Garnepudi } 473b97e9b94SPrameela Rani Garnepudi 474b97e9b94SPrameela Rani Garnepudi static int rsi_usb_load_data_master_write(struct rsi_hw *adapter, 475b97e9b94SPrameela Rani Garnepudi u32 base_address, 476b97e9b94SPrameela Rani Garnepudi u32 instructions_sz, u16 block_size, 477b97e9b94SPrameela Rani Garnepudi u8 *ta_firmware) 478b97e9b94SPrameela Rani Garnepudi { 479b97e9b94SPrameela Rani Garnepudi u16 num_blocks; 480b97e9b94SPrameela Rani Garnepudi u32 cur_indx, i; 481b97e9b94SPrameela Rani Garnepudi u8 temp_buf[256]; 482b97e9b94SPrameela Rani Garnepudi int status; 483b97e9b94SPrameela Rani Garnepudi 484b97e9b94SPrameela Rani Garnepudi num_blocks = instructions_sz / block_size; 485b97e9b94SPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, "num_blocks: %d\n", num_blocks); 486b97e9b94SPrameela Rani Garnepudi 487b97e9b94SPrameela Rani Garnepudi for (cur_indx = 0, i = 0; i < num_blocks; i++, cur_indx += block_size) { 488b97e9b94SPrameela Rani Garnepudi memcpy(temp_buf, ta_firmware + cur_indx, block_size); 489b97e9b94SPrameela Rani Garnepudi status = rsi_usb_write_register_multiple(adapter, base_address, 490b97e9b94SPrameela Rani Garnepudi (u8 *)(temp_buf), 491b97e9b94SPrameela Rani Garnepudi block_size); 492b97e9b94SPrameela Rani Garnepudi if (status < 0) 493b97e9b94SPrameela Rani Garnepudi return status; 494b97e9b94SPrameela Rani Garnepudi 495b97e9b94SPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); 496b97e9b94SPrameela Rani Garnepudi base_address += block_size; 497b97e9b94SPrameela Rani Garnepudi } 498b97e9b94SPrameela Rani Garnepudi 499b97e9b94SPrameela Rani Garnepudi if (instructions_sz % block_size) { 500b97e9b94SPrameela Rani Garnepudi memset(temp_buf, 0, block_size); 501b97e9b94SPrameela Rani Garnepudi memcpy(temp_buf, ta_firmware + cur_indx, 502b97e9b94SPrameela Rani Garnepudi instructions_sz % block_size); 503b97e9b94SPrameela Rani Garnepudi status = rsi_usb_write_register_multiple 504b97e9b94SPrameela Rani Garnepudi (adapter, base_address, 505b97e9b94SPrameela Rani Garnepudi (u8 *)temp_buf, 506b97e9b94SPrameela Rani Garnepudi instructions_sz % block_size); 507b97e9b94SPrameela Rani Garnepudi if (status < 0) 508b97e9b94SPrameela Rani Garnepudi return status; 509b97e9b94SPrameela Rani Garnepudi rsi_dbg(INFO_ZONE, 510b97e9b94SPrameela Rani Garnepudi "Written Last Block in Address 0x%x Successfully\n", 511b97e9b94SPrameela Rani Garnepudi cur_indx); 512b97e9b94SPrameela Rani Garnepudi } 513b97e9b94SPrameela Rani Garnepudi return 0; 514b97e9b94SPrameela Rani Garnepudi } 515b97e9b94SPrameela Rani Garnepudi 516a2ce952cSPrameela Rani Garnepudi static struct rsi_host_intf_ops usb_host_intf_ops = { 517a2ce952cSPrameela Rani Garnepudi .write_pkt = rsi_usb_host_intf_write_pkt, 518a2ce952cSPrameela Rani Garnepudi .read_reg_multiple = rsi_usb_read_register_multiple, 519a2ce952cSPrameela Rani Garnepudi .write_reg_multiple = rsi_usb_write_register_multiple, 520b97e9b94SPrameela Rani Garnepudi .master_reg_read = rsi_usb_master_reg_read, 521b97e9b94SPrameela Rani Garnepudi .master_reg_write = rsi_usb_master_reg_write, 522b97e9b94SPrameela Rani Garnepudi .load_data_master_write = rsi_usb_load_data_master_write, 523a2ce952cSPrameela Rani Garnepudi }; 524a2ce952cSPrameela Rani Garnepudi 525dad0d04fSFariya Fatima /** 526dad0d04fSFariya Fatima * rsi_deinit_usb_interface() - This function deinitializes the usb interface. 527dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 528dad0d04fSFariya Fatima * 529dad0d04fSFariya Fatima * Return: None. 530dad0d04fSFariya Fatima */ 531dad0d04fSFariya Fatima static void rsi_deinit_usb_interface(struct rsi_hw *adapter) 532dad0d04fSFariya Fatima { 533dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 534dad0d04fSFariya Fatima 535dad0d04fSFariya Fatima rsi_kill_thread(&dev->rx_thread); 5361100f81bSPrameela Rani Garnepudi 5378809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[0].rx_urb); 538a1854faeSPrameela Rani Garnepudi if (adapter->priv->coex_mode > 1) 5398809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[1].rx_urb); 5401100f81bSPrameela Rani Garnepudi 541dad0d04fSFariya Fatima kfree(dev->tx_buffer); 542dad0d04fSFariya Fatima } 543dad0d04fSFariya Fatima 5441100f81bSPrameela Rani Garnepudi static int rsi_usb_init_rx(struct rsi_hw *adapter) 5451100f81bSPrameela Rani Garnepudi { 5461100f81bSPrameela Rani Garnepudi struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 5471100f81bSPrameela Rani Garnepudi struct rx_usb_ctrl_block *rx_cb; 5488809f08cSPrameela Rani Garnepudi u8 idx, num_rx_cb; 5491100f81bSPrameela Rani Garnepudi 5508809f08cSPrameela Rani Garnepudi num_rx_cb = (adapter->priv->coex_mode > 1 ? 2 : 1); 5518809f08cSPrameela Rani Garnepudi 5528809f08cSPrameela Rani Garnepudi for (idx = 0; idx < num_rx_cb; idx++) { 5531100f81bSPrameela Rani Garnepudi rx_cb = &dev->rx_cb[idx]; 5541100f81bSPrameela Rani Garnepudi 5551100f81bSPrameela Rani Garnepudi rx_cb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); 5561100f81bSPrameela Rani Garnepudi if (!rx_cb->rx_urb) { 5571100f81bSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "Failed alloc rx urb[%d]\n", idx); 5581100f81bSPrameela Rani Garnepudi goto err; 5591100f81bSPrameela Rani Garnepudi } 5601100f81bSPrameela Rani Garnepudi rx_cb->ep_num = idx + 1; 5611100f81bSPrameela Rani Garnepudi rx_cb->data = (void *)dev; 5621100f81bSPrameela Rani Garnepudi } 563a1854faeSPrameela Rani Garnepudi skb_queue_head_init(&dev->rx_q); 564a1854faeSPrameela Rani Garnepudi rsi_init_event(&dev->rx_thread.event); 565a1854faeSPrameela Rani Garnepudi if (rsi_create_kthread(adapter->priv, &dev->rx_thread, 566a1854faeSPrameela Rani Garnepudi rsi_usb_rx_thread, "RX-Thread")) { 567a1854faeSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); 568a1854faeSPrameela Rani Garnepudi goto err; 569a1854faeSPrameela Rani Garnepudi } 570a1854faeSPrameela Rani Garnepudi 5711100f81bSPrameela Rani Garnepudi return 0; 5721100f81bSPrameela Rani Garnepudi 5731100f81bSPrameela Rani Garnepudi err: 5748809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[0].rx_urb); 575a1854faeSPrameela Rani Garnepudi if (adapter->priv->coex_mode > 1) 5768809f08cSPrameela Rani Garnepudi usb_free_urb(dev->rx_cb[1].rx_urb); 577a1854faeSPrameela Rani Garnepudi 5781100f81bSPrameela Rani Garnepudi return -1; 5791100f81bSPrameela Rani Garnepudi } 5801100f81bSPrameela Rani Garnepudi 581dad0d04fSFariya Fatima /** 582dad0d04fSFariya Fatima * rsi_init_usb_interface() - This function initializes the usb interface. 583dad0d04fSFariya Fatima * @adapter: Pointer to the adapter structure. 584dad0d04fSFariya Fatima * @pfunction: Pointer to USB interface structure. 585dad0d04fSFariya Fatima * 58650591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 587dad0d04fSFariya Fatima */ 588dad0d04fSFariya Fatima static int rsi_init_usb_interface(struct rsi_hw *adapter, 589dad0d04fSFariya Fatima struct usb_interface *pfunction) 590dad0d04fSFariya Fatima { 591dad0d04fSFariya Fatima struct rsi_91x_usbdev *rsi_dev; 5928809f08cSPrameela Rani Garnepudi int status; 593dad0d04fSFariya Fatima 594dad0d04fSFariya Fatima rsi_dev = kzalloc(sizeof(*rsi_dev), GFP_KERNEL); 595dad0d04fSFariya Fatima if (!rsi_dev) 596dad0d04fSFariya Fatima return -ENOMEM; 597dad0d04fSFariya Fatima 598dad0d04fSFariya Fatima adapter->rsi_dev = rsi_dev; 599dad0d04fSFariya Fatima rsi_dev->usbdev = interface_to_usbdev(pfunction); 600a1854faeSPrameela Rani Garnepudi rsi_dev->priv = (void *)adapter; 601dad0d04fSFariya Fatima 602a1854faeSPrameela Rani Garnepudi if (rsi_find_bulk_in_and_out_endpoints(pfunction, adapter)) { 603a1854faeSPrameela Rani Garnepudi status = -EINVAL; 604a1854faeSPrameela Rani Garnepudi goto fail_eps; 605a1854faeSPrameela Rani Garnepudi } 606dad0d04fSFariya Fatima 607dad0d04fSFariya Fatima adapter->device = &pfunction->dev; 608dad0d04fSFariya Fatima usb_set_intfdata(pfunction, adapter); 609dad0d04fSFariya Fatima 6105bc5ca85SAlexey Khoroshilov rsi_dev->tx_buffer = kmalloc(2048, GFP_KERNEL); 61150591c60SAlexey Khoroshilov if (!rsi_dev->tx_buffer) { 61250591c60SAlexey Khoroshilov status = -ENOMEM; 613a1854faeSPrameela Rani Garnepudi goto fail_eps; 61450591c60SAlexey Khoroshilov } 6151100f81bSPrameela Rani Garnepudi 6161100f81bSPrameela Rani Garnepudi if (rsi_usb_init_rx(adapter)) { 6171100f81bSPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "Failed to init RX handle\n"); 618a1854faeSPrameela Rani Garnepudi status = -ENOMEM; 619a1854faeSPrameela Rani Garnepudi goto fail_rx; 62050591c60SAlexey Khoroshilov } 6211100f81bSPrameela Rani Garnepudi 622dad0d04fSFariya Fatima rsi_dev->tx_blk_size = 252; 623b78e91bcSPrameela Rani Garnepudi adapter->block_size = rsi_dev->tx_blk_size; 624dad0d04fSFariya Fatima 625dad0d04fSFariya Fatima /* Initializing function callbacks */ 626dad0d04fSFariya Fatima adapter->check_hw_queue_status = rsi_usb_check_queue_status; 627dad0d04fSFariya Fatima adapter->determine_event_timeout = rsi_usb_event_timeout; 628a2ce952cSPrameela Rani Garnepudi adapter->rsi_host_intf = RSI_HOST_INTF_USB; 629a2ce952cSPrameela Rani Garnepudi adapter->host_intf_ops = &usb_host_intf_ops; 630dad0d04fSFariya Fatima 631dad0d04fSFariya Fatima #ifdef CONFIG_RSI_DEBUGFS 632dad0d04fSFariya Fatima /* In USB, one less than the MAX_DEBUGFS_ENTRIES entries is required */ 633dad0d04fSFariya Fatima adapter->num_debugfs_entries = (MAX_DEBUGFS_ENTRIES - 1); 634dad0d04fSFariya Fatima #endif 635dad0d04fSFariya Fatima 636dad0d04fSFariya Fatima rsi_dbg(INIT_ZONE, "%s: Enabled the interface\n", __func__); 637dad0d04fSFariya Fatima return 0; 638dad0d04fSFariya Fatima 639a1854faeSPrameela Rani Garnepudi fail_rx: 640a1854faeSPrameela Rani Garnepudi kfree(rsi_dev->tx_buffer); 641a1854faeSPrameela Rani Garnepudi 642a1854faeSPrameela Rani Garnepudi fail_eps: 643a1854faeSPrameela Rani Garnepudi kfree(rsi_dev); 644a1854faeSPrameela Rani Garnepudi 645dad0d04fSFariya Fatima return status; 646dad0d04fSFariya Fatima } 647dad0d04fSFariya Fatima 648ea0676c4SKarun Eagalapati static int usb_ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, 649ea0676c4SKarun Eagalapati u16 len_in_bits) 650ea0676c4SKarun Eagalapati { 651ea0676c4SKarun Eagalapati int ret; 652ea0676c4SKarun Eagalapati 653ea0676c4SKarun Eagalapati ret = rsi_usb_master_reg_write 654ea0676c4SKarun Eagalapati (adapter, RSI_GSPI_DATA_REG1, 655ea0676c4SKarun Eagalapati ((addr << 6) | ((data >> 16) & 0xffff)), 2); 656ea0676c4SKarun Eagalapati if (ret < 0) 657ea0676c4SKarun Eagalapati return ret; 658ea0676c4SKarun Eagalapati 659ea0676c4SKarun Eagalapati ret = rsi_usb_master_reg_write(adapter, RSI_GSPI_DATA_REG0, 660ea0676c4SKarun Eagalapati (data & 0xffff), 2); 661ea0676c4SKarun Eagalapati if (ret < 0) 662ea0676c4SKarun Eagalapati return ret; 663ea0676c4SKarun Eagalapati 664ea0676c4SKarun Eagalapati /* Initializing GSPI for ULP read/writes */ 665ea0676c4SKarun Eagalapati rsi_usb_master_reg_write(adapter, RSI_GSPI_CTRL_REG0, 666ea0676c4SKarun Eagalapati RSI_GSPI_CTRL_REG0_VALUE, 2); 667ea0676c4SKarun Eagalapati 668ea0676c4SKarun Eagalapati ret = rsi_usb_master_reg_write(adapter, RSI_GSPI_CTRL_REG1, 669ea0676c4SKarun Eagalapati ((len_in_bits - 1) | RSI_GSPI_TRIG), 2); 670ea0676c4SKarun Eagalapati if (ret < 0) 671ea0676c4SKarun Eagalapati return ret; 672ea0676c4SKarun Eagalapati 673ea0676c4SKarun Eagalapati msleep(20); 674ea0676c4SKarun Eagalapati 675ea0676c4SKarun Eagalapati return 0; 676ea0676c4SKarun Eagalapati } 677ea0676c4SKarun Eagalapati 678ea0676c4SKarun Eagalapati static int rsi_reset_card(struct rsi_hw *adapter) 679ea0676c4SKarun Eagalapati { 680ea0676c4SKarun Eagalapati int ret; 681ea0676c4SKarun Eagalapati 682ea0676c4SKarun Eagalapati rsi_dbg(INFO_ZONE, "Resetting Card...\n"); 683ea0676c4SKarun Eagalapati rsi_usb_master_reg_write(adapter, RSI_TA_HOLD_REG, 0xE, 4); 684ea0676c4SKarun Eagalapati 685ea0676c4SKarun Eagalapati /* This msleep will ensure Thread-Arch processor to go to hold 686ea0676c4SKarun Eagalapati * and any pending dma transfers to rf in device to finish. 687ea0676c4SKarun Eagalapati */ 688ea0676c4SKarun Eagalapati msleep(100); 689ea0676c4SKarun Eagalapati 69048c6b5c9SGustavo A. R. Silva ret = rsi_usb_master_reg_write(adapter, SWBL_REGOUT, 69116d3bb7bSAmitkumar Karwar RSI_FW_WDT_DISABLE_REQ, 69248c6b5c9SGustavo A. R. Silva RSI_COMMON_REG_SIZE); 69348c6b5c9SGustavo A. R. Silva if (ret < 0) { 69416d3bb7bSAmitkumar Karwar rsi_dbg(ERR_ZONE, "Disabling firmware watchdog timer failed\n"); 69516d3bb7bSAmitkumar Karwar goto fail; 69616d3bb7bSAmitkumar Karwar } 69716d3bb7bSAmitkumar Karwar 698ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_1, 699ea0676c4SKarun Eagalapati RSI_ULP_WRITE_2, 32); 700ea0676c4SKarun Eagalapati if (ret < 0) 701ea0676c4SKarun Eagalapati goto fail; 702ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_2, 703ea0676c4SKarun Eagalapati RSI_ULP_WRITE_0, 32); 704ea0676c4SKarun Eagalapati if (ret < 0) 705ea0676c4SKarun Eagalapati goto fail; 706ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_1, 707ea0676c4SKarun Eagalapati RSI_ULP_WRITE_50, 32); 708ea0676c4SKarun Eagalapati if (ret < 0) 709ea0676c4SKarun Eagalapati goto fail; 710ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_2, 711ea0676c4SKarun Eagalapati RSI_ULP_WRITE_0, 32); 712ea0676c4SKarun Eagalapati if (ret < 0) 713ea0676c4SKarun Eagalapati goto fail; 714ea0676c4SKarun Eagalapati ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_ENABLE, 715ea0676c4SKarun Eagalapati RSI_ULP_TIMER_ENABLE, 32); 716ea0676c4SKarun Eagalapati if (ret < 0) 717ea0676c4SKarun Eagalapati goto fail; 718ea0676c4SKarun Eagalapati 719ea0676c4SKarun Eagalapati rsi_dbg(INFO_ZONE, "Reset card done\n"); 720ea0676c4SKarun Eagalapati return ret; 721ea0676c4SKarun Eagalapati 722ea0676c4SKarun Eagalapati fail: 723ea0676c4SKarun Eagalapati rsi_dbg(ERR_ZONE, "Reset card failed\n"); 724ea0676c4SKarun Eagalapati return ret; 725ea0676c4SKarun Eagalapati } 726ea0676c4SKarun Eagalapati 727dad0d04fSFariya Fatima /** 728dad0d04fSFariya Fatima * rsi_probe() - This function is called by kernel when the driver provided 729dad0d04fSFariya Fatima * Vendor and device IDs are matched. All the initialization 730dad0d04fSFariya Fatima * work is done here. 731dad0d04fSFariya Fatima * @pfunction: Pointer to the USB interface structure. 732dad0d04fSFariya Fatima * @id: Pointer to the usb_device_id structure. 733dad0d04fSFariya Fatima * 73450591c60SAlexey Khoroshilov * Return: 0 on success, a negative error code on failure. 735dad0d04fSFariya Fatima */ 736dad0d04fSFariya Fatima static int rsi_probe(struct usb_interface *pfunction, 737dad0d04fSFariya Fatima const struct usb_device_id *id) 738dad0d04fSFariya Fatima { 739dad0d04fSFariya Fatima struct rsi_hw *adapter; 740dad0d04fSFariya Fatima struct rsi_91x_usbdev *dev; 741dad0d04fSFariya Fatima u16 fw_status; 74250591c60SAlexey Khoroshilov int status; 743dad0d04fSFariya Fatima 744dad0d04fSFariya Fatima rsi_dbg(INIT_ZONE, "%s: Init function called\n", __func__); 745dad0d04fSFariya Fatima 746898b2553SPrameela Rani Garnepudi adapter = rsi_91x_init(dev_oper_mode); 747dad0d04fSFariya Fatima if (!adapter) { 748dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed to init os intf ops\n", 749dad0d04fSFariya Fatima __func__); 75050591c60SAlexey Khoroshilov return -ENOMEM; 751dad0d04fSFariya Fatima } 752b78e91bcSPrameela Rani Garnepudi adapter->rsi_host_intf = RSI_HOST_INTF_USB; 753dad0d04fSFariya Fatima 75450591c60SAlexey Khoroshilov status = rsi_init_usb_interface(adapter, pfunction); 75550591c60SAlexey Khoroshilov if (status) { 756dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed to init usb interface\n", 757dad0d04fSFariya Fatima __func__); 758dad0d04fSFariya Fatima goto err; 759dad0d04fSFariya Fatima } 760dad0d04fSFariya Fatima 761dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Initialized os intf ops\n", __func__); 762dad0d04fSFariya Fatima 763dad0d04fSFariya Fatima dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; 764dad0d04fSFariya Fatima 76550591c60SAlexey Khoroshilov status = rsi_usb_reg_read(dev->usbdev, FW_STATUS_REG, &fw_status, 2); 766b78e91bcSPrameela Rani Garnepudi if (status < 0) 767dad0d04fSFariya Fatima goto err1; 768dad0d04fSFariya Fatima else 769dad0d04fSFariya Fatima fw_status &= 1; 770dad0d04fSFariya Fatima 771dad0d04fSFariya Fatima if (!fw_status) { 772b78e91bcSPrameela Rani Garnepudi rsi_dbg(INIT_ZONE, "Loading firmware...\n"); 773b78e91bcSPrameela Rani Garnepudi status = rsi_hal_device_init(adapter); 77450591c60SAlexey Khoroshilov if (status) { 775dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", 776dad0d04fSFariya Fatima __func__); 777dad0d04fSFariya Fatima goto err1; 778dad0d04fSFariya Fatima } 779b78e91bcSPrameela Rani Garnepudi rsi_dbg(INIT_ZONE, "%s: Device Init Done\n", __func__); 780dad0d04fSFariya Fatima } 781dad0d04fSFariya Fatima 7821100f81bSPrameela Rani Garnepudi status = rsi_rx_urb_submit(adapter, WLAN_EP); 78350591c60SAlexey Khoroshilov if (status) 784dad0d04fSFariya Fatima goto err1; 785dad0d04fSFariya Fatima 786a4302bffSSiva Rebbagondla if (adapter->priv->coex_mode > 1) { 787a4302bffSSiva Rebbagondla status = rsi_rx_urb_submit(adapter, BT_EP); 788a4302bffSSiva Rebbagondla if (status) 789a4302bffSSiva Rebbagondla goto err1; 790a4302bffSSiva Rebbagondla } 791a4302bffSSiva Rebbagondla 792dad0d04fSFariya Fatima return 0; 793dad0d04fSFariya Fatima err1: 794dad0d04fSFariya Fatima rsi_deinit_usb_interface(adapter); 795dad0d04fSFariya Fatima err: 796dad0d04fSFariya Fatima rsi_91x_deinit(adapter); 797dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); 79850591c60SAlexey Khoroshilov return status; 799dad0d04fSFariya Fatima } 800dad0d04fSFariya Fatima 801dad0d04fSFariya Fatima /** 802dad0d04fSFariya Fatima * rsi_disconnect() - This function performs the reverse of the probe function, 8031cce2000SMasahiro Yamada * it deinitialize the driver structure. 804dad0d04fSFariya Fatima * @pfunction: Pointer to the USB interface structure. 805dad0d04fSFariya Fatima * 806dad0d04fSFariya Fatima * Return: None. 807dad0d04fSFariya Fatima */ 808dad0d04fSFariya Fatima static void rsi_disconnect(struct usb_interface *pfunction) 809dad0d04fSFariya Fatima { 810dad0d04fSFariya Fatima struct rsi_hw *adapter = usb_get_intfdata(pfunction); 811dad0d04fSFariya Fatima 812dad0d04fSFariya Fatima if (!adapter) 813dad0d04fSFariya Fatima return; 814dad0d04fSFariya Fatima 815dad0d04fSFariya Fatima rsi_mac80211_detach(adapter); 816ea0676c4SKarun Eagalapati rsi_reset_card(adapter); 817dad0d04fSFariya Fatima rsi_deinit_usb_interface(adapter); 818dad0d04fSFariya Fatima rsi_91x_deinit(adapter); 819dad0d04fSFariya Fatima 820dad0d04fSFariya Fatima rsi_dbg(INFO_ZONE, "%s: Deinitialization completed\n", __func__); 821dad0d04fSFariya Fatima } 822dad0d04fSFariya Fatima 823dad0d04fSFariya Fatima #ifdef CONFIG_PM 824dad0d04fSFariya Fatima static int rsi_suspend(struct usb_interface *intf, pm_message_t message) 825dad0d04fSFariya Fatima { 826dad0d04fSFariya Fatima /* Not yet implemented */ 827dad0d04fSFariya Fatima return -ENOSYS; 828dad0d04fSFariya Fatima } 829dad0d04fSFariya Fatima 830dad0d04fSFariya Fatima static int rsi_resume(struct usb_interface *intf) 831dad0d04fSFariya Fatima { 832dad0d04fSFariya Fatima /* Not yet implemented */ 833dad0d04fSFariya Fatima return -ENOSYS; 834dad0d04fSFariya Fatima } 835dad0d04fSFariya Fatima #endif 836dad0d04fSFariya Fatima 837dad0d04fSFariya Fatima static const struct usb_device_id rsi_dev_table[] = { 8385850874cSSiva Rebbagondla { USB_DEVICE(RSI_USB_VID_9113, RSI_USB_PID_9113) }, 839dad0d04fSFariya Fatima { /* Blank */}, 840dad0d04fSFariya Fatima }; 841dad0d04fSFariya Fatima 842dad0d04fSFariya Fatima static struct usb_driver rsi_driver = { 843dad0d04fSFariya Fatima .name = "RSI-USB WLAN", 844dad0d04fSFariya Fatima .probe = rsi_probe, 845dad0d04fSFariya Fatima .disconnect = rsi_disconnect, 846dad0d04fSFariya Fatima .id_table = rsi_dev_table, 847dad0d04fSFariya Fatima #ifdef CONFIG_PM 848dad0d04fSFariya Fatima .suspend = rsi_suspend, 849dad0d04fSFariya Fatima .resume = rsi_resume, 850dad0d04fSFariya Fatima #endif 851dad0d04fSFariya Fatima }; 852dad0d04fSFariya Fatima 853b101426aSAlexey Khoroshilov module_usb_driver(rsi_driver); 854dad0d04fSFariya Fatima 855dad0d04fSFariya Fatima MODULE_AUTHOR("Redpine Signals Inc"); 856dad0d04fSFariya Fatima MODULE_DESCRIPTION("Common USB layer for RSI drivers"); 857dad0d04fSFariya Fatima MODULE_SUPPORTED_DEVICE("RSI-91x"); 858dad0d04fSFariya Fatima MODULE_DEVICE_TABLE(usb, rsi_dev_table); 859dad0d04fSFariya Fatima MODULE_FIRMWARE(FIRMWARE_RSI9113); 860dad0d04fSFariya Fatima MODULE_VERSION("0.1"); 861dad0d04fSFariya Fatima MODULE_LICENSE("Dual BSD/GPL"); 862