Showing posts with label i2c. Show all posts
Showing posts with label i2c. Show all posts

6/22/2012

I2C Power collapse issue in android build

Problem: The modem side processor keeps spinning for the spinlock acquired by the apps side processor for an I2C transaction when the apps side processor is power collapsed.



Solution:

As a solution to this, wakelocks can be used. "Wakelock" is a mechanism which can prevent the system from going into a low-power state.



To prevent the above mentioned problem, the I2C driver at the apps side grabs a wakelock at the beginning of the I2C transaction (inside the msm_i2c_xfer() and then releases it at the end of the transaction. With this, the power collapse is delayed for the time the wakelock is held by the i2c driver i.e. till the spinlock held by the apps side processor is released, and the released spinlock can, then, be used by the modem side processor.



To setup a wakelock in the kernel space:

#include <linux/wakelock.h>

wake_lock_init(struct wake_lock *lock, int type, const char *name)

where,

name: name of the lock

type: kind of wakelock



The two types are : WAKE_LOCK_SUSPEND : prevents the system from suspending

WAKE_LOCK_IDLE: prevents going into a low_power idle state



Following are the APIs to handle this lock:



void wake_lock(struct wake_lock *lock);

void wake_lock_timeout(struct wake_lock *lock, long timeout);

void wake_unlock(struct wake_lock *lock);



Note: pm_qos() is not intended to influence the suspend power collapse. It influences the idle power collapse. Thus, pm_qos() should not be used in the above mentioned scenario.

I2C Suspend Power Collapse in AMSS 8650 Software

Problem: The modem side processor keeps spinning for the spinlock acquired by the apps side processor for an I2C transaction when the apps side processor is suspend power collapsed.



Solution: The interrupts should be enabled before calling I2C on the Apps side.



Suspend() is already using a mutex_lock (which is also being used for the I2C transaction) which makes sure that the transaction is over before suspend happens. So, suspend power collapse should not happen until ongoing I2C transaction is done. And once suspend is called, any further I2C transaction cannot even acquire remote lock.



In such a situation, one should check that the interrupts are enabled when an I2C transaction on the apps side is being initiated. If the interrupts are disabled, then the driver cannot finish the transaction since the driver is interrupt driven and the lock acquired is never released. Thus, the interrupts should be enabled before calling I2C on the Apps side.

How to add GPIO bit-bang i2c device to Linux kernel?

1. Check Kernel configuration
#define CONFIG_I2C_GPIO y
#define CONFIG_I2C_MSM y


2. Configure GPIOs at Modem side for general purpose, in/out...
You should edit TLMMBsp.c at modem side.


*3. ~ 7. You should add/modify "kernel/arch/arm/mach-msm/board-xxxxx.c"

3. Make i2c_gpio_platform_data
static struct i2c_gpio_platform_data ALRAN_i2c_gpio_data = {
.sda_pin = 91, // GPIO pin number for SDA
.scl_pin = 90, // GPIO pin number for SCL
};


4. Make platform_device
static struct platform_device ALRAN_i2c_gpio_device = {
.name = "i2c-gpio",
.id = 3, // do not be same with the another i2c_gpio_device
.dev = {
.platform_data = &ALRAN_i2c_gpio_data, // You have made it at step 3.
},
};


5. Add devices array for initdata
static struct platform_device *devices[] __initdata = {
<snip>
&ALRAN_i2c_gpio_device,
<snip>



6. Add i2c client information
static struct i2c_board_info ALRAN_i2c_devices[] = {
{
I2C_BOARD_INFO("ALRAN",0x4A>>1), // 0x4A should be changed with your device address
},
};


7. Register i2c client to board_init function
static void __init msm7x2x_init(void)
{
<snip>
i2c_register_board_info(3, ALRAN_i2c_devices, ARRAY_SIZE(ALRAN_i2c_devices));
<snip>
}
It's just for i2c client board.

How to analyze the status of I2C Bus for linux build.

I2C SCL state
RESET� Bus idle; the start condition has not yet been detected.
NOT MASTER � This occurs when the I2C controller detects that another master is trying to control the bus.
This is usually the Error state, because the MSM? has only one master. It is manifested as an arbitration lost error.
HIGH � High phase of scl_out
STOP condition � Master releases control of bus and returns to the Reset state
Loss of arbitration � Go to the NOT MASTER state and wait for the other master to release the bus
Unexpected START condition � Error status
LOW � Low phase of scl_out
If data control block is requesting this, it is entering forced Low state and waiting for data control block to return to normal operation


I2C SDA state
RESET � Reset and Wait state
Either STOP condition or bus is free to commence transmission
TX ADDR � 7-bit address has been transmitted to client
When address is issued, clock is pulled to low until it receives ACK from the client
TX DATA � Data has been issued to the bus
Same with TX ADDR, except it is not generating the START condition
RX DATA � Data received from the bus
Software can set the LAST_BYTE bit to terminate transfer


In AMSS\products\XXXX\drivers\hw\t32\XXXX\


There's hwioreg.cmm script that one can use on T32
to monitor I2C SCL and SDA state.
User can type "I2C_STATUS" on menu to monitor the i2c registers
This can be done on the fly to debug i2c bus.