Monday, November 8, 2010

Touch doesnt work in lock screen after resuming from sleep

In file drivers/i2c/busses/i2c-s3c2410.c, function,
static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
{
unsigned long iicstat;
int timeout = 400;

while (timeout-- > 0) {
iicstat = readl(i2c->regs + S3C2410_IICSTAT);

if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
return 0;

msleep(1);
}

return -ETIMEDOUT;
}

Some how the bus is busy even after 400 iterations. The i2c adaptor may be going to some invalid state. Added,

writel(iicstat & ~S3C2410_IICSTAT_TXRXEN, i2c->regs + S3C2410_IICSTAT);

after the msleep(1). This will disable the Rx/Tx of the i2c adapter, which is later enabled. So basically its a reset of the register

I2C-bus data output enable/ disable bit.
0 = Disables Rx/Tx,
1 = Enables Rx/Tx

This blog looks interesting about the i2c drive in linux-2.6.32
http://www.embedded-bits.co.uk/?p=174

Saturday, November 6, 2010

wakeup from suspend to Ram

echo mem > /sys/power/state should suspend to ram and
echo on > /sys/power/state should wake up the device from suspend.

Former was not working on Atlas phone. It was because the read from /sys/power/state was not implemented properly. When you try to read it should print all the valid power states. But it was only giving mem as the output. In file kernel/power/main.c, function state_show calls valid_states which in turn calls a architecture implemented function pointer. The function is called by passing mem, on or standby as the argument. It will return true if it architecture support the argument state. So state_show will give out put accordingly.

Previously it was giving true only for mem. Modified the .valid function pointer in the architecutre file (arch/arm/plat-samsung/pm.c) to give true for mem, on and standby. This fixed the wakeup issue.

Got some help from,
Linux Symposium

Monday, October 18, 2010

Adding send end key as a wake-up source

On MSM chip there are three Interrupt controllers. One for ARM11, one for ARM9 and one dedicated Interrupt controller(Simple Interrupt Controller(SIC), this is always on) to work when both processors sleep. So before ARM11 sleeps we have to send the wake-up irqs to CP. So that MPP IC will monitors only those wake-up interrupts send by AP. This is achieved by using the kernel function enalbe_irq_wake(irq no). This will add the flag IRQ_WAKE to that descriptor of that particular irq. So whenever AP go to sleep it will send this irq number also to the CP as a wake-up soruce.

Tuesday, September 14, 2010

Problem with udelay

I was working on a mobile device, reducing lcd wake up time once powerkey is pressed. In LCD driver there were many msleeps() used in the kernel. There is some structure like this.

Struct lcd_startup_sequence {
U16 cmd;
U16 timeout;/*in ms*/
}

lcd_startup_sequence[10] = {
{0x34, 100},
{0x23, 0},
{0x14, 0},
{0x11, 50},
};

What i did first is this,

if(lcd_starup_sequence.delay)
msleep(lcd_startup_swquence.delay);

So this will avoids the calls from msleep(0); Because even if msleep is called with 0 as the argument, the current thread will be kept on the wait queue from the running queue.

But from this I haven't got much improvement. So I thought of changing msleep() to mdelay(). So it takes the correct time, because it is busy waiting than sleeping. But you should be very careful in using mdelay() because you are just eating up the processor time. So if not necessary use msleep() instead. This give me good improvement.

The funny part is that in another place also I changed from msleep(100) to mdelay(100). Surprisingly here mdelay is taking around 200 ms and msleep is taking 110 ms. What the heck?
Then I digged in the kernel and found plenty of information about kernel time keeping. The following link explaing how the delay is generated in linux kernel:
http://kerneltrap.org/node/6857

But the reason for mdelay behavior is explained below:
udelay() can be incorrect on SMP machines that scale their CPU frequencies independently of one another he delay loop can either be too fast or too slow depending on which CPU the loops_per_jiffy counter is calibrated on and which CPU the delay loop is running on. udelay() can also be incorrect if the CPU frequency switches during the __delay() loop, causing the loop
to either terminate too early, or too late.

For more informations:
http://www.spinics.net/lists/linux-arm-msm/msg00208.html
http://groups.google.co.kr/group/linux.kernel/browse_thread/thread/0a5c1395e82eabc2?pli=1

Monday, August 23, 2010

Samsung work

1) Headset and send-end key driver.
The mobile runs on Qualcomm MSM7627. This is a having two ARM core, two DSP core. There is one ARM11 which is called as Application Processor(AP) on which linux runs. And there is ARM9 which is called Modem Processor(some times called Communication Processor CP) on which REX OS is running. Here CP is the master. Both communicates through Shared memory driver IPC. Whoever want to communicate will place the corresponding COMMAND and data and interrupt the other processor. Send end key is the the switch on the headset to send the key-press events to the application to for disconnecting the call or going to next track in music player. This is implemented as an input device. The driver mechanism is like this.
Headset detection is done on Modem. There is a IPC callback mechanism registered in RIL layer(on AP side) in application space for getting the status change of the headset. So once headset is inserted or remove, modem will pass this information through IPC. The callback in the mode side will write 1 or 0 for headset inserted and headset removed respectively to a sysfs entry(/sys/class/switch/h2w/headset) exported by the headset driver in the AP side. So once the headset is detected we will enable the send-end key interrupt which is done on the AP side. This is implemented on a gpio. Since due to noise created during the headset insertion, lot of spurious interrupts(send end key) where coming. So we enable the send-end key only after 100ms after the headset insertion. This is implemented by using delayed work-queue.

