SPI驅動檔案解析
阿新 • • 發佈:2018-11-04
三:SPI裝置驅動程式
在板檔案中新增SPI裝置
<span style="color:#444444"><strong>static </strong> <strong>struct</strong> spi_board_info s3c_spi_devs [] __initdata [ <span style="color:#880000">0</span> ] = { .modalias = <span style="color:#880000">“spidev”</span>, <span style="color:#888888">/ *裝置節點名稱* /</span> .mode = SPI_MODE_0, <span style="color:#888888">/ * CPOL = 0,CPHA = 0 * /</span> .max_speed_hz = <span style="color:#880000">10000000</span>, <span style="color:#888888">/ *連線到SPI-1作為第1個從站* /</span> .bus_num = <span style="color:#880000">1</span>, .irq = IRQ_SPI1, .chip_select = <span style="color:#880000">0</span>, .controller_data =&smdk_spi1_csi [SMDK_MMCSPI_CS], }, }</span>
裝置的片選資訊
<span style="color:#444444">/ *
static struct s3c64xx_spi_csinfo smdk_spi0_csi [] = {
[SMDK_MMCSPI_CS] = {
.line = S5PV210_GPB(1),
.set_level = gpio_ <span style="color:#1f811f">set</span> _value,
.fb_delay = 0x0,
},
}; * /</span>
設定平臺資訊
<span style="color:#444444"> <strong>if</strong>(!gpio_request(S5PV210_GPB(1),<span style="color:#880000">“SPICS0”</span>)){ gpio_direction_output(S5PV210_GPB(1),1); s3c_gpio_cfgpin(S5PV210_GPB(1),S3C_GPIO_SFN(1)); s3c_gpio_setpull(S5PV210_GPB(1),S3C_GPIO_PULL_UP); s5pv210_spi_ <span style="color:#1f811f">set</span> _info(0,S5PV210_SPI_SRCCLK_PCLK, ARRAY_SIZE(smdk_spi0_csi)); }</span>
<span style="color:#444444">s5pv210_spi_ <span style="color:#1f811f">set</span> _info(0,S5PV210_SPI_SRCCLK_PCLK,
ARRAY_SIZE(smdk_spi0_csi));</span>
<span style="color:#444444"><strong>void</strong> __ init <span style="color:#880000"><strong>s5pv210_spi_set_info </strong></span>(<strong>int</strong> cntrlr,<strong>int</strong> src_clk_nr,<strong>int</strong> num_cs)
{
<strong>struct</strong> s3c64xx_spi_info * pd;
<span style="color:#888888">/ *拒絕無效配置* / </span>
<strong>if</strong>(!num_cs || src_clk_nr < <span style="color:#880000">0</span>
|| src_clk_nr> S5PV210_SPI_SRCCLK_SCLK){
printk(KERN_ERR <span style="color:#880000">“%s:SPI配置無效\ n”</span>,__ func__);
<strong>迴歸</strong> ;
}
<strong>switch</strong>(cntrlr){
<strong>案例</strong> <span style="color:#880000">0</span>:
pd =&s5pv210_spi0_pdata;
<strong>打破</strong> ;
<strong>案例</strong> <span style="color:#880000">1</span>:
pd =&s5pv210_spi1_pdata;
<strong>打破</strong> ;
<strong>預設值</strong>:
printk(KERN_ERR <span style="color:#880000">“%s:無效的SPI控制器(%d)\ n”</span>,
__func __,cntrlr);
<strong>迴歸</strong> ;
}
pd-> num_cs = num_cs;
pd-> src_clk_nr = src_clk_nr;
pd-> src_clk_name = spi_src_clks [src_clk_nr];
}</span>
<span style="color:#444444">pd =&s5pv210_spi0_pdata;</span>
<span style="color:#444444"><strong>static </strong> <strong>struct</strong> s3c64xx_spi_info s5pv210_spi0_pdata = {
.cfg_gpio = s5pv210_spi_cfg_gpio,
.fifo_lvl_mask = <span style="color:#880000">0x1ff</span>,
.rx_lvl_offset = <span style="color:#880000">15</span>,
.high_speed = <span style="color:#880000">1</span>,
};</span>
將該設備註冊到系統中
<span style="color:#444444">spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));</span>
板檔案設定完了,就是裝置驅動了
驅動結構體
<span style="color:#444444"><strong>struct</strong> spidev_data {
<strong>dev_t</strong> devt;
<strong>spinlock_t</strong> spi_lock;
<strong>struct</strong> spi_device * spi;
<strong>struct</strong> list_head device_entry;
<span style="color:#888888">/ * buffer為NULL,除非此裝置已開啟(users> 0)* / </span>
<strong>struct</strong> mutex buf_lock;
<strong>未簽名的</strong> 使用者;
u8 *緩衝;
};</span>
註冊驅動
S5PV210會在/ dev /下生成幾個視訊相關的裝置節點,分別為/ dev / video0,/ dev / video1,/ dev / video2 / dev / video14,/ dev / video21,/ dev / video22 video0,video1, v
<span style="color:#444444"><strong>static </strong> <strong>struct</strong> spi_driver spidev_spi_driver = {
.driver = {
.name = <span style="color:#880000">“spidev”</span>,
.owner = THIS_MODULE,
},
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),
<span style="color:#888888">/ * <strong>注意:</strong> 這裡不需要暫停/恢復方法。
*除了將請求傳遞給/從之外,我們不做任何事情
*底層控制器。冰箱把手
*大多數問題; 控制器驅動程式處理其餘部分。
* /</span>
};</span>
<span style="color:#444444"><strong>static </strong> <strong>int</strong> __ init <span style="color:#880000"><strong>spidev_init </strong></span>(<strong>void</strong>)
{
<strong>int</strong> status;
<span style="color:#888888">/ *宣告我們的256個預留裝置號。然後註冊一個課程
*將金鑰udev / mdev新增/刪除/ dev節點。最後,註冊
*管理這些裝置號的驅動程式。
* /</span>
BUILD_BUG_ON(N_SPI_MINORS> <span style="color:#880000">256</span>);
status = register_chrdev(SPIDEV_MAJOR,<span style="color:#880000">“spi”</span>,&spidev_fops); <span style="color:#888888">//註冊字元驅動,方便檔案io操作</span>
<strong>if</strong>(status < <span style="color:#880000">0</span>)
<strong>返回</strong>狀態;
spidev_class = class_create(THIS_MODULE,<span style="color:#880000">“spidev”</span>); <span style="color:#888888">//用與自動建立節點,在驅動探測到後,就會建立節點</span>
<strong>if</strong>(IS_ERR(spidev_class)){
unregister_chrdev(SPIDEV_MAJOR,spidev_spi_driver.driver.name);
<strong>返回</strong> PTR_ERR(spidev_class);
}
status = spi_register_driver(&spidev_spi_driver); <span style="color:#888888">//註冊spi驅動</span>
<strong>if</strong>(status < <span style="color:#880000">0</span>){
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR,spidev_spi_driver.driver.name);
}
<strong>返回</strong>狀態;
}
巨集module_init(spidev_init);</span>
當驅動探測到後
<span style="color:#444444"><strong>static</strong> int __devinit spidev_probe(struct spi_device * spi)
{
struct spidev_data * spidev;
int狀態;
未簽名的長期未成年人
<span style="color:#888888">/ *分配驅動資料* /</span>
spidev = kzalloc(sizeof(* spidev),GFP_KERNEL); <span style="color:#888888">//分配spi驅動資料</span>
<strong>if</strong>(!spidev)
<strong>return</strong> -ENOMEM;
<span style="color:#888888">/ *初始化驅動程式資料* / </span><span style="color:#888888">//驅動賦值</span>
spidev-> spi = spi;
spin_lock_init(spidev-> spi_lock);
呼叫mutex_init(spidev-> buf_lock);
INIT_LIST_HEAD(spidev-> device_entry); <span style="color:#888888">//初始化連結串列</span>
<span style="color:#888888">/ *如果我們可以分配一個次要號碼,請掛鉤此裝置。
*只要udev或mdev工作,重複使用未成年人就可以了。
* /</span>
的mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors,N_SPI_MINORS);
<strong>if</strong>(minor <N_SPI_MINORS){
struct device * dev;
spidev-> devt = MKDEV(SPIDEV_MAJOR,minor);
dev = device_create(spidev_class,&spi-> dev,spidev-> devt,
spidev,<span style="color:#880000">“spidev%d。%d”</span>,
spi-> master-> bus_num,spi-> chip_select); <span style="color:#888888">//建立裝置節點</span>
status = IS_ERR(dev)?PTR_ERR(dev):<span style="color:#880000">0</span> ;
} <strong>else</strong> {
dev_dbg(&spi-> dev,<span style="color:#880000">“沒有次要號碼!\ n”</span>);
status = -ENODEV;
}
<strong>if</strong>(status == <span style="color:#880000">0</span>){
set_bit(未成年人,未成年人);
list_add(&spidev-> device_entry,&device_list);
}
mutex_unlock(&device_list_lock);
<strong>if</strong>(status == <span style="color:#880000">0</span>)
spi_set_drvdata(spi,spidev); <span style="color:#888888">//儲存驅動資料到SPI的私有資料。用於後面的讀寫操作</span>
<strong>其他</strong>
kfree(spidev);
<strong>返回</strong>狀態;
}</span>
到這裡,,驅動就成功匹配到裝置了
驅動的資料寫流程:
當驅動開啟後,應用層呼叫寫函式
,在驅動中的過程如下
<span style="color:#444444"><strong>static</strong> ssize_t
<span style="color:#880000"><strong>spidev_write </strong></span>(<strong>struct</strong> file * filp,<strong>const </strong> <strong>char</strong> __user * buf,
size_t count,loff_t * f_pos)
{
<strong> struct</strong> spidev_data * spidev;
<strong>ssize_t</strong> status =<span style="color:#880000"> 0</span> ;
<strong>未簽名的</strong> <strong>長期</strong> 失蹤;
<span style="color:#888888">/ * chipselect僅在操作開始或結束時切換* / </span>
<strong>if</strong>(count> bufsiz)
<strong>返回</strong> -EMSGSIZE;
spidev = filp-> private_data; <span style="color:#888888">//從SPI私有資料獲取驅動資訊</span>
的mutex_lock(&spidev-> buf_lock);
missing = copy_from_user(spidev-> buffer,buf,count); <span style="color:#888888">//從使用者層獲取資料</span>
<strong>if</strong>(missing == <span style="color:#880000">0</span>){
status = spidev_sync_write(spidev,count); <span style="color:#888888">//成功,則呼叫該函式</span>
} <strong>else</strong>
status = -EFAULT;
mutex_unlock(&spidev-> buf_lock);
<strong>返回</strong>狀態;
}</span>
<span style="color:#444444"><strong>static</strong> inline ssize_t
spidev_sync_write(struct spidev_data * spidev,size_t len)
{ <span style="color:#888888">// spi傳送資料所需要的兩個結構體,要傳送的資料儲存在</span></span>
// struct spi_transfer中 struct spi_transfer t = { .tx_buf = spidev-> buffer, .len = len, }; struct spi_message m; spi_message_init(米); spi_message_add_tail(&t,&m); // spi是一個訊息佇列來發送的 返回 spidev_sync(spidev,&m); //再呼叫此函式 }
static ssize_t
spidev_sync(struct spidev_data * spidev,struct spi_message * message)
{
DECLARE_COMPLETION_ONSTACK(完成);
int狀態;
message-> complete = spidev_complete; //同步
message-> context =&done;
spin_lock_irq(&spidev-> spi_lock);
if(spidev-> spi == NULL)
status = -ESHUTDOWN;
else
status = spi_async(spidev-> spi,message); //呼叫SPI核心層的傳送函式
spin_unlock_irq(spidev-> spi_lock);
if(status == 0){
wait_for_completion(完成);
status = message-> status;
if(status == 0)
status = message-> actual_length;
}
返回狀態;
}
int spi_async(struct spi_device * spi,struct spi_message * message)
{
struct spi_master * master = spi-> master; //取出該裝置的控制器
/ *半雙工連結包括原始MicroWire和帶有的
*只有一個數據引腳,如SPI_3WIRE(開關方向)或其中
*缺少MOSI或MISO。他們也可能是由
*軟體限制。
* /
if((master-> flags&SPI_MASTER_HALF_DUPLEX)
|| (spi-> mode&SPI_3WIRE)){
struct spi_transfer * xfer;
unsigned flags = master-> flags;
list_for_each_entry(xfer,&message-> transfers,transfer_list){
if(xfer-> rx_buf && xfer-> tx_buf)
返回 -EINVAL;
if((flags&SPI_MASTER_NO_TX)&& xfer-> tx_buf)
return -EINVAL;
if((flags&SPI_MASTER_NO_RX)&& xfer-> rx_buf)
return -EINVAL;
}
} //找到要傳送的資訊
message-> spi = spi;
message-> status = -EINPROGRESS;
return master-> transfer(spi,message); //呼叫控制器的傳送函式傳送
}
即:
master-> transfer = s3c64xx_spi_transfer;
static int s3c64xx_spi_transfer(struct spi_device * spi,
struct spi_message * msg)
{
struct s3c64xx_spi_driver_data * sdd;
無符號長旗;
sdd = spi_master_get_devdata(spi-> master);
spin_lock_irqsave(&sdd-> lock,flags);
printk(KERN_DEBUG “s3c64xx_spi_transfer \ n”);
if(sdd-> state&SUSPND){
spin_unlock_irqrestore(&sdd-> lock,flags);
返回 -ESHUTDOWN;
}
msg-> status = -EINPROGRESS;
msg-> actual_length = 0 ;
list_add_tail(&msg-> queue,&sdd-> queue); //將訊息調價到訊息連結串列尾部
queue_work(sdd-> workqueue,&sdd-> work); //新增到工作佇列
spin_unlock_irqrestore(&sdd-> lock,flags);
返回 0 ;
}
接下來就是工作佇列來發送資料
static void s3c64xx_spi_work(struct work_struct * work)
{
struct s3c64xx_spi_driver_data * sdd = container_of(work,
struct s3c64xx_spi_driver_data,work);
無符號長旗;
printk(KERN_DEBUG “s3c64xx_spi_work \ n”);
/ *獲取DMA通道* /
while(!acquire_dma(sdd))
msleep(10);
spin_lock_irqsave(&sdd-> lock,flags);
while(!list_empty(&sdd-> queue)
&&!(sdd-> state&SUSPND)){
struct spi_message * msg;
msg = container_of(sdd-> queue.next,struct spi_message,queue);
list_del_init(MSG->佇列);
/ *設定Xfer忙標誌* /
sdd-> state | = SPIBUSY;
spin_unlock_irqrestore(&sdd-> lock,flags);
handle_msg(sdd,msg); //傳送資料
spin_lock_irqsave(&sdd-> lock,flags);
sdd-> state&= ~SPIBUSY;
}
spin_unlock_irqrestore(&sdd-> lock,flags);
/ *免費DMA頻道* /
s3c2410_dma_free(sdd-> tx_dmach,&s3c64xx_spi_dma_client);
s3c2410_dma_free(sdd-> rx_dmach,&s3c64xx_spi_dma_client);
}
static int s3c64xx_spi_transfer(struct spi_device * spi,
struct spi_message * msg)
{
struct s3c64xx_spi_driver_data * sdd;
無符號長旗;
sdd = spi_master_get_devdata(spi-> master);
spin_lock_irqsave(&sdd-> lock,flags);
printk(KERN_DEBUG “s3c64xx_spi_transfer \ n”);
if(sdd-> state&SUSPND){
spin_unlock_irqrestore(&sdd-> lock,flags);
返回 -ESHUTDOWN;
}
msg-> status = -EINPROGRESS;
msg-> actual_length = 0 ;
list_add_tail(&msg-> queue,&sdd-> queue);
queue_work(sdd-> workqueue,&sdd-> work);
spin_unlock_irqrestore(&sdd-> lock,flags);
返回 0 ;
}
static void handle_msg(struct s3c64xx_spi_driver_data * sdd,
struct spi_message * msg)
{
struct s3c64xx_spi_info * sci = sdd-> cntrlr_info;
struct spi_device * spi = msg-> spi;
struct s3c64xx_spi_csinfo * cs = spi-> controller_data;
struct spi_transfer * xfer;
int status = 0,cs_toggle = 0 ;
u32速度;
u8 bpw;
int i;
printk(KERN_DEBUG “handle_msg \ n”);
/ *如果Master(控制器)狀態與Slave * /
if 所需的狀態不同(sdd-> cur_speed!= spi-> max_speed_hz
|| sdd-> cur_mode!= spi->模式
|| sdd-> cur_bpw!= spi-> bits_per_word){
sdd-> cur_bpw = spi-> bits_per_word;
sdd-> cur_speed = spi-> max_speed_hz;
sdd-> cur_mode = spi-> mode;
s3c64xx_spi_config(SDD); //主的傳輸方式跟從裝置不同時,重新配置
}
/ *如果需要,對映所有傳輸* /
if(s3c64xx_spi_map_mssg(sdd,msg)){
dev_err(SPI->開發,
“Xfer:無法對映訊息緩衝區!\ n”);
status = -ENOMEM;
轉出;
}
/ *配置反饋延遲* /
writel(cs-> fb_delay&0x3,sdd-> regs + S3C64XX_SPI_FB_CLK);
list_for_each_entry(xfer,&msg-> transfers,transfer_list){
無符號長旗;
int use_dma;
INIT_COMPLETION(sdd-> xfer_completion);
/ *只有BPW和速度可能會在轉移中發生變化* /
bpw = xfer-> bits_per_word?:spi-> bits_per_word;
speed = xfer-> speed_hz?:spi-> max_speed_hz;
if(bpw!= sdd-> cur_bpw || speed!= sdd-> cur_speed){
sdd-> cur_bpw = bpw;
sdd-> cur_speed =速度;
s3c64xx_spi_config(SDD);
}
/ * xfers的輪詢方法不大於FIFO容量* /
if(xfer-> len <=((sci-> fifo_lvl_mask >> 1)+ 1))//這裡可以看晶片手冊,主要是判斷用dma方式傳輸還是fifo,下面有截圖
use_dma = 0 ;
否則
use_dma = 1 ;
spin_lock_irqsave(&sdd-> lock,flags);
/ *僅待處理* /
sdd-> state&= ~RXBUSY;
sdd-> state&= ~TXBUSY;
char * tx_tmp =(char *)xfer-> tx_buf;
for(i = 0 ; i <xfer-> len; i ++)
printk(KERN_DEBUG “xfer-> len =%d,xfer-> tx_buf [%d] =%x \ n”,xfer-> len,i,tx_tmp [i]);
enable_datapath(sdd,spi,xfer,use_dma);
/ *奴隸選擇* /
enable_cs(sdd,spi);
/ *啟動訊號* /
S3C64XX_SPI_ACT(SDD);
spin_unlock_irqrestore(&sdd-> lock,flags);
status = wait_for_xfer(sdd,xfer,use_dma); //等待完成
/ *靜音訊號* /
S3C64XX_SPI_DEACT(SDD);
if(status){
dev_err(&spi-> dev,“I / O錯誤:”
“rx-%d tx-%d res:rx-%c tx-%c len-%d \ n”,
xfer-> rx_buf?1:0,xfer-> tx_buf?1:0,
(sdd-> state&RXBUSY)?'f':'p',
(sdd-> state&TXBUSY)?'f':'p',
xfer-> LEN);
if(use_dma){
if(xfer-> tx_buf!= NULL
&&(sdd-> state&TXBUSY))
s3c2410_dma_ctrl(sdd-> tx_dmach,
S3C2410_DMAOP_FLUSH);
if(xfer-> rx_buf!= NULL
&&(sdd-> state&RXBUSY))
s3c2410_dma_ctrl(sdd-> rx_dmach,
S3C2410_DMAOP_FLUSH);
}
轉出;
}
if(xfer-> delay_usecs)
udelay的(xfer-> delay_usecs);
if(xfer-> cs_change){
/ *暗示下一個mssg會是
對於相同的裝置* /
if(list_is_last(&xfer-> transfer_list,
&MSG->轉移))
cs_toggle = 1 ;
其他
disable_cs(sdd,spi);
}
msg-> actual_length + = xfer-> len;
FLUSH_FIFO(SDD);
}
出:
if(!cs_toggle || status)
disable_cs(sdd,spi);
其他
sdd-> tgl_spi = spi;
s3c64xx_spi_unmap_mssg(sdd,msg);
msg-> status = status;
if(msg->完成)
MSG->完成(MSG->上下文);
}
上面選擇DMA還是FIFO的截圖:
static void enable_datapath(struct s3c64xx_spi_driver_data * sdd,
struct spi_device * spi,
struct spi_transfer * xfer,int dma_mode)
{
struct s3c64xx_spi_info * sci = sdd-> cntrlr_info;
void __iomem * regs = sdd-> regs;
u32 modecfg,chcfg;
printk(KERN_DEBUG “enable_datapath \ n”);
//配置暫存器
modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
modecfg&=〜(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
chcfg = readl(regs + S3C64XX_SPI_CH_CFG);
chcfg&= ~S3C64XX_SPI_CH_TXCH_ON;
if(dma_mode){
chcfg&= ~S3C64XX_SPI_CH_RXCH_ON;
} else {
/ *總是在FIFO中移入資料,即使xfer只是Tx,
*這有助於設定PCKT_CNT值以生成時鐘
*完全需要。
* /
chcfg | = S3C64XX_SPI_CH_RXCH_ON;
writel(((xfer-> len * 8 / sdd-> cur_bpw)&0xffff)
| S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT);
}
if(xfer-> tx_buf!= NULL){
sdd-> state | = TXBUSY;
chcfg | = S3C64XX_SPI_CH_TXCH_ON;
if(dma_mode){
printk(KERN_DEBUG “DMA_MODE \ n”);
modecfg | = S3C64XX_SPI_MODE_TXDMA_ON;
s3c2410_dma_config(sdd-> tx_dmach,1);
s3c2410_dma_enqueue(sdd-> tx_dmach,(void *)sdd,
xfer-> tx_dma,xfer-> len);
s3c2410_dma_ctrl(sdd-> tx_dmach,S3C2410_DMAOP_START);
} else {
unsigned char * buf =(unsigned char *)xfer-> tx_buf;
int i = 0 ;
而(i <xfer-> len)
writeb(buf [i ++],regs + S3C64XX_SPI_TX_DATA); //將資料寫到傳送暫存器
}
}
if(xfer-> rx_buf!= NULL){
sdd-> state | = RXBUSY;
if(sci-> high_speed && sdd-> cur_speed> = 30000000 UL
&&!(sdd-> cur_mode&SPI_CPHA))
chcfg | = S3C64XX_SPI_CH_HS_EN;
if(dma_mode){
modecfg | = S3C64XX_SPI_MODE_RXDMA_ON;
chcfg | = S3C64XX_SPI_CH_RXCH_ON;
writel(((xfer-> len * 8 / sdd-> cur_bpw)&0xffff)
| S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT);
s3c2410_dma_config(sdd-> rx_dmach,1);
s3c2410_dma_enqueue(sdd-> rx_dmach,(void *)sdd,
xfer-> rx_dma,xfer-> len);
s3c2410_dma_ctrl(sdd-> rx_dmach,S3C2410_DMAOP_START);
}
}
writel(modecfg,regs + S3C64XX_SPI_MODE_CFG);
writel(chcfg,regs + S3C64XX_SPI_CH_CFG);
}
static int wait_for_xfer(struct s3c64xx_spi_driver_data * sdd,
struct spi_transfer * xfer,int dma_mode)
{
struct s3c64xx_spi_info * sci = sdd-> cntrlr_info;
void __iomem * regs = sdd-> regs;
無符號長val;
int ms;
printk(KERN_DEBUG “wait_for_xfer \ n”);
/ * millisecs到xfer'len'位元組@'cur_speed'* /
ms = xfer-> len * 8 * 1000 / sdd-> cur_speed;
ms + = 5 ; / *一些公差* /
if(dma_mode){
val = msecs_to_jiffies(ms)+ 10 ;
val = wait_for_completion_timeout(&sdd-> xfer_completion,val);
} else {
u32狀態;
val = msecs_to_loops(ms);
做 {
status = readl(regs + S3C64XX_SPI_STATUS);讀狀態暫存器
printk(KERN_DEBUG “status =%d \ n”,狀態);
} while(RX_FIFO_LVL(status,sci)<xfer-> len && --val);
}
printk(KERN_DEBUG “VAL =%d \ n”,val);
if(!val)
return -EIO;
if(dma_mode){
u32狀態;
/ *
*簡單地在FIFO中寫入資料後,DmaTx返回,
*沒有等待總線上的實際傳輸完成。
* DmaRx僅在Dma從FIFO讀取資料後才返回
*需要匯流排傳輸完成,所以我們不擔心
* Xfer涉及Rx(有或沒有Tx)。
* /
if(xfer-> rx_buf == NULL){
val = msecs_to_loops(10);
status = readl(regs + S3C64XX_SPI_STATUS);
while((TX_FIFO_LVL(status,sci)
|| !S3C64XX_SPI_ST_TX_DONE(status,sci))
&& --val){
cpu_relax();
status = readl(regs + S3C64XX_SPI_STATUS);
}
if(!val)
return -EIO;
}
} else {
unsigned char * buf;
int i;
/ *如果它只是Tx * /
if(xfer-> rx_buf == NULL){
sdd-> state&= ~TXBUSY;
返回 0 ;
}
i = 0 ;
buf = xfer-> rx_buf;
而(i <xfer-> len)
buf [i ++] = readb(regs + S3C64XX_SPI_RX_DATA);
sdd-> state&= ~RXBUSY;
}
返回 0 ;
}