网上的I2C驱动讲解已经很多啦,我不想画蛇添足,我想写一个完整的I2C驱动,包括系统启动,总线注册,驱动注册,设备注册,里面会贯穿Linux设备驱动模型,platform机制等等,基于高通MSM 8x60,I2C控制器为qup,下面开始进入正题:
首先是平台设备的注册:源码位置:(msm/arch/arm/mach-msm/devices-msm8x60.c)
首先说下平台设备,因为Linux所有的设备都是通过总线控制器连接到CPU的,但是还有一些设备不是通过总线控制器连接到CPU,所以就有了platform总线虚拟总线,把那些不是真正通过总线控制器相连的设备,比如:SOC的片内设备,片内控制器,这些都归为平台设备.把这些平台设备通过虚拟总线连接到cpu上,以便维护Linux设备模型中的,总线,设备,驱动之间的关系。
首先注册BSP的平台设备驱动,其中I2C控制器的平台设备如下:
先看下高通的8x60,靠,有6个控制器,所有接下来的事情就是淡定。
下面的是6个控制器在I2C控制器的ID编号
#define MSM_GSBI3_QUP_I2C_BUS_ID 0
#define MSM_GSBI4_QUP_I2C_BUS_ID 1
#define MSM_GSBI9_QUP_I2C_BUS_ID 2
#define MSM_GSBI8_QUP_I2C_BUS_ID 3
#define MSM_GSBI7_QUP_I2C_BUS_ID 4
#define MSM_GSBI12_QUP_I2C_BUS_ID 5
下面是六个控制器所用到的资源
static struct resource gsbi3_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
.start = MSM_GSBI3_QUP_PHYS,
.end = MSM_GSBI3_QUP_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "gsbi_qup_i2c_addr",
.start = MSM_GSBI3_PHYS,
.end = MSM_GSBI3_PHYS + 4 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "qup_err_intr",
.start = GSBI3_QUP_IRQ,
.end = GSBI3_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct resource gsbi4_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
.start = MSM_GSBI4_QUP_PHYS,
.end = MSM_GSBI4_QUP_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "gsbi_qup_i2c_addr",
.start = MSM_GSBI4_PHYS,
.end = MSM_GSBI4_PHYS + 4 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "qup_err_intr",
.start = GSBI4_QUP_IRQ,
.end = GSBI4_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct resource gsbi7_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
.start = MSM_GSBI7_QUP_PHYS,
.end = MSM_GSBI7_QUP_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "gsbi_qup_i2c_addr",
.start = MSM_GSBI7_PHYS,
.end = MSM_GSBI7_PHYS + 4 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "qup_err_intr",
.start = GSBI7_QUP_IRQ,
.end = GSBI7_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct resource gsbi8_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
.start = MSM_GSBI8_QUP_PHYS,
.end = MSM_GSBI8_QUP_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "gsbi_qup_i2c_addr",
.start = MSM_GSBI8_PHYS,
.end = MSM_GSBI8_PHYS + 4 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "qup_err_intr",
.start = GSBI8_QUP_IRQ,
.end = GSBI8_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct resource gsbi9_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
.start = MSM_GSBI9_QUP_PHYS,
.end = MSM_GSBI9_QUP_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "gsbi_qup_i2c_addr",
.start = MSM_GSBI9_PHYS,
.end = MSM_GSBI9_PHYS + 4 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "qup_err_intr",
.start = GSBI9_QUP_IRQ,
.end = GSBI9_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct resource gsbi12_qup_i2c_resources[] = {
{
.name = "qup_phys_addr",
.start = MSM_GSBI12_QUP_PHYS,
.end = MSM_GSBI12_QUP_PHYS + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "gsbi_qup_i2c_addr",
.start = MSM_GSBI12_PHYS,
.end = MSM_GSBI12_PHYS + 4 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "qup_err_intr",
.start = GSBI12_QUP_IRQ,
.end = GSBI12_QUP_IRQ,
.flags = IORESOURCE_IRQ,
},
};
下面是为6个I2C控制器所注册平台设备驱动需要的结构体
/* Use GSBI3 QUP for /dev/i2c-0 */
struct platform_device msm_gsbi3_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI3_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi3_qup_i2c_resources),
.resource = gsbi3_qup_i2c_resources,
};
/* Use GSBI4 QUP for /dev/i2c-1 */
struct platform_device msm_gsbi4_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI4_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi4_qup_i2c_resources),
.resource = gsbi4_qup_i2c_resources,
};
/* Use GSBI8 QUP for /dev/i2c-3 */
struct platform_device msm_gsbi8_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI8_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi8_qup_i2c_resources),
.resource = gsbi8_qup_i2c_resources,
};
/* Use GSBI9 QUP for /dev/i2c-2 */
struct platform_device msm_gsbi9_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI9_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi9_qup_i2c_resources),
.resource = gsbi9_qup_i2c_resources,
};
/* Use GSBI7 QUP for /dev/i2c-4 (Marimba) */
struct platform_device msm_gsbi7_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI7_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi7_qup_i2c_resources),
.resource = gsbi7_qup_i2c_resources,
};
/* Use GSBI12 QUP for /dev/i2c-5 (Sensors) */
struct platform_device msm_gsbi12_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI12_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi12_qup_i2c_resources),
.resource = gsbi12_qup_i2c_resources,
};
注意该6个平台设备结构体的name都是"qup_i2c",下面这些平台设备将在BSP资源注册的时候给添加到系统。