From 4e11f5acb25b0b8eb937c726ade319b988fe3664 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 20 Oct 2015 16:53:05 +0300 Subject: pwm: lpss: Add support for multiple PWMs New Intel SoCs such as Broxton will have four PWMs per PCI (or ACPI) device. Each PWM has 1k of register space allocated from the parent device. Add support for this. Signed-off-by: Mika Westerberg Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'drivers/pwm/pwm-lpss.c') diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index e9798253a16f..e7392bdfdd18 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -29,6 +29,9 @@ #define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION) #define NSECS_PER_SEC 1000000000UL +/* Size of each PWM register space if multiple */ +#define PWM_SIZE 0x400 + struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; @@ -37,13 +40,15 @@ struct pwm_lpss_chip { /* BayTrail */ const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { - .clk_rate = 25000000 + .clk_rate = 25000000, + .npwm = 1, }; EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); /* Braswell */ const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { - .clk_rate = 19200000 + .clk_rate = 19200000, + .npwm = 1, }; EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); @@ -52,6 +57,20 @@ static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) return container_of(chip, struct pwm_lpss_chip, chip); } +static inline u32 pwm_lpss_read(const struct pwm_device *pwm) +{ + struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); + + return readl(lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); +} + +static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value) +{ + struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip); + + writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); +} + static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { @@ -79,38 +98,30 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, duty_ns = 1; on_time_div = 255 - (255 * duty_ns / period_ns); - ctrl = readl(lpwm->regs + PWM); + ctrl = pwm_lpss_read(pwm); ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK); ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT; ctrl |= on_time_div; /* request PWM to update on next cycle */ ctrl |= PWM_SW_UPDATE; - writel(ctrl, lpwm->regs + PWM); + pwm_lpss_write(pwm, ctrl); return 0; } static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct pwm_lpss_chip *lpwm = to_lpwm(chip); - u32 ctrl; - - ctrl = readl(lpwm->regs + PWM); - writel(ctrl | PWM_ENABLE, lpwm->regs + PWM); - + pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); return 0; } static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct pwm_lpss_chip *lpwm = to_lpwm(chip); - u32 ctrl; - - ctrl = readl(lpwm->regs + PWM); - writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); + pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); } static const struct pwm_ops pwm_lpss_ops = { + .free = pwm_lpss_disable, .config = pwm_lpss_config, .enable = pwm_lpss_enable, .disable = pwm_lpss_disable, @@ -135,7 +146,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, lpwm->chip.dev = dev; lpwm->chip.ops = &pwm_lpss_ops; lpwm->chip.base = -1; - lpwm->chip.npwm = 1; + lpwm->chip.npwm = info->npwm; ret = pwmchip_add(&lpwm->chip); if (ret) { @@ -149,11 +160,6 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) { - u32 ctrl; - - ctrl = readl(lpwm->regs + PWM); - writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM); - return pwmchip_remove(&lpwm->chip); } EXPORT_SYMBOL_GPL(pwm_lpss_remove); -- cgit v1.2.3 From 87219cb47e5ccfb932177e960c495d475bc16add Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 20 Oct 2015 16:53:06 +0300 Subject: pwm: lpss: Support all four PWMs on Intel Broxton Intel Broxton has similar PWM than Intel Braswell but instead of one it has four PWMs included in one PCI/ACPI device. This patch adds support for all the four PWMs and changes the PCI part of the driver to use 'pwm_lpss_bxt_info' instead. Signed-off-by: Mika Westerberg Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/pwm/pwm-lpss.c') diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index e7392bdfdd18..df03b50f20dd 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -52,6 +52,13 @@ const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { }; EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); +/* Broxton */ +const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = { + .clk_rate = 19200000, + .npwm = 4, +}; +EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info); + static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip) { return container_of(chip, struct pwm_lpss_chip, chip); -- cgit v1.2.3 From f080be27d7d9333e4815655a2cedab91c3aa7acc Mon Sep 17 00:00:00 2001 From: Qipeng Zha Date: Mon, 26 Oct 2015 12:58:27 +0200 Subject: pwm: lpss: Add support for runtime PM To be able to save some power when PWM is not in use, add support for runtime PM for this driver. This also allows the platform to transition to low power S0ix states when the system is idle. Signed-off-by: Huiquan Zhong Signed-off-by: Qipeng Zha Signed-off-by: Mika Westerberg Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/pwm/pwm-lpss.c') diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index df03b50f20dd..25044104003b 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "pwm-lpss.h" @@ -105,6 +106,8 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, duty_ns = 1; on_time_div = 255 - (255 * duty_ns / period_ns); + pm_runtime_get_sync(chip->dev); + ctrl = pwm_lpss_read(pwm); ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK); ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT; @@ -113,11 +116,14 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, ctrl |= PWM_SW_UPDATE; pwm_lpss_write(pwm, ctrl); + pm_runtime_put(chip->dev); + return 0; } static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) { + pm_runtime_get_sync(chip->dev); pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); return 0; } @@ -125,6 +131,7 @@ static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) { pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); + pm_runtime_put(chip->dev); } static const struct pwm_ops pwm_lpss_ops = { -- cgit v1.2.3