1. 程式人生 > >裝置樹學習之(十)spi flash

裝置樹學習之(十)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類,首先看一下這個類中