研究过S3C6410 SPI驱动的大虾请进!!烦恼啊!

tgvlcw 2010-06-07 04:19:01
自己写的一个A/D转换的驱动,使用SPI进行通信,代码已经写好了,但是读不出数据啊!其中主要看mcpdrv_probe与mcp_read函数,是我初始化得不对吗?还是什么,使用中断也不行,根本就不能中断,用示波器测时钟引脚,没有时钟输出,请大虾们进来探讨一下啊!


void spi_set_cs0(int value)
{
volatile unsigned int reg;
switch (value) {
//Select
case 0:
reg = ioread32(spi_addr0 + S3C_SLAVE_SEL);
reg &= ~(SPI_SLAVE_SIG_INACT);
iowrite32(reg, spi_addr0 + S3C_SLAVE_SEL);
udelay(30);
break;
//Non-Select
case 1:
reg = ioread32(spi_addr0 + S3C_SLAVE_SEL);
reg |= SPI_SLAVE_SIG_INACT;
iowrite32(reg, spi_addr0 + S3C_SLAVE_SEL);
udelay(30);
break;
}
}

void spi_init0(void)
{
volatile unsigned int reg, mode;
volatile unsigned int spi_chcfg;
volatile unsigned int gpc_tmp;

s3c_gpio_cfgpin(S3C64XX_GPC(0), S3C64XX_GPC0_SPI_MISO0);
s3c_gpio_cfgpin(S3C64XX_GPC(1), S3C64XX_GPC1_SPI_CLK0);
s3c_gpio_cfgpin(S3C64XX_GPC(2), S3C64XX_GPC2_SPI_MOSI0);
s3c_gpio_cfgpin(S3C64XX_GPC(3), S3C64XX_GPC3_SPI_nCS0);

s3c_gpio_setpull(S3C64XX_GPC(0), S3C_GPIO_PULL_NONE);
s3c_gpio_setpull(S3C64XX_GPC(1), S3C_GPIO_PULL_NONE);
s3c_gpio_setpull(S3C64XX_GPC(2), S3C_GPIO_PULL_NONE);
s3c_gpio_setpull(S3C64XX_GPC(3), S3C_GPIO_PULL_NONE);

//set GPC
gpc_tmp = ioread32(gpc_addr + 0x0);
printk("gpc_tmp = 0x%x\n", gpc_tmp);
gpc_tmp = ioread32(gpc_addr + 0x8);
printk("gpc_tmp = 0x%x\n", gpc_tmp);
iowrite32(0xf, gpc_addr + 0x4);
udelay(100);
gpc_tmp = ioread32(gpc_addr + 0x4);
printk("gpc_tmp = 0x%x\n", gpc_tmp);

//s3c6410 SPI reset
iowrite32(ioread32(spi_addr0 + S3C_CH_CFG) | SPI_CH_SW_RST, \
spi_addr0 + S3C_CH_CFG);
udelay(100);
iowrite32(ioread32(spi_addr0 + S3C_CH_CFG) & (~SPI_CH_SW_RST), \
spi_addr0 + S3C_CH_CFG);
udelay(100);

//Set transfer type
//spi_chcfg &= ~SPI_CH_HSPD_EN;
//spi_chcfg &= (~SPI_CH_HSPD_EN) | (SPI_CH_FORMAT_A | SPI_CH_RISING | SPI_CH_MASTER);
//spi_chcfg |= SPI_CH_FORMAT_A | SPI_CH_RISING | SPI_CH_MASTER;
//iowrite32(spi_chcfg, spi_addr0 + S3C_CH_CFG);
iowrite32((1 << 3)|(1 << 2)|(0 << 6), spi_addr0 + S3C_CH_CFG);
udelay(100);

//clock config
iowrite32((ioread32(S3C_PCLK_GATE) | S3C_CLKCON_PCLK_SPI0 | \
S3C_CLKCON_PCLK_SPI1), S3C_PCLK_GATE);
iowrite32((ioread32(S3C_SCLK_GATE) | S3C_CLKCON_SCLK_SPI0 | \
S3C_CLKCON_SCLK_SPI1), S3C_SCLK_GATE);

iowrite32(ioread32(S3C_CLK_SRC) | S3C_CLKSRC_MPLL_CLKSEL, S3C_CLK_SRC);
//Set spi clock to DOUT(266Mhz)
iowrite32((ioread32(S3C_CLK_SRC) & ~(0X3 << 14)) | (0x1 << 14), \
S3C_CLK_SRC);

//SPI Input Clock(88.87Mhz) = 266.66Mhz / (2 + 1)
iowrite32(((ioread32(S3C_CLK_DIV2) & ~(0XFF << 0)) | 5), S3C_CLK_DIV2);
iowrite32(ioread32(spi_addr0 + S3C_CLK_CFG) & (~SPI_ENCLK_ENABLE), \
spi_addr0 + S3C_CLK_CFG);
udelay(100);
reg = ioread32(spi_addr0 + S3C_CLK_CFG);
reg |= (0x2 << 9)|(35 << 0);
//iowrite32(reg | (0X2 << 9) | (35 << 0), spi_addr0 + S3C_CLK_CFG);
udelay(100);
iowrite32(SPI_ENCLK_ENABLE, spi_addr0 + S3C_CLK_CFG);
udelay(100);
spi_chcfg = ioread32(spi_addr0 + S3C_CLK_CFG);
printk("spi_clkcfg = 0x%x\n", spi_chcfg);

//Mode cfg
mode = SPI_MODE_CH_TSZ_BYTE | SPI_MODE_BUS_TSZ_BYTE;
//mode |= (SPI_MODE_RXDMA_OFF | SPI_MODE_TXDMA_OFF | 0x1 << 11);
mode |= (SPI_MODE_RXDMA_OFF | SPI_MODE_TXDMA_OFF);
iowrite32(mode, spi_addr0 + S3C_MODE_CFG);
udelay(100);
mode = ioread32(spi_addr0 + S3C_MODE_CFG);
printk("mode = 0x%x\n", mode);


// disable SPI Interrupt
iowrite32(SPI_INT_ALL_DISABLE, spi_addr0 + S3C_SPI_INT_EN);


//Slave_sel cfg
iowrite32(0x0, spi_addr0 + S3C_SLAVE_SEL);

}



