1. Abstract
抱歉这篇报告是我当初用英文写的,有兴趣的朋友可以参考。
2. Introduction
Document [1].chapter8 is a good tip for readers to understanding I2C basic ideas.
3. Adapter Codes
Codes exist in drivers/i2c/busses/i2c-pxa.c.
3.1 Data Structure
The device structure in arch/arm/mach-pxa/generic.c
static struct platform_device i2c_device = {
.name = "pxa2xx-i2c",
.id = 0,
.resource = i2c_resources,
.num_resources = ARRAY_SIZE(i2c_resources),
};
static struct resource i2c_resources[] = {
{
.start = 0x40301680,
.end = 0x403016a3,
.flags = IORESOURCE_MEM,
}, {
.start = IRQ_I2C,
.end = IRQ_I2C,
.flags = IORESOURCE_IRQ,
},
};
The driver data structure in drivers/i2c/busses/i2c-pxa.c:
static struct platform_driver i2c_pxa_driver = {
.probe = i2c_pxa_probe,
.remove = i2c_pxa_remove,
.driver = {
.name = "pxa2xx-i2c",
},
};
The driver private data data structure in drivers/i2c/busses/i2c-pxa.c:
struct pxa_i2c {
spinlock_t lock;
wait_queue_head_t wait;
struct i2c_msg *msg;
unsigned int msg_num;
unsigned int msg_idx;
unsigned int msg_ptr;
unsigned int slave_addr;
struct i2c_adapter adap;
#ifdef CONFIG_I2C_PXA_SLAVE
struct i2c_slave_client *slave;
#endif
unsigned int irqlogidx;
u32 isrlog[32];
u32 icrlog[32];
void __iomem *reg_base;
unsigned long iobase;
unsigned long iosize;
int irq;
};
And its global variable instance:
static struct pxa_i2c i2c_pxa = {
.lock = SPIN_LOCK_UNLOCKED,
.adap = {
.owner = THIS_MODULE,
.algo = &i2c_pxa_algorithm,
.name = "pxa2xx-i2c.0",
.retries = 5,
},
};
static const struct i2c_algorithm i2c_pxa_algorithm = {
.master_xfer = i2c_pxa_xfer,
.functionality = i2c_pxa_functionality,
};
3.2 Initialize Codes
3.2.1 Probe Function
Codes exist in drivers/i2c/busses/i2c-pxa.c.
static int i2c_pxa_probe(struct platform_device *dev)
{
struct pxa_i2c *i2c = &i2c_pxa;
struct resource *res;
#ifdef CONFIG_I2C_PXA_SLAVE
struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
#endif
int ret;
int irq;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
irq = platform_get_irq(dev, 0);
……
if (!request_mem_region(res->start, res_len(res), res->name))
return -ENOMEM;
i2c = kmalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
……
memcpy(i2c, &i2c_pxa, sizeof(struct pxa_i2c));
init_waitqueue_head(&i2c->wait);
i2c->adap.name[strlen(i2c->adap.name) - 1] = '0' + dev->id % 10;
i2c->reg_base = ioremap(res->start, res_len(res));
……
i2c->iobase = res->start;
i2c->iosize = res_len(res);
i2c->irq = irq;
i2c->slave_addr = I2C_PXA_SLAVE_ADDR; // I2C_PXA_SLAVE_ADDR equals to 1.
#ifdef CONFIG_I2C_PXA_SLAVE
if (plat) {
i2c->slave_addr = plat->slave_addr;
i2c->slave = plat->slave;
}
#endif
switch (dev->id) { //In our case it is 0, please refer to section 3.1, this part is used to set the clock.
case 0:
……
#ifndef CONFIG_PXA3xx
pxa_set_cken(CKEN14_I2C, 1);
#else
pxa_set_cken(CKEN_I2C, 1);
#endif
break;
……
}
#ifndef CONFIG_I2C_POLLING //We have not invoke following codes, since we have defined this micro
ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
i2c->adap.name, i2c);
if (ret)
goto ereqirq;
#endif
i2c_pxa_reset(i2c); //Initialize I2C Registers.
i2c->adap.algo_data = i2c; //Let algo to reference the data structure.
i2c->adap.dev.parent = &dev->dev;
ret = i2c_add_adapter(&i2c->adap); //This is a subroutine of i2c-core
……
platform_set_drvdata(dev, i2c); //let dev->driver_data point to i2c
return 0;
……
}
3.2.2 Function i 2c _pxa_reset
Please refer to comments following the codes.
static void i2c_pxa_reset(struct pxa_i2c *i2c)
{
/* abort any transfer currently under way */
i2c_pxa_abort(i2c); //Please see codes below
/* reset according to 9.8 */
writel(ICR_UR, _ICR(i2c)); //Unit Reset, ICR[14].
#ifdef CONFIG_I2C_FAST_MODE
writel(readl(_ICR(i2c)) | ICR_FM, _ICR(i2c)); //Open fast mode, which is 400kbps. ICR[15]
#endif
writel(I2C_ISR_INIT, _ISR(i2c)); // I2C_ISR_INIT equals to 0x7FF, which then set ISR[10..0] to 1 (ISR[31..11] are reserved bits.
writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); //We have already reset it, and now clear it.
writel(i2c->slave_addr, _ISAR(i2c));// i2c->slave_addr is 1, which is set in i2c_pxa_probe function.
/* set control register values */
writel(I2C_ICR_INIT, _ICR(i2c)); // I2C_ICR_INIT is (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE), which means that: BEIE is used to enable BUS Error interruption, which is used to monitor if no ACK received from slave, or NACK is received from master if we behavior as slave. IRFIE is defined as DRFIE in SPEC, which is used to enable interruption when a full byte is received. ITEIE is used to enable interruption when a full byte is sent out. GCD is used to enable or disable generation and reception of general call message, and this kind of message is in fact broadcast message with address equals to zero. SCLE is used to enable I2C to generate clock as a master.
#ifdef CONFIG_I2C_PXA_SLAVE
dev_info(&i2c->adap.dev, "Enabling slave mode/n");
writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c));
#endif
i2c_pxa_set_slave(i2c, 0); //This function is empty since we have not define the Slave macro.
/* enable unit */
writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c)); //IUE is used to enable I2C module
udelay(100);
}
static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
{
return !(readl(_ICR(i2c)) & ICR_SCLE);//Check if SCL is enabled. If SCL is enabled, I2C is working at master mode since it will output clock, otherwise it is working on slave mode. ICR[5].
}
static void i2c_pxa_abort(struct pxa_i2c *i2c)
{
unsigned long timeout = jiffies + HZ/4; //1/4Seconds
if (i2c_pxa_is_slavemode(i2c)) {
return;
}
while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) { //Wait for there is a high value on SDA Pin, MR[0] monitor the SDA PIN
unsigned long icr = readl(_ICR(i2c));
icr &= ~ICR_START; //This bit initialize an I2C transaction. ICR[0].
icr |= ICR_ACKNAK | ICR_STOP | ICR_TB; //ACKNAK is used to give slave a stop signal after reading the last byte, STOP is used to end a transaction, and TB is used to indicate that we can start new transactions, since that every time it is set indicate there is a transaction complete signal which will invoke an interruption.
writel(icr, _ICR(i2c));
msleep(1);
}
writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
_ICR(i2c)); //MA is Master Abort, which is also used in stop a transaction while reading more than one words. START and STOP are used to initialize and stop a transaction.
}
3.3 Function i 2c _pxa_xfer
3.3.1 Main Function
The most important function to implement an adaptor is i2c_algorithm.master_xfer . In our system, this function is i2c_pxa_xfer.
static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct pxa_i2c *i2c = adap->algo_data;
int ret, i;
……
for (i = adap->retries; i >= 0; i--) { // retries equals to 5.
ret = i2c_pxa_do_xfer(i2c, msgs, num);
……
udelay(100);
}
……
out:
i2c_pxa_set_slave(i2c, ret);//According to Spec’s requirements, we should set I2C to slave mode after every transfer. But this function is empty since we have not define the Slave macro.
return ret;
}
3.3.2 Function i 2c _pxa_do_xfer
static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
{
long timeout;
int ret;
/*
* Wait for the bus to become free.
*/
ret = i2c_pxa_wait_bus_not_busy(i2c);//This function check if I2C unit and bus are in free status, and will wait if I2C module is in slave mode.
……
/*
* Set master mode.
*/
ret = i2c_pxa_set_master(i2c);//This function used to check if I2C is in mater mode, which is judged according to following standard: not in slave mode(ISR_SAD is not set), unit and bus not busy(ISR_UB and ISR_IBB are not set), IBMR equals to 3 (SCL and SDA in high level voltage). After these conditions are met, set I2C module to master mode (set ICR_SCLE to 1)
……
#if defined(CONFIG_I2C_POLLING)
{
int i, err = 0;
struct i2c_msg *p;
for (i=0; !err && i<num; i++) {//For each i2c_msg, do the action.
p = &msg[i];
if (!p->len)
continue;
if (p->flags & I2C_M_RD)
err = i2c_pxa_do_read(p, p->buf, p->len); //Do the write on a message.
else
err = i2c_pxa_do_write(p, p->buf, p->len); //Do the read on a message.
}
if (!err)
ret = num - 1;
else
ret = -err;
}
#else //I have not analyze this part of codes since we do not use interruption mechanism.
spin_lock_irq(&i2c->lock);
i2c->msg = msg;
i2c->msg_num = num;
i2c->msg_idx = 0;
i2c->msg_ptr = 0;
i2c->irqlogidx = 0;
i2c_pxa_start_message(i2c);
spin_unlock_irq(&i2c->lock);
/*
* The rest of the processing occurs in the interrupt handler.
*/
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
i2c_pxa_stop_message(i2c);
/*
* We place the return code in i2c->msg_idx.
*/
ret = i2c->msg_idx;
if (timeout == 0)
i2c_pxa_scream_blue_murder(i2c, "timeout");
#endif
out:
return ret;
}
3.3.3 Function i 2c _pxa_do_read
static int i2c_pxa_do_read(struct i2c_msg *msg, unsigned char *buf, int len)
{
int icr;
/*
* Step 1: target slave address into IDBR
*/
IDBR = i2c_pxa_addr_byte(msg);//Fetch out the address 7 bits from the message, and set the direction of the bit 0 in the byte. And set it to IDBR. Note: I do not think it is a good programming style, since register should be referenced from the result of ioremap, but here used the style of __REG.
/*
* Step 2: initiate the write.
*/
icr = ICR & ~(ICR_STOP | ICR_ALDIE); //Clear the stop tag, and disable interruption of arbitration loss.
ICR = icr | ICR_START | ICR_TB; //Set the start flag, and set the send flag(TB)
if (i2c_pxa_polling_txempty(4000)) //Wait for previous sending data process to finish, since we have already started the process to send the address byte.
return 1;
while (len--) {//From now we can read in data.
icr = (ICR & ~ICR_START) | ICR_ALDIE | ICR_TB;//Clear the start tag, enable interruption of arbitration lost, and set the send flag.
if (len == 0)
icr |= ICR_ACKNAK | ICR_STOP;//If it will be the last bit, set the NACK flag and STOP flag.
else
icr &= ~ICR_ACKNAK;//Otherwise should clear NACK flag, since we will sent ACK flag to slave after reading a byte.
ICR = icr;
if (i2c_pxa_polling_rxfull(12000)) //Wait until a byte is read in.(ISR_IRF is full) .
return 1;
*buf++ = (unsigned char) IDBR & 0xff; // record the read byte.
}
ICR &= ~(ICR_STOP | ICR_ACKNAK); //The read process is finished. Now we can clear STOP and NACK for future usage.
return 0;
}
3.3.4 Function i2c_pxa_do_write
This function is very similar to read process, first write the address byte, and then write following bytes. We only list the codes here.
static int i2c_pxa_do_write(struct i2c_msg *msg, unsigned char *buf, int len)
{
int icr;
/*
* Step 1: target slave address into IDBR
*/
IDBR = i2c_pxa_addr_byte(msg);
/*
* Step 2: initiate the write.
*/
icr = ICR & ~(ICR_STOP | ICR_ALDIE);
ICR = icr | ICR_START | ICR_TB;
if (i2c_pxa_polling_txempty(4000))
return 1;
while (len--) {
IDBR = (unsigned int) (*buf++);
icr = (ICR & ~ICR_START) | ICR_ALDIE | ICR_TB;
if (len == 0)
icr |= ICR_STOP;
ICR = icr;
if (i2c_pxa_polling_txempty(50000))
return 1;
}
ICR &= ~ICR_STOP;
return 0;
}
3.4 The Interruption Process
The interruption mode is not implemented in our platform. However, this kind of process is recommended in both SPEC and Internet reference codes. I want to optimize this part in the future.
4. I 2C Core Sub-system
I will cover it in the future if I got time.
5. I 2C Device Codes-Micco
5.1 Initialize Codes
static int __init micco_init(void)
{
int ret;
if ((ret = i2c_add_driver(&i2c_micco_driver))) {
printk(KERN_WARNING "Micco: Driver registration failed,"
" module not inserted./n");
return ret;
}
ret = platform_driver_register(&micco_driver);
return ret;
}
We will cover these two drivers one by one:
struct i2c_driver i2c_micco_driver =
{
.driver = {
.name = "micco i2c client driver",
},
.attach_adapter = &i2c_micco_attach_adapter,
.detach_client = &i2c_micco_detach_client,
};
static struct platform_driver micco_driver = {
.driver = {
.name = "pxa3xx_pmic",
},
.probe = micco_probe,
.remove = micco_remove,
.suspend = micco_suspend,
.resume = micco_resume,
};
5.2 Function of Driver i 2c _micco_driver
The codes before i2c_micco_detect_client is very routine, which just call i2c_probe:
static int i2c_micco_attach_adapter(struct i2c_adapter *adap)
{
return i2c_probe(adap,&addr_data, &i2c_micco_detect_client);
}
5.2.1 Function i 2c _micco_detect_client
static int i2c_micco_detect_client(struct i2c_adapter *adapter,
int address, int kind)
{
struct i2c_client *new_client;
int err = 0;
int chip_id;
/* Let's see whether this adapter can support what we need.
Please substitute the things you need here! */
if ( !i2c_check_functionality(adapter,I2C_FUNC_SMBUS_BYTE_DATA) ) {
……
}
/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet.
But it allows us to access several i2c functions safely */
/* Note that we reserve some space for micco_data too. If you don't
need it, remove it. We do it here to help to lessen memory
fragmentation. */
new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL );
……
new_client->addr = address; //The slave addr of this I2C client. I have not dip into how this address is figured out, since it is in function i2c_proble of i2c core.
new_client->adapter = adapter;
new_client->driver = &i2c_micco_driver;
new_client->flags = 0;
chip_id = i2c_smbus_read_byte_data(new_client, MICCO_CHIP_ID);//This function will finally call i2c_transfer, since we have defined emulated smbus
if (chip_id < 0){
printk("micco unavailable!/n");
goto ERROR1;
} else {
printk("micco(chip id:0x%02x) detected./n", chip_id);
}
g_client = new_client;
strcpy(new_client->name, "MICCO");
/* Tell the i2c layer a new client has arrived */
if ((err = i2c_attach_client(new_client))) // A new I2C Device will be created.
goto ERROR1;
return 0;
…….
}
5.3 Function of Driver micco_driver
5.3.1 Function micco_probe
I have not gone through this function one by one since I have not read through the SPEC of Dialog.
static int micco_probe(struct platform_device *pdev)
{
int ret;
u8 value;
ret = micco_initchip();
……
pxa3xx_mfp_set_configs(lt_micco_pins, ARRAY_SIZE(lt_micco_pins));
pxa3xx_gpio_set_direction(MFP_PMIC_INT, GPIO_DIR_IN);
ret = request_irq(IRQ_MICCO, micco_irq_handler, IRQF_TRIGGER_FALLING,
"Micco", NULL); //All events are dispatched here.
……
/* Mask interrupts that are not needed */
micco_write(MICCO_IRQ_MASK_A, 0xFE);
micco_write(MICCO_IRQ_MASK_B, 0xFF);
micco_write(MICCO_IRQ_MASK_C, 0xFF);
micco_write(MICCO_IRQ_MASK_D, 0xFF);
/* avoid SRAM power off during sleep*/
micco_write(MICCO_OVER1, 0x05);
// micco_write(MICCO_APP_OVER2, 0xff);
// micco_write(MICCO_APP_OVER3, 0xff);
/* Wjt replace begin, by Raymond, 2008-5-14 14:24:31 */
#if 0
/* Enable the ONKEY power down functionality */
micco_write(MICCO_SYSCTRL_B, 0x20);
#endif
/*======== replaced by ===================*/
/* Disable the ONKEY power down functionality */
micco_write(MICCO_SYSCTRL_B, 0x00);
/* Wjt replace end, by Raymond, 2008-5-14 14:24:31 */
micco_write(MICCO_SYSCTRL_A, 0x60);
/* IRQ is masked during the power-up sequence and will not be released
* until they have been read for the first time */
micco_read(MICCO_EVENT_A, &value);
micco_read(MICCO_EVENT_B, &value);
micco_read(MICCO_EVENT_C, &value);
micco_read(MICCO_EVENT_D, &value);
micco_enable_LDO12();
#ifdef CONFIG_PROC_FS
create_micco_proc_file();
#endif
pmic_set_ops(&micco_pmic_ops);
return 0;
}
5.3.2 Function micco_irq_handler
static irqreturn_t micco_irq_handler(int irq, void *dev_id)
{
unsigned int event;
u8 val;
event = micco_event_change(); //Read in the event from registers
pmic_event_handle(event); //Process the events
/* We don't put these codes to USB specific code because
* we need handle it even when no USB callback registered.
*/
if (event & PMIC_EVENT_OTGCP_IOVER) {
/* According to Micco spec, when OTGCP_IOVER happen,
* Need clean the USBPCP_EN in MISC. and then set
* it again.
*/
micco_read(MICCO_MISC, &val);
val &= ~MICCO_MISC_USBCP_EN;
micco_write(MICCO_MISC, val);
val |= MICCO_MISC_USBCP_EN;
micco_write(MICCO_MISC, val);
}
return IRQ_HANDLED;
}
5.3.3 Function pmic_event_handle
int pmic_event_handle(unsigned long event)
{
int ret;
unsigned long flags;
struct pmic_callback *pmic_cb;
ret = check_pmic_ops();
if (ret < 0)
return ret;
spin_lock_irqsave(&pxa3xx_pmic_ops->cb_lock, flags);
list_for_each_entry(pmic_cb, &pxa3xx_pmic_ops->list, list) {
spin_unlock_irqrestore(&pxa3xx_pmic_ops->cb_lock, flags);
/* event is bit-wise parameter, need bit AND here as filter */
if ((pmic_cb->event & event) && (pmic_cb->func))
pmic_cb->func(event); //Here event is dispatched to related handler
spin_lock_irqsave(&pxa3xx_pmic_ops->cb_lock, flags);
}
spin_unlock_irqrestore(&pxa3xx_pmic_ops->cb_lock, flags);
return 0;
}
6. Misc Points
6.1 SMBUS
I will cover it in the future if I got time.
7. Future Works
7.1 Update Polling Mode to Interruption Mode
Polling mode will waste a lot of resources. I will cover it in the future if I got time.
8. References
[1]. Essential Linux Device Drivers, Prentice.Hall.Essential.Linux.Device.Drivers.Apr.2008.chm