Linux i2c probe

probe时用到的一些通用的结构和函数
struct resource 结构体可能包含以下字段:

    resource_size_t start:资源的起始地址或起始中断号。
    resource_size_t end:资源的结束地址或结束中断号。
    const char *name:资源的名称或描述。
    unsigned long flags:资源的标志位,用于指示资源的类型和属性。
    struct resource *parent:父资源的指针,用于表示资源的层次结构关系

该结构在platfrom中定义,龙芯1B的i2c0定义如下
static struct resource ls1x_i2c_resource[] = {
	[0]={
		.start  = LS1X_BOARD_I2C_BASE,
		.end    = (LS1X_BOARD_I2C_BASE + 0x4),
		.flags  = IORESOURCE_MEM,
	},
};
platform_get_resource() 函数的原型如下:
struct resource *platform_get_resource(struct platform_device *pdev, unsigned int type, unsigned int num);

该函数接受三个参数:

  • pdev:指向 struct platform_device 结构体的指针,表示要获取资源的平台设备。
  • type:资源的类型,通常是 IORESOURCE_MEMIORESOURCE_IO,分别表示内存资源和IO端口资源。
  • num:资源的索引号,用于标识同类型的多个资源中的一个。

 

request_mem_region函数是Linux内核中的一个函数,用于请求一块物理内存区域的资源。它的原型定义在include/linux/ioport.h头文件中,具体如下:

unsigned long request_mem_region(resource_size_t start, resource_size_t len, const char *name);

参数:

  • start:要请求的物理内存区域的起始地址。
  • len:要请求的物理内存区域的长度。
  • name:描述请求的内存区域的字符串。

返回值:

  • 成功:返回0。
  • 失败:返回一个负数,表示错误代码。
platform_set_drvdata是一个Linux内核函数,用于将私有数据(driver data)与平台设备相关联。它的原型定义在include/linux/platform_device.h头文件中,具体如下:

void platform_set_drvdata(struct platform_device *pdev, void *data);

参数:

  • pdev:指向平台设备结构体(struct platform_device)的指针。
  • data:要与平台设备相关联的私有数据。
i2c_set_adapdata是一个Linux内核函数,用于设置I2C适配器的私有数据。它的原型定义在include/linux/i2c.h头文件中,具体如下:

void i2c_set_adapdata(struct i2c_adapter *adap, void *data);

参数:

  • adap:指向要设置私有数据的i2c_adapter结构体的指针。
  • data:要设置的私有数据。

 

i2c_add_numbered_adapter是一个Linux内核函数,用于向系统中添加一个已编号的I2C适配器。它的原型定义在include/linux/i2c.h头文件中,具体如下:

struct i2c_adapter *i2c_add_numbered_adapter(struct i2c_adapter *adapter);

参数:

  • adapter:指向要添加的I2C适配器的i2c_adapter结构体的指针。

返回值:

  • 成功:返回新添加的I2C适配器的指针。
  • 失败:返回NULL。
龙芯1B  I2C实现
static int
ls1x_i2c_probe(struct platform_device *pdev)
{
	int result = 0;
	struct ls1x_i2c *i2c;
	printk("in the ls1x_i2c_probe!!\n");
	struct resource *res, *ioarea;  
	
	res =  platform_get_resource(pdev,	IORESOURCE_MEM, 0);  //获取平台或设备树资源
	if (!res) {
		dev_err(&pdev->dev, "no mem resource?\n");
		return -ENODEV;
	}
	
	ioarea = request_mem_region(res->start, resource_size(res), pdev->name);//为设备请求一块物理内存区域的资源
	if (!ioarea) {
		dev_err(&pdev->dev, "I2C region already claimed\n");
		return -EBUSY;
	}

//使用内核内存分配器进行分配 i2c结构内存
	if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) {
		return -ENOMEM;
	}


	init_waitqueue_head(&i2c->queue);//初始化等待队列头

	i2c->base = ioremap(res->start, res->end - res->start + 1);//物理内存映射到虚拟内存空间
	if (!i2c->base) {
		printk(KERN_ERR "i2c-ls1x - failed to map controller\n");
		result = -ENOMEM;
		goto fail_map;
	}
 
/*	if (i2c->irq != 0)
		if ((result = request_irq(i2c->irq, ls1x_i2c_isr,
					IRQF_SHARED, "i2c-ls1x",i2c)) < 0) {
			printk(KERN_ERR
				"i2c-ls1x - failed to attach interrupt\n");
			printk("i2c-ls1x - failed to attach interrupt\n");
			goto fail_irq;
		}*/

	platform_set_drvdata(pdev, i2c);//用于将私有数据(driver data)与平台设备相关联

	i2c->adap = ls1x_ops;//初始化adap成员
	i2c_set_adapdata(&i2c->adap, i2c);//设置I2C适配器的私有数据。
	i2c->adap.algo_data = i2c;
	i2c->adap.dev.parent = &pdev->dev;
//set fre 
	i2c_writeb(i2c, REG_I2C_PRER_LO, 0x64);//设置总线频率
	i2c_writeb(i2c, REG_I2C_PRER_HI, 0x0);
	i2c_writeb(i2c, REG_I2C_CTR, 0x80);//设置正常工作模式


    result = i2c_add_numbered_adapter(&i2c->adap);//向系统中添加一个已编号的I2C适配器
		if (result < 0) {
		printk( "i2c-ls1x - failed to add adapter\n");
		goto fail_add;
	}
	return result;

fail_irq:
fail_get_irq:
		if (i2c->irq != 0)
			free_irq(i2c->irq, NULL);
fail_map:
		iounmap(i2c->base);
		release_mem_region(res->start, resource_size(res));
fail_add:
		kfree(i2c);

	return result;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值