...全文
1232 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
wdl1127 2011-09-03
  • 打赏
  • 举报
回复
请问版主一个弱智问题,你代码里面的spi_addr0 、spi_gpc的值是多少?
qllaoda 2011-02-09
  • 打赏
  • 举报
回复
我认为最好先写SPI总线驱动,然后再写基于SPI的设备驱动,这样比较符合Linux的驱动架构
springdia 2010-08-28
  • 打赏
  • 举报
回复
楼主找到问题了没?我也遇到相同的问题了。
tgvlcw 2010-06-07
  • 打赏
  • 举报
回复
信号极性的都在代码里设置了,请看spi_init0函数,使用的是模式1,芯片的也是一样,芯片在5V下时钟速率可达到3.2M,在2.7V下最低为1.2M,给芯片提供的电压为3.3V,所以使用spi控制器,对时钟原分频后算得的速率大概为1点几M,这些都是次要得的,关键是使用spi控制器使能时钟后,从芯片SCLK引脚上看不到波形,头都大了,网上也找不到相关的资料
l2y3n2 2010-06-07
  • 打赏
  • 举报
回复
直接用SPI控制器的话,信号极性什么的设置的正确吗?

楼主手动拉GPIO读取的频率是280ns,4M不到的码率,使用SPI芯片设置的速度是多少?
如果可以最好用示波器看下手动控制和用芯片时输出的波形是否一致。
tgvlcw 2010-06-07
  • 打赏
  • 举报
回复
mcp_read中使用两种方法读取数据,前一个#if 0到#endif用的是gpc口的spi功能;后一个是直接使用GPC口模拟的spi功能,模拟的比较简单,能够读出数据,就是前一种使用芯片提供的SPI功能读不出数据
tgvlcw 2010-06-07
  • 打赏
  • 举报
回复

