staging: rts5208: add support for rts5208 and rts5288

There are still many rts5208/5288 card readers being used, but no
drivers are supported them in kernel now. This driver can make a
great convenience for people who use them.

Many other rts-series card reader are supported by mfd driver, but due
to much difference with others, rts5208/5288 can not add into mfd driver
pretty now, so we provide a separated driver here to support the device.

Signed-off-by: Micky Ching <micky_ching@realsil.com.cn>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Micky Ching 2013-11-12 17:16:08 +08:00 коммит произвёл Greg Kroah-Hartman
Родитель 8a76714dd3
Коммит fa590c222f
28 изменённых файлов: 23570 добавлений и 0 удалений

Просмотреть файл

@ -54,6 +54,8 @@ source "drivers/staging/rtl8188eu/Kconfig"
source "drivers/staging/rts5139/Kconfig"
source "drivers/staging/rts5208/Kconfig"
source "drivers/staging/frontier/Kconfig"
source "drivers/staging/phison/Kconfig"

Просмотреть файл

@ -19,6 +19,7 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_R8712U) += rtl8712/
obj-$(CONFIG_R8188EU) += rtl8188eu/
obj-$(CONFIG_RTS5139) += rts5139/
obj-$(CONFIG_RTS5208) += rts5208/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_LINE6_USB) += line6/

Просмотреть файл

@ -0,0 +1,15 @@
config RTS5208
tristate "Realtek PCI-E Card Reader RTS5208/5288 support"
depends on PCI && SCSI
help
Say Y here to include driver code to support the Realtek
PCI-E card reader rts5208/rts5288.
If this driver is compiled as a module, it will be named rts5208.
config RTS5208_DEBUG
bool "Realtek PCI-E Card Reader RTS5208/5288 verbose debug"
depends on RTS5208
help
Say Y here in order to have the rts5208 code generate
verbose debugging messages.

Просмотреть файл

@ -0,0 +1,6 @@
obj-$(CONFIG_RTS5208) := rts5208.o
ccflags-y := -Idrivers/scsi
rts5208-y := rtsx.o rtsx_chip.o rtsx_transport.o rtsx_scsi.o \
rtsx_card.o general.o sd.o xd.o ms.o spi.o

Просмотреть файл

@ -0,0 +1,7 @@
TODO:
- use kernel coding style
- checkpatch.pl fixes
- We will use the stack in drivers/mmc to implement
rts5208/5288 in the future
Micky Ching <micky_ching@realsil.com.cn>

Просмотреть файл

@ -0,0 +1,43 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_DEBUG_H
#define __REALTEK_RTSX_DEBUG_H
#include <linux/kernel.h>
#define RTSX_STOR "rts5208: "
#ifdef CONFIG_RTS5208_DEBUG
#define RTSX_DEBUGP(x...) pr_debug(RTSX_STOR x)
#define RTSX_DEBUGPN(x...) pr_debug(x)
#define RTSX_DEBUGPX(x...) printk(x)
#define RTSX_DEBUG(x) x
#else
#define RTSX_DEBUGP(x...)
#define RTSX_DEBUGPN(x...)
#define RTSX_DEBUGPX(x...)
#define RTSX_DEBUG(x)
#endif
#endif /* __REALTEK_RTSX_DEBUG_H */

Просмотреть файл

@ -0,0 +1,35 @@
/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#include "general.h"
int bit1cnt_long(u32 data)
{
int i, cnt = 0;
for (i = 0; i < 32; i++) {
if (data & 0x01)
cnt++;
data >>= 1;
}
return cnt;
}

Просмотреть файл

@ -0,0 +1,31 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __RTSX_GENERAL_H
#define __RTSX_GENERAL_H
#include "rtsx.h"
int bit1cnt_long(u32 data);
#endif /* __RTSX_GENERAL_H */

