From e4728fcf779c37d1bcbd4b6505c9b40d4bb9ff48 Mon Sep 17 00:00:00 2001
From: Heisath <jannis@imserv.org>
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. 

Original patch by helios4 team, updated to work on LK5.11+

Signed-off-by: Heisath <jannis@imserv.org>
---
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index bad399e3f..d3fdaf177 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -97,21 +97,42 @@
 
 #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;
 	u32			 offset;
 	unsigned long		 clk_rate;
-	struct gpio_desc	*gpiod;
-	struct pwm_chip		 chip;
 	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;
 };
 
+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;
@@ -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 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 mvpwm->offset + PWM_BLINK_OFF_DURATION_OFF;
 }
@@ -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;
+	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) {
+	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;
+	}
+
+
+	
+	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;
+	}
 
-		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 int mvebu_pwm_get_state(struct pwm_chip *chip,
@@ -693,27 +759,34 @@ static int mvebu_pwm_get_state(struct pwm_chip *chip,
 	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);
 	/* 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);
 
-	regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
+	regmap_read(controller->regs, mvebu_pwmreg_blink_off_duration(controller), &u);
 	/* 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)
@@ -796,15 +796,17 @@ static int mvebu_pwm_get_state(struct pwm_chip *chip,
 	else
 		state->enabled = false;
 
-	spin_unlock_irqrestore(&mvpwm->lock, flags);
+	spin_unlock_irqrestore(&controller->lock, flags);

 	return 0;
 }
 
 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;
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -811,7 +813,12 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (state->polarity != PWM_POLARITY_NORMAL)
 		return -EINVAL;
 
-	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 + 1ULL)
 		return -EINVAL;
@@ -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 * state->period;
+	val = (unsigned long long) controller->clk_rate * state->period;
 	do_div(val, NSEC_PER_SEC);
 	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;
 
-	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;
 }
@@ -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;
+	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,
@@ -902,6 +902,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
 	void __iomem *base;
 	u32 offset;
 	u32 set;
+	enum mvebu_pwm_ctrl ctrl_set;
 
 	if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
 		int ret = of_property_read_u32(dev->of_node,
@@ -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);
 
-	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->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);
+	if (!mvpwm->controller.clk_rate) {
 		dev_err(dev, "failed to get clock rate\n");
 		return -EINVAL;
 	}
@@ -907,7 +968,10 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
 	mvpwm->chip.ops = &mvebu_pwm_ops;
 	mvpwm->chip.npwm = mvchip->chip.ngpio;
 
-	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);
 }
