19a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#ifndef __LINUX_ATMEL_PWM_H 29a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define __LINUX_ATMEL_PWM_H 39a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 49a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell/** 59a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * struct pwm_channel - driver handle to a PWM channel 69a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * @regs: base of this channel's registers 79a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * @index: number of this channel (0..31) 89a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * @mck: base clock rate, which can be prescaled and maybe subdivided 99a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * 109a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * Drivers initialize a pwm_channel structure using pwm_channel_alloc(). 119a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * Then they configure its clock rate (derived from MCK), alignment, 129a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * polarity, and duty cycle by writing directly to the channel registers, 139a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * before enabling the channel by calling pwm_channel_enable(). 149a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * 159a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * After emitting a PWM signal for the desired length of time, drivers 169a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * may then pwm_channel_disable() or pwm_channel_free(). Both of these 179a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * disable the channel, but when it's freed the IRQ is deconfigured and 189a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * the channel must later be re-allocated and reconfigured. 199a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * 209a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * Note that if the period or duty cycle need to be changed while the 219a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * PWM channel is operating, drivers must use the PWM_CUPD double buffer 229a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * mechanism, either polling until they change or getting implicitly 239a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell * notified through a once-per-period interrupt handler. 249a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell */ 259a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellstruct pwm_channel { 269a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell void __iomem *regs; 279a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell unsigned index; 289a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell unsigned long mck; 299a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell}; 309a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 319a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellextern int pwm_channel_alloc(int index, struct pwm_channel *ch); 329a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellextern int pwm_channel_free(struct pwm_channel *ch); 339a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 349a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellextern int pwm_clk_alloc(unsigned prescale, unsigned div); 359a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellextern void pwm_clk_free(unsigned clk); 369a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 379a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellextern int __pwm_channel_onoff(struct pwm_channel *ch, int enabled); 389a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 399a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define pwm_channel_enable(ch) __pwm_channel_onoff((ch), 1) 409a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define pwm_channel_disable(ch) __pwm_channel_onoff((ch), 0) 419a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 429a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell/* periodic interrupts, mostly for CUPD changes to period or cycle */ 439a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellextern int pwm_channel_handler(struct pwm_channel *ch, 449a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell void (*handler)(struct pwm_channel *ch)); 459a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 469a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell/* per-channel registers (banked at pwm_channel->regs) */ 479a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CMR 0x00 /* mode register */ 489a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CPR_CPD (1 << 10) /* set: CUPD modifies period */ 499a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CPR_CPOL (1 << 9) /* set: idle high */ 509a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CPR_CALG (1 << 8) /* set: center align */ 519a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CPR_CPRE (0xf << 0) /* mask: rate is mck/(2^pre) */ 529a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CPR_CLKA (0xb << 0) /* rate CLKA */ 539a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CPR_CLKB (0xc << 0) /* rate CLKB */ 549a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CDTY 0x04 /* duty cycle (max of CPRD) */ 559a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CPRD 0x08 /* period (count up from zero) */ 569a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CCNT 0x0c /* counter (20 bits?) */ 579a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#define PWM_CUPD 0x10 /* update CPRD (or CDTY) next period */ 589a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 599a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellstatic inline void 609a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellpwm_channel_writel(struct pwm_channel *pwmc, unsigned offset, u32 val) 619a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell{ 629a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell __raw_writel(val, pwmc->regs + offset); 639a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell} 649a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 659a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownellstatic inline u32 pwm_channel_readl(struct pwm_channel *pwmc, unsigned offset) 669a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell{ 679a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell return __raw_readl(pwmc->regs + offset); 689a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell} 699a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell 709a1e8eb1f0b76b5e72a2343ad881c81b08dd6410David Brownell#endif /* __LINUX_ATMEL_PWM_H */ 71