Merge pull request #2651 from armbian/AR-648
[AR-648] mvebu-dev: Adjust gpio-pwm patch
This commit is contained in:
commit
0b8b5f1de6
@ -1,59 +0,0 @@
|
||||
From 0ef9299ef1afce1dbf847e75cdd16e2343d89bf9 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Pecovnik <igor.pecovnik@gmail.com>
|
||||
Date: Sat, 30 Jan 2021 19:06:41 +0100
|
||||
Subject: [PATCH] Revert "gpio: mvebu: fix pwm .get_state period calculation"
|
||||
|
||||
This reverts commit 43f2e6077f441d681f0337ab91f7c4c2d4c62761.
|
||||
---
|
||||
drivers/gpio/gpio-mvebu.c | 25 +++++++++++++++----------
|
||||
1 file changed, 15 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
|
||||
index ed7c5fc47f52..2f245594a90a 100644
|
||||
--- a/drivers/gpio/gpio-mvebu.c
|
||||
+++ b/drivers/gpio/gpio-mvebu.c
|
||||
@@ -660,8 +660,9 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
|
||||
spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
|
||||
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u);
|
||||
- val = (unsigned long long) u * NSEC_PER_SEC;
|
||||
+ val = (unsigned long long)
|
||||
+ readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
+ val *= NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
if (val > UINT_MAX)
|
||||
state->duty_cycle = UINT_MAX;
|
||||
@@ -670,17 +671,21 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
else
|
||||
state->duty_cycle = 1;
|
||||
|
||||
- val = (unsigned long long) u; /* on duration */
|
||||
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
|
||||
- val += (unsigned long long) u; /* period = on + off duration */
|
||||
+ val = (unsigned long long)
|
||||
+ readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
val *= NSEC_PER_SEC;
|
||||
do_div(val, mvpwm->clk_rate);
|
||||
- if (val > UINT_MAX)
|
||||
- state->period = UINT_MAX;
|
||||
- else if (val)
|
||||
- state->period = val;
|
||||
- else
|
||||
+ 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;
|
||||
+ }
|
||||
|
||||
regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
|
||||
if (u)
|
||||
--
|
||||
2.25.1
|
||||
|
||||
@ -0,0 +1,379 @@
|
||||
From e4728fcf779c37d1bcbd4b6505c9b40d4bb9ff48 Mon Sep 17 00:00:00 2001
|
||||
From: Heisath <jannis@imserv.org>
|
||||
Date: Mon, 22 Feb 2021 12:24:54 +0100
|
||||
Subject: [PATCH] Removes the hardcoded timer assignment of timers to pwm controllers
|
||||
This allows to use more than one pwm per gpio bank.
|
||||
|
||||
Original patch by helios4 team, updated to work on LK5.11+
|
||||
|
||||
Signed-off-by: Heisath <jannis@imserv.org>
|
||||
---
|
||||
drivers/gpio/gpio-mvebu.c | 198 +++++++++++++++++++++++++++-----------
|
||||
1 file changed, 144 insertions(+), 54 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
|
||||
index 3a19b4140..195b685de 100644
|
||||
--- a/drivers/gpio/gpio-mvebu.c
|
||||
+++ b/drivers/gpio/gpio-mvebu.c
|
||||
@@ -92,20 +92,41 @@
|
||||
|
||||
#define MVEBU_MAX_GPIO_PER_BANK 32
|
||||
|
||||
-struct mvebu_pwm {
|
||||
+enum mvebu_pwm_ctrl {
|
||||
+ MVEBU_PWM_CTRL_SET_A = 0,
|
||||
+ MVEBU_PWM_CTRL_SET_B,
|
||||
+ MVEBU_PWM_CTRL_MAX
|
||||
+};
|
||||
+
|
||||
+struct mvebu_pwmchip {
|
||||
struct regmap *regs;
|
||||
- unsigned long clk_rate;
|
||||
+ unsigned long clk_rate;
|
||||
+ spinlock_t lock;
|
||||
+ bool in_use;
|
||||
+
|
||||
+ /* Used to preserve GPIO/PWM registers across suspend/resume */
|
||||
+ u32 blink_on_duration;
|
||||
+ u32 blink_off_duration;
|
||||
+};
|
||||
+
|
||||
+struct mvebu_pwm_chip_drv {
|
||||
+ enum mvebu_pwm_ctrl ctrl;
|
||||
struct gpio_desc *gpiod;
|
||||
- struct pwm_chip chip;
|
||||
- spinlock_t lock;
|
||||
+ bool master;
|
||||
+};
|
||||
+
|
||||
+struct mvebu_pwm {
|
||||
+ struct pwm_chip chip;
|
||||
struct mvebu_gpio_chip *mvchip;
|
||||
+ struct mvebu_pwmchip controller;
|
||||
+ enum mvebu_pwm_ctrl default_counter;
|
||||
|
||||
/* Used to preserve GPIO/PWM registers across suspend/resume */
|
||||
u32 blink_select;
|
||||
- u32 blink_on_duration;
|
||||
- u32 blink_off_duration;
|
||||
};
|
||||
|
||||
+static struct mvebu_pwmchip *mvebu_pwm_list[MVEBU_PWM_CTRL_MAX];
|
||||
+
|
||||
struct mvebu_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
struct regmap *regs;
|
||||
@@ -282,12 +303,12 @@ mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
|
||||
* Functions returning offsets of individual registers for a given
|
||||
* PWM controller.
|
||||
*/
|
||||
-static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
|
||||
+static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwmchip *mvpwm)
|
||||
{
|
||||
return PWM_BLINK_ON_DURATION_OFF;
|
||||
}
|
||||
|
||||
-static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
|
||||
+static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwmchip *mvpwm)
|
||||
{
|
||||
return PWM_BLINK_OFF_DURATION_OFF;
|
||||
}
|
||||
@@ -647,39 +668,84 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
struct gpio_desc *desc;
|
||||
+ enum mvebu_pwm_ctrl id;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
+ struct mvebu_pwm_chip_drv *chip_data;
|
||||
+
|
||||
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
|
||||
+ &mvchip->blink_en_reg);
|
||||
|
||||
- if (mvpwm->gpiod) {
|
||||
+ if (pwm->chip_data || (mvchip->blink_en_reg & BIT(pwm->hwpwm))) {
|
||||
ret = -EBUSY;
|
||||
- } else {
|
||||
- desc = gpiochip_request_own_desc(&mvchip->chip,
|
||||
- pwm->hwpwm, "mvebu-pwm",
|
||||
- GPIO_ACTIVE_HIGH,
|
||||
- GPIOD_OUT_LOW);
|
||||
- if (IS_ERR(desc)) {
|
||||
- ret = PTR_ERR(desc);
|
||||
- goto out;
|
||||
- }
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
- mvpwm->gpiod = desc;
|
||||
+ desc = gpiochip_request_own_desc(&mvchip->chip,
|
||||
+ pwm->hwpwm, "mvebu-pwm",
|
||||
+ GPIO_ACTIVE_HIGH,
|
||||
+ GPIOD_OUT_LOW);
|
||||
+
|
||||
+ if (IS_ERR(desc)) {
|
||||
+ ret = PTR_ERR(desc);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ret = gpiod_direction_output(desc, 0);
|
||||
+ if (ret) {
|
||||
+ gpiochip_free_own_desc(desc);
|
||||
+ goto out;
|
||||
}
|
||||
+
|
||||
+ chip_data = kzalloc(sizeof(struct mvebu_pwm_chip_drv), GFP_KERNEL);
|
||||
+ if (!chip_data) {
|
||||
+ gpiochip_free_own_desc(desc);
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ for (id = MVEBU_PWM_CTRL_SET_A; id < MVEBU_PWM_CTRL_MAX; id++) {
|
||||
+ if (!mvebu_pwm_list[id]->in_use) {
|
||||
+ chip_data->ctrl = id;
|
||||
+ chip_data->master = true;
|
||||
+ mvebu_pwm_list[id]->in_use = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!chip_data->master)
|
||||
+ chip_data->ctrl = mvpwm->default_counter;
|
||||
+
|
||||
+ regmap_update_bits(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
+ BIT(pwm->hwpwm), chip_data->ctrl ? BIT(pwm->hwpwm) : 0);
|
||||
+
|
||||
+ chip_data->gpiod = desc;
|
||||
+ pwm->chip_data = chip_data;
|
||||
+
|
||||
+ regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
+ &mvpwm->blink_select);
|
||||
+
|
||||
out:
|
||||
- spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
+ spin_unlock_irqrestore(&mvpwm->controller.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 mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
|
||||
unsigned long flags;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
- gpiochip_free_own_desc(mvpwm->gpiod);
|
||||
- mvpwm->gpiod = NULL;
|
||||
- spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
|
||||
+ if (chip_data->master)
|
||||
+ mvebu_pwm_list[chip_data->ctrl]->in_use = false;
|
||||
+
|
||||
+ gpiochip_free_own_desc(chip_data->gpiod);
|
||||
+ kfree(chip_data);
|
||||
+ pwm->chip_data = NULL;
|
||||
+ spin_unlock_irqrestore(&mvpwm->controller.lock, flags);
|
||||
}
|
||||
|
||||
static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
@@ -687,16 +753,23 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
struct pwm_state *state) {
|
||||
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
+ struct mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
|
||||
+ struct mvebu_pwmchip *controller;
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
unsigned long long val;
|
||||
unsigned long flags;
|
||||
u32 u;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ if (chip_data)
|
||||
+ controller = mvebu_pwm_list[chip_data->ctrl];
|
||||
+ else
|
||||
+ controller = &mvpwm->controller;
|
||||
+
|
||||
+ spin_lock_irqsave(&controller->lock, flags);
|
||||
|
||||
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u);
|
||||
+ regmap_read(controller->regs, mvebu_pwmreg_blink_on_duration(controller), &u);
|
||||
val = (unsigned long long) u * NSEC_PER_SEC;
|
||||
- do_div(val, mvpwm->clk_rate);
|
||||
+ do_div(val, controller->clk_rate);
|
||||
if (val > UINT_MAX)
|
||||
state->duty_cycle = UINT_MAX;
|
||||
else if (val)
|
||||
@@ -705,10 +778,10 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
state->duty_cycle = 1;
|
||||
|
||||
val = (unsigned long long) u; /* on duration */
|
||||
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
|
||||
+ regmap_read(controller->regs, mvebu_pwmreg_blink_off_duration(controller), &u);
|
||||
val += (unsigned long long) u; /* period = on + off duration */
|
||||
val *= NSEC_PER_SEC;
|
||||
- do_div(val, mvpwm->clk_rate);
|
||||
+ do_div(val, controller->clk_rate);
|
||||
if (val > UINT_MAX)
|
||||
state->period = UINT_MAX;
|
||||
else if (val)
|
||||
@@ -722,19 +795,27 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
else
|
||||
state->enabled = false;
|
||||
|
||||
- spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
+ spin_unlock_irqrestore(&controller->lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
+ struct mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
|
||||
+ struct mvebu_pwmchip *controller;
|
||||
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;
|
||||
+ if (chip_data)
|
||||
+ controller = mvebu_pwm_list[chip_data->ctrl];
|
||||
+ else
|
||||
+ controller = &mvpwm->controller;
|
||||
+
|
||||
+
|
||||
+ val = (unsigned long long) controller->clk_rate * state->duty_cycle;
|
||||
do_div(val, NSEC_PER_SEC);
|
||||
if (val > UINT_MAX)
|
||||
return -EINVAL;
|
||||
@@ -743,7 +824,7 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
else
|
||||
on = 1;
|
||||
|
||||
- val = (unsigned long long) mvpwm->clk_rate *
|
||||
+ val = (unsigned long long) controller->clk_rate *
|
||||
(state->period - state->duty_cycle);
|
||||
do_div(val, NSEC_PER_SEC);
|
||||
if (val > UINT_MAX)
|
||||
@@ -753,16 +834,16 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
else
|
||||
off = 1;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ spin_lock_irqsave(&controller->lock, flags);
|
||||
|
||||
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), on);
|
||||
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), off);
|
||||
+ regmap_write(controller->regs, mvebu_pwmreg_blink_on_duration(controller), on);
|
||||
+ regmap_write(controller->regs, mvebu_pwmreg_blink_off_duration(controller), off);
|
||||
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);
|
||||
+ spin_unlock_irqrestore(&controller->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -778,25 +859,27 @@ static const struct pwm_ops mvebu_pwm_ops = {
|
||||
static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = mvchip->mvpwm;
|
||||
+ struct mvebu_pwmchip *controller = &mvpwm->controller;
|
||||
|
||||
regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
&mvpwm->blink_select);
|
||||
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
|
||||
- &mvpwm->blink_on_duration);
|
||||
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
|
||||
- &mvpwm->blink_off_duration);
|
||||
+ regmap_read(controller->regs, mvebu_pwmreg_blink_on_duration(controller),
|
||||
+ &controller->blink_on_duration);
|
||||
+ regmap_read(controller->regs, mvebu_pwmreg_blink_off_duration(controller),
|
||||
+ &controller->blink_off_duration);
|
||||
}
|
||||
|
||||
static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = mvchip->mvpwm;
|
||||
+ struct mvebu_pwmchip *controller = &mvpwm->controller;
|
||||
|
||||
regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
mvpwm->blink_select);
|
||||
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
|
||||
- mvpwm->blink_on_duration);
|
||||
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
|
||||
- mvpwm->blink_off_duration);
|
||||
+ regmap_write(controller->regs, mvebu_pwmreg_blink_on_duration(controller),
|
||||
+ controller->blink_on_duration);
|
||||
+ regmap_write(controller->regs, mvebu_pwmreg_blink_off_duration(controller),
|
||||
+ controller->blink_off_duration);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
@@ -807,6 +890,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
struct mvebu_pwm *mvpwm;
|
||||
void __iomem *base;
|
||||
u32 set;
|
||||
+ enum mvebu_pwm_ctrl ctrl_set;
|
||||
|
||||
if (!of_device_is_compatible(mvchip->chip.of_node,
|
||||
"marvell,armada-370-gpio"))
|
||||
@@ -828,12 +912,16 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
* 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)
|
||||
+ if (id == 0) {
|
||||
set = 0;
|
||||
- else if (id == 1)
|
||||
+ ctrl_set = MVEBU_PWM_CTRL_SET_A;
|
||||
+ } else if (id == 1) {
|
||||
set = U32_MAX;
|
||||
- else
|
||||
+ ctrl_set = MVEBU_PWM_CTRL_SET_B;
|
||||
+ } else {
|
||||
return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
regmap_write(mvchip->regs,
|
||||
GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
|
||||
|
||||
@@ -847,13 +935,13 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
- mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
+ mvpwm->controller.regs = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&mvebu_gpio_regmap_config);
|
||||
- if (IS_ERR(mvpwm->regs))
|
||||
- return PTR_ERR(mvpwm->regs);
|
||||
+ if (IS_ERR(mvpwm->controller.regs))
|
||||
+ return PTR_ERR(mvpwm->controller.regs);
|
||||
|
||||
- mvpwm->clk_rate = clk_get_rate(mvchip->clk);
|
||||
- if (!mvpwm->clk_rate) {
|
||||
+ mvpwm->controller.clk_rate = clk_get_rate(mvchip->clk);
|
||||
+ if (!mvpwm->controller.clk_rate) {
|
||||
dev_err(dev, "failed to get clock rate\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -869,7 +957,9 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
*/
|
||||
mvpwm->chip.base = -1;
|
||||
|
||||
- spin_lock_init(&mvpwm->lock);
|
||||
+ spin_lock_init(&mvpwm->controller.lock);
|
||||
+ mvpwm->default_counter = ctrl_set;
|
||||
+ mvebu_pwm_list[ctrl_set] = &mvpwm->controller;
|
||||
|
||||
return pwmchip_add(&mvpwm->chip);
|
||||
}
|
||||
--
|
||||
Created with Armbian build tools https://github.com/armbian/build
|
||||
|
||||
@ -1,123 +0,0 @@
|
||||
--- a/drivers/gpio/gpio-mvebu.c
|
||||
+++ b/drivers/gpio/gpio-mvebu.c
|
||||
@@ -641,39 +641,81 @@ static int mvebu_pwm_request(struct pwm_
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
struct gpio_desc *desc;
|
||||
+ enum mvebu_pwm_ctrl id;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
+ struct mvebu_pwm_chip_drv *chip_data;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
|
||||
|
||||
- if (mvpwm->gpiod) {
|
||||
- ret = -EBUSY;
|
||||
- } else {
|
||||
- desc = gpiochip_request_own_desc(&mvchip->chip,
|
||||
+ regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
|
||||
+ &mvchip->blink_en_reg);
|
||||
+
|
||||
+ if (pwm->chip_data || (mvchip->blink_en_reg & BIT(pwm->hwpwm)))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ desc = gpiochip_request_own_desc(&mvchip->chip,
|
||||
pwm->hwpwm, "mvebu-pwm",
|
||||
GPIO_ACTIVE_HIGH,
|
||||
GPIOD_OUT_LOW);
|
||||
- if (IS_ERR(desc)) {
|
||||
- ret = PTR_ERR(desc);
|
||||
- goto out;
|
||||
- }
|
||||
+ if (IS_ERR(desc)) {
|
||||
+ ret = PTR_ERR(desc);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ret = gpiod_direction_output(desc, 0);
|
||||
+ if (ret) {
|
||||
+ gpiochip_free_own_desc(desc);
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
- mvpwm->gpiod = desc;
|
||||
+ chip_data = kzalloc(sizeof(struct mvebu_pwm_chip_drv), GFP_KERNEL);
|
||||
+ if (!chip_data) {
|
||||
+ gpiochip_free_own_desc(desc);
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out;
|
||||
}
|
||||
+
|
||||
+ for (id = MVEBU_PWM_CTRL_SET_A;id < MVEBU_PWM_CTRL_MAX; id++) {
|
||||
+ if (!mvebu_pwm_list[id]->in_use) {
|
||||
+ chip_data->ctrl = id;
|
||||
+ chip_data->master = true;
|
||||
+ mvebu_pwm_list[id]->in_use = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!chip_data->master)
|
||||
+ chip_data->ctrl = mvpwm->default_counter;
|
||||
+
|
||||
+ regmap_update_bits(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
+ BIT(pwm->hwpwm), chip_data->ctrl ? BIT(pwm->hwpwm) : 0);
|
||||
+
|
||||
+ chip_data->gpiod = desc;
|
||||
+ pwm->chip_data = chip_data;
|
||||
+
|
||||
+ regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
+ &mvpwm->blink_select);
|
||||
+
|
||||
out:
|
||||
- spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
+ spin_unlock_irqrestore(&mvpwm->controller.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 mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
|
||||
unsigned long flags;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
- gpiochip_free_own_desc(mvpwm->gpiod);
|
||||
- mvpwm->gpiod = NULL;
|
||||
- spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
|
||||
+ if (chip_data->master)
|
||||
+ mvebu_pwm_list[chip_data->ctrl]->in_use = false;
|
||||
+
|
||||
+ gpiochip_free_own_desc(chip_data->gpiod);
|
||||
+ kfree(chip_data);
|
||||
+ pwm->chip_data = NULL;
|
||||
+ spin_unlock_irqrestore(&mvpwm->controller.lock, flags);
|
||||
}
|
||||
|
||||
static void mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
@@ -721,19 +763,21 @@ static void mvebu_pwm_get_state(struct p
|
||||
else
|
||||
state->enabled = false;
|
||||
|
||||
- spin_unlock_irqrestore(&mvpwm->lock, flags);
|
||||
+ spin_unlock_irqrestore(&controller->lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
+ struct mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
|
||||
+ struct mvebu_pwmchip *controller = mvebu_pwm_list[chip_data->ctrl];
|
||||
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;
|
||||
+ val = (unsigned long long) controller->clk_rate * state->duty_cycle;
|
||||
do_div(val, NSEC_PER_SEC);
|
||||
if (val > UINT_MAX)
|
||||
return -EINVAL;
|
||||
@ -1,223 +0,0 @@
|
||||
--- a/drivers/gpio/gpio-mvebu.c
|
||||
+++ b/drivers/gpio/gpio-mvebu.c
|
||||
@@ -93,20 +93,41 @@
|
||||
|
||||
#define MVEBU_MAX_GPIO_PER_BANK 32
|
||||
|
||||
-struct mvebu_pwm {
|
||||
+enum mvebu_pwm_ctrl {
|
||||
+ MVEBU_PWM_CTRL_SET_A = 0,
|
||||
+ MVEBU_PWM_CTRL_SET_B,
|
||||
+ MVEBU_PWM_CTRL_MAX
|
||||
+};
|
||||
+
|
||||
+struct mvebu_pwmchip {
|
||||
void __iomem *membase;
|
||||
unsigned long clk_rate;
|
||||
+ spinlock_t lock;
|
||||
+ bool in_use;
|
||||
+
|
||||
+ /* Used to preserve GPIO/PWM registers across suspend/resume */
|
||||
+ u32 blink_on_duration;
|
||||
+ u32 blink_off_duration;
|
||||
+};
|
||||
+
|
||||
+struct mvebu_pwm_chip_drv {
|
||||
+ enum mvebu_pwm_ctrl ctrl;
|
||||
struct gpio_desc *gpiod;
|
||||
+ bool master;
|
||||
+};
|
||||
+
|
||||
+struct mvebu_pwm {
|
||||
struct pwm_chip chip;
|
||||
- spinlock_t lock;
|
||||
struct mvebu_gpio_chip *mvchip;
|
||||
+ struct mvebu_pwmchip controller;
|
||||
+ enum mvebu_pwm_ctrl default_counter;
|
||||
|
||||
/* Used to preserve GPIO/PWM registers across suspend/resume */
|
||||
u32 blink_select;
|
||||
- u32 blink_on_duration;
|
||||
- u32 blink_off_duration;
|
||||
};
|
||||
|
||||
+static struct mvebu_pwmchip *mvebu_pwm_list[MVEBU_PWM_CTRL_MAX];
|
||||
+
|
||||
struct mvebu_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
struct regmap *regs;
|
||||
@@ -283,12 +304,12 @@ mvebu_gpio_write_level_mask(struct mvebu
|
||||
* Functions returning addresses of individual registers for a given
|
||||
* PWM controller.
|
||||
*/
|
||||
-static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
|
||||
+static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwmchip *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF;
|
||||
}
|
||||
|
||||
-static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
|
||||
+static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwmchip *mvpwm)
|
||||
{
|
||||
return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF;
|
||||
}
|
||||
@@ -723,17 +744,24 @@ static void mvebu_pwm_get_state(struct p
|
||||
struct pwm_state *state) {
|
||||
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
+ struct mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
|
||||
+ struct mvebu_pwmchip *controller;
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
unsigned long long val;
|
||||
unsigned long flags;
|
||||
u32 u;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ if (chip_data)
|
||||
+ controller = mvebu_pwm_list[chip_data->ctrl];
|
||||
+ else
|
||||
+ controller = &mvpwm->controller;
|
||||
+
|
||||
+ spin_lock_irqsave(&controller->lock, flags);
|
||||
|
||||
val = (unsigned long long)
|
||||
- readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
+ readl_relaxed(mvebu_pwmreg_blink_on_duration(controller));
|
||||
val *= NSEC_PER_SEC;
|
||||
- do_div(val, mvpwm->clk_rate);
|
||||
+ do_div(val, controller->clk_rate);
|
||||
if (val > UINT_MAX)
|
||||
state->duty_cycle = UINT_MAX;
|
||||
else if (val)
|
||||
@@ -742,9 +770,9 @@ static void mvebu_pwm_get_state(struct p
|
||||
state->duty_cycle = 1;
|
||||
|
||||
val = (unsigned long long)
|
||||
- readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
+ readl_relaxed(mvebu_pwmreg_blink_off_duration(controller));
|
||||
val *= NSEC_PER_SEC;
|
||||
- do_div(val, mvpwm->clk_rate);
|
||||
+ do_div(val, controller->clk_rate);
|
||||
if (val < state->duty_cycle) {
|
||||
state->period = 1;
|
||||
} else {
|
||||
@@ -786,7 +814,7 @@ static int mvebu_pwm_apply(struct pwm_ch
|
||||
else
|
||||
on = 1;
|
||||
|
||||
- val = (unsigned long long) mvpwm->clk_rate *
|
||||
+ val = (unsigned long long) controller->clk_rate *
|
||||
(state->period - state->duty_cycle);
|
||||
do_div(val, NSEC_PER_SEC);
|
||||
if (val > UINT_MAX)
|
||||
@@ -796,16 +824,16 @@ static int mvebu_pwm_apply(struct pwm_ch
|
||||
else
|
||||
off = 1;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ spin_lock_irqsave(&controller->lock, flags);
|
||||
|
||||
- writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
- writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
+ writel_relaxed(on, mvebu_pwmreg_blink_on_duration(controller));
|
||||
+ writel_relaxed(off, mvebu_pwmreg_blink_off_duration(controller));
|
||||
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);
|
||||
+ spin_unlock_irqrestore(&controller->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -824,10 +852,10 @@ static void __maybe_unused mvebu_pwm_sus
|
||||
|
||||
regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
&mvpwm->blink_select);
|
||||
- mvpwm->blink_on_duration =
|
||||
- readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
- mvpwm->blink_off_duration =
|
||||
- readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
+ mvpwm->controller.blink_on_duration =
|
||||
+ readl_relaxed(mvebu_pwmreg_blink_on_duration(&mvpwm->controller));
|
||||
+ mvpwm->controller.blink_off_duration =
|
||||
+ readl_relaxed(mvebu_pwmreg_blink_off_duration(&mvpwm->controller));
|
||||
}
|
||||
|
||||
static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
|
||||
@@ -836,10 +864,10 @@ static void __maybe_unused mvebu_pwm_res
|
||||
|
||||
regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
mvpwm->blink_select);
|
||||
- writel_relaxed(mvpwm->blink_on_duration,
|
||||
- mvebu_pwmreg_blink_on_duration(mvpwm));
|
||||
- writel_relaxed(mvpwm->blink_off_duration,
|
||||
- mvebu_pwmreg_blink_off_duration(mvpwm));
|
||||
+ writel_relaxed(mvpwm->controller.blink_on_duration,
|
||||
+ mvebu_pwmreg_blink_on_duration(&mvpwm->controller));
|
||||
+ writel_relaxed(mvpwm->controller.blink_off_duration,
|
||||
+ mvebu_pwmreg_blink_off_duration(&mvpwm->controller));
|
||||
}
|
||||
|
||||
static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
@@ -849,6 +877,7 @@ static int mvebu_pwm_probe(struct platfo
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_pwm *mvpwm;
|
||||
u32 set;
|
||||
+ enum mvebu_pwm_ctrl ctrl_set;
|
||||
|
||||
if (!of_device_is_compatible(mvchip->chip.of_node,
|
||||
"marvell,armada-370-gpio"))
|
||||
@@ -870,12 +899,15 @@ static int mvebu_pwm_probe(struct platfo
|
||||
* 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)
|
||||
+ if (id == 0) {
|
||||
set = 0;
|
||||
- else if (id == 1)
|
||||
+ ctrl_set = MVEBU_PWM_CTRL_SET_A;
|
||||
+ } else if (id == 1) {
|
||||
set = U32_MAX;
|
||||
- else
|
||||
+ ctrl_set = MVEBU_PWM_CTRL_SET_B;
|
||||
+ } else {
|
||||
return -EINVAL;
|
||||
+ }
|
||||
regmap_write(mvchip->regs,
|
||||
GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
|
||||
|
||||
@@ -885,15 +917,13 @@ static int mvebu_pwm_probe(struct platfo
|
||||
mvchip->mvpwm = mvpwm;
|
||||
mvpwm->mvchip = mvchip;
|
||||
|
||||
- mvpwm->membase = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
- if (IS_ERR(mvpwm->membase))
|
||||
- return PTR_ERR(mvpwm->membase);
|
||||
-
|
||||
- mvpwm->clk_rate = clk_get_rate(mvchip->clk);
|
||||
- if (!mvpwm->clk_rate) {
|
||||
- dev_err(dev, "failed to get clock rate\n");
|
||||
+ mvpwm->controller.membase = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
+ if (IS_ERR(mvpwm->controller.membase))
|
||||
+ return PTR_ERR(mvpwm->controller.membase);
|
||||
+
|
||||
+ mvpwm->controller.clk_rate = clk_get_rate(mvchip->clk);
|
||||
+ if (!mvpwm->controller.clk_rate)
|
||||
return -EINVAL;
|
||||
- }
|
||||
|
||||
mvpwm->chip.dev = dev;
|
||||
mvpwm->chip.ops = &mvebu_pwm_ops;
|
||||
@@ -906,7 +936,9 @@ static int mvebu_pwm_probe(struct platfo
|
||||
*/
|
||||
mvpwm->chip.base = -1;
|
||||
|
||||
- spin_lock_init(&mvpwm->lock);
|
||||
+ spin_lock_init(&mvpwm->controller.lock);
|
||||
+ mvpwm->default_counter = ctrl_set;
|
||||
+ mvebu_pwm_list[ctrl_set] = &mvpwm->controller;
|
||||
|
||||
return pwmchip_add(&mvpwm->chip);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user