From patchwork Sun Apr 9 18:09:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ralph Sennhauser X-Patchwork-Id: 9671705 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0A5B560365 for ; Sun, 9 Apr 2017 18:10:22 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F398227F94 for ; Sun, 9 Apr 2017 18:10:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E7F5827FA6; Sun, 9 Apr 2017 18:10:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, DKIM_VALID, FREEMAIL_FROM autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2572727F94 for ; Sun, 9 Apr 2017 18:10:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=a2Vn3ONUwIx2fBq+EsmnP+0IdfAPU+jKN1wi07MkP8E=; b=MFYnGxqRqKRW3qK/TsoQ+In2Ox xOea1mYSHma8wnZfWwvWOZxK1ykdtSTlolZFfk7xhB8IGoSEcd6hOi9MlsTmpQ55LBEIngghVYyn0 arP2veCOJkuH+iqLrdhhucgPBdZxtz1ALPYhfmb3eWNaLRAxG+xFh82+PjUDn4+SMQJyvYXymjrVE GxDEl4gNs7zOutOkyKXyOBbkTQOzcjstXtSC2IjOPxFeCNVUgZYEXQgYDYIA5AOKOQonSHgXBemNJ 0oSuiKq1j8HAE1TT0hx+yZXiV4ZG7V1kHzZ09L/msBj9cw/HuDzvQ5C8R0mwjHzV/UVXrIFmQZ7/v 7A03oMIQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1cxHI3-0002mJ-VO; Sun, 09 Apr 2017 18:10:19 +0000 Received: from mail-wr0-x242.google.com ([2a00:1450:400c:c0c::242]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1cxHHp-0001G8-Ar for linux-arm-kernel@lists.infradead.org; Sun, 09 Apr 2017 18:10:08 +0000 Received: by mail-wr0-x242.google.com with SMTP id t20so26449928wra.2 for ; Sun, 09 Apr 2017 11:09:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=FpLSzRDBFCpZ3Mg7TGIeqNJBrGxYU89Qt41RBLRDK2o=; b=J89CQpk6IZAupxD1Hrnv1C6KMzCOhSDLQZhxXzbXamqUSLxaT+UQwUcC5bTxzqMYR4 /jDVofjqVqsuEJVGHwD8uUP6+SIP+oJZwAFwMhYMgacLYd7TvYjTIMPAvUPh6ZhUzOq8 Yt3Hvs2le5ImeWp0EEUTNNg3ycEn9vn9+O9OQv4VNMAKfKXYB944UtlVIk2mAMmfJIht i0mhCm3J0NUyBT3tAs+nX1c00/d/ulXQjfQqVfoRgqJUCEeIbu7jb5IjMO4DoDKyZC4O EEYsLgxhwIr6oYEyBTYsM5Rxf1ycNbdQ9xEBA6Be6DYZ7N0eosfqA9ohlsFx1giNOw8K BAjg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=FpLSzRDBFCpZ3Mg7TGIeqNJBrGxYU89Qt41RBLRDK2o=; b=ISJ9G8vRK8k/BMTXp5kgn24MckagAHhlmVhK/AYQjruA44+sR0v7/OsLAGpezMySQH mX2HPbYFMy10XSsWPilj38hIVQs4MHB3lbmEMF+GyidRE2HAN07pfnPEcXXTxIiSTIX1 eYTBLqEj29DrVBN99sg+5XPDz//YFUn0oXydLXjRalxBOka1XhHujze/WETf7AWqM0bg kJVlNRS1vna7oMG3zTQM9IRHjQ1OSH34oKqjxExOkZgIjuUAud96QrR9daB0XqYQqxBo agKbt/c8hicBeKK9vWow5hlhfD1VZPLPN5QJVQh3Nq4ua2GyVuTLVYJ2XVN4EWhNnZfB 91fA== X-Gm-Message-State: AN3rC/5tVZTkS3Mx8cIeHLpqntfldBwZM4QPHvwZZDHLHNlg6Z9ngT3+J3MWC6S16CCmkw== X-Received: by 10.223.135.84 with SMTP id 20mr2532852wrz.199.1491761382985; Sun, 09 Apr 2017 11:09:42 -0700 (PDT) Received: from localhost.lan ([37.209.189.139]) by smtp.googlemail.com with ESMTPSA id b66sm14366139wrd.29.2017.04.09.11.09.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 09 Apr 2017 11:09:42 -0700 (PDT) From: Ralph Sennhauser To: Thierry Reding Subject: [PATCH v5 1/4] gpio: mvebu: Add limited PWM support Date: Sun, 9 Apr 2017 20:09:27 +0200 Message-Id: <20170409180931.4884-2-ralph.sennhauser@gmail.com> X-Mailer: git-send-email 2.10.2 In-Reply-To: <20170409180931.4884-1-ralph.sennhauser@gmail.com> References: <20170409180931.4884-1-ralph.sennhauser@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170409_111005_717624_7C540875 X-CRM114-Status: GOOD ( 24.99 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Andrew Lunn , Jason Cooper , Alexandre Courbot , Linus Walleij , Russell King , linux-pwm@vger.kernel.org, linux-kernel@vger.kernel.org, Gregory Clement , devicetree@vger.kernel.org, Rob Herring , linux-gpio@vger.kernel.org, Ralph Sennhauser , linux-arm-kernel@lists.infradead.org, Sebastian Hesselbarth MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Andrew Lunn Armada 370/XP devices can 'blink' GPIO lines with a configurable on and off period. This can be modelled as a PWM. However, there are only two sets of PWM configuration registers for all the GPIO lines. This driver simply allows a single GPIO line per GPIO chip of 32 lines to be used as a PWM. Attempts to use more return EBUSY. Due to the interleaving of registers it is not simple to separate the PWM driver from the GPIO driver. Thus the GPIO driver has been extended with a PWM driver. Signed-off-by: Andrew Lunn URL: https://patchwork.ozlabs.org/patch/427287/ URL: https://patchwork.ozlabs.org/patch/427295/ [Ralph Sennhauser: * Port forward * Merge PWM portion into gpio-mvebu.c * Switch to atomic PWM API * Add new compatible string marvell,armada-370-xp-gpio * Update and merge documentation patch * Update MAINTAINERS] Signed-off-by: Ralph Sennhauser Tested-by: Andrew Lunn Acked-by: Thierry Reding Acked-by: Rob Herring --- .../devicetree/bindings/gpio/gpio-mvebu.txt | 32 ++ MAINTAINERS | 2 + drivers/gpio/gpio-mvebu.c | 324 ++++++++++++++++++++- 3 files changed, 346 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt b/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt index a6f3bec..fe49e9d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt @@ -38,6 +38,24 @@ Required properties: - #gpio-cells: Should be two. The first cell is the pin number. The second cell is reserved for flags, unused at the moment. +Optional properties: + +In order to use the gpio lines in PWM mode, some additional optional +properties are required. Only Armada 370 and XP support these properties. + +- compatible: Must contain "marvell,armada-370-xp-gpio" + +- reg: an additional register set is needed, for the GPIO Blink + Counter on/off registers. + +- reg-names: Must contain an entry "pwm" corresponding to the + additional register range needed for pwm operation. + +- #pwm-cells: Should be two. The first cell is the GPIO line number. The + second cell is the period in nanoseconds. + +- clocks: Must be a phandle to the clock for the gpio controller. + Example: gpio0: gpio@d0018100 { @@ -51,3 +69,17 @@ Example: #interrupt-cells = <2>; interrupts = <16>, <17>, <18>, <19>; }; + + gpio1: gpio@18140 { + compatible = "marvell,armada-370-xp-gpio"; + reg = <0x18140 0x40>, <0x181c8 0x08>; + reg-names = "gpio", "pwm"; + ngpios = <17>; + gpio-controller; + #gpio-cells = <2>; + #pwm-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <87>, <88>, <89>; + clocks = <&coreclk 0>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 58b3a22..19382f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10295,6 +10295,8 @@ F: include/linux/pwm.h F: drivers/pwm/ F: drivers/video/backlight/pwm_bl.c F: include/linux/pwm_backlight.h +F: drivers/gpio/gpio-mvebu.c +F: Documentation/devicetree/bindings/gpio/gpio-mvebu.txt PXA2xx/PXA3xx SUPPORT M: Daniel Mack diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index fae4db6..e310951 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -42,22 +42,34 @@ #include #include #include +#include #include #include #include +#include #include +#include "gpiolib.h" + /* * GPIO unit register offsets. */ -#define GPIO_OUT_OFF 0x0000 -#define GPIO_IO_CONF_OFF 0x0004 -#define GPIO_BLINK_EN_OFF 0x0008 -#define GPIO_IN_POL_OFF 0x000c -#define GPIO_DATA_IN_OFF 0x0010 -#define GPIO_EDGE_CAUSE_OFF 0x0014 -#define GPIO_EDGE_MASK_OFF 0x0018 -#define GPIO_LEVEL_MASK_OFF 0x001c +#define GPIO_OUT_OFF 0x0000 +#define GPIO_IO_CONF_OFF 0x0004 +#define GPIO_BLINK_EN_OFF 0x0008 +#define GPIO_IN_POL_OFF 0x000c +#define GPIO_DATA_IN_OFF 0x0010 +#define GPIO_EDGE_CAUSE_OFF 0x0014 +#define GPIO_EDGE_MASK_OFF 0x0018 +#define GPIO_LEVEL_MASK_OFF 0x001c +#define GPIO_BLINK_CNT_SELECT_OFF 0x0020 + +/* + * PWM register offsets. + */ +#define PWM_BLINK_ON_DURATION_OFF 0x0 +#define PWM_BLINK_OFF_DURATION_OFF 0x4 + /* The MV78200 has per-CPU registers for edge mask and level mask */ #define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) @@ -78,6 +90,20 @@ #define MVEBU_MAX_GPIO_PER_BANK 32 +struct mvebu_pwm { + void __iomem *membase; + unsigned long clk_rate; + bool used; + struct pwm_chip chip; + spinlock_t lock; + struct mvebu_gpio_chip *mvchip; + + /* Used to preserve GPIO/PWM registers across suspend/resume */ + u32 blink_select; + u32 blink_on_duration; + u32 blink_off_duration; +}; + struct mvebu_gpio_chip { struct gpio_chip chip; spinlock_t lock; @@ -87,6 +113,10 @@ struct mvebu_gpio_chip { struct irq_domain *domain; int soc_variant; + /* Used for PWM support */ + struct clk *clk; + struct mvebu_pwm *mvpwm; + /* Used to preserve GPIO registers across suspend/resume */ u32 out_reg; u32 io_conf_reg; @@ -110,6 +140,12 @@ static void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_BLINK_EN_OFF; } +static void __iomem *mvebu_gpioreg_blink_counter_select(struct mvebu_gpio_chip + *mvchip) +{ + return mvchip->membase + GPIO_BLINK_CNT_SELECT_OFF; +} + static void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; @@ -181,6 +217,20 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) } /* + * Functions returning addresses of individual registers for a given + * PWM controller. + */ +static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm) +{ + return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF; +} + +static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) +{ + return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF; +} + +/* * Functions implementing the gpio_chip methods */ static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) @@ -484,6 +534,243 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } +/* + * Functions implementing the pwm_chip methods + */ +static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct mvebu_pwm, chip); +} + +static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + struct gpio_desc *desc = gpio_to_desc(pwm->pwm); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&mvpwm->lock, flags); + if (mvpwm->used) { + ret = -EBUSY; + } else { + if (!desc) { + ret = -ENODEV; + goto out; + } + ret = gpiod_request(desc, "mvebu-pwm"); + if (ret) + goto out; + + ret = gpiod_direction_output(desc, 0); + if (ret) { + gpiod_free(desc); + goto out; + } + + mvpwm->used = true; + } + +out: + spin_unlock_irqrestore(&mvpwm->lock, flags); + return ret; +} + +static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + struct gpio_desc *desc = gpio_to_desc(pwm->pwm); + unsigned long flags; + + spin_lock_irqsave(&mvpwm->lock, flags); + gpiod_free(desc); + mvpwm->used = false; + spin_unlock_irqrestore(&mvpwm->lock, flags); +} + +static void mvebu_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) { + + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; + unsigned long long val; + unsigned long flags; + u32 u; + + spin_lock_irqsave(&mvpwm->lock, flags); + + val = (unsigned long long) + readl_relaxed(mvebu_pwmreg_blink_on_duration); + val *= NSEC_PER_SEC; + do_div(val, mvpwm->clk_rate); + if (val > UINT_MAX) + state->duty_cycle = UINT_MAX; + else if (val) + state->duty_cycle = val; + else + state->duty_cycle = 1; + + val = (unsigned long long) + readl_relaxed(mvebu_pwmreg_blink_off_duration); + val *= NSEC_PER_SEC; + do_div(val, mvpwm->clk_rate); + if (val < state->duty_cycle) { + state->period = 1; + } else { + val -= state->duty_cycle; + if (val > UINT_MAX) + state->period = UINT_MAX; + else if (val) + state->period = val; + else + state->period = 1; + } + + u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); + if (u) + state->enabled = true; + else + state->enabled = false; + + spin_unlock_irqrestore(&mvpwm->lock, flags); +} + +static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); + struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; + unsigned long long val; + unsigned long flags; + unsigned int on, off; + + val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle; + do_div(val, NSEC_PER_SEC); + if (val > UINT_MAX) + return -EINVAL; + if (val) + on = val; + else + on = 1; + + val = (unsigned long long) mvpwm->clk_rate * + (state->period - state->duty_cycle); + do_div(val, NSEC_PER_SEC); + if (val > UINT_MAX) + return -EINVAL; + if (val) + off = val; + else + off = 1; + + spin_lock_irqsave(&mvpwm->lock, flags); + + writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm)); + writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm)); + if (state->enabled) + mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1); + else + mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 0); + + spin_unlock_irqrestore(&mvpwm->lock, flags); + + return 0; +} + +static const struct pwm_ops mvebu_pwm_ops = { + .request = mvebu_pwm_request, + .free = mvebu_pwm_free, + .get_state = mvebu_pwm_get_state, + .apply = mvebu_pwm_apply, + .owner = THIS_MODULE, +}; + +static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip) +{ + struct mvebu_pwm *mvpwm = mvchip->mvpwm; + + mvpwm->blink_select = + readl_relaxed(mvebu_gpioreg_blink_counter_select(mvchip)); + mvpwm->blink_on_duration = + readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); + mvpwm->blink_off_duration = + readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm)); +} + +static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip) +{ + struct mvebu_pwm *mvpwm = mvchip->mvpwm; + + writel_relaxed(mvpwm->blink_select, + mvebu_gpioreg_blink_counter_select(mvchip)); + writel_relaxed(mvpwm->blink_on_duration, + mvebu_pwmreg_blink_on_duration(mvpwm)); + writel_relaxed(mvpwm->blink_off_duration, + mvebu_pwmreg_blink_off_duration(mvpwm)); +} + +static int mvebu_pwm_probe(struct platform_device *pdev, + struct mvebu_gpio_chip *mvchip, + int id) +{ + struct device *dev = &pdev->dev; + struct mvebu_pwm *mvpwm; + struct resource *res; + + if (!of_device_is_compatible(mvchip->chip.of_node, + "marvell,armada-370-xp-gpio")) + return 0; + /* + * There are only two sets of PWM configuration registers for + * all the GPIO lines on those SoCs which this driver reserves + * for the first two GPIO chips. So if the resource is missing + * we can't treat it as an error. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"); + if (!res) + return 0; + + /* + * Use set A for lines of GPIO chip with id 0, B for GPIO chip + * with id 1. Don't allow further GPIO chips to be used for PWM. + */ + if (id == 0) + writel_relaxed(0, mvebu_gpioreg_blink_counter_select(mvchip)); + else if (id == 1) + writel_relaxed(U32_MAX, + mvebu_gpioreg_blink_counter_select(mvchip)); + else + return -EINVAL; + + mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); + if (!mvpwm) + return -ENOMEM; + mvchip->mvpwm = mvpwm; + mvpwm->mvchip = mvchip; + + mvpwm->membase = devm_ioremap_resource(dev, res); + if (IS_ERR(mvpwm->membase)) + return PTR_ERR(mvpwm->membase); + + if (IS_ERR(mvchip->clk)) + return PTR_ERR(mvchip->clk); + + mvpwm->clk_rate = clk_get_rate(mvchip->clk); + if (!mvpwm->clk_rate) { + dev_err(dev, "failed to get clock rate\n"); + return -EINVAL; + } + + mvpwm->chip.dev = dev; + mvpwm->chip.ops = &mvebu_pwm_ops; + mvpwm->chip.base = mvchip->chip.base; + mvpwm->chip.npwm = mvchip->chip.ngpio; + + spin_lock_init(&mvpwm->lock); + + return pwmchip_add(&mvpwm->chip); +} + #ifdef CONFIG_DEBUG_FS #include @@ -555,6 +842,10 @@ static const struct of_device_id mvebu_gpio_of_match[] = { .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, }, { + .compatible = "marvell,armada-370-xp-gpio", + .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, + }, + { /* sentinel */ }, }; @@ -600,6 +891,9 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) BUG(); } + if (IS_ENABLED(CONFIG_PWM)) + mvebu_pwm_suspend(mvchip); + return 0; } @@ -643,6 +937,9 @@ static int mvebu_gpio_resume(struct platform_device *pdev) BUG(); } + if (IS_ENABLED(CONFIG_PWM)) + mvebu_pwm_resume(mvchip); + return 0; } @@ -654,7 +951,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev) struct resource *res; struct irq_chip_generic *gc; struct irq_chip_type *ct; - struct clk *clk; unsigned int ngpios; bool have_irqs; int soc_variant; @@ -688,10 +984,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev) return id; } - clk = devm_clk_get(&pdev->dev, NULL); + mvchip->clk = devm_clk_get(&pdev->dev, NULL); /* Not all SoCs require a clock.*/ - if (!IS_ERR(clk)) - clk_prepare_enable(clk); + if (!IS_ERR(mvchip->clk)) + clk_prepare_enable(mvchip->clk); mvchip->soc_variant = soc_variant; mvchip->chip.label = dev_name(&pdev->dev); @@ -822,6 +1118,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip); } + /* Armada 370/XP has simple PWM support for GPIO lines */ + if (IS_ENABLED(CONFIG_PWM)) + return mvebu_pwm_probe(pdev, mvchip, id); + return 0; err_domain: