summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasily Khoruzhick <anarsoul@gmail.com>2010-09-10 10:54:13 +0000
committerEric Bénard <eric@eukrea.com>2010-09-11 18:58:19 +0200
commit7e92d21ca7b6e6685c80243d3b09c06aedaa3354 (patch)
tree017f60781a09e9b93af24b09cc7113d823a97c46
parent18bfe69b58341220399c1a1f9acc0bbc7a905eb8 (diff)
linux-2.6.35: add rx1950 support
Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com> Signed-off-by: Eric Bénard <eric@eukrea.com>
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/0001-s3c2410_ts-add-fake-pressure-events.patch41
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/0002-s3c2410_udc-2440-dual-packet-workaround.patch71
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/0003-rx1950-add-battery-device.patch356
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/0004-rx1950-add-LEDs-support.patch71
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/0005-s3c24xx-DMA-don-t-use-autoreload-feature.patch701
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/0006-s3cmci-minor-fixups.patch40
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/0007-Add-s3c-adc-battery-driver.patch530
-rw-r--r--recipes/linux/linux-2.6.35/rx1950/defconfig1615
-rw-r--r--recipes/linux/linux_2.6.35.bb7
9 files changed, 3432 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.35/rx1950/0001-s3c2410_ts-add-fake-pressure-events.patch b/recipes/linux/linux-2.6.35/rx1950/0001-s3c2410_ts-add-fake-pressure-events.patch
new file mode 100644
index 0000000000..fa43e2d86f
--- /dev/null
+++ b/recipes/linux/linux-2.6.35/rx1950/0001-s3c2410_ts-add-fake-pressure-events.patch
@@ -0,0 +1,41 @@
+From d9b482fc3e5bef43a7845989189cf9b71915a1cb Mon Sep 17 00:00:00 2001
+From: Vasily Khoruzhick <anarsoul@gmail.com>
+Date: Wed, 12 May 2010 09:59:32 +0300
+Subject: [PATCH 01/20] s3c2410_ts: add fake pressure events
+
+Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
+---
+ drivers/input/touchscreen/s3c2410_ts.c | 3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
+index 6085d12..381c295 100644
+--- a/drivers/input/touchscreen/s3c2410_ts.c
++++ b/drivers/input/touchscreen/s3c2410_ts.c
+@@ -126,6 +126,7 @@ static void touch_timer_fire(unsigned long data)
+ input_report_abs(ts.input, ABS_Y, ts.yp);
+
+ input_report_key(ts.input, BTN_TOUCH, 1);
++ input_report_abs(ts.input, ABS_PRESSURE, 1);
+ input_sync(ts.input);
+
+ ts.xp = 0;
+@@ -140,6 +141,7 @@ static void touch_timer_fire(unsigned long data)
+ ts.count = 0;
+
+ input_report_key(ts.input, BTN_TOUCH, 0);
++ input_report_abs(ts.input, ABS_PRESSURE, 0);
+ input_sync(ts.input);
+
+ writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
+@@ -318,6 +320,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
+ ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
+ input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
++ input_set_abs_params(ts.input, ABS_PRESSURE, 0, 1, 0, 0);
+
+ ts.input->name = "S3C24XX TouchScreen";
+ ts.input->id.bustype = BUS_HOST;
+--
+1.7.2.2
+
diff --git a/recipes/linux/linux-2.6.35/rx1950/0002-s3c2410_udc-2440-dual-packet-workaround.patch b/recipes/linux/linux-2.6.35/rx1950/0002-s3c2410_udc-2440-dual-packet-workaround.patch
new file mode 100644
index 0000000000..bd9a8b12e7
--- /dev/null
+++ b/recipes/linux/linux-2.6.35/rx1950/0002-s3c2410_udc-2440-dual-packet-workaround.patch
@@ -0,0 +1,71 @@
+From fc47d51f262ec6d0a4601fe37ac6478e30d68060 Mon Sep 17 00:00:00 2001
+From: Vasily Khoruzhick <anarsoul@gmail.com>
+Date: Thu, 24 Sep 2009 22:17:47 +0300
+Subject: [PATCH 02/20] s3c2410_udc: 2440 dual packet workaround
+
+This is a patch that seems to make the USB hangs on the S3C2440 go away.
+At least a good amount of ping torture didn't make them come back so far.
+
+The issue is that, if there are several back-to-back packets, sometimes no
+interrupt is generated for one of them. This seems to be caused by the
+mysterious dual packet mode, which the USB hardware enters automatically
+if the endpoint size is half that of the FIFO. (On the 2440, this is the
+normal situation for bulk data endpoints.)
+
+There is also a timing factor in this. I think what happens is that the USB
+hardware automatically sends an acknowledgement if there is only one packet
+in the FIFO (the FIFO has space for two). If another packet arrives before
+the host has retrieved and acknowledged the previous one, no interrupt is
+generated for that second one.
+
+However, there may be an indication. There is one undocumented bit (none
+of the 244x manuals document it), OUT_CRS1_REG[1], that seems to be set
+suspiciously often when this condition occurs. There is also
+CLR_DATA_TOGGLE, OUT_CRS1_REG[7], which may have a function related to
+this. (The Samsung manual is rather terse on that, as usual.)
+
+This needs to be examined further. For now, the patch seems to do the
+trick.
+
+Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
+---
+ drivers/usb/gadget/s3c2410_udc.c | 16 +++++++++++++++-
+ 1 files changed, 15 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
+index ea2b3c7..fed323c 100644
+--- a/drivers/usb/gadget/s3c2410_udc.c
++++ b/drivers/usb/gadget/s3c2410_udc.c
+@@ -902,7 +902,7 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
+ int pwr_reg;
+ int ep0csr;
+ int i;
+- u32 idx;
++ u32 idx, idx2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+@@ -1017,6 +1017,20 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
+ }
+ }
+
++ /* what else causes this interrupt? a receive! who is it? */
++ if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) {
++ for (i = 1; i < S3C2410_ENDPOINTS; i++) {
++ idx2 = udc_read(S3C2410_UDC_INDEX_REG);
++ udc_write(i, S3C2410_UDC_INDEX_REG);
++
++ if (udc_read(S3C2410_UDC_OUT_CSR1_REG) & 0x1)
++ s3c2410_udc_handle_ep(&dev->ep[i]);
++
++ /* restore index */
++ udc_write(idx2, S3C2410_UDC_INDEX_REG);
++ }
++ }
++
+ dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
+
+ /* Restore old index */
+--
+1.7.2.2
+
diff --git a/recipes/linux/linux-2.6.35/rx1950/0003-rx1950-add-battery-device.patch b/recipes/linux/linux-2.6.35/rx1950/0003-rx1950-add-battery-device.patch
new file mode 100644
index 0000000000..1a5eff49a0
--- /dev/null
+++ b/recipes/linux/linux-2.6.35/rx1950/0003-rx1950-add-battery-device.patch
@@ -0,0 +1,356 @@
+From 880fc865d99084c3ec697289d34eb12a0aa54103 Mon Sep 17 00:00:00 2001
+From: Vasily Khoruzhick <anarsoul@gmail.com>
+Date: Wed, 16 Jun 2010 23:16:08 +0300
+Subject: [PATCH 03/20] rx1950: add battery device
+
+Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
+---
+ arch/arm/mach-s3c2440/mach-rx1950.c | 316 +++++++++++++++++++++++++++++++++++
+ 1 files changed, 316 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-s3c2440/mach-rx1950.c b/arch/arm/mach-s3c2440/mach-rx1950.c
+index 142d1f9..2bfa43a 100644
+--- a/arch/arm/mach-s3c2440/mach-rx1950.c
++++ b/arch/arm/mach-s3c2440/mach-rx1950.c
+@@ -25,8 +25,10 @@
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
+ #include <linux/sysdev.h>
++#include <linux/pda_power.h>
+ #include <linux/pwm_backlight.h>
+ #include <linux/pwm.h>
++#include <linux/s3c_adc_battery.h>
+
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -127,6 +129,318 @@ static struct s3c2410fb_display rx1950_display = {
+
+ };
+
++static int power_supply_init(struct device *dev)
++{
++ return gpio_request(S3C2410_GPF(2), "cable plugged");
++}
++
++static int rx1950_is_ac_online(void)
++{
++ return !gpio_get_value(S3C2410_GPF(2));
++}
++
++static void power_supply_exit(struct device *dev)
++{
++ gpio_free(S3C2410_GPF(2));
++}
++
++static char *rx1950_supplicants[] = {
++ "main-battery"
++};
++
++static struct pda_power_pdata power_supply_info = {
++ .init = power_supply_init,
++ .is_ac_online = rx1950_is_ac_online,
++ .exit = power_supply_exit,
++ .supplied_to = rx1950_supplicants,
++ .num_supplicants = ARRAY_SIZE(rx1950_supplicants),
++};
++
++static struct resource power_supply_resources[] = {
++ [0] = {
++ .name = "ac",
++ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
++ IORESOURCE_IRQ_HIGHEDGE,
++ .start = IRQ_EINT2,
++ .end = IRQ_EINT2,
++ },
++};
++
++static struct platform_device power_supply = {
++ .name = "pda-power",
++ .id = -1,
++ .dev = {
++ .platform_data =
++ &power_supply_info,
++ },
++ .resource = power_supply_resources,
++ .num_resources = ARRAY_SIZE(power_supply_resources),
++};
++
++static const struct s3c_adc_bat_thresh bat_lut_noac[] = {
++ {
++ .volt = 4100,
++ .cur = 156,
++ .level = 100
++ },
++ {
++ .volt = 4050,
++ .cur = 156,
++ .level = 95
++ },
++ {
++ .volt = 4025,
++ .cur = 141,
++ .level = 90
++ },
++ {
++ .volt = 3995,
++ .cur = 144,
++ .level = 85
++ },
++ {
++ .volt = 3957,
++ .cur = 162,
++ .level = 80
++ },
++ {
++ .volt = 3931,
++ .cur = 147,
++ .level = 75
++ },
++ {
++ .volt = 3902,
++ .cur = 147,
++ .level = 70
++ },
++ {
++ .volt = 3863,
++ .cur = 153,
++ .level = 65
++ },
++ {
++ .volt = 3838,
++ .cur = 150,
++ .level = 60
++ },
++ {
++ .volt = 3800,
++ .cur = 153,
++ .level = 55
++ },
++ {
++ .volt = 3765,
++ .cur = 153,
++ .level = 50
++ },
++ {
++ .volt = 3748,
++ .cur = 172,
++ .level = 45
++ },
++ {
++ .volt = 3740,
++ .cur = 153,
++ .level = 40
++ },
++ {
++ .volt = 3714,
++ .cur = 175,
++ .level = 35
++ },
++ {
++ .volt = 3710,
++ .cur = 156,
++ .level = 30
++ },
++ {
++ .volt = 3963,
++ .cur = 156,
++ .level = 25
++ },
++ {
++ .volt = 3672,
++ .cur = 178,
++ .level = 20
++ },
++ {
++ .volt = 3651,
++ .cur = 178,
++ .level = 15
++ },
++ {
++ .volt = 3629,
++ .cur = 178,
++ .level = 10
++ },
++ {
++ .volt = 3612,
++ .cur = 162,
++ .level = 5
++ },
++ {
++ .volt = 3605,
++ .cur = 162,
++ .level = 0
++ },
++};
++
++static const struct s3c_adc_bat_thresh bat_lut_acin[] = {
++ {
++ .volt = 4200,
++ .cur = 0,
++ .level = 100
++ },
++ {
++ .volt = 4190,
++ .cur = 0,
++ .level = 99
++ },
++ {
++ .volt = 4178,
++ .cur = 0,
++ .level = 95
++ },
++ {
++ .volt = 4110,
++ .cur = 0,
++ .level = 70
++ },
++ {
++ .volt = 4076,
++ .cur = 0,
++ .level = 65
++ },
++ {
++ .volt = 4046,
++ .cur = 0,
++ .level = 60
++ },
++ {
++ .volt = 4021,
++ .cur = 0,
++ .level = 55
++ },
++ {
++ .volt = 3999,
++ .cur = 0,
++ .level = 50
++ },
++ {
++ .volt = 3982,
++ .cur = 0,
++ .level = 45
++ },
++ {
++ .volt = 3965,
++ .cur = 0,
++ .level = 40
++ },
++ {
++ .volt = 3957,
++ .cur = 0,
++ .level = 35
++ },
++ {
++ .volt = 3948,
++ .cur = 0,
++ .level = 30
++ },
++ {
++ .volt = 3936,
++ .cur = 0,
++ .level = 25
++ },
++ {
++ .volt = 3927,
++ .cur = 0,
++ .level = 20
++ },
++ {
++ .volt = 3906,
++ .cur = 0,
++ .level = 15
++ },
++ {
++ .volt = 3880,
++ .cur = 0,
++ .level = 10
++ },
++ {
++ .volt = 3829,
++ .cur = 0,
++ .level = 5
++ },
++ {
++ .volt = 3820,
++ .cur = 0,
++ .level = 0
++ },
++};
++
++int rx1950_bat_init(void)
++{
++ int ret;
++
++ ret = gpio_request(S3C2410_GPJ(2), "rx1950-charger-enable-1");
++ if (ret)
++ goto err_gpio1;
++ ret = gpio_request(S3C2410_GPJ(3), "rx1950-charger-enable-2");
++ if (ret)
++ goto err_gpio2;
++
++ return 0;
++
++err_gpio2:
++ gpio_free(S3C2410_GPJ(2));
++err_gpio1:
++ return ret;
++}
++
++void rx1950_bat_exit(void)
++{
++ gpio_free(S3C2410_GPJ(2));
++ gpio_free(S3C2410_GPJ(3));
++}
++
++void rx1950_enable_charger(void)
++{
++ gpio_direction_output(S3C2410_GPJ(2), 1);
++ gpio_direction_output(S3C2410_GPJ(3), 1);
++}
++
++void rx1950_disable_charger(void)
++{
++ gpio_direction_output(S3C2410_GPJ(2), 0);
++ gpio_direction_output(S3C2410_GPJ(3), 0);
++}
++
++static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
++ .init = rx1950_bat_init,
++ .exit = rx1950_bat_exit,
++ .enable_charger = rx1950_enable_charger,
++ .disable_charger = rx1950_disable_charger,
++ .gpio_charge_finished = S3C2410_GPF(3),
++ .lut_noac = bat_lut_noac,
++ .lut_noac_cnt = ARRAY_SIZE(bat_lut_noac),
++ .lut_acin = bat_lut_acin,
++ .lut_acin_cnt = ARRAY_SIZE(bat_lut_acin),
++ .volt_channel = 0,
++ .current_channel = 1,
++ .volt_mult = 4235,
++ .current_mult = 2900,
++ .internal_impedance = 200,
++};
++
++static struct platform_device rx1950_battery = {
++ .name = "s3c-adc-battery",
++ .id = -1,
++ .dev = {
++ .parent = &s3c_device_adc.dev,
++ .platform_data = &rx1950_bat_cfg,
++ },
++};
++
+ static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
+ .displays = &rx1950_display,
+ .num_displays = 1,
+@@ -503,6 +817,8 @@ static struct platform_device *rx1950_devices[] __initdata = {
+ &s3c_device_timer[1],
+ &rx1950_backlight,
+ &rx1950_device_gpiokeys,
++ &power_supply,
++ &rx1950_battery,
+ };
+
+ static struct clk *rx1950_clocks[] __initdata = {
+--
+1.7.2.2
+
diff --git a/recipes/linux/linux-2.6.35/rx1950/0004-rx1950-add-LEDs-support.patch b/recipes/linux/linux-2.6.35/rx1950/0004-rx1950-add-LEDs-support.patch
new file mode 100644
index 0000000000..36ac70f467
--- /dev/null
+++ b/recipes/linux/linux-2.6.35/rx1950/0004-rx1950-add-LEDs-support.patch
@@ -0,0 +1,71 @@
+From 2133ac2c163fb3963eb2463b1482a525112ea6e1 Mon Sep 17 00:00:00 2001
+From: Vasily Khoruzhick <anarsoul@gmail.com>
+Date: Fri, 23 Jul 2010 17:06:47 +0300
+Subject: [PATCH 04/20] rx1950: add LEDs support
+
+Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
+---
+ arch/arm/mach-s3c2440/mach-rx1950.c | 33 +++++++++++++++++++++++++++++++++
+ 1 files changed, 33 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-s3c2440/mach-rx1950.c b/arch/arm/mach-s3c2440/mach-rx1950.c
+index 2bfa43a..53180da 100644
+--- a/arch/arm/mach-s3c2440/mach-rx1950.c
++++ b/arch/arm/mach-s3c2440/mach-rx1950.c
+@@ -29,6 +29,7 @@
+ #include <linux/pwm_backlight.h>
+ #include <linux/pwm.h>
+ #include <linux/s3c_adc_battery.h>
++#include <linux/leds.h>
+
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+@@ -415,6 +416,37 @@ void rx1950_disable_charger(void)
+ gpio_direction_output(S3C2410_GPJ(3), 0);
+ }
+
++static struct gpio_led rx1950_leds_desc[] = {
++ {
++ .name = "Green",
++ .default_trigger = "main-battery-charging-or-full",
++ .gpio = S3C2410_GPA(6),
++ },
++ {
++ .name = "Red",
++ .default_trigger = "main-battery-full",
++ .gpio = S3C2410_GPA(7),
++ },
++ {
++ .name = "Blue",
++ .default_trigger = "rx1950-acx-mem",
++ .gpio = S3C2410_GPA(11),
++ },
++};
++
++static struct gpio_led_platform_data rx1950_leds_pdata = {
++ .num_leds = ARRAY_SIZE(rx1950_leds_desc),
++ .leds = rx1950_leds_desc,
++};
++
++static struct platform_device rx1950_leds = {
++ .name = "leds-gpio",
++ .id = -1,
++ .dev = {
++ .platform_data = &rx1950_leds_pdata,
++ },
++};
++
+ static struct s3c_adc_bat_pdata rx1950_bat_cfg = {
+ .init = rx1950_bat_init,
+ .exit = rx1950_bat_exit,
+@@ -819,6 +851,7 @@ static struct platform_device *rx1950_devices[] __initdata = {
+ &rx1950_device_gpiokeys,
+ &power_supply,
+ &rx1950_battery,
++ &rx1950_leds,
+ };
+
+ static struct clk *rx1950_clocks[] __initdata = {
+--
+1.7.2.2
+
diff --git a/recipes/linux/linux-2.6.35/rx1950/0005-s3c24xx-DMA-don-t-use-autoreload-feature.patch b/recipes/linux/linux-2.6.35/rx1950/0005-s3c24xx-DMA-don-t-use-autoreload-feature.patch
new file mode 100644
index 0000000000..ea2208e0fc
--- /dev/null
+++ b/recipes/linux/linux-2.6.35/rx1950/0005-s3c24xx-DMA-don-t-use-autoreload-feature.patch
@@ -0,0 +1,701 @@
+From 3f78c6a448e380c40c6cc9dff2b7175be8fc2b9a Mon Sep 17 00:00:00 2001
+From: Vasily Khoruzhick <anarsoul@gmail.com>
+Date: Thu, 12 Aug 2010 21:32:25 +0300
+Subject: [PATCH 05/20] s3c24xx: DMA: don't use autoreload feature
+
+Some integrated DMA-capable hardware doesn't like autoreload
+feature of s3c24xx DMA-engine, that's why s3cmci driver
+didn't work with DMA transfers enabled.
+
+I rewrote DMA driver not to use autoreload feature and removed
+all pre-loading features. Buffer re-load is fast enought to perform
+it in IRQ handler, and anyway I don't see any reason to waste CPU
+cycles on waiting for buffer load. Driver is much simplier now,
+it was tested with s3cmci and s3c24xx-i2s drivers on s3c2442 and
+s3c2410 SoCs and works just nice.
+
+Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
+---
+ arch/arm/mach-s3c2410/include/mach/dma.h | 17 +-
+ arch/arm/plat-s3c24xx/dma.c | 442 +++++-------------------------
+ 2 files changed, 75 insertions(+), 384 deletions(-)
+
+diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h
+index cf68136..1cbeff2 100644
+--- a/arch/arm/mach-s3c2410/include/mach/dma.h
++++ b/arch/arm/mach-s3c2410/include/mach/dma.h
+@@ -79,28 +79,15 @@ enum s3c2410_dma_state {
+ *
+ * There are no buffers loaded (the channel should be inactive)
+ *
+- * S3C2410_DMA_1LOADED
+- *
+- * There is one buffer loaded, however it has not been confirmed to be
+- * loaded by the DMA engine. This may be because the channel is not
+- * yet running, or the DMA driver decided that it was too costly to
+- * sit and wait for it to happen.
+- *
+ * S3C2410_DMA_1RUNNING
+ *
+- * The buffer has been confirmed running, and not finisged
+- *
+- * S3C2410_DMA_1LOADED_1RUNNING
++ * The buffer has been confirmed running, and not finished
+ *
+- * There is a buffer waiting to be loaded by the DMA engine, and one
+- * currently running.
+ */
+
+ enum s3c2410_dma_loadst {
+ S3C2410_DMALOAD_NONE,
+- S3C2410_DMALOAD_1LOADED,
+ S3C2410_DMALOAD_1RUNNING,
+- S3C2410_DMALOAD_1LOADED_1RUNNING,
+ };
+
+
+@@ -129,6 +116,7 @@ struct s3c2410_dma_buf {
+ dma_addr_t data; /* start of DMA data */
+ dma_addr_t ptr; /* where the DMA got to [1] */
+ void *id; /* client's id */
++ unsigned int timestamp;
+ };
+
+ /* [1] is this updated for both recv/send modes? */
+@@ -189,6 +177,7 @@ struct s3c2410_dma_chan {
+ struct s3c2410_dma_buf *curr; /* current dma buffer */
+ struct s3c2410_dma_buf *next; /* next buffer to load */
+ struct s3c2410_dma_buf *end; /* end of queue */
++ spinlock_t queue_lock;
+
+ /* system device */
+ struct sys_device dev;
+diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
+index 6ad274e..5ed045b 100644
+--- a/arch/arm/plat-s3c24xx/dma.c
++++ b/arch/arm/plat-s3c24xx/dma.c
+@@ -133,70 +133,6 @@ dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
+ #define dbg_showchan(chan) do { } while(0)
+ #endif /* CONFIG_S3C2410_DMA_DEBUG */
+
+-/* s3c2410_dma_stats_timeout
+- *
+- * Update DMA stats from timeout info
+-*/
+-
+-static void
+-s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
+-{
+- if (stats == NULL)
+- return;
+-
+- if (val > stats->timeout_longest)
+- stats->timeout_longest = val;
+- if (val < stats->timeout_shortest)
+- stats->timeout_shortest = val;
+-
+- stats->timeout_avg += val;
+-}
+-
+-/* s3c2410_dma_waitforload
+- *
+- * wait for the DMA engine to load a buffer, and update the state accordingly
+-*/
+-
+-static int
+-s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
+-{
+- int timeout = chan->load_timeout;
+- int took;
+-
+- if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
+- printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
+- return 0;
+- }
+-
+- if (chan->stats != NULL)
+- chan->stats->loads++;
+-
+- while (--timeout > 0) {
+- if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
+- took = chan->load_timeout - timeout;
+-
+- s3c2410_dma_stats_timeout(chan->stats, took);
+-
+- switch (chan->load_state) {
+- case S3C2410_DMALOAD_1LOADED:
+- chan->load_state = S3C2410_DMALOAD_1RUNNING;
+- break;
+-
+- default:
+- printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
+- }
+-
+- return 1;
+- }
+- }
+-
+- if (chan->stats != NULL) {
+- chan->stats->timeout_failed++;
+- }
+-
+- return 0;
+-}
+-
+ /* s3c2410_dma_loadbuffer
+ *
+ * load a buffer, and update the channel state
+@@ -206,66 +142,35 @@ static inline int
+ s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
+ struct s3c2410_dma_buf *buf)
+ {
+- unsigned long reload;
+-
+ if (buf == NULL) {
+ dmawarn("buffer is NULL\n");
+ return -EINVAL;
+ }
+
+- pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
++ pr_debug("%s: loading buff %p (0x%08lx,0x%06x)\n", __func__,
+ buf, (unsigned long)buf->data, buf->size);
+
+ /* check the state of the channel before we do anything */
+
+- if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+- dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
+- }
+-
+- if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
+- dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
+- }
++ if (chan->load_state != S3C2410_DMALOAD_NONE)
++ printk(KERN_ERR "dma%d: channel already has buffer loaded\n",
++ chan->number);
+
+- /* it would seem sensible if we are the last buffer to not bother
+- * with the auto-reload bit, so that the DMA engine will not try
+- * and load another transfer after this one has finished...
+- */
+- if (chan->load_state == S3C2410_DMALOAD_NONE) {
+- pr_debug("load_state is none, checking for noreload (next=%p)\n",
+- buf->next);
+- reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
+- } else {
+- //pr_debug("load_state is %d => autoreload\n", chan->load_state);
+- reload = S3C2410_DCON_AUTORELOAD;
+- }
+-
+- if ((buf->data & 0xf0000000) != 0x30000000) {
++ if ((buf->data & 0xf0000000) != 0x30000000)
+ dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
+- }
+
+ writel(buf->data, chan->addr_reg);
+
+ dma_wrreg(chan, S3C2410_DMA_DCON,
+- chan->dcon | reload | (buf->size/chan->xfer_unit));
++ chan->dcon | S3C2410_DCON_NORELOAD |
++ (buf->size/chan->xfer_unit));
+
+- chan->next = buf->next;
++ chan->curr = buf;
+
+ /* update the state of the channel */
++ chan->load_state = S3C2410_DMALOAD_1RUNNING;
+
+- switch (chan->load_state) {
+- case S3C2410_DMALOAD_NONE:
+- chan->load_state = S3C2410_DMALOAD_1LOADED;
+- break;
+-
+- case S3C2410_DMALOAD_1RUNNING:
+- chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
+- break;
+-
+- default:
+- dmawarn("dmaload: unknown state %d in loadbuffer\n",
+- chan->load_state);
+- break;
+- }
++ buf->timestamp = jiffies;
+
+ return 0;
+ }
+@@ -345,7 +250,6 @@ static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
+ dbg_showchan(chan);
+
+ /* enable the channel */
+-
+ if (!chan->irq_enabled) {
+ enable_irq(chan->irq);
+ chan->irq_enabled = 1;
+@@ -360,14 +264,6 @@ static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
+
+ pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
+
+-#if 0
+- /* the dma buffer loads should take care of clearing the AUTO
+- * reloading feature */
+- tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+- tmp &= ~S3C2410_DCON_NORELOAD;
+- dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+-#endif
+-
+ s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
+
+ dbg_showchan(chan);
+@@ -377,43 +273,11 @@ static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
+ * the first buffer is finished, the new one will be loaded onto
+ * the channel */
+
+- if (chan->next != NULL) {
+- if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+-
+- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+- pr_debug("%s: buff not yet loaded, no more todo\n",
+- __func__);
+- } else {
+- chan->load_state = S3C2410_DMALOAD_1RUNNING;
+- s3c2410_dma_loadbuffer(chan, chan->next);
+- }
+-
+- } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
+- s3c2410_dma_loadbuffer(chan, chan->next);
+- }
+- }
+-
+-
+ local_irq_restore(flags);
+
+ return 0;
+ }
+
+-/* s3c2410_dma_canload
+- *
+- * work out if we can queue another buffer into the DMA engine
+-*/
+-
+-static int
+-s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
+-{
+- if (chan->load_state == S3C2410_DMALOAD_NONE ||
+- chan->load_state == S3C2410_DMALOAD_1RUNNING)
+- return 1;
+-
+- return 0;
+-}
+-
+ /* s3c2410_dma_enqueue
+ *
+ * queue an given buffer for dma transfer.
+@@ -462,47 +326,19 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id,
+
+ local_irq_save(flags);
+
+- if (chan->curr == NULL) {
+- /* we've got nothing loaded... */
+- pr_debug("%s: buffer %p queued onto empty channel\n",
+- __func__, buf);
+-
+- chan->curr = buf;
+- chan->end = buf;
+- chan->next = NULL;
++ if (chan->end == NULL) {
++ pr_debug("dma%d: queued buffer onto empty channel\n",
++ chan->number);
++ chan->next = buf;
++ chan->end = buf;
+ } else {
+- pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
+- chan->number, __func__, buf);
+-
+- if (chan->end == NULL)
+- pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
+- chan->number, __func__, chan);
+-
++ pr_debug("dma%d: queued buffer onto non-empty channel\n",
++ chan->number);
+ chan->end->next = buf;
+ chan->end = buf;
+ }
+
+- /* if necessary, update the next buffer field */
+- if (chan->next == NULL)
+- chan->next = buf;
+-
+- /* check to see if we can load a buffer */
+- if (chan->state == S3C2410_DMA_RUNNING) {
+- if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
+- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+- printk(KERN_ERR "dma%d: loadbuffer:"
+- "timeout loading buffer\n",
+- chan->number);
+- dbg_showchan(chan);
+- local_irq_restore(flags);
+- return -EINVAL;
+- }
+- }
+-
+- while (s3c2410_dma_canload(chan) && chan->next != NULL) {
+- s3c2410_dma_loadbuffer(chan, chan->next);
+- }
+- } else if (chan->state == S3C2410_DMA_IDLE) {
++ if (chan->state == S3C2410_DMA_IDLE) {
+ if (chan->flags & S3C2410_DMAF_AUTOSTART) {
+ s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
+ S3C2410_DMAOP_START);
+@@ -529,51 +365,6 @@ s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
+ }
+ }
+
+-/* s3c2410_dma_lastxfer
+- *
+- * called when the system is out of buffers, to ensure that the channel
+- * is prepared for shutdown.
+-*/
+-
+-static inline void
+-s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
+-{
+-#if 0
+- pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
+- chan->number, chan->load_state);
+-#endif
+-
+- switch (chan->load_state) {
+- case S3C2410_DMALOAD_NONE:
+- break;
+-
+- case S3C2410_DMALOAD_1LOADED:
+- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+- /* flag error? */
+- printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
+- chan->number, __func__);
+- return;
+- }
+- break;
+-
+- case S3C2410_DMALOAD_1LOADED_1RUNNING:
+- /* I belive in this case we do not have anything to do
+- * until the next buffer comes along, and we turn off the
+- * reload */
+- return;
+-
+- default:
+- pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
+- chan->number, chan->load_state);
+- return;
+-
+- }
+-
+- /* hopefully this'll shut the damned thing up after the transfer... */
+- dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
+-}
+-
+-
+ #define dmadbg2(x...)
+
+ static irqreturn_t
+@@ -582,57 +373,25 @@ s3c2410_dma_irq(int irq, void *devpw)
+ struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
+ struct s3c2410_dma_buf *buf;
+
++ /* Check for orphaned irq */
++ if (chan->state == S3C2410_DMA_IDLE)
++ return IRQ_HANDLED;
++
+ buf = chan->curr;
+
+ dbg_showchan(chan);
+
+ /* modify the channel state */
+
+- switch (chan->load_state) {
+- case S3C2410_DMALOAD_1RUNNING:
+- /* TODO - if we are running only one buffer, we probably
+- * want to reload here, and then worry about the buffer
+- * callback */
+-
+- chan->load_state = S3C2410_DMALOAD_NONE;
+- break;
+-
+- case S3C2410_DMALOAD_1LOADED:
+- /* iirc, we should go back to NONE loaded here, we
+- * had a buffer, and it was never verified as being
+- * loaded.
+- */
+-
++ if (chan->load_state == S3C2410_DMALOAD_1RUNNING)
+ chan->load_state = S3C2410_DMALOAD_NONE;
+- break;
+-
+- case S3C2410_DMALOAD_1LOADED_1RUNNING:
+- /* we'll worry about checking to see if another buffer is
+- * ready after we've called back the owner. This should
+- * ensure we do not wait around too long for the DMA
+- * engine to start the next transfer
+- */
+-
+- chan->load_state = S3C2410_DMALOAD_1LOADED;
+- break;
+-
+- case S3C2410_DMALOAD_NONE:
++ else
+ printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
+- chan->number);
+- break;
+-
+- default:
+- printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
+- chan->number, chan->load_state);
+- break;
+- }
++ chan->number);
+
+ if (buf != NULL) {
+- /* update the chain to make sure that if we load any more
+- * buffers when we call the callback function, things should
+- * work properly */
+-
+- chan->curr = buf->next;
++ chan->curr = NULL;
++ chan->next = buf->next;
+ buf->next = NULL;
+
+ if (buf->magic != BUF_MAGIC) {
+@@ -640,12 +399,14 @@ s3c2410_dma_irq(int irq, void *devpw)
+ chan->number, __func__, buf);
+ return IRQ_HANDLED;
+ }
+-
++ pr_debug("dma%d: transfer of size %d took %u ms\n",
++ chan->number,
++ buf->size,
++ jiffies_to_msecs(jiffies - buf->timestamp));
+ s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
+
+ /* free resouces */
+ s3c2410_dma_freebuf(buf);
+- } else {
+ }
+
+ /* only reload if the channel is still running... our buffer done
+@@ -655,53 +416,36 @@ s3c2410_dma_irq(int irq, void *devpw)
+ /* todo: check that when the channel is shut-down from inside this
+ * function, we cope with unsetting reload, etc */
+
+- if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
+- unsigned long flags;
+-
+- switch (chan->load_state) {
+- case S3C2410_DMALOAD_1RUNNING:
+- /* don't need to do anything for this state */
+- break;
+-
+- case S3C2410_DMALOAD_NONE:
+- /* can load buffer immediately */
+- break;
+-
+- case S3C2410_DMALOAD_1LOADED:
+- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+- /* flag error? */
+- printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
+- chan->number, __func__);
+- return IRQ_HANDLED;
+- }
+-
+- break;
+-
+- case S3C2410_DMALOAD_1LOADED_1RUNNING:
+- goto no_load;
+-
+- default:
+- printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
+- chan->number, chan->load_state);
+- return IRQ_HANDLED;