diff options
author | David Brownell <david-b@pacbell.net> | 2008-02-08 07:21:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 12:22:38 -0500 |
commit | 9a1e8eb1f0b76b5e72a2343ad881c81b08dd6410 (patch) | |
tree | f844d0e1316b49fd66cf773009ba2c3d46fcd18f /include | |
parent | c8cece84c9f36410de5164735e909603426e4d5f (diff) |
Basic PWM driver for AVR32 and AT91
PWM device setup, and a simple PWM driver exposing a programming interface
giving access to each channel's full capabilities. Note that this doesn't
support starting several channels in synch.
[hskinnemoen@atmel.com: allocate platform device dynamically]
[hskinnemoen@atmel.com: Kconfig fix]
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Andrew Victor <linux@maxim.org.za>
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-avr32/arch-at32ap/board.h | 3 | ||||
-rw-r--r-- | include/linux/atmel_pwm.h | 70 |
2 files changed, 73 insertions, 0 deletions
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h index d6993a6b6473..7597b0bd2f01 100644 --- a/include/asm-avr32/arch-at32ap/board.h +++ b/include/asm-avr32/arch-at32ap/board.h | |||
@@ -51,6 +51,9 @@ struct platform_device * | |||
51 | at32_add_device_ide(unsigned int id, unsigned int extint, | 51 | at32_add_device_ide(unsigned int id, unsigned int extint, |
52 | struct ide_platform_data *data); | 52 | struct ide_platform_data *data); |
53 | 53 | ||
54 | /* mask says which PWM channels to mux */ | ||
55 | struct platform_device *at32_add_device_pwm(u32 mask); | ||
56 | |||
54 | /* depending on what's hooked up, not all SSC pins will be used */ | 57 | /* depending on what's hooked up, not all SSC pins will be used */ |
55 | #define ATMEL_SSC_TK 0x01 | 58 | #define ATMEL_SSC_TK 0x01 |
56 | #define ATMEL_SSC_TF 0x02 | 59 | #define ATMEL_SSC_TF 0x02 |
diff --git a/include/linux/atmel_pwm.h b/include/linux/atmel_pwm.h new file mode 100644 index 000000000000..ea04abb3db8e --- /dev/null +++ b/include/linux/atmel_pwm.h | |||
@@ -0,0 +1,70 @@ | |||
1 | #ifndef __LINUX_ATMEL_PWM_H | ||
2 | #define __LINUX_ATMEL_PWM_H | ||
3 | |||
4 | /** | ||
5 | * struct pwm_channel - driver handle to a PWM channel | ||
6 | * @regs: base of this channel's registers | ||
7 | * @index: number of this channel (0..31) | ||
8 | * @mck: base clock rate, which can be prescaled and maybe subdivided | ||
9 | * | ||
10 | * Drivers initialize a pwm_channel structure using pwm_channel_alloc(). | ||
11 | * Then they configure its clock rate (derived from MCK), alignment, | ||
12 | * polarity, and duty cycle by writing directly to the channel registers, | ||
13 | * before enabling the channel by calling pwm_channel_enable(). | ||
14 | * | ||
15 | * After emitting a PWM signal for the desired length of time, drivers | ||
16 | * may then pwm_channel_disable() or pwm_channel_free(). Both of these | ||
17 | * disable the channel, but when it's freed the IRQ is deconfigured and | ||
18 | * the channel must later be re-allocated and reconfigured. | ||
19 | * | ||
20 | * Note that if the period or duty cycle need to be changed while the | ||
21 | * PWM channel is operating, drivers must use the PWM_CUPD double buffer | ||
22 | * mechanism, either polling until they change or getting implicitly | ||
23 | * notified through a once-per-period interrupt handler. | ||
24 | */ | ||
25 | struct pwm_channel { | ||
26 | void __iomem *regs; | ||
27 | unsigned index; | ||
28 | unsigned long mck; | ||
29 | }; | ||
30 | |||
31 | extern int pwm_channel_alloc(int index, struct pwm_channel *ch); | ||
32 | extern int pwm_channel_free(struct pwm_channel *ch); | ||
33 | |||
34 | extern int pwm_clk_alloc(unsigned prescale, unsigned div); | ||
35 | extern void pwm_clk_free(unsigned clk); | ||
36 | |||
37 | extern int __pwm_channel_onoff(struct pwm_channel *ch, int enabled); | ||
38 | |||
39 | #define pwm_channel_enable(ch) __pwm_channel_onoff((ch), 1) | ||
40 | #define pwm_channel_disable(ch) __pwm_channel_onoff((ch), 0) | ||
41 | |||
42 | /* periodic interrupts, mostly for CUPD changes to period or cycle */ | ||
43 | extern int pwm_channel_handler(struct pwm_channel *ch, | ||
44 | void (*handler)(struct pwm_channel *ch)); | ||
45 | |||
46 | /* per-channel registers (banked at pwm_channel->regs) */ | ||
47 | #define PWM_CMR 0x00 /* mode register */ | ||
48 | #define PWM_CPR_CPD (1 << 10) /* set: CUPD modifies period */ | ||
49 | #define PWM_CPR_CPOL (1 << 9) /* set: idle high */ | ||
50 | #define PWM_CPR_CALG (1 << 8) /* set: center align */ | ||
51 | #define PWM_CPR_CPRE (0xf << 0) /* mask: rate is mck/(2^pre) */ | ||
52 | #define PWM_CPR_CLKA (0xb << 0) /* rate CLKA */ | ||
53 | #define PWM_CPR_CLKB (0xc << 0) /* rate CLKB */ | ||
54 | #define PWM_CDTY 0x04 /* duty cycle (max of CPRD) */ | ||
55 | #define PWM_CPRD 0x08 /* period (count up from zero) */ | ||
56 | #define PWM_CCNT 0x0c /* counter (20 bits?) */ | ||
57 | #define PWM_CUPD 0x10 /* update CPRD (or CDTY) next period */ | ||
58 | |||
59 | static inline void | ||
60 | pwm_channel_writel(struct pwm_channel *pwmc, unsigned offset, u32 val) | ||
61 | { | ||
62 | __raw_writel(val, pwmc->regs + offset); | ||
63 | } | ||
64 | |||
65 | static inline u32 pwm_channel_readl(struct pwm_channel *pwmc, unsigned offset) | ||
66 | { | ||
67 | return __raw_readl(pwmc->regs + offset); | ||
68 | } | ||
69 | |||
70 | #endif /* __LINUX_ATMEL_PWM_H */ | ||