微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 手机设计讨论 > MTK手机平台交流 > How to use the SPI interface for a slave device

How to use the SPI interface for a slave device

时间:10-02 整理:3721RD 点击:

目前我司MT6572、MT6582、MT6589、MT6592平台的SPI接口是默认打开的,即直接支持使用。一般分
为两路:一路是供PMIC专用,另一路可以用作外设通信使用(这一点请注意),例如72平台
GPIO97~GPIO100,89上GPIO134~GPIO137, 82上GPIO80~GPIO83。使用SPI接口的sample code 如下
,其中传输数据以FIFO mode 为例,大数据量可以考虑使用DMA mode。
主要调用到SPI核心code路径如下:
linux core:
alps\kernel\driver\spi\
mtk:
alps\mediatek\platform\mt65xx\kernel\drivers\spi\
Porting Guide:
moduleInit:
ret = spi_register_board_info(spi_board_devs, ARRAY_SIZE(spi_board_devs));
……
ret = spi_register_driver(&xxxx_spi_driver);
……
Probe:
static int __devinit xxxx_spi_probe(struct spi_device *spi)里,
xxxx_set_spi_mode(1);
……
xxxx_spi_CLIent = spi;
xxxx_spi_client->bits_per_word = 8; // 0 表示默认 8bit per word
xxxx_spi_client->mode = SPI_MODE_0; //决定极性、相位。即采样、输出是在前沿还是后沿,是
上升沿还是下降沿
if(xxxx_spi_client)
{
xxxx_spi_client->controller_data = (void*)&spi_conf;
spi_par =&spi_conf;
if(!spi_par){
printk("spi config fail");
return 0;
}
spi_par->setuptime =15;
spi_par->holdtime = 15;
spi_par->high_time = 10; // 与low_time 共同决定着SPI CLK 的周期
spi_par->low_time = 10;
spi_par->cs_idletime = 20;
spi_par->rx_mlsb = 1;
spi_par->tx_mlsb = 1; //mlsb=1 表示高bit位先传,通常不需要改
spi_par->tx_endian = 0; //tx_endian =1 表示大端模式,对于DMA模式,需要根据设备的Spec 来
选择,通常为大端。
spi_par->rx_endian = 0;
spi_par->cpol = 0; // 这里不需要再设置, xxxx_spi_client->mode = SPI_MODE_0 这里设置即

spi_par->cpha = 0; // 这里不需要再设置, xxxx_spi_client->mode = SPI_MODE_0 这里设置即

//spi_par->com_mod = DMA_TRANSFER;// DMA or FIFO
spi_par->com_mod = FIFO_TRANSFER;
spi_par->pause = 0; //与 deassert 的意思相反。即是否支持暂停模式,如此做SPI_CS在多次
transfer之间 不会被de-active
spi_par->finish_intr = 1;
//spi_par->deassert = 0;
spi_par->ulthigh = 0;
spi_par->tckdly = 0;
printk("setuptime=%d \n",spi_conf.setuptime);
if(spi_setup(xxxx_spi_client)){
printk("spi_setup fail");
return 0;
}
}
else
{
printk("spi config fail");
}
TX_BUF = kzalloc(2, GFP_KERNEL);
RX_BUF = kzalloc(0x400, GFP_KERNEL);
return 0;
spi的mode setting是有缺省值的,详见spi.c 的mt_spi_setup(JB版本) ,或 MT6575_spi.c 的
mt6575_spi_setup(ICS2版)
path : mediatek\platform\mt65xx\kernel\driver\spi\
SPI System clock Peroid: 75,77平台 7.519ns , 89平台round 10 ns
Write\Read :
static int xxxx_spi_write_cmd(struct spi_device *spi,
unsigned char reg_addr, unsigned char write_val)
{
int error;
u8 rx[32] = {0};
TX_BUF[0] = reg_addr;
TX_BUF[1] = write_val;
struct spi_message m;
tr[0].tx_buf = TX_BUF;
tr[0].rx_buf = rx;
tr[0].len = 2;
//tr[0].tx_dma = 0;
//tr[0].rx_dma = 0;
tr[0].bits_per_word = 0;
spi_message_init(&m);
spi_message_add_tail(&tr[0], &m);
error = spi_sync(spi, &m);
if (error)
printk("spi_sync failed.\n");
printk("wrote %X to register %X\n", write_val, reg_addr);
return error;
}
static int xxxx_spi_read_data(struct spi_device *spi,unsigned char *read_buf,int len)
{
int error;
u8 tx[32] = {0};
struct spi_message m;
tr[1].tx_buf = tx;
tr[1].rx_buf = read_buf;
tr[1].len = len; // if >= 32 byte ,循环读取,FIFO模式只支持一次32byte
//tr[1].tx_dma = 0;
//tr[1].rx_dma = 0;
//tr[1].bits_per_word = 0;
spi_message_init(&m);
spi_message_add_tail(&tr[1], &m);
error = spi_sync(spi, &m);
if (error)
printk("spi_sync failed.\n");
printk("read data after write register \n");
return error;
}
相关定义如下:
unsigned char *RX_BUF = NULL;
unsigned char *TX_BUF = NULL;
struct spi_transfer tr[2];
static struct spi_device *xxxx_spi_client;
static struct mt_chip_conf spi_conf;
static struct spi_board_info spi_board_devs[] __initdata = {
[0] = {
.modalias="xxxx",//"spidev"
.bus_num = 0,
.chip_select=0,
.mode = SPI_MODE_0,
},
};
static struct spi_driver xxxx_spi_driver = {
.driver = {
.name = ="xxxx",
.owner = THIS_MODULE,
},
.probe = xxxx_spi_probe,
.remove = __devexit_p(xxxx_spi_remove),
};
static void xxxx_set_spi_mode(int enable) //如果不需要上拉,可以不用mt_set_gpio_pull_函

