裝置樹學習之(十)spi flash
開發板:tiny4412SDK + S702 + 4GB Flash
要移植的核心版本:Linux-4.4.0 (支援device tree)
u-boot版本:友善之臂自帶的 U-Boot 2010.12
busybox版本:busybox 1.25
目標:
驅動外接的8M的 spi flash,註冊為塊裝置。
裝置樹:
&spi_0 {
status = "okay";
cs-gpios = <&gpb 1 GPIO_ACTIVE_HIGH>;
[email protected] 0 {
compatible = "tiny4412,spi_flash";
spi-max-frequency = <10000000>;
reg = <0>;
controller-data {
samsung,spi-feedback-delay = <0>;
};
};
};
這裡指定的 reg = <0> 表示的該 spi 裝置引用第一個 cs-gpios
spi-max-frequency = <10000000>;表示最大速率
程式碼:
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/media.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/videodev2.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/s5c73m3.h>
#include <media/v4l2-of.h>
#include <linux/mtd/mtd.h>
/* 參考:
* drivers\mtd\devices\mtdram.c
* drivers/mtd/devices/m25p80.c
*/
static struct spi_device *spi_flash;
void SPIFlashReadID(int *pMID, int *pDID)
{
unsigned char tx_buf[4];
unsigned char rx_buf[2];
//printk("%s\n",__func__);
tx_buf[0] = 0x90;
tx_buf[1] = 0;
tx_buf[2] = 0;
tx_buf[3] = 0;
spi_write_then_read(spi_flash, tx_buf, 4, rx_buf, 2);
*pMID = rx_buf[0];
*pDID = rx_buf[1];
}
static void SPIFlashWriteEnable(int enable)
{
unsigned char val = enable ? 0x06 : 0x04;
//printk("%s\n",__func__);
spi_write(spi_flash, &val, 1);
}
static unsigned char SPIFlashReadStatusReg1(void)
{
unsigned char val;
unsigned char cmd = 0x05;
//printk("%s\n",__func__);
spi_write_then_read(spi_flash, &cmd, 1, &val, 1);
return val;
}
static unsigned char SPIFlashReadStatusReg2(void)
{
unsigned char val;
unsigned char cmd = 0x35;
//printk("%s\n",__func__);
spi_write_then_read(spi_flash, &cmd, 1, &val, 1);
return val;
}
static void SPIFlashWaitWhenBusy(void)
{
//printk("%s\n",__func__);
while (SPIFlashReadStatusReg1() & 1)
{
/* 休眠一段時間 */
/* Sector erase time : 60ms
* Page program time : 0.7ms
* Write status reg time : 10ms
*/
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 100); /* 休眠10MS後再次判斷 */
}
}
static void SPIFlashWriteStatusReg(unsigned char reg1, unsigned char reg2)
{
unsigned char tx_buf[4];
//printk("%s\n",__func__);
SPIFlashWriteEnable(1);
tx_buf[0] = 0x01;
tx_buf[1] = reg1;
tx_buf[2] = reg2;
spi_write(spi_flash, tx_buf, 3);
SPIFlashWaitWhenBusy();
}
static void SPIFlashClearProtectForStatusReg(void)
{
unsigned char reg1, reg2;
//printk("%s\n",__func__);
reg1 = SPIFlashReadStatusReg1();
reg2 = SPIFlashReadStatusReg2();
reg1 &= ~(1 << 7);
reg2 &= ~(1 << 0);
SPIFlashWriteStatusReg(reg1, reg2);
}
static void SPIFlashClearProtectForData(void)
{
/* cmp=0,bp2,1,0=0b000 */
unsigned char reg1, reg2;
//printk("%s\n",__func__);
reg1 = SPIFlashReadStatusReg1();
reg2 = SPIFlashReadStatusReg2();
reg1 &= ~(7 << 2);
reg2 &= ~(1 << 6);
SPIFlashWriteStatusReg(reg1, reg2);
}
/* erase 4K */
void SPIFlashEraseSector(unsigned int addr)
{
unsigned char tx_buf[4];
//printk("%s\n",__func__);
tx_buf[0] = 0x20;
tx_buf[1] = addr >> 16;
tx_buf[2] = addr >> 8;
tx_buf[3] = addr & 0xff;
SPIFlashWriteEnable(1);
spi_write(spi_flash, tx_buf, 4);
SPIFlashWaitWhenBusy();
}
/* program */
void SPIFlashProgram(unsigned int addr, unsigned char *buf, int len)
{
unsigned char tx_buf[4];
struct spi_transfer t[] =
{
{
.tx_buf = tx_buf,
.len = 4,
},
{
.tx_buf = buf,
.len = len,
},
};
struct spi_message m;
//printk("%s\n",__func__);
tx_buf[0] = 0x02;
tx_buf[1] = addr >> 16;
tx_buf[2] = addr >> 8;
tx_buf[3] = addr & 0xff;
SPIFlashWriteEnable(1);
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
spi_sync(spi_flash, &m);
SPIFlashWaitWhenBusy();
}
void SPIFlashRead(unsigned int addr, unsigned char *buf, int len)
{
/* spi_write_then_read規定了tx_cnt+rx_cnt < 32
* 所以對於大量資料的讀取,不能使用該函式
*/
unsigned char tx_buf[4];
struct spi_transfer t[] =
{
{
.tx_buf = tx_buf,
.len = 4,
},
{
.rx_buf = buf,
.len = len,
},
};
struct spi_message m;
//printk("%s\n",__func__);
tx_buf[0] = 0x03;
tx_buf[1] = addr >> 16;
tx_buf[2] = addr >> 8;
tx_buf[3] = addr & 0xff;
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
spi_sync(spi_flash, &m);
}
static void SPIFlashInit(void)
{
SPIFlashClearProtectForStatusReg();
SPIFlashClearProtectForData();
}
/* 構造註冊一個mtd_info
* mtd_device_register(master, parts, nr_parts)
*
*/
/* 首先: 構造註冊spi_driver
* 然後: 在spi_driver的probe函式裡構造註冊mtd_info
*/
static struct mtd_info spi_flash_dev;
static int spi_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
{
unsigned int addr = instr->addr;
unsigned int len = 0;
//判斷引數
if ((addr & (spi_flash_dev.erasesize - 1)) || (instr->len & (spi_flash_dev.erasesize - 1)))
{
printk("spi_flash_erase addr/len is not aligned %x %x\n",(unsigned int)instr->addr,(unsigned int)instr->len);
return -EINVAL;
}
for (len = 0; len < instr->len; len += 4096)
{
SPIFlashEraseSector(addr);
addr += 4096;
}
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
return 0;
}
static int spi_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
SPIFlashRead(from, buf, len);
*retlen = len;
return 0;
}
static int spi_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
unsigned int addr = to;
unsigned int wlen = 0;
unsigned int i;
//判斷引數
if ((to & (spi_flash_dev.erasesize - 1)))
{
printk("spi_flash_write addr/len is not aligned %x %x\n",(unsigned int)to,(unsigned int)len);
return -EINVAL;
}
if (len <= 256)
{
SPIFlashProgram(addr, (unsigned char *)buf, len);
}
else
{
for (i = 0; i < len / 256; i ++)
{
SPIFlashProgram(addr, (unsigned char *)buf, 256);
addr += 256;
buf += 256;
}
if (len % 256 != 0)
{
SPIFlashProgram(addr, (unsigned char *)buf, len % 256);
}
}
*retlen = len;
return 0;
}
static int spi_flash_probe(struct spi_device *spi)
{
int mid, did, ret;
spi_flash = spi;
spi->mode = SPI_MODE_0;
ret = spi_setup(spi);
if (ret < 0)
{
printk("spi_setup error\n");
}
printk("%s\n",__func__);
//s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);
SPIFlashInit();
SPIFlashReadID(&mid, &did);
printk("SPI Flash ID: %02x %02x\n", mid, did);
memset(&spi_flash_dev, 0, sizeof(spi_flash_dev));
//Setup the MTD structure
spi_flash_dev.name = "spi_flash";
spi_flash_dev.type = MTD_NORFLASH;
spi_flash_dev.flags = MTD_CAP_NORFLASH;
spi_flash_dev.size = 0x800000;
spi_flash_dev.writesize = 1;
spi_flash_dev.writebufsize = 4096;
spi_flash_dev.erasesize = 4096;
spi_flash_dev.owner = THIS_MODULE;
spi_flash_dev._erase = spi_flash_erase;
spi_flash_dev._read = spi_flash_read;
spi_flash_dev._write = spi_flash_write;
mtd_device_register(&spi_flash_dev, NULL, 0);
return 0;
}
static int spi_flash_remove(struct spi_device *spi)
{
mtd_device_unregister(&spi_flash_dev);
return 0;
}
static const struct of_device_id spi_flash_ids[] = {
{ .compatible = "tiny4412,spi_flash" },
{ }
};
static struct spi_driver spi_flash_drv =
{
.driver = {
.name = "spi_flash",
},
.probe = spi_flash_probe,
.remove = spi_flash_remove,
};
static int spi_flash_init(void)
{
printk("init\n");
return spi_register_driver(&spi_flash_drv);
}
static void spi_flash_exit(void)
{
spi_unregister_driver(&spi_flash_drv);
}
module_init(spi_flash_init);
module_exit(spi_flash_exit);
MODULE_LICENSE("GPL");
相關推薦
裝置樹學習之(十)spi flash
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busy
裝置樹學習之(九)SPI設備註冊過程
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busy
裝置樹學習之(十二)LCD驅動
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busy
裝置樹學習之(二)點燈
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busy
裝置樹學習之(七)I2C裝置的註冊過程分析
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busy
裝置樹學習之(一)GPIO中斷
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busybox 1.25目標: 學習裝置樹中GP
裝置樹學習之(十三)電容觸控式螢幕驅動
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:bu
裝置樹學習之(五)watchdog
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busybox 1.25 目標: 學習裝置樹中普通
裝置樹學習之(三)Clock
開發板:tiny4412SDK + S702 + 4GB Flash 要移植的核心版本:Linux-4.4.0 (支援device tree) u-boot版本:友善之臂自帶的 U-Boot 2010.12 busybox版本:busybox 1.25 目標:
Linux裝置樹學習日記(一)裝置樹簡單介紹
一、linux裝置樹簡介1. 裝置樹是一種描述硬體的資料結構,它起源於openfirmware,採用裝置樹後,許多硬體的細節可以直接通過它傳遞給linux,而不需要在核心中進行大量冗餘編碼。2. 裝置樹由一系列被命名的節點(Node)和屬性(property)組成
SQL Server2012 學習之(十) :插入與修改SQL資料
插入資料是資料庫使用中的常用操作,在對資料庫進行操作時,更經常使用的是用T-SQL語句進行資料插入,視覺化介面的操作較少,因此這篇部落格在介紹資料插入的時候側重於使用T-SQL語句進行。其語法格式如下。1.insert……value語句insert value是基本的新增資料
嵌入式核心及驅動開發之學習筆記(十) 非同步通訊+中斷實現讀取資料
對於linux一切都是檔案,驅動裝置在應用層也是以檔案的形式進行讀寫。之前學了阻塞、非阻塞、多路複用的方式讀裝置,它們都需要應用主動讀取。那麼應用層有沒有一種方式,當底層將資料準備好了,應用程式自動處理這些資料?通過非同步通訊可以實現,這有寫類似硬體層的中斷概念 驅動層(準備好了資料) --&g
Redis學習筆記(十)進階之訊息通知
任務佇列 使用LPUSH和RPOP命令操作列表來實現佇列 BLPOP key [key ...] timeout(s) BRPOP key [key ...] timeout(s) BLPOP/BRPOP是阻塞式,同時檢測多個鍵,如果所有鍵都沒有元素則阻塞,如果其中有一個鍵
各種音視訊編解碼學習詳解之 編解碼學習筆記(十):Ogg系列
最近在研究音視訊編解碼這一塊兒,看到@bitbit大神寫的【各種音視訊編解碼學習詳解】這篇文章,非常感謝,佩服的五體投地。奈何大神這邊文章太長,在這裡我把它分解成很多小的篇幅,方便閱讀。大神部落格傳送門:https://www.cnblogs.com/skyofbitbit/p/3651
《機器學習實戰》學習筆記(十)之使用Apriori演算法進行關聯
轉載請註明作者和出處:http://blog.csdn.net/john_bh/ 執行平臺: Windows Python版本: Python3.6 IDE: Sublime text3 背景 一、關聯分析 二、Apriori原理
OpenCV2學習筆記(十):特徵點檢測之Harris法
在計算機視覺中,特徵點的概念被大量用於解決物體識別、影象匹配、視覺跟蹤、三維重建等問題,比如影象中物體的角點,它們是在影象中可被輕易而精確地定位的二維特徵。顧名思義,特徵點檢測的思想是無需觀察整幅影象,而是通過選擇某些特殊點,然後對它們執行區域性分析。如果能檢測
非監督學習之混合高斯模型和EM演算法——Andrew Ng機器學習筆記(十)
0、內容提要 這篇博文主要介紹: - 混合高斯模型(mixture of Gaussians model) - EM演算法(Expectation-Maximization algorithm) 1、引入 假設給定一個訓練集{x(1),...,x(m)
深度學習之(十一)Deep learning中的優化方法:隨機梯度下降、受限的BFGS、共軛梯度法
三種常見優化演算法:SGD(隨機梯度下降),LBFGS(受限的BFGS),CG(共軛梯度法)。 1.SGD(隨機梯度下降) 隨機梯度下降(Stochastic Gradient Descent, SGD)是隨機和優化相結合的產物,是一種很神奇的優化方法,屬於
SQL Server2012 學習之(十六) :觸發器的建立與使用
接上篇部落格的內容,觸發器可以看作是一個特殊的儲存過程。本篇部落格主要關注DML和DDL觸發器對應的使用方法。1.觸發器的定義觸發器的定義如下圖。它與儲存過程的區別在於觸發器是被動呼叫的 ,即在滿足特定事件的情況下被執行,而儲存過程是在使用操作語句時主動進行呼叫。觸發器大致分
J2EE系列之Spring4學習筆記(十)--Spring對JDBC的支援
一、JdbcDaoSupport類的引入 上一節的工程裡面資料庫操作實現類StudentDaoImpl類中要想使用Spring操作資料庫需要首先定義JdbcTemplate類的物件,這一節我們引入Spring對JDBC支援的JdbcDaoSupport類,首先看一下這個類中