Linux-PWM Archive mirror
 help / color / mirror / Atom feed
From: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
To: Thierry Reding <thierry.reding@gmail.com>
Cc: linux-pwm@vger.kernel.org, kernel@pengutronix.de
Subject: [PATCH v3 107/108] pwm: Add more locking
Date: Tue, 21 Nov 2023 14:50:49 +0100	[thread overview]
Message-ID: <20231121134901.208535-108-u.kleine-koenig@pengutronix.de> (raw)
In-Reply-To: <20231121134901.208535-1-u.kleine-koenig@pengutronix.de>

This ensures that a pwm_chip that has no corresponding driver isn't used
and that a driver doesn't go away while a callback is still running.

As with the previous commit this is not needed yet, but once we have PWM
character device support this is required for race-free operation.

To not serialize all pwm_apply_state() calls, this introduces a per chip
lock. To prepare for a more sophisticated locking scheme involving spin
locks instead of mutexes for "fast" chips, there are (for now trivial)
functions introduced for locking and unlocking.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/core.c  | 76 ++++++++++++++++++++++++++++++++++++++-------
 include/linux/pwm.h |  6 +++-
 2 files changed, 69 insertions(+), 13 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index dd376fe9e265..8dbc79f7218c 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -32,6 +32,16 @@ static DEFINE_MUTEX(pwm_lock);
 
 static DEFINE_IDR(pwmchip_idr);
 
