From 758aa8f8f24580433686e0e21083035e92e814b8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=BB=84=E6=B6=9B?= Date: Fri, 4 Jan 2013 18:24:03 +0800 Subject: [PATCH] rk: add common pwm driver --- arch/arm/plat-rk/Makefile | 1 + arch/arm/plat-rk/include/plat/pwm.h | 61 ++++++++++++++++++++++++ arch/arm/plat-rk/pwm.c | 73 +++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 arch/arm/plat-rk/include/plat/pwm.h create mode 100644 arch/arm/plat-rk/pwm.c diff --git a/arch/arm/plat-rk/Makefile b/arch/arm/plat-rk/Makefile index a2580b5f189a..accfca14b1f4 100644 --- a/arch/arm/plat-rk/Makefile +++ b/arch/arm/plat-rk/Makefile @@ -14,3 +14,4 @@ obj-y += iomux.o CFLAGS_sram.o += -mthumb obj-$(CONFIG_DDR_TEST) += memtester.o ddr_test.o obj-$(CONFIG_DDR_FREQ) += ddr_freq.o +obj-y += pwm.o diff --git a/arch/arm/plat-rk/include/plat/pwm.h b/arch/arm/plat-rk/include/plat/pwm.h new file mode 100644 index 000000000000..21d2c3659ead --- /dev/null +++ b/arch/arm/plat-rk/include/plat/pwm.h @@ -0,0 +1,61 @@ +#ifndef __PLAT_PWM_H +#define __PLAT_PWM_H + +#include + +enum pwm_div { + PWM_DIV2 = (0x0 << 9), + PWM_DIV4 = (0x1 << 9), + PWM_DIV8 = (0x2 << 9), + PWM_DIV16 = (0x3 << 9), + PWM_DIV32 = (0x4 << 9), + PWM_DIV64 = (0x5 << 9), + PWM_DIV128 = (0x6 << 9), + PWM_DIV256 = (0x7 << 9), + PWM_DIV512 = (0x8 << 9), + PWM_DIV1024 = (0x9 << 9), + PWM_DIV2048 = (0xa << 9), + PWM_DIV4096 = (0xb << 9), + PWM_DIV8192 = (0xc << 9), + PWM_DIV16384 = (0xd << 9), + PWM_DIV32768 = (0xe << 9), + PWM_DIV65536 = (0xf << 9), +}; + +#define PWM_DIV_MASK (0xf << 9) +#define PWM_CAPTURE (1 << 8) +#define PWM_RESET (1 << 7) +#define PWM_INTCLR (1 << 6) +#define PWM_INTEN (1 << 5) +#define PWM_SINGLE (1 << 4) + +#define PWM_ENABLE (1 << 3) +#define PWM_TIMER_EN (1 << 0) +#define PWM_TimeEN PWM_TIMER_EN + +#define PWM_REG_CNTR 0x00 +#define PWM_REG_HRC 0x04 +#define PWM_REG_LRC 0x08 +#define PWM_REG_CTRL 0x0c + +static inline void __rk_pwm_setup(const void __iomem *base, enum pwm_div div, u32 hrc, u32 lrc) +{ + u32 off = div | PWM_RESET; + u32 on = div | PWM_ENABLE | PWM_TIMER_EN; + + barrier(); + writel_relaxed(off, base + PWM_REG_CTRL); + dsb(); + writel_relaxed(hrc, base + PWM_REG_HRC); + writel_relaxed(lrc, base + PWM_REG_LRC); + writel_relaxed(0, base + PWM_REG_CNTR); + dsb(); + writel_relaxed(on, base + PWM_REG_CTRL); + dsb(); +} + +struct clk *rk_pwm_get_clk(unsigned pwm_id); +void __iomem *rk_pwm_get_base(unsigned pwm_id); +void rk_pwm_setup(unsigned pwm_id, enum pwm_div div, u32 hrc, u32 lrc); + +#endif diff --git a/arch/arm/plat-rk/pwm.c b/arch/arm/plat-rk/pwm.c new file mode 100644 index 000000000000..c4d01cb46504 --- /dev/null +++ b/arch/arm/plat-rk/pwm.c @@ -0,0 +1,73 @@ +#define pr_fmt(fmt) "pwm: " fmt +#include +#include +#include +#include +#include +#include +#include + +static spinlock_t pwm_lock[4] = { + __SPIN_LOCK_UNLOCKED(pwm_lock0), + __SPIN_LOCK_UNLOCKED(pwm_lock1), + __SPIN_LOCK_UNLOCKED(pwm_lock2), + __SPIN_LOCK_UNLOCKED(pwm_lock3), +}; + +struct clk *rk_pwm_get_clk(unsigned id) +{ +#if defined(CONFIG_ARCH_RK29) + if (id < 4) + return clk_get(NULL, "pwm"); +#elif defined(CONFIG_ARCH_RK30) + if (id == 0 || id == 1) + return clk_get(NULL, "pwm01"); + else if (id== 2 || id == 3) + return clk_get(NULL, "pwm23"); +#elif defined(CONFIG_ARCH_RK2928) + if (id < 3) + return clk_get(NULL, "pwm01"); +#endif + pr_err("invalid pwm id %d\n", id); + BUG(); + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(rk_pwm_get_clk); + +void __iomem *rk_pwm_get_base(unsigned id) +{ +#if defined(CONFIG_ARCH_RK29) + if (id < 4) + return RK29_PWM_BASE + id * 0x10; +#elif defined(CONFIG_ARCH_RK30) + if (id == 0 || id == 1) + return RK30_PWM01_BASE + id * 0x10; + else if (id== 2 || id == 3) + return RK30_PWM23_BASE + id * 0x10; +#elif defined(CONFIG_ARCH_RK2928) + if (id < 3) + return RK2928_PWM_BASE + id * 0x10; +#endif + pr_err("invalid pwm id %d\n", id); + BUG(); + return 0; +} +EXPORT_SYMBOL(rk_pwm_get_base); + +void rk_pwm_setup(unsigned id, enum pwm_div div, u32 hrc, u32 lrc) +{ + unsigned long flags; + spinlock_t *lock; + const void __iomem *base = rk_pwm_get_base(id); + + if (hrc > lrc) { + pr_err("invalid hrc %d lrc %d\n", hrc, lrc); + return; + } + + lock = &pwm_lock[id]; + spin_lock_irqsave(lock, flags); + __rk_pwm_setup(base, div, hrc, lrc); + spin_unlock_irqrestore(lock, flags); +} +EXPORT_SYMBOL(rk_pwm_setup); -- 2.34.1