Linux 2.6.21 读核笔记 at91_i2c篇
时间:2007-05-25 来源:minicore
在linux 2.6.21 在at91rm9200(Atmel)的使用过程中,好像i2c不太灵光,有的时候不太可靠!
读写几千次就会出现错误,一致没有明白问题出在哪。但有些需要注意的地方:
A.at91rm9200 datasheet Page396 要求如下:
• Program the PIO controller to:
– Dedicate TWD and TWCK as peripheral lines.
– Define TWD and TWCK as open-drain.
那么在linux 2.6.21 kernel里是如何实现的呢?
2.6.21于2.4.18有很多体系上的不同,例如初始化这部分 2.4.18放在kernel_source_root/drivers/i2c/里面,而2.6.21放在了kernel_source_root/Arch/arm/Mach-at91/At91rm9200_devices.c里面实现。
/* --------------------------------------------------------------------
* TWI (i2c)
* -------------------------------------------------------------------- */
#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
static struct resource twi_resources[] = {
[0] = {
.start = AT91RM9200_BASE_TWI,
.end = AT91RM9200_BASE_TWI + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AT91RM9200_ID_TWI,
.end = AT91RM9200_ID_TWI,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device at91rm9200_twi_device = {
.name = "at91_i2c",
.id = -1,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
void __init at91_add_device_i2c(void)
{
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */
at91_set_multi_drive(AT91_PIN_PA25, 1);
at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */
at91_set_multi_drive(AT91_PIN_PA26, 1);
platform_device_register(&at91rm9200_twi_device);
}
#else
void __init at91_add_device_i2c(void) {}
#endif
函数at91_add_device_i2c()完成了at91 i2c的初始化,我们再近一步给出两个函数的定义
/*
* mux the pin to the "A" internal peripheral role.
*/
int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio)
return -EINVAL;
__raw_writel(mask, pio + PIO_IDR);
__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
__raw_writel(mask, pio + PIO_ASR);
__raw_writel(mask, pio + PIO_PDR);
return 0;
}
很明显:at91_set_A_periph把引脚赋予了PeriphA功能,同时由use_pullup给出标志。
int __init_or_module at91_set_multi_drive(unsigned pin, int is_on)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio)
return -EINVAL;
__raw_writel(mask, pio + (is_on ? PIO_MDER : PIO_MDDR));
return 0;
}
而at91_set_multi_drive(unsigned pin, int is_on)则设置该引脚是否多功能使能.
B.at91rm9200 datasheet Page400 Figure 23-10. TWI Write in Master Mode
Set the control register:
- Master enable
TWI_CR = TWI_MSEN
目前,我还没有发现2.6.21哪里有实现?
datasheet Page403
• MSEN: TWI Master Transfer Enabled
0 = No effect.
1 = If MSDIS = 0, the master data transfer is enabled.
读写几千次就会出现错误,一致没有明白问题出在哪。但有些需要注意的地方:
A.at91rm9200 datasheet Page396 要求如下:
• Program the PIO controller to:
– Dedicate TWD and TWCK as peripheral lines.
– Define TWD and TWCK as open-drain.
那么在linux 2.6.21 kernel里是如何实现的呢?
2.6.21于2.4.18有很多体系上的不同,例如初始化这部分 2.4.18放在kernel_source_root/drivers/i2c/里面,而2.6.21放在了kernel_source_root/Arch/arm/Mach-at91/At91rm9200_devices.c里面实现。
/* --------------------------------------------------------------------
* TWI (i2c)
* -------------------------------------------------------------------- */
#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
static struct resource twi_resources[] = {
[0] = {
.start = AT91RM9200_BASE_TWI,
.end = AT91RM9200_BASE_TWI + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = AT91RM9200_ID_TWI,
.end = AT91RM9200_ID_TWI,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device at91rm9200_twi_device = {
.name = "at91_i2c",
.id = -1,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
void __init at91_add_device_i2c(void)
{
/* pins used for TWI interface */
at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */
at91_set_multi_drive(AT91_PIN_PA25, 1);
at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */
at91_set_multi_drive(AT91_PIN_PA26, 1);
platform_device_register(&at91rm9200_twi_device);
}
#else
void __init at91_add_device_i2c(void) {}
#endif
函数at91_add_device_i2c()完成了at91 i2c的初始化,我们再近一步给出两个函数的定义
/*
* mux the pin to the "A" internal peripheral role.
*/
int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio)
return -EINVAL;
__raw_writel(mask, pio + PIO_IDR);
__raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
__raw_writel(mask, pio + PIO_ASR);
__raw_writel(mask, pio + PIO_PDR);
return 0;
}
很明显:at91_set_A_periph把引脚赋予了PeriphA功能,同时由use_pullup给出标志。
int __init_or_module at91_set_multi_drive(unsigned pin, int is_on)
{
void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin);
if (!pio)
return -EINVAL;
__raw_writel(mask, pio + (is_on ? PIO_MDER : PIO_MDDR));
return 0;
}
而at91_set_multi_drive(unsigned pin, int is_on)则设置该引脚是否多功能使能.
B.at91rm9200 datasheet Page400 Figure 23-10. TWI Write in Master Mode
Set the control register:
- Master enable
TWI_CR = TWI_MSEN
目前,我还没有发现2.6.21哪里有实现?
datasheet Page403
• MSEN: TWI Master Transfer Enabled
0 = No effect.
1 = If MSDIS = 0, the master data transfer is enabled.
相关阅读 更多 +
排行榜 更多 +