aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ep93xx
diff options
context:
space:
mode:
authorRyan Mallon <ryan@bluewatersys.com>2010-06-08 06:01:10 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-06-09 06:12:36 -0400
commited67ea82c0d9a163458dc6a69a7a3123db1a8b3b (patch)
tree6789785686ddf249ab813c296ade58b7b0443d33 /arch/arm/mach-ep93xx
parente40152ee1e1c7a63f4777791863215e3faa37a86 (diff)
EP93xx: Add i2s core support
Add core support for EP93xx i2s audio Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'arch/arm/mach-ep93xx')
-rw-r--r--arch/arm/mach-ep93xx/clock.c67
-rw-r--r--arch/arm/mach-ep93xx/core.c67
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h10
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h3
4 files changed, 146 insertions, 1 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 5f80092b6ace..e782af18ffb7 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
43 43
44static int set_keytchclk_rate(struct clk *clk, unsigned long rate); 44static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
45static int set_div_rate(struct clk *clk, unsigned long rate); 45static int set_div_rate(struct clk *clk, unsigned long rate);
46 46static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
47static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
47 48
48static struct clk clk_xtali = { 49static struct clk clk_xtali = {
49 .rate = EP93XX_EXT_CLK_RATE, 50 .rate = EP93XX_EXT_CLK_RATE,
@@ -108,6 +109,29 @@ static struct clk clk_video = {
108 .set_rate = set_div_rate, 109 .set_rate = set_div_rate,
109}; 110};
110 111
112static struct clk clk_i2s_mclk = {
113 .sw_locked = 1,
114 .enable_reg = EP93XX_SYSCON_I2SCLKDIV,
115 .enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE,
116 .set_rate = set_div_rate,
117};
118
119static struct clk clk_i2s_sclk = {
120 .sw_locked = 1,
121 .parent = &clk_i2s_mclk,
122 .enable_reg = EP93XX_SYSCON_I2SCLKDIV,
123 .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA,
124 .set_rate = set_i2s_sclk_rate,
125};
126
127static struct clk clk_i2s_lrclk = {
128 .sw_locked = 1,
129 .parent = &clk_i2s_sclk,
130 .enable_reg = EP93XX_SYSCON_I2SCLKDIV,
131 .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA,
132 .set_rate = set_i2s_lrclk_rate,
133};
134
111/* DMA Clocks */ 135/* DMA Clocks */
112static struct clk clk_m2p0 = { 136static struct clk clk_m2p0 = {
113 .parent = &clk_h, 137 .parent = &clk_h,
@@ -186,6 +210,9 @@ static struct clk_lookup clocks[] = {
186 INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), 210 INIT_CK("ep93xx-ohci", NULL, &clk_usb_host),
187 INIT_CK("ep93xx-keypad", NULL, &clk_keypad), 211 INIT_CK("ep93xx-keypad", NULL, &clk_keypad),
188 INIT_CK("ep93xx-fb", NULL, &clk_video), 212 INIT_CK("ep93xx-fb", NULL, &clk_video),
213 INIT_CK("ep93xx-i2s", "mclk", &clk_i2s_mclk),
214 INIT_CK("ep93xx-i2s", "sclk", &clk_i2s_sclk),
215 INIT_CK("ep93xx-i2s", "lrclk", &clk_i2s_lrclk),
189 INIT_CK(NULL, "pwm_clk", &clk_pwm), 216 INIT_CK(NULL, "pwm_clk", &clk_pwm),
190 INIT_CK(NULL, "m2p0", &clk_m2p0), 217 INIT_CK(NULL, "m2p0", &clk_m2p0),
191 INIT_CK(NULL, "m2p1", &clk_m2p1), 218 INIT_CK(NULL, "m2p1", &clk_m2p1),
@@ -396,6 +423,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
396 return 0; 423 return 0;
397} 424}
398 425
426static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
427{
428 unsigned val = __raw_readl(clk->enable_reg);
429
430 if (rate == clk_i2s_mclk.rate / 2)
431 ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV,
432 clk->enable_reg);
433 else if (rate == clk_i2s_mclk.rate / 4)
434 ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV,
435 clk->enable_reg);
436 else
437 return -EINVAL;
438
439 clk_i2s_sclk.rate = rate;
440 return 0;
441}
442
443static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
444{
445 unsigned val = __raw_readl(clk->enable_reg) &
446 ~EP93XX_I2SCLKDIV_LRDIV_MASK;
447
448 if (rate == clk_i2s_sclk.rate / 32)
449 ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
450 clk->enable_reg);
451 else if (rate == clk_i2s_sclk.rate / 64)
452 ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
453 clk->enable_reg);
454 else if (rate == clk_i2s_sclk.rate / 128)
455 ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
456 clk->enable_reg);
457 else
458 return -EINVAL;
459
460 clk_i2s_lrclk.rate = rate;
461 return 0;
462}
463
399int clk_set_rate(struct clk *clk, unsigned long rate) 464int clk_set_rate(struct clk *clk, unsigned long rate)
400{ 465{
401 if (clk->set_rate) 466 if (clk->set_rate)
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 90fb591cbffa..005af0fba334 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -617,6 +617,73 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev)
617} 617}
618EXPORT_SYMBOL(ep93xx_keypad_release_gpio); 618EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
619 619
620/*************************************************************************
621 * EP93xx I2S audio peripheral handling
622 *************************************************************************/
623static struct resource ep93xx_i2s_resource[] = {
624 {
625 .start = EP93XX_I2S_PHYS_BASE,
626 .end = EP93XX_I2S_PHYS_BASE + 0x100 - 1,
627 .flags = IORESOURCE_MEM,
628 },
629};
630
631static struct platform_device ep93xx_i2s_device = {
632 .name = "ep93xx-i2s",
633 .id = -1,
634 .num_resources = ARRAY_SIZE(ep93xx_i2s_resource),
635 .resource = ep93xx_i2s_resource,
636};
637
638void __init ep93xx_register_i2s(void)
639{
640 platform_device_register(&ep93xx_i2s_device);
641}
642
643#define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
644 EP93XX_SYSCON_DEVCFG_I2SONAC97)
645
646#define EP93XX_I2SCLKDIV_MASK (EP93XX_SYSCON_I2SCLKDIV_ORIDE | \
647 EP93XX_SYSCON_I2SCLKDIV_SPOL)
648
649int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config)
650{
651 unsigned val;
652
653 /* Sanity check */
654 if (i2s_pins & ~EP93XX_SYSCON_DEVCFG_I2S_MASK)
655 return -EINVAL;
656 if (i2s_config & ~EP93XX_I2SCLKDIV_MASK)
657 return -EINVAL;
658
659 /* Must have only one of I2SONSSP/I2SONAC97 set */
660 if ((i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONSSP) ==
661 (i2s_pins & EP93XX_SYSCON_DEVCFG_I2SONAC97))
662 return -EINVAL;
663
664 ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK);
665 ep93xx_devcfg_set_bits(i2s_pins);
666
667 /*
668 * This is potentially racy with the clock api for i2s_mclk, sclk and
669 * lrclk. Since the i2s driver is the only user of those clocks we
670 * rely on it to prevent parallel use of this function and the
671 * clock api for the i2s clocks.
672 */
673 val = __raw_readl(EP93XX_SYSCON_I2SCLKDIV);
674 val &= ~EP93XX_I2SCLKDIV_MASK;
675 val |= i2s_config;
676 ep93xx_syscon_swlocked_write(val, EP93XX_SYSCON_I2SCLKDIV);
677
678 return 0;
679}
680EXPORT_SYMBOL(ep93xx_i2s_acquire);
681
682void ep93xx_i2s_release(void)
683{
684 ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK);
685}
686EXPORT_SYMBOL(ep93xx_i2s_release);
620 687
621extern void ep93xx_gpio_init(void); 688extern void ep93xx_gpio_init(void);
622 689
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 93e2ecc79ceb..3fbb095be6e9 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -93,6 +93,7 @@
93/* APB peripherals */ 93/* APB peripherals */
94#define EP93XX_TIMER_BASE EP93XX_APB_IOMEM(0x00010000) 94#define EP93XX_TIMER_BASE EP93XX_APB_IOMEM(0x00010000)
95 95
96#define EP93XX_I2S_PHYS_BASE EP93XX_APB_PHYS(0x00020000)
96#define EP93XX_I2S_BASE EP93XX_APB_IOMEM(0x00020000) 97#define EP93XX_I2S_BASE EP93XX_APB_IOMEM(0x00020000)
97 98
98#define EP93XX_SECURITY_BASE EP93XX_APB_IOMEM(0x00030000) 99#define EP93XX_SECURITY_BASE EP93XX_APB_IOMEM(0x00030000)
@@ -193,6 +194,15 @@
193#define EP93XX_SYSCON_CLKDIV_ESEL (1<<14) 194#define EP93XX_SYSCON_CLKDIV_ESEL (1<<14)
194#define EP93XX_SYSCON_CLKDIV_PSEL (1<<13) 195#define EP93XX_SYSCON_CLKDIV_PSEL (1<<13)
195#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8 196#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
197#define EP93XX_SYSCON_I2SCLKDIV EP93XX_SYSCON_REG(0x8c)
198#define EP93XX_SYSCON_I2SCLKDIV_SENA (1<<31)
199#define EP93XX_SYSCON_I2SCLKDIV_ORIDE (1<<29)
200#define EP93XX_SYSCON_I2SCLKDIV_SPOL (1<<19)
201#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
202#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
203#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
204#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
205#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
196#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90) 206#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90)
197#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31) 207#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31)
198#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16) 208#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index c6dc14dbca18..0f2822d7ec8b 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -43,6 +43,9 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev);
43void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data); 43void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
44int ep93xx_keypad_acquire_gpio(struct platform_device *pdev); 44int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
45void ep93xx_keypad_release_gpio(struct platform_device *pdev); 45void ep93xx_keypad_release_gpio(struct platform_device *pdev);
46void ep93xx_register_i2s(void);
47int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
48void ep93xx_i2s_release(void);
46 49
47void ep93xx_init_devices(void); 50void ep93xx_init_devices(void);
48extern struct sys_timer ep93xx_timer; 51extern struct sys_timer ep93xx_timer;