rtl8188eu/os_dep/linux/gspi_ops_linux.c
Larry Finger 065126d8ce rtl8188eu: Place driver rtl8188EUS_rtl8189ES_linux_v4.1.8_9499.20131104 in branch v4.1.8_9499
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
2014-12-11 15:15:04 -06:00

432 lines
10 KiB
C
Executable file

/******************************************************************************
*
* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*
*******************************************************************************/
#define _GSPI_OPS_LINUX_C_
#include <drv_types.h>
#include <linux/spi/spi.h>
#include "rtl8723a_hal.h"
#include "rtl8723a_spec.h"
#include "gspi_ops.h"
int spi_send_msg(PADAPTER Adapter, struct spi_transfer xfers[], u32 IoAction)
{
struct dvobj_priv *psddev;
struct spi_device *spi;
struct spi_message msg;
int ret = 1;
if (Adapter == NULL) {
DBG_8192C(KERN_ERR "%s: padapter is NULL!\n", __func__);
return 1;
}
psddev = adapter_to_dvobj(Adapter);
spi = psddev->intf_data.func;
spi_message_init(&msg);
spi_message_add_tail(&xfers[0], &msg);
spi_message_add_tail(&xfers[1], &msg);
spi_message_add_tail(&xfers[2], &msg);
ret = spi_sync(spi, &msg);
if (ret) {
DBG_8192C("%s: FAIL!\n", __func__);
}
return ret;
}
int addr_convert(u32 addr)
{
u32 domain_id = 0 ;
u32 temp_addr = addr&0xffff0000;
if (temp_addr == 0 ) {
domain_id = WLAN_IOREG_DOMAIN;
return domain_id;
}
switch (temp_addr) {
case SPI_LOCAL_OFFSET:
domain_id = SPI_LOCAL_DOMAIN;
break;
case WLAN_IOREG_OFFSET:
domain_id = WLAN_IOREG_DOMAIN;
break;
case FW_FIFO_OFFSET:
domain_id = FW_FIFO_DOMAIN;
break;
case TX_HIQ_OFFSET:
domain_id = TX_HIQ_DOMAIN;
break;
case TX_MIQ_OFFSET:
domain_id = TX_MIQ_DOMAIN;
break;
case TX_LOQ_OFFSET:
domain_id = TX_LOQ_DOMAIN;
break;
case RX_RXOFF_OFFSET:
domain_id = RX_RXFIFO_DOMAIN;
break;
default:
break;
}
//sys_mib.Spi_Transation_record.domain_id =domain_id;
return domain_id;
}
static u32 buf_endian_reverse(u32 src)
{
return (((src&0x000000ff)<<24)|((src&0x0000ff00)<<8)|
((src&0x00ff0000)>>8)|((src&0xff000000)>>24));
}
void spi_get_status_info(ADAPTER* Adapter, unsigned char *status)
{
HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter);
pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX] = GET_STATUS_PUB_PAGE_NUM(status);
pHalData->SdioTxFIFOFreePage[HI_QUEUE_IDX] = GET_STATUS_HI_PAGE_NUM(status);
pHalData->SdioTxFIFOFreePage[MID_QUEUE_IDX] = GET_STATUS_MID_PAGE_NUM(status);
pHalData->SdioTxFIFOFreePage[LOW_QUEUE_IDX] = GET_STATUS_LOW_PAGE_NUM(status);
//DBG_8192C("%s: Free page for HIQ(%#x),MIDQ(%#x),LOWQ(%#x),PUBQ(%#x)\n",
// __FUNCTION__,
// pHalData->SdioTxFIFOFreePage[HI_QUEUE_IDX],
// pHalData->SdioTxFIFOFreePage[MID_QUEUE_IDX],
// pHalData->SdioTxFIFOFreePage[LOW_QUEUE_IDX],
// pHalData->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]);
}
int spi_read_write_reg(PADAPTER pAdapter, int write_flag, u32 addr, char * buf, int len, u32 eddien)
{
int fun = 1, domain_id = 0x0; //LOCAL
unsigned int cmd = 0 ;
int byte_en = 0 ;//,i = 0 ;
int ret = 0;
unsigned char status[8] = {0};
unsigned int data_tmp = 0;
//u32 force_bigendian = !eddien;
u32 force_bigendian = eddien;
if (len!=1 && len!=2 && len != 4) {
return -1;
}
domain_id = addr_convert(addr);
addr &= 0x7fff;
len &= 0xff;
if (write_flag) //write register
{
int remainder = addr % 4;
u32 val32 = *(u32 *)buf;
switch(len) {
case 1:
byte_en = (0x1 << remainder);
data_tmp = (val32& 0xff)<< (remainder*8);
break;
case 2:
byte_en = (0x3 << remainder);
data_tmp = (val32 & 0xffff)<< (remainder*8);
break;
case 4:
byte_en = 0xf;
data_tmp = val32 & 0xffffffff;
break;
default:
byte_en = 0xf;
data_tmp = val32 & 0xffffffff;
break;
}
}
else //read register
{
switch(len) {
case 1:
byte_en = 0x1;
break;
case 2:
byte_en = 0x3;
break;
case 4:
byte_en = 0xf;
break;
default:
byte_en = 0xf;
break;
}
}
//addr = 0xF0 4byte: 0x2800f00f
REG_LEN_FORMAT(&cmd, byte_en);
REG_ADDR_FORMAT(&cmd, (addr&0xfffffffc));
REG_DOMAIN_ID_FORMAT(&cmd, domain_id);
REG_FUN_FORMAT(&cmd, fun);
REG_RW_FORMAT(&cmd, write_flag);
//DBG_8192C("spi_read_write_reg cmd1: %x, data_tmp is %x\n",cmd, data_tmp);
if (force_bigendian) {
cmd = buf_endian_reverse(cmd);
}
//io is one by one, so we do not need fwps_lock here
//rtw_spin_lock(&padapter->halpriv.fwps_lock);
//padapter->io_fifo_processing = _TRUE;
if (!write_flag && (domain_id!= RX_RXFIFO_DOMAIN)) {
u32 read_data = 0;
struct spi_transfer xfers[3];
_rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer));
_rtw_memset(buf, 0x0, len);
xfers[0].tx_buf = &cmd;
xfers[0].len = 4;
xfers[1].rx_buf = status;
xfers[1].len = 8;
xfers[2].rx_buf = &read_data;
xfers[2].len = 4;
//DBG_8192C("spi_read_write_reg: read_data is %x\n", read_data);
ret = spi_send_msg(pAdapter, xfers, 0);
if (ret) {
DBG_8192C(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, ret, addr);
read_data = 0;
_rtw_memset(status, 0, 8);
}
//DBG_8192C("spi_read_write_reg: read_data is %x\n", read_data);
read_data = EF4Byte(read_data);
//add for 8810
#ifdef CONFIG_BIG_ENDIAN
if (!force_bigendian)
read_data = buf_endian_reverse(read_data);
#else
if (force_bigendian)
read_data = buf_endian_reverse(read_data);
#endif
*(u32*)buf = read_data;
//DBG_8192C("spi_read_write_reg: read: buf is %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3]);
} else if (write_flag ) {
struct spi_transfer xfers[3];
_rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer));
xfers[0].tx_buf = &cmd;
xfers[0].len = 4;
xfers[1].tx_buf = &data_tmp;
xfers[1].len = 4;
xfers[2].rx_buf = status;
xfers[2].len = 8;
//DBG_8192C("spi_read_write_reg data_tmp 111: %x\n",data_tmp);
#ifdef CONFIG_BIG_ENDIAN
if (!force_bigendian)
data_tmp = buf_endian_reverse(data_tmp);
#else
if (force_bigendian)
data_tmp = buf_endian_reverse(data_tmp);
#endif
ret = spi_send_msg(pAdapter, xfers, 0);
if (ret) {
DBG_8192C(KERN_ERR "%s: FAIL!(%d) addr=0x%05x\n", __func__, ret, addr);
_rtw_memset(status, 0, 8);
}
}
//padapter->io_fifo_processing = _FALSE;
spi_get_status_info(pAdapter, (unsigned char*)status);
return ret;
}
u8 spi_read8(ADAPTER *Adapter, unsigned int addr, s32 *err)
{
unsigned int ret = 0;
int val32 = 0 , remainder = 0 ;
s32 _err = 0;
_err = spi_read_write_reg(Adapter,0,addr&0xFFFFFFFC,(char *)&ret,4,0);
remainder = addr % 4;
val32 = ret;
val32 = (val32& (0xff<< (remainder<<3)))>>(remainder<<3);
if (err)
*err = _err;
return (u8)val32;
}
u16 spi_read16(ADAPTER *Adapter, u32 addr, s32 *err)
{
unsigned int ret = 0;
int val32 = 0 , remainder = 0 ;
s32 _err = 0;
_err = spi_read_write_reg(Adapter,0,addr&0xFFFFFFFC,(char *)&ret,4,0);
remainder = addr % 4;
val32 = ret;
val32 = (val32& (0xffff<< (remainder<<3)))>>(remainder<<3);
if (err)
*err = _err;
return (u16)val32;
}
u32 spi_read32(ADAPTER *Adapter, u32 addr, s32 *err)
{
unsigned int ret = 0;
s32 _err = 0;
_err = spi_read_write_reg(Adapter,0,addr&0xFFFFFFFC,(char *)&ret,4,0);
if (err)
*err = _err;
return ret;
}
void spi_write8(ADAPTER *Adapter, u32 addr, u8 buf, s32 *err)
{
int ret = 0;
ret = spi_read_write_reg(Adapter,1,addr,(char *)&buf,1,0);
if (err)
*err = ret;
}
void spi_write16(ADAPTER *Adapter, u32 addr, u16 buf, s32 *err)
{
int ret = 0;
ret = spi_read_write_reg(Adapter,1,addr,(char *)&buf,2,0);
if (err)
*err = ret;
}
void spi_write32(ADAPTER *Adapter, u32 addr, u32 buf, s32 *err)
{
int ret = 0;
ret = spi_read_write_reg(Adapter, 1,addr,(char *)&buf,4,0);
if (err)
*err = ret;
}
unsigned int spi_write8_endian(ADAPTER *Adapter, unsigned int addr, unsigned int buf, u32 big)
{
int ret = 0;
ret = spi_read_write_reg(Adapter,1,addr,(char *)&buf,1, big);
return ret;
}
void spi_write_tx_fifo(ADAPTER *Adapter, u8 *buf, int len, u32 fifo)
{
int fun =1; //TX_HIQ_FIFO
unsigned int cmd = 0;
unsigned char status[8];
u8 more_data = 0;
int ret = 0;
struct spi_transfer xfers[3];
_rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer));
xfers[0].tx_buf = &cmd;
xfers[0].len = 4;
xfers[1].tx_buf = buf;
xfers[1].len = len;//len/4;
xfers[2].rx_buf = status;
xfers[2].len = 8;
_func_enter_;
FIFO_LEN_FORMAT(&cmd, len); //TX Agg len
FIFO_DOMAIN_ID_FORMAT(&cmd, fifo);
FIFO_FUN_FORMAT(&cmd, fun);
FIFO_RW_FORMAT(&cmd, (unsigned int)1); //write
_rtw_memset(status, 0x00, 8);
ret = spi_send_msg(Adapter, xfers, 1);
if (ret) {
DBG_8192C("%s: FAIL!(%d)\n", __func__, ret);
_rtw_memset(status, 0, 8);
}
spi_get_status_info(Adapter, status);
more_data = GET_STATUS_HISR_LOW8BIT(status) & BIT(0);
//if(more_data) {
// rtw_queue_delayed_work(Adapter->recv_wq, &Adapter->recv_work, 0, (void*)Adapter);
//}
_func_exit_;
return;
}
int spi_read_rx_fifo(ADAPTER *Adapter, unsigned char *buf, int len, struct spi_more_data *pmore_data)
{
int fun =1, domain_id = 0x1f; //RX_FIFO
unsigned int cmd = 0;
unsigned char status[8];
int ret = 0;
struct spi_transfer xfers[3];
_rtw_memset(xfers, 0x00, 3*sizeof(struct spi_transfer));
xfers[0].tx_buf = &cmd;
xfers[0].len = 4;
xfers[1].rx_buf = buf;
xfers[1].len = len;
xfers[2].rx_buf = status;
xfers[2].len = 8;
FIFO_LEN_FORMAT(&cmd, len); //TX Agg len
FIFO_DOMAIN_ID_FORMAT(&cmd, domain_id);
FIFO_FUN_FORMAT(&cmd, fun);
FIFO_RW_FORMAT(&cmd, 0); //read
_rtw_memset(status, 0x00, 8);
_rtw_memset(buf, 0x0, len);
ret = spi_send_msg(Adapter, xfers, 1);
if (ret) {
DBG_8192C(KERN_ERR "%s: FAIL!(%d)\n", __func__, ret);
_rtw_memset(status, 0x00, 8);
_rtw_memset(buf, 0x0, len);
return _FAIL;
}
spi_get_status_info(Adapter, (unsigned char*)status);
pmore_data->more_data = GET_STATUS_HISR_LOW8BIT(status) & BIT(0);
pmore_data->len = GET_STATUS_RX_LENGTH(status);
return _SUCCESS;
}