4208
drivers/staging/rts5208/ms.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,227 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_MS_H
#define __REALTEK_RTSX_MS_H
#define MS_DELAY_WRITE
#define MS_MAX_RETRY_COUNT 3
#define MS_EXTRA_SIZE 0x9
#define WRT_PRTCT 0x01
/* Error Code */
#define MS_NO_ERROR 0x00
#define MS_CRC16_ERROR 0x80
#define MS_TO_ERROR 0x40
#define MS_NO_CARD 0x20
#define MS_NO_MEMORY 0x10
#define MS_CMD_NK 0x08
#define MS_FLASH_READ_ERROR 0x04
#define MS_FLASH_WRITE_ERROR 0x02
#define MS_BREQ_ERROR 0x01
#define MS_NOT_FOUND 0x03
/* Transfer Protocol Command */
#define READ_PAGE_DATA 0x02
#define READ_REG 0x04
#define GET_INT 0x07
#define WRITE_PAGE_DATA 0x0D
#define WRITE_REG 0x0B
#define SET_RW_REG_ADRS 0x08
#define SET_CMD 0x0E
#define PRO_READ_LONG_DATA 0x02
#define PRO_READ_SHORT_DATA 0x03
#define PRO_READ_REG 0x04
#define PRO_READ_QUAD_DATA 0x05
#define PRO_GET_INT 0x07
#define PRO_WRITE_LONG_DATA 0x0D
#define PRO_WRITE_SHORT_DATA 0x0C
#define PRO_WRITE_QUAD_DATA 0x0A
#define PRO_WRITE_REG 0x0B
#define PRO_SET_RW_REG_ADRS 0x08
#define PRO_SET_CMD 0x0E
#define PRO_EX_SET_CMD 0x09
#ifdef SUPPORT_MAGIC_GATE
#define MG_GET_ID 0x40
#define MG_SET_LID 0x41
#define MG_GET_LEKB 0x42
#define MG_SET_RD 0x43
#define MG_MAKE_RMS 0x44
#define MG_MAKE_KSE 0x45
#define MG_SET_IBD 0x46
#define MG_GET_IBD 0x47
#endif
#ifdef XC_POWERCLASS
#define XC_CHG_POWER 0x16
#endif
#define BLOCK_READ 0xAA
#define BLOCK_WRITE 0x55
#define BLOCK_END 0x33
#define BLOCK_ERASE 0x99
#define FLASH_STOP 0xCC
#define SLEEP 0x5A
#define CLEAR_BUF 0xC3
#define MS_RESET 0x3C
#define PRO_READ_DATA 0x20
#define PRO_WRITE_DATA 0x21
#define PRO_READ_ATRB 0x24
#define PRO_STOP 0x25
#define PRO_ERASE 0x26
#define PRO_READ_2K_DATA 0x27
#define PRO_WRITE_2K_DATA 0x28
#define PRO_FORMAT 0x10
#define PRO_SLEEP 0x11
#define IntReg 0x01
#define StatusReg0 0x02
#define StatusReg1 0x03
#define SystemParm 0x10
#define BlockAdrs 0x11
#define CMDParm 0x14
#define PageAdrs 0x15
#define OverwriteFlag 0x16
#define ManagemenFlag 0x17
#define LogicalAdrs 0x18
#define ReserveArea 0x1A
#define Pro_IntReg 0x01
#define Pro_StatusReg 0x02
#define Pro_TypeReg 0x04
#define Pro_IFModeReg 0x05
#define Pro_CatagoryReg 0x06
#define Pro_ClassReg 0x07
#define Pro_SystemParm 0x10
#define Pro_DataCount1 0x11
#define Pro_DataCount0 0x12
#define Pro_DataAddr3 0x13
#define Pro_DataAddr2 0x14
#define Pro_DataAddr1 0x15
#define Pro_DataAddr0 0x16
#define Pro_TPCParm 0x17
#define Pro_CMDParm 0x18
#define INT_REG_CED 0x80
#define INT_REG_ERR 0x40
#define INT_REG_BREQ 0x20
#define INT_REG_CMDNK 0x01
#define BLOCK_BOOT 0xC0
#define BLOCK_OK 0x80
#define PAGE_OK 0x60
#define DATA_COMPL 0x10
#define NOT_BOOT_BLOCK 0x4
#define NOT_TRANSLATION_TABLE 0x8
#define HEADER_ID0 PPBUF_BASE2
#define HEADER_ID1 (PPBUF_BASE2 + 1)
#define DISABLED_BLOCK0 (PPBUF_BASE2 + 0x170 + 4)
#define DISABLED_BLOCK1 (PPBUF_BASE2 + 0x170 + 5)
#define DISABLED_BLOCK2 (PPBUF_BASE2 + 0x170 + 6)
#define DISABLED_BLOCK3 (PPBUF_BASE2 + 0x170 + 7)
#define BLOCK_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 2)
#define BLOCK_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 3)
#define BLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 4)
#define BLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 5)
#define EBLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 6)
#define EBLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 7)
#define PAGE_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 8)
#define PAGE_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 9)
#define MS_Device_Type (PPBUF_BASE2 + 0x1D8)
#define MS_4bit_Support (PPBUF_BASE2 + 0x1D3)
#define setPS_NG 1
#define setPS_Error 0
#define PARALLEL_8BIT_IF 0x40
#define PARALLEL_4BIT_IF 0x00
#define SERIAL_IF 0x80
#define BUF_FULL 0x10
#define BUF_EMPTY 0x20
#define MEDIA_BUSY 0x80
#define FLASH_BUSY 0x40
#define DATA_ERROR 0x20
#define STS_UCDT 0x10
#define EXTRA_ERROR 0x08
#define STS_UCEX 0x04
#define FLAG_ERROR 0x02
#define STS_UCFG 0x01
#define MS_SHORT_DATA_LEN 32
#define FORMAT_SUCCESS 0
#define FORMAT_FAIL 1
#define FORMAT_IN_PROGRESS 2
#define MS_SET_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag |= 0x80)
#define MS_CLR_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag &= 0x7F)
#define MS_TST_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag & 0x80)
void mspro_polling_format_status(struct rtsx_chip *chip);
void mspro_stop_seq_mode(struct rtsx_chip *chip);
int reset_ms_card(struct rtsx_chip *chip);
int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
u32 start_sector, u16 sector_cnt);
int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip,
int short_data_len, int quick_format);
void ms_free_l2p_tbl(struct rtsx_chip *chip);
void ms_cleanup_work(struct rtsx_chip *chip);
int ms_power_off_card3v3(struct rtsx_chip *chip);
int release_ms_card(struct rtsx_chip *chip);
#ifdef MS_DELAY_WRITE
int ms_delay_write(struct rtsx_chip *chip);
#endif
#ifdef SUPPORT_MAGIC_GATE
int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip);
#endif
#endif /* __REALTEK_RTSX_MS_H */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,186 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_H
#define __REALTEK_RTSX_H
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/cdrom.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include "debug.h"
#include "trace.h"
#include "general.h"
#define CR_DRIVER_NAME "rts5208"
#define pci_get_bus_and_slot(bus, devfn) \
pci_get_domain_bus_and_slot(0, (bus), (devfn))
/*
* macros for easy use
*/
#define rtsx_writel(chip, reg, value) \
iowrite32(value, (chip)->rtsx->remap_addr + reg)
#define rtsx_readl(chip, reg) \
ioread32((chip)->rtsx->remap_addr + reg)
#define rtsx_writew(chip, reg, value) \
iowrite16(value, (chip)->rtsx->remap_addr + reg)
#define rtsx_readw(chip, reg) \
ioread16((chip)->rtsx->remap_addr + reg)
#define rtsx_writeb(chip, reg, value) \
iowrite8(value, (chip)->rtsx->remap_addr + reg)
#define rtsx_readb(chip, reg) \
ioread8((chip)->rtsx->remap_addr + reg)
#define rtsx_read_config_byte(chip, where, val) \
pci_read_config_byte((chip)->rtsx->pci, where, val)
#define rtsx_write_config_byte(chip, where, val) \
pci_write_config_byte((chip)->rtsx->pci, where, val)
#define wait_timeout_x(task_state, msecs) \
do { \
set_current_state((task_state)); \
schedule_timeout((msecs) * HZ / 1000); \
} while (0)
#define wait_timeout(msecs) wait_timeout_x(TASK_INTERRUPTIBLE, (msecs))
#define STATE_TRANS_NONE 0
#define STATE_TRANS_CMD 1
#define STATE_TRANS_BUF 2
#define STATE_TRANS_SG 3
#define TRANS_NOT_READY 0
#define TRANS_RESULT_OK 1
#define TRANS_RESULT_FAIL 2
#define SCSI_LUN(srb) ((srb)->device->lun)
typedef unsigned long DELAY_PARA_T;
struct rtsx_chip;
struct rtsx_dev {
struct pci_dev *pci;
/* pci resources */
unsigned long addr;
void __iomem *remap_addr;
int irq;
/* locks */
spinlock_t reg_lock;
struct task_struct *ctl_thread; /* the control thread */
struct task_struct *polling_thread; /* the polling thread */
/* mutual exclusion and synchronization structures */
struct completion cmnd_ready; /* to sleep thread on */
struct completion control_exit; /* control thread exit */
struct completion polling_exit; /* polling thread exit */
struct completion notify; /* thread begin/end */
struct completion scanning_done; /* wait for scan thread */
wait_queue_head_t delay_wait; /* wait during scan, reset */
struct mutex dev_mutex;
/* host reserved buffer */
void *rtsx_resv_buf;
dma_addr_t rtsx_resv_buf_addr;
char trans_result;
char trans_state;
struct completion *done;
/* Whether interrupt handler should care card cd info */
u32 check_card_cd;
struct rtsx_chip *chip;
};
typedef struct rtsx_dev rtsx_dev_t;
/* Convert between rtsx_dev and the corresponding Scsi_Host */
static inline struct Scsi_Host *rtsx_to_host(struct rtsx_dev *dev)
{
return container_of((void *) dev, struct Scsi_Host, hostdata);
}
static inline struct rtsx_dev *host_to_rtsx(struct Scsi_Host *host)
{
return (struct rtsx_dev *) host->hostdata;
}
static inline void get_current_time(u8 *timeval_buf, int buf_len)
{
struct timeval tv;
if (!timeval_buf || (buf_len < 8))
return;
do_gettimeofday(&tv);
timeval_buf[0] = (u8)(tv.tv_sec >> 24);
timeval_buf[1] = (u8)(tv.tv_sec >> 16);
timeval_buf[2] = (u8)(tv.tv_sec >> 8);
timeval_buf[3] = (u8)(tv.tv_sec);
timeval_buf[4] = (u8)(tv.tv_usec >> 24);
timeval_buf[5] = (u8)(tv.tv_usec >> 16);
timeval_buf[6] = (u8)(tv.tv_usec >> 8);
timeval_buf[7] = (u8)(tv.tv_usec);
}
/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
* single queue element srb for write access */
#define scsi_unlock(host) spin_unlock_irq(host->host_lock)
#define scsi_lock(host) spin_lock_irq(host->host_lock)
#define lock_state(chip) spin_lock_irq(&((chip)->rtsx->reg_lock))
#define unlock_state(chip) spin_unlock_irq(&((chip)->rtsx->reg_lock))
/* struct scsi_cmnd transfer buffer access utilities */
enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF};
int rtsx_read_pci_cfg_byte(u8 bus, u8 dev, u8 func, u8 offset, u8 *val);
#endif /* __REALTEK_RTSX_H */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,143 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_SCSI_H
#define __REALTEK_RTSX_SCSI_H
#include "rtsx.h"
#include "rtsx_chip.h"
#define MS_SP_CMND 0xFA
#define MS_FORMAT 0xA0
#define GET_MS_INFORMATION 0xB0
#define VENDOR_CMND 0xF0
#define READ_STATUS 0x09
#define READ_EEPROM 0x04
#define WRITE_EEPROM 0x05
#define READ_MEM 0x0D
#define WRITE_MEM 0x0E
#define GET_BUS_WIDTH 0x13
#define GET_SD_CSD 0x14
#define TOGGLE_GPIO 0x15
#define TRACE_MSG 0x18
#define SCSI_APP_CMD 0x10
#define PP_READ10 0x1A
#define PP_WRITE10 0x0A
#define READ_HOST_REG 0x1D
#define WRITE_HOST_REG 0x0D
#define SET_VAR 0x05
#define GET_VAR 0x15
#define DMA_READ 0x16
#define DMA_WRITE 0x06
#define GET_DEV_STATUS 0x10
#define SET_CHIP_MODE 0x27
#define SUIT_CMD 0xE0
#define WRITE_PHY 0x07
#define READ_PHY 0x17
#define WRITE_EEPROM2 0x03
#define READ_EEPROM2 0x13
#define ERASE_EEPROM2 0x23
#define WRITE_EFUSE 0x04
#define READ_EFUSE 0x14
#define WRITE_CFG 0x0E
#define READ_CFG 0x1E
#define SPI_VENDOR_COMMAND 0x1C
#define SCSI_SPI_GETSTATUS 0x00
#define SCSI_SPI_SETPARAMETER 0x01
#define SCSI_SPI_READFALSHID 0x02
#define SCSI_SPI_READFLASH 0x03
#define SCSI_SPI_WRITEFLASH 0x04
#define SCSI_SPI_WRITEFLASHSTATUS 0x05
#define SCSI_SPI_ERASEFLASH 0x06
#define INIT_BATCHCMD 0x41
#define ADD_BATCHCMD 0x42
#define SEND_BATCHCMD 0x43
#define GET_BATCHRSP 0x44
#define CHIP_NORMALMODE 0x00
#define CHIP_DEBUGMODE 0x01
/* SD Pass Through Command Extension */
#define SD_PASS_THRU_MODE 0xD0
#define SD_EXECUTE_NO_DATA 0xD1
#define SD_EXECUTE_READ 0xD2
#define SD_EXECUTE_WRITE 0xD3
#define SD_GET_RSP 0xD4
#define SD_HW_RST 0xD6
#ifdef SUPPORT_MAGIC_GATE
#define CMD_MSPRO_MG_RKEY 0xA4 /* Report Key Command */
#define CMD_MSPRO_MG_SKEY 0xA3 /* Send Key Command */
/* CBWCB field: key class */
#define KC_MG_R_PRO 0xBE /* MG-R PRO*/
/* CBWCB field: key format */
#define KF_SET_LEAF_ID 0x31 /* Set Leaf ID */
#define KF_GET_LOC_EKB 0x32 /* Get Local EKB */
#define KF_CHG_HOST 0x33 /* Challenge (host) */
#define KF_RSP_CHG 0x34 /* Response and Challenge (device) */
#define KF_RSP_HOST 0x35 /* Response (host) */
#define KF_GET_ICV 0x36 /* Get ICV */
#define KF_SET_ICV 0x37 /* SSet ICV */
#endif
/* Sense type */
#define SENSE_TYPE_NO_SENSE 0
#define SENSE_TYPE_MEDIA_CHANGE 1
#define SENSE_TYPE_MEDIA_NOT_PRESENT 2
#define SENSE_TYPE_MEDIA_LBA_OVER_RANGE 3
#define SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT 4
#define SENSE_TYPE_MEDIA_WRITE_PROTECT 5
#define SENSE_TYPE_MEDIA_INVALID_CMD_FIELD 6
#define SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR 7
#define SENSE_TYPE_MEDIA_WRITE_ERR 8
#define SENSE_TYPE_FORMAT_IN_PROGRESS 9
#define SENSE_TYPE_FORMAT_CMD_FAILED 10
#ifdef SUPPORT_MAGIC_GATE
#define SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB 0x0b
#define SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN 0x0c
#define SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM 0x0d
#define SENSE_TYPE_MG_WRITE_ERR 0x0e
#endif
#ifdef SUPPORT_SD_LOCK
/* FOR Locked SD card*/
#define SENSE_TYPE_MEDIA_READ_FORBIDDEN 0x10
#endif
void scsi_show_command(struct scsi_cmnd *srb);
void set_sense_type(struct rtsx_chip *chip, unsigned int lun, int sense_type);
void set_sense_data(struct rtsx_chip *chip, unsigned int lun, u8 err_code,
u8 sense_key, u32 info, u8 asc, u8 ascq,
u8 sns_key_info0, u16 sns_key_info1);
int rtsx_scsi_handler(struct scsi_cmnd *srb, struct rtsx_chip *chip);
#endif /* __REALTEK_RTSX_SCSI_H */