void spi_start0(void)
{
volatile unsigned int tmp;

tmp = ioread32(spi_addr0 + S3C_CH_CFG);
tmp |= 0x3;
iowrite32(tmp, spi_addr0 + S3C_CH_CFG);
}

static unsigned short mcp3002_read_data(unsigned short cmd)
{
int i;
unsigned short tmp;
unsigned short data = 0;

tmp = cmd;

gpio_set_value(S3C64XX_GPC(3), 1);
gpio_set_value(S3C64XX_GPC(1), 0);
udelay(50);
gpio_set_value(S3C64XX_GPC(3), 0);
udelay(50);

for (i = 15; i >= 0; i--) {
gpio_set_value(S3C64XX_GPC(1), 0);

if (i > 10) {
if ((tmp >> i) & 0x01)
gpio_set_value(S3C64XX_GPC(2), 1);
else
gpio_set_value(S3C64XX_GPC(2), 0);
} else {
if (gpio_get_value(S3C64XX_GPC(0)))
data |= 1 << i;
}
ndelay(140);

gpio_set_value(S3C64XX_GPC(1), 1);
ndelay(140);
}

return data;
}

static ssize_t mcp_read(struct file *filp, char __user *buf, \
size_t count, loff_t *f_pos)
{
unsigned short cmd = 0;
unsigned short value[3];

#if 0
unsigned int spi_int;

//spi_int = SPI_INT_RX_FIFORDY_EN | SPI_INT_RX_UNDERRUN_EN | SPI_INT_RX_OVERRUN_EN | SPI_INT_TRAILING_EN;
//iowrite32(spi_int, spi_addr0 + S3C_SPI_INT_EN);
mdelay(1);
spi_start0();
spi_set_cs0(1);
udelay(140);
spi_set_cs0(0);
udelay(140);

cmd = ((1 << 6) | (1 << 5) | (0 << 4) | (1 << 3));
iowrite8(cmd, spi_addr0 + S3C_SPI_TX_DATA);
//wait_for_completion(&rx_done);
udelay(50);
value[0] = ioread8(spi_addr0 + S3C_SPI_RX_DATA);
spi_set_cs0(1);
spi_stop0();
printk(DEVICE_NAME " value[0] = 0x%x\n", rx);
#endif

#if 1
//芯片的设置请查看mcp3002第13页, 15页
cmd = ((1 << 14) | (1 << 13) | (0 << 12) | (0 << 11));
value[0] = mcp3002_read_data(cmd);
//printk(DEVICE_NAME " value[0] = 0x%x\n", value[0]);
#endif

if (copy_to_user(buf, &value[0], 2)) {
return -EFAULT;
}

return count;
}

static ssize_t mcp_write(struct file *filp, const char __user *buf, \
size_t count, loff_t *f_pos)
{

return count;
}

static int mcp_open(struct inode *inode, struct file *filp)
{
printk("mcp is opened\n");
try_module_get(THIS_MODULE);
return 0;
}

static int mcp_release(struct inode *inode, struct file *filp)
{
printk("mcp is closed\n");
module_put(THIS_MODULE);
return 0;
}

static struct file_operations mcp_fops = {
.owner = THIS_MODULE,
.open = mcp_open,
.release = mcp_release,
.write = mcp_write,
.read = mcp_read,
};

