CubieBoard博客-HomeCubieTech公司网站

cubie.cc CubieBoard中文论坛

 找回密码
 立即注册
搜索
热搜: unable
查看: 4672|回复: 0

I2C进阶5

[复制链接]

113

主题

1

好友

1万

积分

版主

Rank: 7Rank: 7Rank: 7

贡献
2467
金钱
5721
威望
2467
买家信用
卖家信用
积分
13584
发表于 2014-9-25 11:34:37 |显示全部楼层
在i2c_sunxi_core_process这个函数中,我们发现有很多

error_out → aw_twi_stop(base_addr)终止函数,

msg_null --》i2c_sunxi_xfer_complete(i2c, err_code)调用了s3c24xx_i2c_master_complete这个函数来唤醒传输等待队列中的进程

那么让我们来看看这两个函数

static int aw_twi_stop(void *base_addr)

{

unsigned int timeout = 0xff;

aw_twi_set_stop(base_addr); //设置适配器状态为停止

aw_twi_clear_irq_flag(base_addr); //清中断

aw_twi_get_stop(base_addr);/* it must delay 1 nop to check stop bit */

while(( 1 == aw_twi_get_stop(base_addr))&& (--timeout));

if(timeout == 0) {

i2c_dbg("1.STOP can't sendout!\n");

return AWXX_I2C_FAIL;

}

if (sunxi_is_sun7i())

timeout = 0xffff;

else

timeout = 0xff;

while((TWI_STAT_IDLE != readl(base_addr + TWI_STAT_REG))&&(--timeout));

if(timeout == 0)

{

i2c_dbg("i2c state isn't idle(0xf8)\n");

return AWXX_I2C_FAIL;

}

timeout = 0xff;

while((TWI_LCR_IDLE_STATUS != readl(base_addr + TWI_LCR_REG))&&(--timeout));

if(timeout == 0) {

i2c_dbg("2.STOP can't sendout!\n");

return AWXX_I2C_FAIL;

}

return AWXX_I2C_OK;

}

static int i2c_sunxi_xfer_complete(struct sunxi_i2c *i2c, int code)

{

int ret = AWXX_I2C_OK;

i2c->msg = NULL; //表示没有可传输的消息

i2c->msg_num = 0; //表示没有可传输的消息

i2c->msg_ptr = 0; //下一条消息字符串的首地址置0

i2c->status = I2C_XFER_IDLE;

/* i2c->msg_idx store the information */

if(code == AWXX_I2C_FAIL) {

i2c_dbg("Maybe Logic Error,debug it!\n");

i2c->msg_idx = code;

ret = AWXX_I2C_FAIL;

}

else if(code != AWXX_I2C_OK) {

//return the ERROR code, for debug or detect error type

i2c->msg_idx = code; //记录已经传输完的信息个数

ret = AWXX_I2C_FAIL;

}

wake_up(&i2c->wait); //唤醒等待队列中的进程

return ret;

}

此为止,我们已经完成了在I2C总线驱动层填充了i2c_adapter和i2c_algorithm结构体,剩下来我们需要把这两个结构体外包一下,来注册这个适配器,这怎么实现呢?当然我们在上面已经分析了中断处理函数i2c_sunxi_handler,那么这个函数什么时候被注册的呢?带着这两个问题我们需要继续往下走,go
恩恩,有一定平台驱动基础的朋友应该就明白了,平台驱动的这个探测函数i2c_sunxi_probe应该就完成了整个适配器的注册和中断处理函数的注册工作了。别发呆了,那我们就来看看这个si2c_sunxi_probe函数吧。

static int i2c_sunxi_probe(struct platform_device *dev)