Просмотреть файл

@ -0,0 +1,50 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __RTSX_SYS_H
#define __RTSX_SYS_H
#include "rtsx.h"
#include "rtsx_chip.h"
#include "rtsx_card.h"
typedef dma_addr_t ULONG_PTR;
static inline void rtsx_exclusive_enter_ss(struct rtsx_chip *chip)
{
struct rtsx_dev *dev = chip->rtsx;
spin_lock(&(dev->reg_lock));
rtsx_enter_ss(chip);
spin_unlock(&(dev->reg_lock));
}
static inline void rtsx_reset_detected_cards(struct rtsx_chip *chip, int flag)
{
rtsx_reset_cards(chip);
}
#define RTSX_MSG_IN_INT(x)
#endif /* __RTSX_SYS_H */

Просмотреть файл

@ -0,0 +1,769 @@
/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include "rtsx.h"
#include "rtsx_scsi.h"
#include "rtsx_transport.h"
#include "rtsx_chip.h"
#include "rtsx_card.h"
#include "debug.h"
/***********************************************************************
* Scatter-gather transfer buffer access routines
***********************************************************************/
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
* (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
* points to a list of s-g entries and we ignore srb->request_bufflen.
* For non-scatter-gather transfers, srb->request_buffer points to the
* transfer buffer itself and srb->request_bufflen is the buffer's length.)
* Update the *index and *offset variables so that the next copy will
* pick up from where this one left off. */
unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
unsigned int *offset, enum xfer_buf_dir dir)
{
unsigned int cnt;
/* If not using scatter-gather, just transfer the data directly.
* Make certain it will fit in the available buffer space. */
if (scsi_sg_count(srb) == 0) {
if (*offset >= scsi_bufflen(srb))
return 0;
cnt = min(buflen, scsi_bufflen(srb) - *offset);
if (dir == TO_XFER_BUF)
memcpy((unsigned char *) scsi_sglist(srb) + *offset,
buffer, cnt);
else
memcpy(buffer, (unsigned char *) scsi_sglist(srb) +
*offset, cnt);
*offset += cnt;
/* Using scatter-gather. We have to go through the list one entry
* at a time. Each s-g entry contains some number of pages, and
* each page has to be kmap()'ed separately. If the page is already
* in kernel-addressable memory then kmap() will return its address.
* If the page is not directly accessible -- such as a user buffer
* located in high memory -- then kmap() will map it to a temporary
* position in the kernel's virtual address space. */
} else {
struct scatterlist *sg =
(struct scatterlist *) scsi_sglist(srb)
+ *index;
/* This loop handles a single s-g list entry, which may
* include multiple pages. Find the initial page structure
* and the starting offset within the page, and update
* the *offset and *index values for the next loop. */
cnt = 0;
while (cnt < buflen && *index < scsi_sg_count(srb)) {
struct page *page = sg_page(sg) +
((sg->offset + *offset) >> PAGE_SHIFT);
unsigned int poff =
(sg->offset + *offset) & (PAGE_SIZE-1);
unsigned int sglen = sg->length - *offset;
if (sglen > buflen - cnt) {
/* Transfer ends within this s-g entry */
sglen = buflen - cnt;
*offset += sglen;
} else {
/* Transfer continues to next s-g entry */
*offset = 0;
++*index;
++sg;
}
/* Transfer the data for all the pages in this
* s-g entry. For each page: call kmap(), do the
* transfer, and call kunmap() immediately after. */
while (sglen > 0) {
unsigned int plen = min(sglen, (unsigned int)
PAGE_SIZE - poff);
unsigned char *ptr = kmap(page);
if (dir == TO_XFER_BUF)
memcpy(ptr + poff, buffer + cnt, plen);
else
memcpy(buffer + cnt, ptr + poff, plen);
kunmap(page);
/* Start at the beginning of the next page */
poff = 0;
++page;
cnt += plen;
sglen -= plen;
}
}
}
/* Return the amount actually transferred */
return cnt;
}
/* Store the contents of buffer into srb's transfer buffer and set the
* SCSI residue. */
void rtsx_stor_set_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int index = 0, offset = 0;
rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
TO_XFER_BUF);
if (buflen < scsi_bufflen(srb))
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
void rtsx_stor_get_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int index = 0, offset = 0;
rtsx_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
FROM_XFER_BUF);
if (buflen < scsi_bufflen(srb))
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
/***********************************************************************
* Transport routines
***********************************************************************/
/* Invoke the transport and basic error-handling/recovery methods
*
* This is used to send the message to the device and receive the response.
*/
void rtsx_invoke_transport(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
int result;
result = rtsx_scsi_handler(srb, chip);
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
*/
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) {
RTSX_DEBUGP("-- command was aborted\n");
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
/* if there is a transport error, reset and don't auto-sense */
if (result == TRANSPORT_ERROR) {
RTSX_DEBUGP("-- transport indicates error, resetting\n");
srb->result = DID_ERROR << 16;
goto Handle_Errors;
}
srb->result = SAM_STAT_GOOD;
/*
* If we have a failure, we're going to do a REQUEST_SENSE
* automatically. Note that we differentiate between a command
* "failure" and an "error" in the transport mechanism.
*/
if (result == TRANSPORT_FAILED) {
/* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION;
memcpy(srb->sense_buffer,
(unsigned char *)&(chip->sense_buffer[SCSI_LUN(srb)]),
sizeof(struct sense_data_t));
}
return;
/* Error and abort processing: try to resynchronize with the device
* by issuing a port reset. If that fails, try a class-specific
* device reset. */
Handle_Errors:
return;
}
void rtsx_add_cmd(struct rtsx_chip *chip,
u8 cmd_type, u16 reg_addr, u8 mask, u8 data)
{
u32 *cb = (u32 *)(chip->host_cmds_ptr);
u32 val = 0;
val |= (u32)(cmd_type & 0x03) << 30;
val |= (u32)(reg_addr & 0x3FFF) << 16;
val |= (u32)mask << 8;
val |= (u32)data;
spin_lock_irq(&chip->rtsx->reg_lock);
if (chip->ci < (HOST_CMDS_BUF_LEN / 4))
cb[(chip->ci)++] = cpu_to_le32(val);
spin_unlock_irq(&chip->rtsx->reg_lock);
}
void rtsx_send_cmd_no_wait(struct rtsx_chip *chip)
{
u32 val = 1 << 31;
rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);
val |= (u32)(chip->ci * 4) & 0x00FFFFFF;
/* Hardware Auto Response */
val |= 0x40000000;
rtsx_writel(chip, RTSX_HCBCTLR, val);
}
int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout)
{
struct rtsx_dev *rtsx = chip->rtsx;
struct completion trans_done;
u32 val = 1 << 31;
long timeleft;
int err = 0;
if (card == SD_CARD)
rtsx->check_card_cd = SD_EXIST;
else if (card == MS_CARD)
rtsx->check_card_cd = MS_EXIST;
else if (card == XD_CARD)
rtsx->check_card_cd = XD_EXIST;
else
rtsx->check_card_cd = 0;
spin_lock_irq(&rtsx->reg_lock);
/* set up data structures for the wakeup system */
rtsx->done = &trans_done;
rtsx->trans_result = TRANS_NOT_READY;
init_completion(&trans_done);
rtsx->trans_state = STATE_TRANS_CMD;
rtsx_writel(chip, RTSX_HCBAR, chip->host_cmds_addr);
val |= (u32)(chip->ci * 4) & 0x00FFFFFF;
/* Hardware Auto Response */
val |= 0x40000000;
rtsx_writel(chip, RTSX_HCBCTLR, val);
spin_unlock_irq(&rtsx->reg_lock);
/* Wait for TRANS_OK_INT */
timeleft = wait_for_completion_interruptible_timeout(
&trans_done, timeout * HZ / 1000);
if (timeleft <= 0) {
RTSX_DEBUGP("chip->int_reg = 0x%x\n", chip->int_reg);
err = -ETIMEDOUT;
TRACE_GOTO(chip, finish_send_cmd);
}
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_RESULT_FAIL)
err = -EIO;
else if (rtsx->trans_result == TRANS_RESULT_OK)
err = 0;
spin_unlock_irq(&rtsx->reg_lock);
finish_send_cmd:
rtsx->done = NULL;
rtsx->trans_state = STATE_TRANS_NONE;
if (err < 0)
rtsx_stop_cmd(chip, card);
return err;
}
static inline void rtsx_add_sg_tbl(
struct rtsx_chip *chip, u32 addr, u32 len, u8 option)
{
u64 *sgb = (u64 *)(chip->host_sg_tbl_ptr);
u64 val = 0;
u32 temp_len = 0;
u8 temp_opt = 0;
do {
if (len > 0x80000) {
temp_len = 0x80000;
temp_opt = option & (~SG_END);
} else {
temp_len = len;
temp_opt = option;
}
val = ((u64)addr << 32) | ((u64)temp_len << 12) | temp_opt;
if (chip->sgi < (HOST_SG_TBL_BUF_LEN / 8))
sgb[(chip->sgi)++] = cpu_to_le64(val);
len -= temp_len;
addr += temp_len;
} while (len);
}
static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card,
struct scatterlist *sg, int num_sg, unsigned int *index,
unsigned int *offset, int size,
enum dma_data_direction dma_dir, int timeout)
{
struct rtsx_dev *rtsx = chip->rtsx;
struct completion trans_done;
u8 dir;
int sg_cnt, i, resid;
int err = 0;
long timeleft;
struct scatterlist *sg_ptr;
u32 val = TRIG_DMA;
if ((sg == NULL) || (num_sg <= 0) || !offset || !index)
return -EIO;
if (dma_dir == DMA_TO_DEVICE)
dir = HOST_TO_DEVICE;
else if (dma_dir == DMA_FROM_DEVICE)
dir = DEVICE_TO_HOST;
else
return -ENXIO;
if (card == SD_CARD)
rtsx->check_card_cd = SD_EXIST;
else if (card == MS_CARD)
rtsx->check_card_cd = MS_EXIST;
else if (card == XD_CARD)
rtsx->check_card_cd = XD_EXIST;
else
rtsx->check_card_cd = 0;
spin_lock_irq(&rtsx->reg_lock);
/* set up data structures for the wakeup system */
rtsx->done = &trans_done;
rtsx->trans_state = STATE_TRANS_SG;
rtsx->trans_result = TRANS_NOT_READY;
spin_unlock_irq(&rtsx->reg_lock);
sg_cnt = dma_map_sg(&(rtsx->pci->dev), sg, num_sg, dma_dir);
resid = size;
sg_ptr = sg;
chip->sgi = 0;
/* Usually the next entry will be @sg@ + 1, but if this sg element
* is part of a chained scatterlist, it could jump to the start of
* a new scatterlist array. So here we use sg_next to move to
* the proper sg
*/
for (i = 0; i < *index; i++)
sg_ptr = sg_next(sg_ptr);
for (i = *index; i < sg_cnt; i++) {
dma_addr_t addr;
unsigned int len;
u8 option;
addr = sg_dma_address(sg_ptr);
len = sg_dma_len(sg_ptr);
RTSX_DEBUGP("DMA addr: 0x%x, Len: 0x%x\n",
(unsigned int)addr, len);
RTSX_DEBUGP("*index = %d, *offset = %d\n", *index, *offset);
addr += *offset;
if ((len - *offset) > resid) {
*offset += resid;
len = resid;
resid = 0;
} else {
resid -= (len - *offset);
len -= *offset;
*offset = 0;
*index = *index + 1;
}
if ((i == (sg_cnt - 1)) || !resid)
option = SG_VALID | SG_END | SG_TRANS_DATA;
else
option = SG_VALID | SG_TRANS_DATA;
rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
if (!resid)
break;
sg_ptr = sg_next(sg_ptr);
}
RTSX_DEBUGP("SG table count = %d\n", chip->sgi);
val |= (u32)(dir & 0x01) << 29;
val |= ADMA_MODE;
spin_lock_irq(&rtsx->reg_lock);
init_completion(&trans_done);
rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr);
rtsx_writel(chip, RTSX_HDBCTLR, val);
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
&trans_done, timeout * HZ / 1000);
if (timeleft <= 0) {
RTSX_DEBUGP("Timeout (%s %d)\n", __func__, __LINE__);
RTSX_DEBUGP("chip->int_reg = 0x%x\n", chip->int_reg);
err = -ETIMEDOUT;
goto out;
}
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_RESULT_FAIL) {
err = -EIO;
spin_unlock_irq(&rtsx->reg_lock);
goto out;
}
spin_unlock_irq(&rtsx->reg_lock);
/* Wait for TRANS_OK_INT */
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_NOT_READY) {
init_completion(&trans_done);
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
&trans_done, timeout * HZ / 1000);
if (timeleft <= 0) {
RTSX_DEBUGP("Timeout (%s %d)\n", __func__, __LINE__);
RTSX_DEBUGP("chip->int_reg = 0x%x\n", chip->int_reg);
err = -ETIMEDOUT;
goto out;
}
} else {
spin_unlock_irq(&rtsx->reg_lock);
}
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_RESULT_FAIL)
err = -EIO;
else if (rtsx->trans_result == TRANS_RESULT_OK)
err = 0;
spin_unlock_irq(&rtsx->reg_lock);
out:
rtsx->done = NULL;
rtsx->trans_state = STATE_TRANS_NONE;
dma_unmap_sg(&(rtsx->pci->dev), sg, num_sg, dma_dir);
if (err < 0)
rtsx_stop_cmd(chip, card);
return err;
}
static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card,
struct scatterlist *sg, int num_sg,
enum dma_data_direction dma_dir, int timeout)
{
struct rtsx_dev *rtsx = chip->rtsx;
struct completion trans_done;
u8 dir;
int buf_cnt, i;
int err = 0;
long timeleft;
struct scatterlist *sg_ptr;
if ((sg == NULL) || (num_sg <= 0))
return -EIO;
if (dma_dir == DMA_TO_DEVICE)
dir = HOST_TO_DEVICE;
else if (dma_dir == DMA_FROM_DEVICE)
dir = DEVICE_TO_HOST;
else
return -ENXIO;
if (card == SD_CARD)
rtsx->check_card_cd = SD_EXIST;
else if (card == MS_CARD)
rtsx->check_card_cd = MS_EXIST;
else if (card == XD_CARD)
rtsx->check_card_cd = XD_EXIST;
else
rtsx->check_card_cd = 0;
spin_lock_irq(&rtsx->reg_lock);
/* set up data structures for the wakeup system */
rtsx->done = &trans_done;
rtsx->trans_state = STATE_TRANS_SG;
rtsx->trans_result = TRANS_NOT_READY;
spin_unlock_irq(&rtsx->reg_lock);
buf_cnt = dma_map_sg(&(rtsx->pci->dev), sg, num_sg, dma_dir);
sg_ptr = sg;
for (i = 0; i <= buf_cnt / (HOST_SG_TBL_BUF_LEN / 8); i++) {
u32 val = TRIG_DMA;
int sg_cnt, j;
if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8))
sg_cnt = buf_cnt % (HOST_SG_TBL_BUF_LEN / 8);
else
sg_cnt = (HOST_SG_TBL_BUF_LEN / 8);
chip->sgi = 0;
for (j = 0; j < sg_cnt; j++) {
dma_addr_t addr = sg_dma_address(sg_ptr);
unsigned int len = sg_dma_len(sg_ptr);
u8 option;
RTSX_DEBUGP("DMA addr: 0x%x, Len: 0x%x\n",
(unsigned int)addr, len);
if (j == (sg_cnt - 1))
option = SG_VALID | SG_END | SG_TRANS_DATA;
else
option = SG_VALID | SG_TRANS_DATA;
rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option);
sg_ptr = sg_next(sg_ptr);
}
RTSX_DEBUGP("SG table count = %d\n", chip->sgi);
val |= (u32)(dir & 0x01) << 29;
val |= ADMA_MODE;
spin_lock_irq(&rtsx->reg_lock);
init_completion(&trans_done);
rtsx_writel(chip, RTSX_HDBAR, chip->host_sg_tbl_addr);
rtsx_writel(chip, RTSX_HDBCTLR, val);
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
&trans_done, timeout * HZ / 1000);
if (timeleft <= 0) {
RTSX_DEBUGP("Timeout (%s %d)\n", __func__, __LINE__);
RTSX_DEBUGP("chip->int_reg = 0x%x\n", chip->int_reg);
err = -ETIMEDOUT;
goto out;
}
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_RESULT_FAIL) {
err = -EIO;
spin_unlock_irq(&rtsx->reg_lock);
goto out;
}
spin_unlock_irq(&rtsx->reg_lock);
sg_ptr += sg_cnt;
}
/* Wait for TRANS_OK_INT */
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_NOT_READY) {
init_completion(&trans_done);
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
&trans_done, timeout * HZ / 1000);
if (timeleft <= 0) {
RTSX_DEBUGP("Timeout (%s %d)\n", __func__, __LINE__);
RTSX_DEBUGP("chip->int_reg = 0x%x\n", chip->int_reg);
err = -ETIMEDOUT;
goto out;
}
} else {
spin_unlock_irq(&rtsx->reg_lock);
}
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_RESULT_FAIL)
err = -EIO;
else if (rtsx->trans_result == TRANS_RESULT_OK)
err = 0;
spin_unlock_irq(&rtsx->reg_lock);
out:
rtsx->done = NULL;
rtsx->trans_state = STATE_TRANS_NONE;
dma_unmap_sg(&(rtsx->pci->dev), sg, num_sg, dma_dir);
if (err < 0)
rtsx_stop_cmd(chip, card);
return err;
}
static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf, size_t len,
enum dma_data_direction dma_dir, int timeout)
{
struct rtsx_dev *rtsx = chip->rtsx;
struct completion trans_done;
dma_addr_t addr;
u8 dir;
int err = 0;
u32 val = (1 << 31);
long timeleft;
if ((buf == NULL) || (len <= 0))
return -EIO;
if (dma_dir == DMA_TO_DEVICE)
dir = HOST_TO_DEVICE;
else if (dma_dir == DMA_FROM_DEVICE)
dir = DEVICE_TO_HOST;
else
return -ENXIO;
addr = dma_map_single(&(rtsx->pci->dev), buf, len, dma_dir);
if (!addr)
return -ENOMEM;
if (card == SD_CARD)
rtsx->check_card_cd = SD_EXIST;
else if (card == MS_CARD)
rtsx->check_card_cd = MS_EXIST;
else if (card == XD_CARD)
rtsx->check_card_cd = XD_EXIST;
else
rtsx->check_card_cd = 0;
val |= (u32)(dir & 0x01) << 29;
val |= (u32)(len & 0x00FFFFFF);
spin_lock_irq(&rtsx->reg_lock);
/* set up data structures for the wakeup system */
rtsx->done = &trans_done;
init_completion(&trans_done);
rtsx->trans_state = STATE_TRANS_BUF;
rtsx->trans_result = TRANS_NOT_READY;
rtsx_writel(chip, RTSX_HDBAR, addr);
rtsx_writel(chip, RTSX_HDBCTLR, val);
spin_unlock_irq(&rtsx->reg_lock);
/* Wait for TRANS_OK_INT */
timeleft = wait_for_completion_interruptible_timeout(
&trans_done, timeout * HZ / 1000);
if (timeleft <= 0) {
RTSX_DEBUGP("Timeout (%s %d)\n", __func__, __LINE__);
RTSX_DEBUGP("chip->int_reg = 0x%x\n", chip->int_reg);
err = -ETIMEDOUT;
goto out;
}
spin_lock_irq(&rtsx->reg_lock);
if (rtsx->trans_result == TRANS_RESULT_FAIL)
err = -EIO;
else if (rtsx->trans_result == TRANS_RESULT_OK)
err = 0;
spin_unlock_irq(&rtsx->reg_lock);
out:
rtsx->done = NULL;
rtsx->trans_state = STATE_TRANS_NONE;
dma_unmap_single(&(rtsx->pci->dev), addr, len, dma_dir);
if (err < 0)
rtsx_stop_cmd(chip, card);
return err;
}
int rtsx_transfer_data_partial(struct rtsx_chip *chip, u8 card,
void *buf, size_t len, int use_sg, unsigned int *index,
unsigned int *offset, enum dma_data_direction dma_dir,
int timeout)
{
int err = 0;
/* don't transfer data during abort processing */
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT))
return -EIO;
if (use_sg) {
err = rtsx_transfer_sglist_adma_partial(chip, card,
(struct scatterlist *)buf, use_sg,
index, offset, (int)len, dma_dir, timeout);
} else {
err = rtsx_transfer_buf(chip, card,
buf, len, dma_dir, timeout);
}
if (err < 0) {
if (RTSX_TST_DELINK(chip)) {
RTSX_CLR_DELINK(chip);
chip->need_reinit = SD_CARD | MS_CARD | XD_CARD;
rtsx_reinit_cards(chip, 1);
}
}
return err;
}
int rtsx_transfer_data(struct rtsx_chip *chip, u8 card, void *buf, size_t len,
int use_sg, enum dma_data_direction dma_dir, int timeout)
{
int err = 0;
RTSX_DEBUGP("use_sg = %d\n", use_sg);
/* don't transfer data during abort processing */
if (rtsx_chk_stat(chip, RTSX_STAT_ABORT))
return -EIO;
if (use_sg) {
err = rtsx_transfer_sglist_adma(chip, card,
(struct scatterlist *)buf,
use_sg, dma_dir, timeout);
} else {
err = rtsx_transfer_buf(chip, card, buf, len, dma_dir, timeout);
}
if (err < 0) {
if (RTSX_TST_DELINK(chip)) {
RTSX_CLR_DELINK(chip);
chip->need_reinit = SD_CARD | MS_CARD | XD_CARD;
rtsx_reinit_cards(chip, 1);
}
}
return err;
}