static irqreturn_t mcp_spi_irq(int irq, void *dev)
{
int err = 0;
unsigned int pend = ioread32(spi_addr0 + S3C_SPI_STATUS);

printk("===mcp irq: %d===\n", irq);
printk("pend = 0x%x\n", pend);
iowrite32(SPI_INT_ALL_DISABLE, spi_addr0 + S3C_SPI_INT_EN);

if(pend & SPI_STUS_RX_OVERRUN_ERR)
{
printk(DEVICE_NAME " RX FIFO overrun error\n");
iowrite32(SPI_PND_RX_OVERRUN_CLR, spi_addr0 + S3C_PENDING_CLR);
err = 1;
}

if(pend & SPI_STUS_RX_UNDERRUN_ERR)
{
printk(DEVICE_NAME " RX FIFO underrun error\n");
iowrite32(SPI_PND_RX_UNDERRUN_CLR, spi_addr0 + S3C_PENDING_CLR);
err = 1;
}

if(pend & SPI_STUS_TX_OVERRUN_ERR)
{
printk(DEVICE_NAME " TX FIFO overrun error\n");
iowrite32(SPI_PND_TX_OVERRUN_CLR, spi_addr0 + S3C_PENDING_CLR);
err = 1;
}

if(pend & SPI_STUS_TX_UNDERRUN_ERR)
{
printk(DEVICE_NAME " TX FIFO underrun error\n");
iowrite32(SPI_PND_TX_UNDERRUN_CLR, spi_addr0 + S3C_PENDING_CLR);
err = 1;
}

if(pend & SPI_STUS_TX_FIFORDY)
{
printk(DEVICE_NAME " TX FIFO ready\n");
}

if(pend & SPI_STUS_RX_FIFORDY)
{
printk(DEVICE_NAME " RX FIFO ready\n");
}

if(err)
{
printk("====s3c_spi_irq error===\n");
complete(&rx_done);
return IRQ_HANDLED;
}

if (pend & SPI_STUS_RX_FIFOLVL) {
rx = ioread8(spi_addr0 + S3C_SPI_RX_DATA);
complete(&rx_done);
return IRQ_HANDLED;
}

complete(&rx_done);
return IRQ_HANDLED;
}

static void spi_gpio_init(void)
{
//init mcp interface
//gpio_direction_input(S3C64XX_GPC(0));
//gpio_direction_output(S3C64XX_GPC(1), 1);
//gpio_direction_output(S3C64XX_GPC(2), 1);
//gpio_direction_output(S3C64XX_GPC(3), 1);
s3c_gpio_cfgpin(S3C64XX_GPC(0), S3C_GPIO_INPUT);
s3c_gpio_cfgpin(S3C64XX_GPC(1), S3C_GPIO_OUTPUT);
s3c_gpio_cfgpin(S3C64XX_GPC(2), S3C_GPIO_OUTPUT);
s3c_gpio_cfgpin(S3C64XX_GPC(3), S3C_GPIO_OUTPUT);

s3c_gpio_setpull(S3C64XX_GPC(0), S3C_GPIO_PULL_NONE);
s3c_gpio_setpull(S3C64XX_GPC(1), S3C_GPIO_PULL_NONE);
s3c_gpio_setpull(S3C64XX_GPC(2), S3C_GPIO_PULL_NONE);
s3c_gpio_setpull(S3C64XX_GPC(3), S3C_GPIO_PULL_NONE);

}

static int mcp_probe(struct platform_device *dev)
{
int ret;

ret = register_chrdev(SPI_MAJOR, DEVICE_NAME, &mcp_fops);
if (ret < 0)
return ret;

if (!request_mem_region(GPC_PHYS_ADDR, 0x20, DEVICE_NAME)) {
printk(KERN_ERR "mcp:IO %X is not free\n", GPC_PHYS_ADDR);
return -EBUSY;
}

if (!request_mem_region(SPI0_PHYS_ADDR, 0xff, DEVICE_NAME)) {
printk(KERN_ERR "mcp:IO %X is not free\n", SPI0_PHYS_ADDR);
return -EBUSY;
}

gpc_addr = ioremap(GPC_PHYS_ADDR, 0x20);
if (gpc_addr < 0) {
printk(KERN_ERR "mcp: ioremap failed\n");
iounmap(gpc_addr);
return -EINVAL;
}

spi_addr0 = ioremap(SPI0_PHYS_ADDR, 0xff);
if (spi_addr0 < 0) {
printk(KERN_ERR "mcp: ioremap failed\n");
iounmap(spi_addr0);
return -EINVAL;
}

/*
err = request_irq(IRQ_SPI0, mcp_spi_irq, IRQF_DISABLED, \
DEVICE_NAME, NULL);
if (err) {
printk(DEVICE_NAME " cannot request irq\n");
return -1;
}
//init_completion(&rx_done);
*/
spi_init0();
//spi_gpio_init();

return 0;
}

21,619

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