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_MEM
或IORESOURCE_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;
}