diff options
Diffstat (limited to 'arch/arm/plat-s3c64xx')
-rw-r--r-- | arch/arm/plat-s3c64xx/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/dev-audio.c | 68 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/dma.c | 82 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/include/plat/dma-plat.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/include/plat/irqs.h | 10 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/include/plat/regs-clock.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/pm.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-s3c64xx/s3c6400-clock.c | 15 |
9 files changed, 148 insertions, 39 deletions
diff --git a/arch/arm/plat-s3c64xx/Kconfig b/arch/arm/plat-s3c64xx/Kconfig index 5ebd8b425a5..bcfa778614d 100644 --- a/arch/arm/plat-s3c64xx/Kconfig +++ b/arch/arm/plat-s3c64xx/Kconfig @@ -19,6 +19,7 @@ config PLAT_S3C64XX select S3C_GPIO_PULL_UPDOWN select S3C_GPIO_CFG_S3C24XX select S3C_GPIO_CFG_S3C64XX + select S3C_DEV_NAND select USB_ARCH_HAS_OHCI help Base platform code for any Samsung S3C64XX device diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile index 3c8882cd626..b85b4359e93 100644 --- a/arch/arm/plat-s3c64xx/Makefile +++ b/arch/arm/plat-s3c64xx/Makefile @@ -40,4 +40,5 @@ obj-$(CONFIG_S3C64XX_DMA) += dma.o obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0.o obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o -obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
\ No newline at end of file +obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o +obj-$(CONFIG_SND_S3C24XX_SOC) += dev-audio.o diff --git a/arch/arm/plat-s3c64xx/dev-audio.c b/arch/arm/plat-s3c64xx/dev-audio.c new file mode 100644 index 00000000000..1322beb40dd --- /dev/null +++ b/arch/arm/plat-s3c64xx/dev-audio.c @@ -0,0 +1,68 @@ +/* linux/arch/arm/plat-s3c/dev-audio.c + * + * Copyright 2009 Wolfson Microelectronics + * Mark Brown <broonie@opensource.wolfsonmicro.com> + * + + * 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 <linux/kernel.h> +#include <linux/string.h> +#include <linux/platform_device.h> + +#include <mach/irqs.h> +#include <mach/map.h> + +#include <plat/devs.h> + + +static struct resource s3c64xx_iis0_resource[] = { + [0] = { + .start = S3C64XX_PA_IIS0, + .end = S3C64XX_PA_IIS0 + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device s3c64xx_device_iis0 = { + .name = "s3c64xx-iis", + .id = 0, + .num_resources = ARRAY_SIZE(s3c64xx_iis0_resource), + .resource = s3c64xx_iis0_resource, +}; +EXPORT_SYMBOL(s3c64xx_device_iis0); + +static struct resource s3c64xx_iis1_resource[] = { + [0] = { + .start = S3C64XX_PA_IIS1, + .end = S3C64XX_PA_IIS1 + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device s3c64xx_device_iis1 = { + .name = "s3c64xx-iis", + .id = 1, + .num_resources = ARRAY_SIZE(s3c64xx_iis1_resource), + .resource = s3c64xx_iis1_resource, +}; +EXPORT_SYMBOL(s3c64xx_device_iis1); + +static struct resource s3c64xx_iisv4_resource[] = { + [0] = { + .start = S3C64XX_PA_IISV4, + .end = S3C64XX_PA_IISV4 + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device s3c64xx_device_iisv4 = { + .name = "s3c64xx-iis-v4", + .id = -1, + .num_resources = ARRAY_SIZE(s3c64xx_iisv4_resource), + .resource = s3c64xx_iisv4_resource, +}; +EXPORT_SYMBOL(s3c64xx_device_iisv4); diff --git a/arch/arm/plat-s3c64xx/dma.c b/arch/arm/plat-s3c64xx/dma.c index 67aa93dbb69..d554b936fcf 100644 --- a/arch/arm/plat-s3c64xx/dma.c +++ b/arch/arm/plat-s3c64xx/dma.c @@ -151,8 +151,6 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan, src = chan->dev_addr; dst = data; control0 = PL080_CONTROL_SRC_AHB2; - control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT; - control0 |= 2 << PL080_CONTROL_DWIDTH_SHIFT; control0 |= PL080_CONTROL_DST_INCR; break; @@ -160,8 +158,6 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan, src = data; dst = chan->dev_addr; control0 = PL080_CONTROL_DST_AHB2; - control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT; - control0 |= 2 << PL080_CONTROL_SWIDTH_SHIFT; control0 |= PL080_CONTROL_SRC_INCR; break; default: @@ -173,6 +169,8 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan, control1 = size >> chan->hw_width; /* size in no of xfers */ control0 |= PL080_CONTROL_PROT_SYS; /* always in priv. mode */ control0 |= PL080_CONTROL_TC_IRQ_EN; /* always fire IRQ */ + control0 |= (u32)chan->hw_width << PL080_CONTROL_DWIDTH_SHIFT; + control0 |= (u32)chan->hw_width << PL080_CONTROL_SWIDTH_SHIFT; lli->src_addr = src; lli->dst_addr = dst; @@ -339,19 +337,20 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id, struct s3c64xx_dma_buff *next; struct s3c64xx_dma_buff *buff; struct pl080s_lli *lli; + unsigned long flags; int ret; WARN_ON(!chan); if (!chan) return -EINVAL; - buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_KERNEL); + buff = kzalloc(sizeof(struct s3c64xx_dma_buff), GFP_ATOMIC); if (!buff) { printk(KERN_ERR "%s: no memory for buffer\n", __func__); return -ENOMEM; } - lli = dma_pool_alloc(dma_pool, GFP_KERNEL, &buff->lli_dma); + lli = dma_pool_alloc(dma_pool, GFP_ATOMIC, &buff->lli_dma); if (!lli) { printk(KERN_ERR "%s: no memory for lli\n", __func__); ret = -ENOMEM; @@ -366,6 +365,8 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id, s3c64xx_dma_fill_lli(chan, lli, data, size); + local_irq_save(flags); + if ((next = chan->next) != NULL) { struct s3c64xx_dma_buff *end = chan->end; struct pl080s_lli *endlli = end->lli; @@ -397,6 +398,8 @@ int s3c2410_dma_enqueue(unsigned int channel, void *id, s3c64xx_lli_to_regs(chan, lli); } + local_irq_restore(flags); + show_lli(lli); dbg_showchan(chan); @@ -560,26 +563,11 @@ int s3c2410_dma_free(unsigned int channel, struct s3c2410_dma_client *client) EXPORT_SYMBOL(s3c2410_dma_free); - -static void s3c64xx_dma_tcirq(struct s3c64xx_dmac *dmac, int offs) -{ - struct s3c2410_dma_chan *chan = dmac->channels + offs; - - /* note, we currently do not bother to work out which buffer - * or buffers have been completed since the last tc-irq. */ - - if (chan->callback_fn) - (chan->callback_fn)(chan, chan->curr->pw, 0, S3C2410_RES_OK); -} - -static void s3c64xx_dma_errirq(struct s3c64xx_dmac *dmac, int offs) -{ - printk(KERN_DEBUG "%s: offs %d\n", __func__, offs); -} - static irqreturn_t s3c64xx_dma_irq(int irq, void *pw) { struct s3c64xx_dmac *dmac = pw; + struct s3c2410_dma_chan *chan; + enum s3c2410_dma_buffresult res; u32 tcstat, errstat; u32 bit; int offs; @@ -588,14 +576,54 @@ static irqreturn_t s3c64xx_dma_irq(int irq, void *pw) errstat = readl(dmac->regs + PL080_ERR_STATUS); for (offs = 0, bit = 1; offs < 8; offs++, bit <<= 1) { + struct s3c64xx_dma_buff *buff; + + if (!(errstat & bit) && !(tcstat & bit)) + continue; + + chan = dmac->channels + offs; + res = S3C2410_RES_ERR; + if (tcstat & bit) { writel(bit, dmac->regs + PL080_TC_CLEAR); - s3c64xx_dma_tcirq(dmac, offs); + res = S3C2410_RES_OK; } - if (errstat & bit) { - s3c64xx_dma_errirq(dmac, offs); + if (errstat & bit) writel(bit, dmac->regs + PL080_ERR_CLEAR); + + /* 'next' points to the buffer that is next to the + * currently active buffer. + * For CIRCULAR queues, 'next' will be same as 'curr' + * when 'end' is the active buffer. + */ + buff = chan->curr; + while (buff && buff != chan->next + && buff->next != chan->next) + buff = buff->next; + + if (!buff) + BUG(); + + if (buff == chan->next) + buff = chan->end; + + s3c64xx_dma_bufffdone(chan, buff, res); + + /* Free the node and update curr, if non-circular queue */ + if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) { + chan->curr = buff->next; + s3c64xx_dma_freebuff(buff); + } + + /* Update 'next' */ + buff = chan->next; + if (chan->next == chan->end) { + chan->next = chan->curr; + if (!(chan->flags & S3C2410_DMAF_CIRCULAR)) + chan->end = NULL; + } else { + chan->next = buff->next; } } @@ -697,7 +725,7 @@ static int __init s3c64xx_dma_init(void) printk(KERN_INFO "%s: Registering DMA channels\n", __func__); - dma_pool = dma_pool_create("DMA-LLI", NULL, 32, 16, 0); + dma_pool = dma_pool_create("DMA-LLI", NULL, sizeof(struct pl080s_lli), 16, 0); if (!dma_pool) { printk(KERN_ERR "%s: failed to create pool\n", __func__); return -ENOMEM; diff --git a/arch/arm/plat-s3c64xx/include/plat/dma-plat.h b/arch/arm/plat-s3c64xx/include/plat/dma-plat.h index 0c30dd98672..8f76a1e474d 100644 --- a/arch/arm/plat-s3c64xx/include/plat/dma-plat.h +++ b/arch/arm/plat-s3c64xx/include/plat/dma-plat.h @@ -26,7 +26,7 @@ struct s3c64xx_dma_buff { struct s3c64xx_dma_buff *next; void *pw; - struct pl080_lli *lli; + struct pl080s_lli *lli; dma_addr_t lli_dma; }; diff --git a/arch/arm/plat-s3c64xx/include/plat/irqs.h b/arch/arm/plat-s3c64xx/include/plat/irqs.h index 743a70094d0..7956fd3bb19 100644 --- a/arch/arm/plat-s3c64xx/include/plat/irqs.h +++ b/arch/arm/plat-s3c64xx/include/plat/irqs.h @@ -194,9 +194,17 @@ #define IRQ_EINT_GROUP(group, no) (IRQ_EINT_GROUP##group##_BASE + (no)) +/* Define a group of interrupts for board-specific use (eg, for MFD + * interrupt controllers). */ +#define IRQ_BOARD_START (IRQ_EINT_GROUP9_BASE + IRQ_EINT_GROUP9_NR + 1) + +#define IRQ_BOARD_NR 16 + +#define IRQ_BOARD_END (IRQ_BOARD_START + IRQ_BOARD_NR) + /* Set the default NR_IRQS */ -#define NR_IRQS (IRQ_EINT_GROUP9_BASE + IRQ_EINT_GROUP9_NR + 1) +#define NR_IRQS (IRQ_BOARD_END + 1) #endif /* __ASM_PLAT_S3C64XX_IRQS_H */ diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h index a8777a755df..ff46e7fa957 100644 --- a/arch/arm/plat-s3c64xx/include/plat/regs-clock.h +++ b/arch/arm/plat-s3c64xx/include/plat/regs-clock.h @@ -51,8 +51,8 @@ #define S3C6400_CLKDIV0_HCLK_SHIFT (8) #define S3C6400_CLKDIV0_MPLL_MASK (0x1 << 4) #define S3C6400_CLKDIV0_MPLL_SHIFT (4) -#define S3C6400_CLKDIV0_ARM_MASK (0x3 << 0) -#define S3C6410_CLKDIV0_ARM_MASK (0x7 << 0) +#define S3C6400_CLKDIV0_ARM_MASK (0x7 << 0) +#define S3C6410_CLKDIV0_ARM_MASK (0xf << 0) #define S3C6400_CLKDIV0_ARM_SHIFT (0) /* CLKDIV1 */ diff --git a/arch/arm/plat-s3c64xx/pm.c b/arch/arm/plat-s3c64xx/pm.c index 07a6516a4f3..47632fc7eb6 100644 --- a/arch/arm/plat-s3c64xx/pm.c +++ b/arch/arm/plat-s3c64xx/pm.c @@ -117,8 +117,6 @@ void s3c_pm_save_core(void) * this. */ -#include <plat/regs-gpio.h> - static void s3c64xx_cpu_suspend(void) { unsigned long tmp; diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 1debc1f9f98..6ffa21eb1b9 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c @@ -153,7 +153,7 @@ static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk, u32 div; if (parent < rate) - return rate; + return parent; div = (parent / rate) - 1; if (div > armclk_mask) @@ -175,7 +175,7 @@ static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate) div = clk_get_rate(clk->parent) / rate; val = __raw_readl(S3C_CLK_DIV0); - val &= armclk_mask; + val &= ~armclk_mask; val |= (div - 1); __raw_writel(val, S3C_CLK_DIV0); @@ -302,8 +302,8 @@ static int s3c64xx_setrate_clksrc(struct clk *clk, unsigned long rate) return -EINVAL; val = __raw_readl(reg); - val &= ~(0xf << sclk->shift); - val |= (div - 1) << sclk->shift; + val &= ~(0xf << sclk->divider_shift); + val |= (div - 1) << sclk->divider_shift; __raw_writel(val, reg); return 0; @@ -328,6 +328,8 @@ static int s3c64xx_setparent_clksrc(struct clk *clk, struct clk *parent) clksrc |= src_nr << sclk->shift; __raw_writel(clksrc, S3C_CLK_SRC); + + clk->parent = parent; return 0; } @@ -343,7 +345,7 @@ static unsigned long s3c64xx_roundrate_clksrc(struct clk *clk, if (rate > parent_rate) rate = parent_rate; else { - div = rate / parent_rate; + div = parent_rate / rate; if (div == 0) div = 1; @@ -675,6 +677,9 @@ void __init_or_cpufreq s3c6400_setup_clocks(void) printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); + /* For now assume the mux always selects the crystal */ + clk_ext_xtal_mux.parent = xtal_clk; + epll = s3c6400_get_epll(xtal); mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON)); apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON)); |