rsi: SDIO functionality
PATCH 5/9 rsi: SDIO functionality
From: Jahnavi Meher <[email protected]>
This file adds the rsi_sdio module, enabling the SDIO interface for the 91x chipsets.
Signed-off-by Jahnavi Meher <[email protected]>
---
rsi_sdio.c | 941 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 941 insertions(+)
drivers/net/wireless/rsi/common/rsi_sdio.c +941 -0
@@ -0,0 +1,941 @@ +/** +* @file rsi_sdio.c +* @author +* @version 1.0 +* +* @section LICENSE +* Copyright (c) 2013 Redpine Signals Inc. +* +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +* +* @section DESCRIPTION +* +* The file contains Generic HAL layer for SDIO. +*/ + +#include "../include/rsi_main.h" +#include "../include/rsi_hw_intf.h" +#include "../include/rsi_device_ops.h" + +/** +* This function prepares cmd 52 read/write arg +* +* @param rw Read/write +* @param func function number +* @param raw indicates whether to perform read after write +* @param address address to which to read/write +* @param writedata data to write +* @return argument +*/ +static unsigned long rsi_sdio_set_cmd52_arg (bool rw, +unsigned char func, +unsigned char raw, +unsigned int address, +unsigned char writedata) +{ +return ((rw &1 ) <<31 ) | ((func &0x7 ) <<28 ) | + ((raw &1 ) <<27 ) | (1 <<26 ) | + ((address &0x1FFFF ) <<9 ) | (1 <<8 ) | + (writedata &0xFF ); +} + +/** +* This function issues cmd52 byte write onto the card. +* +* @param card Pointer to the mmc_card. +* @param address Address to write. +* @param byte Data to write. +* @return Write status. +*/ +static int rsi_cmd52writebyte (struct mmc_card *card, +unsigned int address, +unsigned char byte) +{ +struct mmc_command io_cmd; +unsigned long arg; + +memset (&io_cmd,0 ,sizeof (io_cmd)); + arg =rsi_sdio_set_cmd52_arg (1 ,0 ,0 , address, byte); + io_cmd.opcode =SD_IO_RW_DIRECT ; + io_cmd.arg = arg; + io_cmd.flags =MMC_RSP_R5 |MMC_CMD_AC ; + +return mmc_wait_for_cmd (card->host, &io_cmd,0 ); +} + +/** +* This function issues cmd52 byte read onto the card. +* +* @param card Pointer to the mmc_card. +* @param address Address to read from. +* @param byte Variable to store read value. +* @return Read status. +*/ +static int rsi_cmd52readbyte (struct mmc_card *card, +unsigned int address, +unsigned char *byte) +{ +struct mmc_command io_cmd; +unsigned long arg; +int err; + +memset (&io_cmd,0 ,sizeof (io_cmd)); + arg =rsi_sdio_set_cmd52_arg (0 ,0 ,0 , address,0 ); + io_cmd.opcode =SD_IO_RW_DIRECT ; + io_cmd.arg = arg; + io_cmd.flags =MMC_RSP_R5 |MMC_CMD_AC ; + + err =mmc_wait_for_cmd (card->host, &io_cmd,0 ); +if ((!err) && (byte)) + *byte = io_cmd.resp[0 ] &0xFF ; +return err; +} + +/** +* This function issues sdio commands. +* +* @param func Pointer to the sdio_func structure. +* @param opcode Opcode value. +* @param arg Arguments to pass. +* @param flags Flags which are set. +* @param resp Pointer to store response. +* @return err: command status as 0 or -1. +*/ +static int rsi_issue_sdiocommand (struct sdio_func *func, +unsigned int opcode, +unsigned int arg, +unsigned int flags, +unsigned int *resp) +{ +struct mmc_command cmd; +int err; +struct mmc_host *host; + + host = func->card->host; + +memset (&cmd,0 ,sizeof (struct mmc_command )); + cmd.opcode = opcode; + cmd.arg = arg; + cmd.flags = flags; + err =mmc_wait_for_cmd (host, &cmd,3 ); + +if ((!err) && (resp)) + *resp = cmd.resp[0 ]; + +return err; +} + +/** +* This function is called upon the occurence of an interrupt. +* +* @param function Pointer to the sdio_func structure. +* @return None. +*/ +static void rsi_handle_interrupt (struct sdio_func *function) +{ +struct rsi_hw *adapter =sdio_get_drvdata (function); + +sdio_release_host (function); +rsi_interrupt_handler (adapter->priv); +sdio_claim_host (function); + +return ; +} + +/** +* This function resets and re-initializes the card. +* +* @param pfunction Pointer to the sdio_func structure. +* @return None. +*/ +static void rsi_reset_card (struct sdio_func *pfunction) +{ +int ret =0 ; +int err; +struct mmc_card *card = pfunction->card; +struct mmc_host *host = card->host; +unsigned char cmd52_resp; +unsigned int clock; +unsigned int resp, i; +unsigned short rca; +int bit = (fls (host->ocr_avail) -1 ); + +/* Reset 9110 chip */ + ret =rsi_cmd52writebyte (pfunction->card, +SDIO_CCCR_ABORT , + (1 <<3 )); + +/* Card will not send any response as it is getting reset immediately +* Hence expect a timeout status from host controller +*/ +if (ret != -ETIMEDOUT ) +rsi_dbg (ERR_ZONE ,"%s: Reset failed : %d\n" , __func__, ret); + +/* Wait for few milli seconds to get rid of residue charges if any */ +msleep (20 ); + +/* Initialize the SDIO card */ + host->ios.vdd = bit; + host->ios.chip_select =MMC_CS_DONTCARE ; + host->ios.bus_mode =MMC_BUSMODE_OPENDRAIN ; + host->ios.power_mode =MMC_POWER_UP ; + host->ios.bus_width =MMC_BUS_WIDTH_1 ; + host->ios.timing =MMC_TIMING_LEGACY ; + host->ops->set_ios (host, &host->ios); + +/** +* This delay should be sufficient to allow the power supply +* to reach the minimum voltage. +*/ +msleep (20 ); + + host->ios.clock = host->f_min; + host->ios.power_mode =MMC_POWER_ON ; + host->ops->set_ios (host, &host->ios); + +/** +* This delay must be at least 74 clock sizes, or 1 ms, or the +* time required to reach a stable voltage. +*/ +msleep (20 ); + +/* Issue CMD0. Goto idle state */ + host->ios.chip_select =MMC_CS_HIGH ; + host->ops->set_ios (host, &host->ios); +msleep (20 ); + err =rsi_issue_sdiocommand (pfunction, +MMC_GO_IDLE_STATE , +0 , + (MMC_RSP_NONE |MMC_CMD_BC ), +NULL ); + host->ios.chip_select =MMC_CS_DONTCARE ; + host->ops->set_ios (host, &host->ios); +msleep (20 ); + host->use_spi_crc =0 ; + +if (err) +rsi_dbg (ERR_ZONE ,"%s: CMD0 failed : %d\n" , __func__, err); + +if (!host->ocr_avail) { +/* Issue CMD5, arg = 0 */ + err =rsi_issue_sdiocommand (pfunction, +SD_IO_SEND_OP_COND , +0 , + (MMC_RSP_R4 |MMC_CMD_BCR ), + &resp); +if (err) { +rsi_dbg (ERR_ZONE ,"%s: CMD5 failed : %d\n" , + __func__, err); + } + host->ocr_avail = resp; + } + +/* Issue CMD5, arg = ocr. Wait till card is ready */ +for (i =0 ; i <100 ; i++) { + err =rsi_issue_sdiocommand (pfunction, +SD_IO_SEND_OP_COND , + host->ocr_avail, + (MMC_RSP_R4 |MMC_CMD_BCR ), + &resp); +if (err) { +rsi_dbg (ERR_ZONE ,"%s: CMD5 failed : %d\n" , + __func__, err); +break ; + } + +if (resp &MMC_CARD_BUSY ) +break ; +msleep (20 ); + } + +if ((i ==100 ) || (err)) { +rsi_dbg (ERR_ZONE ,"%s: card in not ready : %d %d\n" , + __func__, i, err); +return ; + } + +/* Issue CMD3, get RCA */ + err =rsi_issue_sdiocommand (pfunction, +SD_SEND_RELATIVE_ADDR , +0 , + (MMC_RSP_R6 |MMC_CMD_BCR ), + &resp); +if (err) { +rsi_dbg (ERR_ZONE ,"%s: CMD3 failed : %d\n" , __func__, err); +return ; + } + rca = resp >>16 ; + host->ios.bus_mode =MMC_BUSMODE_PUSHPULL ; + host->ops->set_ios (host, &host->ios); + +/* Issue CMD7, select card */ + err =rsi_issue_sdiocommand (pfunction, +MMC_SELECT_CARD , + (rca <<16 ), + (MMC_RSP_R1 |MMC_CMD_AC ), +NULL ); +if (err) { +rsi_dbg (ERR_ZONE ,"%s: CMD7 failed : %d\n" , __func__, err); +return ; + } + +/* Enable high speed */ +if (card->host->caps &MMC_CAP_SD_HIGHSPEED ) { +rsi_dbg (ERR_ZONE ,"%s: Set high speed mode\n" , __func__); + err =rsi_cmd52readbyte (card,SDIO_CCCR_SPEED , &cmd52_resp); +if (err) { +rsi_dbg (ERR_ZONE ,"%s: CCCR speed reg read failed: %d\n" , + __func__, err); + card->state &= ~MMC_STATE_HIGHSPEED ; + }else { + err =rsi_cmd52writebyte (card, +SDIO_CCCR_SPEED , + (cmd52_resp |SDIO_SPEED_EHS )); +if (err) { +rsi_dbg (ERR_ZONE , +"%s: CCR speed regwrite failed %d\n" , + __func__, err); +return ; + } +mmc_card_set_highspeed (card); + host->ios.timing =MMC_TIMING_SD_HS ; + host->ops->set_ios (host, &host->ios); + } + } + +/* Set clock */ +if (mmc_card_highspeed (card)) + clock =50000000 ; +else + clock = card->cis.max_dtr; + +if (clock > host->f_max) + clock = host->f_max; + + host->ios.clock = clock; + host->ops->set_ios (host, &host->ios); + +if (card->host->caps &MMC_CAP_4_BIT_DATA ) { +/* CMD52: Set bus width & disable card detect resistor */ + err =rsi_cmd52writebyte (card, +SDIO_CCCR_IF , + (SDIO_BUS_CD_DISABLE | +SDIO_BUS_WIDTH_4BIT )); +if (err) { +rsi_dbg (ERR_ZONE ,"%s: Set bus mode failed : %d\n" , + __func__, err); +return ; + } + host->ios.bus_width =MMC_BUS_WIDTH_4 ; + host->ops->set_ios (host, &host->ios); + } +return ; +} + +/** +* This function sets the clock frequency +* +* @param adapter Pointer to the adapter structure. +* @param freq Clock frequency. +* @return 0 on success. +*/ +static int rsi_setclock (struct rsi_hw *adapter,unsigned int freq) +{ +unsigned int clock; +struct mmc_host *host = adapter->pfunction->card->host; + + clock = freq *1000 ; +if (clock > host->f_max) + clock = host->f_max; + host->ios.clock = clock; + host->ops->set_ios (host, &host->ios); +return 0 ; +} + +/** +* This function sets the host block length. +* +* @param adapter Pointer to the adapter structure. +* @param length Block length to be set. +* @return status: 0 on success, -1 on failure. +*/ +static int rsi_setblocklength (struct rsi_hw *adapter,unsigned int length) +{ +int status; +rsi_dbg (INIT_ZONE ,"%s: Setting the block length\n" , __func__); + + status =sdio_set_block_size (adapter->pfunction, length); + adapter->pfunction->max_blksize =256 ; + +rsi_dbg (INFO_ZONE , +"%s: Operational blk length is %d\n" , __func__, length); +return status; +} + +/** +* This function queries and sets the card's features. +* +* @param adapter Pointer to the adapter structure. +* @return status: 0 on success, -1 on failure. +*/ +static int rsi_setupcard (struct rsi_hw *adapter) +{ +int status =0 ; + +if (rsi_setclock (adapter,50000 )) { +rsi_dbg (INFO_ZONE , +"%s: Unsuccessful at setting clk\n" , __func__); +return -1 ; + } + + adapter->tx_blk_size =256 ; + adapter->rx_blk_size =256 ; + status =rsi_setblocklength (adapter, adapter->tx_blk_size); +if (status) { +rsi_dbg (ERR_ZONE , +"%s: Unable to set block length\n" , __func__); + } +return status; +} + +/** +* This function does the actual initialization of SDBUS slave registers. +* +* @param adapter Pointer to the adapter structure. +* @return status: 0 on success, -1 on failure. +*/ +static int rsi_init_sdio_slave_regs (struct rsi_hw *adapter) +{ +unsigned char function =0 ; +unsigned char byte; +int status =0 ; + +if (adapter->next_read_delay) { + byte = adapter->next_read_delay; + status =rsi_write_register (adapter, + function, +SDIO_NXT_RD_DELAY2 , + &byte); +if (status) { +rsi_dbg (ERR_ZONE , +"%s: Failed to write SDIO_NXT_RD_DELAY2\n" , + __func__); +return -1 ; + } + } + +if (adapter->sdio_high_speed_enable) { +rsi_dbg (INIT_ZONE ,"%s: Enabling SDIO High speed\n" , __func__); + byte =0x3 ; + + status =rsi_write_register (adapter, + function, +SDIO_REG_HIGH_SPEED , + &byte); +if (status) { +rsi_dbg (ERR_ZONE , +"%s: Failed to enable SDIO high speed\n" , + __func__); +return -1 ; + } + } + +/* This tells SDIO FIFO when to start read to host */ +rsi_dbg (INIT_ZONE ,"%s: Initialzing SDIO read start level\n" , __func__); + byte =0x24 ; + + status =rsi_write_register (adapter, + function, +SDIO_READ_START_LVL , + &byte); +if (status) { +rsi_dbg (ERR_ZONE , +"%s: Failed to write SDIO_READ_START_LVL\n" , __func__); +return -1 ; + } + +rsi_dbg (INIT_ZONE ,"%s: Initialzing FIFO ctrl registers\n" , __func__); + byte = (128 -32 ); + + status =rsi_write_register (adapter, + function, +SDIO_READ_FIFO_CTL , + &byte); +if (status) { +rsi_dbg (ERR_ZONE , +"%s: Failed to write SDIO_READ_FIFO_CTL\n" , __func__); +return -1 ; + } + + byte =32 ; + status =rsi_write_register (adapter, + function, +SDIO_WRITE_FIFO_CTL , + &byte); +if (status) { +rsi_dbg (ERR_ZONE , +"%s: Failed to write SDIO_WRITE_FIFO_CTL\n" , __func__); +return -1 ; + } + +return 0 ; +} + +static int rsi_init_sdio_interface (struct rsi_hw *adapter, +struct sdio_func *pfunction) +{ +int status =0 ; +sdio_claim_host (pfunction); + + pfunction->enable_timeout =100 ; + status =sdio_enable_func (pfunction); +if (status) { +rsi_dbg (ERR_ZONE ,"%s: Failed to enable interface\n" , __func__); +sdio_release_host (pfunction); +return status; + } + +rsi_dbg (INIT_ZONE ,"%s: Enabled the interface\n" , __func__); + + adapter->pfunction = pfunction; + adapter->device = &pfunction->dev; + +sdio_set_drvdata (pfunction, adapter); + + status =rsi_setupcard (adapter); +if (status) { +rsi_dbg (ERR_ZONE ,"%s: Failed to setup card\n" , __func__); + goto fail; + } + +rsi_dbg (INIT_ZONE ,"%s: Setup card succesfully\n" , __func__); + + status =rsi_init_sdio_slave_regs (adapter); +if (status) { +rsi_dbg (ERR_ZONE ,"%s: Failed to init slave regs\n" , __func__); + goto fail; + } +sdio_release_host (pfunction); +return status; +fail: +sdio_disable_func (pfunction); +sdio_release_host (pfunction); +return status; +} + +/** +* This function registers the client driver's interrupt handler +* with the bus driver. +* +* @param pfunction Pointer to the sdio_func structure. +* @param interrupt_handler Pointer to the interrupt handler. +* @param pContext Pointer to context of interrupt. +* @return None. +*/ +static int rsi_request_interrupt_handler (struct sdio_func *pfunction, +SD_INTERRUPT interrupt_handler) +{ +int status; + + status =sdio_claim_irq (pfunction, + (sdio_irq_handler_t *)interrupt_handler); +if (status) { +rsi_dbg (ERR_ZONE ,"%s: Failed to request IRQ %d\n" , __func__, + status); + } +return status; +} + +/** +* This function acks the interrupt received. +* +* @param adapter Pointer to the adapter structure. +* @param int_bit Interrupt bit to write into register. +* @return Void. +*/ +void rsi_ack_interrupt (struct rsi_hw *adapter,unsigned char int_bit) +{ +int status; + status =rsi_write_register (adapter, +1 , + (SDIO_FUN1_INTR_CLR_REG | +SD_REQUEST_MASTER ), + &int_bit); +if (status) +rsi_dbg (ERR_ZONE ,"%s: unable to send ack\n" , __func__); +return ; +} + +/** +* This function reads one byte of information from a register. +* +* @param adapter Pointer to the adapter structure. +* @param addr Address of the register. +* @param data Pointer to the data that stores the data read. +* @return 0 on success, -1 on failure. +*/ +int rsi_read_register (struct rsi_hw *adapter, +unsigned int addr, +unsigned char *data) +{ +unsigned char fun_num =0 ; +int status; + +sdio_claim_host (adapter->pfunction); + +if (fun_num ==0 ) + *data =sdio_f0_readb (adapter->pfunction, addr, &status); +else + *data =sdio_readb (adapter->pfunction, addr, &status); + +sdio_release_host (adapter->pfunction); + +if (status) +return -1 ; +else +return 0 ; +} + +/** +* This function writes one byte of information into a register. +* +* @param adapter Pointer to the adapter structure. +* @param function Function Number. +* @param addr Address of the register. +* @param data Pointer to the data tha has to be written. +* @return 0 on success, -1 on failure. +*/ +int rsi_write_register (struct rsi_hw *adapter, +unsigned char function, +unsigned int addr, +unsigned char *data) +{ +int status =0 ; + +sdio_claim_host (adapter->pfunction); + +if (function ==0 ) +sdio_f0_writeb (adapter->pfunction, *data, addr, &status); +else +sdio_writeb (adapter->pfunction, *data, addr, &status); + +sdio_release_host (adapter->pfunction); + +if (status) +return -1 ; +else +return 0 ; +} + +/** +* This function read multiple bytes of information from the SD card. +* +* @param adapter Pointer to the adapter structure. +* @param addr Address of the register. +* @param count Number of multiple bytes to be read. +* @param data Pointer to the read data. +* @return 0 on success, -1 on failure. +*/ +int rsi_read_register_multiple (struct rsi_hw *adapter, +unsigned int addr, +unsigned int count, +unsigned char *data) +{ +unsigned int status; + +sdio_claim_host (adapter->pfunction); + + status =sdio_readsb (adapter->pfunction, data, addr, count); + +sdio_release_host (adapter->pfunction); + +if (status !=0 ) +rsi_dbg (ERR_ZONE ,"%s: Synch Cmd53 read failed\n" , __func__); +return status; +} + +/** +* This function writes multiple bytes of information to the SD card. +* +* @param adapter Pointer to the adapter structure. +* @param addr Address of the register. +* @param Pointer to the data that has to be written. +* @param count Number of multiple bytes to be written. +* @return 0 on success, -1 on failure. +*/ +int rsi_write_register_multiple (struct rsi_hw *adapter, +unsigned int addr, +unsigned char *data, +unsigned int count) +{ +int status =0 ; + +if (adapter->stop_card_write ==2 ) { +rsi_dbg (ERR_ZONE ,"%s: Stopping card writes\n" , __func__); +return 0 ; + }else if (adapter->stop_card_write ==1 ) { +rsi_dbg (ERR_ZONE ,"%s: Continue card writes\n" , __func__); + adapter->stop_card_write++; + } + +sdio_claim_host (adapter->pfunction); + + status =sdio_writesb (adapter->pfunction, addr, data, count); + +sdio_release_host (adapter->pfunction); + +if (status) { +rsi_dbg (ERR_ZONE ,"%s: Synch Cmd53 write failed %d\n" , + __func__, status); + adapter->stop_card_write =2 ; +rsi_print (ERR_ZONE , adapter->prev_desc,FRAME_DESC_SZ ); + }else { +memcpy (adapter->prev_desc, data,FRAME_DESC_SZ ); + } +return status; +} + +/** +* This function writes the packet to the device. +* +* @param adapter Pointer to the adapter structure. +* @param pkt Pointer to the data to be written on to the device. +* @param len length of the data to be written on to the device. +* @return 0 on success, -1 on failure. +*/ +int rsi_host_intf_write_pkt (struct rsi_hw *adapter, +unsigned char *pkt, +unsigned int len) +{ +unsigned int block_size = adapter->tx_blk_size; +unsigned int num_blocks, address, length; +unsigned int queueno; +int status =0 ; + + queueno = ((pkt[1 ] >>4 ) &0xf ); + +if ((!len) && (queueno ==RSI_WIFI_DATA_Q )) { +rsi_dbg (ERR_ZONE ,"%s: Wrong length\n" , __func__); +return -1 ; + } + + num_blocks = len / block_size; + +if (len % block_size) + num_blocks++; + +if ((cpu_to_le16 (*(unsigned short *)pkt) <14 ) && + (queueno ==RSI_WIFI_DATA_Q )) { +rsi_dbg (ERR_ZONE ,"%s:Small pkt sending@@@\n" , __func__); +return -1 ; + } + + address = (num_blocks * block_size | (queueno <<12 )); + length = num_blocks * block_size; + + status =rsi_write_register_multiple (adapter, + address, + (unsigned char *)pkt, + length); +if (status) { +rsi_dbg (ERR_ZONE ,"%s: Unable to write onto the card: %d\n" , + __func__, status); + } +rsi_dbg (DATA_TX_ZONE ,"%s: Successfully written onto card\n" , __func__); +return status; +} + +/** +* This function reads the packet from the SD card. +* +* @param adapter Pointer to the adapter data structure. +* @param pkt Pointer to the packet data to be read from the the device. +* @param length Length of the data to be read from the device. +* @return 0 on success, -1 on failure. +*/ +int rsi_host_intf_read_pkt (struct rsi_hw *adapter, +unsigned char *pkt, +unsigned int length) +{ +int status =0 ; + +if (!length) { +rsi_dbg (ERR_ZONE ,"%s: Pkt size is zero\n" , __func__); +return status; + } + + status =rsi_read_register_multiple (adapter, + length, + length,/*num of bytes*/ + (unsigned char *)pkt); + +if (status) { +rsi_dbg (ERR_ZONE ,"%s: Failed to read frame: %d\n" , __func__, + status); + } +return status; +} + +/** +* This function is called by kernel when the driver provided +* Vendor and device IDs are matched. All the initialization +* work is done here. +* +* @param pfunction Pointer to the sdio_func structure. +* @param id Pointer to sdio_device_id structure. +* @return 0 on success, 1 on failure. +*/ +static int rsi_probe (struct sdio_func *pfunction, +const struct sdio_device_id *id) +{ +struct rsi_hw *adapter; + +rsi_dbg (INIT_ZONE ,"%s: Init function called\n" , __func__); + + adapter =rsi_init_os_intf_ops (); +if (!adapter) { +rsi_dbg (ERR_ZONE ,"%s: Failed to init os intf ops\n" , + __func__); +return 1 ; + } + +if (rsi_init_sdio_interface (adapter, pfunction)) { +rsi_dbg (ERR_ZONE ,"%s: Failed to init sdio interface\n" , + __func__); + goto fail; + } + +if (rsi_device_init (adapter->priv,0 )) { +rsi_dbg (ERR_ZONE ,"%s: Failed in device init\n" , __func__); +sdio_claim_host (pfunction); +sdio_disable_func (pfunction); +sdio_release_host (pfunction); + goto fail; + } + +sdio_claim_host (pfunction); +if (rsi_request_interrupt_handler (pfunction, + (SD_INTERRUPT )rsi_handle_interrupt)) { +sdio_release_host (pfunction); + goto fail; + } + +sdio_release_host (pfunction); +rsi_dbg (INIT_ZONE ,"%s: Registered Interrupt handler\n" , __func__); + +return 0 ; +fail: +rsi_deinit_os_intf_ops (adapter); +rsi_dbg (ERR_ZONE ,"%s: Failed in probe...Exiting\n" , __func__); +return 1 ; +} + +/** +* This function performs the reverse of the probe function. +* +* @param pfunction Pointer to the sdio_func structure. +* @return void. +*/ +static void rsi_disconnect (struct sdio_func *pfunction) +{ +struct rsi_hw *adapter =sdio_get_drvdata (pfunction); + +if (!adapter) +return ; + + adapter->stop_card_write =2 ; +rsi_device_deinit (adapter); + +sdio_claim_host (pfunction); +sdio_release_irq (pfunction); +sdio_disable_func (pfunction); +rsi_deinit_os_intf_ops (adapter); +rsi_reset_card (pfunction); +sdio_release_host (pfunction); + +return ; +} + +#ifdef CONFIG_PM +static int rsi_suspend (struct device *dev) +{ +/* Not yet implemented */ +return -ENOSYS ; +} + +static int rsi_resume (struct device *dev) +{ +/* Not yet implemented */ +return -ENOSYS ; +} + +static const struct dev_pm_ops rsi_pm_ops = { + .suspend = rsi_suspend, + .resume = rsi_resume, +}; +#endif + +static const struct sdio_device_id rsi_dev_table[] = { + {SDIO_DEVICE (0x303 ,0x100 ) }, + {SDIO_DEVICE (0x041B ,0x0301 ) }, + {SDIO_DEVICE (0x041B ,0x0201 ) }, + {SDIO_DEVICE (0x041B ,0x9330 ) }, + {/* Blank */ }, +}; + +static struct sdio_driver rsi_driver = { + .name ="RSI-SDIO WLAN" , + .probe = rsi_probe, + .remove = rsi_disconnect, + .id_table = rsi_dev_table, +#ifdef CONFIG_PM + .drv = { + .pm = &rsi_pm_ops, + } +#endif +}; + +/** +* This function registers the sdio module. +* +* @param Void. +* @return 0 on success. +*/ +static int rsi_module_init (void ) +{ +sdio_register_driver (&rsi_driver); +rsi_dbg (INIT_ZONE ,"%s: Registering driver\n" , __func__); +return 0 ; +} + +/** +* This function unregisters the sdio module. +* +* @param Void. +* @return None. +*/ +static void rsi_module_exit (void ) +{ +sdio_unregister_driver (&rsi_driver); +rsi_dbg (INFO_ZONE ,"%s: Unregistering driver\n" , __func__); +return ; +} + +module_init (rsi_module_init); +module_exit (rsi_module_exit); + +MODULE_AUTHOR ("Redpine Signals Inc" ); +MODULE_DESCRIPTION ("Common layer for RSI drivers" ); +MODULE_SUPPORTED_DEVICE ("RSI-91x" ); +MODULE_VERSION ("0.1" ); +MODULE_LICENSE ("GPL" );