Update 92-mvebu-gpio-remove-hardcoded-timer-assignment.patch for lk5.12

Tested with helios4, pwm working on both channels
This commit is contained in:
Heisath 2021-06-03 12:37:10 +02:00
parent d787b30311
commit ebc3997e4b

View File

@ -1,6 +1,6 @@
From e4728fcf779c37d1bcbd4b6505c9b40d4bb9ff48 Mon Sep 17 00:00:00 2001
From: Heisath <jannis@imserv.org>
Date: Mon, 22 Feb 2021 12:24:54 +0100
Date: Thu, 03 Jun 2021 10:56:53 +0200
Subject: [PATCH] Removes the hardcoded timer assignment of timers to pwm controllers
This allows to use more than one pwm per gpio bank.
@ -8,14 +8,12 @@ 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
index bad399e3f..d3fdaf177 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -92,20 +92,41 @@
@@ -97,21 +97,42 @@
#define MVEBU_MAX_GPIO_PER_BANK 32
@ -28,57 +26,57 @@ index 3a19b4140..195b685de 100644
+
+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;
u32 offset;
unsigned long clk_rate;
- 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;
spinlock_t lock;
- struct mvebu_gpio_chip *mvchip;
+ bool in_use;
/* Used to preserve GPIO/PWM registers across suspend/resume */
u32 blink_select;
- u32 blink_on_duration;
- u32 blink_off_duration;
- u32 blink_select;
u32 blink_on_duration;
u32 blink_off_duration;
};
+static struct mvebu_pwmchip *mvebu_pwm_list[MVEBU_PWM_CTRL_MAX];
+struct mvebu_pwm_chip_drv {
+ enum mvebu_pwm_ctrl ctrl;
+ struct gpio_desc *gpiod;
+ 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;
+};
+
+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)
@@ -288,12 +309,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;
return mvpwm->offset + 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;
return mvpwm->offset + PWM_BLINK_OFF_DURATION_OFF;
}
@@ -647,39 +668,84 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -653,39 +674,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;
@ -86,12 +84,9 @@ index 3a19b4140..195b685de 100644
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);
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
- if (mvpwm->gpiod) {
+ if (pwm->chip_data || (mvchip->blink_en_reg & BIT(pwm->hwpwm))) {
@ -106,13 +101,14 @@ index 3a19b4140..195b685de 100644
- goto out;
- }
+ goto out;
+ }
- mvpwm->gpiod = desc;
+ }
+
+
+
+ desc = gpiochip_request_own_desc(&mvchip->chip,
+ pwm->hwpwm, "mvebu-pwm",
+ GPIO_ACTIVE_HIGH,
+ GPIOD_OUT_LOW);
+ pwm->hwpwm, "mvebu-pwm",
+ GPIO_ACTIVE_HIGH,
+ GPIOD_OUT_LOW);
+
+ if (IS_ERR(desc)) {
+ ret = PTR_ERR(desc);
@ -120,28 +116,29 @@ index 3a19b4140..195b685de 100644
+ }
+
+ ret = gpiod_direction_output(desc, 0);
+ if (ret) {
+ 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;
+ chip_data->ctrl = id;
+ chip_data->master = true;
+ mvebu_pwm_list[id]->in_use = true;
+ break;
+ }
+ }
}
+
+ if (!chip_data->master)
+ if (!chip_data->master)
+ chip_data->ctrl = mvpwm->default_counter;
+
+ regmap_update_bits(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
@ -149,7 +146,7 @@ index 3a19b4140..195b685de 100644
+
+ chip_data->gpiod = desc;
+ pwm->chip_data = chip_data;
+
+
+ regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
+ &mvpwm->blink_select);
+
@ -173,6 +170,7 @@ index 3a19b4140..195b685de 100644
+ 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;
@ -180,7 +178,7 @@ index 3a19b4140..195b685de 100644
}
static void mvebu_pwm_get_state(struct pwm_chip *chip,
@@ -687,16 +753,23 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
@@ -693,29 +759,36 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
struct pwm_state *state) {
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
@ -201,26 +199,28 @@ index 3a19b4140..195b685de 100644
- 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;
/* Hardware treats zero as 2^32. See mvebu_pwm_apply(). */
if (u > 0)
val = u;
else
val = UINT_MAX + 1ULL;
state->duty_cycle = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC,
- mvpwm->clk_rate);
+ controller->clk_rate);
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,
/* period = on + off duration */
if (u > 0)
val += u;
else
val += UINT_MAX + 1ULL;
- state->period = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, mvpwm->clk_rate);
+ state->period = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, controller->clk_rate);
regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
if (u)
@@ -723,19 +796,26 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
else
state->enabled = false;
@ -245,21 +245,20 @@ index 3a19b4140..195b685de 100644
+ else
+ controller = &mvpwm->controller;
+
+
+ val = (unsigned long long) controller->clk_rate * state->duty_cycle;
do_div(val, NSEC_PER_SEC);
if (val > UINT_MAX)
if (val > UINT_MAX + 1ULL)
return -EINVAL;
@@ -743,7 +824,7 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -750,7 +830,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);
- val = (unsigned long long) mvpwm->clk_rate * state->period;
+ val = (unsigned long long) controller->clk_rate * state->period;
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,
val -= on;
if (val > UINT_MAX + 1ULL)
@@ -762,16 +842,16 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
else
off = 1;
@ -280,7 +279,7 @@ index 3a19b4140..195b685de 100644
return 0;
}
@@ -778,25 +859,27 @@ static const struct pwm_ops mvebu_pwm_ops = {
@@ -787,25 +867,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;
@ -316,46 +315,116 @@ index 3a19b4140..195b685de 100644
}
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;
@@ -817,26 +899,20 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
void __iomem *base;
u32 offset;
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;
+ }
- if (of_device_is_compatible(mvchip->chip.of_node,
- "marvell,armada-370-gpio")) {
- /*
- * 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.
- */
- if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"))
- return 0;
- offset = 0;
- } else if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
- int ret = of_property_read_u32(dev->of_node,
- "marvell,pwm-offset", &offset);
- if (ret < 0)
- return 0;
- } else {
+ if (!of_device_is_compatible(mvchip->chip.of_node,
+ "marvell,armada-370-gpio"))
+ return 0;
+
regmap_write(mvchip->regs,
GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
+ /*
+ * 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.
+ */
+ if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"))
return 0;
- }
@@ -847,13 +935,13 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
if (IS_ERR(base))
return PTR_ERR(base);
if (IS_ERR(mvchip->clk))
return PTR_ERR(mvchip->clk);
@@ -844,54 +920,39 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
if (!mvpwm)
return -ENOMEM;
+
mvchip->mvpwm = mvpwm;
mvpwm->mvchip = mvchip;
- mvpwm->offset = offset;
+
+
+ base = devm_platform_ioremap_resource_byname(pdev, "pwm");
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
- if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
- mvpwm->regs = mvchip->regs;
+ mvpwm->controller.regs = devm_regmap_init_mmio(&pdev->dev, base,
&mvebu_gpio_regmap_config);
- if (IS_ERR(mvpwm->regs))
- return PTR_ERR(mvpwm->regs);
+ &mvebu_gpio_regmap_config);
+ if (IS_ERR(mvpwm->controller.regs))
+ return PTR_ERR(mvpwm->controller.regs);
- switch (mvchip->offset) {
- case AP80X_GPIO0_OFF_A8K:
- case CP11X_GPIO0_OFF_A8K:
- /* Blink counter A */
- set = 0;
- break;
- case CP11X_GPIO1_OFF_A8K:
- /* Blink counter B */
- set = U32_MAX;
- mvpwm->offset += PWM_BLINK_COUNTER_B_OFF;
- break;
- default:
- return -EINVAL;
- }
+ /*
+ * 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) {
+ set = 0;
+ ctrl_set = MVEBU_PWM_CTRL_SET_A;
+ } else if (id == 1) {
+ set = U32_MAX;
+ ctrl_set = MVEBU_PWM_CTRL_SET_B;
} else {
- base = devm_platform_ioremap_resource_byname(pdev, "pwm");
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
- &mvebu_gpio_regmap_config);
- if (IS_ERR(mvpwm->regs))
- return PTR_ERR(mvpwm->regs);
-
- /*
- * 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)
- set = 0;
- else if (id == 1)
- set = U32_MAX;
- else
- return -EINVAL;
+ return -EINVAL;
}
regmap_write(mvchip->regs,
GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
- mvpwm->clk_rate = clk_get_rate(mvchip->clk);
- if (!mvpwm->clk_rate) {
+ mvpwm->controller.clk_rate = clk_get_rate(mvchip->clk);
@ -363,17 +432,15 @@ index 3a19b4140..195b685de 100644
dev_err(dev, "failed to get clock rate\n");
return -EINVAL;
}
@@ -869,7 +957,9 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
@@ -907,7 +968,10 @@ 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