+static void pwmchip_lock(struct pwm_chip *chip)
+{
+	mutex_lock(&chip->lock);
+}
+
+static void pwmchip_unlock(struct pwm_chip *chip)
+{
+	mutex_unlock(&chip->lock);
+}
+
 static struct pwm_chip *pwmchip_find_by_name(const char *name)
 {
 	struct pwm_chip *chip;
@@ -231,6 +241,7 @@ static struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm,
 
 	chip->npwm = npwm;
 	chip->uses_pwmchip_alloc = true;
+	chip->operational = false;
 
 	for (i = 0; i < chip->npwm; i++) {
 		struct pwm_device *pwm = &chip->pwms[i];
@@ -311,23 +322,29 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 	if (IS_ENABLED(CONFIG_OF))
 		of_pwmchip_add(chip);
 
+	mutex_init(&chip->lock);
+
 	ret = device_add(&chip->dev);
 	if (ret)
 		goto err_device_add;
 
+	pwmchip_lock(chip);
+	chip->operational = true;
+	pwmchip_unlock(chip);
+
 	mutex_unlock(&pwm_lock);
 
 	return 0;
 
 err_device_add:
 
-	if (IS_ENABLED(CONFIG_OF))
-		of_pwmchip_remove(chip);
+	of_pwmchip_remove(chip);
 
 	idr_remove(&pwmchip_idr, chip->id);
 err_idr_alloc:
 
 	mutex_unlock(&pwm_lock);
+
 	module_put(owner);
 
 	return ret;
@@ -343,12 +360,27 @@ EXPORT_SYMBOL_GPL(__pwmchip_add);
 void pwmchip_remove(struct pwm_chip *chip)
 {
 	pwmchip_sysfs_unexport(chip);
+	unsigned int i;
 
 	if (IS_ENABLED(CONFIG_OF))
 		of_pwmchip_remove(chip);
 
 	mutex_lock(&pwm_lock);
 
+	pwmchip_lock(chip);
+	chip->operational = false;
+	pwmchip_unlock(chip);
+
+	for (i = 0; i < chip->npwm; ++i) {
+		struct pwm_device *pwm = &chip->pwms[i];
+
+		if (test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
+			dev_alert(&chip->dev, "Freeing requested PWM #%u\n", i);
+			if (pwm->chip->ops->free)
+				pwm->chip->ops->free(pwm->chip, pwm);
+		}
+	}
+
 	idr_remove(&pwmchip_idr, chip->id);
 
 	mutex_unlock(&pwm_lock);
@@ -524,7 +556,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
 int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
 {
 	struct pwm_chip *chip;
-	int err;
+	int err = 0;
 
 	/*
 	 * Some lowlevel driver's implementations of .apply() make use of
@@ -541,17 +573,24 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
 
 	chip = pwm->chip;
 
+	pwmchip_lock(chip);
+
+	if (!chip->operational) {
+		err = -ENXIO;
+		goto out_unlock;
+	}
+
 	if (state->period == pwm->state.period &&
 	    state->duty_cycle == pwm->state.duty_cycle &&
 	    state->polarity == pwm->state.polarity &&
 	    state->enabled == pwm->state.enabled &&
 	    state->usage_power == pwm->state.usage_power)
-		return 0;
+		goto out_unlock;
 
 	err = chip->ops->apply(chip, pwm, state);
 	trace_pwm_apply(pwm, state, err);
 	if (err)
-		return err;
+		goto out_unlock;
 
 	pwm->state = *state;
 
@@ -561,7 +600,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
 	 */
 	pwm_apply_state_debug(pwm, state);
 
-	return 0;
+out_unlock:
+	pwmchip_unlock(chip);
+
+	return err;
 }
 EXPORT_SYMBOL_GPL(pwm_apply_state);
 
@@ -585,7 +627,12 @@ int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
 		return -ENOSYS;
 
 	mutex_lock(&pwm_lock);
-	err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
+
+	if (pwm->chip->operational)
+		err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
+	else
+		err = -ENXIO;
+
 	mutex_unlock(&pwm_lock);
 
 	return err;
@@ -992,23 +1039,28 @@ EXPORT_SYMBOL_GPL(pwm_get);
  */
 void pwm_put(struct pwm_device *pwm)
 {
+	bool operational;
+
 	if (!pwm)
 		return;
 
 	mutex_lock(&pwm_lock);
 
-	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
-		pr_warn("PWM device already freed\n");
+	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags))
 		goto out;
-	}
 
-	if (pwm->chip->ops->free)
+	pwmchip_lock(pwm->chip);
+	operational = pwm->chip->operational;
+	pwmchip_unlock(pwm->chip);
+
+	if (operational && pwm->chip->ops->free)
 		pwm->chip->ops->free(pwm->chip, pwm);
 
 	pwm->label = NULL;
 
-	put_device(&pwm->chip->dev);
 out:
+	put_device(&pwm->chip->dev);
+
 	mutex_unlock(&pwm_lock);
 }
 EXPORT_SYMBOL_GPL(pwm_put);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 081c8402155d..4e81e8819f8c 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -287,7 +287,9 @@ struct pwm_ops {
  * @npwm: number of PWMs controlled by this chip
  * @of_xlate: request a PWM device given a device tree PWM specifier
  * @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
- * @list: list node for internal use
+ * @lock: mutex protecting .operational and serializing ops and chip unregistration
+ * @uses_pwmchip_alloc: signals if pwmchip_allow was used to allocate this chip
+ * @operational: tracks if the chip is operational
  * @pwms: array of PWM devices allocated by the framework
  */
 struct pwm_chip {
@@ -302,7 +304,9 @@ struct pwm_chip {
 	unsigned int of_pwm_n_cells;
 
 	/* only used internally by the PWM framework */
+	struct mutex lock;
 	bool uses_pwmchip_alloc;
+	bool operational;
 	struct pwm_device pwms[] __counted_by(npwm);
 };
 
-- 
2.42.0


  parent reply	other threads:[~2023-11-21 13:52 UTC|newest]

Thread overview: 163+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-21 13:49 [PATCH v3 000/108] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 001/108] pwm: cros-ec: Change prototype of helper to prepare further changes Uwe Kleine-König
2023-11-22  8:52   ` Tzung-Bi Shih
2023-11-23  9:24     ` Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 002/108] pwm: Provide a macro to get the parent device of a given chip Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 003/108] pwm: ab8500: Make use of pwmchip_parent() macro Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 004/108] pwm: atmel: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 005/108] pwm: atmel-tcb: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 006/108] pwm: bcm-kona: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 007/108] pwm: crc: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 008/108] pwm: cros-ec: " Uwe Kleine-König
2023-11-22  8:52   ` Tzung-Bi Shih
2023-11-21 13:49 ` [PATCH v3 009/108] pwm: dwc: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 010/108] pwm: ep93xx: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 011/108] pwm: fsl-ftm: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 012/108] pwm: img: Make use of parent device pointer in driver data Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 013/108] pwm: imx27: Make use of pwmchip_parent() macro Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 014/108] pwm: jz4740: " Uwe Kleine-König
2023-11-21 14:13   ` Paul Cercueil
2023-11-21 15:51     ` Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 015/108] pwm: lpc18xx-sct: Make use of parent device pointer in driver data Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 016/108] pwm: lpss: Make use of pwmchip_parent() macro Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 017/108] pwm: mediatek: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 018/108] pwm: meson: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 019/108] pwm: mtk-disp: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 020/108] pwm: omap: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 021/108] pwm: pca9685: Store parent device in driver data Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 022/108] pwm: raspberrypi-poe: Make use of pwmchip_parent() macro Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 023/108] pwm: rcar: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 024/108] pwm: rz-mtu3: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 025/108] pwm: samsung: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 026/108] pwm: sifive: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 027/108] pwm: stm32-lp: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 028/108] pwm: stm32: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 029/108] pwm: stmpe: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 030/108] pwm: sun4i: " Uwe Kleine-König
2023-11-25 18:48   ` Jernej Škrabec
2023-11-21 13:49 ` [PATCH v3 031/108] pwm: tiecap: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 032/108] pwm: tiehrpwm: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 033/108] pwm: twl-led: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 034/108] pwm: twl: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 035/108] pwm: vt8500: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 036/108] staging: greybus: pwm: " Uwe Kleine-König
2023-11-23 12:55   ` Greg Kroah-Hartman
2023-11-21 13:49 ` [PATCH v3 037/108] pwm: Provide devm_pwmchip_alloc() function Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 038/108] pwm: ab8500: Make use of " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 039/108] pwm: apple: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 040/108] pwm: atmel-hlcdc: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 041/108] pwm: atmel: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 042/108] pwm: atmel-tcb: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 043/108] pwm: bcm2835: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 044/108] pwm: bcm-iproc: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 045/108] pwm: bcm-kona: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 046/108] pwm: berlin: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 047/108] pwm: brcmstb: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 048/108] pwm: clk: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 049/108] pwm: clps711x: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 050/108] pwm: crc: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 051/108] pwm: cros-ec: " Uwe Kleine-König
2023-11-22  8:52   ` Tzung-Bi Shih
2023-11-22 23:56     ` Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 052/108] pwm: dwc: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 053/108] pwm: ep93xx: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 054/108] pwm: fsl-ftm: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 055/108] pwm: hibvt: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 056/108] pwm: img: " Uwe Kleine-König
2023-11-21 13:49 ` [PATCH v3 057/108] pwm: imx1: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 058/108] pwm: imx27: " Uwe Kleine-König
2023-12-05 11:49   ` Philipp Zabel
2023-12-05 12:14     ` Uwe Kleine-König
2023-12-05 12:50       ` Philipp Zabel
2023-11-21 13:50 ` [PATCH v3 059/108] pwm: imx-tpm: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 060/108] pwm: intel-lgm: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 061/108] pwm: iqs620a: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 062/108] pwm: jz4740: " Uwe Kleine-König
2023-11-21 14:16   ` Paul Cercueil
2023-11-21 13:50 ` [PATCH v3 063/108] pwm: keembay: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 064/108] pwm: lp3943: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 065/108] pwm: lpc18xx-sct: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 066/108] pwm: lpc32xx: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 067/108] pwm: lpss-*: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 068/108] pwm: mediatek: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 069/108] pwm: meson: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 070/108] pwm: microchip-core: " Uwe Kleine-König
2023-11-22 11:14   ` Conor Dooley
2023-11-22 22:48     ` Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 071/108] pwm: mtk-disp: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 072/108] pwm: mxs: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 073/108] pwm: ntxec: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 074/108] pwm: omap-dmtimer: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 075/108] pwm: pca9685: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 076/108] pwm: pxa: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 077/108] pwm: raspberrypi-poe: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 078/108] pwm: rcar: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 079/108] pwm: renesas-tpu: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 080/108] pwm: rockchip: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 081/108] pwm: rz-mtu3: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 082/108] pwm: samsung: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 083/108] pwm: sifive: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 084/108] pwm: sl28cpld: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 085/108] pwm: spear: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 086/108] pwm: sprd: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 087/108] pwm: sti: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 088/108] pwm: stm32-lp: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 089/108] pwm: stm32: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 090/108] pwm: stmpe: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 091/108] pwm: sun4i: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 092/108] pwm: sunplus: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 093/108] pwm: tegra: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 094/108] pwm: tiecap: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 095/108] pwm: twl-led: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 096/108] pwm: twl: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 097/108] pwm: visconti: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 098/108] pwm: vt8500: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 099/108] pwm: xilinx: " Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 100/108] gpio: mvebu: " Uwe Kleine-König
2023-11-21 14:02   ` Bartosz Golaszewski
2023-11-21 16:11     ` Uwe Kleine-König
2023-11-22  9:05       ` Uwe Kleine-König
2023-11-22 10:36         ` Bartosz Golaszewski
2023-11-22 23:39           ` Uwe Kleine-König
2023-11-24 12:14           ` Thierry Reding
2023-11-24 21:16             ` Bartosz Golaszewski
2023-11-24 21:59               ` Uwe Kleine-König
2023-11-27 10:58               ` Uwe Kleine-König
2023-11-27 20:22                 ` Bartosz Golaszewski
2023-11-28  9:07                   ` Uwe Kleine-König
2023-12-01 10:14                     ` Bartosz Golaszewski
2023-12-02  0:43                       ` Uwe Kleine-König
2023-12-04 20:27                         ` Bartosz Golaszewski
2023-12-04 21:28                           ` Bartosz Golaszewski
2023-12-05  9:31                             ` Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 101/108] drm/bridge: ti-sn65dsi86: " Uwe Kleine-König
2023-11-21 15:15   ` Doug Anderson
2023-11-21 16:05     ` Uwe Kleine-König
2023-11-21 16:14       ` Doug Anderson
2023-11-23  9:17         ` Uwe Kleine-König
2023-11-27  9:32           ` Uwe Kleine-König
2023-11-23  9:46   ` Laurent Pinchart
2023-11-23 10:10     ` Uwe Kleine-König
2023-12-06 12:06       ` Laurent Pinchart
2023-12-06 14:23         ` Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 102/108] leds: qcom-lpg: " Uwe Kleine-König
2023-11-21 15:16   ` Lee Jones
2023-11-21 15:58     ` Uwe Kleine-König
2023-11-22 11:56   ` Lee Jones
2023-11-22 17:15     ` Thierry Reding
2023-11-23 10:44       ` Uwe Kleine-König
2023-11-24 12:27         ` Thierry Reding
2023-11-24 18:22           ` Uwe Kleine-König
2023-11-24 21:21             ` Bartosz Golaszewski
2023-11-22 17:54     ` Uwe Kleine-König
2023-11-23 10:21       ` Lee Jones
2023-11-23 10:54         ` Uwe Kleine-König
2023-11-21 13:50 ` [PATCH v3 104/108] pwm: Ensure that pwm_chips are allocated using pwmchip_alloc() Uwe Kleine-König
2023-11-22 17:19   ` Thierry Reding
2023-11-22 23:52     ` Uwe Kleine-König
2023-11-24 12:28       ` Thierry Reding
2023-11-21 13:50 ` [PATCH v3 105/108] pwm: Ensure a struct pwm has the same lifetime as its pwm_chip Uwe Kleine-König
2023-11-21 15:53   ` Gustavo A. R. Silva
2023-11-21 13:50 ` [PATCH v3 106/108] pwm: Ensure the memory backing a PWM chip isn't freed while used Uwe Kleine-König
2023-11-21 13:50 ` Uwe Kleine-König [this message]
2023-11-21 13:50 ` [PATCH v3 108/108] WIP: pwm: Add support for pwmchip devices for faster and easier userspace access Uwe Kleine-König

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231121134901.208535-108-u.kleine-koenig@pengutronix.de \
    --to=u.kleine-koenig@pengutronix.de \
    --cc=kernel@pengutronix.de \
    --cc=linux-pwm@vger.kernel.org \
    --cc=thierry.reding@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).