{
if(enable)
{
mt_set_gpio_mode(GPIO_SPI_CS_PIN, GPIO_SPI_CS_PIN_M_SPI_CS_N);
mt_set_gpio_pull_enable(GPIO_SPI_CS_PIN, GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_SPI_CS_PIN, GPIO_PULL_UP);
mt_set_gpio_mode(GPIO_SPI_SCK_PIN, GPIO_SPI_SCK_PIN_M_SPI_SCK);
mt_set_gpio_pull_enable(GPIO_SPI_SCK_PIN, GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_SPI_SCK_PIN, GPIO_PULL_DOWN);
mt_set_gpio_mode(GPIO_SPI_MISO_PIN, GPIO_SPI_MISO_PIN_M_SPI_MISO);
mt_set_gpio_pull_enable(GPIO_SPI_MISO_PIN, GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_SPI_MISO_PIN, GPIO_PULL_DOWN);
mt_set_gpio_mode(GPIO_SPI_MOSI_PIN, GPIO_SPI_MOSI_PIN_M_SPI_MOSI);
mt_set_gpio_pull_enable(GPIO_SPI_MOSI_PIN, GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_SPI_MOSI_PIN, GPIO_PULL_DOWN);
}
else
{
mt_set_gpio_mode(GPIO_SPI_CS_PIN, GPIO_SPI_CS_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_SPI_CS_PIN, GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_SPI_CS_PIN, GPIO_PULL_DISABLE);
mt_set_gpio_mode(GPIO_SPI_SCK_PIN, GPIO_SPI_SCK_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_SPI_SCK_PIN, GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_SPI_SCK_PIN, GPIO_PULL_DISABLE);
mt_set_gpio_mode(GPIO_SPI_MISO_PIN, GPIO_SPI_MISO_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_SPI_MISO_PIN, GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_SPI_MISO_PIN, GPIO_PULL_DISABLE);
mt_set_gpio_mode(GPIO_SPI_MOSI_PIN, GPIO_SPI_MOSI_PIN_M_GPIO);
mt_set_gpio_dir(GPIO_SPI_MOSI_PIN, GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_SPI_MOSI_PIN, GPIO_PULL_DISABLE);
}
return;
}
DMA传输可以参考我司CMMB的部分code,这里不再赘述
.alps\mediatek\platform\mt65xx\kernel\drivers\cmmbdrv\
相关结构体说明可参考我司release的一份文档:SPI_Customer_Document_MT65xx.docx 以及查看
datasheet。

請問一下,在MTK的板子上可以透過device tree的方法來取代spi_register_board_info嗎?
小的我在device tree上的SPI1中加了slave device,但是在呼叫spi_register_driver時,都不會work,跪求高手協助,感謝。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top