Просмотреть файл

@ -0,0 +1,66 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_TRANSPORT_H
#define __REALTEK_RTSX_TRANSPORT_H
#include "rtsx.h"
#include "rtsx_chip.h"
#define WAIT_TIME 2000
unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
unsigned int *offset, enum xfer_buf_dir dir);
void rtsx_stor_set_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb);
void rtsx_stor_get_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb);
void rtsx_invoke_transport(struct scsi_cmnd *srb, struct rtsx_chip *chip);
#define rtsx_init_cmd(chip) ((chip)->ci = 0)
void rtsx_add_cmd(struct rtsx_chip *chip,
u8 cmd_type, u16 reg_addr, u8 mask, u8 data);
void rtsx_send_cmd_no_wait(struct rtsx_chip *chip);
int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout);
extern inline u8 *rtsx_get_cmd_data(struct rtsx_chip *chip)
{
#ifdef CMD_USING_SG
return (u8 *)(chip->host_sg_tbl_ptr);
#else
return (u8 *)(chip->host_cmds_ptr);
#endif
}
int rtsx_transfer_data(struct rtsx_chip *chip, u8 card, void *buf, size_t len,
int use_sg, enum dma_data_direction dma_dir, int timeout);
int rtsx_transfer_data_partial(struct rtsx_chip *chip, u8 card,
void *buf, size_t len,
int use_sg, unsigned int *index, unsigned int *offset,
enum dma_data_direction dma_dir, int timeout);
#endif /* __REALTEK_RTSX_TRANSPORT_H */

