diff -urN -X ../dontdiff linux-2.6.11-rc5/arch/arm/mach-s3c2410/Kconfig linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/Kconfig --- linux-2.6.11-rc5/arch/arm/mach-s3c2410/Kconfig 2005-02-25 11:14:06.000000000 +0000 +++ linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/Kconfig 2005-03-03 15:03:21.000000000 +0000 @@ -5,6 +5,7 @@ config ARCH_BAST bool "Simtec Electronics BAST (EB2410ITX)" select CPU_S3C2410 + select SIMTEC_AUDIO help Say Y here if you are using the Simtec Electronics EB2410ITX development board (also known as BAST) @@ -29,6 +30,7 @@ config MACH_VR1000 bool "Thorcom VR1000" select CPU_S3C2410 + select SIMTEC_AUDIO help Say Y here if you are using the Thorcom VR1000 board. @@ -46,6 +48,12 @@ endmenu +config SIMTEC_AUDIO + bool "Simtec Audio support" + depends on ARCH_BAST || MACH_VR1000 + help + Say y here for the base Simtec audio support. + config CPU_S3C2410 bool depends on ARCH_S3C2410 @@ -69,6 +77,12 @@ use the S3C2410's DMA system to move data to and from the peripheral blocks. +config S3C2410_DMA_SYSFS + bool "S3C2410 DMA sysfs export" + depends on S3C2410_DMA + help + Export DMA channel state via the sysfs interface. + config S3C2410_DMA_DEBUG bool "S3C2410 DMA support debug" depends on ARCH_S3C2410 && S3C2410_DMA diff -urN -X ../dontdiff linux-2.6.11-rc5/arch/arm/mach-s3c2410/Makefile linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/Makefile --- linux-2.6.11-rc5/arch/arm/mach-s3c2410/Makefile 2005-01-04 10:57:48.000000000 +0000 +++ linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/Makefile 2005-03-03 15:03:44.000000000 +0000 @@ -14,6 +14,7 @@ obj-$(CONFIG_CPU_S3C2410) += s3c2410.o obj-$(CONFIG_S3C2410_DMA) += dma.o +obj-$(CONFIG_S3C2410_DMA_SYSFS) += dma-sysfs.o # Power Management support @@ -30,3 +31,5 @@ obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o + +obj-$(CONFIG_SIMTEC_AUDIO) += audio-simtec.o \ No newline at end of file diff -urN -X ../dontdiff linux-2.6.11-rc5/arch/arm/mach-s3c2410/audio-simtec.c linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/audio-simtec.c --- linux-2.6.11-rc5/arch/arm/mach-s3c2410/audio-simtec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/audio-simtec.c 2005-03-15 11:28:48.000000000 +0000 @@ -0,0 +1,138 @@ +/* linux/arch/arm/mach-s3c2410/audio-simtec.c + * + * Copyright (c) 2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include "devs.h" +#include "pm.h" + +/* platform ops for audio */ + +static int simtec_audio_startup(struct s3c24xx_iis_ops *ops) +{ + unsigned int tmp; + unsigned long flags; + + local_irq_save(flags); + + tmp = __raw_readb(BAST_VA_CTRL1); + tmp &= ~BAST_CPLD_CTRL1_LRMASK; + tmp |= BAST_CPLD_CTRL1_LRCDAC; + __raw_writeb(tmp, BAST_VA_CTRL1); + + local_irq_restore(flags); + + return 0; +} + +static void simtec_audio_shutdown(struct s3c24xx_iis_ops *ops) +{ + unsigned int tmp; + unsigned long flags; + + /* switch off LR clock routing */ + + local_irq_save(flags); + + tmp = __raw_readb(BAST_VA_CTRL1); + tmp &= ~BAST_CPLD_CTRL1_LRMASK; + tmp |= BAST_CPLD_CTRL1_LRCOFF; + __raw_writeb(tmp, BAST_VA_CTRL1); + + local_irq_restore(flags); +} + +static int simtec_audio_matchdev(struct device *dev) +{ + printk(KERN_INFO "%s: dev=%p\n", __FUNCTION__, dev); + + if (dev->parent == NULL || dev->parent->parent == NULL) + return 0; + + printk("%s: parent %s\n", __FUNCTION__, dev->parent->bus_id); + printk("%s: parent2 %s\n", __FUNCTION__, dev->parent->parent->bus_id); + + if (strncmp(dev->parent->bus_id, "i2c", strlen("i2c")) != 0) + return 0; + + if (strncmp(dev->parent->parent->bus_id, "s3c24", + strlen("s3c24")) == 0) + return 1; + + return 0; +} + +/* device registration info */ + +static struct s3c24xx_iis_ops simtec_audio_ops = { + .startup = simtec_audio_startup, + .shutdown = simtec_audio_shutdown, +}; + +static struct s3c24xx_platdata_iis simtec_audio_platdata = { + .ops = &simtec_audio_ops, + .codec_clk = "clkout0", + .match_dev = simtec_audio_matchdev, +}; + +static struct platform_device audio_dev = { + .name = "s3c24xx-tlv320aic23", + .dev = { + .parent = &s3c_device_iis.dev, + .platform_data = &simtec_audio_platdata, + }, +}; + +static int __init simtec_audio_init(void) +{ + if (!machine_is_bast() && !machine_is_vr1000()) + return 0; + + printk(KERN_INFO "Simtec TLV320AIC23 Audio platform driver\n"); + + simtec_audio_shutdown(NULL); + + platform_device_register(&s3c_device_iis); + return platform_device_register(&audio_dev); +} + +device_initcall(simtec_audio_init); diff -urN -X ../dontdiff linux-2.6.11-rc5/arch/arm/mach-s3c2410/dma-sysfs.c linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/dma-sysfs.c --- linux-2.6.11-rc5/arch/arm/mach-s3c2410/dma-sysfs.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/dma-sysfs.c 2005-03-03 16:05:50.000000000 +0000 @@ -0,0 +1,276 @@ +/* linux/arch/arm/mach-bast/dma-sysfs.c + * + * (c) 2005 Simtec Electronics + * Ben Dooks + * + * S3C2410 DMA core sysfs interface + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +extern struct sysdev_class dma_sysclass; +extern s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS]; + +#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) + + +static const char *s3c2410_dma_decode_state(s3c2410_dma_state_t state) +{ + switch (state) { + case S3C2410_DMA_IDLE: + return "Idle"; + case S3C2410_DMA_RUNNING: + return "Running"; + case S3C2410_DMA_PAUSED: + return "Paused"; + default: + return "Invalid"; + } + + return NULL; +} + +static const char *s3c2410_dma_decode_loadstate(s3c2410_dma_loadst_t state) +{ + switch (state) { + case S3C2410_DMALOAD_NONE: + return "Nothing Loaded"; + case S3C2410_DMALOAD_1LOADED: + return "1 Loaded"; + case S3C2410_DMALOAD_1RUNNING: + return "1 Running"; + case S3C2410_DMALOAD_1LOADED_1RUNNING: + return "1 Loaded, 1 Running"; + default: + return "Invalid Load State"; + } + + return NULL; +} + +static const char *s3c2410_dma_decode_source(s3c2410_dmasrc_t source) +{ + switch (source) { + case S3C2410_DMASRC_HW: + return "Hardware"; + case S3C2410_DMASRC_MEM: + return "Memory"; + default: + return "Unknown Source"; + } + + return NULL; +} + + +struct outbuff { + char *buff; + int offset; + int size; +}; + +static inline void outbuf_init(struct outbuff *ob, char *buf, int size) +{ + ob->buff = buf; + ob->offset = 0; + ob->size = size; +} + +static void outbuf_pf(struct outbuff *ob, const char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + + ob->offset += vsnprintf(ob->buff + ob->offset, + ob->size - ob->offset, + fmt, va); + va_end(va); +} + +static void dma_sysfs_showregs(s3c2410_dma_chan_t *chan, struct outbuff *buf) +{ + outbuf_pf(buf, "Hardware Registers:\n\n"); + + outbuf_pf(buf, " DISRC \t\t\t%08lx\n", readl(chan->regs + 0x00)); + outbuf_pf(buf, " DISRCC\t\t\t%08lx\n", readl(chan->regs + 0x04)); + outbuf_pf(buf, " DIDST \t\t\t%08lx\n", readl(chan->regs + 0x08)); + outbuf_pf(buf, " DIDSTC\t\t\t%08lx\n", readl(chan->regs + 0x0C)); + outbuf_pf(buf, " DCON \t\t\t%08lx\n", readl(chan->regs + 0x10)); + outbuf_pf(buf, " DSTAT \t\t\t%08lx\n", readl(chan->regs + 0x14)); + outbuf_pf(buf, " DCSRC \t\t\t%08lx\n", readl(chan->regs + 0x18)); + outbuf_pf(buf, " DCDST \t\t\t%08lx\n", readl(chan->regs + 0x1c)); + outbuf_pf(buf, " DMTRG \t\t\t%08lx\n", readl(chan->regs + 0x20)); +} + +static void dma_sysfs_showbuf(s3c2410_dma_chan_t *chan, + struct outbuff *buf, + s3c2410_dma_buf_t *ptr) +{ + if (ptr == NULL) + return; + + outbuf_pf(buf, " buff %p: data=%08x, size=%08x, id=%08x\n", + ptr, ptr->data, ptr->size, ptr->id); +} + +static void dma_sysfs_showbuffers(s3c2410_dma_chan_t *chan, struct outbuff *buf) +{ + s3c2410_dma_buf_t *ptr = chan->next; + unsigned long flags; + + local_irq_save(flags); + + outbuf_pf(buf, "Current Buffer:\n"); + dma_sysfs_showbuf(chan, buf, chan->curr); + + outbuf_pf(buf, "\nBuffer Queue: %p -> %p\n", chan->next, chan->end); + + for (; ptr != NULL; ptr = ptr->next) + dma_sysfs_showbuf(chan, buf, ptr); + + local_irq_restore(flags); +} + +static void dma_sysfs_showstate(s3c2410_dma_chan_t *chan, struct outbuff *buf) +{ + outbuf_pf(buf, "IRQ:\t\t\t\t%d\n", chan->irq); + outbuf_pf(buf, "Register Base:\t\t\t0x%08x\n", chan->regs); + outbuf_pf(buf, "Address Register:\t\t0x%08lx\n", chan->addr_reg); + outbuf_pf(buf, "Hardware Register:\t\t0x%08lx\n", chan->dev_addr); + outbuf_pf(buf, "Load Timeout:\t\t\t0x%08x\n", chan->load_timeout); + outbuf_pf(buf, "Data Source:\t\t\t%s\n", + s3c2410_dma_decode_source(chan->source)); + + outbuf_pf(buf, "Channel State:\t\t\t%s (%d)\n", + s3c2410_dma_decode_state(chan->state), chan->state); + outbuf_pf(buf, "Load State:\t\t\t%s (%d)\n", + s3c2410_dma_decode_loadstate(chan->load_state), + chan->load_state); + + if (chan->client != NULL) { + outbuf_pf(buf, "Claimed by:\t\t\t%s\n", + chan->client->name); + } else { + outbuf_pf(buf, "Claimed by:\t\t\tNo-one\n"); + } +} + +static inline s3c2410_dma_chan_t *dev_to_chan(struct sys_device *dev) +{ + return &s3c2410_chans[dev->id]; +} + +static ssize_t dma_sysfs_show_regs(struct sys_device *dev, char *buf) +{ + s3c2410_dma_chan_t *cp = dev_to_chan(dev); + struct outbuff buff; + + outbuf_init(&buff, buf, PAGE_SIZE); + dma_sysfs_showregs(cp, &buff); + + return buff.offset; +} + +static ssize_t dma_sysfs_show_state(struct sys_device *dev, char *buf) +{ + s3c2410_dma_chan_t *cp = dev_to_chan(dev); + struct outbuff buff; + + outbuf_init(&buff, buf, PAGE_SIZE); + dma_sysfs_showstate(cp, &buff); + + return buff.offset; +} + +static ssize_t dma_sysfs_show_buffers(struct sys_device *dev, char *buf) +{ + s3c2410_dma_chan_t *cp = dev_to_chan(dev); + struct outbuff buff; + + outbuf_init(&buff, buf, PAGE_SIZE); + dma_sysfs_showbuffers(cp, &buff); + + return buff.offset; +} + +static ssize_t dma_sysfs_show_all(struct sys_device *dev, char *buf) +{ + s3c2410_dma_chan_t *cp = dev_to_chan(dev); + struct outbuff buff; + + outbuf_init(&buff, buf, PAGE_SIZE); + + dma_sysfs_showstate(cp, &buff); + dma_sysfs_showregs(cp, &buff); + dma_sysfs_showbuffers(cp, &buff); + + return buff.offset; +} + +static SYSDEV_ATTR(all, S_IRUGO, dma_sysfs_show_all, NULL); +static SYSDEV_ATTR(regs, S_IRUGO, dma_sysfs_show_regs, NULL); +static SYSDEV_ATTR(state, S_IRUGO, dma_sysfs_show_state, NULL); +static SYSDEV_ATTR(buffers, S_IRUGO, dma_sysfs_show_buffers, NULL); + +static struct sysdev_attribute *attrs[] = { + &attr_all, + &attr_regs, + &attr_state, + &attr_buffers, +}; + +static int dma_sysfs_attach(struct sys_device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(attrs); i++) + sysdev_create_file(dev, attrs[i]); + + return 0; +} + +static int dma_sysfs_remove(struct sys_device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(attrs); i++) + sysdev_create_file(dev, attrs[i]); + + return 0; +} + +static struct sysdev_driver dma_sysfs_driver = { + .add = dma_sysfs_attach, + .remove = dma_sysfs_remove, +}; + +static int __init s3c2410_init_dma_sysfs(void) +{ + printk("S3C24XX DMA sysfs support, (c) 2005 Simtec Electronics\n"); + + return sysdev_driver_register(&dma_sysclass, &dma_sysfs_driver); +} + +__initcall(s3c2410_init_dma_sysfs); diff -urN -X ../dontdiff linux-2.6.11-rc5/arch/arm/mach-s3c2410/dma.c linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/dma.c --- linux-2.6.11-rc5/arch/arm/mach-s3c2410/dma.c 2005-02-25 11:14:06.000000000 +0000 +++ linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/dma.c 2005-03-08 17:23:46.000000000 +0000 @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-bast/dma.c * - * (c) 2003,2004 Simtec Electronics + * (c) 2003-2005 Simtec Electronics * Ben Dooks * * S3C2410 DMA core @@ -12,6 +12,7 @@ * published by the Free Software Foundation. * * Changelog: + * 27-Feb-2005 BJD Added kmem cache for dma descriptors * 18-Nov-2004 BJD Removed error for loading onto stopped channel * 10-Nov-2004 BJD Ensure all external symbols exported for modules * 10-Nov-2004 BJD Use sys_device and sysdev_class for power management @@ -57,6 +58,7 @@ /* io map for dma */ static void __iomem *dma_base; +static kmem_cache_t *dma_kmem; /* dma channel state information */ s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS]; @@ -190,6 +192,15 @@ if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { took = chan->load_timeout - timeout; + if (0) { + unsigned long a = dma_rdreg(chan, S3C2410_DMA_DCSRC); + unsigned long b = dma_rdreg(chan, S3C2410_DMA_DISRC); + + if (a != b && (a-b) > 0x0c) { + printk(KERN_DEBUG "DCSRC[%lx] != DISRC[%lx]\n", a, b); + } + } + s3c2410_dma_stats_timeout(chan->stats, took); switch (chan->load_state) { @@ -364,14 +375,7 @@ /* start the channel going */ - tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); - tmp &= ~S3C2410_DMASKTRIG_STOP; - tmp |= S3C2410_DMASKTRIG_ON; - dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); - - pr_debug("wrote %08lx to DMASKTRIG\n", tmp); - -#if 0 +#if 1 /* the dma buffer loads should take care of clearing the AUTO * reloading feature */ tmp = dma_rdreg(chan, S3C2410_DMA_DCON); @@ -379,6 +383,13 @@ dma_wrreg(chan, S3C2410_DMA_DCON, tmp); #endif + tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + tmp &= ~S3C2410_DMASKTRIG_STOP; + tmp |= S3C2410_DMASKTRIG_ON; + dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + + pr_debug("wrote %08lx to DMASKTRIG\n", tmp); + s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); dbg_showchan(chan); @@ -432,10 +443,9 @@ pr_debug("%s: id=%p, data=%08x, size=%d\n", __FUNCTION__, id, (unsigned int)data, size); - buf = (s3c2410_dma_buf_t *)kmalloc(sizeof(*buf), GFP_ATOMIC); + buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC); if (buf == NULL) { - pr_debug("%s: out of memory (%d alloc)\n", - __FUNCTION__, sizeof(*buf)); + printk(KERN_ERR "dma<%d> no memory for buffer\n", channel); return -ENOMEM; } @@ -494,6 +504,8 @@ } else if (chan->state == S3C2410_DMA_IDLE) { if (chan->flags & S3C2410_DMAF_AUTOSTART) { s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START); + } else { + printk(KERN_DEBUG "loading onto stopped channel\n"); } } @@ -511,7 +523,7 @@ buf->magic = -1; if (magicok) { - kfree(buf); + kmem_cache_free(dma_kmem, buf); } else { printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); } @@ -764,7 +776,6 @@ local_irq_save(flags); - if (chan->client != client) { printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", channel, chan->client, client); @@ -807,7 +818,7 @@ tmp |= S3C2410_DMASKTRIG_STOP; dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); -#if 0 +#if 1 /* should also clear interrupts, according to WinCE BSP */ tmp = dma_rdreg(chan, S3C2410_DMA_DCON); tmp |= S3C2410_DCON_NORELOAD; @@ -822,6 +833,20 @@ return 0; } +static void s3c2410_dma_showchan(s3c2410_dma_chan_t *chan) +{ + printk(KERN_DEBUG "dma[%d]: st %d, lst %d, cli %p, dcon %08lx\n", + chan->number, chan->state, + chan->load_state, chan->client, chan->dcon); + printk(KERN_DEBUG "dma[%d]: CSRC=%x, ISRC=%x, STAT=%x, CON=%x, MT=%x\n", + chan->number, + dma_rdreg(chan, S3C2410_DMA_DCSRC), + dma_rdreg(chan, S3C2410_DMA_DISRC), + dma_rdreg(chan, S3C2410_DMA_DSTAT), + dma_rdreg(chan, S3C2410_DMA_DCON), + dma_rdreg(chan, S3C2410_DMA_DMASKTRIG)); +} + /* s3c2410_dma_flush * * stop the channel, and remove all current and pending transfers @@ -836,6 +861,8 @@ local_irq_save(flags); + s3c2410_dma_showchan(chan); + if (chan->state != S3C2410_DMA_IDLE) { pr_debug("%s: stopping channel...\n", __FUNCTION__ ); s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); @@ -846,7 +873,8 @@ buf = chan->next; chan->curr = chan->next = chan->end = NULL; - + chan->load_state = S3C2410_DMALOAD_NONE; + if (buf != NULL) { for ( ; buf != NULL; buf = next) { next = buf->next; @@ -859,6 +887,8 @@ } } + s3c2410_dma_showchan(chan); + local_irq_restore(flags); return 0; @@ -1122,12 +1152,20 @@ #define s3c2410_dma_resume NULL #endif /* CONFIG_PM */ -static struct sysdev_class dma_sysclass = { +struct sysdev_class dma_sysclass = { set_kset_name("s3c24xx-dma"), .suspend = s3c2410_dma_suspend, .resume = s3c2410_dma_resume, }; +/* kmem cache implementation */ + +static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f) +{ + memset(p, 0, sizeof(s3c2410_dma_buf_t)); +} + + /* initialisation code */ static int __init s3c2410_init_dma(void) @@ -1150,6 +1188,16 @@ goto err; } + dma_kmem = kmem_cache_create("dma_desc", sizeof(s3c2410_dma_buf_t), 0, + SLAB_HWCACHE_ALIGN, + s3c2410_dma_cache_ctor, NULL); + + if (dma_kmem == NULL) { + printk(KERN_ERR "dma failed to make kmem cache\n"); + ret = -ENOMEM; + goto err; + } + for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) { cp = &s3c2410_chans[channel]; @@ -1181,6 +1229,7 @@ return 0; err: + kmem_cache_destroy(dma_kmem); iounmap(dma_base); dma_base = NULL; return ret; diff -urN -X ../dontdiff linux-2.6.11-rc5/arch/arm/mach-s3c2410/mach-bast.c linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/mach-bast.c --- linux-2.6.11-rc5/arch/arm/mach-s3c2410/mach-bast.c 2005-02-25 11:14:06.000000000 +0000 +++ linux-2.6.11-rc5-audio9/arch/arm/mach-s3c2410/mach-bast.c 2005-03-15 12:49:40.000000000 +0000 @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -320,7 +321,6 @@ .select_chip = bast_nand_select, }; - /* Standard BAST devices */ static struct platform_device *bast_devices[] __initdata = { @@ -328,7 +328,6 @@ &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c, - &s3c_device_iis, &s3c_device_rtc, &s3c_device_nand, &bast_device_nor