diff options
author | Hartley Sweeten <hartleys@visionengravers.com> | 2009-07-29 17:41:06 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-07-30 12:45:43 -0400 |
commit | ef12379f205bed7e92434e12ddd44e62d13bebe1 (patch) | |
tree | c372f5741826e7fbdaec8eac86191b52e3e621af /arch/arm/mach-ep93xx | |
parent | 3aa7a9a3cf8774f6701b1903a6353f9545f561ce (diff) |
ARM: 5628/1: ep93xx: Introduce Pulse Width Modulator (PWM) driver
The EP93xx features two PWMs (one on the EP9307) with the following
features:
* Configurable dual output
* Separate input clocks for each PWM output
* 16-bit resolution
* Programmable pulse width (duty cycle), interval (frequency), and
polarity
This adds the necessary core support as well as the driver. A sysfs
interface is provided to control the PWM outputs.
Signed-off-by: Matthieu Crapet <mcrapet@gmail.com>
Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Acked-by: Ryan Mallon <ryan@bluewatersys.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-ep93xx')
-rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/core.c | 85 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/platform.h | 4 |
4 files changed, 94 insertions, 0 deletions
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index b6b53447b1b4..3dd0e2a23095 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c | |||
@@ -72,6 +72,9 @@ static struct clk clk_keypad = { | |||
72 | .enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_KEN, | 72 | .enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_KEN, |
73 | .set_rate = set_keytchclk_rate, | 73 | .set_rate = set_keytchclk_rate, |
74 | }; | 74 | }; |
75 | static struct clk clk_pwm = { | ||
76 | .rate = EP93XX_EXT_CLK_RATE, | ||
77 | }; | ||
75 | 78 | ||
76 | /* DMA Clocks */ | 79 | /* DMA Clocks */ |
77 | static struct clk clk_m2p0 = { | 80 | static struct clk clk_m2p0 = { |
@@ -137,6 +140,7 @@ static struct clk_lookup clocks[] = { | |||
137 | INIT_CK(NULL, "pll2", &clk_pll2), | 140 | INIT_CK(NULL, "pll2", &clk_pll2), |
138 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), | 141 | INIT_CK("ep93xx-ohci", NULL, &clk_usb_host), |
139 | INIT_CK("ep93xx-keypad", NULL, &clk_keypad), | 142 | INIT_CK("ep93xx-keypad", NULL, &clk_keypad), |
143 | INIT_CK(NULL, "pwm_clk", &clk_pwm), | ||
140 | INIT_CK(NULL, "m2p0", &clk_m2p0), | 144 | INIT_CK(NULL, "m2p0", &clk_m2p0), |
141 | INIT_CK(NULL, "m2p1", &clk_m2p1), | 145 | INIT_CK(NULL, "m2p1", &clk_m2p1), |
142 | INIT_CK(NULL, "m2p2", &clk_m2p2), | 146 | INIT_CK(NULL, "m2p2", &clk_m2p2), |
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 2b58df0184c1..40755298fa33 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c | |||
@@ -597,6 +597,91 @@ static struct platform_device ep93xx_leds = { | |||
597 | }; | 597 | }; |
598 | 598 | ||
599 | 599 | ||
600 | /************************************************************************* | ||
601 | * EP93xx pwm peripheral handling | ||
602 | *************************************************************************/ | ||
603 | static struct resource ep93xx_pwm0_resource[] = { | ||
604 | { | ||
605 | .start = EP93XX_PWM_PHYS_BASE, | ||
606 | .end = EP93XX_PWM_PHYS_BASE + 0x10 - 1, | ||
607 | .flags = IORESOURCE_MEM, | ||
608 | }, | ||
609 | }; | ||
610 | |||
611 | static struct platform_device ep93xx_pwm0_device = { | ||
612 | .name = "ep93xx-pwm", | ||
613 | .id = 0, | ||
614 | .num_resources = ARRAY_SIZE(ep93xx_pwm0_resource), | ||
615 | .resource = ep93xx_pwm0_resource, | ||
616 | }; | ||
617 | |||
618 | static struct resource ep93xx_pwm1_resource[] = { | ||
619 | { | ||
620 | .start = EP93XX_PWM_PHYS_BASE + 0x20, | ||
621 | .end = EP93XX_PWM_PHYS_BASE + 0x30 - 1, | ||
622 | .flags = IORESOURCE_MEM, | ||
623 | }, | ||
624 | }; | ||
625 | |||
626 | static struct platform_device ep93xx_pwm1_device = { | ||
627 | .name = "ep93xx-pwm", | ||
628 | .id = 1, | ||
629 | .num_resources = ARRAY_SIZE(ep93xx_pwm1_resource), | ||
630 | .resource = ep93xx_pwm1_resource, | ||
631 | }; | ||
632 | |||
633 | void __init ep93xx_register_pwm(int pwm0, int pwm1) | ||
634 | { | ||
635 | if (pwm0) | ||
636 | platform_device_register(&ep93xx_pwm0_device); | ||
637 | |||
638 | /* NOTE: EP9307 does not have PWMOUT1 (pin EGPIO14) */ | ||
639 | if (pwm1) | ||
640 | platform_device_register(&ep93xx_pwm1_device); | ||
641 | } | ||
642 | |||
643 | int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) | ||
644 | { | ||
645 | int err; | ||
646 | |||
647 | if (pdev->id == 0) { | ||
648 | err = 0; | ||
649 | } else if (pdev->id == 1) { | ||
650 | err = gpio_request(EP93XX_GPIO_LINE_EGPIO14, | ||
651 | dev_name(&pdev->dev)); | ||
652 | if (err) | ||
653 | return err; | ||
654 | err = gpio_direction_output(EP93XX_GPIO_LINE_EGPIO14, 0); | ||
655 | if (err) | ||
656 | goto fail; | ||
657 | |||
658 | /* PWM 1 output on EGPIO[14] */ | ||
659 | ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_PONG); | ||
660 | } else { | ||
661 | err = -ENODEV; | ||
662 | } | ||
663 | |||
664 | return err; | ||
665 | |||
666 | fail: | ||
667 | gpio_free(EP93XX_GPIO_LINE_EGPIO14); | ||
668 | return err; | ||
669 | } | ||
670 | EXPORT_SYMBOL(ep93xx_pwm_acquire_gpio); | ||
671 | |||
672 | void ep93xx_pwm_release_gpio(struct platform_device *pdev) | ||
673 | { | ||
674 | if (pdev->id == 1) { | ||
675 | gpio_direction_input(EP93XX_GPIO_LINE_EGPIO14); | ||
676 | gpio_free(EP93XX_GPIO_LINE_EGPIO14); | ||
677 | |||
678 | /* EGPIO[14] used for GPIO */ | ||
679 | ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_PONG); | ||
680 | } | ||
681 | } | ||
682 | EXPORT_SYMBOL(ep93xx_pwm_release_gpio); | ||
683 | |||
684 | |||
600 | extern void ep93xx_gpio_init(void); | 685 | extern void ep93xx_gpio_init(void); |
601 | 686 | ||
602 | void __init ep93xx_init_devices(void) | 687 | void __init ep93xx_init_devices(void) |
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h index a11ae779baa0..ea78e908fc82 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | |||
@@ -147,6 +147,7 @@ | |||
147 | #define EP93XX_ADC_BASE EP93XX_APB_IOMEM(0x00100000) | 147 | #define EP93XX_ADC_BASE EP93XX_APB_IOMEM(0x00100000) |
148 | #define EP93XX_TOUCHSCREEN_BASE EP93XX_APB_IOMEM(0x00100000) | 148 | #define EP93XX_TOUCHSCREEN_BASE EP93XX_APB_IOMEM(0x00100000) |
149 | 149 | ||
150 | #define EP93XX_PWM_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00110000) | ||
150 | #define EP93XX_PWM_BASE EP93XX_APB_IOMEM(0x00110000) | 151 | #define EP93XX_PWM_BASE EP93XX_APB_IOMEM(0x00110000) |
151 | 152 | ||
152 | #define EP93XX_RTC_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00120000) | 153 | #define EP93XX_RTC_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00120000) |
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index 0af0a3ba7047..5f5fa6574d34 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #ifndef __ASSEMBLY__ | 5 | #ifndef __ASSEMBLY__ |
6 | 6 | ||
7 | struct i2c_board_info; | 7 | struct i2c_board_info; |
8 | struct platform_device; | ||
8 | 9 | ||
9 | struct ep93xx_eth_data | 10 | struct ep93xx_eth_data |
10 | { | 11 | { |
@@ -32,6 +33,9 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits) | |||
32 | 33 | ||
33 | void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); | 34 | void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr); |
34 | void ep93xx_register_i2c(struct i2c_board_info *devices, int num); | 35 | void ep93xx_register_i2c(struct i2c_board_info *devices, int num); |
36 | void ep93xx_register_pwm(int pwm0, int pwm1); | ||
37 | int ep93xx_pwm_acquire_gpio(struct platform_device *pdev); | ||
38 | void ep93xx_pwm_release_gpio(struct platform_device *pdev); | ||
35 | 39 | ||
36 | void ep93xx_init_devices(void); | 40 | void ep93xx_init_devices(void); |
37 | extern struct sys_timer ep93xx_timer; | 41 | extern struct sys_timer ep93xx_timer; |