4525
drivers/staging/rts5208/sd.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,301 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_SD_H
#define __REALTEK_RTSX_SD_H
#include "rtsx_chip.h"
#define SUPPORT_VOLTAGE 0x003C0000
/* Error Code */
#define SD_NO_ERROR 0x0
#define SD_CRC_ERR 0x80
#define SD_TO_ERR 0x40
#define SD_NO_CARD 0x20
#define SD_BUSY 0x10
#define SD_STS_ERR 0x08
#define SD_RSP_TIMEOUT 0x04
#define SD_IO_ERR 0x02
/* Return code for MMC switch bus */
#define SWITCH_SUCCESS 0
#define SWITCH_ERR 1
#define SWITCH_FAIL 2
/* MMC/SD Command Index */
/* Basic command (class 0) */
#define GO_IDLE_STATE 0
#define SEND_OP_COND 1
#define ALL_SEND_CID 2
#define SET_RELATIVE_ADDR 3
#define SEND_RELATIVE_ADDR 3
#define SET_DSR 4
#define IO_SEND_OP_COND 5
#define SWITCH 6
#define SELECT_CARD 7
#define DESELECT_CARD 7
/* CMD8 is "SEND_EXT_CSD" for MMC4.x Spec
* while is "SEND_IF_COND" for SD 2.0
*/
#define SEND_EXT_CSD 8
#define SEND_IF_COND 8
#define SEND_CSD 9
#define SEND_CID 10
#define VOLTAGE_SWITCH 11
#define READ_DAT_UTIL_STOP 11
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define GO_INACTIVE_STATE 15
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCK 18
#define SEND_TUNING_PATTERN 19
#define BUSTEST_R 14
#define BUSTEST_W 19
#define WRITE_BLOCK 24
#define WRITE_MULTIPLE_BLOCK 25
#define PROGRAM_CSD 27
#define ERASE_WR_BLK_START 32
#define ERASE_WR_BLK_END 33
#define ERASE_CMD 38
#define LOCK_UNLOCK 42
#define IO_RW_DIRECT 52
#define APP_CMD 55
#define GEN_CMD 56
#define SET_BUS_WIDTH 6
#define SD_STATUS 13
#define SEND_NUM_WR_BLOCKS 22
#define SET_WR_BLK_ERASE_COUNT 23
#define SD_APP_OP_COND 41
#define SET_CLR_CARD_DETECT 42
#define SEND_SCR 51
#define SD_READ_COMPLETE 0x00
#define SD_READ_TO 0x01
#define SD_READ_ADVENCE 0x02
#define SD_CHECK_MODE 0x00
#define SD_SWITCH_MODE 0x80
#define SD_FUNC_GROUP_1 0x01
#define SD_FUNC_GROUP_2 0x02
#define SD_FUNC_GROUP_3 0x03
#define SD_FUNC_GROUP_4 0x04
#define SD_CHECK_SPEC_V1_1 0xFF
#define NO_ARGUMENT 0x00
#define CHECK_PATTERN 0x000000AA
#define VOLTAGE_SUPPLY_RANGE 0x00000100
#define SUPPORT_HIGH_AND_EXTENDED_CAPACITY 0x40000000
#define SUPPORT_MAX_POWER_PERMANCE 0x10000000
#define SUPPORT_1V8 0x01000000
#define SWTICH_NO_ERR 0x00
#define CARD_NOT_EXIST 0x01
#define SPEC_NOT_SUPPORT 0x02
#define CHECK_MODE_ERR 0x03
#define CHECK_NOT_READY 0x04
#define SWITCH_CRC_ERR 0x05
#define SWITCH_MODE_ERR 0x06
#define SWITCH_PASS 0x07
#ifdef SUPPORT_SD_LOCK
#define SD_ERASE 0x08
#define SD_LOCK 0x04
#define SD_UNLOCK 0x00
#define SD_CLR_PWD 0x02
#define SD_SET_PWD 0x01
#define SD_PWD_LEN 0x10
#define SD_LOCKED 0x80
#define SD_LOCK_1BIT_MODE 0x40
#define SD_PWD_EXIST 0x20
#define SD_UNLOCK_POW_ON 0x01
#define SD_SDR_RST 0x02
#define SD_NOT_ERASE 0x00
#define SD_UNDER_ERASING 0x01
#define SD_COMPLETE_ERASE 0x02
#define SD_RW_FORBIDDEN 0x0F
#endif
#define HS_SUPPORT 0x01
#define SDR50_SUPPORT 0x02
#define SDR104_SUPPORT 0x03
#define DDR50_SUPPORT 0x04
#define HS_SUPPORT_MASK 0x02
#define SDR50_SUPPORT_MASK 0x04
#define SDR104_SUPPORT_MASK 0x08
#define DDR50_SUPPORT_MASK 0x10
#define HS_QUERY_SWITCH_OK 0x01
#define SDR50_QUERY_SWITCH_OK 0x02
#define SDR104_QUERY_SWITCH_OK 0x03
#define DDR50_QUERY_SWITCH_OK 0x04
#define HS_SWITCH_BUSY 0x02
#define SDR50_SWITCH_BUSY 0x04
#define SDR104_SWITCH_BUSY 0x08
#define DDR50_SWITCH_BUSY 0x10
#define FUNCTION_GROUP1_SUPPORT_OFFSET 0x0D
#define FUNCTION_GROUP1_QUERY_SWITCH_OFFSET 0x10
#define FUNCTION_GROUP1_CHECK_BUSY_OFFSET 0x1D
#define DRIVING_TYPE_A 0x01
#define DRIVING_TYPE_B 0x00
#define DRIVING_TYPE_C 0x02
#define DRIVING_TYPE_D 0x03
#define DRIVING_TYPE_A_MASK 0x02
#define DRIVING_TYPE_B_MASK 0x01
#define DRIVING_TYPE_C_MASK 0x04
#define DRIVING_TYPE_D_MASK 0x08
#define TYPE_A_QUERY_SWITCH_OK 0x01
#define TYPE_B_QUERY_SWITCH_OK 0x00
#define TYPE_C_QUERY_SWITCH_OK 0x02
#define TYPE_D_QUERY_SWITCH_OK 0x03
#define TYPE_A_SWITCH_BUSY 0x02
#define TYPE_B_SWITCH_BUSY 0x01
#define TYPE_C_SWITCH_BUSY 0x04
#define TYPE_D_SWITCH_BUSY 0x08
#define FUNCTION_GROUP3_SUPPORT_OFFSET 0x09
#define FUNCTION_GROUP3_QUERY_SWITCH_OFFSET 0x0F
#define FUNCTION_GROUP3_CHECK_BUSY_OFFSET 0x19
#define CURRENT_LIMIT_200 0x00
#define CURRENT_LIMIT_400 0x01
#define CURRENT_LIMIT_600 0x02
#define CURRENT_LIMIT_800 0x03
#define CURRENT_LIMIT_200_MASK 0x01
#define CURRENT_LIMIT_400_MASK 0x02
#define CURRENT_LIMIT_600_MASK 0x04
#define CURRENT_LIMIT_800_MASK 0x08
#define CURRENT_LIMIT_200_QUERY_SWITCH_OK 0x00
#define CURRENT_LIMIT_400_QUERY_SWITCH_OK 0x01
#define CURRENT_LIMIT_600_QUERY_SWITCH_OK 0x02
#define CURRENT_LIMIT_800_QUERY_SWITCH_OK 0x03
#define CURRENT_LIMIT_200_SWITCH_BUSY 0x01
#define CURRENT_LIMIT_400_SWITCH_BUSY 0x02
#define CURRENT_LIMIT_600_SWITCH_BUSY 0x04
#define CURRENT_LIMIT_800_SWITCH_BUSY 0x08
#define FUNCTION_GROUP4_SUPPORT_OFFSET 0x07
#define FUNCTION_GROUP4_QUERY_SWITCH_OFFSET 0x0F
#define FUNCTION_GROUP4_CHECK_BUSY_OFFSET 0x17
#define DATA_STRUCTURE_VER_OFFSET 0x11
#define MAX_PHASE 31
#define MMC_8BIT_BUS 0x0010
#define MMC_4BIT_BUS 0x0020
#define MMC_SWITCH_ERR 0x80
#define SD_IO_3V3 0
#define SD_IO_1V8 1
#define TUNE_TX 0x00
#define TUNE_RX 0x01
#define CHANGE_TX 0x00
#define CHANGE_RX 0x01
#define DCM_HIGH_FREQUENCY_MODE 0x00
#define DCM_LOW_FREQUENCY_MODE 0x01
#define DCM_HIGH_FREQUENCY_MODE_SET 0x0C
#define DCM_Low_FREQUENCY_MODE_SET 0x00
#define MULTIPLY_BY_1 0x00
#define MULTIPLY_BY_2 0x01
#define MULTIPLY_BY_3 0x02
#define MULTIPLY_BY_4 0x03
#define MULTIPLY_BY_5 0x04
#define MULTIPLY_BY_6 0x05
#define MULTIPLY_BY_7 0x06
#define MULTIPLY_BY_8 0x07
#define MULTIPLY_BY_9 0x08
#define MULTIPLY_BY_10 0x09
#define DIVIDE_BY_2 0x01
#define DIVIDE_BY_3 0x02
#define DIVIDE_BY_4 0x03
#define DIVIDE_BY_5 0x04
#define DIVIDE_BY_6 0x05
#define DIVIDE_BY_7 0x06
#define DIVIDE_BY_8 0x07
#define DIVIDE_BY_9 0x08
#define DIVIDE_BY_10 0x09
struct timing_phase_path {
int start;
int end;
int mid;
int len;
};
int sd_select_card(struct rtsx_chip *chip, int select);
int sd_pull_ctl_enable(struct rtsx_chip *chip);
int reset_sd_card(struct rtsx_chip *chip);
int sd_switch_clock(struct rtsx_chip *chip);
void sd_stop_seq_mode(struct rtsx_chip *chip);
int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
u32 start_sector, u16 sector_cnt);
void sd_cleanup_work(struct rtsx_chip *chip);
int sd_power_off_card3v3(struct rtsx_chip *chip);
int release_sd_card(struct rtsx_chip *chip);
#ifdef SUPPORT_CPRM
int soft_reset_sd_card(struct rtsx_chip *chip);
int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx,
u32 arg, u8 rsp_type, u8 *rsp, int rsp_len, int special_check);
int ext_sd_get_rsp(struct rtsx_chip *chip, int len, u8 *rsp, u8 rsp_type);
int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int sd_get_cmd_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int sd_hw_rst(struct scsi_cmnd *srb, struct rtsx_chip *chip);
#endif
#endif /* __REALTEK_RTSX_SD_H */

