diff options
author | Ryan Mallon <ryan@bluewatersys.com> | 2010-06-08 06:01:10 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-06-09 06:12:36 -0400 |
commit | ed67ea82c0d9a163458dc6a69a7a3123db1a8b3b (patch) | |
tree | 6789785686ddf249ab813c296ade58b7b0443d33 /arch/arm/mach-ep93xx | |
parent | e40152ee1e1c7a63f4777791863215e3faa37a86 (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.c | 67 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/core.c | 67 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 10 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/platform.h | 3 |
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 | ||
44 | static int set_keytchclk_rate(struct clk *clk, unsigned long rate); | 44 | static int set_keytchclk_rate(struct clk *clk, unsigned long rate); |
45 | static int set_div_rate(struct clk *clk, unsigned long rate); | 45 | static int set_div_rate(struct clk *clk, unsigned long rate); |
46 | 46 | static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate); | |
47 | static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate); | ||
47 | 48 | ||
48 | static struct clk clk_xtali = { | 49 | static 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 | ||
112 | static 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 | |||
119 | static 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 | |||
127 | static 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 */ |
112 | static struct clk clk_m2p0 = { | 136 | static 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 | ||
426 | static 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 | |||
443 | static 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 | |||
399 | int clk_set_rate(struct clk *clk, unsigned long rate) | 464 | int 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 | } |
618 | EXPORT_SYMBOL(ep93xx_keypad_release_gpio); | 618 | EXPORT_SYMBOL(ep93xx_keypad_release_gpio); |
619 | 619 | ||
620 | /************************************************************************* | ||
621 | * EP93xx I2S audio peripheral handling | ||
622 | *************************************************************************/ | ||
623 | static 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 | |||
631 | static 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 | |||
638 | void __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 | |||
649 | int 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 | } | ||
680 | EXPORT_SYMBOL(ep93xx_i2s_acquire); | ||
681 | |||
682 | void ep93xx_i2s_release(void) | ||
683 | { | ||
684 | ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2S_MASK); | ||
685 | } | ||
686 | EXPORT_SYMBOL(ep93xx_i2s_release); | ||
620 | 687 | ||
621 | extern void ep93xx_gpio_init(void); | 688 | extern 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); | |||
43 | void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data); | 43 | void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data); |
44 | int ep93xx_keypad_acquire_gpio(struct platform_device *pdev); | 44 | int ep93xx_keypad_acquire_gpio(struct platform_device *pdev); |
45 | void ep93xx_keypad_release_gpio(struct platform_device *pdev); | 45 | void ep93xx_keypad_release_gpio(struct platform_device *pdev); |
46 | void ep93xx_register_i2s(void); | ||
47 | int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config); | ||
48 | void ep93xx_i2s_release(void); | ||
46 | 49 | ||
47 | void ep93xx_init_devices(void); | 50 | void ep93xx_init_devices(void); |
48 | extern struct sys_timer ep93xx_timer; | 51 | extern struct sys_timer ep93xx_timer; |