diff options
| author | Vasily Khoruzhick <anarsoul@gmail.com> | 2010-09-10 10:54:13 +0000 |
|---|---|---|
| committer | Eric Bénard <eric@eukrea.com> | 2010-09-11 18:58:19 +0200 |
| commit | 7e92d21ca7b6e6685c80243d3b09c06aedaa3354 (patch) | |
| tree | 017f60781a09e9b93af24b09cc7113d823a97c46 | |
| parent | 18bfe69b58341220399c1a1f9acc0bbc7a905eb8 (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>
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; |