Просмотреть файл

@ -0,0 +1,877 @@
/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include "rtsx.h"
#include "rtsx_transport.h"
#include "rtsx_scsi.h"
#include "rtsx_card.h"
#include "spi.h"
static inline void spi_set_err_code(struct rtsx_chip *chip, u8 err_code)
{
struct spi_info *spi = &(chip->spi);
spi->err_code = err_code;
}
static int spi_init(struct rtsx_chip *chip)
{
RTSX_WRITE_REG(chip, SPI_CONTROL, 0xFF,
CS_POLARITY_LOW | DTO_MSB_FIRST | SPI_MASTER | SPI_MODE0 |
SPI_AUTO);
RTSX_WRITE_REG(chip, SPI_TCTL, EDO_TIMING_MASK, SAMPLE_DELAY_HALF);
return STATUS_SUCCESS;
}
static int spi_set_init_para(struct rtsx_chip *chip)
{
struct spi_info *spi = &(chip->spi);
int retval;
RTSX_WRITE_REG(chip, SPI_CLK_DIVIDER1, 0xFF, (u8)(spi->clk_div >> 8));
RTSX_WRITE_REG(chip, SPI_CLK_DIVIDER0, 0xFF, (u8)(spi->clk_div));
retval = switch_clock(chip, spi->spi_clock);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = select_card(chip, SPI_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
RTSX_WRITE_REG(chip, CARD_CLK_EN, SPI_CLK_EN, SPI_CLK_EN);
RTSX_WRITE_REG(chip, CARD_OE, SPI_OUTPUT_EN, SPI_OUTPUT_EN);
wait_timeout(10);
retval = spi_init(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
static int sf_polling_status(struct rtsx_chip *chip, int msec)
{
int retval;
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, SPI_RDSR);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_POLLING_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, msec);
if (retval < 0) {
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_BUSY_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int sf_enable_write(struct rtsx_chip *chip, u8 ins)
{
struct spi_info *spi = &(chip->spi);
int retval;
if (!spi->write_en)
return STATUS_SUCCESS;
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_C_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0) {
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int sf_disable_write(struct rtsx_chip *chip, u8 ins)
{
struct spi_info *spi = &(chip->spi);
int retval;
if (!spi->write_en)
return STATUS_SUCCESS;
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_C_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0) {
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static void sf_program(struct rtsx_chip *chip, u8 ins, u8 addr_mode, u32 addr,
u16 len)
{
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, (u8)len);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, (u8)(len >> 8));
if (addr_mode) {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
(u8)(addr >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
(u8)(addr >> 16));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CADO_MODE0);
} else {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CDO_MODE0);
}
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
}
static int sf_erase(struct rtsx_chip *chip, u8 ins, u8 addr_mode, u32 addr)
{
int retval;
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
if (addr_mode) {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
(u8)(addr >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
(u8)(addr >> 16));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CA_MODE0);
} else {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_C_MODE0);
}
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0) {
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int spi_init_eeprom(struct rtsx_chip *chip)
{
int retval;
int clk;
if (chip->asic_code)
clk = 30;
else
clk = CLK_30;
RTSX_WRITE_REG(chip, SPI_CLK_DIVIDER1, 0xFF, 0x00);
RTSX_WRITE_REG(chip, SPI_CLK_DIVIDER0, 0xFF, 0x27);
retval = switch_clock(chip, clk);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = select_card(chip, SPI_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
RTSX_WRITE_REG(chip, CARD_CLK_EN, SPI_CLK_EN, SPI_CLK_EN);
RTSX_WRITE_REG(chip, CARD_OE, SPI_OUTPUT_EN, SPI_OUTPUT_EN);
wait_timeout(10);
RTSX_WRITE_REG(chip, SPI_CONTROL, 0xFF,
CS_POLARITY_HIGH | SPI_EEPROM_AUTO);
RTSX_WRITE_REG(chip, SPI_TCTL, EDO_TIMING_MASK, SAMPLE_DELAY_HALF);
return STATUS_SUCCESS;
}
static int spi_eeprom_program_enable(struct rtsx_chip *chip)
{
int retval;
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x86);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x13);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CA_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
int spi_erase_eeprom_chip(struct rtsx_chip *chip)
{
int retval;
retval = spi_init_eeprom(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = spi_eeprom_program_enable(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x12);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x84);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CA_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0)
TRACE_RET(chip, STATUS_FAIL);
RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0x01, 0x01);
return STATUS_SUCCESS;
}
int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr)
{
int retval;
retval = spi_init_eeprom(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = spi_eeprom_program_enable(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x07);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)(addr >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x46);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CA_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0)
TRACE_RET(chip, STATUS_FAIL);
RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0x01, 0x01);
return STATUS_SUCCESS;
}
int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val)
{
int retval;
u8 data;
retval = spi_init_eeprom(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x06);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, (u8)addr);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)(addr >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x46);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, 1);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CADI_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0)
TRACE_RET(chip, STATUS_FAIL);
wait_timeout(5);
RTSX_READ_REG(chip, SPI_DATA, &data);
if (val)
*val = data;
RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0x01, 0x01);
return STATUS_SUCCESS;
}
int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val)
{
int retval;
retval = spi_init_eeprom(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = spi_eeprom_program_enable(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO_DIR, 0x01, 0);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, 0x05);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, val);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, (u8)addr);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, (u8)(addr >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF, 0x4E);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CA_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0)
TRACE_RET(chip, STATUS_FAIL);
RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0x01, 0x01);
return STATUS_SUCCESS;
}
int spi_get_status(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
struct spi_info *spi = &(chip->spi);
RTSX_DEBUGP("spi_get_status: err_code = 0x%x\n", spi->err_code);
rtsx_stor_set_xfer_buf(&(spi->err_code),
min_t(int, scsi_bufflen(srb), 1), srb);
scsi_set_resid(srb, scsi_bufflen(srb) - 1);
return STATUS_SUCCESS;
}
int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
struct spi_info *spi = &(chip->spi);
spi_set_err_code(chip, SPI_NO_ERR);
if (chip->asic_code)
spi->spi_clock = ((u16)(srb->cmnd[8]) << 8) | srb->cmnd[9];
else
spi->spi_clock = srb->cmnd[3];
spi->clk_div = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5];
spi->write_en = srb->cmnd[6];
RTSX_DEBUGP("spi_set_parameter: spi_clock = %d, clk_div = %d, write_en = %d\n",
spi->spi_clock, spi->clk_div, spi->write_en);
return STATUS_SUCCESS;
}
int spi_read_flash_id(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
int retval;
u16 len;
u8 *buf;
spi_set_err_code(chip, SPI_NO_ERR);
len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
if (len > 512) {
spi_set_err_code(chip, SPI_INVALID_COMMAND);
TRACE_RET(chip, STATUS_FAIL);
}
retval = spi_set_init_para(chip);
if (retval != STATUS_SUCCESS) {
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, srb->cmnd[3]);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF, srb->cmnd[4]);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF, srb->cmnd[5]);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF, srb->cmnd[6]);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, srb->cmnd[7]);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, srb->cmnd[8]);
if (len == 0) {
if (srb->cmnd[9]) {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0,
0xFF, SPI_TRANSFER0_START | SPI_CA_MODE0);
} else {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0,
0xFF, SPI_TRANSFER0_START | SPI_C_MODE0);
}
} else {
if (srb->cmnd[9]) {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CADI_MODE0);
} else {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CDI_MODE0);
}
}
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0) {
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
if (len) {
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
TRACE_RET(chip, STATUS_ERROR);
retval = rtsx_read_ppbuf(chip, buf, len);
if (retval != STATUS_SUCCESS) {
spi_set_err_code(chip, SPI_READ_ERR);
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb);
scsi_set_resid(srb, 0);
kfree(buf);
}
return STATUS_SUCCESS;
}
int spi_read_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
int retval;
unsigned int index = 0, offset = 0;
u8 ins, slow_read;
u32 addr;
u16 len;
u8 *buf;
spi_set_err_code(chip, SPI_NO_ERR);
ins = srb->cmnd[3];
addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5])
<< 8) | srb->cmnd[6];
len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
slow_read = srb->cmnd[9];
retval = spi_set_init_para(chip);
if (retval != STATUS_SUCCESS) {
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL);
if (buf == NULL)
TRACE_RET(chip, STATUS_ERROR);
while (len) {
u16 pagelen = SF_PAGE_LEN - (u8)addr;
if (pagelen > len)
pagelen = len;
rtsx_init_cmd(chip);
trans_dma_enable(DMA_FROM_DEVICE, chip, 256, DMA_256);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
if (slow_read) {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR0, 0xFF,
(u8)addr);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
(u8)(addr >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
(u8)(addr >> 16));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
} else {
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR1, 0xFF,
(u8)addr);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR2, 0xFF,
(u8)(addr >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_ADDR3, 0xFF,
(u8)(addr >> 16));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_32);
}
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF,
(u8)(pagelen >> 8));
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF,
(u8)pagelen);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CADI_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0,
SPI_TRANSFER0_END, SPI_TRANSFER0_END);
rtsx_send_cmd_no_wait(chip);
retval = rtsx_transfer_data(chip, 0, buf, pagelen, 0,
DMA_FROM_DEVICE, 10000);
if (retval < 0) {
kfree(buf);
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
rtsx_stor_access_xfer_buf(buf, pagelen, srb, &index, &offset,
TO_XFER_BUF);
addr += pagelen;
len -= pagelen;
}
scsi_set_resid(srb, 0);
kfree(buf);
return STATUS_SUCCESS;
}
int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
int retval;
u8 ins, program_mode;
u32 addr;
u16 len;
u8 *buf;
unsigned int index = 0, offset = 0;
spi_set_err_code(chip, SPI_NO_ERR);
ins = srb->cmnd[3];
addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5])
<< 8) | srb->cmnd[6];
len = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8];
program_mode = srb->cmnd[9];
retval = spi_set_init_para(chip);
if (retval != STATUS_SUCCESS) {
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
if (program_mode == BYTE_PROGRAM) {
buf = kmalloc(4, GFP_KERNEL);
if (!buf)
TRACE_RET(chip, STATUS_ERROR);
while (len) {
retval = sf_enable_write(chip, SPI_WREN);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
rtsx_stor_access_xfer_buf(buf, 1, srb, &index, &offset,
FROM_XFER_BUF);
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF,
buf[0]);
sf_program(chip, ins, 1, addr, 1);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0) {
kfree(buf);
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
retval = sf_polling_status(chip, 100);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
addr++;
len--;
}
kfree(buf);
} else if (program_mode == AAI_PROGRAM) {
int first_byte = 1;
retval = sf_enable_write(chip, SPI_WREN);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
buf = kmalloc(4, GFP_KERNEL);
if (!buf)
TRACE_RET(chip, STATUS_ERROR);
while (len) {
rtsx_stor_access_xfer_buf(buf, 1, srb, &index, &offset,
FROM_XFER_BUF);
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF,
buf[0]);
if (first_byte) {
sf_program(chip, ins, 1, addr, 1);
first_byte = 0;
} else {
sf_program(chip, ins, 0, 0, 1);
}
retval = rtsx_send_cmd(chip, 0, 100);
if (retval < 0) {
kfree(buf);
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
retval = sf_polling_status(chip, 100);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
len--;
}
kfree(buf);
retval = sf_disable_write(chip, SPI_WRDI);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = sf_polling_status(chip, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
} else if (program_mode == PAGE_PROGRAM) {
buf = kmalloc(SF_PAGE_LEN, GFP_KERNEL);
if (!buf)
TRACE_RET(chip, STATUS_NOMEM);
while (len) {
u16 pagelen = SF_PAGE_LEN - (u8)addr;
if (pagelen > len)
pagelen = len;
retval = sf_enable_write(chip, SPI_WREN);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
rtsx_init_cmd(chip);
trans_dma_enable(DMA_TO_DEVICE, chip, 256, DMA_256);
sf_program(chip, ins, 1, addr, pagelen);
rtsx_send_cmd_no_wait(chip);
rtsx_stor_access_xfer_buf(buf, pagelen, srb, &index,
&offset, FROM_XFER_BUF);
retval = rtsx_transfer_data(chip, 0, buf, pagelen, 0,
DMA_TO_DEVICE, 100);
if (retval < 0) {
kfree(buf);
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
retval = sf_polling_status(chip, 100);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
addr += pagelen;
len -= pagelen;
}
kfree(buf);
} else {
spi_set_err_code(chip, SPI_INVALID_COMMAND);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
int spi_erase_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
int retval;
u8 ins, erase_mode;
u32 addr;
spi_set_err_code(chip, SPI_NO_ERR);
ins = srb->cmnd[3];
addr = ((u32)(srb->cmnd[4]) << 16) | ((u32)(srb->cmnd[5])
<< 8) | srb->cmnd[6];
erase_mode = srb->cmnd[9];
retval = spi_set_init_para(chip);
if (retval != STATUS_SUCCESS) {
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
if (erase_mode == PAGE_ERASE) {
retval = sf_enable_write(chip, SPI_WREN);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = sf_erase(chip, ins, 1, addr);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
} else if (erase_mode == CHIP_ERASE) {
retval = sf_enable_write(chip, SPI_WREN);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = sf_erase(chip, ins, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
} else {
spi_set_err_code(chip, SPI_INVALID_COMMAND);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
int spi_write_flash_status(struct scsi_cmnd *srb, struct rtsx_chip *chip)
{
int retval;
u8 ins, status, ewsr;
ins = srb->cmnd[3];
status = srb->cmnd[4];
ewsr = srb->cmnd[5];
retval = spi_set_init_para(chip);
if (retval != STATUS_SUCCESS) {
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
retval = sf_enable_write(chip, ewsr);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
rtsx_init_cmd(chip);
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_COMMAND, 0xFF, ins);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_CA_NUMBER, 0xFF,
SPI_COMMAND_BIT_8 | SPI_ADDRESS_BIT_24);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH1, 0xFF, 0);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_LENGTH0, 0xFF, 1);
rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2, 0xFF, status);
rtsx_add_cmd(chip, WRITE_REG_CMD, SPI_TRANSFER0, 0xFF,
SPI_TRANSFER0_START | SPI_CDO_MODE0);
rtsx_add_cmd(chip, CHECK_REG_CMD, SPI_TRANSFER0, SPI_TRANSFER0_END,
SPI_TRANSFER0_END);
retval = rtsx_send_cmd(chip, 0, 100);
if (retval != STATUS_SUCCESS) {
rtsx_clear_spi_error(chip);
spi_set_err_code(chip, SPI_HW_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}

Просмотреть файл

@ -0,0 +1,65 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_SPI_H
#define __REALTEK_RTSX_SPI_H
/* SPI operation error */
#define SPI_NO_ERR 0x00
#define SPI_HW_ERR 0x01
#define SPI_INVALID_COMMAND 0x02
#define SPI_READ_ERR 0x03
#define SPI_WRITE_ERR 0x04
#define SPI_ERASE_ERR 0x05
#define SPI_BUSY_ERR 0x06
/* Serial flash instruction */
#define SPI_READ 0x03
#define SPI_FAST_READ 0x0B
#define SPI_WREN 0x06
#define SPI_WRDI 0x04
#define SPI_RDSR 0x05
#define SF_PAGE_LEN 256
#define BYTE_PROGRAM 0
#define AAI_PROGRAM 1
#define PAGE_PROGRAM 2
#define PAGE_ERASE 0
#define CHIP_ERASE 1
int spi_erase_eeprom_chip(struct rtsx_chip *chip);
int spi_erase_eeprom_byte(struct rtsx_chip *chip, u16 addr);
int spi_read_eeprom(struct rtsx_chip *chip, u16 addr, u8 *val);
int spi_write_eeprom(struct rtsx_chip *chip, u16 addr, u8 val);
int spi_get_status(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int spi_read_flash_id(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int spi_read_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int spi_write_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int spi_erase_flash(struct scsi_cmnd *srb, struct rtsx_chip *chip);
int spi_write_flash_status(struct scsi_cmnd *srb, struct rtsx_chip *chip);
#endif /* __REALTEK_RTSX_SPI_H */

Просмотреть файл

@ -0,0 +1,93 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_TRACE_H
#define __REALTEK_RTSX_TRACE_H
#define _MSG_TRACE
#ifdef _MSG_TRACE
static inline char *filename(char *path)
{
char *ptr;
if (path == NULL)
return NULL;
ptr = path;
while (*ptr != '\0') {
if ((*ptr == '\\') || (*ptr == '/'))
path = ptr + 1;
ptr++;
}
return path;
}
#define TRACE_RET(chip, ret) \
do { \
char *_file = filename(__FILE__); \
RTSX_DEBUGP("[%s][%s]:[%d]\n", _file, __func__, __LINE__); \
(chip)->trace_msg[(chip)->msg_idx].line = (u16)(__LINE__); \
strncpy((chip)->trace_msg[(chip)->msg_idx].func, __func__, MSG_FUNC_LEN-1); \
strncpy((chip)->trace_msg[(chip)->msg_idx].file, _file, MSG_FILE_LEN-1); \
get_current_time((chip)->trace_msg[(chip)->msg_idx].timeval_buf, TIME_VAL_LEN); \
(chip)->trace_msg[(chip)->msg_idx].valid = 1; \
(chip)->msg_idx++; \
if ((chip)->msg_idx >= TRACE_ITEM_CNT) { \
(chip)->msg_idx = 0; \
} \
return ret; \
} while (0)
#define TRACE_GOTO(chip, label) \
do { \
char *_file = filename(__FILE__); \
RTSX_DEBUGP("[%s][%s]:[%d]\n", _file, __func__, __LINE__); \
(chip)->trace_msg[(chip)->msg_idx].line = (u16)(__LINE__); \
strncpy((chip)->trace_msg[(chip)->msg_idx].func, __func__, MSG_FUNC_LEN-1); \
strncpy((chip)->trace_msg[(chip)->msg_idx].file, _file, MSG_FILE_LEN-1); \
get_current_time((chip)->trace_msg[(chip)->msg_idx].timeval_buf, TIME_VAL_LEN); \
(chip)->trace_msg[(chip)->msg_idx].valid = 1; \
(chip)->msg_idx++; \
if ((chip)->msg_idx >= TRACE_ITEM_CNT) { \
(chip)->msg_idx = 0; \
} \
goto label; \
} while (0)
#else
#define TRACE_RET(chip, ret) return ret
#define TRACE_GOTO(chip, label) goto label
#endif
#ifdef CONFIG_RTS5208_DEBUG
#define RTSX_DUMP(buf, buf_len) \
print_hex_dump(KERN_DEBUG, RTSX_STOR, DUMP_PREFIX_NONE, \
16, 1, (buf), (buf_len), false)
#else
#define RTSX_DUMP(buf, buf_len)
#endif
#endif /* __REALTEK_RTSX_TRACE_H */

2088
drivers/staging/rts5208/xd.c Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,188 @@
/* Driver for Realtek PCI-Express card reader
* Header file
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Wei WANG (wei_wang@realsil.com.cn)
* Micky Ching (micky_ching@realsil.com.cn)
*/
#ifndef __REALTEK_RTSX_XD_H
#define __REALTEK_RTSX_XD_H
#define XD_DELAY_WRITE
/* Error Codes */
#define XD_NO_ERROR 0x00
#define XD_NO_MEMORY 0x80
#define XD_PRG_ERROR 0x40
#define XD_NO_CARD 0x20
#define XD_READ_FAIL 0x10
#define XD_ERASE_FAIL 0x08
#define XD_WRITE_FAIL 0x04
#define XD_ECC_ERROR 0x02
#define XD_TO_ERROR 0x01
/* XD Commands */
#define READ1_1 0x00
#define READ1_2 0x01
#define READ2 0x50
#define READ_ID 0x90
#define RESET 0xff
#define PAGE_PRG_1 0x80
#define PAGE_PRG_2 0x10
#define BLK_ERASE_1 0x60
#define BLK_ERASE_2 0xD0
#define READ_STS 0x70
#define READ_xD_ID 0x9A
#define COPY_BACK_512 0x8A
#define COPY_BACK_2K 0x85
#define READ1_1_2 0x30
#define READ1_1_3 0x35
#define CHG_DAT_OUT_1 0x05
#define RDM_DAT_OUT_1 0x05
#define CHG_DAT_OUT_2 0xE0
#define RDM_DAT_OUT_2 0xE0
#define CHG_DAT_OUT_2 0xE0
#define CHG_DAT_IN_1 0x85
#define CACHE_PRG 0x15
/* Redundant Area Related */
#define XD_EXTRA_SIZE 0x10
#define XD_2K_EXTRA_SIZE 0x40
#define NOT_WRITE_PROTECTED 0x80
#define READY_STATE 0x40
#define PROGRAM_ERROR 0x01
#define PROGRAM_ERROR_N_1 0x02
#define INTERNAL_READY 0x20
#define READY_FLAG 0x5F
#define XD_8M_X8_512 0xE6
#define XD_16M_X8_512 0x73
#define XD_32M_X8_512 0x75
#define XD_64M_X8_512 0x76
#define XD_128M_X8_512 0x79
#define XD_256M_X8_512 0x71
#define XD_128M_X8_2048 0xF1
#define XD_256M_X8_2048 0xDA
#define XD_512M_X8 0xDC
#define XD_128M_X16_2048 0xC1
#define XD_4M_X8_512_1 0xE3
#define XD_4M_X8_512_2 0xE5
#define xD_1G_X8_512 0xD3
#define xD_2G_X8_512 0xD5
#define XD_ID_CODE 0xB5
#define VENDOR_BLOCK 0xEFFF
#define CIS_BLOCK 0xDFFF
#define BLK_NOT_FOUND 0xFFFFFFFF
#define NO_NEW_BLK 0xFFFFFFFF
#define PAGE_CORRECTABLE 0x0
#define PAGE_NOTCORRECTABLE 0x1
#define NO_OFFSET 0x0
#define WITH_OFFSET 0x1
#define Sect_Per_Page 4
#define XD_ADDR_MODE_2C XD_ADDR_MODE_2A
#define ZONE0_BAD_BLOCK 23
#define NOT_ZONE0_BAD_BLOCK 24
#define XD_RW_ADDR 0x01
#define XD_ERASE_ADDR 0x02
#define XD_PAGE_512(xd_card) \
do { \
(xd_card)->block_shift = 5; \
(xd_card)->page_off = 0x1F; \
} while (0)
#define XD_SET_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag |= 0x01)
#define XD_CLR_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag &= ~0x01)
#define XD_CHK_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag & 0x01)
#define XD_SET_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag |= 0x02)
#define XD_CLR_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag &= ~0x02)
#define XD_CHK_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag & 0x02)
#define XD_SET_MBR_FAIL(xd_card) ((xd_card)->multi_flag |= 0x04)
#define XD_CLR_MBR_FAIL(xd_card) ((xd_card)->multi_flag &= ~0x04)
#define XD_CHK_MBR_FAIL(xd_card) ((xd_card)->multi_flag & 0x04)
#define XD_SET_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag |= 0x08)
#define XD_CLR_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag &= ~0x08)
#define XD_CHK_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag & 0x08)
#define XD_SET_4MB(xd_card) ((xd_card)->multi_flag |= 0x10)
#define XD_CLR_4MB(xd_card) ((xd_card)->multi_flag &= ~0x10)
#define XD_CHK_4MB(xd_card) ((xd_card)->multi_flag & 0x10)
#define XD_SET_ECC_ERR(xd_card) ((xd_card)->multi_flag |= 0x40)
#define XD_CLR_ECC_ERR(xd_card) ((xd_card)->multi_flag &= ~0x40)
#define XD_CHK_ECC_ERR(xd_card) ((xd_card)->multi_flag & 0x40)
#define PAGE_STATUS 0
#define BLOCK_STATUS 1
#define BLOCK_ADDR1_L 2
#define BLOCK_ADDR1_H 3
#define BLOCK_ADDR2_L 4
#define BLOCK_ADDR2_H 5
#define RESERVED0 6
#define RESERVED1 7
#define RESERVED2 8
#define RESERVED3 9
#define PARITY 10
#define CIS0_0 0
#define CIS0_1 1
#define CIS0_2 2
#define CIS0_3 3
#define CIS0_4 4
#define CIS0_5 5
#define CIS0_6 6
#define CIS0_7 7
#define CIS0_8 8
#define CIS0_9 9
#define CIS1_0 256
#define CIS1_1 (256 + 1)
#define CIS1_2 (256 + 2)
#define CIS1_3 (256 + 3)
#define CIS1_4 (256 + 4)
#define CIS1_5 (256 + 5)
#define CIS1_6 (256 + 6)
#define CIS1_7 (256 + 7)
#define CIS1_8 (256 + 8)
#define CIS1_9 (256 + 9)
int reset_xd_card(struct rtsx_chip *chip);
#ifdef XD_DELAY_WRITE
int xd_delay_write(struct rtsx_chip *chip);
#endif
int xd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
u32 start_sector, u16 sector_cnt);
void xd_free_l2p_tbl(struct rtsx_chip *chip);
void xd_cleanup_work(struct rtsx_chip *chip);
int xd_power_off_card3v3(struct rtsx_chip *chip);
int release_xd_card(struct rtsx_chip *chip);
#endif /* __REALTEK_RTSX_XD_H */