{

struct sunxi_i2c *i2c = NULL; //适配器指针

struct resource *res = NULL;    //指向资源

struct sunxi_i2c_platform_data *pdata = NULL; //平台数据

char *i2c_clk[] ={"twi0","twi1","twi2"};

char *i2c_pclk[] ={"apb_twi0","apb_twi1","apb_twi2"};

int ret;

int irq;

pdata = dev->dev.platform_data; //获取平台数据

if(pdata == NULL) {

return -ENODEV;

}

res = platform_get_resource(dev, IORESOURCE_MEM, 0);

irq = platform_get_irq(dev, 0);

if (res == NULL || irq < 0) {

return -ENODEV;

}

if (!request_mem_region(res->start, resource_size(res), res->name)) {

return -ENOMEM;

}

i2c = kzalloc(sizeof(struct sunxi_i2c), GFP_KERNEL); //分配适配器空间

if (!i2c) {

ret = -ENOMEM;

goto emalloc;

}

//给适配器赋予名字sunxi-i2c,这个名字会由cat /sys/class/i2c_dev/0/name看到。

strlcpy(i2c->adap.name, "sunxi-i2c", sizeof(i2c->adap.name));

i2c->adap.owner = THIS_MODULE;

i2c->adap.nr = pdata->bus_num;

i2c->adap.retries = 2; //两次总线仲裁尝试

i2c->adap.timeout = 5*HZ;

i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;

i2c->bus_freq = pdata->frequency;

i2c->irq = irq;

i2c->bus_num = pdata->bus_num;

i2c->status = I2C_XFER_IDLE;

i2c->suspend_flag = 0;

spin_lock_init(&i2c->lock);

init_waitqueue_head(&i2c->wait);

i2c->pclk = clk_get(NULL, i2c_pclk[i2c->adap.nr]);

if(NULL == i2c->pclk){

i2c_dbg("request apb_i2c clock failed\n");

ret = -EIO;

goto eremap;

}

i2c->clk = clk_get(NULL, i2c_clk[i2c->adap.nr]);

if(NULL == i2c->clk){

i2c_dbg("request i2c clock failed\n");

clk_put(i2c->pclk);

ret = -EIO;

goto eremap;

}

snprintf(i2c->adap.name, sizeof(i2c->adap.name),\

"sunxi-i2c.%u", i2c->adap.nr);

i2c->base_addr = ioremap(res->start, resource_size(res));

if (!i2c->base_addr) {

ret = -EIO;

goto eremap;

}

#ifndef SYS_I2C_PIN

gpio_addr = ioremap(_PIO_BASE_ADDRESS, 0x1000);

if(!gpio_addr) {

ret = -EIO;

goto ereqirq;

}

#endif

i2c->adap.algo = &i2c_sunxi_algorithm;

ret = request_irq(irq, i2c_sunxi_handler, IRQF_DISABLED, i2c->adap.name, i2c);

if (ret)

{

goto ereqirq;

}

if(-1 == i2c_sunxi_hw_init(i2c)){

ret = -EIO;

goto eadapt;

}

i2c->adap.algo_data = i2c;

i2c->adap.dev.parent = &dev->dev;

i2c->iobase = res->start;

i2c->iosize = resource_size(res);

ret = i2c_add_numbered_adapter(&i2c->adap);

if (ret < 0) {

i2c_dbg(KERN_INFO "I2C: Failed to add bus\n");

goto eadapt;

}

platform_set_drvdata(dev, i2c);

i2c_dbg(KERN_INFO "I2C: %s: AW16XX I2C adapter\n",

dev_name(&i2c->adap.dev));

return 0;

eadapt:

free_irq(irq, i2c);

clk_disable(i2c->clk);

ereqirq:

#ifndef SYS_I2C_PIN

if(gpio_addr){

iounmap(gpio_addr);

}

#endif

iounmap(i2c->base_addr);

clk_put(i2c->clk);

eremap:

kfree(i2c);

emalloc:

release_mem_region(i2c->iobase, i2c->iosize);

return ret;

}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

QQ|Archiver|手机版|邮件群发|cubie.cc---深刻的嵌入式技术和应用讨论中文社区 ( 粤ICP备13051116号-1  

GMT+8, 2019-10-24 00:48 , Processed in 0.021852 second(s), 8 queries , Apc On.

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc. | Style by Coxxs

回顶部