2) Firmware up-gradation on Touch screen.
The touch screen driver is from Melfas. The I2C is implemented using the i2c-gpio driver. This is a kernel driver which manipulates the gpio to implement the I2C protocol. We have to pass the gpios for sda and scl during the initialization of the driver.
some notes about this driver
=======================


This is a very simple bitbanging i2c bus driver utilizing the new
arch-neutral GPIO API. Useful for chips that don't have a built-in
i2c controller, additional i2c busses, or testing purposes.

To use, include something similar to the following in the
board-specific setup code:

#include

static struct i2c_gpio_platform_data i2c_gpio_data = {
.sda_pin = GPIO_PIN_FOO,
.scl_pin = GPIO_PIN_BAR,
};
static struct platform_device i2c_gpio_device = {
.name = "i2c-gpio",
.id = 0,
.dev = {
.platform_data = &i2c_gpio_data,
},
};

Register this platform_device, set up the i2c pins as GPIO if required and you're ready to go. This will use default values for udelay and timeout, and will work with GPIO hardware that does not support open drain mode, but allows changing the direction of the SDA i2c_gpio_device.id is the I2C adapter number i2c_gpio_platform_data has more members to define the pin is

struct i2c_gpio_platform_data {
unsigned int sda_pin;
unsigned int scl_pin;
/*signal toggle delay. SCL frequency is (500 / udelay) kHz*/
int udelay;
/*timeout: clock stretching timeout in jiffies. If the slave keeps
SCL low for longer than this, the transfer will time out.*/
int timeout;
unsigned int sda_is_open_drain:1;
unsigned int scl_is_open_drain:1;
unsigned int scl_is_output_only:1;
}
=============================

3) RamDump Issues
RamDump is a mechanism used by the samsung to catch the cause of any kernel crash and dump it in the RAM. Later they use one software to extract to the machine and can be analyzed. I will explain on RamDump here,
A kernel crash was happening like, freeing the VMA in interrupt context. The kernel back trace is showing starting from work_pending to a place where vumap().
In vunmap() function a BUG(in_interrupt()) is there. It is an assertion to tell that vma should not be freed in interrupt context.
Its takes some time to fix. But I feel little proud of myself after fixing that.
There was one call to lib/genalloc.c gen_pool_destroy(). In that function
write_unlock() is called without the write_lock(). This function basically decrements
and increments the preemt_count to disable the preemption. And everything was going wrong from here. So it was a kernel bug in 2.6.29 kernel.

4) changed msleep() to mdelay()
Not a good thing to do. But in this scenario it is the only solution. The scenario is when user press the , the device should wake up. But the lcd is taking around 900ms to wake up. I saw few msleep(), changed it to mdelay(). This got a reduction of 350ms The only problem is that, the processor will just spin and waist the processor cycles. But here when the device wakes up from sleep it wont be having other things to do. Moreover, mdelay() is not locking anything, it just uses its full time slot. Once its time-slot is over, scheduler will schedules it out.
Another option- One structure they are giving delay after each command. But most of the delay are zero. But in the kernel code they are using like this
msleep(table->wait).
I modified to
if(table->wait)
msleep(table->wait);
The reason is that even msleep(0) will take more than 10ms.

Monday, November 10, 2008

Cross Compilling ALSA 1.0.18 lib and utils for ARM

Building ALSA-LIB
Steps 1) ./configure CC=arm-linux-gcc --host=arm-linux -build=i686-pc-linux-gnu --disable-python

I am building for arm
Step 2) make
Step 3) make install DESTDIR=/home/arunks/arun_bins

Building ALSA-Utils
Step 1)./configure CC=arm-linux-gcc --host=arm-linux -build=i686-pc-linux-gnu --with-alsa-prefix=/home/arunks/alsa_sep20/arun_bins/usr/lib/ --with-alsa-inc-prefix=/home/arunks/alsa_sep20/arun_bins/usr/include --disable-alsatest --disable-alsamixer --disable-largefile

Step 2)make
Step 3) make install DESTDIR=/home/arunks/arun_bins

This will install Alsa lib an Alsa utill at /home/arunks/arun_bins.
Now you may copy it to your file system and enjoy playing music.

Friday, November 7, 2008

Poll() or Select() system call

Poll_wait()

When ever an application call the select or poll with an fdset,the kernel inovkes the poll method of all files referenced by the system call, passing the same poll_table to each of them. So all the fops->poll will get called. poll_wait call will add the wait queue to the common poll_table. If none of the drivers being polled indicates that I/O can occur without blocking, the poll call simply sleeps until one of the wait queues it is on wakes it up. When one of the wait queue wakes up, the kernel call the poll() function concerning that driver again.