summaryrefslogtreecommitdiff
path: root/drivers/pwm/pwm-brcmstb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pwm/pwm-brcmstb.c')
-rw-r--r--drivers/pwm/pwm-brcmstb.c143
1 files changed, 47 insertions, 96 deletions
diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
index 8063cffa1c96..82d27d07ba91 100644
--- a/drivers/pwm/pwm-brcmstb.c
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Broadcom BCM7038 PWM driver
* Author: Florian Fainelli
*
* Copyright (C) 2015 Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -62,9 +53,7 @@
struct brcmstb_pwm {
void __iomem *base;
- spinlock_t lock;
struct clk *clk;
- struct pwm_chip chip;
};
static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
@@ -87,7 +76,7 @@ static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value,
static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
{
- return container_of(chip, struct brcmstb_pwm, chip);
+ return pwmchip_get_drvdata(chip);
}
/*
@@ -104,7 +93,7 @@ static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
* "on" time, so this translates directly into our HW programming here.
*/
static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+ u64 duty_ns, u64 period_ns)
{
struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
unsigned long pc, dc, cword = CONST_VAR_F_MAX;
@@ -123,22 +112,17 @@ static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
}
while (1) {
- u64 rate, tmp;
+ u64 rate;
/*
* Calculate the base rate from base frequency and current
* cword
*/
rate = (u64)clk_get_rate(p->clk) * (u64)cword;
- do_div(rate, 1 << CWORD_BIT_SIZE);
+ rate >>= CWORD_BIT_SIZE;
- tmp = period_ns * rate;
- do_div(tmp, NSEC_PER_SEC);
- pc = tmp;
-
- tmp = (duty_ns + 1) * rate;
- do_div(tmp, NSEC_PER_SEC);
- dc = tmp;
+ pc = mul_u64_u64_div_u64(period_ns, rate, NSEC_PER_SEC);
+ dc = mul_u64_u64_div_u64(duty_ns + 1, rate, NSEC_PER_SEC);
/*
* We can be called with separate duty and period updates,
@@ -173,7 +157,6 @@ done:
* generator output a base frequency for the constant frequency
* generator to derive from.
*/
- spin_lock(&p->lock);
brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel));
brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel));
@@ -185,7 +168,6 @@ done:
/* Configure on and period value */
brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel));
brcmstb_pwm_writel(p, dc, PWM_ON(channel));
- spin_unlock(&p->lock);
return 0;
}
@@ -196,7 +178,6 @@ static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p,
unsigned int shift = channel * CTRL_CHAN_OFFS;
u32 value;
- spin_lock(&p->lock);
value = brcmstb_pwm_readl(p, PWM_CTRL);
if (enable) {
@@ -208,30 +189,36 @@ static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p,
}
brcmstb_pwm_writel(p, value, PWM_CTRL);
- spin_unlock(&p->lock);
}
-static int brcmstb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int brcmstb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
+ int err;
- brcmstb_pwm_enable_set(p, pwm->hwpwm, true);
+ if (state->polarity != PWM_POLARITY_NORMAL)
+ return -EINVAL;
- return 0;
-}
+ if (!state->enabled) {
+ if (pwm->state.enabled)
+ brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
-static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
+ return 0;
+ }
- brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
+ err = brcmstb_pwm_config(chip, pwm, state->duty_cycle, state->period);
+ if (err)
+ return err;
+
+ if (!pwm->state.enabled)
+ brcmstb_pwm_enable_set(p, pwm->hwpwm, true);
+
+ return 0;
}
static const struct pwm_ops brcmstb_pwm_ops = {
- .config = brcmstb_pwm_config,
- .enable = brcmstb_pwm_enable,
- .disable = brcmstb_pwm_disable,
- .owner = THIS_MODULE,
+ .apply = brcmstb_pwm_apply,
};
static const struct of_device_id brcmstb_pwm_of_match[] = {
@@ -242,72 +229,40 @@ MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match);
static int brcmstb_pwm_probe(struct platform_device *pdev)
{
+ struct pwm_chip *chip;
struct brcmstb_pwm *p;
- struct resource *res;
int ret;
- p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- spin_lock_init(&p->lock);
+ chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*p));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+ p = to_brcmstb_pwm(chip);
- p->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(p->clk)) {
- dev_err(&pdev->dev, "failed to obtain clock\n");
- return PTR_ERR(p->clk);
- }
-
- ret = clk_prepare_enable(p->clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
- return ret;
- }
+ p->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(p->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(p->clk),
+ "failed to obtain clock\n");
platform_set_drvdata(pdev, p);
- p->chip.dev = &pdev->dev;
- p->chip.ops = &brcmstb_pwm_ops;
- p->chip.base = -1;
- p->chip.npwm = 2;
+ chip->ops = &brcmstb_pwm_ops;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- p->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(p->base)) {
- ret = PTR_ERR(p->base);
- goto out_clk;
- }
+ p->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(p->base))
+ return PTR_ERR(p->base);
- ret = pwmchip_add(&p->chip);
- if (ret) {
- dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
- goto out_clk;
- }
+ ret = devm_pwmchip_add(&pdev->dev, chip);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
return 0;
-
-out_clk:
- clk_disable_unprepare(p->clk);
- return ret;
-}
-
-static int brcmstb_pwm_remove(struct platform_device *pdev)
-{
- struct brcmstb_pwm *p = platform_get_drvdata(pdev);
- int ret;
-
- ret = pwmchip_remove(&p->chip);
- clk_disable_unprepare(p->clk);
-
- return ret;
}
-#ifdef CONFIG_PM_SLEEP
static int brcmstb_pwm_suspend(struct device *dev)
{
struct brcmstb_pwm *p = dev_get_drvdata(dev);
- clk_disable(p->clk);
+ clk_disable_unprepare(p->clk);
return 0;
}
@@ -316,22 +271,18 @@ static int brcmstb_pwm_resume(struct device *dev)
{
struct brcmstb_pwm *p = dev_get_drvdata(dev);
- clk_enable(p->clk);
-
- return 0;
+ return clk_prepare_enable(p->clk);
}
-#endif
-static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
- brcmstb_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
+ brcmstb_pwm_resume);
static struct platform_driver brcmstb_pwm_driver = {
.probe = brcmstb_pwm_probe,
- .remove = brcmstb_pwm_remove,
.driver = {
.name = "pwm-brcmstb",
.of_match_table = brcmstb_pwm_of_match,
- .pm = &brcmstb_pwm_pm_ops,
+ .pm = pm_ptr(&brcmstb_pwm_pm_ops),
},
};
module_platform_driver(brcmstb_pwm_driver);