All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
@ 2023-08-08 17:17 Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function Uwe Kleine-König
                   ` (102 more replies)
  0 siblings, 103 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

Hello,

this series addresses the issues I reported already earlier to this
list[1]. It is based on pwm/for-next and several patches I already sent
out, too. Maybe some of these have to be reworked (e.g. Thierry already
signalled not to like the patches dropping runtime error messages) but
in the expectation that I will have to create a v2 for this series, too
and it actually fixes a race condition, I sent the patches out for
review anyhow. For the same reason I didn't Cc: all the individual
maintainers.

If you want to actually test I suggest you fetch my complete history
from

	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking

. 

In the end drivers have to allocate their pwm_chip using
pwmchip_alloc(). This is important for the memory backing the pwm_chip
being able to have a longer life than the driver.

The motivation for this series is to prepare the pwm framework to add a
character device for each pwm_chip for easier and faster access to PWMs
from userspace compared to the sysfs API. For such an extension proper
lifetime tracking is important, too, as such a device can still be open
if a PWM disappears.

Have fun
Uwe

[1] https://lore.kernel.org/linux-pwm/20230725211004.peqxxb4y3j62gmnp@pengutronix.de/

Uwe Kleine-König (101):
  pwm: Provide devm_pwmchip_alloc() function
  pwm: ab8500: Make use of devm_pwmchip_alloc() function
  pwm: apple: Make use of devm_pwmchip_alloc() function
  pwm: atmel-hlcdc: Make use of devm_pwmchip_alloc() function
  pwm: atmel: Make use of devm_pwmchip_alloc() function
  pwm: atmel-tcb: Make use of devm_pwmchip_alloc() function
  pwm: bcm2835: Make use of devm_pwmchip_alloc() function
  pwm: bcm-iproc: Make use of devm_pwmchip_alloc() function
  pwm: bcm-kona: Make use of devm_pwmchip_alloc() function
  pwm: berlin: Make use of devm_pwmchip_alloc() function
  pwm: brcmstb: Make use of devm_pwmchip_alloc() function
  pwm: clk: Make use of devm_pwmchip_alloc() function
  pwm: clps711x: Make use of devm_pwmchip_alloc() function
  pwm: crc: Make use of devm_pwmchip_alloc() function
  pwm: cros-ec: Change prototype of helper to prepare further changes
  pwm: cros-ec: Make use of devm_pwmchip_alloc() function
  pwm: dwc: Make use of devm_pwmchip_alloc() function
  pwm: ep93xx: Make use of devm_pwmchip_alloc() function
  pwm: fsl-ftm: Make use of devm_pwmchip_alloc() function
  pwm: hibvt: Make use of devm_pwmchip_alloc() function
  pwm: img: Make use of devm_pwmchip_alloc() function
  pwm: imx1: Make use of devm_pwmchip_alloc() function
  pwm: imx27: Make use of devm_pwmchip_alloc() function
  pwm: imx-tpm: Make use of devm_pwmchip_alloc() function
  pwm: intel-lgm: Make use of devm_pwmchip_alloc() function
  pwm: iqs620a: Make use of devm_pwmchip_alloc() function
  pwm: jz4740: Make use of devm_pwmchip_alloc() function
  pwm: keembay: Make use of devm_pwmchip_alloc() function
  pwm: lp3943: Make use of devm_pwmchip_alloc() function
  pwm: lpc18xx-sct: Make use of devm_pwmchip_alloc() function
  pwm: lpc32xx: Make use of devm_pwmchip_alloc() function
  pwm: lpss-*: Make use of devm_pwmchip_alloc() function
  pwm: mediatek: Make use of devm_pwmchip_alloc() function
  pwm: meson: Make use of devm_pwmchip_alloc() function
  pwm: microchip-core: Make use of devm_pwmchip_alloc() function
  pwm: mtk-disp: Make use of devm_pwmchip_alloc() function
  pwm: mxs: Make use of devm_pwmchip_alloc() function
  pwm: ntxec: Make use of devm_pwmchip_alloc() function
  pwm: omap-dmtimer: Make use of devm_pwmchip_alloc() function
  pwm: pca9685: Make use of devm_pwmchip_alloc() function
  pwm: pxa: Make use of devm_pwmchip_alloc() function
  pwm: raspberrypi-poe: Make use of devm_pwmchip_alloc() function
  pwm: rcar: Make use of devm_pwmchip_alloc() function
  pwm: renesas-tpu: Make use of devm_pwmchip_alloc() function
  pwm: rockchip: Make use of devm_pwmchip_alloc() function
  pwm: rz-mtu3: Make use of devm_pwmchip_alloc() function
  pwm: samsung: Make use of devm_pwmchip_alloc() function
  pwm: sifive: Make use of devm_pwmchip_alloc() function
  pwm: sl28cpld: Make use of devm_pwmchip_alloc() function
  pwm: spear: Make use of devm_pwmchip_alloc() function
  pwm: sprd: Make use of devm_pwmchip_alloc() function
  pwm: sti: Make use of devm_pwmchip_alloc() function
  pwm: stm32-lp: Make use of devm_pwmchip_alloc() function
  pwm: stm32: Make use of devm_pwmchip_alloc() function
  pwm: stmpe: Make use of devm_pwmchip_alloc() function
  pwm: sun4i: Make use of devm_pwmchip_alloc() function
  pwm: sunplus: Make use of devm_pwmchip_alloc() function
  pwm: tegra: Make use of devm_pwmchip_alloc() function
  pwm: tiecap: Make use of devm_pwmchip_alloc() function
  pwm: tiehrpwm: Make use of devm_pwmchip_alloc() function
  pwm: twl-led: Make use of devm_pwmchip_alloc() function
  pwm: twl: Make use of devm_pwmchip_alloc() function
  pwm: visconti: Make use of devm_pwmchip_alloc() function
  pwm: vt8500: Make use of devm_pwmchip_alloc() function
  pwm: xilinx: Make use of devm_pwmchip_alloc() function
  gpio: mvebu: Make use of devm_pwmchip_alloc() function
  drm/bridge: ti-sn65dsi86: Make use of devm_pwmchip_alloc() function
  leds: qcom-lpg: Make use of devm_pwmchip_alloc() function
  staging: greybus: pwm: Make use of devm_pwmchip_alloc() function
  pwm: Ensure a struct pwm have the same lifetime as its pwm_chip
  pwm: ab8500: Store parent device in driver data
  pwm: atmel: Stop using struct pwm_chip::dev
  pwm: dwc: Store parent device in driver data
  pwm: ep93xx: Store parent device in driver data
  pwm: fsl-ftm: Store parent device in driver data
  pwm: img: Make use of parent device pointer in driver data
  pwm: imx27: Store parent device in driver data
  pwm: jz4740: Store parent device in driver data
  pwm: lpc18xx-sct: Make use of parent device pointer in driver data
  pwm: lpss: Store parent device in driver data
  pwm: mediatek: Store parent device in driver data
  pwm: meson: Store parent device in driver data
  pwm: mtk-disp: Store parent device in driver data
  pwm: omap: Store parent device in driver data
  pwm: pca9685: Store parent device in driver data
  pwm: raspberrypi-poe: Store parent device in driver data
  pwm: rcar: Store parent device in driver data
  pwm: rz-mtu3: Make use of parent device pointer in driver data
  pwm: samsung: Store parent device in driver data
  pwm: sifive: Make use of parent device pointer in driver data
  pwm: stm32: Store parent device in driver data
  pwm: stmpe: Store parent device in driver data
  pwm: sun4i: Store parent device in driver data
  pwm: tiecap: Store parent device in driver data
  pwm: tiehrpwm: Store parent device in driver data
  pwm: twl: Store parent device in driver data
  pwm: twl-led: Store parent device in driver data
  pwm: vt8500: Store parent device in driver data
  staging: greybus: pwm: Store parent device in driver data
  pwm: Ensure the memory backing a PWM chip isn't freed while used
  pwm: Add more locking

 .../driver-api/driver-model/devres.rst        |   1 +
 Documentation/driver-api/pwm.rst              |  10 +-
 drivers/gpio/gpio-mvebu.c                     |  18 +-
 drivers/gpu/drm/bridge/ti-sn65dsi86.c         |  25 ++-
 drivers/leds/rgb/leds-qcom-lpg.c              |  30 ++-
 drivers/pwm/Kconfig                           |   4 -
 drivers/pwm/Makefile                          |   3 +-
 drivers/pwm/core.c                            | 208 +++++++++++++-----
 drivers/pwm/pwm-ab8500.c                      |  34 +--
 drivers/pwm/pwm-apple.c                       |  18 +-
 drivers/pwm/pwm-atmel-hlcdc.c                 |  35 +--
 drivers/pwm/pwm-atmel-tcb.c                   |  24 +-
 drivers/pwm/pwm-atmel.c                       |  31 ++-
 drivers/pwm/pwm-bcm-iproc.c                   |  19 +-
 drivers/pwm/pwm-bcm-kona.c                    |  17 +-
 drivers/pwm/pwm-bcm2835.c                     |  17 +-
 drivers/pwm/pwm-berlin.c                      |  29 +--
 drivers/pwm/pwm-brcmstb.c                     |  17 +-
 drivers/pwm/pwm-clk.c                         |  27 ++-
 drivers/pwm/pwm-clps711x.c                    |  21 +-
 drivers/pwm/pwm-crc.c                         |  23 +-
 drivers/pwm/pwm-cros-ec.c                     |  49 ++---
 drivers/pwm/pwm-dwc.c                         |  54 +++--
 drivers/pwm/pwm-ep93xx.c                      |  28 +--
 drivers/pwm/pwm-fsl-ftm.c                     |  50 +++--
 drivers/pwm/pwm-hibvt.c                       |  25 ++-
 drivers/pwm/pwm-img.c                         |  51 ++---
 drivers/pwm/pwm-imx-tpm.c                     |  34 +--
 drivers/pwm/pwm-imx1.c                        |  17 +-
 drivers/pwm/pwm-imx27.c                       |  28 ++-
 drivers/pwm/pwm-intel-lgm.c                   |  17 +-
 drivers/pwm/pwm-iqs620a.c                     |  37 ++--
 drivers/pwm/pwm-jz4740.c                      |  38 ++--
 drivers/pwm/pwm-keembay.c                     |  17 +-
 drivers/pwm/pwm-lp3943.c                      |  17 +-
 drivers/pwm/pwm-lpc18xx-sct.c                 |  29 ++-
 drivers/pwm/pwm-lpc32xx.c                     |  19 +-
 drivers/pwm/pwm-lpss-pci.c                    |  10 +-
 drivers/pwm/pwm-lpss-platform.c               |  10 +-
 drivers/pwm/pwm-lpss.c                        |  36 +--
 drivers/pwm/pwm-lpss.h                        |   2 +-
 drivers/pwm/pwm-mediatek.c                    |  30 +--
 drivers/pwm/pwm-meson.c                       |  59 ++---
 drivers/pwm/pwm-microchip-core.c              |  17 +-
 drivers/pwm/pwm-mtk-disp.c                    |  27 +--
 drivers/pwm/pwm-mxs.c                         |  32 +--
 drivers/pwm/pwm-ntxec.c                       |  30 ++-
 drivers/pwm/pwm-omap-dmtimer.c                |  48 ++--
 drivers/pwm/pwm-pca9685.c                     |  44 ++--
 drivers/pwm/pwm-pxa.c                         |  21 +-
 drivers/pwm/pwm-raspberrypi-poe.c             |  22 +-
 drivers/pwm/pwm-rcar.c                        |  28 +--
 drivers/pwm/pwm-renesas-tpu.c                 |  18 +-
 drivers/pwm/pwm-rockchip.c                    |  24 +-
 drivers/pwm/pwm-rz-mtu3.c                     |  35 +--
 drivers/pwm/pwm-samsung.c                     |  56 ++---
 drivers/pwm/pwm-sifive.c                      |  30 +--
 drivers/pwm/pwm-sl28cpld.c                    |  13 +-
 drivers/pwm/pwm-spear.c                       |  17 +-
 drivers/pwm/pwm-sprd.c                        |  50 ++---
 drivers/pwm/pwm-sti.c                         |  34 +--
 drivers/pwm/pwm-stm32-lp.c                    |  23 +-
 drivers/pwm/pwm-stm32.c                       |  46 ++--
 drivers/pwm/pwm-stmpe.c                       |  64 +++---
 drivers/pwm/pwm-sun4i.c                       |  39 ++--
 drivers/pwm/pwm-sunplus.c                     |  17 +-
 drivers/pwm/pwm-tegra.c                       |  27 ++-
 drivers/pwm/pwm-tiecap.c                      |  57 ++---
 drivers/pwm/pwm-tiehrpwm.c                    |  70 +++---
 drivers/pwm/pwm-twl-led.c                     |  62 +++---
 drivers/pwm/pwm-twl.c                         |  52 ++---
 drivers/pwm/pwm-visconti.c                    |  17 +-
 drivers/pwm/pwm-vt8500.c                      |  24 +-
 drivers/pwm/pwm-xilinx.c                      |  34 ++-
 drivers/pwm/sysfs.c                           |  45 +---
 drivers/staging/greybus/pwm.c                 |  80 ++-----
 include/linux/platform_data/x86/pwm-lpss.h    |   4 +-
 include/linux/pwm.h                           |  24 +-
 78 files changed, 1310 insertions(+), 1189 deletions(-)


base-commit: 3ccb179aa40d931eb00ef8910d7b812a95659563
prerequisite-patch-id: cc42495033fc6c784c3139f92610cc9deeb2d87e
prerequisite-patch-id: c3fb50527e1bdd0c63ffba939d24d9d347470bb6
prerequisite-patch-id: f3333980376bf2207e993d0714845f3301c86e2e
prerequisite-patch-id: b30ff565416aab449c4e14fbd6535cad52f61096
prerequisite-patch-id: bea14e240bcd525e2fd1256882e645491624f8c6
prerequisite-patch-id: cd271964ea5243e89857030e28c3e0046ae64bd9
prerequisite-patch-id: 143c8d917c67280ec8cc8465e1a8dce8f7f77618
prerequisite-patch-id: 369332bf9747e4702010d08b45eaa72496cef9ec
prerequisite-patch-id: 2df33999582eeaf1cd2a5c805b989c969577ca0c
prerequisite-patch-id: e8dad0c65b1deb6f8cd7ea2a5a08b3ab2cb2e291
prerequisite-patch-id: b540c7ef3ea7add5e54a65f480daff3018735fd3
prerequisite-patch-id: 72247967f924911ad08210638853d3d3b3d5d278
prerequisite-patch-id: 313ada72ab57438a8d54df0df9c0926bb4f69b36
prerequisite-patch-id: 318824c08f3e7d6500e3c5a47a11c5daffaea34a
prerequisite-patch-id: 921e5b577da74b4f1b666c433e182ddd3cb7e854
prerequisite-patch-id: 4e608e07dc1adf781f21274e37b72fa528b8c60a
prerequisite-patch-id: 9abd8b16e74625e2630655da7d22e75bbe0c6231
prerequisite-patch-id: 7a0daa2918f8a317333e57c1d1698078a1968720
prerequisite-patch-id: a0c8d63424241e64c3e5f9991ea04018a51fcc94
prerequisite-patch-id: 2cae8f054048b5074ed99163e476bee87cd9b7ef
prerequisite-patch-id: 8f6f3e08d426c4d349e93f5fdb3650efcd523299
prerequisite-patch-id: f7dd05d650cd2b4368ec1ce9f7db1716841a72d8
prerequisite-patch-id: e4abcc7c18f6cc49d3d4b4221cd3856189ec71d8
prerequisite-patch-id: 67e046597429677c0bfa48bb044aac39fdcc9eb2
prerequisite-patch-id: 02694b208c763f5dac10bce135cd43a7d50d979f
prerequisite-patch-id: 4317fa5ef50613649e319fff57bb507dab10909d
prerequisite-patch-id: 1483ab31d5f3f7504dda11b5f4660022152f6e88
prerequisite-patch-id: da542cefd47056ad9f5b6fd57b5218437ba7025b
prerequisite-patch-id: 9cded674bc2c8c1a899f6da498b372ae599a7e72
prerequisite-patch-id: 25c85a2b73850671bb4bc970472cfc4c1f9f59f5
prerequisite-patch-id: 07a107646a7f974ff11acb7cd08db31d6dd8f254
prerequisite-patch-id: fdf3805aa0c2f6b7bd250673755936668db6cd4a
prerequisite-patch-id: 13386aad0b7b3f163e27bcb450e9e4c8f42630d2
prerequisite-patch-id: 5b55d44ff77e37c24646bbbee4feb8adbdccfcf7
prerequisite-patch-id: 1fe585c132c1d850e573257fe30f07a7789a235f
prerequisite-patch-id: 027a0eff436112b5c76d5c50aca6eced6ace4355
prerequisite-patch-id: a4068519ff48d7e157d59d77e99b1d95fe33a987
prerequisite-patch-id: 83665e92c2a6d2b40675330bae4bcb9b4f695e48
prerequisite-patch-id: 032d7d39b0111ddc4791a1892348be5fabb1e83b
-- 
2.40.1


^ permalink raw reply	[flat|nested] 129+ messages in thread

* [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-10-06  9:23   ` Thierry Reding
  2023-08-08 17:17 ` [PATCH v1 002/101] pwm: ab8500: Make use of " Uwe Kleine-König
                   ` (101 subsequent siblings)
  102 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This function allocates a struct pwm_chip and driver data. Compared to
the status quo the split into pwm_chip and driver data is new, otherwise
it doesn't change anything relevant (yet).

The intention is that after all drivers are switched to use this
allocation function, its possible to add a struct device to struct
pwm_chip to properly track the latter's lifetime without touching all
drivers again. Proper lifetime tracking is a necessary precondition to
introduce character device support for PWMs (that implements atomic
setting and doesn't suffer from the sysfs overhead of the /sys/class/pwm
userspace support).

The new function pwmchip_priv() (obviously?) only works for chips
allocated with devm_pwmchip_alloc().

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 .../driver-api/driver-model/devres.rst        |  1 +
 Documentation/driver-api/pwm.rst              | 10 +++----
 drivers/pwm/core.c                            | 30 ++++++++++++++++---
 include/linux/pwm.h                           |  5 ++++
 4 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
index 8be086b3f829..73a9ee074737 100644
--- a/Documentation/driver-api/driver-model/devres.rst
+++ b/Documentation/driver-api/driver-model/devres.rst
@@ -414,6 +414,7 @@ POWER
   devm_reboot_mode_unregister()
 
 PWM
+  devm_pwmchip_alloc()
   devm_pwmchip_add()
   devm_pwm_get()
   devm_fwnode_pwm_get()
diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst
index 3fdc95f7a1d1..a3824bd58e4c 100644
--- a/Documentation/driver-api/pwm.rst
+++ b/Documentation/driver-api/pwm.rst
@@ -134,11 +134,11 @@ to implement the pwm_*() functions itself. This means that it's impossible
 to have multiple PWM drivers in the system. For this reason it's mandatory
 for new drivers to use the generic PWM framework.
 
-A new PWM controller/chip can be added using pwmchip_add() and removed
-again with pwmchip_remove(). pwmchip_add() takes a filled in struct
-pwm_chip as argument which provides a description of the PWM chip, the
-number of PWM devices provided by the chip and the chip-specific
-implementation of the supported PWM operations to the framework.
+A new PWM controller/chip can be allocated using devm_pwmchip_alloc, then added
+using pwmchip_add() and removed again with pwmchip_remove(). pwmchip_add()
+takes a filled in struct pwm_chip as argument which provides a description of
+the PWM chip, the number of PWM devices provided by the chip and the
+chip-specific implementation of the supported PWM operations to the framework.
 
 When implementing polarity support in a PWM driver, make sure to respect the
 signal conventions in the PWM framework. By definition, normal polarity
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 8aa3feec12a9..cfcddf62ab01 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -196,6 +196,31 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
 	return true;
 }
 
+void *pwmchip_priv(struct pwm_chip *chip)
+{
+	return &chip[1];
+}
+EXPORT_SYMBOL_GPL(pwmchip_priv);
+
+struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
+{
+	struct pwm_chip *chip;
+	size_t alloc_size;
+	unsigned int i;
+
+	alloc_size = sizeof(*chip) + sizeof_priv;
+
+	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
+	if (!chip)
+		return ERR_PTR(-ENOMEM);
+
+	chip->dev = parent;
+	chip->npwm = npwm;
+
+	return chip;
+}
+EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
+
 /**
  * __pwmchip_add() - register a new PWM chip
  * @chip: the PWM chip to add
@@ -208,8 +233,6 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
  */
 int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 {
-	struct pwm_device *pwm;
-	unsigned int i;
 	int ret;
 
 	if (!chip || !chip->dev || !chip->ops || !chip->npwm)
@@ -234,9 +257,8 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 	}
 
 	chip->id = ret;
-
 	for (i = 0; i < chip->npwm; i++) {
-		pwm = &chip->pwms[i];
+		struct pwm_device *pwm = &chip->pwms[i];
 
 		pwm->chip = chip;
 		pwm->hwpwm = i;
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 6f139784d6f5..3c0da17e193c 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -5,6 +5,7 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/compiler_attributes.h>
 
 struct pwm_chip;
 
@@ -380,6 +381,10 @@ static inline void pwm_disable(struct pwm_device *pwm)
 int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
 		unsigned long timeout);
 
+void *pwmchip_priv(struct pwm_chip *chip) __attribute_const__;
+
+struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv);
+
 int __pwmchip_add(struct pwm_chip *chip, struct module *owner);
 #define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE)
 void pwmchip_remove(struct pwm_chip *chip);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 002/101] pwm: ab8500: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 003/101] pwm: apple: " Uwe Kleine-König
                   ` (100 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-ab8500 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-ab8500.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c
index e37495ed8158..f64f3fd251e7 100644
--- a/drivers/pwm/pwm-ab8500.c
+++ b/drivers/pwm/pwm-ab8500.c
@@ -24,13 +24,12 @@
 #define AB8500_PWM_CLKRATE 9600000
 
 struct ab8500_pwm_chip {
-	struct pwm_chip chip;
 	unsigned int hwid;
 };
 
 static struct ab8500_pwm_chip *ab8500_pwm_from_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct ab8500_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -179,6 +178,7 @@ static const struct pwm_ops ab8500_pwm_ops = {
 
 static int ab8500_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct ab8500_pwm_chip *ab8500;
 	int err;
 
@@ -189,16 +189,16 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
 	 * Nothing to be done in probe, this is required to get the
 	 * device which is required for ab8500 read and write
 	 */
-	ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
-	if (ab8500 == NULL)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*ab8500));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
-	ab8500->chip.dev = &pdev->dev;
-	ab8500->chip.ops = &ab8500_pwm_ops;
-	ab8500->chip.npwm = 1;
+	ab8500 = pwmchip_priv(chip);
+
+	chip->ops = &ab8500_pwm_ops;
 	ab8500->hwid = pdev->id - 1;
 
-	err = devm_pwmchip_add(&pdev->dev, &ab8500->chip);
+	err = devm_pwmchip_add(&pdev->dev, chip);
 	if (err < 0)
 		return dev_err_probe(&pdev->dev, err, "Failed to add pwm chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 003/101] pwm: apple: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 002/101] pwm: ab8500: Make use of " Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 004/101] pwm: atmel-hlcdc: " Uwe Kleine-König
                   ` (99 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-apple driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-apple.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-apple.c b/drivers/pwm/pwm-apple.c
index 4d755b628d9e..1560b6f88821 100644
--- a/drivers/pwm/pwm-apple.c
+++ b/drivers/pwm/pwm-apple.c
@@ -32,14 +32,13 @@
 #define APPLE_PWM_CTRL_OUTPUT_ENABLE BIT(14)
 
 struct apple_pwm {
-	struct pwm_chip chip;
 	void __iomem *base;
 	u64 clkrate;
 };
 
 static inline struct apple_pwm *to_apple_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct apple_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int apple_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -103,13 +102,16 @@ static const struct pwm_ops apple_pwm_ops = {
 
 static int apple_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct apple_pwm *fpwm;
 	struct clk *clk;
 	int ret;
 
-	fpwm = devm_kzalloc(&pdev->dev, sizeof(*fpwm), GFP_KERNEL);
-	if (!fpwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*fpwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	fpwm = to_apple_pwm(chip);
 
 	fpwm->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(fpwm->base))
@@ -129,11 +131,9 @@ static int apple_pwm_probe(struct platform_device *pdev)
 	if (fpwm->clkrate > NSEC_PER_SEC)
 		return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock out of range");
 
-	fpwm->chip.dev = &pdev->dev;
-	fpwm->chip.npwm = 1;
-	fpwm->chip.ops = &apple_pwm_ops;
+	chip->ops = &apple_pwm_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &fpwm->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "unable to add pwm chip");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 004/101] pwm: atmel-hlcdc: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (2 preceding siblings ...)
  2023-08-08 17:17 ` [PATCH v1 003/101] pwm: apple: " Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 005/101] pwm: atmel: " Uwe Kleine-König
                   ` (98 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-atme-hlcdc driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-atmel-hlcdc.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 07920e034757..c3b18a51c926 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -28,7 +28,6 @@ struct atmel_hlcdc_pwm_errata {
 };
 
 struct atmel_hlcdc_pwm {
-	struct pwm_chip chip;
 	struct atmel_hlcdc *hlcdc;
 	struct clk *cur_clk;
 	const struct atmel_hlcdc_pwm_errata *errata;
@@ -36,7 +35,7 @@ struct atmel_hlcdc_pwm {
 
 static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct atmel_hlcdc_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int atmel_hlcdc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -183,10 +182,11 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = {
 #ifdef CONFIG_PM_SLEEP
 static int atmel_hlcdc_pwm_suspend(struct device *dev)
 {
-	struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip);
 
 	/* Keep the periph clock enabled if the PWM is still running. */
-	if (pwm_is_enabled(&atmel->chip.pwms[0]))
+	if (pwm_is_enabled(&chip->pwms[0]))
 		clk_disable_unprepare(atmel->hlcdc->periph_clk);
 
 	return 0;
@@ -194,11 +194,12 @@ static int atmel_hlcdc_pwm_suspend(struct device *dev)
 
 static int atmel_hlcdc_pwm_resume(struct device *dev)
 {
-	struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip);
 	struct pwm_state state;
 	int ret;
 
-	pwm_get_state(&atmel->chip.pwms[0], &state);
+	pwm_get_state(&chip->pwms[0], &state);
 
 	/* Re-enable the periph clock it was stopped during suspend. */
 	if (!state.enabled) {
@@ -207,8 +208,7 @@ static int atmel_hlcdc_pwm_resume(struct device *dev)
 			return ret;
 	}
 
-	return atmel_hlcdc_pwm_apply(&atmel->chip, &atmel->chip.pwms[0],
-				     &state);
+	return atmel_hlcdc_pwm_apply(chip, &chip->pwms[0], &state);
 }
 #endif
 
@@ -245,15 +245,17 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
+	struct pwm_chip *chip;
 	struct atmel_hlcdc_pwm *atmel;
 	struct atmel_hlcdc *hlcdc;
 	int ret;
 
 	hlcdc = dev_get_drvdata(dev->parent);
 
-	atmel = devm_kzalloc(dev, sizeof(*atmel), GFP_KERNEL);
-	if (!atmel)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, 1, sizeof(*atmel));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	atmel = to_atmel_hlcdc_pwm(chip);
 
 	ret = clk_prepare_enable(hlcdc->periph_clk);
 	if (ret)
@@ -264,11 +266,9 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
 		atmel->errata = match->data;
 
 	atmel->hlcdc = hlcdc;
-	atmel->chip.ops = &atmel_hlcdc_pwm_ops;
-	atmel->chip.dev = dev;
-	atmel->chip.npwm = 1;
+	chip->ops = &atmel_hlcdc_pwm_ops;
 
-	ret = pwmchip_add(&atmel->chip);
+	ret = pwmchip_add(chip);
 	if (ret) {
 		clk_disable_unprepare(hlcdc->periph_clk);
 		return ret;
@@ -281,9 +281,10 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
 
 static void atmel_hlcdc_pwm_remove(struct platform_device *pdev)
 {
-	struct atmel_hlcdc_pwm *atmel = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct atmel_hlcdc_pwm *atmel = to_atmel_hlcdc_pwm(chip);
 
-	pwmchip_remove(&atmel->chip);
+	pwmchip_remove(chip);
 
 	clk_disable_unprepare(atmel->hlcdc->periph_clk);
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 005/101] pwm: atmel: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (3 preceding siblings ...)
  2023-08-08 17:17 ` [PATCH v1 004/101] pwm: atmel-hlcdc: " Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 006/101] pwm: atmel-tcb: " Uwe Kleine-König
                   ` (97 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-atmel driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-atmel.c | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 591f4b0493a7..48b79b8488a4 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -77,7 +77,6 @@ struct atmel_pwm_data {
 };
 
 struct atmel_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	void __iomem *base;
 	const struct atmel_pwm_data *data;
@@ -99,7 +98,7 @@ struct atmel_pwm_chip {
 
 static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct atmel_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline u32 atmel_pwm_readl(struct atmel_pwm_chip *chip,
@@ -456,8 +455,9 @@ static const struct of_device_id atmel_pwm_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
 
-static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on)
+static int atmel_pwm_enable_clk_if_on(struct pwm_chip *chip, bool on)
 {
+	struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
 	unsigned int i, cnt = 0;
 	unsigned long sr;
 	int ret = 0;
@@ -466,7 +466,7 @@ static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on)
 	if (!sr)
 		return 0;
 
-	cnt = bitmap_weight(&sr, atmel_pwm->chip.npwm);
+	cnt = bitmap_weight(&sr, chip->npwm);
 
 	if (!on)
 		goto disable_clk;
@@ -474,9 +474,8 @@ static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on)
 	for (i = 0; i < cnt; i++) {
 		ret = clk_enable(atmel_pwm->clk);
 		if (ret) {
-			dev_err(atmel_pwm->chip.dev,
-				"failed to enable clock for pwm %pe\n",
-				ERR_PTR(ret));
+			dev_err_probe(chip->dev, ret,
+				"failed to enable clock for pwm\n");
 
 			cnt = i;
 			goto disable_clk;
@@ -494,12 +493,14 @@ static int atmel_pwm_enable_clk_if_on(struct atmel_pwm_chip *atmel_pwm, bool on)
 
 static int atmel_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct atmel_pwm_chip *atmel_pwm;
 	int ret;
 
-	atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL);
-	if (!atmel_pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 4, sizeof(*atmel_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	atmel_pwm = to_atmel_pwm_chip(chip);
 
 	atmel_pwm->data = of_device_get_match_data(&pdev->dev);
 
@@ -515,15 +516,13 @@ static int atmel_pwm_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(atmel_pwm->clk),
 				     "failed to get prepared PWM clock\n");
 
-	atmel_pwm->chip.dev = &pdev->dev;
-	atmel_pwm->chip.ops = &atmel_pwm_ops;
-	atmel_pwm->chip.npwm = 4;
+	chip->ops = &atmel_pwm_ops;
 
-	ret = atmel_pwm_enable_clk_if_on(atmel_pwm, true);
+	ret = atmel_pwm_enable_clk_if_on(chip, true);
 	if (ret < 0)
 		return ret;
 
-	ret = devm_pwmchip_add(&pdev->dev, &atmel_pwm->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0) {
 		dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
 		goto disable_clk;
@@ -532,7 +531,7 @@ static int atmel_pwm_probe(struct platform_device *pdev)
 	return 0;
 
 disable_clk:
-	atmel_pwm_enable_clk_if_on(atmel_pwm, false);
+	atmel_pwm_enable_clk_if_on(chip, false);
 
 	return ret;
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 006/101] pwm: atmel-tcb: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (4 preceding siblings ...)
  2023-08-08 17:17 ` [PATCH v1 005/101] pwm: atmel: " Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 007/101] pwm: bcm2835: " Uwe Kleine-König
                   ` (96 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-atmel-tcb driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-atmel-tcb.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index 9415d3373e4b..a5dfd244811b 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -47,7 +47,6 @@ struct atmel_tcb_channel {
 };
 
 struct atmel_tcb_pwm_chip {
-	struct pwm_chip chip;
 	spinlock_t lock;
 	u8 channel;
 	u8 width;
@@ -63,7 +62,7 @@ static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128, 0, };
 
 static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct atmel_tcb_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int atmel_tcb_pwm_request(struct pwm_chip *chip,
@@ -386,6 +385,7 @@ static const struct of_device_id atmel_tcb_of_match[] = {
 static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *match;
+	struct pwm_chip *chip;
 	struct atmel_tcb_pwm_chip *tcbpwm;
 	const struct atmel_tcb_config *config;
 	struct device_node *np = pdev->dev.of_node;
@@ -393,9 +393,10 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 	int err;
 	int channel;
 
-	tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL);
-	if (tcbpwm == NULL)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, NPWM, sizeof(*tcbpwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	tcbpwm = to_tcb_chip(chip);
 
 	err = of_property_read_u32(np, "reg", &channel);
 	if (err < 0) {
@@ -433,9 +434,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 		}
 	}
 
-	tcbpwm->chip.dev = &pdev->dev;
-	tcbpwm->chip.ops = &atmel_tcb_pwm_ops;
-	tcbpwm->chip.npwm = NPWM;
+	chip->ops = &atmel_tcb_pwm_ops;
 	tcbpwm->channel = channel;
 	tcbpwm->width = config->counter_width;
 
@@ -445,11 +444,11 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 
 	spin_lock_init(&tcbpwm->lock);
 
-	err = pwmchip_add(&tcbpwm->chip);
+	err = pwmchip_add(chip);
 	if (err < 0)
 		goto err_disable_clk;
 
-	platform_set_drvdata(pdev, tcbpwm);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 
@@ -470,9 +469,10 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 
 static void atmel_tcb_pwm_remove(struct platform_device *pdev)
 {
-	struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct atmel_tcb_pwm_chip *tcbpwm = to_tcb_chip(chip);
 
-	pwmchip_remove(&tcbpwm->chip);
+	pwmchip_remove(chip);
 
 	clk_disable_unprepare(tcbpwm->slow_clk);
 	clk_put(tcbpwm->gclk);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 007/101] pwm: bcm2835: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (5 preceding siblings ...)
  2023-08-08 17:17 ` [PATCH v1 006/101] pwm: atmel-tcb: " Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 008/101] pwm: bcm-iproc: " Uwe Kleine-König
                   ` (95 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-bcm2835 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-bcm2835.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c
index 8c69ddfea2d0..15ba04090b31 100644
--- a/drivers/pwm/pwm-bcm2835.c
+++ b/drivers/pwm/pwm-bcm2835.c
@@ -24,7 +24,6 @@
 #define PERIOD_MIN		0x2
 
 struct bcm2835_pwm {
-	struct pwm_chip chip;
 	struct device *dev;
 	void __iomem *base;
 	struct clk *clk;
@@ -32,7 +31,7 @@ struct bcm2835_pwm {
 
 static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct bcm2835_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int bcm2835_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -133,12 +132,14 @@ static const struct pwm_ops bcm2835_pwm_ops = {
 
 static int bcm2835_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct bcm2835_pwm *pc;
 	int ret;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_bcm2835_pwm(chip);
 
 	pc->dev = &pdev->dev;
 
@@ -151,11 +152,9 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
 				     "clock not found\n");
 
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &bcm2835_pwm_ops;
-	pc->chip.npwm = 2;
+	chip->ops = &bcm2835_pwm_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret,
 				     "failed to add pwmchip\n");
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 008/101] pwm: bcm-iproc: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (6 preceding siblings ...)
  2023-08-08 17:17 ` [PATCH v1 007/101] pwm: bcm2835: " Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:17 ` [PATCH v1 009/101] pwm: bcm-kona: " Uwe Kleine-König
                   ` (94 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-bcm-iproc driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-bcm-iproc.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c
index 758254025683..4c8d82de50a9 100644
--- a/drivers/pwm/pwm-bcm-iproc.c
+++ b/drivers/pwm/pwm-bcm-iproc.c
@@ -34,14 +34,13 @@
 #define IPROC_PWM_PRESCALE_MAX			0x3f
 
 struct iproc_pwmc {
-	struct pwm_chip chip;
 	void __iomem *base;
 	struct clk *clk;
 };
 
 static inline struct iproc_pwmc *to_iproc_pwmc(struct pwm_chip *chip)
 {
-	return container_of(chip, struct iproc_pwmc, chip);
+	return pwmchip_priv(chip);
 }
 
 static void iproc_pwmc_enable(struct iproc_pwmc *ip, unsigned int channel)
@@ -187,20 +186,20 @@ static const struct pwm_ops iproc_pwm_ops = {
 
 static int iproc_pwmc_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct iproc_pwmc *ip;
 	unsigned int i;
 	u32 value;
 	int ret;
 
-	ip = devm_kzalloc(&pdev->dev, sizeof(*ip), GFP_KERNEL);
-	if (!ip)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 4, sizeof(*ip));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	ip = to_iproc_pwmc(chip);
 
 	platform_set_drvdata(pdev, ip);
 
-	ip->chip.dev = &pdev->dev;
-	ip->chip.ops = &iproc_pwm_ops;
-	ip->chip.npwm = 4;
+	chip->ops = &iproc_pwm_ops;
 
 	ip->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(ip->base))
@@ -214,14 +213,14 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
 	/* Set full drive and normal polarity for all channels */
 	value = readl(ip->base + IPROC_PWM_CTRL_OFFSET);
 
-	for (i = 0; i < ip->chip.npwm; i++) {
+	for (i = 0; i < chip->npwm; i++) {
 		value &= ~(1 << IPROC_PWM_CTRL_TYPE_SHIFT(i));
 		value |= 1 << IPROC_PWM_CTRL_POLARITY_SHIFT(i);
 	}
 
 	writel(value, ip->base + IPROC_PWM_CTRL_OFFSET);
 
-	ret = devm_pwmchip_add(&pdev->dev, &ip->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret,
 				     "failed to add PWM chip\n");
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 009/101] pwm: bcm-kona: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (7 preceding siblings ...)
  2023-08-08 17:17 ` [PATCH v1 008/101] pwm: bcm-iproc: " Uwe Kleine-König
@ 2023-08-08 17:17 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 010/101] pwm: berlin: " Uwe Kleine-König
                   ` (93 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:17 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-bcm-kona driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-bcm-kona.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index c0d9956b6443..a0d961173b86 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -56,14 +56,13 @@
 #define DUTY_CYCLE_HIGH_MAX			0x00ffffff
 
 struct kona_pwmc {
-	struct pwm_chip chip;
 	void __iomem *base;
 	struct clk *clk;
 };
 
 static inline struct kona_pwmc *to_kona_pwmc(struct pwm_chip *chip)
 {
-	return container_of(chip, struct kona_pwmc, chip);
+	return pwmchip_priv(chip);
 }
 
 /*
@@ -264,18 +263,18 @@ static const struct pwm_ops kona_pwm_ops = {
 
 static int kona_pwmc_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct kona_pwmc *kp;
 	unsigned int chan;
 	unsigned int value = 0;
 	int ret = 0;
 
-	kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL);
-	if (kp == NULL)
+	chip = devm_pwmchip_alloc(&pdev->dev, 6, sizeof(*kp));
+	if (chip == NULL)
 		return -ENOMEM;
+	kp = to_kona_pwmc(chip);
 
-	kp->chip.dev = &pdev->dev;
-	kp->chip.ops = &kona_pwm_ops;
-	kp->chip.npwm = 6;
+	chip->ops = &kona_pwm_ops;
 
 	kp->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(kp->base))
@@ -295,14 +294,14 @@ static int kona_pwmc_probe(struct platform_device *pdev)
 	}
 
 	/* Set push/pull for all channels */
-	for (chan = 0; chan < kp->chip.npwm; chan++)
+	for (chan = 0; chan < chip->npwm; chan++)
 		value |= (1 << PWM_CONTROL_TYPE_SHIFT(chan));
 
 	writel(value, kp->base + PWM_CONTROL_OFFSET);
 
 	clk_disable_unprepare(kp->clk);
 
-	ret = devm_pwmchip_add(&pdev->dev, &kp->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 010/101] pwm: berlin: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (8 preceding siblings ...)
  2023-08-08 17:17 ` [PATCH v1 009/101] pwm: bcm-kona: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 011/101] pwm: brcmstb: " Uwe Kleine-König
                   ` (92 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-berlin driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-berlin.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index ba2d79991769..fd5901dda874 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -49,7 +49,6 @@ struct berlin_pwm_channel {
 };
 
 struct berlin_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	void __iomem *base;
 	struct berlin_pwm_channel channel[BERLIN_PWM_NUMPWMS];
@@ -57,7 +56,7 @@ struct berlin_pwm_chip {
 
 static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct berlin_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *bpc,
@@ -198,12 +197,14 @@ MODULE_DEVICE_TABLE(of, berlin_pwm_match);
 
 static int berlin_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct berlin_pwm_chip *bpc;
 	int ret;
 
-	bpc = devm_kzalloc(&pdev->dev, sizeof(*bpc), GFP_KERNEL);
-	if (!bpc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, BERLIN_PWM_NUMPWMS, sizeof(*bpc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	bpc = to_berlin_pwm_chip(chip);
 
 	bpc->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(bpc->base))
@@ -213,15 +214,13 @@ static int berlin_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(bpc->clk))
 		return PTR_ERR(bpc->clk);
 
-	bpc->chip.dev = &pdev->dev;
-	bpc->chip.ops = &berlin_pwm_ops;
-	bpc->chip.npwm = BERLIN_PWM_NUMPWMS;
+	chip->ops = &berlin_pwm_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &bpc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
 
-	platform_set_drvdata(pdev, bpc);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 }
@@ -229,10 +228,11 @@ static int berlin_pwm_probe(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int berlin_pwm_suspend(struct device *dev)
 {
-	struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
 	unsigned int i;
 
-	for (i = 0; i < bpc->chip.npwm; i++) {
+	for (i = 0; i < chip->npwm; i++) {
 		struct berlin_pwm_channel *channel = &bpc->channel[i];
 
 		channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE);
@@ -248,7 +248,8 @@ static int berlin_pwm_suspend(struct device *dev)
 
 static int berlin_pwm_resume(struct device *dev)
 {
-	struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct berlin_pwm_chip *bpc = to_berlin_pwm_chip(chip);
 	unsigned int i;
 	int ret;
 
@@ -256,7 +257,7 @@ static int berlin_pwm_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	for (i = 0; i < bpc->chip.npwm; i++) {
+	for (i = 0; i < chip->npwm; i++) {
 		struct berlin_pwm_channel *channel = &bpc->channel[i];
 
 		berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 011/101] pwm: brcmstb: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (9 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 010/101] pwm: berlin: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 012/101] pwm: clk: " Uwe Kleine-König
                   ` (91 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-brcmstb driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-brcmstb.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
index 62bd01c08350..6671d9cf310f 100644
--- a/drivers/pwm/pwm-brcmstb.c
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -54,7 +54,6 @@
 struct brcmstb_pwm {
 	void __iomem *base;
 	struct clk *clk;
-	struct pwm_chip chip;
 };
 
 static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
@@ -77,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_priv(chip);
 }
 
 /*
@@ -230,12 +229,14 @@ 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;
 	int ret;
 
-	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return -ENOMEM;
+	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_enabled(&pdev->dev, NULL);
 	if (IS_ERR(p->clk))
@@ -244,15 +245,13 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, p);
 
-	p->chip.dev = &pdev->dev;
-	p->chip.ops = &brcmstb_pwm_ops;
-	p->chip.npwm = 2;
+	chip->ops = &brcmstb_pwm_ops;
 
 	p->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(p->base))
 		return PTR_ERR(p->base);
 
-	ret = devm_pwmchip_add(&pdev->dev, &p->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 012/101] pwm: clk: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (10 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 011/101] pwm: brcmstb: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 013/101] pwm: clps711x: " Uwe Kleine-König
                   ` (90 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-clk driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-clk.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-clk.c b/drivers/pwm/pwm-clk.c
index 9dd88b386907..86bf1ddedf89 100644
--- a/drivers/pwm/pwm-clk.c
+++ b/drivers/pwm/pwm-clk.c
@@ -28,12 +28,14 @@
 #include <linux/pwm.h>
 
 struct pwm_clk_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	bool clk_enabled;
 };
 
-#define to_pwm_clk_chip(_chip) container_of(_chip, struct pwm_clk_chip, chip)
+static inline struct pwm_clk_chip *to_pwm_clk_chip(struct pwm_chip *chip)
+{
+	return pwmchip_priv(chip);
+}
 
 static int pwm_clk_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 			 const struct pwm_state *state)
@@ -81,35 +83,36 @@ static const struct pwm_ops pwm_clk_ops = {
 
 static int pwm_clk_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct pwm_clk_chip *pcchip;
 	int ret;
 
-	pcchip = devm_kzalloc(&pdev->dev, sizeof(*pcchip), GFP_KERNEL);
-	if (!pcchip)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pcchip));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pcchip = to_pwm_clk_chip(chip);
 
 	pcchip->clk = devm_clk_get_prepared(&pdev->dev, NULL);
 	if (IS_ERR(pcchip->clk))
 		return dev_err_probe(&pdev->dev, PTR_ERR(pcchip->clk),
 				     "Failed to get clock\n");
 
-	pcchip->chip.dev = &pdev->dev;
-	pcchip->chip.ops = &pwm_clk_ops;
-	pcchip->chip.npwm = 1;
+	chip->ops = &pwm_clk_ops;
 
-	ret = pwmchip_add(&pcchip->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "Failed to add pwm chip\n");
 
-	platform_set_drvdata(pdev, pcchip);
+	platform_set_drvdata(pdev, chip);
 	return 0;
 }
 
 static void pwm_clk_remove(struct platform_device *pdev)
 {
-	struct pwm_clk_chip *pcchip = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct pwm_clk_chip *pcchip = to_pwm_clk_chip(chip);
 
-	pwmchip_remove(&pcchip->chip);
+	pwmchip_remove(chip);
 
 	if (pcchip->clk_enabled)
 		clk_disable(pcchip->clk);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 013/101] pwm: clps711x: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (11 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 012/101] pwm: clk: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 014/101] pwm: crc: " Uwe Kleine-König
                   ` (89 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-clps711x driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-clps711x.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
index 42179b3f7ec3..f8a05a11a5d0 100644
--- a/drivers/pwm/pwm-clps711x.c
+++ b/drivers/pwm/pwm-clps711x.c
@@ -12,7 +12,6 @@
 #include <linux/pwm.h>
 
 struct clps711x_chip {
-	struct pwm_chip chip;
 	void __iomem *pmpcon;
 	struct clk *clk;
 	spinlock_t lock;
@@ -20,7 +19,7 @@ struct clps711x_chip {
 
 static inline struct clps711x_chip *to_clps711x_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct clps711x_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -85,11 +84,13 @@ static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip,
 
 static int clps711x_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct clps711x_chip *priv;
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = to_clps711x_chip(chip);
 
 	priv->pmpcon = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(priv->pmpcon))
@@ -99,15 +100,13 @@ static int clps711x_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(priv->clk))
 		return PTR_ERR(priv->clk);
 
-	priv->chip.ops = &clps711x_pwm_ops;
-	priv->chip.dev = &pdev->dev;
-	priv->chip.npwm = 2;
-	priv->chip.of_xlate = clps711x_pwm_xlate;
-	priv->chip.of_pwm_n_cells = 1;
+	chip->ops = &clps711x_pwm_ops;
+	chip->of_xlate = clps711x_pwm_xlate;
+	chip->of_pwm_n_cells = 1;
 
 	spin_lock_init(&priv->lock);
 
-	return devm_pwmchip_add(&pdev->dev, &priv->chip);
+	return devm_pwmchip_add(&pdev->dev, chip);
 }
 
 static const struct of_device_id __maybe_unused clps711x_pwm_dt_ids[] = {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 014/101] pwm: crc: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (12 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 013/101] pwm: clps711x: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 015/101] pwm: cros-ec: Change prototype of helper to prepare further changes Uwe Kleine-König
                   ` (88 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-crc driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-crc.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index b9f063dc6b5f..5f8651b87880 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -26,17 +26,15 @@
 
 /**
  * struct crystalcove_pwm - Crystal Cove PWM controller
- * @chip: the abstract pwm_chip structure.
  * @regmap: the regmap from the parent device.
  */
 struct crystalcove_pwm {
-	struct pwm_chip chip;
 	struct regmap *regmap;
 };
 
 static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct crystalcove_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int crc_pwm_calc_clk_div(int period_ns)
@@ -160,22 +158,23 @@ static const struct pwm_ops crc_pwm_ops = {
 
 static int crystalcove_pwm_probe(struct platform_device *pdev)
 {
-	struct crystalcove_pwm *pwm;
+	struct pwm_chip *chip;
+	struct crystalcove_pwm *crc_pwm;
 	struct device *dev = pdev->dev.parent;
 	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
 
-	pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
-	if (!pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, sizeof(*pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	crc_pwm = to_crc_pwm(chip);
 
-	pwm->chip.dev = &pdev->dev;
-	pwm->chip.ops = &crc_pwm_ops;
-	pwm->chip.npwm = 1;
+	chip->ops = &crc_pwm_ops;
+	chip->npwm = 1;
 
 	/* get the PMIC regmap */
-	pwm->regmap = pmic->regmap;
+	crc_pwm->regmap = pmic->regmap;
 
-	return devm_pwmchip_add(&pdev->dev, &pwm->chip);
+	return devm_pwmchip_add(&pdev->dev, chip);
 }
 
 static struct platform_driver crystalcove_pwm_driver = {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 015/101] pwm: cros-ec: Change prototype of helper to prepare further changes
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (13 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 014/101] pwm: crc: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 016/101] pwm: cros-ec: Make use of devm_pwmchip_alloc() function Uwe Kleine-König
                   ` (87 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

pwm_chip allocation and registration is about to change. For that the number
of PWM devices must be known earlier in cros_ec_pwm_probe(). So make
cros_ec_pwm_get_duty() independant from struct cros_ec_pwm_device which is only
available later.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-cros-ec.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c
index e2a5e54face1..8a5925a624e6 100644
--- a/drivers/pwm/pwm-cros-ec.c
+++ b/drivers/pwm/pwm-cros-ec.c
@@ -93,9 +93,8 @@ static int cros_ec_pwm_set_duty(struct cros_ec_pwm_device *ec_pwm, u8 index,
 	return cros_ec_cmd_xfer_status(ec, msg);
 }
 
-static int cros_ec_pwm_get_duty(struct cros_ec_pwm_device *ec_pwm, u8 index)
+static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, bool use_pwm_type, u8 index)
 {
-	struct cros_ec_device *ec = ec_pwm->ec;
 	struct {
 		struct cros_ec_command msg;
 		union {
@@ -115,7 +114,7 @@ static int cros_ec_pwm_get_duty(struct cros_ec_pwm_device *ec_pwm, u8 index)
 	msg->insize = sizeof(*resp);
 	msg->outsize = sizeof(*params);
 
-	if (ec_pwm->use_pwm_type) {
+	if (use_pwm_type) {
 		ret = cros_ec_dt_type_to_pwm_type(index, &params->pwm_type);
 		if (ret)
 			return ret;
@@ -169,7 +168,7 @@ static int cros_ec_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	struct cros_ec_pwm *channel = &ec_pwm->channel[pwm->hwpwm];
 	int ret;
 
-	ret = cros_ec_pwm_get_duty(ec_pwm, pwm->hwpwm);
+	ret = cros_ec_pwm_get_duty(ec_pwm->ec, ec_pwm->use_pwm_type, pwm->hwpwm);
 	if (ret < 0)
 		return ret;
 
@@ -228,7 +227,7 @@ static int cros_ec_num_pwms(struct cros_ec_pwm_device *ec_pwm)
 
 	/* The index field is only 8 bits */
 	for (i = 0; i <= U8_MAX; i++) {
-		ret = cros_ec_pwm_get_duty(ec_pwm, i);
+		ret = cros_ec_pwm_get_duty(ec_pwm->ec, ec_pwm->use_pwm_type, i);
 		/*
 		 * We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM
 		 * responses; everything else is treated as an error.
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 016/101] pwm: cros-ec: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (14 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 015/101] pwm: cros-ec: Change prototype of helper to prepare further changes Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 017/101] pwm: dwc: " Uwe Kleine-König
                   ` (86 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-cros-ec driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.
The probe function had to be changed a bit because the number of PWMs
must be determined before allocation of the pwm_chip and its private
data now.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-cros-ec.c | 42 +++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c
index 8a5925a624e6..780d2820ecb3 100644
--- a/drivers/pwm/pwm-cros-ec.c
+++ b/drivers/pwm/pwm-cros-ec.c
@@ -27,7 +27,6 @@
 struct cros_ec_pwm_device {
 	struct device *dev;
 	struct cros_ec_device *ec;
-	struct pwm_chip chip;
 	bool use_pwm_type;
 	struct cros_ec_pwm *channel;
 };
@@ -42,7 +41,7 @@ struct cros_ec_pwm {
 
 static inline struct cros_ec_pwm_device *pwm_to_cros_ec_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct cros_ec_pwm_device, chip);
+	return pwmchip_priv(chip);
 }
 
 static int cros_ec_dt_type_to_pwm_type(u8 dt_index, u8 *pwm_type)
@@ -221,13 +220,13 @@ static const struct pwm_ops cros_ec_pwm_ops = {
  * of PWMs it supports directly, so we have to read the pwm duty cycle for
  * subsequent channels until we get an error.
  */
-static int cros_ec_num_pwms(struct cros_ec_pwm_device *ec_pwm)
+static int cros_ec_num_pwms(struct cros_ec_device *ec, bool use_pwm_type)
 {
 	int i, ret;
 
 	/* The index field is only 8 bits */
 	for (i = 0; i <= U8_MAX; i++) {
-		ret = cros_ec_pwm_get_duty(ec_pwm->ec, ec_pwm->use_pwm_type, i);
+		ret = cros_ec_pwm_get_duty(ec, use_pwm_type, i);
 		/*
 		 * We look for SUCCESS, INVALID_COMMAND, or INVALID_PARAM
 		 * responses; everything else is treated as an error.
@@ -256,35 +255,36 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct cros_ec_pwm_device *ec_pwm;
 	struct pwm_chip *chip;
+	bool use_pwm_type = false;
+	unsigned npwm;
 	int ret;
 
 	if (!ec)
 		return dev_err_probe(dev, -EINVAL, "no parent EC device\n");
 
-	ec_pwm = devm_kzalloc(dev, sizeof(*ec_pwm), GFP_KERNEL);
-	if (!ec_pwm)
-		return -ENOMEM;
-	chip = &ec_pwm->chip;
+	if (of_device_is_compatible(np, "google,cros-ec-pwm-type")) {
+		use_pwm_type = true;
+		npwm = CROS_EC_PWM_DT_COUNT;
+	} else {
+		ret = cros_ec_num_pwms(ec, use_pwm_type);
+		if (ret < 0)
+			return dev_err_probe(dev, ret, "Couldn't find PWMs\n");
+		npwm = ret;
+	}
+
+	chip = devm_pwmchip_alloc(dev, npwm, sizeof(*ec_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	ec_pwm = pwm_to_cros_ec_pwm(chip);
+	ec_pwm->use_pwm_type = use_pwm_type;
 	ec_pwm->ec = ec;
 
-	if (of_device_is_compatible(np, "google,cros-ec-pwm-type"))
-		ec_pwm->use_pwm_type = true;
-
 	/* PWM chip */
-	chip->dev = dev;
 	chip->ops = &cros_ec_pwm_ops;
 	chip->of_xlate = cros_ec_pwm_xlate;
 	chip->of_pwm_n_cells = 1;
 
-	if (ec_pwm->use_pwm_type) {
-		chip->npwm = CROS_EC_PWM_DT_COUNT;
-	} else {
-		ret = cros_ec_num_pwms(ec_pwm);
-		if (ret < 0)
-			return dev_err_probe(dev, ret, "Couldn't find PWMs\n");
-		chip->npwm = ret;
-	}
-
 	ec_pwm->channel = devm_kcalloc(dev, chip->npwm, sizeof(*ec_pwm->channel),
 					GFP_KERNEL);
 	if (!ec_pwm->channel)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 017/101] pwm: dwc: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (15 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 016/101] pwm: cros-ec: Make use of devm_pwmchip_alloc() function Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 018/101] pwm: ep93xx: " Uwe Kleine-König
                   ` (85 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-dwc driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-dwc.c | 43 +++++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c
index 53fe00ccd47e..19b9a23d5ee1 100644
--- a/drivers/pwm/pwm-dwc.c
+++ b/drivers/pwm/pwm-dwc.c
@@ -51,11 +51,13 @@ struct dwc_pwm_ctx {
 };
 
 struct dwc_pwm {
-	struct pwm_chip chip;
 	void __iomem *base;
 	struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
 };
-#define to_dwc_pwm(p)	(container_of((p), struct dwc_pwm, chip))
+static inline struct dwc_pwm *to_dwc_pwm(struct pwm_chip *chip)
+{
+	return pwmchip_priv(chip);
+}
 
 static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset)
 {
@@ -197,31 +199,32 @@ static const struct pwm_ops dwc_pwm_ops = {
 	.get_state = dwc_pwm_get_state,
 };
 
-static struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
+static struct pwm_chip *dwc_pwm_alloc(struct device *dev)
 {
-	struct dwc_pwm *dwc;
+	struct pwm_chip *chip;
 
-	dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
-	if (!dwc)
+	chip = devm_pwmchip_alloc(dev, DWC_TIMERS_TOTAL, sizeof(struct dwc_pwm));
+	if (!chip)
 		return NULL;
 
-	dwc->chip.dev = dev;
-	dwc->chip.ops = &dwc_pwm_ops;
-	dwc->chip.npwm = DWC_TIMERS_TOTAL;
+	chip->ops = &dwc_pwm_ops;
 
-	dev_set_drvdata(dev, dwc);
-	return dwc;
+	dev_set_drvdata(dev, chip);
+
+	return chip;
 }
 
 static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
 	struct device *dev = &pci->dev;
 	struct dwc_pwm *dwc;
+	struct pwm_chip *chip;
 	int ret;
 
-	dwc = dwc_pwm_alloc(dev);
-	if (!dwc)
+	chip = dwc_pwm_alloc(dev);
+	if (!chip)
 		return -ENOMEM;
+	dwc = to_dwc_pwm(chip);
 
 	ret = pcim_enable_device(pci);
 	if (ret) {
@@ -243,7 +246,7 @@ static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
 		return -ENOMEM;
 	}
 
-	ret = devm_pwmchip_add(dev, &dwc->chip);
+	ret = devm_pwmchip_add(dev, chip);
 	if (ret)
 		return ret;
 
@@ -262,14 +265,14 @@ static void dwc_pwm_remove(struct pci_dev *pci)
 #ifdef CONFIG_PM_SLEEP
 static int dwc_pwm_suspend(struct device *dev)
 {
-	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
-	struct dwc_pwm *dwc = pci_get_drvdata(pdev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct dwc_pwm *dwc = to_dwc_pwm(chip);
 	int i;
 
 	for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
-		if (dwc->chip.pwms[i].state.enabled) {
+		if (chip->pwms[i].state.enabled) {
 			dev_err(dev, "PWM %u in use by consumer (%s)\n",
-				i, dwc->chip.pwms[i].label);
+				i, chip->pwms[i].label);
 			return -EBUSY;
 		}
 		dwc->ctx[i].cnt = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(i));
@@ -282,8 +285,8 @@ static int dwc_pwm_suspend(struct device *dev)
 
 static int dwc_pwm_resume(struct device *dev)
 {
-	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
-	struct dwc_pwm *dwc = pci_get_drvdata(pdev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct dwc_pwm *dwc = to_dwc_pwm(chip);
 	int i;
 
 	for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 018/101] pwm: ep93xx: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (16 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 017/101] pwm: dwc: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 019/101] pwm: fsl-ftm: " Uwe Kleine-König
                   ` (84 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-ep93xx driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-ep93xx.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c
index 51e072572a87..394013c545ac 100644
--- a/drivers/pwm/pwm-ep93xx.c
+++ b/drivers/pwm/pwm-ep93xx.c
@@ -36,12 +36,11 @@
 struct ep93xx_pwm {
 	void __iomem *base;
 	struct clk *clk;
-	struct pwm_chip chip;
 };
 
 static inline struct ep93xx_pwm *to_ep93xx_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct ep93xx_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int ep93xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -163,12 +162,14 @@ static const struct pwm_ops ep93xx_pwm_ops = {
 
 static int ep93xx_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct ep93xx_pwm *ep93xx_pwm;
 	int ret;
 
-	ep93xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_pwm), GFP_KERNEL);
-	if (!ep93xx_pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*ep93xx_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	ep93xx_pwm = to_ep93xx_pwm(chip);
 
 	ep93xx_pwm->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(ep93xx_pwm->base))
@@ -178,11 +179,9 @@ static int ep93xx_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(ep93xx_pwm->clk))
 		return PTR_ERR(ep93xx_pwm->clk);
 
-	ep93xx_pwm->chip.dev = &pdev->dev;
-	ep93xx_pwm->chip.ops = &ep93xx_pwm_ops;
-	ep93xx_pwm->chip.npwm = 1;
+	chip->ops = &ep93xx_pwm_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &ep93xx_pwm->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return ret;
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 019/101] pwm: fsl-ftm: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (17 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 018/101] pwm: ep93xx: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 020/101] pwm: hibvt: " Uwe Kleine-König
                   ` (83 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-fsl-ftm driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-fsl-ftm.c | 48 ++++++++++++++++++++-------------------
 1 file changed, 25 insertions(+), 23 deletions(-)

diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index d1b6d1aa4773..f56c7e9f491a 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -40,7 +40,6 @@ struct fsl_pwm_periodcfg {
 };
 
 struct fsl_pwm_chip {
-	struct pwm_chip chip;
 	struct mutex lock;
 	struct regmap *regmap;
 
@@ -55,7 +54,7 @@ struct fsl_pwm_chip {
 
 static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct fsl_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc)
@@ -221,10 +220,11 @@ static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc,
 		return false;
 }
 
-static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
+static int fsl_pwm_apply_config(struct pwm_chip *chip,
 				struct pwm_device *pwm,
 				const struct pwm_state *newstate)
 {
+	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
 	unsigned int duty;
 	u32 reg_polarity;
 
@@ -232,7 +232,7 @@ static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
 	bool do_write_period = false;
 
 	if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {
-		dev_err(fpc->chip.dev, "failed to calculate new period\n");
+		dev_err(chip->dev, "failed to calculate new period\n");
 		return -EINVAL;
 	}
 
@@ -246,7 +246,7 @@ static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
 	 */
 	else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {
 		if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {
-			dev_err(fpc->chip.dev,
+			dev_err(chip->dev,
 				"Cannot change period for PWM %u, disable other PWMs first\n",
 				pwm->hwpwm);
 			return -EBUSY;
@@ -322,7 +322,7 @@ static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 		goto end_mutex;
 	}
 
-	ret = fsl_pwm_apply_config(fpc, pwm, newstate);
+	ret = fsl_pwm_apply_config(chip, pwm, newstate);
 	if (ret)
 		goto end_mutex;
 
@@ -392,18 +392,19 @@ static const struct regmap_config fsl_pwm_regmap_config = {
 
 static int fsl_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct fsl_pwm_chip *fpc;
 	void __iomem *base;
 	int ret;
 
-	fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL);
-	if (!fpc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 8, sizeof(*fpc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	fpc = to_fsl_chip(chip);
 
 	mutex_init(&fpc->lock);
 
 	fpc->soc = of_device_get_match_data(&pdev->dev);
-	fpc->chip.dev = &pdev->dev;
 
 	base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(base))
@@ -422,16 +423,16 @@ static int fsl_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);
 	}
 
-	fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(fpc->chip.dev, "ftm_fix");
+	fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(&pdev->dev, "ftm_fix");
 	if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX]))
 		return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]);
 
-	fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(fpc->chip.dev, "ftm_ext");
+	fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(&pdev->dev, "ftm_ext");
 	if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT]))
 		return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]);
 
 	fpc->clk[FSL_PWM_CLK_CNTEN] =
-				devm_clk_get(fpc->chip.dev, "ftm_cnt_clk_en");
+				devm_clk_get(&pdev->dev, "ftm_cnt_clk_en");
 	if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))
 		return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);
 
@@ -444,16 +445,15 @@ static int fsl_pwm_probe(struct platform_device *pdev)
 		fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS];
 
 
-	fpc->chip.ops = &fsl_pwm_ops;
-	fpc->chip.npwm = 8;
+	chip->ops = &fsl_pwm_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &fpc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
 		return ret;
 	}
 
-	platform_set_drvdata(pdev, fpc);
+	platform_set_drvdata(pdev, chip);
 
 	return fsl_pwm_init(fpc);
 }
@@ -461,14 +461,15 @@ static int fsl_pwm_probe(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int fsl_pwm_suspend(struct device *dev)
 {
-	struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
 	int i;
 
 	regcache_cache_only(fpc->regmap, true);
 	regcache_mark_dirty(fpc->regmap);
 
-	for (i = 0; i < fpc->chip.npwm; i++) {
-		struct pwm_device *pwm = &fpc->chip.pwms[i];
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
 
 		if (!test_bit(PWMF_REQUESTED, &pwm->flags))
 			continue;
@@ -487,11 +488,12 @@ static int fsl_pwm_suspend(struct device *dev)
 
 static int fsl_pwm_resume(struct device *dev)
 {
-	struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
 	int i;
 
-	for (i = 0; i < fpc->chip.npwm; i++) {
-		struct pwm_device *pwm = &fpc->chip.pwms[i];
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
 
 		if (!test_bit(PWMF_REQUESTED, &pwm->flags))
 			continue;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 020/101] pwm: hibvt: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (18 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 019/101] pwm: fsl-ftm: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 021/101] pwm: img: " Uwe Kleine-König
                   ` (82 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-hibvt driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-hibvt.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c
index c435776e2f78..60be59ce4320 100644
--- a/drivers/pwm/pwm-hibvt.c
+++ b/drivers/pwm/pwm-hibvt.c
@@ -33,7 +33,6 @@
 #define PWM_DUTY_MASK       GENMASK(31, 0)
 
 struct hibvt_pwm_chip {
-	struct pwm_chip	chip;
 	struct clk *clk;
 	void __iomem *base;
 	struct reset_control *rstc;
@@ -65,7 +64,7 @@ static const struct hibvt_pwm_soc hi3559v100_soc_info = {
 
 static inline struct hibvt_pwm_chip *to_hibvt_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct hibvt_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static void hibvt_pwm_set_bits(void __iomem *base, u32 offset,
@@ -191,12 +190,14 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
 {
 	const struct hibvt_pwm_soc *soc =
 				of_device_get_match_data(&pdev->dev);
+	struct pwm_chip	*chip;
 	struct hibvt_pwm_chip *pwm_chip;
 	int ret, i;
 
-	pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL);
-	if (pwm_chip == NULL)
+	chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms, sizeof(*pwm_chip));
+	if (chip == NULL)
 		return -ENOMEM;
+	pwm_chip = to_hibvt_pwm_chip(chip);
 
 	pwm_chip->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(pwm_chip->clk)) {
@@ -205,9 +206,7 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(pwm_chip->clk);
 	}
 
-	pwm_chip->chip.ops = &hibvt_pwm_ops;
-	pwm_chip->chip.dev = &pdev->dev;
-	pwm_chip->chip.npwm = soc->num_pwms;
+	chip->ops = &hibvt_pwm_ops;
 	pwm_chip->soc = soc;
 
 	pwm_chip->base = devm_platform_ioremap_resource(pdev, 0);
@@ -228,29 +227,31 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
 	msleep(30);
 	reset_control_deassert(pwm_chip->rstc);
 
-	ret = pwmchip_add(&pwm_chip->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		clk_disable_unprepare(pwm_chip->clk);
 		return ret;
 	}
 
-	for (i = 0; i < pwm_chip->chip.npwm; i++) {
+	for (i = 0; i < chip->npwm; i++) {
 		hibvt_pwm_set_bits(pwm_chip->base, PWM_CTRL_ADDR(i),
 				PWM_KEEP_MASK, (0x1 << PWM_KEEP_SHIFT));
 	}
 
-	platform_set_drvdata(pdev, pwm_chip);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 }
 
 static void hibvt_pwm_remove(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct hibvt_pwm_chip *pwm_chip;
 
-	pwm_chip = platform_get_drvdata(pdev);
+	chip = platform_get_drvdata(pdev);
+	pwm_chip = to_hibvt_pwm_chip(chip);
 
-	pwmchip_remove(&pwm_chip->chip);
+	pwmchip_remove(chip);
 
 	reset_control_assert(pwm_chip->rstc);
 	msleep(30);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 021/101] pwm: img: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (19 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 020/101] pwm: hibvt: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 022/101] pwm: imx1: " Uwe Kleine-König
                   ` (81 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-img driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-img.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c
index 116fa060e302..64e35ca1b576 100644
--- a/drivers/pwm/pwm-img.c
+++ b/drivers/pwm/pwm-img.c
@@ -60,7 +60,6 @@ struct img_pwm_soc_data {
 
 struct img_pwm_chip {
 	struct device	*dev;
-	struct pwm_chip	chip;
 	struct clk	*pwm_clk;
 	struct clk	*sys_clk;
 	void __iomem	*base;
@@ -74,7 +73,7 @@ struct img_pwm_chip {
 
 static inline struct img_pwm_chip *to_img_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct img_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline void img_pwm_writel(struct img_pwm_chip *imgchip,
@@ -259,12 +258,14 @@ static int img_pwm_probe(struct platform_device *pdev)
 	int ret;
 	u64 val;
 	unsigned long clk_rate;
+	struct pwm_chip *chip;
 	struct img_pwm_chip *imgchip;
 	const struct of_device_id *of_dev_id;
 
-	imgchip = devm_kzalloc(&pdev->dev, sizeof(*imgchip), GFP_KERNEL);
-	if (!imgchip)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, IMG_PWM_NPWM, sizeof(*imgchip));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	imgchip = to_img_pwm_chip(chip);
 
 	imgchip->dev = &pdev->dev;
 
@@ -294,7 +295,7 @@ static int img_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(imgchip->pwm_clk);
 	}
 
-	platform_set_drvdata(pdev, imgchip);
+	platform_set_drvdata(pdev, chip);
 
 	pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_PWM_PM_TIMEOUT);
 	pm_runtime_use_autosuspend(&pdev->dev);
@@ -321,11 +322,9 @@ static int img_pwm_probe(struct platform_device *pdev)
 	do_div(val, clk_rate);
 	imgchip->min_period_ns = val;
 
-	imgchip->chip.dev = &pdev->dev;
-	imgchip->chip.ops = &img_pwm_ops;
-	imgchip->chip.npwm = IMG_PWM_NPWM;
+	chip->ops = &img_pwm_ops;
 
-	ret = pwmchip_add(&imgchip->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
 		goto err_suspend;
@@ -344,19 +343,20 @@ static int img_pwm_probe(struct platform_device *pdev)
 
 static void img_pwm_remove(struct platform_device *pdev)
 {
-	struct img_pwm_chip *imgchip = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
 
 	pm_runtime_disable(&pdev->dev);
 	if (!pm_runtime_status_suspended(&pdev->dev))
 		img_pwm_runtime_suspend(&pdev->dev);
 
-	pwmchip_remove(&imgchip->chip);
+	pwmchip_remove(chip);
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int img_pwm_suspend(struct device *dev)
 {
-	struct img_pwm_chip *imgchip = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
 	int i, ret;
 
 	if (pm_runtime_status_suspended(dev)) {
@@ -365,7 +365,7 @@ static int img_pwm_suspend(struct device *dev)
 			return ret;
 	}
 
-	for (i = 0; i < imgchip->chip.npwm; i++)
+	for (i = 0; i < chip->npwm; i++)
 		imgchip->suspend_ch_cfg[i] = img_pwm_readl(imgchip,
 							   PWM_CH_CFG(i));
 
@@ -378,7 +378,8 @@ static int img_pwm_suspend(struct device *dev)
 
 static int img_pwm_resume(struct device *dev)
 {
-	struct img_pwm_chip *imgchip = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
 	int ret;
 	int i;
 
@@ -386,13 +387,13 @@ static int img_pwm_resume(struct device *dev)
 	if (ret)
 		return ret;
 
-	for (i = 0; i < imgchip->chip.npwm; i++)
+	for (i = 0; i < chip->npwm; i++)
 		img_pwm_writel(imgchip, PWM_CH_CFG(i),
 			       imgchip->suspend_ch_cfg[i]);
 
 	img_pwm_writel(imgchip, PWM_CTRL_CFG, imgchip->suspend_ctrl_cfg);
 
-	for (i = 0; i < imgchip->chip.npwm; i++)
+	for (i = 0; i < chip->npwm; i++)
 		if (imgchip->suspend_ctrl_cfg & BIT(i))
 			regmap_clear_bits(imgchip->periph_regs,
 					  PERIP_PWM_PDM_CONTROL,
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 022/101] pwm: imx1: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (20 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 021/101] pwm: img: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 023/101] pwm: imx27: " Uwe Kleine-König
                   ` (80 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-imx1 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-imx1.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c
index d175d895f22a..e4cf6e957b63 100644
--- a/drivers/pwm/pwm-imx1.c
+++ b/drivers/pwm/pwm-imx1.c
@@ -28,10 +28,9 @@ struct pwm_imx1_chip {
 	struct clk *clk_ipg;
 	struct clk *clk_per;
 	void __iomem *mmio_base;
-	struct pwm_chip chip;
 };
 
-#define to_pwm_imx1_chip(chip)	container_of(chip, struct pwm_imx1_chip, chip)
+#define to_pwm_imx1_chip(chip)	pwmchip_priv(chip)
 
 static int pwm_imx1_clk_prepare_enable(struct pwm_chip *chip)
 {
@@ -156,11 +155,13 @@ MODULE_DEVICE_TABLE(of, pwm_imx1_dt_ids);
 
 static int pwm_imx1_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct pwm_imx1_chip *imx;
 
-	imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
-	if (!imx)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*imx));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	imx = to_pwm_imx1_chip(chip);
 
 	imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(imx->clk_ipg))
@@ -172,15 +173,13 @@ static int pwm_imx1_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per),
 				     "failed to get peripheral clock\n");
 
-	imx->chip.ops = &pwm_imx1_ops;
-	imx->chip.dev = &pdev->dev;
-	imx->chip.npwm = 1;
+	chip->ops = &pwm_imx1_ops;
 
 	imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(imx->mmio_base))
 		return PTR_ERR(imx->mmio_base);
 
-	return devm_pwmchip_add(&pdev->dev, &imx->chip);
+	return devm_pwmchip_add(&pdev->dev, chip);
 }
 
 static struct platform_driver pwm_imx1_driver = {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 023/101] pwm: imx27: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (21 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 022/101] pwm: imx1: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 024/101] pwm: imx-tpm: " Uwe Kleine-König
                   ` (79 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-imx27 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-imx27.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c
index 7d9bc43f12b0..79af72fbcec3 100644
--- a/drivers/pwm/pwm-imx27.c
+++ b/drivers/pwm/pwm-imx27.c
@@ -83,7 +83,6 @@ struct pwm_imx27_chip {
 	struct clk	*clk_ipg;
 	struct clk	*clk_per;
 	void __iomem	*mmio_base;
-	struct pwm_chip	chip;
 
 	/*
 	 * The driver cannot read the current duty cycle from the hardware if
@@ -93,7 +92,10 @@ struct pwm_imx27_chip {
 	unsigned int duty_cycle;
 };
 
-#define to_pwm_imx27_chip(chip)	container_of(chip, struct pwm_imx27_chip, chip)
+static inline struct pwm_imx27_chip *to_pwm_imx27_chip(struct pwm_chip *chip)
+{
+	return pwmchip_priv(chip);
+}
 
 static int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx)
 {
@@ -306,13 +308,15 @@ MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids);
 
 static int pwm_imx27_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct pwm_imx27_chip *imx;
 	int ret;
 	u32 pwmcr;
 
-	imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
-	if (imx == NULL)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*imx));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	imx = pwmchip_priv(chip);
 
 	imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(imx->clk_ipg))
@@ -324,9 +328,7 @@ static int pwm_imx27_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per),
 				     "failed to get peripheral clock\n");
 
-	imx->chip.ops = &pwm_imx27_ops;
-	imx->chip.dev = &pdev->dev;
-	imx->chip.npwm = 1;
+	chip->ops = &pwm_imx27_ops;
 
 	imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(imx->mmio_base))
@@ -341,7 +343,7 @@ static int pwm_imx27_probe(struct platform_device *pdev)
 	if (!(pwmcr & MX3_PWMCR_EN))
 		pwm_imx27_clk_disable_unprepare(imx);
 
-	return devm_pwmchip_add(&pdev->dev, &imx->chip);
+	return devm_pwmchip_add(&pdev->dev, chip);
 }
 
 static struct platform_driver imx_pwm_driver = {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 024/101] pwm: imx-tpm: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (22 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 023/101] pwm: imx27: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 025/101] pwm: intel-lgm: " Uwe Kleine-König
                   ` (78 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-tmp driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-imx-tpm.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
index dc6aafeb9f7b..6c668c78f849 100644
--- a/drivers/pwm/pwm-imx-tpm.c
+++ b/drivers/pwm/pwm-imx-tpm.c
@@ -57,7 +57,6 @@
 #define PWM_IMX_TPM_MOD_MOD	GENMASK(PWM_IMX_TPM_MOD_WIDTH - 1, 0)
 
 struct imx_tpm_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	void __iomem *base;
 	struct mutex lock;
@@ -75,7 +74,7 @@ struct imx_tpm_pwm_param {
 static inline struct imx_tpm_pwm_chip *
 to_imx_tpm_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct imx_tpm_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 /*
@@ -336,35 +335,40 @@ static const struct pwm_ops imx_tpm_pwm_ops = {
 
 static int pwm_imx_tpm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct imx_tpm_pwm_chip *tpm;
+	void __iomem *base;
 	int ret;
+	unsigned int npwm;
 	u32 val;
 
-	tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL);
-	if (!tpm)
-		return -ENOMEM;
+	base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	/* get number of channels */
+	val = readl(tpm->base + PWM_IMX_TPM_PARAM);
+	npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val);
+
+	chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*tpm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	tpm = to_imx_tpm_pwm_chip(chip);
 
 	platform_set_drvdata(pdev, tpm);
 
-	tpm->base = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(tpm->base))
-		return PTR_ERR(tpm->base);
+	tpm->base = base;
 
 	tpm->clk = devm_clk_get_enabled(&pdev->dev, NULL);
 	if (IS_ERR(tpm->clk))
 		return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk),
 				     "failed to get PWM clock\n");
 
-	tpm->chip.dev = &pdev->dev;
-	tpm->chip.ops = &imx_tpm_pwm_ops;
-
-	/* get number of channels */
-	val = readl(tpm->base + PWM_IMX_TPM_PARAM);
-	tpm->chip.npwm = FIELD_GET(PWM_IMX_TPM_PARAM_CHAN, val);
+	chip->ops = &imx_tpm_pwm_ops;
 
 	mutex_init(&tpm->lock);
 
-	ret = devm_pwmchip_add(&pdev->dev, &tpm->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 025/101] pwm: intel-lgm: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (23 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 024/101] pwm: imx-tpm: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 026/101] pwm: iqs620a: " Uwe Kleine-König
                   ` (77 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-intel-lgm driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-intel-lgm.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-intel-lgm.c b/drivers/pwm/pwm-intel-lgm.c
index 54ecae7f937e..9abd8859f869 100644
--- a/drivers/pwm/pwm-intel-lgm.c
+++ b/drivers/pwm/pwm-intel-lgm.c
@@ -42,14 +42,13 @@
 #define LGM_PWM_PERIOD_2WIRE_NS		(40 * NSEC_PER_MSEC)
 
 struct lgm_pwm_chip {
-	struct pwm_chip chip;
 	struct regmap *regmap;
 	u32 period;
 };
 
 static inline struct lgm_pwm_chip *to_lgm_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct lgm_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int lgm_pwm_enable(struct pwm_chip *chip, bool enable)
@@ -168,14 +167,16 @@ static int lgm_pwm_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct reset_control *rst;
+	struct pwm_chip *chip;
 	struct lgm_pwm_chip *pc;
 	void __iomem *io_base;
 	struct clk *clk;
 	int ret;
 
-	pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, 1, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_lgm_pwm_chip(chip);
 
 	io_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(io_base))
@@ -203,13 +204,11 @@ static int lgm_pwm_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(dev, ret, "cannot deassert reset control\n");
 
-	pc->chip.dev = dev;
-	pc->chip.ops = &lgm_pwm_ops;
-	pc->chip.npwm = 1;
+	chip->ops = &lgm_pwm_ops;
 
 	lgm_pwm_init(pc);
 
-	ret = devm_pwmchip_add(dev, &pc->chip);
+	ret = devm_pwmchip_add(dev, chip);
 	if (ret < 0)
 		return dev_err_probe(dev, ret, "failed to add PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 026/101] pwm: iqs620a: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (24 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 025/101] pwm: intel-lgm: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 027/101] pwm: jz4740: " Uwe Kleine-König
                   ` (76 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-iqs620a driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-iqs620a.c | 37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c
index 378ab036edfe..a012a0f22b9a 100644
--- a/drivers/pwm/pwm-iqs620a.c
+++ b/drivers/pwm/pwm-iqs620a.c
@@ -34,12 +34,17 @@
 
 struct iqs620_pwm_private {
 	struct iqs62x_core *iqs62x;
-	struct pwm_chip chip;
+	struct device *dev;
 	struct notifier_block notifier;
 	struct mutex lock;
 	unsigned int duty_scale;
 };
 
+static inline struct iqs620_pwm_private *iqs620_pwm_from_chip(struct pwm_chip *chip)
+{
+	return pwmchip_priv(chip);
+}
+
 static int iqs620_pwm_init(struct iqs620_pwm_private *iqs620_pwm,
 			   unsigned int duty_scale)
 {
@@ -73,7 +78,7 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (state->period < IQS620_PWM_PERIOD_NS)
 		return -EINVAL;
 
-	iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip);
+	iqs620_pwm = iqs620_pwm_from_chip(chip);
 
 	/*
 	 * The duty cycle generated by the device is calculated as follows:
@@ -107,9 +112,7 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 static int iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 				struct pwm_state *state)
 {
-	struct iqs620_pwm_private *iqs620_pwm;
-
-	iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip);
+	struct iqs620_pwm_private *iqs620_pwm = iqs620_pwm_from_chip(chip);
 
 	mutex_lock(&iqs620_pwm->lock);
 
@@ -155,7 +158,7 @@ static int iqs620_pwm_notifier(struct notifier_block *notifier,
 	mutex_unlock(&iqs620_pwm->lock);
 
 	if (ret) {
-		dev_err(iqs620_pwm->chip.dev,
+		dev_err(iqs620_pwm->dev,
 			"Failed to re-initialize device: %d\n", ret);
 		return NOTIFY_BAD;
 	}
@@ -170,28 +173,32 @@ static const struct pwm_ops iqs620_pwm_ops = {
 
 static void iqs620_pwm_notifier_unregister(void *context)
 {
-	struct iqs620_pwm_private *iqs620_pwm = context;
+	struct pwm_chip *chip = context;
+	struct iqs620_pwm_private *iqs620_pwm = iqs620_pwm_from_chip(chip);
 	int ret;
 
 	ret = blocking_notifier_chain_unregister(&iqs620_pwm->iqs62x->nh,
 						 &iqs620_pwm->notifier);
 	if (ret)
-		dev_err(iqs620_pwm->chip.dev,
+		dev_err(iqs620_pwm->dev,
 			"Failed to unregister notifier: %d\n", ret);
 }
 
 static int iqs620_pwm_probe(struct platform_device *pdev)
 {
 	struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
+	struct pwm_chip *chip;
 	struct iqs620_pwm_private *iqs620_pwm;
 	unsigned int val;
 	int ret;
 
-	iqs620_pwm = devm_kzalloc(&pdev->dev, sizeof(*iqs620_pwm), GFP_KERNEL);
-	if (!iqs620_pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*iqs620_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	iqs620_pwm = iqs620_pwm_from_chip(chip);
 
 	iqs620_pwm->iqs62x = iqs62x;
+	iqs620_pwm->dev = &pdev->dev;
 
 	ret = regmap_read(iqs62x->regmap, IQS620_PWR_SETTINGS, &val);
 	if (ret)
@@ -205,9 +212,7 @@ static int iqs620_pwm_probe(struct platform_device *pdev)
 		iqs620_pwm->duty_scale = val + 1;
 	}
 
-	iqs620_pwm->chip.dev = &pdev->dev;
-	iqs620_pwm->chip.ops = &iqs620_pwm_ops;
-	iqs620_pwm->chip.npwm = 1;
+	chip->ops = &iqs620_pwm_ops;
 
 	mutex_init(&iqs620_pwm->lock);
 
@@ -221,11 +226,11 @@ static int iqs620_pwm_probe(struct platform_device *pdev)
 
 	ret = devm_add_action_or_reset(&pdev->dev,
 				       iqs620_pwm_notifier_unregister,
-				       iqs620_pwm);
+				       chip);
 	if (ret)
 		return ret;
 
-	ret = devm_pwmchip_add(&pdev->dev, &iqs620_pwm->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret)
 		dev_err(&pdev->dev, "Failed to add device: %d\n", ret);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 027/101] pwm: jz4740: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (25 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 026/101] pwm: iqs620a: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 028/101] pwm: keembay: " Uwe Kleine-König
                   ` (75 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-jz4740 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-jz4740.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 881958a79d55..f06010590504 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -25,23 +25,22 @@ struct soc_info {
 };
 
 struct jz4740_pwm_chip {
-	struct pwm_chip chip;
 	struct regmap *map;
 	struct clk *clk[];
 };
 
 static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
 {
-	return container_of(chip, struct jz4740_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
-static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz,
+static bool jz4740_pwm_can_use_chn(struct pwm_chip *chip,
 				   unsigned int channel)
 {
 	/* Enable all TCU channels for PWM use by default except channels 0/1 */
-	u32 pwm_channels_mask = GENMASK(jz->chip.npwm - 1, 2);
+	u32 pwm_channels_mask = GENMASK(chip->npwm - 1, 2);
 
-	device_property_read_u32(jz->chip.dev->parent,
+	device_property_read_u32(chip->dev->parent,
 				 "ingenic,pwm-channels-mask",
 				 &pwm_channels_mask);
 
@@ -55,7 +54,7 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	char name[16];
 	int err;
 
-	if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm))
+	if (!jz4740_pwm_can_use_chn(chip, pwm->hwpwm))
 		return -EBUSY;
 
 	snprintf(name, sizeof(name), "timer%u", pwm->hwpwm);
@@ -223,6 +222,7 @@ static const struct pwm_ops jz4740_pwm_ops = {
 static int jz4740_pwm_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct pwm_chip *chip;
 	struct jz4740_pwm_chip *jz;
 	const struct soc_info *info;
 
@@ -230,10 +230,10 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
 	if (!info)
 		return -EINVAL;
 
-	jz = devm_kzalloc(dev, struct_size(jz, clk, info->num_pwms),
-			  GFP_KERNEL);
-	if (!jz)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, info->num_pwms, struct_size(jz, clk, info->num_pwms));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	jz = to_jz4740(chip);
 
 	jz->map = device_node_to_regmap(dev->parent->of_node);
 	if (IS_ERR(jz->map)) {
@@ -241,11 +241,9 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(jz->map);
 	}
 
-	jz->chip.dev = dev;
-	jz->chip.ops = &jz4740_pwm_ops;
-	jz->chip.npwm = info->num_pwms;
+	chip->ops = &jz4740_pwm_ops;
 
-	return devm_pwmchip_add(dev, &jz->chip);
+	return devm_pwmchip_add(dev, chip);
 }
 
 static const struct soc_info jz4740_soc_info = {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 028/101] pwm: keembay: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (26 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 027/101] pwm: jz4740: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 029/101] pwm: lp3943: " Uwe Kleine-König
                   ` (74 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-keembay driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-keembay.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-keembay.c b/drivers/pwm/pwm-keembay.c
index ac824ecc3f64..2af5e6565705 100644
--- a/drivers/pwm/pwm-keembay.c
+++ b/drivers/pwm/pwm-keembay.c
@@ -36,7 +36,6 @@
 #define KMB_PWM_HIGHLOW_OFFSET(ch)	(0x20 + 4 * (ch))
 
 struct keembay_pwm {
-	struct pwm_chip chip;
 	struct device *dev;
 	struct clk *clk;
 	void __iomem *base;
@@ -44,7 +43,7 @@ struct keembay_pwm {
 
 static inline struct keembay_pwm *to_keembay_pwm_dev(struct pwm_chip *chip)
 {
-	return container_of(chip, struct keembay_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static void keembay_clk_unprepare(void *data)
@@ -185,12 +184,14 @@ static const struct pwm_ops keembay_pwm_ops = {
 static int keembay_pwm_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct pwm_chip *chip;
 	struct keembay_pwm *priv;
 	int ret;
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, KMB_TOTAL_PWM_CHANNELS, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = to_keembay_pwm_dev(chip);
 
 	priv->clk = devm_clk_get(dev, NULL);
 	if (IS_ERR(priv->clk))
@@ -204,11 +205,9 @@ static int keembay_pwm_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	priv->chip.dev = dev;
-	priv->chip.ops = &keembay_pwm_ops;
-	priv->chip.npwm = KMB_TOTAL_PWM_CHANNELS;
+	chip->ops = &keembay_pwm_ops;
 
-	ret = devm_pwmchip_add(dev, &priv->chip);
+	ret = devm_pwmchip_add(dev, chip);
 	if (ret)
 		return dev_err_probe(dev, ret, "Failed to add PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 029/101] pwm: lp3943: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (27 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 028/101] pwm: keembay: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 030/101] pwm: lpc18xx-sct: " Uwe Kleine-König
                   ` (73 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-lp3943 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-lp3943.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c
index 32350a357278..c8d728a6259c 100644
--- a/drivers/pwm/pwm-lp3943.c
+++ b/drivers/pwm/pwm-lp3943.c
@@ -20,7 +20,6 @@
 #define LP3943_MAX_PERIOD		1600000
 
 struct lp3943_pwm {
-	struct pwm_chip chip;
 	struct lp3943 *lp3943;
 	struct lp3943_platform_data *pdata;
 	struct lp3943_pwm_map pwm_map[LP3943_NUM_PWMS];
@@ -28,7 +27,7 @@ struct lp3943_pwm {
 
 static inline struct lp3943_pwm *to_lp3943_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct lp3943_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static struct lp3943_pwm_map *
@@ -273,12 +272,14 @@ static int lp3943_pwm_parse_dt(struct device *dev,
 static int lp3943_pwm_probe(struct platform_device *pdev)
 {
 	struct lp3943 *lp3943 = dev_get_drvdata(pdev->dev.parent);
+	struct pwm_chip *chip;
 	struct lp3943_pwm *lp3943_pwm;
 	int ret;
 
-	lp3943_pwm = devm_kzalloc(&pdev->dev, sizeof(*lp3943_pwm), GFP_KERNEL);
-	if (!lp3943_pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, LP3943_NUM_PWMS, sizeof(*lp3943_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	lp3943_pwm = to_lp3943_pwm(chip);
 
 	lp3943_pwm->pdata = lp3943->pdata;
 	if (!lp3943_pwm->pdata) {
@@ -292,11 +293,9 @@ static int lp3943_pwm_probe(struct platform_device *pdev)
 	}
 
 	lp3943_pwm->lp3943 = lp3943;
-	lp3943_pwm->chip.dev = &pdev->dev;
-	lp3943_pwm->chip.ops = &lp3943_pwm_ops;
-	lp3943_pwm->chip.npwm = LP3943_NUM_PWMS;
+	chip->ops = &lp3943_pwm_ops;
 
-	return devm_pwmchip_add(&pdev->dev, &lp3943_pwm->chip);
+	return devm_pwmchip_add(&pdev->dev, chip);
 }
 
 #ifdef CONFIG_OF
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 030/101] pwm: lpc18xx-sct: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (28 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 029/101] pwm: lp3943: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 031/101] pwm: lpc32xx: " Uwe Kleine-König
                   ` (72 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-lpc18xx-sct driver to further changes of the pwm
core outlined in the commit introducing devm_pwmchip_alloc(). There is
no intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-lpc18xx-sct.c | 25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
index ef7d0da137ed..49eabd9c1e36 100644
--- a/drivers/pwm/pwm-lpc18xx-sct.c
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -93,7 +93,6 @@ struct lpc18xx_pwm_data {
 
 struct lpc18xx_pwm_chip {
 	struct device *dev;
-	struct pwm_chip chip;
 	void __iomem *base;
 	struct clk *pwm_clk;
 	unsigned long clk_rate;
@@ -110,7 +109,7 @@ struct lpc18xx_pwm_chip {
 static inline struct lpc18xx_pwm_chip *
 to_lpc18xx_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct lpc18xx_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline void lpc18xx_pwm_writel(struct lpc18xx_pwm_chip *lpc18xx_pwm,
@@ -351,14 +350,15 @@ MODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match);
 
 static int lpc18xx_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct lpc18xx_pwm_chip *lpc18xx_pwm;
 	int ret;
 	u64 val;
 
-	lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm),
-				   GFP_KERNEL);
-	if (!lpc18xx_pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, LPC18XX_NUM_PWMS, sizeof(*lpc18xx_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
 
 	lpc18xx_pwm->dev = &pdev->dev;
 
@@ -391,9 +391,7 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
 	lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC,
 						  lpc18xx_pwm->clk_rate);
 
-	lpc18xx_pwm->chip.dev = &pdev->dev;
-	lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
-	lpc18xx_pwm->chip.npwm = LPC18XX_NUM_PWMS;
+	chip->ops = &lpc18xx_pwm_ops;
 
 	/* SCT counter must be in unify (32 bit) mode */
 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG,
@@ -425,21 +423,22 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
 	val |= LPC18XX_PWM_PRE(0);
 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val);
 
-	ret = pwmchip_add(&lpc18xx_pwm->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "pwmchip_add failed\n");
 
-	platform_set_drvdata(pdev, lpc18xx_pwm);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 }
 
 static void lpc18xx_pwm_remove(struct platform_device *pdev)
 {
-	struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
 	u32 val;
 
-	pwmchip_remove(&lpc18xx_pwm->chip);
+	pwmchip_remove(chip);
 
 	val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
 	lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL,
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 031/101] pwm: lpc32xx: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (29 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 030/101] pwm: lpc18xx-sct: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 032/101] pwm: lpss-*: " Uwe Kleine-König
                   ` (71 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-lpc32xx driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-lpc32xx.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c
index 78f664e41e6e..2b4186c309a6 100644
--- a/drivers/pwm/pwm-lpc32xx.c
+++ b/drivers/pwm/pwm-lpc32xx.c
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 
 struct lpc32xx_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	void __iomem *base;
 };
@@ -23,8 +22,8 @@ struct lpc32xx_pwm_chip {
 #define PWM_ENABLE	BIT(31)
 #define PWM_PIN_LEVEL	BIT(30)
 
-#define to_lpc32xx_pwm_chip(_chip) \
-	container_of(_chip, struct lpc32xx_pwm_chip, chip)
+#define to_lpc32xx_pwm_chip(chip) \
+	pwmchip_priv(chip)
 
 static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			      int duty_ns, int period_ns)
@@ -119,13 +118,15 @@ static const struct pwm_ops lpc32xx_pwm_ops = {
 
 static int lpc32xx_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct lpc32xx_pwm_chip *lpc32xx;
 	int ret;
 	u32 val;
 
-	lpc32xx = devm_kzalloc(&pdev->dev, sizeof(*lpc32xx), GFP_KERNEL);
-	if (!lpc32xx)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*lpc32xx));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	lpc32xx = to_lpc32xx_pwm_chip(chip);
 
 	lpc32xx->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(lpc32xx->base))
@@ -135,16 +136,14 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(lpc32xx->clk))
 		return PTR_ERR(lpc32xx->clk);
 
-	lpc32xx->chip.dev = &pdev->dev;
-	lpc32xx->chip.ops = &lpc32xx_pwm_ops;
-	lpc32xx->chip.npwm = 1;
+	chip->ops = &lpc32xx_pwm_ops;
 
 	/* If PWM is disabled, configure the output to the default value */
 	val = readl(lpc32xx->base);
 	val &= ~PWM_PIN_LEVEL;
 	writel(val, lpc32xx->base);
 
-	ret = devm_pwmchip_add(&pdev->dev, &lpc32xx->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add PWM chip, error %d\n", ret);
 		return ret;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 032/101] pwm: lpss-*: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (30 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 031/101] pwm: lpc32xx: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 033/101] pwm: mediatek: " Uwe Kleine-König
                   ` (70 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-lpc drivers to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-lpss-pci.c                 | 10 +++++-----
 drivers/pwm/pwm-lpss-platform.c            | 10 +++++-----
 drivers/pwm/pwm-lpss.c                     | 20 ++++++++++----------
 drivers/pwm/pwm-lpss.h                     |  1 -
 include/linux/platform_data/x86/pwm-lpss.h |  4 ++--
 5 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c
index b4134bee2863..abaeac0e3226 100644
--- a/drivers/pwm/pwm-lpss-pci.c
+++ b/drivers/pwm/pwm-lpss-pci.c
@@ -18,7 +18,7 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev,
 			      const struct pci_device_id *id)
 {
 	const struct pwm_lpss_boardinfo *info;
-	struct pwm_lpss_chip *lpwm;
+	struct pwm_chip *chip;
 	int err;
 
 	err = pcim_enable_device(pdev);
@@ -30,11 +30,11 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev,
 		return err;
 
 	info = (struct pwm_lpss_boardinfo *)id->driver_data;
-	lpwm = devm_pwm_lpss_probe(&pdev->dev, pcim_iomap_table(pdev)[0], info);
-	if (IS_ERR(lpwm))
-		return PTR_ERR(lpwm);
+	chip = devm_pwm_lpss_probe(&pdev->dev, pcim_iomap_table(pdev)[0], info);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
-	pci_set_drvdata(pdev, lpwm);
+	pci_set_drvdata(pdev, chip);
 
 	pm_runtime_put(&pdev->dev);
 	pm_runtime_allow(&pdev->dev);
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 319809aac2c4..90aeafa02a3b 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -20,7 +20,7 @@
 static int pwm_lpss_probe_platform(struct platform_device *pdev)
 {
 	const struct pwm_lpss_boardinfo *info;
-	struct pwm_lpss_chip *lpwm;
+	struct pwm_chip *chip;
 	void __iomem *base;
 
 	info = device_get_match_data(&pdev->dev);
@@ -31,11 +31,11 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
-	lpwm = devm_pwm_lpss_probe(&pdev->dev, base, info);
-	if (IS_ERR(lpwm))
-		return PTR_ERR(lpwm);
+	chip = devm_pwm_lpss_probe(&pdev->dev, base, info);
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
-	platform_set_drvdata(pdev, lpwm);
+	platform_set_drvdata(pdev, chip);
 
 	/*
 	 * On Cherry Trail devices the GFX0._PS0 AML checks if the controller
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index a6ea3ce7e019..13087203d05a 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(pwm_lpss_tng_info);
 
 static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct pwm_lpss_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline u32 pwm_lpss_read(const struct pwm_device *pwm)
@@ -245,9 +245,10 @@ static const struct pwm_ops pwm_lpss_ops = {
 	.get_state = pwm_lpss_get_state,
 };
 
-struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
+struct pwm_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
 					  const struct pwm_lpss_boardinfo *info)
 {
+	struct pwm_chip *chip;
 	struct pwm_lpss_chip *lpwm;
 	unsigned long c;
 	int i, ret;
@@ -256,9 +257,10 @@ struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base
 	if (WARN_ON(info->npwm > LPSS_MAX_PWMS))
 		return ERR_PTR(-ENODEV);
 
-	lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL);
-	if (!lpwm)
+	chip = devm_pwmchip_alloc(dev, info->npwm, sizeof(*lpwm));
+	if (!chip)
 		return ERR_PTR(-ENOMEM);
+	lpwm = to_lpwm(chip);
 
 	lpwm->regs = base;
 	lpwm->info = info;
@@ -267,23 +269,21 @@ struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base
 	if (!c)
 		return ERR_PTR(-EINVAL);
 
-	lpwm->chip.dev = dev;
-	lpwm->chip.ops = &pwm_lpss_ops;
-	lpwm->chip.npwm = info->npwm;
+	chip->ops = &pwm_lpss_ops;
 
-	ret = devm_pwmchip_add(dev, &lpwm->chip);
+	ret = devm_pwmchip_add(dev, chip);
 	if (ret) {
 		dev_err(dev, "failed to add PWM chip: %d\n", ret);
 		return ERR_PTR(ret);
 	}
 
 	for (i = 0; i < lpwm->info->npwm; i++) {
-		ctrl = pwm_lpss_read(&lpwm->chip.pwms[i]);
+		ctrl = pwm_lpss_read(&chip->pwms[i]);
 		if (ctrl & PWM_ENABLE)
 			pm_runtime_get(dev);
 	}
 
-	return lpwm;
+	return chip;
 }
 EXPORT_SYMBOL_GPL(devm_pwm_lpss_probe);
 
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index bf841250385f..b5267ab5193b 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -18,7 +18,6 @@
 #define LPSS_MAX_PWMS			4
 
 struct pwm_lpss_chip {
-	struct pwm_chip chip;
 	void __iomem *regs;
 	const struct pwm_lpss_boardinfo *info;
 };
diff --git a/include/linux/platform_data/x86/pwm-lpss.h b/include/linux/platform_data/x86/pwm-lpss.h
index c852fe24fe2a..752c06b47cc8 100644
--- a/include/linux/platform_data/x86/pwm-lpss.h
+++ b/include/linux/platform_data/x86/pwm-lpss.h
@@ -27,7 +27,7 @@ struct pwm_lpss_boardinfo {
 	bool other_devices_aml_touches_pwm_regs;
 };
 
-struct pwm_lpss_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
-					  const struct pwm_lpss_boardinfo *info);
+struct pwm_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
+				     const struct pwm_lpss_boardinfo *info);
 
 #endif	/* __PLATFORM_DATA_X86_PWM_LPSS_H */
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 033/101] pwm: mediatek: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (31 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 032/101] pwm: lpss-*: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 034/101] pwm: meson: " Uwe Kleine-König
                   ` (69 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-mediatek driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-mediatek.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index 373abfd25acb..68cdeeb1ecf2 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -51,7 +51,6 @@ struct pwm_mediatek_of_data {
  * @soc: pointer to chip's platform data
  */
 struct pwm_mediatek_chip {
-	struct pwm_chip chip;
 	void __iomem *regs;
 	struct clk *clk_top;
 	struct clk *clk_main;
@@ -70,7 +69,7 @@ static const unsigned int mtk_pwm_reg_offset_v2[] = {
 static inline struct pwm_mediatek_chip *
 to_pwm_mediatek_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct pwm_mediatek_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int pwm_mediatek_clk_enable(struct pwm_chip *chip,
@@ -233,21 +232,26 @@ static const struct pwm_ops pwm_mediatek_ops = {
 
 static int pwm_mediatek_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct pwm_mediatek_chip *pc;
+	const struct pwm_mediatek_of_data *soc;
 	unsigned int i;
 	int ret;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	soc = of_device_get_match_data(&pdev->dev);
 
-	pc->soc = of_device_get_match_data(&pdev->dev);
+	chip = devm_pwmchip_alloc(&pdev->dev, soc->num_pwms, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_pwm_mediatek_chip(chip);
+
+	pc->soc = soc;
 
 	pc->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(pc->regs))
 		return PTR_ERR(pc->regs);
 
-	pc->clk_pwms = devm_kmalloc_array(&pdev->dev, pc->soc->num_pwms,
+	pc->clk_pwms = devm_kmalloc_array(&pdev->dev, soc->num_pwms,
 				    sizeof(*pc->clk_pwms), GFP_KERNEL);
 	if (!pc->clk_pwms)
 		return -ENOMEM;
@@ -262,7 +266,7 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk_main),
 				     "Failed to get main clock\n");
 
-	for (i = 0; i < pc->soc->num_pwms; i++) {
+	for (i = 0; i < soc->num_pwms; i++) {
 		char name[8];
 
 		snprintf(name, sizeof(name), "pwm%d", i + 1);
@@ -273,11 +277,9 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
 					     "Failed to get %s clock\n", name);
 	}
 
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &pwm_mediatek_ops;
-	pc->chip.npwm = pc->soc->num_pwms;
+	chip->ops = &pwm_mediatek_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 034/101] pwm: meson: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (32 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 033/101] pwm: mediatek: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 035/101] pwm: microchip-core: " Uwe Kleine-König
                   ` (68 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-meson driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-meson.c | 55 ++++++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 26 deletions(-)

diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 5bea53243ed2..3b6a8c9466a2 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -102,7 +102,6 @@ struct meson_pwm_data {
 };
 
 struct meson_pwm {
-	struct pwm_chip chip;
 	const struct meson_pwm_data *data;
 	struct meson_pwm_channel channels[MESON_NUM_PWMS];
 	void __iomem *base;
@@ -115,7 +114,7 @@ struct meson_pwm {
 
 static inline struct meson_pwm *to_meson_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct meson_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -143,9 +142,10 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 	clk_disable_unprepare(channel->clk);
 }
 
-static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,
 			  const struct pwm_state *state)
 {
+	struct meson_pwm *meson = to_meson_pwm(chip);
 	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
 	unsigned int cnt, duty_cnt;
 	unsigned long fin_freq;
@@ -169,19 +169,19 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
 
 	fin_freq = clk_round_rate(channel->clk, freq);
 	if (fin_freq == 0) {
-		dev_err(meson->chip.dev, "invalid source clock frequency\n");
+		dev_err(chip->dev, "invalid source clock frequency\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
+	dev_dbg(chip->dev, "fin_freq: %lu Hz\n", fin_freq);
 
 	cnt = div_u64(fin_freq * period, NSEC_PER_SEC);
 	if (cnt > 0xffff) {
-		dev_err(meson->chip.dev, "unable to get period cnt\n");
+		dev_err(chip->dev, "unable to get period cnt\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(meson->chip.dev, "period=%llu cnt=%u\n", period, cnt);
+	dev_dbg(chip->dev, "period=%llu cnt=%u\n", period, cnt);
 
 	if (duty == period) {
 		channel->hi = cnt;
@@ -192,7 +192,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
 	} else {
 		duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC);
 
-		dev_dbg(meson->chip.dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
+		dev_dbg(chip->dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
 
 		channel->hi = duty_cnt;
 		channel->lo = cnt - duty_cnt;
@@ -203,8 +203,9 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
 	return 0;
 }
 
-static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
+static void meson_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+	struct meson_pwm *meson = to_meson_pwm(chip);
 	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
 	struct meson_pwm_channel_data *channel_data;
 	unsigned long flags;
@@ -215,7 +216,7 @@ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
 
 	err = clk_set_rate(channel->clk, channel->rate);
 	if (err)
-		dev_err(meson->chip.dev, "setting clock rate failed\n");
+		dev_err(chip->dev, "setting clock rate failed\n");
 
 	spin_lock_irqsave(&meson->lock, flags);
 
@@ -230,8 +231,9 @@ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
 	spin_unlock_irqrestore(&meson->lock, flags);
 }
 
-static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm)
+static void meson_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+	struct meson_pwm *meson = to_meson_pwm(chip);
 	unsigned long flags;
 	u32 value;
 
@@ -269,16 +271,16 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 			channel->hi = ~0;
 			channel->lo = 0;
 
-			meson_pwm_enable(meson, pwm);
+			meson_pwm_enable(chip, pwm);
 		} else {
-			meson_pwm_disable(meson, pwm);
+			meson_pwm_disable(chip, pwm);
 		}
 	} else {
-		err = meson_pwm_calc(meson, pwm, state);
+		err = meson_pwm_calc(chip, pwm, state);
 		if (err < 0)
 			return err;
 
-		meson_pwm_enable(meson, pwm);
+		meson_pwm_enable(chip, pwm);
 	}
 
 	return 0;
@@ -432,10 +434,11 @@ static const struct of_device_id meson_pwm_matches[] = {
 };
 MODULE_DEVICE_TABLE(of, meson_pwm_matches);
 
-static int meson_pwm_init_channels(struct meson_pwm *meson)
+static int meson_pwm_init_channels(struct pwm_chip *chip)
 {
+	struct meson_pwm *meson = to_meson_pwm(chip);
 	struct clk_parent_data mux_parent_data[MESON_MAX_MUX_PARENTS] = {};
-	struct device *dev = meson->chip.dev;
+	struct device *dev = chip->dev;
 	unsigned int i;
 	char name[255];
 	int err;
@@ -445,7 +448,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
 		mux_parent_data[i].name = meson->data->parent_names[i];
 	}
 
-	for (i = 0; i < meson->chip.npwm; i++) {
+	for (i = 0; i < chip->npwm; i++) {
 		struct meson_pwm_channel *channel = &meson->channels[i];
 		struct clk_parent_data div_parent = {}, gate_parent = {};
 		struct clk_init_data init = {};
@@ -531,29 +534,29 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
 
 static int meson_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct meson_pwm *meson;
 	int err;
 
-	meson = devm_kzalloc(&pdev->dev, sizeof(*meson), GFP_KERNEL);
-	if (!meson)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, MESON_NUM_PWMS, sizeof(*meson));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	meson = to_meson_pwm(chip);
 
 	meson->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(meson->base))
 		return PTR_ERR(meson->base);
 
 	spin_lock_init(&meson->lock);
-	meson->chip.dev = &pdev->dev;
-	meson->chip.ops = &meson_pwm_ops;
-	meson->chip.npwm = MESON_NUM_PWMS;
+	chip->ops = &meson_pwm_ops;
 
 	meson->data = of_device_get_match_data(&pdev->dev);
 
-	err = meson_pwm_init_channels(meson);
+	err = meson_pwm_init_channels(chip);
 	if (err < 0)
 		return err;
 
-	err = devm_pwmchip_add(&pdev->dev, &meson->chip);
+	err = devm_pwmchip_add(&pdev->dev, chip);
 	if (err < 0) {
 		dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
 		return err;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 035/101] pwm: microchip-core: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (33 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 034/101] pwm: meson: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 036/101] pwm: mtk-disp: " Uwe Kleine-König
                   ` (67 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-microchip-core driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-microchip-core.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-microchip-core.c b/drivers/pwm/pwm-microchip-core.c
index c0c53968f3e9..6e0c2cbfc120 100644
--- a/drivers/pwm/pwm-microchip-core.c
+++ b/drivers/pwm/pwm-microchip-core.c
@@ -54,7 +54,6 @@
 #define MCHPCOREPWM_TIMEOUT_MS	100u
 
 struct mchp_core_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	void __iomem *base;
 	struct mutex lock; /* protects the shared period */
@@ -65,7 +64,7 @@ struct mchp_core_pwm_chip {
 
 static inline struct mchp_core_pwm_chip *to_mchp_core_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct mchp_core_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static void mchp_core_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -447,13 +446,15 @@ MODULE_DEVICE_TABLE(of, mchp_core_of_match);
 
 static int mchp_core_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct mchp_core_pwm_chip *mchp_core_pwm;
 	struct resource *regs;
 	int ret;
 
-	mchp_core_pwm = devm_kzalloc(&pdev->dev, sizeof(*mchp_core_pwm), GFP_KERNEL);
-	if (!mchp_core_pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 16, sizeof(*mchp_core_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	mchp_core_pwm = to_mchp_core_pwm(chip);
 
 	mchp_core_pwm->base = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
 	if (IS_ERR(mchp_core_pwm->base))
@@ -470,9 +471,7 @@ static int mchp_core_pwm_probe(struct platform_device *pdev)
 
 	mutex_init(&mchp_core_pwm->lock);
 
-	mchp_core_pwm->chip.dev = &pdev->dev;
-	mchp_core_pwm->chip.ops = &mchp_core_pwm_ops;
-	mchp_core_pwm->chip.npwm = 16;
+	chip->ops = &mchp_core_pwm_ops;
 
 	mchp_core_pwm->channel_enabled = readb_relaxed(mchp_core_pwm->base + MCHPCOREPWM_EN(0));
 	mchp_core_pwm->channel_enabled |=
@@ -485,7 +484,7 @@ static int mchp_core_pwm_probe(struct platform_device *pdev)
 	writel_relaxed(1U, mchp_core_pwm->base + MCHPCOREPWM_SYNC_UPD);
 	mchp_core_pwm->update_timestamp = ktime_get();
 
-	ret = devm_pwmchip_add(&pdev->dev, &mchp_core_pwm->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "Failed to add pwmchip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 036/101] pwm: mtk-disp: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (34 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 035/101] pwm: microchip-core: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 037/101] pwm: mxs: " Uwe Kleine-König
                   ` (66 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-mtk-disp driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-mtk-disp.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index a72f7be36996..0c4f88145dc6 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -42,7 +42,6 @@ struct mtk_pwm_data {
 };
 
 struct mtk_disp_pwm {
-	struct pwm_chip chip;
 	const struct mtk_pwm_data *data;
 	struct clk *clk_main;
 	struct clk *clk_mm;
@@ -52,7 +51,7 @@ struct mtk_disp_pwm {
 
 static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct mtk_disp_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
@@ -231,12 +230,14 @@ static const struct pwm_ops mtk_disp_pwm_ops = {
 
 static int mtk_disp_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct mtk_disp_pwm *mdp;
 	int ret;
 
-	mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL);
-	if (!mdp)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*mdp));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	mdp = to_mtk_disp_pwm(chip);
 
 	mdp->data = of_device_get_match_data(&pdev->dev);
 
@@ -254,11 +255,9 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(mdp->clk_mm),
 				     "Failed to get mm clock\n");
 
-	mdp->chip.dev = &pdev->dev;
-	mdp->chip.ops = &mtk_disp_pwm_ops;
-	mdp->chip.npwm = 1;
+	chip->ops = &mtk_disp_pwm_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &mdp->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 037/101] pwm: mxs: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (35 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 036/101] pwm: mtk-disp: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 038/101] pwm: ntxec: " Uwe Kleine-König
                   ` (65 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-mxs driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-mxs.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 1b5e787d78f1..7c05b22bc7c9 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -37,12 +37,14 @@ static const u8 cdiv_shift[PERIOD_CDIV_MAX] = {
 };
 
 struct mxs_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	void __iomem *base;
 };
 
-#define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip)
+static inline struct mxs_pwm_chip *to_mxs_pwm_chip(struct pwm_chip *chip)
+{
+	return pwmchip_priv(chip);
+}
 
 static int mxs_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 			 const struct pwm_state *state)
@@ -120,12 +122,21 @@ static const struct pwm_ops mxs_pwm_ops = {
 static int mxs_pwm_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pwm_chip *chip;
 	struct mxs_pwm_chip *mxs;
+	u32 npwm;
 	int ret;
 
-	mxs = devm_kzalloc(&pdev->dev, sizeof(*mxs), GFP_KERNEL);
-	if (!mxs)
-		return -ENOMEM;
+	ret = of_property_read_u32(np, "fsl,pwm-number", &npwm);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret);
+		return ret;
+	}
+
+	chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*mxs));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	mxs = to_mxs_pwm_chip(chip);
 
 	mxs->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(mxs->base))
@@ -135,21 +146,14 @@ static int mxs_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(mxs->clk))
 		return PTR_ERR(mxs->clk);
 
-	mxs->chip.dev = &pdev->dev;
-	mxs->chip.ops = &mxs_pwm_ops;
-
-	ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to get pwm number: %d\n", ret);
-		return ret;
-	}
+	chip->ops = &mxs_pwm_ops;
 
 	/* FIXME: Only do this if the PWM isn't already running */
 	ret = stmp_reset_block(mxs->base);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "failed to reset PWM\n");
 
-	ret = devm_pwmchip_add(&pdev->dev, &mxs->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add pwm chip %d\n", ret);
 		return ret;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 038/101] pwm: ntxec: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (36 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 037/101] pwm: mxs: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 039/101] pwm: omap-dmtimer: " Uwe Kleine-König
                   ` (64 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-ntxec driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-ntxec.c | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/drivers/pwm/pwm-ntxec.c b/drivers/pwm/pwm-ntxec.c
index 78606039eda2..0c54dc0d1e9c 100644
--- a/drivers/pwm/pwm-ntxec.c
+++ b/drivers/pwm/pwm-ntxec.c
@@ -25,12 +25,11 @@
 
 struct ntxec_pwm {
 	struct ntxec *ec;
-	struct pwm_chip chip;
 };
 
 static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct ntxec_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 #define NTXEC_REG_AUTO_OFF_HI	0xa1
@@ -57,7 +56,7 @@ static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip)
 static int ntxec_pwm_set_raw_period_and_duty_cycle(struct pwm_chip *chip,
 						   int period, int duty)
 {
-	struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
+	struct ntxec *ec = ntxec_pwm_from_chip(chip)->ec;
 
 	/*
 	 * Changes to the period and duty cycle take effect as soon as the
@@ -77,13 +76,13 @@ static int ntxec_pwm_set_raw_period_and_duty_cycle(struct pwm_chip *chip,
 		{ NTXEC_REG_DUTY_LOW, ntxec_reg8(duty) },
 	};
 
-	return regmap_multi_reg_write(priv->ec->regmap, regs, ARRAY_SIZE(regs));
+	return regmap_multi_reg_write(ec->regmap, regs, ARRAY_SIZE(regs));
 }
 
 static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev,
 			   const struct pwm_state *state)
 {
-	struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
+	struct ntxec *ec = ntxec_pwm_from_chip(chip)->ec;
 	unsigned int period, duty;
 	int res;
 
@@ -110,18 +109,18 @@ static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev,
 		if (res)
 			return res;
 
-		res = regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(1));
+		res = regmap_write(ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(1));
 		if (res)
 			return res;
 
 		/* Disable the auto-off timer */
-		res = regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_HI, ntxec_reg8(0xff));
+		res = regmap_write(ec->regmap, NTXEC_REG_AUTO_OFF_HI, ntxec_reg8(0xff));
 		if (res)
 			return res;
 
-		return regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_LO, ntxec_reg8(0xff));
+		return regmap_write(ec->regmap, NTXEC_REG_AUTO_OFF_LO, ntxec_reg8(0xff));
 	} else {
-		return regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(0));
+		return regmap_write(ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(0));
 	}
 }
 
@@ -135,22 +134,19 @@ static const struct pwm_ops ntxec_pwm_ops = {
 
 static int ntxec_pwm_probe(struct platform_device *pdev)
 {
-	struct ntxec *ec = dev_get_drvdata(pdev->dev.parent);
 	struct ntxec_pwm *priv;
 	struct pwm_chip *chip;
 
 	device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = ntxec_pwm_from_chip(chip);
 
-	priv->ec = ec;
+	priv->ec = dev_get_drvdata(pdev->dev.parent);
 
-	chip = &priv->chip;
-	chip->dev = &pdev->dev;
 	chip->ops = &ntxec_pwm_ops;
-	chip->npwm = 1;
 
 	return devm_pwmchip_add(&pdev->dev, chip);
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 039/101] pwm: omap-dmtimer: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (37 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 038/101] pwm: ntxec: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 040/101] pwm: pca9685: " Uwe Kleine-König
                   ` (63 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-omap-dmtimer driver to further changes of the pwm
core outlined in the commit introducing devm_pwmchip_alloc(). There is
no intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-omap-dmtimer.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index 40a46138ebbb..c8d2db240b9e 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -61,7 +61,6 @@
  * @dm_timer_pdev:	Pointer to omap dm timer platform device
  */
 struct pwm_omap_dmtimer_chip {
-	struct pwm_chip chip;
 	/* Mutex to protect pwm apply state */
 	struct mutex mutex;
 	struct omap_dm_timer *dm_timer;
@@ -72,7 +71,7 @@ struct pwm_omap_dmtimer_chip {
 static inline struct pwm_omap_dmtimer_chip *
 to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 /**
@@ -319,6 +318,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	struct dmtimer_platform_data *timer_pdata;
 	const struct omap_dm_timer_ops *pdata;
 	struct platform_device *timer_pdev;
+	struct pwm_chip *chip;
 	struct pwm_omap_dmtimer_chip *omap;
 	struct omap_dm_timer *dm_timer;
 	struct device_node *timer;
@@ -376,11 +376,12 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 		goto err_request_timer;
 	}
 
-	omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
-	if (!omap) {
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*omap));
+	if (!chip) {
 		ret = -ENOMEM;
 		goto err_alloc_omap;
 	}
+	omap = to_pwm_omap_dmtimer_chip(chip);
 
 	omap->pdata = pdata;
 	omap->dm_timer = dm_timer;
@@ -400,13 +401,11 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v))
 		omap->pdata->set_source(omap->dm_timer, v);
 
-	omap->chip.dev = &pdev->dev;
-	omap->chip.ops = &pwm_omap_dmtimer_ops;
-	omap->chip.npwm = 1;
+	chip->ops = &pwm_omap_dmtimer_ops;
 
 	mutex_init(&omap->mutex);
 
-	ret = pwmchip_add(&omap->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register PWM\n");
 		goto err_pwmchip_add;
@@ -414,14 +413,14 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 
 	of_node_put(timer);
 
-	platform_set_drvdata(pdev, omap);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 
 err_pwmchip_add:
 
 	/*
-	 * *omap is allocated using devm_kzalloc,
+	 * *omap is allocated using devm_pwmchip_alloc,
 	 * so no free necessary here
 	 */
 err_alloc_omap:
@@ -442,9 +441,10 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 
 static void pwm_omap_dmtimer_remove(struct platform_device *pdev)
 {
-	struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
 
-	pwmchip_remove(&omap->chip);
+	pwmchip_remove(chip);
 
 	if (pm_runtime_active(&omap->dm_timer_pdev->dev))
 		omap->pdata->stop(omap->dm_timer);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 040/101] pwm: pca9685: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (38 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 039/101] pwm: omap-dmtimer: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 041/101] pwm: pxa: " Uwe Kleine-König
                   ` (62 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-pca9685 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-pca9685.c | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 9d4e7915c1e9..0d32b4bb51d8 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -76,7 +76,7 @@
 #define REG_OFF_L(C)	((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : LED_N_OFF_L((C)))
 
 struct pca9685 {
-	struct pwm_chip chip;
+	struct pwm_chip *chip;
 	struct regmap *regmap;
 	struct mutex lock;
 	DECLARE_BITMAP(pwms_enabled, PCA9685_MAXCHAN + 1);
@@ -88,7 +88,7 @@ struct pca9685 {
 
 static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 {
-	return container_of(chip, struct pca9685, chip);
+	return pwmchip_priv(chip);
 }
 
 /* This function is supposed to be called with the lock mutex held */
@@ -120,7 +120,7 @@ static int pca9685_write_reg(struct pca9685 *pca, unsigned int reg, unsigned int
 /* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */
 static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned int duty)
 {
-	struct pwm_device *pwm = &pca->chip.pwms[channel];
+	struct pwm_device *pwm = &pca->chip->pwms[channel];
 	unsigned int on, off;
 
 	if (duty == 0) {
@@ -159,7 +159,7 @@ static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned int
 
 static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
 {
-	struct pwm_device *pwm = &pca->chip.pwms[channel];
+	struct pwm_device *pwm = &pca->chip->pwms[channel];
 	unsigned int off = 0, on = 0, val = 0;
 
 	if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
@@ -237,7 +237,7 @@ static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
 
 	if (pca9685_pwm_test_and_set_inuse(pca, offset))
 		return -EBUSY;
-	pm_runtime_get_sync(pca->chip.dev);
+	pm_runtime_get_sync(pca->chip->dev);
 	return 0;
 }
 
@@ -261,7 +261,7 @@ static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
 	struct pca9685 *pca = gpiochip_get_data(gpio);
 
 	pca9685_pwm_set_duty(pca, offset, 0);
-	pm_runtime_put(pca->chip.dev);
+	pm_runtime_put(pca->chip->dev);
 	pca9685_pwm_clear_inuse(pca, offset);
 }
 
@@ -294,7 +294,7 @@ static int pca9685_pwm_gpio_direction_output(struct gpio_chip *gpio,
  */
 static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
-	struct device *dev = pca->chip.dev;
+	struct device *dev = pca->chip->dev;
 
 	pca->gpio.label = dev_name(dev);
 	pca->gpio.parent = dev;
@@ -331,7 +331,7 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 
 static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
 {
-	struct device *dev = pca->chip.dev;
+	struct device *dev = pca->chip->dev;
 	int err = regmap_update_bits(pca->regmap, PCA9685_MODE1,
 				     MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
 	if (err) {
@@ -497,13 +497,17 @@ static const struct regmap_config pca9685_regmap_i2c_config = {
 
 static int pca9685_pwm_probe(struct i2c_client *client)
 {
+	struct pwm_chip *chip;
 	struct pca9685 *pca;
 	unsigned int reg;
 	int ret;
 
-	pca = devm_kzalloc(&client->dev, sizeof(*pca), GFP_KERNEL);
-	if (!pca)
-		return -ENOMEM;
+	/* Add an extra channel for ALL_LED */
+	chip = devm_pwmchip_alloc(&client->dev, PCA9685_MAXCHAN + 1, sizeof(*pca));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pca = to_pca(chip);
+	pca->chip = chip;
 
 	pca->regmap = devm_regmap_init_i2c(client, &pca9685_regmap_i2c_config);
 	if (IS_ERR(pca->regmap)) {
@@ -546,19 +550,15 @@ static int pca9685_pwm_probe(struct i2c_client *client)
 	pca9685_write_reg(pca, PCA9685_ALL_LED_ON_L, 0);
 	pca9685_write_reg(pca, PCA9685_ALL_LED_ON_H, LED_FULL);
 
-	pca->chip.ops = &pca9685_pwm_ops;
-	/* Add an extra channel for ALL_LED */
-	pca->chip.npwm = PCA9685_MAXCHAN + 1;
+	chip->ops = &pca9685_pwm_ops;
 
-	pca->chip.dev = &client->dev;
-
-	ret = pwmchip_add(&pca->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0)
 		return ret;
 
 	ret = pca9685_pwm_gpio_probe(pca);
 	if (ret < 0) {
-		pwmchip_remove(&pca->chip);
+		pwmchip_remove(chip);
 		return ret;
 	}
 
@@ -583,7 +583,7 @@ static void pca9685_pwm_remove(struct i2c_client *client)
 {
 	struct pca9685 *pca = i2c_get_clientdata(client);
 
-	pwmchip_remove(&pca->chip);
+	pwmchip_remove(pca->chip);
 
 	if (!pm_runtime_enabled(&client->dev)) {
 		/* Put chip in sleep state if runtime PM is disabled */
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 041/101] pwm: pxa: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (39 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 040/101] pwm: pca9685: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 042/101] pwm: raspberrypi-poe: " Uwe Kleine-König
                   ` (61 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-pxa driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-pxa.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index faf6b35b9336..afdcaadce0b8 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(platform, pwm_id_table);
 #define PWMDCR_FD	(1 << 10)
 
 struct pxa_pwm_chip {
-	struct pwm_chip	chip;
 	struct device	*dev;
 
 	struct clk	*clk;
@@ -58,7 +57,7 @@ struct pxa_pwm_chip {
 
 static inline struct pxa_pwm_chip *to_pxa_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct pxa_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 /*
@@ -159,6 +158,7 @@ MODULE_DEVICE_TABLE(of, pwm_of_match);
 static int pwm_probe(struct platform_device *pdev)
 {
 	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct pwm_chip *chip;
 	struct pxa_pwm_chip *pc;
 	int ret = 0;
 
@@ -168,28 +168,29 @@ static int pwm_probe(struct platform_device *pdev)
 	if (id == NULL)
 		return -EINVAL;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (pc == NULL)
+	chip = devm_pwmchip_alloc(&pdev->dev,
+				  (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1,
+				  sizeof(*pc));
+	if (chip == NULL)
 		return -ENOMEM;
+	pc = to_pxa_pwm_chip(chip);
 
 	pc->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(pc->clk))
 		return PTR_ERR(pc->clk);
 
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &pxa_pwm_ops;
-	pc->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
+	chip->ops = &pxa_pwm_ops;
 
 	if (IS_ENABLED(CONFIG_OF)) {
-		pc->chip.of_xlate = of_pwm_single_xlate;
-		pc->chip.of_pwm_n_cells = 1;
+		chip->of_xlate = of_pwm_single_xlate;
+		chip->of_pwm_n_cells = 1;
 	}
 
 	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(pc->mmio_base))
 		return PTR_ERR(pc->mmio_base);
 
-	ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 		return ret;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 042/101] pwm: raspberrypi-poe: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (40 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 041/101] pwm: pxa: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 043/101] pwm: rcar: " Uwe Kleine-König
                   ` (60 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-raspberrypi-poe driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-raspberrypi-poe.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c
index 1ad814fdec6b..4b2711d59e7c 100644
--- a/drivers/pwm/pwm-raspberrypi-poe.c
+++ b/drivers/pwm/pwm-raspberrypi-poe.c
@@ -27,7 +27,6 @@
 
 struct raspberrypi_pwm {
 	struct rpi_firmware *firmware;
-	struct pwm_chip chip;
 	unsigned int duty_cycle;
 };
 
@@ -40,7 +39,7 @@ struct raspberrypi_pwm_prop {
 static inline
 struct raspberrypi_pwm *raspberrypi_pwm_from_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct raspberrypi_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware,
@@ -142,6 +141,7 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
 	struct device_node *firmware_node;
 	struct device *dev = &pdev->dev;
 	struct rpi_firmware *firmware;
+	struct pwm_chip *chip;
 	struct raspberrypi_pwm *rpipwm;
 	int ret;
 
@@ -157,14 +157,14 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, -EPROBE_DEFER,
 				     "Failed to get firmware handle\n");
 
-	rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL);
-	if (!rpipwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, RASPBERRYPI_FIRMWARE_PWM_NUM,
+				  sizeof(*rpipwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	rpipwm = raspberrypi_pwm_from_chip(chip);
 
 	rpipwm->firmware = firmware;
-	rpipwm->chip.dev = dev;
-	rpipwm->chip.ops = &raspberrypi_pwm_ops;
-	rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM;
+	chip->ops = &raspberrypi_pwm_ops;
 
 	ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG,
 					   &rpipwm->duty_cycle);
@@ -173,7 +173,7 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	return devm_pwmchip_add(dev, &rpipwm->chip);
+	return devm_pwmchip_add(dev, chip);
 }
 
 static const struct of_device_id raspberrypi_pwm_of_match[] = {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 043/101] pwm: rcar: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (41 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 042/101] pwm: raspberrypi-poe: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 044/101] pwm: renesas-tpu: " Uwe Kleine-König
                   ` (59 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-rcar driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rcar.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 13269f55fccf..5bb7b579705d 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -38,14 +38,13 @@
 #define  RCAR_PWMCNT_PH0_SHIFT	0
 
 struct rcar_pwm_chip {
-	struct pwm_chip chip;
 	void __iomem *base;
 	struct clk *clk;
 };
 
 static inline struct rcar_pwm_chip *to_rcar_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct rcar_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static void rcar_pwm_write(struct rcar_pwm_chip *rp, u32 data,
@@ -202,12 +201,14 @@ static const struct pwm_ops rcar_pwm_ops = {
 
 static int rcar_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct rcar_pwm_chip *rcar_pwm;
 	int ret;
 
-	rcar_pwm = devm_kzalloc(&pdev->dev, sizeof(*rcar_pwm), GFP_KERNEL);
-	if (rcar_pwm == NULL)
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*rcar_pwm));
+	if (chip == NULL)
 		return -ENOMEM;
+	rcar_pwm = to_rcar_pwm_chip(chip);
 
 	rcar_pwm->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(rcar_pwm->base))
@@ -219,15 +220,13 @@ static int rcar_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(rcar_pwm->clk);
 	}
 
-	platform_set_drvdata(pdev, rcar_pwm);
+	platform_set_drvdata(pdev, chip);
 
-	rcar_pwm->chip.dev = &pdev->dev;
-	rcar_pwm->chip.ops = &rcar_pwm_ops;
-	rcar_pwm->chip.npwm = 1;
+	chip->ops = &rcar_pwm_ops;
 
 	pm_runtime_enable(&pdev->dev);
 
-	ret = pwmchip_add(&rcar_pwm->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret);
 		pm_runtime_disable(&pdev->dev);
@@ -239,9 +238,9 @@ static int rcar_pwm_probe(struct platform_device *pdev)
 
 static void rcar_pwm_remove(struct platform_device *pdev)
 {
-	struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
 
-	pwmchip_remove(&rcar_pwm->chip);
+	pwmchip_remove(chip);
 
 	pm_runtime_disable(&pdev->dev);
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 044/101] pwm: renesas-tpu: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (42 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 043/101] pwm: rcar: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 045/101] pwm: rockchip: " Uwe Kleine-König
                   ` (58 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-renesas-tpu driver to further changes of the pwm
core outlined in the commit introducing devm_pwmchip_alloc(). There is
no intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-renesas-tpu.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
index 4239f2c3e8b2..2f6b2351619b 100644
--- a/drivers/pwm/pwm-renesas-tpu.c
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -80,7 +80,6 @@ struct tpu_pwm_device {
 
 struct tpu_device {
 	struct platform_device *pdev;
-	struct pwm_chip chip;
 	spinlock_t lock;
 
 	void __iomem *base;
@@ -88,7 +87,10 @@ struct tpu_device {
 	struct tpu_pwm_device tpd[TPU_CHANNEL_MAX];
 };
 
-#define to_tpu_device(c)	container_of(c, struct tpu_device, chip)
+static inline struct tpu_device *to_tpu_device(struct pwm_chip *chip)
+{
+	return pwmchip_priv(chip);
+}
 
 static void tpu_pwm_write(struct tpu_pwm_device *tpd, int reg_nr, u16 value)
 {
@@ -439,12 +441,14 @@ static const struct pwm_ops tpu_pwm_ops = {
 
 static int tpu_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct tpu_device *tpu;
 	int ret;
 
-	tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
-	if (tpu == NULL)
+	chip = devm_pwmchip_alloc(&pdev->dev, TPU_CHANNEL_MAX, sizeof(*tpu));
+	if (chip == NULL)
 		return -ENOMEM;
+	tpu = to_tpu_device(chip);
 
 	spin_lock_init(&tpu->lock);
 	tpu->pdev = pdev;
@@ -461,15 +465,13 @@ static int tpu_probe(struct platform_device *pdev)
 	/* Initialize and register the device. */
 	platform_set_drvdata(pdev, tpu);
 
-	tpu->chip.dev = &pdev->dev;
-	tpu->chip.ops = &tpu_pwm_ops;
-	tpu->chip.npwm = TPU_CHANNEL_MAX;
+	chip->ops = &tpu_pwm_ops;
 
 	ret = devm_pm_runtime_enable(&pdev->dev);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "Failed to enable runtime PM\n");
 
-	ret = devm_pwmchip_add(&pdev->dev, &tpu->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "Failed to register PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 045/101] pwm: rockchip: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (43 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 044/101] pwm: renesas-tpu: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 046/101] pwm: rz-mtu3: " Uwe Kleine-König
                   ` (57 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-rockchip driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rockchip.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index cce4381e188a..18fb092f4bec 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -30,7 +30,6 @@
 #define PWM_LP_DISABLE		(0 << 8)
 
 struct rockchip_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *clk;
 	struct clk *pclk;
 	const struct rockchip_pwm_data *data;
@@ -54,7 +53,7 @@ struct rockchip_pwm_data {
 
 static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct rockchip_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int rockchip_pwm_get_state(struct pwm_chip *chip,
@@ -297,6 +296,7 @@ MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
 static int rockchip_pwm_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *id;
+	struct pwm_chip *chip;
 	struct rockchip_pwm_chip *pc;
 	u32 enable_conf, ctrl;
 	bool enabled;
@@ -306,9 +306,10 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
 	if (!id)
 		return -EINVAL;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_rockchip_pwm_chip(chip);
 
 	pc->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(pc->base))
@@ -342,18 +343,16 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
 		goto err_clk;
 	}
 
-	platform_set_drvdata(pdev, pc);
+	platform_set_drvdata(pdev, chip);
 
 	pc->data = id->data;
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &rockchip_pwm_ops;
-	pc->chip.npwm = 1;
+	chip->ops = &rockchip_pwm_ops;
 
 	enable_conf = pc->data->enable_conf;
 	ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
 	enabled = (ctrl & enable_conf) == enable_conf;
 
-	ret = pwmchip_add(&pc->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
 		goto err_pclk;
@@ -377,9 +376,10 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
 
 static void rockchip_pwm_remove(struct platform_device *pdev)
 {
-	struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
 
-	pwmchip_remove(&pc->chip);
+	pwmchip_remove(chip);
 
 	clk_unprepare(pc->pclk);
 	clk_unprepare(pc->clk);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 046/101] pwm: rz-mtu3: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (44 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 045/101] pwm: rockchip: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 047/101] pwm: samsung: " Uwe Kleine-König
                   ` (56 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-rz-mtu3 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rz-mtu3.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/pwm/pwm-rz-mtu3.c b/drivers/pwm/pwm-rz-mtu3.c
index bdda315b3bd3..ff396e2de7ab 100644
--- a/drivers/pwm/pwm-rz-mtu3.c
+++ b/drivers/pwm/pwm-rz-mtu3.c
@@ -72,7 +72,7 @@ struct rz_mtu3_pwm_channel {
  */
 
 struct rz_mtu3_pwm_chip {
-	struct pwm_chip chip;
+	struct device *parent;
 	struct clk *clk;
 	struct mutex lock;
 	unsigned long rate;
@@ -92,7 +92,7 @@ static const struct rz_mtu3_channel_io_map channel_map[] = {
 
 static inline struct rz_mtu3_pwm_chip *to_rz_mtu3_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct rz_mtu3_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static void rz_mtu3_pwm_read_tgr_registers(struct rz_mtu3_pwm_channel *priv,
@@ -219,7 +219,7 @@ static int rz_mtu3_pwm_enable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
 	u8 val;
 	int rc;
 
-	rc = pm_runtime_resume_and_get(rz_mtu3_pwm->chip.dev);
+	rc = pm_runtime_resume_and_get(rz_mtu3_pwm->parent);
 	if (rc)
 		return rc;
 
@@ -265,7 +265,7 @@ static void rz_mtu3_pwm_disable(struct rz_mtu3_pwm_chip *rz_mtu3_pwm,
 
 	mutex_unlock(&rz_mtu3_pwm->lock);
 
-	pm_runtime_put_sync(rz_mtu3_pwm->chip.dev);
+	pm_runtime_put_sync(rz_mtu3_pwm->parent);
 }
 
 static int rz_mtu3_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -465,21 +465,24 @@ static void rz_mtu3_pwm_pm_disable(void *data)
 	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = data;
 
 	clk_rate_exclusive_put(rz_mtu3_pwm->clk);
-	pm_runtime_disable(rz_mtu3_pwm->chip.dev);
-	pm_runtime_set_suspended(rz_mtu3_pwm->chip.dev);
+	pm_runtime_disable(rz_mtu3_pwm->parent);
+	pm_runtime_set_suspended(rz_mtu3_pwm->parent);
 }
 
 static int rz_mtu3_pwm_probe(struct platform_device *pdev)
 {
 	struct rz_mtu3 *parent_ddata = dev_get_drvdata(pdev->dev.parent);
+	struct pwm_chip *chip;
 	struct rz_mtu3_pwm_chip *rz_mtu3_pwm;
 	struct device *dev = &pdev->dev;
 	unsigned int i, j = 0;
 	int ret;
 
-	rz_mtu3_pwm = devm_kzalloc(&pdev->dev, sizeof(*rz_mtu3_pwm), GFP_KERNEL);
-	if (!rz_mtu3_pwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, RZ_MTU3_MAX_PWM_CHANNELS, sizeof(*rz_mtu3_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
+	rz_mtu3_pwm->parent = &pdev->dev;
 
 	rz_mtu3_pwm->clk = parent_ddata->clk;
 
@@ -514,15 +517,13 @@ static int rz_mtu3_pwm_probe(struct platform_device *pdev)
 
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
-	rz_mtu3_pwm->chip.dev = &pdev->dev;
 	ret = devm_add_action_or_reset(&pdev->dev, rz_mtu3_pwm_pm_disable,
 				       rz_mtu3_pwm);
 	if (ret < 0)
 		return ret;
 
-	rz_mtu3_pwm->chip.ops = &rz_mtu3_pwm_ops;
-	rz_mtu3_pwm->chip.npwm = RZ_MTU3_MAX_PWM_CHANNELS;
-	ret = devm_pwmchip_add(&pdev->dev, &rz_mtu3_pwm->chip);
+	chip->ops = &rz_mtu3_pwm_ops;
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 047/101] pwm: samsung: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (45 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 046/101] pwm: rz-mtu3: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 048/101] pwm: sifive: " Uwe Kleine-König
                   ` (55 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-samsung driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-samsung.c | 52 ++++++++++++++++++++-------------------
 1 file changed, 27 insertions(+), 25 deletions(-)

diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 10fe2c13cd80..88d66c281015 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -79,7 +79,6 @@ struct samsung_pwm_channel {
  * @tclk1:		external clock 1 (can be ERR_PTR if not present)
  */
 struct samsung_pwm_chip {
-	struct pwm_chip chip;
 	struct samsung_pwm_variant variant;
 	u8 inverter_mask;
 	u8 disabled_mask;
@@ -109,7 +108,7 @@ static DEFINE_SPINLOCK(samsung_pwm_lock);
 static inline
 struct samsung_pwm_chip *to_samsung_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct samsung_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline unsigned int to_tcon_channel(unsigned int channel)
@@ -180,9 +179,10 @@ static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *our_chip,
 	return rate / (reg + 1);
 }
 
-static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *our_chip,
+static unsigned long pwm_samsung_calc_tin(struct pwm_chip *chip,
 					  unsigned int chan, unsigned long freq)
 {
+	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 	struct samsung_pwm_variant *variant = &our_chip->variant;
 	unsigned long rate;
 	struct clk *clk;
@@ -196,12 +196,12 @@ static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *our_chip,
 				return rate;
 		}
 
-		dev_warn(our_chip->chip.dev,
+		dev_warn(chip->dev,
 			"tclk of PWM %d is inoperational, using tdiv\n", chan);
 	}
 
 	rate = pwm_samsung_get_tin_rate(our_chip, chan);
-	dev_dbg(our_chip->chip.dev, "tin parent at %lu\n", rate);
+	dev_dbg(chip->dev, "tin parent at %lu\n", rate);
 
 	/*
 	 * Compare minimum PWM frequency that can be achieved with possible
@@ -325,12 +325,12 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 		period = NSEC_PER_SEC / period_ns;
 
-		dev_dbg(our_chip->chip.dev, "duty_ns=%d, period_ns=%d (%u)\n",
+		dev_dbg(chip->dev, "duty_ns=%d, period_ns=%d (%u)\n",
 						duty_ns, period_ns, period);
 
-		tin_rate = pwm_samsung_calc_tin(our_chip, pwm->hwpwm, period);
+		tin_rate = pwm_samsung_calc_tin(chip, pwm->hwpwm, period);
 
-		dev_dbg(our_chip->chip.dev, "tin_rate=%lu\n", tin_rate);
+		dev_dbg(chip->dev, "tin_rate=%lu\n", tin_rate);
 
 		tin_ns = NSEC_PER_SEC / tin_rate;
 		tcnt = period_ns / tin_ns;
@@ -354,7 +354,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	/* -1UL will give 100% duty. */
 	--tcmp;
 
-	dev_dbg(our_chip->chip.dev,
+	dev_dbg(chip->dev,
 				"tin_ns=%u, tcmp=%u/%u\n", tin_ns, tcmp, tcnt);
 
 	/* Update PWM registers. */
@@ -367,7 +367,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	 * shortly afer this update (before it autoreloaded the new values).
 	 */
 	if (oldtcmp == (u32) -1) {
-		dev_dbg(our_chip->chip.dev, "Forcing manual update");
+		dev_dbg(chip->dev, "Forcing manual update");
 		pwm_samsung_manual_update(our_chip, pwm);
 	}
 
@@ -506,9 +506,10 @@ static const struct of_device_id samsung_pwm_matches[] = {
 };
 MODULE_DEVICE_TABLE(of, samsung_pwm_matches);
 
-static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
+static int pwm_samsung_parse_dt(struct pwm_chip *chip)
 {
-	struct device_node *np = our_chip->chip.dev->of_node;
+	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
+	struct device_node *np = chip->dev->of_node;
 	const struct of_device_id *match;
 	struct property *prop;
 	const __be32 *cur;
@@ -522,7 +523,7 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
 
 	of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
 		if (val >= SAMSUNG_PWM_NUM) {
-			dev_err(our_chip->chip.dev,
+			dev_err(chip->dev,
 				"%s: invalid channel index in samsung,pwm-outputs property\n",
 								__func__);
 			continue;
@@ -533,7 +534,7 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
 	return 0;
 }
 #else
-static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
+static int pwm_samsung_parse_dt(struct pwm_chip *chip)
 {
 	return -ENODEV;
 }
@@ -542,21 +543,21 @@ static int pwm_samsung_parse_dt(struct samsung_pwm_chip *our_chip)
 static int pwm_samsung_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct pwm_chip *chip;
 	struct samsung_pwm_chip *our_chip;
 	unsigned int chan;
 	int ret;
 
-	our_chip = devm_kzalloc(&pdev->dev, sizeof(*our_chip), GFP_KERNEL);
-	if (our_chip == NULL)
+	chip = devm_pwmchip_alloc(&pdev->dev, SAMSUNG_PWM_NUM, sizeof(*chip));
+	if (chip == NULL)
 		return -ENOMEM;
+	our_chip = to_samsung_pwm_chip(chip);
 
-	our_chip->chip.dev = &pdev->dev;
-	our_chip->chip.ops = &pwm_samsung_ops;
-	our_chip->chip.npwm = SAMSUNG_PWM_NUM;
+	chip->ops = &pwm_samsung_ops;
 	our_chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1;
 
 	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
-		ret = pwm_samsung_parse_dt(our_chip);
+		ret = pwm_samsung_parse_dt(chip);
 		if (ret)
 			return ret;
 	} else {
@@ -595,7 +596,7 @@ static int pwm_samsung_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, our_chip);
 
-	ret = pwmchip_add(&our_chip->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(dev, "failed to register PWM chip\n");
 		clk_disable_unprepare(our_chip->base_clk);
@@ -612,9 +613,10 @@ static int pwm_samsung_probe(struct platform_device *pdev)
 
 static void pwm_samsung_remove(struct platform_device *pdev)
 {
-	struct samsung_pwm_chip *our_chip = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 
-	pwmchip_remove(&our_chip->chip);
+	pwmchip_remove(chip);
 
 	clk_disable_unprepare(our_chip->base_clk);
 }
@@ -622,8 +624,8 @@ static void pwm_samsung_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int pwm_samsung_resume(struct device *dev)
 {
-	struct samsung_pwm_chip *our_chip = dev_get_drvdata(dev);
-	struct pwm_chip *chip = &our_chip->chip;
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 	unsigned int i;
 
 	for (i = 0; i < SAMSUNG_PWM_NUM; i++) {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 048/101] pwm: sifive: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (46 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 047/101] pwm: samsung: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 049/101] pwm: sl28cpld: " Uwe Kleine-König
                   ` (54 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-sifive driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sifive.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
index 089e50bdbbf0..1f8a50143300 100644
--- a/drivers/pwm/pwm-sifive.c
+++ b/drivers/pwm/pwm-sifive.c
@@ -41,7 +41,7 @@
 #define PWM_SIFIVE_DEFAULT_PERIOD	10000000
 
 struct pwm_sifive_ddata {
-	struct pwm_chip	chip;
+	struct device *parent;
 	struct mutex lock; /* lock to protect user_count and approx_period */
 	struct notifier_block notifier;
 	struct clk *clk;
@@ -54,7 +54,7 @@ struct pwm_sifive_ddata {
 static inline
 struct pwm_sifive_ddata *pwm_sifive_chip_to_ddata(struct pwm_chip *chip)
 {
-	return container_of(chip, struct pwm_sifive_ddata, chip);
+	return pwmchip_priv(chip);
 }
 
 static int pwm_sifive_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -102,7 +102,7 @@ static void pwm_sifive_update_clock(struct pwm_sifive_ddata *ddata,
 	/* As scale <= 15 the shift operation cannot overflow. */
 	num = (unsigned long long)NSEC_PER_SEC << (PWM_SIFIVE_CMPWIDTH + scale);
 	ddata->real_period = div64_ul(num, rate);
-	dev_dbg(ddata->chip.dev,
+	dev_dbg(ddata->parent,
 		"New real_period = %u ns\n", ddata->real_period);
 }
 
@@ -185,7 +185,7 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (!enabled) {
 		ret = clk_enable(ddata->clk);
 		if (ret) {
-			dev_err(ddata->chip.dev, "Enable clk failed\n");
+			dev_err(chip->dev, "Enable clk failed\n");
 			return ret;
 		}
 	}
@@ -230,15 +230,14 @@ static int pwm_sifive_probe(struct platform_device *pdev)
 	u32 val;
 	unsigned int enabled_pwms = 0, enabled_clks = 1;
 
-	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
-	if (!ddata)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, 4, sizeof(*ddata));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	ddata = pwm_sifive_chip_to_ddata(chip);
+	ddata->parent = dev;
 
 	mutex_init(&ddata->lock);
-	chip = &ddata->chip;
-	chip->dev = dev;
 	chip->ops = &pwm_sifive_ops;
-	chip->npwm = 4;
 
 	ddata->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(ddata->regs))
@@ -296,7 +295,7 @@ static int pwm_sifive_probe(struct platform_device *pdev)
 		goto unregister_clk;
 	}
 
-	platform_set_drvdata(pdev, ddata);
+	platform_set_drvdata(pdev, chip);
 	dev_dbg(dev, "SiFive PWM chip registered %d PWMs\n", chip->npwm);
 
 	return 0;
@@ -314,15 +313,16 @@ static int pwm_sifive_probe(struct platform_device *pdev)
 
 static void pwm_sifive_remove(struct platform_device *dev)
 {
-	struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
+	struct pwm_chip *chip = platform_get_drvdata(dev);
+	struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
 	struct pwm_device *pwm;
 	int ch;
 
-	pwmchip_remove(&ddata->chip);
+	pwmchip_remove(chip);
 	clk_notifier_unregister(ddata->clk, &ddata->notifier);
 
-	for (ch = 0; ch < ddata->chip.npwm; ch++) {
-		pwm = &ddata->chip.pwms[ch];
+	for (ch = 0; ch < chip->npwm; ch++) {
+		pwm = &chip->pwms[ch];
 		if (pwm->state.enabled)
 			clk_disable(ddata->clk);
 	}
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 049/101] pwm: sl28cpld: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (47 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 048/101] pwm: sifive: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 050/101] pwm: spear: " Uwe Kleine-König
                   ` (53 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-sl28cpld driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sl28cpld.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c
index 88b01ff9e460..30f96d10a3b8 100644
--- a/drivers/pwm/pwm-sl28cpld.c
+++ b/drivers/pwm/pwm-sl28cpld.c
@@ -81,14 +81,13 @@
 	regmap_write((priv)->regmap, (priv)->offset + (reg), (val))
 
 struct sl28cpld_pwm {
-	struct pwm_chip chip;
 	struct regmap *regmap;
 	u32 offset;
 };
 
 static inline struct sl28cpld_pwm *sl28cpld_pwm_from_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct sl28cpld_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int sl28cpld_pwm_get_state(struct pwm_chip *chip,
@@ -213,9 +212,10 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = sl28cpld_pwm_from_chip(chip);
 
 	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
 	if (!priv->regmap) {
@@ -231,10 +231,7 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev)
 	}
 
 	/* Initialize the pwm_chip structure */
-	chip = &priv->chip;
-	chip->dev = &pdev->dev;
 	chip->ops = &sl28cpld_pwm_ops;
-	chip->npwm = 1;
 
 	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret) {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 050/101] pwm: spear: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (48 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 049/101] pwm: sl28cpld: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 051/101] pwm: sprd: " Uwe Kleine-König
                   ` (52 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-spear driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-spear.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
index ff991319feef..5679732cd77e 100644
--- a/drivers/pwm/pwm-spear.c
+++ b/drivers/pwm/pwm-spear.c
@@ -53,12 +53,11 @@
 struct spear_pwm_chip {
 	void __iomem *mmio_base;
 	struct clk *clk;
-	struct pwm_chip chip;
 };
 
 static inline struct spear_pwm_chip *to_spear_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct spear_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline u32 spear_pwm_readl(struct spear_pwm_chip *chip, unsigned int num,
@@ -194,13 +193,15 @@ static const struct pwm_ops spear_pwm_ops = {
 static int spear_pwm_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pwm_chip *chip;
 	struct spear_pwm_chip *pc;
 	int ret;
 	u32 val;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_spear_pwm_chip(chip);
 
 	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(pc->mmio_base))
@@ -211,9 +212,7 @@ static int spear_pwm_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
 				     "Failed to get clock\n");
 
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &spear_pwm_ops;
-	pc->chip.npwm = NUM_PWM;
+	chip->ops = &spear_pwm_ops;
 
 	if (of_device_is_compatible(np, "st,spear1340-pwm")) {
 		ret = clk_enable(pc->clk);
@@ -232,7 +231,7 @@ static int spear_pwm_probe(struct platform_device *pdev)
 		clk_disable(pc->clk);
 	}
 
-	ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "pwmchip_add() failed\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 051/101] pwm: sprd: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (49 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 050/101] pwm: spear: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 052/101] pwm: sti: " Uwe Kleine-König
                   ` (51 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-sprd driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sprd.c | 50 +++++++++++++++++++++---------------------
 1 file changed, 25 insertions(+), 25 deletions(-)

diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c
index 77939e161006..b7ecd875b605 100644
--- a/drivers/pwm/pwm-sprd.c
+++ b/drivers/pwm/pwm-sprd.c
@@ -35,14 +35,13 @@ struct sprd_pwm_chn {
 struct sprd_pwm_chip {
 	void __iomem *base;
 	struct device *dev;
-	struct pwm_chip chip;
 	int num_pwms;
 	struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];
 };
 
 static inline struct sprd_pwm_chip* sprd_pwm_from_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct sprd_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 /*
@@ -215,65 +214,66 @@ static const struct pwm_ops sprd_pwm_ops = {
 	.get_state = sprd_pwm_get_state,
 };
 
-static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc)
+static int sprd_pwm_clk_init(struct device *dev,
+			     struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM])
 {
 	struct clk *clk_pwm;
 	int ret, i;
 
 	for (i = 0; i < SPRD_PWM_CHN_NUM; i++) {
-		struct sprd_pwm_chn *chn = &spc->chn[i];
 		int j;
 
 		for (j = 0; j < SPRD_PWM_CHN_CLKS_NUM; ++j)
-			chn->clks[j].id =
+			chn[i].clks[j].id =
 				sprd_pwm_clks[i * SPRD_PWM_CHN_CLKS_NUM + j];
 
-		ret = devm_clk_bulk_get(spc->dev, SPRD_PWM_CHN_CLKS_NUM,
-					chn->clks);
+		ret = devm_clk_bulk_get(dev, SPRD_PWM_CHN_CLKS_NUM,
+					chn[i].clks);
 		if (ret) {
 			if (ret == -ENOENT)
 				break;
 
-			return dev_err_probe(spc->dev, ret,
+			return dev_err_probe(dev, ret,
 					     "failed to get channel clocks\n");
 		}
 
-		clk_pwm = chn->clks[SPRD_PWM_CHN_OUTPUT_CLK].clk;
-		chn->clk_rate = clk_get_rate(clk_pwm);
+		clk_pwm = chn[i].clks[SPRD_PWM_CHN_OUTPUT_CLK].clk;
+		chn[i].clk_rate = clk_get_rate(clk_pwm);
 	}
 
 	if (!i)
-		return dev_err_probe(spc->dev, -ENODEV, "no available PWM channels\n");
+		return dev_err_probe(dev, -ENODEV, "no available PWM channels\n");
 
-	spc->num_pwms = i;
-
-	return 0;
+	return i;
 }
 
 static int sprd_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct sprd_pwm_chip *spc;
+	struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];
 	int ret;
 
-	spc = devm_kzalloc(&pdev->dev, sizeof(*spc), GFP_KERNEL);
-	if (!spc)
-		return -ENOMEM;
+	ret = sprd_pwm_clk_init(&pdev->dev, chn);
+	if (ret < 0)
+		return ret;
+
+	chip = devm_pwmchip_alloc(&pdev->dev, ret, sizeof(*spc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	spc = sprd_pwm_from_chip(chip);
 
 	spc->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(spc->base))
 		return PTR_ERR(spc->base);
 
 	spc->dev = &pdev->dev;
+	memcpy(spc->chn, chn, sizeof(chn));
 
-	ret = sprd_pwm_clk_init(spc);
-	if (ret)
-		return ret;
+	chip->ops = &sprd_pwm_ops;
+	chip->npwm = spc->num_pwms;
 
-	spc->chip.dev = &pdev->dev;
-	spc->chip.ops = &sprd_pwm_ops;
-	spc->chip.npwm = spc->num_pwms;
-
-	ret = devm_pwmchip_add(&pdev->dev, &spc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret)
 		dev_err(&pdev->dev, "failed to add PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 052/101] pwm: sti: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (50 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 051/101] pwm: sprd: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 053/101] pwm: stm32-lp: " Uwe Kleine-König
                   ` (50 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-sti driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sti.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index dc92cea31cd0..9de9083bb407 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -94,7 +94,6 @@ struct sti_pwm_chip {
 	struct regmap_field *pwm_cpt_en;
 	struct regmap_field *pwm_cpt_int_en;
 	struct regmap_field *pwm_cpt_int_stat;
-	struct pwm_chip chip;
 	struct pwm_device *cur;
 	unsigned long configured;
 	unsigned int en_count;
@@ -114,7 +113,7 @@ static const struct reg_field sti_pwm_regfields[MAX_REGFIELDS] = {
 
 static inline struct sti_pwm_chip *to_sti_pwmchip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct sti_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 /*
@@ -503,10 +502,6 @@ static int sti_pwm_probe_dt(struct sti_pwm_chip *pc)
 	u32 num_devs;
 	int ret;
 
-	ret = of_property_read_u32(np, "st,pwm-num-chan", &num_devs);
-	if (!ret)
-		cdata->pwm_num_devs = num_devs;
-
 	ret = of_property_read_u32(np, "st,capture-num-chan", &num_devs);
 	if (!ret)
 		cdata->cpt_num_devs = num_devs;
@@ -561,13 +556,18 @@ static int sti_pwm_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct sti_pwm_compat_data *cdata;
+	struct pwm_chip *chip;
 	struct sti_pwm_chip *pc;
 	unsigned int i;
 	int irq, ret;
+	u32 num_devs = 0;
 
-	pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	of_property_read_u32(dev->of_node, "st,pwm-num-chan", &num_devs);
+
+	chip = devm_pwmchip_alloc(dev, num_devs, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_sti_pwmchip(chip);
 
 	cdata = devm_kzalloc(dev, sizeof(*cdata), GFP_KERNEL);
 	if (!cdata)
@@ -600,7 +600,7 @@ static int sti_pwm_probe(struct platform_device *pdev)
 	cdata->reg_fields = sti_pwm_regfields;
 	cdata->max_prescale = 0xff;
 	cdata->max_pwm_cnt = 255;
-	cdata->pwm_num_devs = 0;
+	cdata->pwm_num_devs = num_devs;
 	cdata->cpt_num_devs = 0;
 
 	pc->cdata = cdata;
@@ -644,9 +644,8 @@ static int sti_pwm_probe(struct platform_device *pdev)
 			return -ENOMEM;
 	}
 
-	pc->chip.dev = dev;
-	pc->chip.ops = &sti_pwm_ops;
-	pc->chip.npwm = pc->cdata->pwm_num_devs;
+	chip->ops = &sti_pwm_ops;
+	chip->npwm = pc->cdata->pwm_num_devs;
 
 	for (i = 0; i < cdata->cpt_num_devs; i++) {
 		struct sti_cpt_ddata *ddata = &cdata->ddata[i];
@@ -655,23 +654,24 @@ static int sti_pwm_probe(struct platform_device *pdev)
 		mutex_init(&ddata->lock);
 	}
 
-	ret = pwmchip_add(&pc->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		clk_unprepare(pc->pwm_clk);
 		clk_unprepare(pc->cpt_clk);
 		return ret;
 	}
 
-	platform_set_drvdata(pdev, pc);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 }
 
 static void sti_pwm_remove(struct platform_device *pdev)
 {
-	struct sti_pwm_chip *pc = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
 
-	pwmchip_remove(&pc->chip);
+	pwmchip_remove(chip);
 
 	clk_unprepare(pc->pwm_clk);
 	clk_unprepare(pc->cpt_clk);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 053/101] pwm: stm32-lp: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (51 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 052/101] pwm: sti: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 054/101] pwm: stm32: " Uwe Kleine-König
                   ` (49 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-stm32-lp driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-stm32-lp.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index 444a9c9c2c29..1fdf91ec9c9b 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -18,14 +18,13 @@
 #include <linux/pwm.h>
 
 struct stm32_pwm_lp {
-	struct pwm_chip chip;
 	struct clk *clk;
 	struct regmap *regmap;
 };
 
 static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip)
 {
-	return container_of(chip, struct stm32_pwm_lp, chip);
+	return pwmchip_priv(chip);
 }
 
 /* STM32 Low-Power Timer is preceded by a configurable power-of-2 prescaler */
@@ -192,20 +191,20 @@ static const struct pwm_ops stm32_pwm_lp_ops = {
 static int stm32_pwm_lp_probe(struct platform_device *pdev)
 {
 	struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
+	struct pwm_chip *chip;
 	struct stm32_pwm_lp *priv;
 	int ret;
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = to_stm32_pwm_lp(chip);
 
 	priv->regmap = ddata->regmap;
 	priv->clk = ddata->clk;
-	priv->chip.dev = &pdev->dev;
-	priv->chip.ops = &stm32_pwm_lp_ops;
-	priv->chip.npwm = 1;
+	chip->ops = &stm32_pwm_lp_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &priv->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return ret;
 
@@ -216,13 +215,13 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
 
 static int __maybe_unused stm32_pwm_lp_suspend(struct device *dev)
 {
-	struct stm32_pwm_lp *priv = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
 	struct pwm_state state;
 
-	pwm_get_state(&priv->chip.pwms[0], &state);
+	pwm_get_state(&chip->pwms[0], &state);
 	if (state.enabled) {
 		dev_err(dev, "The consumer didn't stop us (%s)\n",
-			priv->chip.pwms[0].label);
+			chip->pwms[0].label);
 		return -EBUSY;
 	}
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 054/101] pwm: stm32: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (52 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 053/101] pwm: stm32-lp: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 055/101] pwm: stmpe: " Uwe Kleine-König
                   ` (48 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-stm32 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-stm32.c | 44 +++++++++++++++++++++--------------------
 1 file changed, 23 insertions(+), 21 deletions(-)

diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 3303a754ea02..73fbd7a119ec 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -27,7 +27,6 @@ struct stm32_breakinput {
 };
 
 struct stm32_pwm {
-	struct pwm_chip chip;
 	struct mutex lock; /* protect pwm config/enable */
 	struct clk *clk;
 	struct regmap *regmap;
@@ -40,7 +39,7 @@ struct stm32_pwm {
 
 static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip)
 {
-	return container_of(chip, struct stm32_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static u32 active_channels(struct stm32_pwm *dev)
@@ -109,7 +108,7 @@ static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm,
 				 unsigned long tmo_ms, u32 *raw_prd,
 				 u32 *raw_dty)
 {
-	struct device *parent = priv->chip.dev->parent;
+	struct device *parent = pwm->chip->dev->parent;
 	enum stm32_timers_dmas dma_id;
 	u32 ccen, ccr;
 	int ret;
@@ -185,7 +184,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	ret = clk_enable(priv->clk);
 	if (ret) {
-		dev_err(priv->chip.dev, "failed to enable counter clock\n");
+		dev_err(chip->dev, "failed to enable counter clock\n");
 		goto unlock;
 	}
 
@@ -578,18 +577,18 @@ static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
 	priv->have_complementary_output = (ccer != 0);
 }
 
-static int stm32_pwm_detect_channels(struct stm32_pwm *priv)
+static unsigned int stm32_pwm_detect_channels(struct stm32_timers *ddata)
 {
 	u32 ccer;
-	int npwm = 0;
+	unsigned int npwm = 0;
 
 	/*
 	 * If channels enable bits don't exist writing 1 will have no
 	 * effect so we can detect and count them.
 	 */
-	regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
-	regmap_read(priv->regmap, TIM_CCER, &ccer);
-	regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
+	regmap_set_bits(ddata->regmap, TIM_CCER, TIM_CCER_CCXE);
+	regmap_read(ddata->regmap, TIM_CCER, &ccer);
+	regmap_clear_bits(ddata->regmap, TIM_CCER, TIM_CCER_CCXE);
 
 	if (ccer & TIM_CCER_CC1E)
 		npwm++;
@@ -612,11 +611,14 @@ static int stm32_pwm_probe(struct platform_device *pdev)
 	struct device_node *np = dev->of_node;
 	struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
 	struct stm32_pwm *priv;
+	struct pwm_chip *chip;
 	int ret;
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, stm32_pwm_detect_channels(ddata),
+				  sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = to_stm32_pwm_dev(chip);
 
 	mutex_init(&priv->lock);
 	priv->regmap = ddata->regmap;
@@ -632,33 +634,32 @@ static int stm32_pwm_probe(struct platform_device *pdev)
 
 	stm32_pwm_detect_complementary(priv);
 
-	priv->chip.dev = dev;
-	priv->chip.ops = &stm32pwm_ops;
-	priv->chip.npwm = stm32_pwm_detect_channels(priv);
+	chip->ops = &stm32pwm_ops;
 
-	ret = devm_pwmchip_add(dev, &priv->chip);
+	ret = devm_pwmchip_add(dev, chip);
 	if (ret < 0)
 		return ret;
 
-	platform_set_drvdata(pdev, priv);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 }
 
 static int __maybe_unused stm32_pwm_suspend(struct device *dev)
 {
-	struct stm32_pwm *priv = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
 	unsigned int i;
 	u32 ccer, mask;
 
 	/* Look for active channels */
 	ccer = active_channels(priv);
 
-	for (i = 0; i < priv->chip.npwm; i++) {
+	for (i = 0; i < chip->npwm; i++) {
 		mask = TIM_CCER_CC1E << (i * 4);
 		if (ccer & mask) {
 			dev_err(dev, "PWM %u still in use by consumer %s\n",
-				i, priv->chip.pwms[i].label);
+				i, chip->pwms[i].label);
 			return -EBUSY;
 		}
 	}
@@ -668,7 +669,8 @@ static int __maybe_unused stm32_pwm_suspend(struct device *dev)
 
 static int __maybe_unused stm32_pwm_resume(struct device *dev)
 {
-	struct stm32_pwm *priv = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
 	int ret;
 
 	ret = pinctrl_pm_select_default_state(dev);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 055/101] pwm: stmpe: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (53 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 054/101] pwm: stm32: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 056/101] pwm: sun4i: " Uwe Kleine-König
                   ` (47 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-stmpe driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-stmpe.c | 38 ++++++++++++++++++++------------------
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c
index a46f5b4dd816..9c0f96b77c42 100644
--- a/drivers/pwm/pwm-stmpe.c
+++ b/drivers/pwm/pwm-stmpe.c
@@ -27,13 +27,12 @@
 
 struct stmpe_pwm {
 	struct stmpe *stmpe;
-	struct pwm_chip chip;
 	u8 last_duty;
 };
 
 static inline struct stmpe_pwm *to_stmpe_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct stmpe_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -292,33 +291,36 @@ static const struct pwm_ops stmpe_24xx_pwm_ops = {
 static int __init stmpe_pwm_probe(struct platform_device *pdev)
 {
 	struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+	struct pwm_chip *chip;
 	struct stmpe_pwm *stmpe_pwm;
 	int ret;
 
-	stmpe_pwm = devm_kzalloc(&pdev->dev, sizeof(*stmpe_pwm), GFP_KERNEL);
-	if (!stmpe_pwm)
-		return -ENOMEM;
+	switch (stmpe->partnum) {
+	case STMPE2401:
+	case STMPE2403:
+		break;
+	case STMPE1601:
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				     "STMPE1601 not yet supported\n");
+	default:
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				     "Unknown STMPE PWM\n");
+	}
+
+	chip = devm_pwmchip_alloc(&pdev->dev, 3, sizeof(*stmpe_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	stmpe_pwm = to_stmpe_pwm(chip);
 
 	stmpe_pwm->stmpe = stmpe;
-	stmpe_pwm->chip.dev = &pdev->dev;
 
-	if (stmpe->partnum == STMPE2401 || stmpe->partnum == STMPE2403) {
-		stmpe_pwm->chip.ops = &stmpe_24xx_pwm_ops;
-		stmpe_pwm->chip.npwm = 3;
-	} else {
-		if (stmpe->partnum == STMPE1601)
-			dev_err(&pdev->dev, "STMPE1601 not yet supported\n");
-		else
-			dev_err(&pdev->dev, "Unknown STMPE PWM\n");
-
-		return -ENODEV;
-	}
+	chip->ops = &stmpe_24xx_pwm_ops;
 
 	ret = stmpe_enable(stmpe, STMPE_BLOCK_PWM);
 	if (ret)
 		return ret;
 
-	ret = pwmchip_add(&stmpe_pwm->chip);
+	ret = pwmchip_add(chip);
 	if (ret) {
 		stmpe_disable(stmpe, STMPE_BLOCK_PWM);
 		return ret;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 056/101] pwm: sun4i: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (54 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 055/101] pwm: stmpe: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 057/101] pwm: sunplus: " Uwe Kleine-König
                   ` (46 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-sun4i driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sun4i.c | 33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index 1a439025540d..4251807e496b 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -81,7 +81,6 @@ struct sun4i_pwm_data {
 };
 
 struct sun4i_pwm_chip {
-	struct pwm_chip chip;
 	struct clk *bus_clk;
 	struct clk *clk;
 	struct reset_control *rst;
@@ -92,7 +91,7 @@ struct sun4i_pwm_chip {
 
 static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct sun4i_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline u32 sun4i_pwm_readl(struct sun4i_pwm_chip *chip,
@@ -384,17 +383,21 @@ MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids);
 
 static int sun4i_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct sun4i_pwm_chip *sun4ichip;
+	const struct sun4i_pwm_data *data;
 	int ret;
 
-	sun4ichip = devm_kzalloc(&pdev->dev, sizeof(*sun4ichip), GFP_KERNEL);
-	if (!sun4ichip)
-		return -ENOMEM;
-
-	sun4ichip->data = of_device_get_match_data(&pdev->dev);
-	if (!sun4ichip->data)
+	data = of_device_get_match_data(&pdev->dev);
+	if (!data)
 		return -ENODEV;
 
+	chip = devm_pwmchip_alloc(&pdev->dev, data->npwm, sizeof(*sun4ichip));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	sun4ichip = to_sun4i_pwm_chip(chip);
+
+	sun4ichip->data = data;
 	sun4ichip->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(sun4ichip->base))
 		return PTR_ERR(sun4ichip->base);
@@ -451,19 +454,18 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 		goto err_bus;
 	}
 
-	sun4ichip->chip.dev = &pdev->dev;
-	sun4ichip->chip.ops = &sun4i_pwm_ops;
-	sun4ichip->chip.npwm = sun4ichip->data->npwm;
+	chip->ops = &sun4i_pwm_ops;
+	chip->npwm = sun4ichip->data->npwm;
 
 	spin_lock_init(&sun4ichip->ctrl_lock);
 
-	ret = pwmchip_add(&sun4ichip->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
 		goto err_pwm_add;
 	}
 
-	platform_set_drvdata(pdev, sun4ichip);
+	platform_set_drvdata(pdev, chip);
 
 	return 0;
 
@@ -477,9 +479,10 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 
 static void sun4i_pwm_remove(struct platform_device *pdev)
 {
-	struct sun4i_pwm_chip *sun4ichip = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct sun4i_pwm_chip *sun4ichip = to_sun4i_pwm_chip(chip);
 
-	pwmchip_remove(&sun4ichip->chip);
+	pwmchip_remove(chip);
 
 	clk_disable_unprepare(sun4ichip->bus_clk);
 	reset_control_assert(sun4ichip->rst);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 057/101] pwm: sunplus: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (55 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 056/101] pwm: sun4i: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 058/101] pwm: tegra: " Uwe Kleine-König
                   ` (45 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-sunplus driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sunplus.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-sunplus.c b/drivers/pwm/pwm-sunplus.c
index 773e2f80526e..46181b9149b0 100644
--- a/drivers/pwm/pwm-sunplus.c
+++ b/drivers/pwm/pwm-sunplus.c
@@ -43,14 +43,13 @@
 #define SP7021_PWM_NUM			4
 
 struct sunplus_pwm {
-	struct pwm_chip chip;
 	void __iomem *base;
 	struct clk *clk;
 };
 
 static inline struct sunplus_pwm *to_sunplus_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct sunplus_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int sunplus_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -175,12 +174,14 @@ static void sunplus_pwm_clk_release(void *data)
 static int sunplus_pwm_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct pwm_chip *chip;
 	struct sunplus_pwm *priv;
 	int ret;
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, SP7021_PWM_NUM, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = to_sunplus_pwm(chip);
 
 	priv->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(priv->base))
@@ -203,11 +204,9 @@ static int sunplus_pwm_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	priv->chip.dev = dev;
-	priv->chip.ops = &sunplus_pwm_ops;
-	priv->chip.npwm = SP7021_PWM_NUM;
+	chip->ops = &sunplus_pwm_ops;
 
-	ret = devm_pwmchip_add(dev, &priv->chip);
+	ret = devm_pwmchip_add(dev, chip);
 	if (ret < 0)
 		return dev_err_probe(dev, ret, "Cannot register sunplus PWM\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 058/101] pwm: tegra: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (56 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 057/101] pwm: sunplus: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 059/101] pwm: tiecap: " Uwe Kleine-König
                   ` (44 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-tegra driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-tegra.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 39ea51e08c94..f41791d7630d 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -65,7 +65,6 @@ struct tegra_pwm_soc {
 };
 
 struct tegra_pwm_chip {
-	struct pwm_chip chip;
 	struct device *dev;
 
 	struct clk *clk;
@@ -81,7 +80,7 @@ struct tegra_pwm_chip {
 
 static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct tegra_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline u32 pwm_readl(struct tegra_pwm_chip *pc, unsigned int offset)
@@ -272,14 +271,19 @@ static const struct pwm_ops tegra_pwm_ops = {
 
 static int tegra_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct tegra_pwm_chip *pc;
+	const struct tegra_pwm_soc *soc;
 	int ret;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	soc = of_device_get_match_data(&pdev->dev);
 
-	pc->soc = of_device_get_match_data(&pdev->dev);
+	chip = devm_pwmchip_alloc(&pdev->dev, soc->num_channels, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_tegra_pwm_chip(chip);
+
+	pc->soc = soc;
 	pc->dev = &pdev->dev;
 
 	pc->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -328,11 +332,9 @@ static int tegra_pwm_probe(struct platform_device *pdev)
 
 	reset_control_deassert(pc->rst);
 
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &tegra_pwm_ops;
-	pc->chip.npwm = pc->soc->num_channels;
+	chip->ops = &tegra_pwm_ops;
 
-	ret = pwmchip_add(&pc->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 		reset_control_assert(pc->rst);
@@ -350,9 +352,10 @@ static int tegra_pwm_probe(struct platform_device *pdev)
 
 static void tegra_pwm_remove(struct platform_device *pdev)
 {
-	struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
 
-	pwmchip_remove(&pc->chip);
+	pwmchip_remove(chip);
 
 	reset_control_assert(pc->rst);
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 059/101] pwm: tiecap: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (57 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 058/101] pwm: tegra: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 060/101] pwm: tiehrpwm: " Uwe Kleine-König
                   ` (43 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-tiecap driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-tiecap.c | 55 +++++++++++++++++++++-------------------
 1 file changed, 29 insertions(+), 26 deletions(-)

diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 11e3549cf103..9ff9a6de8be2 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -32,7 +32,6 @@ struct ecap_context {
 };
 
 struct ecap_pwm_chip {
-	struct pwm_chip chip;
 	unsigned int clk_rate;
 	void __iomem *mmio_base;
 	struct ecap_context ctx;
@@ -40,7 +39,7 @@ struct ecap_pwm_chip {
 
 static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct ecap_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 /*
@@ -70,7 +69,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		duty_cycles = (u32)c;
 	}
 
-	pm_runtime_get_sync(pc->chip.dev);
+	pm_runtime_get_sync(chip->dev);
 
 	value = readw(pc->mmio_base + ECCTL2);
 
@@ -100,7 +99,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		writew(value, pc->mmio_base + ECCTL2);
 	}
 
-	pm_runtime_put_sync(pc->chip.dev);
+	pm_runtime_put_sync(chip->dev);
 
 	return 0;
 }
@@ -111,7 +110,7 @@ static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 	struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
 	u16 value;
 
-	pm_runtime_get_sync(pc->chip.dev);
+	pm_runtime_get_sync(chip->dev);
 
 	value = readw(pc->mmio_base + ECCTL2);
 
@@ -124,7 +123,7 @@ static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	writew(value, pc->mmio_base + ECCTL2);
 
-	pm_runtime_put_sync(pc->chip.dev);
+	pm_runtime_put_sync(chip->dev);
 
 	return 0;
 }
@@ -135,7 +134,7 @@ static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	u16 value;
 
 	/* Leave clock enabled on enabling PWM */
-	pm_runtime_get_sync(pc->chip.dev);
+	pm_runtime_get_sync(chip->dev);
 
 	/*
 	 * Enable 'Free run Time stamp counter mode' to start counter
@@ -162,7 +161,7 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	writew(value, pc->mmio_base + ECCTL2);
 
 	/* Disable clock on PWM disable */
-	pm_runtime_put_sync(pc->chip.dev);
+	pm_runtime_put_sync(chip->dev);
 }
 
 static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -217,13 +216,15 @@ MODULE_DEVICE_TABLE(of, ecap_of_match);
 static int ecap_pwm_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pwm_chip *chip;
 	struct ecap_pwm_chip *pc;
 	struct clk *clk;
 	int ret;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 1, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_ecap_pwm_chip(chip);
 
 	clk = devm_clk_get(&pdev->dev, "fck");
 	if (IS_ERR(clk)) {
@@ -244,21 +245,19 @@ static int ecap_pwm_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &ecap_pwm_ops;
-	pc->chip.npwm = 1;
+	chip->ops = &ecap_pwm_ops;
 
 	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(pc->mmio_base))
 		return PTR_ERR(pc->mmio_base);
 
-	ret = devm_pwmchip_add(&pdev->dev, &pc->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 		return ret;
 	}
 
-	platform_set_drvdata(pdev, pc);
+	platform_set_drvdata(pdev, chip);
 	pm_runtime_enable(&pdev->dev);
 
 	return 0;
@@ -270,17 +269,21 @@ static void ecap_pwm_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static void ecap_pwm_save_context(struct ecap_pwm_chip *pc)
+static void ecap_pwm_save_context(struct pwm_chip *chip)
 {
-	pm_runtime_get_sync(pc->chip.dev);
+	struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
+
+	pm_runtime_get_sync(chip->dev);
 	pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2);
 	pc->ctx.cap4 = readl(pc->mmio_base + CAP4);
 	pc->ctx.cap3 = readl(pc->mmio_base + CAP3);
-	pm_runtime_put_sync(pc->chip.dev);
+	pm_runtime_put_sync(chip->dev);
 }
 
-static void ecap_pwm_restore_context(struct ecap_pwm_chip *pc)
+static void ecap_pwm_restore_context(struct pwm_chip *chip)
 {
+	struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
+
 	writel(pc->ctx.cap3, pc->mmio_base + CAP3);
 	writel(pc->ctx.cap4, pc->mmio_base + CAP4);
 	writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2);
@@ -288,10 +291,10 @@ static void ecap_pwm_restore_context(struct ecap_pwm_chip *pc)
 
 static int ecap_pwm_suspend(struct device *dev)
 {
-	struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
-	struct pwm_device *pwm = pc->chip.pwms;
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct pwm_device *pwm = chip->pwms;
 
-	ecap_pwm_save_context(pc);
+	ecap_pwm_save_context(chip);
 
 	/* Disable explicitly if PWM is running */
 	if (pwm_is_enabled(pwm))
@@ -302,14 +305,14 @@ static int ecap_pwm_suspend(struct device *dev)
 
 static int ecap_pwm_resume(struct device *dev)
 {
-	struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
-	struct pwm_device *pwm = pc->chip.pwms;
+	struct pwm_chip *chip = dev_get_drvdata(dev);
+	struct pwm_device *pwm = chip->pwms;
 
 	/* Enable explicitly if PWM was running */
 	if (pwm_is_enabled(pwm))
 		pm_runtime_get_sync(dev);
 
-	ecap_pwm_restore_context(pc);
+	ecap_pwm_restore_context(chip);
 	return 0;
 }
 #endif
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 060/101] pwm: tiehrpwm: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (58 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 059/101] pwm: tiecap: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 061/101] pwm: twl-led: " Uwe Kleine-König
                   ` (42 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-tiehrpwm driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-tiehrpwm.c | 52 ++++++++++++++++++++------------------
 1 file changed, 28 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 27cf9d001ae1..5516cca7e3ac 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -105,7 +105,6 @@ struct ehrpwm_context {
 };
 
 struct ehrpwm_pwm_chip {
-	struct pwm_chip chip;
 	unsigned long clk_rate;
 	void __iomem *mmio_base;
 	unsigned long period_cycles[NUM_PWM_CHANNEL];
@@ -116,7 +115,7 @@ struct ehrpwm_pwm_chip {
 
 static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct ehrpwm_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static inline u16 ehrpwm_read(void __iomem *base, unsigned int offset)
@@ -441,13 +440,15 @@ MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
 static int ehrpwm_pwm_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
+	struct pwm_chip *chip;
 	struct ehrpwm_pwm_chip *pc;
 	struct clk *clk;
 	int ret;
 
-	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
-	if (!pc)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, NUM_PWM_CHANNEL, sizeof(*pc));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	pc = to_ehrpwm_pwm_chip(chip);
 
 	clk = devm_clk_get(&pdev->dev, "fck");
 	if (IS_ERR(clk)) {
@@ -466,9 +467,7 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	pc->chip.dev = &pdev->dev;
-	pc->chip.ops = &ehrpwm_pwm_ops;
-	pc->chip.npwm = NUM_PWM_CHANNEL;
+	chip->ops = &ehrpwm_pwm_ops;
 
 	pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(pc->mmio_base))
@@ -485,13 +484,13 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = pwmchip_add(&pc->chip);
+	ret = pwmchip_add(chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 		goto err_clk_unprepare;
 	}
 
-	platform_set_drvdata(pdev, pc);
+	platform_set_drvdata(pdev, chip);
 	pm_runtime_enable(&pdev->dev);
 
 	return 0;
@@ -504,9 +503,10 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 
 static void ehrpwm_pwm_remove(struct platform_device *pdev)
 {
-	struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 
-	pwmchip_remove(&pc->chip);
+	pwmchip_remove(chip);
 
 	clk_unprepare(pc->tbclk);
 
@@ -514,9 +514,11 @@ static void ehrpwm_pwm_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
+static void ehrpwm_pwm_save_context(struct pwm_chip *chip)
 {
-	pm_runtime_get_sync(pc->chip.dev);
+	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+
+	pm_runtime_get_sync(chip->dev);
 
 	pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL);
 	pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD);
@@ -527,11 +529,13 @@ static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
 	pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC);
 	pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC);
 
-	pm_runtime_put_sync(pc->chip.dev);
+	pm_runtime_put_sync(chip->dev);
 }
 
-static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
+static void ehrpwm_pwm_restore_context(struct pwm_chip *chip)
 {
+	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
+
 	ehrpwm_write(pc->mmio_base, TBPRD, pc->ctx.tbprd);
 	ehrpwm_write(pc->mmio_base, CMPA, pc->ctx.cmpa);
 	ehrpwm_write(pc->mmio_base, CMPB, pc->ctx.cmpb);
@@ -544,13 +548,13 @@ static void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
 
 static int ehrpwm_pwm_suspend(struct device *dev)
 {
-	struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
 	unsigned int i;
 
-	ehrpwm_pwm_save_context(pc);
+	ehrpwm_pwm_save_context(chip);
 
-	for (i = 0; i < pc->chip.npwm; i++) {
-		struct pwm_device *pwm = &pc->chip.pwms[i];
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
 
 		if (!pwm_is_enabled(pwm))
 			continue;
@@ -564,11 +568,11 @@ static int ehrpwm_pwm_suspend(struct device *dev)
 
 static int ehrpwm_pwm_resume(struct device *dev)
 {
-	struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
+	struct pwm_chip *chip = dev_get_drvdata(dev);
 	unsigned int i;
 
-	for (i = 0; i < pc->chip.npwm; i++) {
-		struct pwm_device *pwm = &pc->chip.pwms[i];
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
 
 		if (!pwm_is_enabled(pwm))
 			continue;
@@ -577,7 +581,7 @@ static int ehrpwm_pwm_resume(struct device *dev)
 		pm_runtime_get_sync(dev);
 	}
 
-	ehrpwm_pwm_restore_context(pc);
+	ehrpwm_pwm_restore_context(chip);
 
 	return 0;
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 061/101] pwm: twl-led: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (59 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 060/101] pwm: tiehrpwm: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 062/101] pwm: twl: " Uwe Kleine-König
                   ` (41 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-twl-led driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-twl-led.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
index 625233f4703a..4591ffab7863 100644
--- a/drivers/pwm/pwm-twl-led.c
+++ b/drivers/pwm/pwm-twl-led.c
@@ -62,13 +62,12 @@
 #define TWL6040_LED_MODE_MASK	0x03
 
 struct twl_pwmled_chip {
-	struct pwm_chip chip;
 	struct mutex mutex;
 };
 
 static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip)
 {
-	return container_of(chip, struct twl_pwmled_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -345,25 +344,28 @@ static const struct pwm_ops twl6030_pwmled_ops = {
 
 static int twl_pwmled_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct twl_pwmled_chip *twl;
+	unsigned int npwm;
 
-	twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
-	if (!twl)
-		return -ENOMEM;
+	if (twl_class_is_4030())
+		npwm = 2;
+	else
+		npwm = 1;
 
-	if (twl_class_is_4030()) {
-		twl->chip.ops = &twl4030_pwmled_ops;
-		twl->chip.npwm = 2;
-	} else {
-		twl->chip.ops = &twl6030_pwmled_ops;
-		twl->chip.npwm = 1;
-	}
+	chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*twl));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	twl = to_twl(chip);
 
-	twl->chip.dev = &pdev->dev;
+	if (twl_class_is_4030())
+		chip->ops = &twl4030_pwmled_ops;
+	else
+		chip->ops = &twl6030_pwmled_ops;
 
 	mutex_init(&twl->mutex);
 
-	return devm_pwmchip_add(&pdev->dev, &twl->chip);
+	return devm_pwmchip_add(&pdev->dev, chip);
 }
 
 #ifdef CONFIG_OF
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 062/101] pwm: twl: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (60 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 061/101] pwm: twl-led: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 063/101] pwm: visconti: " Uwe Kleine-König
                   ` (40 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-twol driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-twl.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
index 603d31f27470..d66596c8597d 100644
--- a/drivers/pwm/pwm-twl.c
+++ b/drivers/pwm/pwm-twl.c
@@ -46,7 +46,6 @@
 #define TWL6030_PWM_TOGGLE(pwm, x)	((x) << (pwm * 3))
 
 struct twl_pwm_chip {
-	struct pwm_chip chip;
 	struct mutex mutex;
 	u8 twl6030_toggle3;
 	u8 twl4030_pwm_mux;
@@ -54,7 +53,7 @@ struct twl_pwm_chip {
 
 static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
 {
-	return container_of(chip, struct twl_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -341,23 +340,22 @@ static const struct pwm_ops twl6030_pwm_ops = {
 
 static int twl_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct twl_pwm_chip *twl;
 
-	twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
-	if (!twl)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(&pdev->dev, 2, sizeof(*twl));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	twl = to_twl(chip);
 
 	if (twl_class_is_4030())
-		twl->chip.ops = &twl4030_pwm_ops;
+		chip->ops = &twl4030_pwm_ops;
 	else
-		twl->chip.ops = &twl6030_pwm_ops;
-
-	twl->chip.dev = &pdev->dev;
-	twl->chip.npwm = 2;
+		chip->ops = &twl6030_pwm_ops;
 
 	mutex_init(&twl->mutex);
 
-	return devm_pwmchip_add(&pdev->dev, &twl->chip);
+	return devm_pwmchip_add(&pdev->dev, chip);
 }
 
 #ifdef CONFIG_OF
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 063/101] pwm: visconti: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (61 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 062/101] pwm: twl: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 064/101] pwm: vt8500: " Uwe Kleine-König
                   ` (39 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-visconti driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-visconti.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-visconti.c b/drivers/pwm/pwm-visconti.c
index 8d736d558122..64ca4059a5a0 100644
--- a/drivers/pwm/pwm-visconti.c
+++ b/drivers/pwm/pwm-visconti.c
@@ -34,13 +34,12 @@
 #define PIPGM_PWMC_POLARITY_MASK	GENMASK(5, 5)
 
 struct visconti_pwm_chip {
-	struct pwm_chip chip;
 	void __iomem *base;
 };
 
 static inline struct visconti_pwm_chip *visconti_pwm_from_chip(struct pwm_chip *chip)
 {
-	return container_of(chip, struct visconti_pwm_chip, chip);
+	return pwmchip_priv(chip);
 }
 
 static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -134,22 +133,22 @@ static const struct pwm_ops visconti_pwm_ops = {
 static int visconti_pwm_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct pwm_chip *chip;
 	struct visconti_pwm_chip *priv;
 	int ret;
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, 4, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = visconti_pwm_from_chip(chip);
 
 	priv->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(priv->base))
 		return PTR_ERR(priv->base);
 
-	priv->chip.dev = dev;
-	priv->chip.ops = &visconti_pwm_ops;
-	priv->chip.npwm = 4;
+	chip->ops = &visconti_pwm_ops;
 
-	ret = devm_pwmchip_add(&pdev->dev, &priv->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "Cannot register visconti PWM\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 064/101] pwm: vt8500: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (62 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 063/101] pwm: visconti: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 065/101] pwm: xilinx: " Uwe Kleine-König
                   ` (38 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-vt8500 driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-vt8500.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index 47c3abe82f97..41d9f1a0f74f 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -45,12 +45,14 @@
 #define STATUS_ALL_UPDATE	0x0F
 
 struct vt8500_chip {
-	struct pwm_chip chip;
 	void __iomem *base;
 	struct clk *clk;
 };
 
-#define to_vt8500_chip(chip)	container_of(chip, struct vt8500_chip, chip)
+static inline struct vt8500_chip *to_vt8500_chip(struct pwm_chip *chip)
+{
+	return pwmchip_priv(chip);
+}
 
 #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
 static inline int vt8500_pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 bitmask)
@@ -240,6 +242,7 @@ MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids);
 
 static int vt8500_pwm_probe(struct platform_device *pdev)
 {
+	struct pwm_chip *chip;
 	struct vt8500_chip *vt8500;
 	struct device_node *np = pdev->dev.of_node;
 	int ret;
@@ -247,13 +250,12 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
 	if (!np)
 		return dev_err_probe(&pdev->dev, -EINVAL, "invalid devicetree node\n");
 
-	vt8500 = devm_kzalloc(&pdev->dev, sizeof(*vt8500), GFP_KERNEL);
-	if (vt8500 == NULL)
+	chip = devm_pwmchip_alloc(&pdev->dev, VT8500_NR_PWMS, sizeof(*vt8500));
+	if (chip == NULL)
 		return -ENOMEM;
+	vt8500 = to_vt8500_chip(chip);
 
-	vt8500->chip.dev = &pdev->dev;
-	vt8500->chip.ops = &vt8500_pwm_ops;
-	vt8500->chip.npwm = VT8500_NR_PWMS;
+	chip->ops = &vt8500_pwm_ops;
 
 	vt8500->clk = devm_clk_get_prepared(&pdev->dev, NULL);
 	if (IS_ERR(vt8500->clk))
@@ -263,7 +265,7 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(vt8500->base))
 		return PTR_ERR(vt8500->base);
 
-	ret = devm_pwmchip_add(&pdev->dev, &vt8500->chip);
+	ret = devm_pwmchip_add(&pdev->dev, chip);
 	if (ret < 0)
 		return dev_err_probe(&pdev->dev, ret, "failed to add PWM chip\n");
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 065/101] pwm: xilinx: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (63 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 064/101] pwm: vt8500: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 066/101] gpio: mvebu: " Uwe Kleine-König
                   ` (37 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm-xilinx driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-xilinx.c | 34 ++++++++++++++--------------------
 1 file changed, 14 insertions(+), 20 deletions(-)

diff --git a/drivers/pwm/pwm-xilinx.c b/drivers/pwm/pwm-xilinx.c
index 5f3c2a6fed11..47184916239b 100644
--- a/drivers/pwm/pwm-xilinx.c
+++ b/drivers/pwm/pwm-xilinx.c
@@ -80,15 +80,10 @@ unsigned int xilinx_timer_get_period(struct xilinx_timer_priv *priv,
 #define TCSR_PWM_CLEAR (TCSR_MDT | TCSR_LOAD)
 #define TCSR_PWM_MASK (TCSR_PWM_SET | TCSR_PWM_CLEAR)
 
-struct xilinx_pwm_device {
-	struct pwm_chip chip;
-	struct xilinx_timer_priv priv;
-};
-
 static inline struct xilinx_timer_priv
 *xilinx_pwm_chip_to_priv(struct pwm_chip *chip)
 {
-	return &container_of(chip, struct xilinx_pwm_device, chip)->priv;
+	return pwmchip_priv(chip);
 }
 
 static bool xilinx_timer_pwm_enabled(u32 tcsr0, u32 tcsr1)
@@ -213,8 +208,8 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
 	int ret;
 	struct device *dev = &pdev->dev;
 	struct device_node *np = dev->of_node;
+	struct pwm_chip *chip;
 	struct xilinx_timer_priv *priv;
-	struct xilinx_pwm_device *xilinx_pwm;
 	u32 pwm_cells, one_timer, width;
 	void __iomem *regs;
 
@@ -225,11 +220,11 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(dev, ret, "could not read #pwm-cells\n");
 
-	xilinx_pwm = devm_kzalloc(dev, sizeof(*xilinx_pwm), GFP_KERNEL);
-	if (!xilinx_pwm)
-		return -ENOMEM;
-	platform_set_drvdata(pdev, xilinx_pwm);
-	priv = &xilinx_pwm->priv;
+	chip = devm_pwmchip_alloc(dev, 1, sizeof(*priv));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	priv = xilinx_pwm_chip_to_priv(chip);
+	platform_set_drvdata(pdev, chip);
 
 	regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(regs))
@@ -278,10 +273,8 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, ret, "Clock enable failed\n");
 	clk_rate_exclusive_get(priv->clk);
 
-	xilinx_pwm->chip.dev = dev;
-	xilinx_pwm->chip.ops = &xilinx_pwm_ops;
-	xilinx_pwm->chip.npwm = 1;
-	ret = pwmchip_add(&xilinx_pwm->chip);
+	chip->ops = &xilinx_pwm_ops;
+	ret = pwmchip_add(chip);
 	if (ret) {
 		clk_rate_exclusive_put(priv->clk);
 		clk_disable_unprepare(priv->clk);
@@ -293,11 +286,12 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
 
 static void xilinx_pwm_remove(struct platform_device *pdev)
 {
-	struct xilinx_pwm_device *xilinx_pwm = platform_get_drvdata(pdev);
+	struct pwm_chip *chip = platform_get_drvdata(pdev);
+	struct xilinx_timer_priv *priv = xilinx_pwm_chip_to_priv(chip);
 
-	pwmchip_remove(&xilinx_pwm->chip);
-	clk_rate_exclusive_put(xilinx_pwm->priv.clk);
-	clk_disable_unprepare(xilinx_pwm->priv.clk);
+	pwmchip_remove(chip);
+	clk_rate_exclusive_put(priv->clk);
+	clk_disable_unprepare(priv->clk);
 }
 
 static const struct of_device_id xilinx_pwm_of_match[] = {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 066/101] gpio: mvebu: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (64 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 065/101] pwm: xilinx: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 067/101] drm/bridge: ti-sn65dsi86: " Uwe Kleine-König
                   ` (36 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm sub-driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/gpio/gpio-mvebu.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index b8387fea630e..6dec099dcc7d 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -98,7 +98,6 @@ struct mvebu_pwm {
 	u32			 offset;
 	unsigned long		 clk_rate;
 	struct gpio_desc	*gpiod;
-	struct pwm_chip		 chip;
 	spinlock_t		 lock;
 	struct mvebu_gpio_chip	*mvchip;
 
@@ -614,7 +613,7 @@ static const struct regmap_config mvebu_gpio_regmap_config = {
  */
 static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip)
 {
-	return container_of(chip, struct mvebu_pwm, chip);
+	return pwmchip_priv(chip);
 }
 
 static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -788,6 +787,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
 {
 	struct device *dev = &pdev->dev;
 	struct mvebu_pwm *mvpwm;
+	struct pwm_chip *chip;
 	void __iomem *base;
 	u32 offset;
 	u32 set;
@@ -812,9 +812,11 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
 	if (IS_ERR(mvchip->clk))
 		return PTR_ERR(mvchip->clk);
 
-	mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
-	if (!mvpwm)
-		return -ENOMEM;
+	chip = devm_pwmchip_alloc(dev, mvchip->chip.ngpio, sizeof(struct mvebu_pwm));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+	mvpwm = pwmchip_priv(chip);
+
 	mvchip->mvpwm = mvpwm;
 	mvpwm->mvchip = mvchip;
 	mvpwm->offset = offset;
@@ -867,13 +869,11 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
 		return -EINVAL;
 	}
 
-	mvpwm->chip.dev = dev;
-	mvpwm->chip.ops = &mvebu_pwm_ops;
-	mvpwm->chip.npwm = mvchip->chip.ngpio;
+	chip->ops = &mvebu_pwm_ops;
 
 	spin_lock_init(&mvpwm->lock);
 
-	return devm_pwmchip_add(dev, &mvpwm->chip);
+	return devm_pwmchip_add(dev, chip);
 }
 
 #ifdef CONFIG_DEBUG_FS
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 067/101] drm/bridge: ti-sn65dsi86: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (65 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 066/101] gpio: mvebu: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 068/101] leds: qcom-lpg: " Uwe Kleine-König
                   ` (35 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm driver of the ti-sn65dsi86 to further changes of
the pwm core outlined in the commit introducing devm_pwmchip_alloc().
There is no intended semantical change and the driver should behave as
before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/gpu/drm/bridge/ti-sn65dsi86.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 53d133d18c18..1469993acda9 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -197,7 +197,7 @@ struct ti_sn65dsi86 {
 	DECLARE_BITMAP(gchip_output, SN_NUM_GPIOS);
 #endif
 #if defined(CONFIG_PWM)
-	struct pwm_chip			pchip;
+	struct pwm_chip			*pchip;
 	bool				pwm_enabled;
 	atomic_t			pwm_pin_busy;
 #endif
@@ -1363,7 +1363,8 @@ static void ti_sn_pwm_pin_release(struct ti_sn65dsi86 *pdata)
 
 static struct ti_sn65dsi86 *pwm_chip_to_ti_sn_bridge(struct pwm_chip *chip)
 {
-	return container_of(chip, struct ti_sn65dsi86, pchip);
+	struct ti_sn65dsi86 **pdata = pwmchip_priv(chip);
+	return *pdata;
 }
 
 static int ti_sn_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -1576,22 +1577,28 @@ static const struct pwm_ops ti_sn_pwm_ops = {
 static int ti_sn_pwm_probe(struct auxiliary_device *adev,
 			   const struct auxiliary_device_id *id)
 {
+	struct pwm_chip *chip;
 	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
 
-	pdata->pchip.dev = pdata->dev;
-	pdata->pchip.ops = &ti_sn_pwm_ops;
-	pdata->pchip.npwm = 1;
-	pdata->pchip.of_xlate = of_pwm_single_xlate;
-	pdata->pchip.of_pwm_n_cells = 1;
+	/* XXX: should this better use adev->dev instead of pdata->dev? */
+	pdata->pchip = chip = devm_pwmchip_alloc(pdata->dev, 1, sizeof(&pdata));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
-	return pwmchip_add(&pdata->pchip);
+	*(struct ti_sn65dsi86 **)pwmchip_priv(chip) = pdata;
+
+	chip->ops = &ti_sn_pwm_ops;
+	chip->of_xlate = of_pwm_single_xlate;
+	chip->of_pwm_n_cells = 1;
+
+	return pwmchip_add(chip);
 }
 
 static void ti_sn_pwm_remove(struct auxiliary_device *adev)
 {
 	struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent);
 
-	pwmchip_remove(&pdata->pchip);
+	pwmchip_remove(pdata->pchip);
 
 	if (pdata->pwm_enabled)
 		pm_runtime_put_sync(pdata->dev);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 068/101] leds: qcom-lpg: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (66 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 067/101] drm/bridge: ti-sn65dsi86: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:18 ` [PATCH v1 069/101] staging: greybus: pwm: " Uwe Kleine-König
                   ` (34 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the pwm sub-driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/leds/rgb/leds-qcom-lpg.c | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c
index 9e5a03f66543..182412cb0384 100644
--- a/drivers/leds/rgb/leds-qcom-lpg.c
+++ b/drivers/leds/rgb/leds-qcom-lpg.c
@@ -78,7 +78,7 @@ struct lpg {
 
 	struct mutex lock;
 
-	struct pwm_chip pwm;
+	struct pwm_chip *pwm;
 
 	const struct lpg_data *data;
 
@@ -978,9 +978,15 @@ static int lpg_pattern_mc_clear(struct led_classdev *cdev)
 	return lpg_pattern_clear(led);
 }
 
+static inline struct lpg *lpg_pwm_from_chip(struct pwm_chip *chip)
+{
+	struct lpg **lpg = pwmchip_priv(chip);
+	return *lpg;
+}
+
 static int lpg_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	struct lpg *lpg = container_of(chip, struct lpg, pwm);
+	struct lpg *lpg = lpg_pwm_from_chip(chip);
 	struct lpg_channel *chan = &lpg->channels[pwm->hwpwm];
 
 	return chan->in_use ? -EBUSY : 0;
@@ -996,7 +1002,7 @@ static int lpg_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 			 const struct pwm_state *state)
 {
-	struct lpg *lpg = container_of(chip, struct lpg, pwm);
+	struct lpg *lpg = lpg_pwm_from_chip(chip);
 	struct lpg_channel *chan = &lpg->channels[pwm->hwpwm];
 	int ret = 0;
 
@@ -1027,7 +1033,7 @@ static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 			     struct pwm_state *state)
 {
-	struct lpg *lpg = container_of(chip, struct lpg, pwm);
+	struct lpg *lpg = lpg_pwm_from_chip(chip);
 	struct lpg_channel *chan = &lpg->channels[pwm->hwpwm];
 	unsigned int resolution;
 	unsigned int pre_div;
@@ -1090,13 +1096,19 @@ static const struct pwm_ops lpg_pwm_ops = {
 
 static int lpg_add_pwm(struct lpg *lpg)
 {
+	struct pwm_chip *chip;
 	int ret;
 
-	lpg->pwm.dev = lpg->dev;
-	lpg->pwm.npwm = lpg->num_channels;
-	lpg->pwm.ops = &lpg_pwm_ops;
+	lpg->pwm = chip = devm_pwmchip_alloc(lpg->dev, lpg->num_channels,
+					     sizeof(&lpg));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
 
-	ret = pwmchip_add(&lpg->pwm);
+	*(struct lpg **)pwmchip_priv(chip) = lpg;
+
+	chip->ops = &lpg_pwm_ops;
+
+	ret = pwmchip_add(chip);
 	if (ret)
 		dev_err(lpg->dev, "failed to add PWM chip: ret %d\n", ret);
 
@@ -1368,7 +1380,7 @@ static int lpg_remove(struct platform_device *pdev)
 {
 	struct lpg *lpg = platform_get_drvdata(pdev);
 
-	pwmchip_remove(&lpg->pwm);
+	pwmchip_remove(lpg->pwm);
 
 	return 0;
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 069/101] staging: greybus: pwm: Make use of devm_pwmchip_alloc() function
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (67 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 068/101] leds: qcom-lpg: " Uwe Kleine-König
@ 2023-08-08 17:18 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip Uwe Kleine-König
                   ` (33 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:18 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

This prepares the greybus pwm driver to further changes of the pwm core
outlined in the commit introducing devm_pwmchip_alloc(). There is no
intended semantical change and the driver should behave as before.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/staging/greybus/pwm.c | 63 +++++++++--------------------------
 1 file changed, 15 insertions(+), 48 deletions(-)

diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c
index a3cb68cfa0f9..60b3bddae08a 100644
--- a/drivers/staging/greybus/pwm.c
+++ b/drivers/staging/greybus/pwm.c
@@ -16,7 +16,6 @@
 
 struct gb_pwm_chip {
 	struct gb_connection	*connection;
-	u8			pwm_max;	/* max pwm number */
 
 	struct pwm_chip		chip;
 };
@@ -26,19 +25,6 @@ static inline struct gb_pwm_chip *pwm_chip_to_gb_pwm_chip(struct pwm_chip *chip)
 	return container_of(chip, struct gb_pwm_chip, chip);
 }
 
-static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
-{
-	struct gb_pwm_count_response response;
-	int ret;
-
-	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
-				NULL, 0, &response, sizeof(response));
-	if (ret)
-		return ret;
-	pwmc->pwm_max = response.count;
-	return 0;
-}
-
 static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
 				     u8 which)
 {
@@ -46,9 +32,6 @@ static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
 	struct gbphy_device *gbphy_dev;
 	int ret;
 
-	if (which > pwmc->pwm_max)
-		return -EINVAL;
-
 	request.which = which;
 
 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
@@ -71,9 +54,6 @@ static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
 	struct gbphy_device *gbphy_dev;
 	int ret;
 
-	if (which > pwmc->pwm_max)
-		return -EINVAL;
-
 	request.which = which;
 
 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
@@ -96,9 +76,6 @@ static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
 	struct gbphy_device *gbphy_dev;
 	int ret;
 
-	if (which > pwmc->pwm_max)
-		return -EINVAL;
-
 	request.which = which;
 	request.duty = cpu_to_le32(duty);
 	request.period = cpu_to_le32(period);
@@ -123,9 +100,6 @@ static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
 	struct gbphy_device *gbphy_dev;
 	int ret;
 
-	if (which > pwmc->pwm_max)
-		return -EINVAL;
-
 	request.which = which;
 	request.polarity = polarity;
 
@@ -149,9 +123,6 @@ static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
 	struct gbphy_device *gbphy_dev;
 	int ret;
 
-	if (which > pwmc->pwm_max)
-		return -EINVAL;
-
 	request.which = which;
 
 	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
@@ -174,9 +145,6 @@ static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
 	struct gbphy_device *gbphy_dev;
 	int ret;
 
-	if (which > pwmc->pwm_max)
-		return -EINVAL;
-
 	request.which = which;
 
 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
@@ -266,20 +234,28 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
 	struct gb_connection *connection;
 	struct gb_pwm_chip *pwmc;
 	struct pwm_chip *chip;
+	struct gb_pwm_count_response response;
 	int ret;
 
-	pwmc = kzalloc(sizeof(*pwmc), GFP_KERNEL);
-	if (!pwmc)
-		return -ENOMEM;
-
 	connection = gb_connection_create(gbphy_dev->bundle,
 					  le16_to_cpu(gbphy_dev->cport_desc->id),
 					  NULL);
-	if (IS_ERR(connection)) {
-		ret = PTR_ERR(connection);
-		goto exit_pwmc_free;
+	if (IS_ERR(connection))
+		return PTR_ERR(connection);
+
+	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PWM_COUNT,
+				NULL, 0, &response, sizeof(response));
+	if (ret)
+		goto exit_connection_destroy;
+
+	chip = devm_pwmchip_alloc(&gbphy_dev->dev, response.count, sizeof(*pwmc));
+	if (IS_ERR(chip)) {
+		ret = PTR_ERR(chip);
+		goto exit_connection_destroy;
 	}
 
+	pwmc = pwmchip_priv(chip);
+
 	pwmc->connection = connection;
 	gb_connection_set_data(connection, pwmc);
 	gb_gbphy_set_data(gbphy_dev, pwmc);
@@ -288,16 +264,9 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
 	if (ret)
 		goto exit_connection_destroy;
 
-	/* Query number of pwms present */
-	ret = gb_pwm_count_operation(pwmc);
-	if (ret)
-		goto exit_connection_disable;
-
 	chip = &pwmc->chip;
 
-	chip->dev = &gbphy_dev->dev;
 	chip->ops = &gb_pwm_ops;
-	chip->npwm = pwmc->pwm_max + 1;
 
 	ret = pwmchip_add(chip);
 	if (ret) {
@@ -313,8 +282,6 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
 	gb_connection_disable(connection);
 exit_connection_destroy:
 	gb_connection_destroy(connection);
-exit_pwmc_free:
-	kfree(pwmc);
 	return ret;
 }
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (68 preceding siblings ...)
  2023-08-08 17:18 ` [PATCH v1 069/101] staging: greybus: pwm: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-10-06  9:38   ` Thierry Reding
  2023-08-08 17:19 ` [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data Uwe Kleine-König
                   ` (32 subsequent siblings)
  102 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

It's required to not free the memory underlying a requested PWM
while a consumer still has a reference to it. While currently a pwm_chip
doesn't life long enough in all cases, linking the struct pwm to the
pwm_chip results in the right lifetime as soon as the pwmchip is living
long enough. This happens with the following commits.

Note this is a breaking change for all pwm drivers that don't use
pwmchip_alloc().

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

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index cfcddf62ab01..3b8d41fdda1b 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -198,7 +198,7 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
 
 void *pwmchip_priv(struct pwm_chip *chip)
 {
-	return &chip[1];
+	return &chip->pwms[chip->npwm];
 }
 EXPORT_SYMBOL_GPL(pwmchip_priv);
 
@@ -208,7 +208,7 @@ struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
 	size_t alloc_size;
 	unsigned int i;
 
-	alloc_size = sizeof(*chip) + sizeof_priv;
+	alloc_size = sizeof(*chip) + npwm * sizeof(struct pwm_device) + sizeof_priv;
 
 	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
 	if (!chip)
@@ -217,6 +217,13 @@ struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
 	chip->dev = parent;
 	chip->npwm = npwm;
 
+	for (i = 0; i < chip->npwm; i++) {
+		struct pwm_device *pwm = &chip->pwms[i];
+
+		pwm->chip = chip;
+		pwm->hwpwm = i;
+	}
+
 	return chip;
 }
 EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
@@ -243,26 +250,15 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 
 	chip->owner = owner;
 
-	chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL);
-	if (!chip->pwms)
-		return -ENOMEM;
-
 	mutex_lock(&pwm_lock);
 
 	ret = idr_alloc(&pwmchip_idr, chip, 0, 0, GFP_KERNEL);
 	if (ret < 0) {
 		mutex_unlock(&pwm_lock);
-		kfree(chip->pwms);
 		return ret;
 	}
 
 	chip->id = ret;
-	for (i = 0; i < chip->npwm; i++) {
-		struct pwm_device *pwm = &chip->pwms[i];
-
-		pwm->chip = chip;
-		pwm->hwpwm = i;
-	}
 
 	mutex_unlock(&pwm_lock);
 
@@ -293,8 +289,6 @@ void pwmchip_remove(struct pwm_chip *chip)
 	idr_remove(&pwmchip_idr, chip->id);
 
 	mutex_unlock(&pwm_lock);
-
-	kfree(chip->pwms);
 }
 EXPORT_SYMBOL_GPL(pwmchip_remove);
 
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 3c0da17e193c..fbcba204de44 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -301,7 +301,7 @@ struct pwm_chip {
 	unsigned int of_pwm_n_cells;
 
 	/* only used internally by the PWM framework */
-	struct pwm_device *pwms;
+	struct pwm_device pwms[];
 };
 
 #if IS_ENABLED(CONFIG_PWM)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (69 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-10-06  9:41   ` Thierry Reding
  2023-08-08 17:19 ` [PATCH v1 072/101] pwm: atmel: Stop using struct pwm_chip::dev Uwe Kleine-König
                   ` (31 subsequent siblings)
  102 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-ab8500.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c
index f64f3fd251e7..663fdfe90bb6 100644
--- a/drivers/pwm/pwm-ab8500.c
+++ b/drivers/pwm/pwm-ab8500.c
@@ -24,6 +24,7 @@
 #define AB8500_PWM_CLKRATE 9600000
 
 struct ab8500_pwm_chip {
+	struct device *parent;
 	unsigned int hwid;
 };
 
@@ -91,7 +92,7 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	 * when disabled.
 	 */
 	if (!state->enabled || duty_steps == 0) {
-		ret = abx500_mask_and_set_register_interruptible(chip->dev,
+		ret = abx500_mask_and_set_register_interruptible(ab8500->parent,
 					AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
 					1 << ab8500->hwid, 0);
 
@@ -111,18 +112,18 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	reg = AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2);
 
-	ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
+	ret = abx500_set_register_interruptible(ab8500->parent, AB8500_MISC,
 			reg, lower_val);
 	if (ret < 0)
 		return ret;
 
-	ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
+	ret = abx500_set_register_interruptible(ab8500->parent, AB8500_MISC,
 			(reg + 1), higher_val);
 	if (ret < 0)
 		return ret;
 
 	/* enable */
-	ret = abx500_mask_and_set_register_interruptible(chip->dev,
+	ret = abx500_mask_and_set_register_interruptible(ab8500->parent,
 				AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
 				1 << ab8500->hwid, 1 << ab8500->hwid);
 
@@ -137,7 +138,7 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);
 	unsigned int div, duty_steps;
 
-	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
+	ret = abx500_get_register_interruptible(ab8500->parent, AB8500_MISC,
 						AB8500_PWM_OUT_CTRL7_REG,
 						&ctrl7);
 	if (ret)
@@ -150,13 +151,13 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 		return 0;
 	}
 
-	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
+	ret = abx500_get_register_interruptible(ab8500->parent, AB8500_MISC,
 						AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2),
 						&lower_val);
 	if (ret)
 		return ret;
 
-	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
+	ret = abx500_get_register_interruptible(ab8500->parent, AB8500_MISC,
 						AB8500_PWM_OUT_CTRL2_REG + (ab8500->hwid * 2),
 						&higher_val);
 	if (ret)
@@ -196,6 +197,7 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
 	ab8500 = pwmchip_priv(chip);
 
 	chip->ops = &ab8500_pwm_ops;
+	ab8500->parent = &pdev->dev;
 	ab8500->hwid = pdev->id - 1;
 
 	err = devm_pwmchip_add(&pdev->dev, chip);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 072/101] pwm: atmel: Stop using struct pwm_chip::dev
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (70 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 073/101] pwm: dwc: Store parent device in driver data Uwe Kleine-König
                   ` (30 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, pass the parent
device pointer to atmel_pwm_enable_clk_if_on().

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-atmel.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 48b79b8488a4..0f6a53a14dd0 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -455,7 +455,7 @@ static const struct of_device_id atmel_pwm_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
 
-static int atmel_pwm_enable_clk_if_on(struct pwm_chip *chip, bool on)
+static int atmel_pwm_enable_clk_if_on(struct device *dev, struct pwm_chip *chip, bool on)
 {
 	struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
 	unsigned int i, cnt = 0;
@@ -474,7 +474,7 @@ static int atmel_pwm_enable_clk_if_on(struct pwm_chip *chip, bool on)
 	for (i = 0; i < cnt; i++) {
 		ret = clk_enable(atmel_pwm->clk);
 		if (ret) {
-			dev_err_probe(chip->dev, ret,
+			dev_err_probe(dev, ret,
 				"failed to enable clock for pwm\n");
 
 			cnt = i;
@@ -518,7 +518,7 @@ static int atmel_pwm_probe(struct platform_device *pdev)
 
 	chip->ops = &atmel_pwm_ops;
 
-	ret = atmel_pwm_enable_clk_if_on(chip, true);
+	ret = atmel_pwm_enable_clk_if_on(&pdev->dev, chip, true);
 	if (ret < 0)
 		return ret;
 
@@ -531,7 +531,7 @@ static int atmel_pwm_probe(struct platform_device *pdev)
 	return 0;
 
 disable_clk:
-	atmel_pwm_enable_clk_if_on(chip, false);
+	atmel_pwm_enable_clk_if_on(&pdev->dev, chip, false);
 
 	return ret;
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 073/101] pwm: dwc: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (71 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 072/101] pwm: atmel: Stop using struct pwm_chip::dev Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 074/101] pwm: ep93xx: " Uwe Kleine-König
                   ` (29 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-dwc.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c
index 19b9a23d5ee1..71e322e045f8 100644
--- a/drivers/pwm/pwm-dwc.c
+++ b/drivers/pwm/pwm-dwc.c
@@ -51,6 +51,7 @@ struct dwc_pwm_ctx {
 };
 
 struct dwc_pwm {
+	struct device *parent;
 	void __iomem *base;
 	struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
 };
@@ -153,12 +154,12 @@ static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	if (state->enabled) {
 		if (!pwm->state.enabled)
-			pm_runtime_get_sync(chip->dev);
+			pm_runtime_get_sync(dwc->parent);
 		return __dwc_pwm_configure_timer(dwc, pwm, state);
 	} else {
 		if (pwm->state.enabled) {
 			__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
-			pm_runtime_put_sync(chip->dev);
+			pm_runtime_put_sync(dwc->parent);
 		}
 	}
 
@@ -171,7 +172,7 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	struct dwc_pwm *dwc = to_dwc_pwm(chip);
 	u64 duty, period;
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(dwc->parent);
 
 	state->enabled = !!(dwc_pwm_readl(dwc,
 				DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN);
@@ -189,7 +190,7 @@ static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	state->polarity = PWM_POLARITY_INVERSED;
 
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(dwc->parent);
 
 	return 0;
 }
@@ -202,8 +203,9 @@ static const struct pwm_ops dwc_pwm_ops = {
 static struct pwm_chip *dwc_pwm_alloc(struct device *dev)
 {
 	struct pwm_chip *chip;
+	struct dwc_pwm *dwc;
 
-	chip = devm_pwmchip_alloc(dev, DWC_TIMERS_TOTAL, sizeof(struct dwc_pwm));
+	chip = devm_pwmchip_alloc(dev, DWC_TIMERS_TOTAL, sizeof(*dwc));
 	if (!chip)
 		return NULL;
 
@@ -211,6 +213,9 @@ static struct pwm_chip *dwc_pwm_alloc(struct device *dev)
 
 	dev_set_drvdata(dev, chip);
 
+	dwc = to_dwc_pwm(chip);
+	dwc->parent = dev;
+
 	return chip;
 }
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 074/101] pwm: ep93xx: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (72 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 073/101] pwm: dwc: Store parent device in driver data Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 075/101] pwm: fsl-ftm: " Uwe Kleine-König
                   ` (28 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-ep93xx.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c
index 394013c545ac..4d5147b403a4 100644
--- a/drivers/pwm/pwm-ep93xx.c
+++ b/drivers/pwm/pwm-ep93xx.c
@@ -34,6 +34,7 @@
 #define EP93XX_PWMx_INVERT	0x0c
 
 struct ep93xx_pwm {
+	struct platform_device *pdev;
 	void __iomem *base;
 	struct clk *clk;
 };
@@ -45,16 +46,16 @@ static inline struct ep93xx_pwm *to_ep93xx_pwm(struct pwm_chip *chip)
 
 static int ep93xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	struct platform_device *pdev = to_platform_device(chip->dev);
+	struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
 
-	return ep93xx_pwm_acquire_gpio(pdev);
+	return ep93xx_pwm_acquire_gpio(ep93xx_pwm->pdev);
 }
 
 static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	struct platform_device *pdev = to_platform_device(chip->dev);
+	struct ep93xx_pwm *ep93xx_pwm = to_ep93xx_pwm(chip);
 
-	ep93xx_pwm_release_gpio(pdev);
+	ep93xx_pwm_release_gpio(ep93xx_pwm->pdev);
 }
 
 static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -171,6 +172,8 @@ static int ep93xx_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	ep93xx_pwm = to_ep93xx_pwm(chip);
 
+	ep93xx_pwm->pdev = pdev;
+
 	ep93xx_pwm->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(ep93xx_pwm->base))
 		return PTR_ERR(ep93xx_pwm->base);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 075/101] pwm: fsl-ftm: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (73 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 074/101] pwm: ep93xx: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 076/101] pwm: img: Make use of parent device pointer " Uwe Kleine-König
                   ` (27 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-fsl-ftm.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index f56c7e9f491a..48e37a9df629 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -40,6 +40,7 @@ struct fsl_pwm_periodcfg {
 };
 
 struct fsl_pwm_chip {
+	struct device *parent;
 	struct mutex lock;
 	struct regmap *regmap;
 
@@ -232,7 +233,7 @@ static int fsl_pwm_apply_config(struct pwm_chip *chip,
 	bool do_write_period = false;
 
 	if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {
-		dev_err(chip->dev, "failed to calculate new period\n");
+		dev_err(fpc->parent, "failed to calculate new period\n");
 		return -EINVAL;
 	}
 
@@ -246,7 +247,7 @@ static int fsl_pwm_apply_config(struct pwm_chip *chip,
 	 */
 	else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {
 		if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {
-			dev_err(chip->dev,
+			dev_err(fpc->parent,
 				"Cannot change period for PWM %u, disable other PWMs first\n",
 				pwm->hwpwm);
 			return -EBUSY;
@@ -404,6 +405,7 @@ static int fsl_pwm_probe(struct platform_device *pdev)
 
 	mutex_init(&fpc->lock);
 
+	fpc->parent = &pdev->dev;
 	fpc->soc = of_device_get_match_data(&pdev->dev);
 
 	base = devm_platform_ioremap_resource(pdev, 0);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 076/101] pwm: img: Make use of parent device pointer in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (74 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 075/101] pwm: fsl-ftm: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 077/101] pwm: imx27: Store parent device " Uwe Kleine-König
                   ` (26 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, make use of the
already existing pointer to the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-img.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c
index 64e35ca1b576..18776e2ca054 100644
--- a/drivers/pwm/pwm-img.c
+++ b/drivers/pwm/pwm-img.c
@@ -98,7 +98,7 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	if (period_ns < imgchip->min_period_ns ||
 	    period_ns > imgchip->max_period_ns) {
-		dev_err(chip->dev, "configured period not in range\n");
+		dev_err(imgchip->dev, "configured period not in range\n");
 		return -ERANGE;
 	}
 
@@ -119,14 +119,14 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		div = PWM_CTRL_CFG_SUB_DIV0_DIV1;
 		timebase = DIV_ROUND_UP(mul, 512);
 	} else {
-		dev_err(chip->dev,
+		dev_err(imgchip->dev,
 			"failed to configure timebase steps/divider value\n");
 		return -EINVAL;
 	}
 
 	duty = DIV_ROUND_UP(timebase * duty_ns, period_ns);
 
-	ret = pm_runtime_resume_and_get(chip->dev);
+	ret = pm_runtime_resume_and_get(imgchip->dev);
 	if (ret < 0)
 		return ret;
 
@@ -140,8 +140,8 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	      (timebase << PWM_CH_CFG_TMBASE_SHIFT);
 	img_pwm_writel(imgchip, PWM_CH_CFG(pwm->hwpwm), val);
 
-	pm_runtime_mark_last_busy(chip->dev);
-	pm_runtime_put_autosuspend(chip->dev);
+	pm_runtime_mark_last_busy(imgchip->dev);
+	pm_runtime_put_autosuspend(imgchip->dev);
 
 	return 0;
 }
@@ -152,7 +152,7 @@ static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	struct img_pwm_chip *imgchip = to_img_pwm_chip(chip);
 	int ret;
 
-	ret = pm_runtime_resume_and_get(chip->dev);
+	ret = pm_runtime_resume_and_get(imgchip->dev);
 	if (ret < 0)
 		return ret;
 
@@ -176,8 +176,8 @@ static void img_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	val &= ~BIT(pwm->hwpwm);
 	img_pwm_writel(imgchip, PWM_CTRL_CFG, val);
 
-	pm_runtime_mark_last_busy(chip->dev);
-	pm_runtime_put_autosuspend(chip->dev);
+	pm_runtime_mark_last_busy(imgchip->dev);
+	pm_runtime_put_autosuspend(imgchip->dev);
 }
 
 static int img_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 077/101] pwm: imx27: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (75 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 076/101] pwm: img: Make use of parent device pointer " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 078/101] pwm: jz4740: " Uwe Kleine-König
                   ` (25 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-imx27.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c
index 79af72fbcec3..cdda3967c6c0 100644
--- a/drivers/pwm/pwm-imx27.c
+++ b/drivers/pwm/pwm-imx27.c
@@ -80,6 +80,7 @@
 #define MX3_PWMPR_MAX			0xfffe
 
 struct pwm_imx27_chip {
+	struct device *parent;
 	struct clk	*clk_ipg;
 	struct clk	*clk_per;
 	void __iomem	*mmio_base;
@@ -147,7 +148,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip,
 		state->polarity = PWM_POLARITY_INVERSED;
 		break;
 	default:
-		dev_warn(chip->dev, "can't set polarity, output disconnected");
+		dev_warn(imx->parent, "can't set polarity, output disconnected");
 	}
 
 	prescaler = MX3_PWMCR_PRESCALER_GET(val);
@@ -179,7 +180,7 @@ static int pwm_imx27_get_state(struct pwm_chip *chip,
 static void pwm_imx27_sw_reset(struct pwm_chip *chip)
 {
 	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
-	struct device *dev = chip->dev;
+	struct device *dev = imx->parent;
 	int wait_count = 0;
 	u32 cr;
 
@@ -198,7 +199,7 @@ static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip,
 				     struct pwm_device *pwm)
 {
 	struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
-	struct device *dev = chip->dev;
+	struct device *dev = imx->parent;
 	unsigned int period_ms;
 	int fifoav;
 	u32 sr;
@@ -318,6 +319,7 @@ static int pwm_imx27_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	imx = pwmchip_priv(chip);
 
+	imx->parent = &pdev->dev;
 	imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
 	if (IS_ERR(imx->clk_ipg))
 		return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg),
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 078/101] pwm: jz4740: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (76 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 077/101] pwm: imx27: Store parent device " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 079/101] pwm: lpc18xx-sct: Make use of parent device pointer " Uwe Kleine-König
                   ` (24 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

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

diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index f06010590504..ae25b70c4955 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -25,6 +25,7 @@ struct soc_info {
 };
 
 struct jz4740_pwm_chip {
+	struct device *parent;
 	struct regmap *map;
 	struct clk *clk[];
 };
@@ -37,10 +38,11 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
 static bool jz4740_pwm_can_use_chn(struct pwm_chip *chip,
 				   unsigned int channel)
 {
+	struct jz4740_pwm_chip *jz = to_jz4740(chip);
 	/* Enable all TCU channels for PWM use by default except channels 0/1 */
 	u32 pwm_channels_mask = GENMASK(chip->npwm - 1, 2);
 
-	device_property_read_u32(chip->dev->parent,
+	device_property_read_u32(jz->parent->parent,
 				 "ingenic,pwm-channels-mask",
 				 &pwm_channels_mask);
 
@@ -59,9 +61,9 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	snprintf(name, sizeof(name), "timer%u", pwm->hwpwm);
 
-	clk = clk_get(chip->dev, name);
+	clk = clk_get(jz->parent, name);
 	if (IS_ERR(clk))
-		return dev_err_probe(chip->dev, PTR_ERR(clk),
+		return dev_err_probe(jz->parent, PTR_ERR(clk),
 				     "Failed to get clock\n");
 
 	err = clk_prepare_enable(clk);
@@ -148,7 +150,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	 */
 	rate = clk_round_rate(clk, tmp);
 	if (rate < 0) {
-		dev_err(chip->dev, "Unable to round rate: %ld", rate);
+		dev_err(jz->parent, "Unable to round rate: %ld", rate);
 		return rate;
 	}
 
@@ -169,7 +171,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	err = clk_set_rate(clk, rate);
 	if (err) {
-		dev_err(chip->dev, "Unable to set rate: %d", err);
+		dev_err(jz->parent, "Unable to set rate: %d", err);
 		return err;
 	}
 
@@ -235,6 +237,8 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	jz = to_jz4740(chip);
 
+	jz->parent = &pdev->dev;
+
 	jz->map = device_node_to_regmap(dev->parent->of_node);
 	if (IS_ERR(jz->map)) {
 		dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz->map));
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index fbcba204de44..74f095afffa4 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -290,7 +290,7 @@ struct pwm_ops {
  * @pwms: array of PWM devices allocated by the framework
  */
 struct pwm_chip {
-	struct device *dev;
+	struct device dev;
 	const struct pwm_ops *ops;
 	struct module *owner;
 	int id;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 079/101] pwm: lpc18xx-sct: Make use of parent device pointer in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (77 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 078/101] pwm: jz4740: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 080/101] pwm: lpss: Store parent device " Uwe Kleine-König
                   ` (23 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, make use of the
already existing pointer to the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-lpc18xx-sct.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
index 49eabd9c1e36..cb7e230b1b36 100644
--- a/drivers/pwm/pwm-lpc18xx-sct.c
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -197,7 +197,7 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	if (period_ns < lpc18xx_pwm->min_period_ns ||
 	    period_ns > lpc18xx_pwm->max_period_ns) {
-		dev_err(chip->dev, "period %d not in range\n", period_ns);
+		dev_err(lpc18xx_pwm->dev, "period %d not in range\n", period_ns);
 		return -ERANGE;
 	}
 
@@ -213,7 +213,7 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	 */
 	if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns &&
 	    lpc18xx_pwm->period_ns) {
-		dev_err(chip->dev, "conflicting period requested for PWM %u\n",
+		dev_err(lpc18xx_pwm->dev, "conflicting period requested for PWM %u\n",
 			pwm->hwpwm);
 		mutex_unlock(&lpc18xx_pwm->period_lock);
 		return -EBUSY;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 080/101] pwm: lpss: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (78 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 079/101] pwm: lpc18xx-sct: Make use of parent device pointer " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:49   ` Andy Shevchenko
  2023-08-08 17:19 ` [PATCH v1 081/101] pwm: mediatek: " Uwe Kleine-König
                   ` (22 subsequent siblings)
  102 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-lpss.c | 16 +++++++++-------
 drivers/pwm/pwm-lpss.h |  1 +
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 13087203d05a..105b06f1a6bc 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -106,15 +106,16 @@ static int pwm_lpss_wait_for_update(struct pwm_device *pwm)
 	 */
 	err = readl_poll_timeout(addr, val, !(val & PWM_SW_UPDATE), 40, ms);
 	if (err)
-		dev_err(pwm->chip->dev, "PWM_SW_UPDATE was not cleared\n");
+		dev_err(lpwm->parent, "PWM_SW_UPDATE was not cleared\n");
 
 	return err;
 }
 
 static inline int pwm_lpss_is_updating(struct pwm_device *pwm)
 {
+	struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
 	if (pwm_lpss_read(pwm) & PWM_SW_UPDATE) {
-		dev_err(pwm->chip->dev, "PWM_SW_UPDATE is still set, skipping update\n");
+		dev_err(lpwm->parent, "PWM_SW_UPDATE is still set, skipping update\n");
 		return -EBUSY;
 	}
 
@@ -190,16 +191,16 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	if (state->enabled) {
 		if (!pwm_is_enabled(pwm)) {
-			pm_runtime_get_sync(chip->dev);
+			pm_runtime_get_sync(lpwm->parent);
 			ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
 			if (ret)
-				pm_runtime_put(chip->dev);
+				pm_runtime_put(lpwm->parent);
 		} else {
 			ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
 		}
 	} else if (pwm_is_enabled(pwm)) {
 		pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
-		pm_runtime_put(chip->dev);
+		pm_runtime_put(lpwm->parent);
 	}
 
 	return ret;
@@ -213,7 +214,7 @@ static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	unsigned long long base_unit, freq, on_time_div;
 	u32 ctrl;
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(lpwm->parent);
 
 	base_unit_range = BIT(lpwm->info->base_unit_bits);
 
@@ -235,7 +236,7 @@ static int pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	state->polarity = PWM_POLARITY_NORMAL;
 	state->enabled = !!(ctrl & PWM_ENABLE);
 
-	pm_runtime_put(chip->dev);
+	pm_runtime_put(lpwm->parent);
 
 	return 0;
 }
@@ -262,6 +263,7 @@ struct pwm_chip *devm_pwm_lpss_probe(struct device *dev, void __iomem *base,
 		return ERR_PTR(-ENOMEM);
 	lpwm = to_lpwm(chip);
 
+	lpwm->parent = dev;
 	lpwm->regs = base;
 	lpwm->info = info;
 
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index b5267ab5193b..5ccc607c6811 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -18,6 +18,7 @@
 #define LPSS_MAX_PWMS			4
 
 struct pwm_lpss_chip {
+	struct device *parent;
 	void __iomem *regs;
 	const struct pwm_lpss_boardinfo *info;
 };
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 081/101] pwm: mediatek: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (79 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 080/101] pwm: lpss: Store parent device " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 082/101] pwm: meson: " Uwe Kleine-König
                   ` (21 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-mediatek.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index 68cdeeb1ecf2..11e345474e1a 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -51,6 +51,7 @@ struct pwm_mediatek_of_data {
  * @soc: pointer to chip's platform data
  */
 struct pwm_mediatek_chip {
+	struct device *parent;
 	void __iomem *regs;
 	struct clk *clk_top;
 	struct clk *clk_main;
@@ -149,7 +150,7 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	if (clkdiv > PWM_CLK_DIV_MAX) {
 		pwm_mediatek_clk_disable(chip, pwm);
-		dev_err(chip->dev, "period of %d ns not supported\n", period_ns);
+		dev_err(pc->parent, "period of %d ns not supported\n", period_ns);
 		return -EINVAL;
 	}
 
@@ -246,6 +247,7 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
 	pc = to_pwm_mediatek_chip(chip);
 
 	pc->soc = soc;
+	pc->parent = &pdev->dev;
 
 	pc->regs = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(pc->regs))
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 082/101] pwm: meson: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (80 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 081/101] pwm: mediatek: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 083/101] pwm: mtk-disp: " Uwe Kleine-König
                   ` (20 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-meson.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 3b6a8c9466a2..52cf7ca5aa7f 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -102,6 +102,7 @@ struct meson_pwm_data {
 };
 
 struct meson_pwm {
+	struct device *parent;
 	const struct meson_pwm_data *data;
 	struct meson_pwm_channel channels[MESON_NUM_PWMS];
 	void __iomem *base;
@@ -121,7 +122,7 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct meson_pwm *meson = to_meson_pwm(chip);
 	struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
-	struct device *dev = chip->dev;
+	struct device *dev = meson->parent;
 	int err;
 
 	err = clk_prepare_enable(channel->clk);
@@ -169,19 +170,19 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	fin_freq = clk_round_rate(channel->clk, freq);
 	if (fin_freq == 0) {
-		dev_err(chip->dev, "invalid source clock frequency\n");
+		dev_err(meson->parent, "invalid source clock frequency\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(chip->dev, "fin_freq: %lu Hz\n", fin_freq);
+	dev_dbg(meson->parent, "fin_freq: %lu Hz\n", fin_freq);
 
 	cnt = div_u64(fin_freq * period, NSEC_PER_SEC);
 	if (cnt > 0xffff) {
-		dev_err(chip->dev, "unable to get period cnt\n");
+		dev_err(meson->parent, "unable to get period cnt\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(chip->dev, "period=%llu cnt=%u\n", period, cnt);
+	dev_dbg(meson->parent, "period=%llu cnt=%u\n", period, cnt);
 
 	if (duty == period) {
 		channel->hi = cnt;
@@ -192,7 +193,7 @@ static int meson_pwm_calc(struct pwm_chip *chip, struct pwm_device *pwm,
 	} else {
 		duty_cnt = div_u64(fin_freq * duty, NSEC_PER_SEC);
 
-		dev_dbg(chip->dev, "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
+		dev_dbg(meson->parent, "duty=%llu duty_cnt=%u\n", duty, duty_cnt);
 
 		channel->hi = duty_cnt;
 		channel->lo = cnt - duty_cnt;
@@ -216,7 +217,7 @@ static void meson_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	err = clk_set_rate(channel->clk, channel->rate);
 	if (err)
-		dev_err(chip->dev, "setting clock rate failed\n");
+		dev_err(meson->parent, "setting clock rate failed\n");
 
 	spin_lock_irqsave(&meson->lock, flags);
 
@@ -438,7 +439,7 @@ static int meson_pwm_init_channels(struct pwm_chip *chip)
 {
 	struct meson_pwm *meson = to_meson_pwm(chip);
 	struct clk_parent_data mux_parent_data[MESON_MAX_MUX_PARENTS] = {};
-	struct device *dev = chip->dev;
+	struct device *dev = meson->parent;
 	unsigned int i;
 	char name[255];
 	int err;
@@ -543,6 +544,7 @@ static int meson_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	meson = to_meson_pwm(chip);
 
+	meson->parent = &pdev->dev;
 	meson->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(meson->base))
 		return PTR_ERR(meson->base);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 083/101] pwm: mtk-disp: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (81 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 082/101] pwm: meson: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 084/101] pwm: omap: " Uwe Kleine-König
                   ` (19 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-mtk-disp.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index 0c4f88145dc6..9e51be25b2bb 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -42,6 +42,7 @@ struct mtk_pwm_data {
 };
 
 struct mtk_disp_pwm {
+	struct device *parent;
 	const struct mtk_pwm_data *data;
 	struct clk *clk_main;
 	struct clk *clk_mm;
@@ -90,14 +91,14 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (!mdp->enabled) {
 		err = clk_prepare_enable(mdp->clk_main);
 		if (err < 0) {
-			dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n",
+			dev_err(mdp->parent, "Can't enable mdp->clk_main: %pe\n",
 				ERR_PTR(err));
 			return err;
 		}
 
 		err = clk_prepare_enable(mdp->clk_mm);
 		if (err < 0) {
-			dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n",
+			dev_err(mdp->parent, "Can't enable mdp->clk_mm: %pe\n",
 				ERR_PTR(err));
 			clk_disable_unprepare(mdp->clk_main);
 			return err;
@@ -180,13 +181,13 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
 
 	err = clk_prepare_enable(mdp->clk_main);
 	if (err < 0) {
-		dev_err(chip->dev, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
+		dev_err(mdp->parent, "Can't enable mdp->clk_main: %pe\n", ERR_PTR(err));
 		return err;
 	}
 
 	err = clk_prepare_enable(mdp->clk_mm);
 	if (err < 0) {
-		dev_err(chip->dev, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
+		dev_err(mdp->parent, "Can't enable mdp->clk_mm: %pe\n", ERR_PTR(err));
 		clk_disable_unprepare(mdp->clk_main);
 		return err;
 	}
@@ -239,6 +240,7 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	mdp = to_mtk_disp_pwm(chip);
 
+	mdp->parent = &pdev->dev;
 	mdp->data = of_device_get_match_data(&pdev->dev);
 
 	mdp->base = devm_platform_ioremap_resource(pdev, 0);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 084/101] pwm: omap: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (82 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 083/101] pwm: mtk-disp: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 085/101] pwm: pca9685: " Uwe Kleine-König
                   ` (18 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-omap-dmtimer.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index c8d2db240b9e..d00133d44324 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -61,6 +61,7 @@
  * @dm_timer_pdev:	Pointer to omap dm timer platform device
  */
 struct pwm_omap_dmtimer_chip {
+	struct device *parent;
 	/* Mutex to protect pwm apply state */
 	struct mutex mutex;
 	struct omap_dm_timer *dm_timer;
@@ -157,7 +158,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 	unsigned long clk_rate;
 	struct clk *fclk;
 
-	dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
+	dev_dbg(omap->parent, "requested duty cycle: %d ns, period: %d ns\n",
 		duty_ns, period_ns);
 
 	if (duty_ns == pwm_get_duty_cycle(pwm) &&
@@ -166,17 +167,17 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 
 	fclk = omap->pdata->get_fclk(omap->dm_timer);
 	if (!fclk) {
-		dev_err(chip->dev, "invalid pmtimer fclk\n");
+		dev_err(omap->parent, "invalid pmtimer fclk\n");
 		return -EINVAL;
 	}
 
 	clk_rate = clk_get_rate(fclk);
 	if (!clk_rate) {
-		dev_err(chip->dev, "invalid pmtimer fclk rate\n");
+		dev_err(omap->parent, "invalid pmtimer fclk rate\n");
 		return -EINVAL;
 	}
 
-	dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
+	dev_dbg(omap->parent, "clk rate: %luHz\n", clk_rate);
 
 	/*
 	 * Calculate the appropriate load and match values based on the
@@ -198,27 +199,27 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 	duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns);
 
 	if (period_cycles < 2) {
-		dev_info(chip->dev,
+		dev_info(omap->parent,
 			 "period %d ns too short for clock rate %lu Hz\n",
 			 period_ns, clk_rate);
 		return -EINVAL;
 	}
 
 	if (duty_cycles < 1) {
-		dev_dbg(chip->dev,
+		dev_dbg(omap->parent,
 			"duty cycle %d ns is too short for clock rate %lu Hz\n",
 			duty_ns, clk_rate);
-		dev_dbg(chip->dev, "using minimum of 1 clock cycle\n");
+		dev_dbg(omap->parent, "using minimum of 1 clock cycle\n");
 		duty_cycles = 1;
 	} else if (duty_cycles >= period_cycles) {
-		dev_dbg(chip->dev,
+		dev_dbg(omap->parent,
 			"duty cycle %d ns is too long for period %d ns at clock rate %lu Hz\n",
 			duty_ns, period_ns, clk_rate);
-		dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n");
+		dev_dbg(omap->parent, "using maximum of 1 clock cycle less than period\n");
 		duty_cycles = period_cycles - 1;
 	}
 
-	dev_dbg(chip->dev, "effective duty cycle: %lld ns, period: %lld ns\n",
+	dev_dbg(omap->parent, "effective duty cycle: %lld ns, period: %lld ns\n",
 		DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * duty_cycles,
 				      clk_rate),
 		DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * period_cycles,
@@ -230,7 +231,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 	omap->pdata->set_load(omap->dm_timer, load_value);
 	omap->pdata->set_match(omap->dm_timer, true, match_value);
 
-	dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
+	dev_dbg(omap->parent, "load value: %#08x (%d), match value: %#08x (%d)\n",
 		load_value, load_value,	match_value, match_value);
 
 	return 0;
@@ -386,6 +387,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	omap->pdata = pdata;
 	omap->dm_timer = dm_timer;
 	omap->dm_timer_pdev = timer_pdev;
+	omap->parent = &pdev->dev;
 
 	/*
 	 * Ensure that the timer is stopped before we allow PWM core to call
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 085/101] pwm: pca9685: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (83 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 084/101] pwm: omap: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 086/101] pwm: raspberrypi-poe: " Uwe Kleine-König
                   ` (17 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

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

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 0d32b4bb51d8..679adf48cb4d 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -76,6 +76,7 @@
 #define REG_OFF_L(C)	((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : LED_N_OFF_L((C)))
 
 struct pca9685 {
+	struct device *parent;
 	struct pwm_chip *chip;
 	struct regmap *regmap;
 	struct mutex lock;
@@ -237,7 +238,7 @@ static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
 
 	if (pca9685_pwm_test_and_set_inuse(pca, offset))
 		return -EBUSY;
-	pm_runtime_get_sync(pca->chip->dev);
+	pm_runtime_get_sync(pca->parent);
 	return 0;
 }
 
@@ -261,7 +262,7 @@ static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
 	struct pca9685 *pca = gpiochip_get_data(gpio);
 
 	pca9685_pwm_set_duty(pca, offset, 0);
-	pm_runtime_put(pca->chip->dev);
+	pm_runtime_put(pca->parent);
 	pca9685_pwm_clear_inuse(pca, offset);
 }
 
@@ -294,7 +295,7 @@ static int pca9685_pwm_gpio_direction_output(struct gpio_chip *gpio,
  */
 static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 {
-	struct device *dev = pca->chip->dev;
+	struct device *dev = pca->parent;
 
 	pca->gpio.label = dev_name(dev);
 	pca->gpio.parent = dev;
@@ -331,7 +332,7 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 
 static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
 {
-	struct device *dev = pca->chip->dev;
+	struct device *dev = pca->parent;
 	int err = regmap_update_bits(pca->regmap, PCA9685_MODE1,
 				     MODE1_SLEEP, enable ? MODE1_SLEEP : 0);
 	if (err) {
@@ -463,7 +464,7 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 		mutex_unlock(&pca->lock);
 	}
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pca->parent);
 
 	return 0;
 }
@@ -477,7 +478,7 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 	clear_bit(pwm->hwpwm, pca->pwms_enabled);
 	mutex_unlock(&pca->lock);
 
-	pm_runtime_put(chip->dev);
+	pm_runtime_put(pca->parent);
 	pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
 }
 
@@ -508,6 +509,7 @@ static int pca9685_pwm_probe(struct i2c_client *client)
 		return PTR_ERR(chip);
 	pca = to_pca(chip);
 	pca->chip = chip;
+	pca->parent = &client->dev;
 
 	pca->regmap = devm_regmap_init_i2c(client, &pca9685_regmap_i2c_config);
 	if (IS_ERR(pca->regmap)) {
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 74f095afffa4..fbcba204de44 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -290,7 +290,7 @@ struct pwm_ops {
  * @pwms: array of PWM devices allocated by the framework
  */
 struct pwm_chip {
-	struct device dev;
+	struct device *dev;
 	const struct pwm_ops *ops;
 	struct module *owner;
 	int id;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 086/101] pwm: raspberrypi-poe: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (84 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 085/101] pwm: pca9685: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 087/101] pwm: rcar: " Uwe Kleine-König
                   ` (16 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-raspberrypi-poe.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c
index 4b2711d59e7c..b6d1326a3741 100644
--- a/drivers/pwm/pwm-raspberrypi-poe.c
+++ b/drivers/pwm/pwm-raspberrypi-poe.c
@@ -26,6 +26,7 @@
 #define RPI_PWM_CUR_DUTY_REG		0x0
 
 struct raspberrypi_pwm {
+	struct device *parent;
 	struct rpi_firmware *firmware;
 	unsigned int duty_cycle;
 };
@@ -121,7 +122,7 @@ static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG,
 					   duty_cycle);
 	if (ret) {
-		dev_err(chip->dev, "Failed to set duty cycle: %pe\n",
+		dev_err(rpipwm->parent, "Failed to set duty cycle: %pe\n",
 			ERR_PTR(ret));
 		return ret;
 	}
@@ -163,6 +164,7 @@ static int raspberrypi_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	rpipwm = raspberrypi_pwm_from_chip(chip);
 
+	rpipwm->parent = &pdev->dev;
 	rpipwm->firmware = firmware;
 	chip->ops = &raspberrypi_pwm_ops;
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 087/101] pwm: rcar: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (85 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 086/101] pwm: raspberrypi-poe: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 088/101] pwm: rz-mtu3: Make use of parent device pointer " Uwe Kleine-König
                   ` (15 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rcar.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 5bb7b579705d..ecbe7d2a26d7 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -38,6 +38,7 @@
 #define  RCAR_PWMCNT_PH0_SHIFT	0
 
 struct rcar_pwm_chip {
+	struct device *parent;
 	void __iomem *base;
 	struct clk *clk;
 };
@@ -131,12 +132,14 @@ static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns,
 
 static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	return pm_runtime_get_sync(chip->dev);
+	struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+	return pm_runtime_get_sync(rp->parent);
 }
 
 static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	pm_runtime_put(chip->dev);
+	struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+	pm_runtime_put(rp->parent);
 }
 
 static int rcar_pwm_enable(struct rcar_pwm_chip *rp)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 088/101] pwm: rz-mtu3: Make use of parent device pointer in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (86 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 087/101] pwm: rcar: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 089/101] pwm: samsung: Store parent device " Uwe Kleine-König
                   ` (14 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, make use of the
already existing pointer to the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rz-mtu3.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-rz-mtu3.c b/drivers/pwm/pwm-rz-mtu3.c
index ff396e2de7ab..2dedeaa35de8 100644
--- a/drivers/pwm/pwm-rz-mtu3.c
+++ b/drivers/pwm/pwm-rz-mtu3.c
@@ -274,7 +274,7 @@ static int rz_mtu3_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	struct rz_mtu3_pwm_chip *rz_mtu3_pwm = to_rz_mtu3_pwm_chip(chip);
 	int rc;
 
-	rc = pm_runtime_resume_and_get(chip->dev);
+	rc = pm_runtime_resume_and_get(rz_mtu3_pwm->parent);
 	if (rc)
 		return rc;
 
@@ -307,7 +307,7 @@ static int rz_mtu3_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	}
 
 	state->polarity = PWM_POLARITY_NORMAL;
-	pm_runtime_put(chip->dev);
+	pm_runtime_put(rz_mtu3_pwm->parent);
 
 	return 0;
 }
@@ -362,7 +362,7 @@ static int rz_mtu3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (!pwm->state.enabled) {
 		int rc;
 
-		rc = pm_runtime_resume_and_get(chip->dev);
+		rc = pm_runtime_resume_and_get(rz_mtu3_pwm->parent);
 		if (rc)
 			return rc;
 	}
@@ -399,7 +399,7 @@ static int rz_mtu3_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	/* If the PWM is not enabled, turn the clock off again to save power. */
 	if (!pwm->state.enabled)
-		pm_runtime_put(chip->dev);
+		pm_runtime_put(rz_mtu3_pwm->parent);
 
 	return 0;
 }
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 089/101] pwm: samsung: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (87 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 088/101] pwm: rz-mtu3: Make use of parent device pointer " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 090/101] pwm: sifive: Make use of parent device pointer " Uwe Kleine-König
                   ` (13 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-samsung.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 88d66c281015..4ef2cb5d3ad3 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -79,6 +79,7 @@ struct samsung_pwm_channel {
  * @tclk1:		external clock 1 (can be ERR_PTR if not present)
  */
 struct samsung_pwm_chip {
+	struct device *parent;
 	struct samsung_pwm_variant variant;
 	u8 inverter_mask;
 	u8 disabled_mask;
@@ -196,12 +197,12 @@ static unsigned long pwm_samsung_calc_tin(struct pwm_chip *chip,
 				return rate;
 		}
 
-		dev_warn(chip->dev,
+		dev_warn(our_chip->parent,
 			"tclk of PWM %d is inoperational, using tdiv\n", chan);
 	}
 
 	rate = pwm_samsung_get_tin_rate(our_chip, chan);
-	dev_dbg(chip->dev, "tin parent at %lu\n", rate);
+	dev_dbg(our_chip->parent, "tin parent at %lu\n", rate);
 
 	/*
 	 * Compare minimum PWM frequency that can be achieved with possible
@@ -231,7 +232,7 @@ static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 
 	if (!(our_chip->variant.output_mask & BIT(pwm->hwpwm))) {
-		dev_warn(chip->dev,
+		dev_warn(our_chip->parent,
 			"tried to request PWM channel %d without output\n",
 			pwm->hwpwm);
 		return -EINVAL;
@@ -325,12 +326,12 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 		period = NSEC_PER_SEC / period_ns;
 
-		dev_dbg(chip->dev, "duty_ns=%d, period_ns=%d (%u)\n",
+		dev_dbg(our_chip->parent, "duty_ns=%d, period_ns=%d (%u)\n",
 						duty_ns, period_ns, period);
 
 		tin_rate = pwm_samsung_calc_tin(chip, pwm->hwpwm, period);
 
-		dev_dbg(chip->dev, "tin_rate=%lu\n", tin_rate);
+		dev_dbg(our_chip->parent, "tin_rate=%lu\n", tin_rate);
 
 		tin_ns = NSEC_PER_SEC / tin_rate;
 		tcnt = period_ns / tin_ns;
@@ -354,7 +355,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	/* -1UL will give 100% duty. */
 	--tcmp;
 
-	dev_dbg(chip->dev,
+	dev_dbg(our_chip->parent,
 				"tin_ns=%u, tcmp=%u/%u\n", tin_ns, tcmp, tcnt);
 
 	/* Update PWM registers. */
@@ -367,7 +368,7 @@ static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	 * shortly afer this update (before it autoreloaded the new values).
 	 */
 	if (oldtcmp == (u32) -1) {
-		dev_dbg(chip->dev, "Forcing manual update");
+		dev_dbg(our_chip->parent, "Forcing manual update");
 		pwm_samsung_manual_update(our_chip, pwm);
 	}
 
@@ -509,7 +510,7 @@ MODULE_DEVICE_TABLE(of, samsung_pwm_matches);
 static int pwm_samsung_parse_dt(struct pwm_chip *chip)
 {
 	struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
-	struct device_node *np = chip->dev->of_node;
+	struct device_node *np = our_chip->parent->of_node;
 	const struct of_device_id *match;
 	struct property *prop;
 	const __be32 *cur;
@@ -523,7 +524,7 @@ static int pwm_samsung_parse_dt(struct pwm_chip *chip)
 
 	of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
 		if (val >= SAMSUNG_PWM_NUM) {
-			dev_err(chip->dev,
+			dev_err(our_chip->parent,
 				"%s: invalid channel index in samsung,pwm-outputs property\n",
 								__func__);
 			continue;
@@ -554,6 +555,7 @@ static int pwm_samsung_probe(struct platform_device *pdev)
 	our_chip = to_samsung_pwm_chip(chip);
 
 	chip->ops = &pwm_samsung_ops;
+	our_chip->parent = &pdev->dev;
 	our_chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1;
 
 	if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 090/101] pwm: sifive: Make use of parent device pointer in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (88 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 089/101] pwm: samsung: Store parent device " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 091/101] pwm: stm32: Store parent device " Uwe Kleine-König
                   ` (12 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, make use of the
already existing pointer to the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sifive.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
index 1f8a50143300..0de02da98484 100644
--- a/drivers/pwm/pwm-sifive.c
+++ b/drivers/pwm/pwm-sifive.c
@@ -185,7 +185,7 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (!enabled) {
 		ret = clk_enable(ddata->clk);
 		if (ret) {
-			dev_err(chip->dev, "Enable clk failed\n");
+			dev_err(ddata->parent, "Enable clk failed\n");
 			return ret;
 		}
 	}
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 091/101] pwm: stm32: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (89 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 090/101] pwm: sifive: Make use of parent device pointer " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 092/101] pwm: stmpe: " Uwe Kleine-König
                   ` (11 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-stm32.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 73fbd7a119ec..e07c43e38724 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -27,6 +27,7 @@ struct stm32_breakinput {
 };
 
 struct stm32_pwm {
+	struct device *parent;
 	struct mutex lock; /* protect pwm config/enable */
 	struct clk *clk;
 	struct regmap *regmap;
@@ -108,7 +109,7 @@ static int stm32_pwm_raw_capture(struct stm32_pwm *priv, struct pwm_device *pwm,
 				 unsigned long tmo_ms, u32 *raw_prd,
 				 u32 *raw_dty)
 {
-	struct device *parent = pwm->chip->dev->parent;
+	struct device *parent = priv->parent;
 	enum stm32_timers_dmas dma_id;
 	u32 ccen, ccr;
 	int ret;
@@ -184,7 +185,7 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	ret = clk_enable(priv->clk);
 	if (ret) {
-		dev_err(chip->dev, "failed to enable counter clock\n");
+		dev_err(priv->parent, "failed to enable counter clock\n");
 		goto unlock;
 	}
 
@@ -621,6 +622,7 @@ static int stm32_pwm_probe(struct platform_device *pdev)
 	priv = to_stm32_pwm_dev(chip);
 
 	mutex_init(&priv->lock);
+	priv->parent = &pdev->dev;
 	priv->regmap = ddata->regmap;
 	priv->clk = ddata->clk;
 	priv->max_arr = ddata->max_arr;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 092/101] pwm: stmpe: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (90 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 091/101] pwm: stm32: Store parent device " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 093/101] pwm: sun4i: " Uwe Kleine-König
                   ` (10 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-stmpe.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c
index 9c0f96b77c42..3efa28a5a9a3 100644
--- a/drivers/pwm/pwm-stmpe.c
+++ b/drivers/pwm/pwm-stmpe.c
@@ -26,6 +26,7 @@
 #define STMPE_PWM_24XX_PINBASE	21
 
 struct stmpe_pwm {
+	struct device *parent;
 	struct stmpe *stmpe;
 	u8 last_duty;
 };
@@ -43,7 +44,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
 	if (ret < 0) {
-		dev_err(chip->dev, "error reading PWM#%u control\n",
+		dev_err(stmpe_pwm->parent, "error reading PWM#%u control\n",
 			pwm->hwpwm);
 		return ret;
 	}
@@ -52,7 +53,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
 	if (ret) {
-		dev_err(chip->dev, "error writing PWM#%u control\n",
+		dev_err(stmpe_pwm->parent, "error writing PWM#%u control\n",
 			pwm->hwpwm);
 		return ret;
 	}
@@ -69,7 +70,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
 
 	ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
 	if (ret < 0) {
-		dev_err(chip->dev, "error reading PWM#%u control\n",
+		dev_err(stmpe_pwm->parent, "error reading PWM#%u control\n",
 			pwm->hwpwm);
 		return ret;
 	}
@@ -78,7 +79,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
 
 	ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
 	if (ret)
-		dev_err(chip->dev, "error writing PWM#%u control\n",
+		dev_err(stmpe_pwm->parent, "error writing PWM#%u control\n",
 			pwm->hwpwm);
 	return ret;
 }
@@ -124,7 +125,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		ret = stmpe_set_altfunc(stmpe_pwm->stmpe, BIT(pin),
 					STMPE_BLOCK_PWM);
 		if (ret) {
-			dev_err(chip->dev, "unable to connect PWM#%u to pin\n",
+			dev_err(stmpe_pwm->parent, "unable to connect PWM#%u to pin\n",
 				pwm->hwpwm);
 			return ret;
 		}
@@ -149,7 +150,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		return -ENODEV;
 	}
 
-	dev_dbg(chip->dev, "PWM#%u: config duty %d ns, period %d ns\n",
+	dev_dbg(stmpe_pwm->parent, "PWM#%u: config duty %d ns, period %d ns\n",
 		pwm->hwpwm, duty_ns, period_ns);
 
 	if (duty_ns == 0) {
@@ -215,7 +216,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			program[1] = BRANCH;
 		}
 
-		dev_dbg(chip->dev,
+		dev_dbg(stmpe_pwm->parent,
 			"PWM#%u: value = %02x, last_duty = %02x, program=%04x,%04x,%04x\n",
 			pwm->hwpwm, value, last, program[0], program[1],
 			program[2]);
@@ -232,7 +233,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 		ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
 		if (ret) {
-			dev_err(chip->dev, "error writing register %02x: %d\n",
+			dev_err(stmpe_pwm->parent, "error writing register %02x: %d\n",
 				offset, ret);
 			return ret;
 		}
@@ -241,7 +242,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 		ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
 		if (ret) {
-			dev_err(chip->dev, "error writing register %02x: %d\n",
+			dev_err(stmpe_pwm->parent, "error writing register %02x: %d\n",
 				offset, ret);
 			return ret;
 		}
@@ -254,7 +255,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	/* Sleep for 200ms so we're sure it will take effect */
 	msleep(200);
 
-	dev_dbg(chip->dev, "programmed PWM#%u, %u bytes\n", pwm->hwpwm, i);
+	dev_dbg(stmpe_pwm->parent, "programmed PWM#%u, %u bytes\n", pwm->hwpwm, i);
 
 	return 0;
 }
@@ -312,6 +313,7 @@ static int __init stmpe_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	stmpe_pwm = to_stmpe_pwm(chip);
 
+	stmpe_pwm->parent = &pdev->dev;
 	stmpe_pwm->stmpe = stmpe;
 
 	chip->ops = &stmpe_24xx_pwm_ops;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 093/101] pwm: sun4i: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (91 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 092/101] pwm: stmpe: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 094/101] pwm: tiecap: " Uwe Kleine-König
                   ` (9 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-sun4i.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index 4251807e496b..f2e85484f397 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -81,6 +81,7 @@ struct sun4i_pwm_data {
 };
 
 struct sun4i_pwm_chip {
+	struct device *parent;
 	struct clk *bus_clk;
 	struct clk *clk;
 	struct reset_control *rst;
@@ -244,7 +245,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (!cstate.enabled) {
 		ret = clk_prepare_enable(sun4i_pwm->clk);
 		if (ret) {
-			dev_err(chip->dev, "failed to enable PWM clock\n");
+			dev_err(sun4i_pwm->parent, "failed to enable PWM clock\n");
 			return ret;
 		}
 	}
@@ -252,7 +253,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler,
 				  &bypass);
 	if (ret) {
-		dev_err(chip->dev, "period exceeds the maximum value\n");
+		dev_err(sun4i_pwm->parent, "period exceeds the maximum value\n");
 		if (!cstate.enabled)
 			clk_disable_unprepare(sun4i_pwm->clk);
 		return ret;
@@ -397,6 +398,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(chip);
 	sun4ichip = to_sun4i_pwm_chip(chip);
 
+	sun4ichip->parent = &pdev->dev;
 	sun4ichip->data = data;
 	sun4ichip->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(sun4ichip->base))
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 094/101] pwm: tiecap: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (92 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 093/101] pwm: sun4i: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 095/101] pwm: tiehrpwm: " Uwe Kleine-König
                   ` (8 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-tiecap.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 9ff9a6de8be2..dfdec2a19b15 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -32,6 +32,7 @@ struct ecap_context {
 };
 
 struct ecap_pwm_chip {
+	struct device *parent;
 	unsigned int clk_rate;
 	void __iomem *mmio_base;
 	struct ecap_context ctx;
@@ -69,7 +70,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		duty_cycles = (u32)c;
 	}
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pc->parent);
 
 	value = readw(pc->mmio_base + ECCTL2);
 
@@ -99,7 +100,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 		writew(value, pc->mmio_base + ECCTL2);
 	}
 
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(pc->parent);
 
 	return 0;
 }
@@ -110,7 +111,7 @@ static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 	struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
 	u16 value;
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pc->parent);
 
 	value = readw(pc->mmio_base + ECCTL2);
 
@@ -123,7 +124,7 @@ static int ecap_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	writew(value, pc->mmio_base + ECCTL2);
 
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(pc->parent);
 
 	return 0;
 }
@@ -134,7 +135,7 @@ static int ecap_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	u16 value;
 
 	/* Leave clock enabled on enabling PWM */
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pc->parent);
 
 	/*
 	 * Enable 'Free run Time stamp counter mode' to start counter
@@ -161,7 +162,7 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	writew(value, pc->mmio_base + ECCTL2);
 
 	/* Disable clock on PWM disable */
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(pc->parent);
 }
 
 static int ecap_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -239,6 +240,7 @@ static int ecap_pwm_probe(struct platform_device *pdev)
 		return PTR_ERR(clk);
 	}
 
+	pc->parent = &pdev->dev;
 	pc->clk_rate = clk_get_rate(clk);
 	if (!pc->clk_rate) {
 		dev_err(&pdev->dev, "failed to get clock rate\n");
@@ -273,11 +275,11 @@ static void ecap_pwm_save_context(struct pwm_chip *chip)
 {
 	struct ecap_pwm_chip *pc = to_ecap_pwm_chip(chip);
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pc->parent);
 	pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2);
 	pc->ctx.cap4 = readl(pc->mmio_base + CAP4);
 	pc->ctx.cap3 = readl(pc->mmio_base + CAP3);
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(pc->parent);
 }
 
 static void ecap_pwm_restore_context(struct pwm_chip *chip)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 095/101] pwm: tiehrpwm: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (93 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 094/101] pwm: tiecap: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 096/101] pwm: twl: " Uwe Kleine-König
                   ` (7 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-tiehrpwm.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 5516cca7e3ac..e9ba78308997 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -105,6 +105,7 @@ struct ehrpwm_context {
 };
 
 struct ehrpwm_pwm_chip {
+	struct device *parent;
 	unsigned long clk_rate;
 	void __iomem *mmio_base;
 	unsigned long period_cycles[NUM_PWM_CHANNEL];
@@ -255,7 +256,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			if (i == pwm->hwpwm)
 				continue;
 
-			dev_err(chip->dev,
+			dev_err(pc->parent,
 				"period value conflicts with channel %u\n",
 				i);
 			return -EINVAL;
@@ -267,11 +268,11 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	/* Configure clock prescaler to support Low frequency PWM wave */
 	if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
 			     &tb_divval)) {
-		dev_err(chip->dev, "Unsupported values\n");
+		dev_err(pc->parent, "Unsupported values\n");
 		return -EINVAL;
 	}
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pc->parent);
 
 	/* Update clock prescaler values */
 	ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_CLKDIV_MASK, tb_divval);
@@ -298,7 +299,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	ehrpwm_write(pc->mmio_base, cmp_reg, duty_cycles);
 
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(pc->parent);
 
 	return 0;
 }
@@ -321,7 +322,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	u16 aqcsfrc_val, aqcsfrc_mask;
 
 	/* Leave clock enabled on enabling PWM */
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pc->parent);
 
 	/* Disabling Action Qualifier on PWM output */
 	if (pwm->hwpwm) {
@@ -376,7 +377,7 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	clk_disable(pc->tbclk);
 
 	/* Disable clock on PWM disable */
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(pc->parent);
 }
 
 static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -384,8 +385,8 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 
 	if (pwm_is_enabled(pwm)) {
-		dev_warn(chip->dev, "Removing PWM device without disabling\n");
-		pm_runtime_put_sync(chip->dev);
+		dev_warn(pc->parent, "Removing PWM device without disabling\n");
+		pm_runtime_put_sync(pc->parent);
 	}
 
 	/* set period value to zero on free */
@@ -461,6 +462,7 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(clk))
 		return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get fck\n");
 
+	pc->parent = &pdev->dev;
 	pc->clk_rate = clk_get_rate(clk);
 	if (!pc->clk_rate) {
 		dev_err(&pdev->dev, "failed to get clock rate\n");
@@ -518,7 +520,7 @@ static void ehrpwm_pwm_save_context(struct pwm_chip *chip)
 {
 	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
 
-	pm_runtime_get_sync(chip->dev);
+	pm_runtime_get_sync(pc->parent);
 
 	pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL);
 	pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD);
@@ -529,7 +531,7 @@ static void ehrpwm_pwm_save_context(struct pwm_chip *chip)
 	pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC);
 	pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC);
 
-	pm_runtime_put_sync(chip->dev);
+	pm_runtime_put_sync(pc->parent);
 }
 
 static void ehrpwm_pwm_restore_context(struct pwm_chip *chip)
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 096/101] pwm: twl: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (94 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 095/101] pwm: tiehrpwm: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 097/101] pwm: twl-led: " Uwe Kleine-König
                   ` (6 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-twl.c | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
index d66596c8597d..f7aa9b34f67e 100644
--- a/drivers/pwm/pwm-twl.c
+++ b/drivers/pwm/pwm-twl.c
@@ -46,6 +46,7 @@
 #define TWL6030_PWM_TOGGLE(pwm, x)	((x) << (pwm * 3))
 
 struct twl_pwm_chip {
+	struct device *parent;
 	struct mutex mutex;
 	u8 twl6030_toggle3;
 	u8 twl4030_pwm_mux;
@@ -59,6 +60,7 @@ static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
 static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			  u64 duty_ns, u64 period_ns)
 {
+	struct twl_pwm_chip *twl = to_twl(chip);
 	int duty_cycle = DIV64_U64_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
 	u8 pwm_config[2] = { 1, 0 };
 	int base, ret;
@@ -85,7 +87,7 @@ static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to configure PWM\n", pwm->label);
 
 	return ret;
 }
@@ -99,7 +101,7 @@ static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to read GPBR1\n", pwm->label);
 		goto out;
 	}
 
@@ -107,13 +109,13 @@ static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to enable PWM\n", pwm->label);
 
 	val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to enable PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -129,7 +131,7 @@ static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to read GPBR1\n", pwm->label);
 		goto out;
 	}
 
@@ -137,13 +139,13 @@ static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to disable PWM\n", pwm->label);
 
 	val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to disable PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -166,7 +168,7 @@ static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to read PMBR1\n", pwm->label);
 		goto out;
 	}
 
@@ -180,7 +182,7 @@ static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to request PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -201,7 +203,7 @@ static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to read PMBR1\n", pwm->label);
 		goto out;
 	}
 
@@ -211,7 +213,7 @@ static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to free PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -230,7 +232,7 @@ static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to enable PWM\n", pwm->label);
 		goto out;
 	}
 
@@ -253,7 +255,7 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to disable PWM\n", pwm->label);
 		goto out;
 	}
 
@@ -261,7 +263,7 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to disable PWM\n", pwm->label);
 		goto out;
 	}
 
@@ -269,7 +271,7 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to disable PWM\n", pwm->label);
 		goto out;
 	}
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 097/101] pwm: twl-led: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (95 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 096/101] pwm: twl: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 098/101] pwm: vt8500: " Uwe Kleine-König
                   ` (5 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-twl-led.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
index 4591ffab7863..8222107cf272 100644
--- a/drivers/pwm/pwm-twl-led.c
+++ b/drivers/pwm/pwm-twl-led.c
@@ -62,6 +62,7 @@
 #define TWL6040_LED_MODE_MASK	0x03
 
 struct twl_pwmled_chip {
+	struct device *parent;
 	struct mutex mutex;
 };
 
@@ -73,6 +74,7 @@ static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip)
 static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			      int duty_ns, int period_ns)
 {
+	struct twl_pwmled_chip *twl = to_twl(chip);
 	int duty_cycle = DIV_ROUND_UP(duty_ns * TWL4030_LED_MAX, period_ns) + 1;
 	u8 pwm_config[2] = { 1, 0 };
 	int base, ret;
@@ -99,7 +101,7 @@ static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	ret = twl_i2c_write(TWL4030_MODULE_LED, pwm_config, base, 2);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to configure PWM\n", pwm->label);
 
 	return ret;
 }
@@ -113,7 +115,7 @@ static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to read LEDEN\n", pwm->label);
 		goto out;
 	}
 
@@ -121,7 +123,7 @@ static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to enable PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -138,7 +140,7 @@ static void twl4030_pwmled_disable(struct pwm_chip *chip,
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to read LEDEN\n", pwm->label);
 		goto out;
 	}
 
@@ -146,7 +148,7 @@ static void twl4030_pwmled_disable(struct pwm_chip *chip,
 
 	ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to disable PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -193,6 +195,7 @@ static const struct pwm_ops twl4030_pwmled_ops = {
 static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			      int duty_ns, int period_ns)
 {
+	struct twl_pwmled_chip *twl = to_twl(chip);
 	int duty_cycle = (duty_ns * TWL6030_LED_MAX) / period_ns;
 	u8 on_time;
 	int ret;
@@ -202,7 +205,7 @@ static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, on_time,
 			       TWL6030_LED_PWM_CTRL1);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to configure PWM\n", pwm->label);
 
 	return ret;
 }
@@ -216,7 +219,7 @@ static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+		dev_err(twl->parent, "%s: Failed to read PWM_CTRL2\n",
 			pwm->label);
 		goto out;
 	}
@@ -226,7 +229,7 @@ static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to enable PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -243,7 +246,7 @@ static void twl6030_pwmled_disable(struct pwm_chip *chip,
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+		dev_err(twl->parent, "%s: Failed to read PWM_CTRL2\n",
 			pwm->label);
 		goto out;
 	}
@@ -253,7 +256,7 @@ static void twl6030_pwmled_disable(struct pwm_chip *chip,
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to disable PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -294,7 +297,7 @@ static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+		dev_err(twl->parent, "%s: Failed to read PWM_CTRL2\n",
 			pwm->label);
 		goto out;
 	}
@@ -304,7 +307,7 @@ static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to request PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -320,7 +323,7 @@ static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_lock(&twl->mutex);
 	ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0) {
-		dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+		dev_err(twl->parent, "%s: Failed to read PWM_CTRL2\n",
 			pwm->label);
 		goto out;
 	}
@@ -330,7 +333,7 @@ static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
 	if (ret < 0)
-		dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
+		dev_err(twl->parent, "%s: Failed to free PWM\n", pwm->label);
 
 out:
 	mutex_unlock(&twl->mutex);
@@ -357,6 +360,7 @@ static int twl_pwmled_probe(struct platform_device *pdev)
 	if (IS_ERR(chip))
 		return PTR_ERR(chip);
 	twl = to_twl(chip);
+	twl->parent = &pdev->dev;
 
 	if (twl_class_is_4030())
 		chip->ops = &twl4030_pwmled_ops;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 098/101] pwm: vt8500: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (96 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 097/101] pwm: twl-led: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 099/101] staging: greybus: pwm: " Uwe Kleine-König
                   ` (4 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-vt8500.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index 41d9f1a0f74f..634dac40594f 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -45,6 +45,7 @@
 #define STATUS_ALL_UPDATE	0x0F
 
 struct vt8500_chip {
+	struct device *parent;
 	void __iomem *base;
 	struct clk *clk;
 };
@@ -80,7 +81,7 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 	err = clk_enable(vt8500->clk);
 	if (err < 0) {
-		dev_err(chip->dev, "failed to enable clock\n");
+		dev_err(vt8500->parent, "failed to enable clock\n");
 		return err;
 	}
 
@@ -139,7 +140,7 @@ static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	err = clk_enable(vt8500->clk);
 	if (err < 0) {
-		dev_err(chip->dev, "failed to enable clock\n");
+		dev_err(vt8500->parent, "failed to enable clock\n");
 		return err;
 	}
 
@@ -257,6 +258,7 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
 
 	chip->ops = &vt8500_pwm_ops;
 
+	vt8500->parent = &pdev->dev;
 	vt8500->clk = devm_clk_get_prepared(&pdev->dev, NULL);
 	if (IS_ERR(vt8500->clk))
 		return dev_err_probe(&pdev->dev, PTR_ERR(vt8500->clk), "clock source not specified\n");
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 099/101] staging: greybus: pwm: Store parent device in driver data
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (97 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 098/101] pwm: vt8500: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-08-08 17:19 ` [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used Uwe Kleine-König
                   ` (3 subsequent siblings)
  102 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

struct pwm_chip::dev is about to change. To not have to touch this
driver in the same commit as struct pwm_chip::dev, store a pointer to
the parent device in driver data.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/staging/greybus/pwm.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c
index 60b3bddae08a..6af07ebcbaa4 100644
--- a/drivers/staging/greybus/pwm.c
+++ b/drivers/staging/greybus/pwm.c
@@ -16,7 +16,7 @@
 
 struct gb_pwm_chip {
 	struct gb_connection	*connection;
-
+	struct device		*parent;
 	struct pwm_chip		chip;
 };
 
@@ -34,7 +34,7 @@ static int gb_pwm_activate_operation(struct gb_pwm_chip *pwmc,
 
 	request.which = which;
 
-	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
+	gbphy_dev = to_gbphy_dev(pwmc->parent);
 	ret = gbphy_runtime_get_sync(gbphy_dev);
 	if (ret)
 		return ret;
@@ -56,7 +56,7 @@ static int gb_pwm_deactivate_operation(struct gb_pwm_chip *pwmc,
 
 	request.which = which;
 
-	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
+	gbphy_dev = to_gbphy_dev(pwmc->parent);
 	ret = gbphy_runtime_get_sync(gbphy_dev);
 	if (ret)
 		return ret;
@@ -80,7 +80,7 @@ static int gb_pwm_config_operation(struct gb_pwm_chip *pwmc,
 	request.duty = cpu_to_le32(duty);
 	request.period = cpu_to_le32(period);
 
-	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
+	gbphy_dev = to_gbphy_dev(pwmc->parent);
 	ret = gbphy_runtime_get_sync(gbphy_dev);
 	if (ret)
 		return ret;
@@ -103,7 +103,7 @@ static int gb_pwm_set_polarity_operation(struct gb_pwm_chip *pwmc,
 	request.which = which;
 	request.polarity = polarity;
 
-	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
+	gbphy_dev = to_gbphy_dev(pwmc->parent);
 	ret = gbphy_runtime_get_sync(gbphy_dev);
 	if (ret)
 		return ret;
@@ -125,7 +125,7 @@ static int gb_pwm_enable_operation(struct gb_pwm_chip *pwmc,
 
 	request.which = which;
 
-	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
+	gbphy_dev = to_gbphy_dev(pwmc->parent);
 	ret = gbphy_runtime_get_sync(gbphy_dev);
 	if (ret)
 		return ret;
@@ -150,7 +150,7 @@ static int gb_pwm_disable_operation(struct gb_pwm_chip *pwmc,
 	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_DISABLE,
 				&request, sizeof(request), NULL, 0);
 
-	gbphy_dev = to_gbphy_dev(pwmc->chip.dev);
+	gbphy_dev = to_gbphy_dev(pwmc->parent);
 	gbphy_runtime_put_autosuspend(gbphy_dev);
 
 	return ret;
@@ -168,7 +168,7 @@ static void gb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 	struct gb_pwm_chip *pwmc = pwm_chip_to_gb_pwm_chip(chip);
 
 	if (pwm_is_enabled(pwm))
-		dev_warn(chip->dev, "freeing PWM device without disabling\n");
+		dev_warn(pwmc->parent, "freeing PWM device without disabling\n");
 
 	gb_pwm_deactivate_operation(pwmc, pwm->hwpwm);
 }
@@ -256,6 +256,7 @@ static int gb_pwm_probe(struct gbphy_device *gbphy_dev,
 
 	pwmc = pwmchip_priv(chip);
 
+	pwmc->parent = &gbphy_dev->dev;
 	pwmc->connection = connection;
 	gb_connection_set_data(connection, pwmc);
 	gb_gbphy_set_data(gbphy_dev, pwmc);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (98 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 099/101] staging: greybus: pwm: " Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-10-06 12:37   ` Thierry Reding
  2023-08-08 17:19 ` [PATCH v1 101/101] pwm: Add more locking Uwe Kleine-König
                   ` (2 subsequent siblings)
  102 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

With adding a call to msleep() to stm32_pwm_apply() and a pwm-fan device
making use of an stm32-pwm device it's possible to trigger a use after
free with:

	echo fan > /sys/bus/platform/drivers/pwm-fan/unbind & sleep 1; echo 40007000.timer:pwm > /sys/bus/platform/drivers/stm32-pwm/unbind

as unbinding the pwm device already completes (including kfree()ing
driver data allocated in pwmchip_alloc()) while unbinding the fan still
sleeps in stm32_pwm_apply().

Normally device links should prevent this issue such that the fan is
completely removed when unbinding the PWM device results in calling
pwmchip_remove(). I'm not sure if this is a bug related to device links,
but as with a (still to be created) pwmchip character device similar
things can happen when the character device is still open and the driver
is removed, this is worth fixing already now.

The memory allocated to hold a struct pwm_chip is tied now to the struct
device that is added to struct pwm_chip. This way it's only freed when
the last reference is dropped. In the above case this only happens when
the fan driver released its reference using pwm_put().

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/Kconfig  |   4 --
 drivers/pwm/Makefile |   3 +-
 drivers/pwm/core.c   | 120 ++++++++++++++++++++++++++++++-------------
 drivers/pwm/sysfs.c  |  45 +++-------------
 include/linux/pwm.h  |  15 ++----
 5 files changed, 96 insertions(+), 91 deletions(-)

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6210babb0741..831c09dce692 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -29,10 +29,6 @@ menuconfig PWM
 
 if PWM
 
-config PWM_SYSFS
-	bool
-	default y if SYSFS
-
 config PWM_DEBUG
 	bool "PWM lowlevel drivers additional checks and debug messages"
 	depends on DEBUG_KERNEL
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index c822389c2a24..f90d283c2c31 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -1,6 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_PWM)		+= core.o
-obj-$(CONFIG_PWM_SYSFS)		+= sysfs.o
+obj-$(CONFIG_PWM)		+= core.o sysfs.o
 obj-$(CONFIG_PWM_AB8500)	+= pwm-ab8500.o
 obj-$(CONFIG_PWM_APPLE)		+= pwm-apple.o
 obj-$(CONFIG_PWM_ATMEL)		+= pwm-atmel.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 3b8d41fdda1b..fcf30f77da34 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -43,7 +43,7 @@ static struct pwm_chip *pwmchip_find_by_name(const char *name)
 	mutex_lock(&pwm_lock);
 
 	idr_for_each_entry_ul(&pwmchip_idr, chip, tmp, id) {
-		const char *chip_name = dev_name(chip->dev);
+		const char *chip_name = dev_name(chip->dev.parent);
 
 		if (chip_name && strcmp(chip_name, name) == 0) {
 			mutex_unlock(&pwm_lock);
@@ -63,13 +63,13 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
 	if (test_bit(PWMF_REQUESTED, &pwm->flags))
 		return -EBUSY;
 
-	if (!try_module_get(pwm->chip->owner))
+	if (!get_device(&pwm->chip->dev))
 		return -ENODEV;
 
 	if (pwm->chip->ops->request) {
 		err = pwm->chip->ops->request(pwm->chip, pwm);
 		if (err) {
-			module_put(pwm->chip->owner);
+			put_device(&pwm->chip->dev);
 			return err;
 		}
 	}
@@ -159,13 +159,13 @@ EXPORT_SYMBOL_GPL(of_pwm_single_xlate);
 
 static void of_pwmchip_add(struct pwm_chip *chip)
 {
-	if (!chip->dev || !chip->dev->of_node)
+	if (!chip->dev.parent || !chip->dev.parent->of_node)
 		return;
 
 	if (!chip->of_xlate) {
 		u32 pwm_cells;
 
-		if (of_property_read_u32(chip->dev->of_node, "#pwm-cells",
+		if (of_property_read_u32(chip->dev.parent->of_node, "#pwm-cells",
 					 &pwm_cells))
 			pwm_cells = 2;
 
@@ -173,13 +173,13 @@ static void of_pwmchip_add(struct pwm_chip *chip)
 		chip->of_pwm_n_cells = pwm_cells;
 	}
 
-	of_node_get(chip->dev->of_node);
+	of_node_get(chip->dev.parent->of_node);
 }
 
 static void of_pwmchip_remove(struct pwm_chip *chip)
 {
-	if (chip->dev)
-		of_node_put(chip->dev->of_node);
+	if (chip->dev.parent)
+		of_node_put(chip->dev.parent->of_node);
 }
 
 static bool pwm_ops_check(const struct pwm_chip *chip)
@@ -190,7 +190,7 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
 		return false;
 
 	if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state)
-		dev_warn(chip->dev,
+		dev_warn(chip->dev.parent,
 			 "Please implement the .get_state() callback\n");
 
 	return true;
@@ -202,19 +202,33 @@ void *pwmchip_priv(struct pwm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(pwmchip_priv);
 
-struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
+static void pwmchip_release(struct device *dev)
+{
+	struct pwm_chip *chip = container_of(dev, struct pwm_chip, dev);
+
+	kfree(chip);
+}
+
+static struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
 {
 	struct pwm_chip *chip;
+	struct device *dev;
 	size_t alloc_size;
 	unsigned int i;
 
 	alloc_size = sizeof(*chip) + npwm * sizeof(struct pwm_device) + sizeof_priv;
 
-	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
+	chip = kzalloc(alloc_size, GFP_KERNEL);
 	if (!chip)
 		return ERR_PTR(-ENOMEM);
 
-	chip->dev = parent;
+	dev = &chip->dev;
+
+	device_initialize(dev);
+	dev->class = &pwm_class;
+	dev->parent = parent;
+	dev->release = pwmchip_release;
+
 	chip->npwm = npwm;
 
 	for (i = 0; i < chip->npwm; i++) {
@@ -226,6 +240,29 @@ struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
 
 	return chip;
 }
+
+static void devm_pwmchip_put(void *_chip)
+{
+	struct pwm_chip *chip = _chip;
+
+	put_device(&chip->dev);
+}
+
+struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
+{
+	struct pwm_chip *chip;
+	int ret;
+
+	chip = pwmchip_alloc(parent, npwm, sizeof_priv);
+	if (IS_ERR(chip))
+		return chip;
+
+	ret = devm_add_action_or_reset(parent, devm_pwmchip_put, chip);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return chip;
+}
 EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
 
 /**
@@ -242,32 +279,39 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 {
 	int ret;
 
-	if (!chip || !chip->dev || !chip->ops || !chip->npwm)
+	if (!chip || !chip->dev.parent || !chip->ops || !chip->npwm)
 		return -EINVAL;
 
 	if (!pwm_ops_check(chip))
 		return -EINVAL;
 
 	chip->owner = owner;
+	if (!try_module_get(owner))
+		return -EINVAL;
 
 	mutex_lock(&pwm_lock);
 
 	ret = idr_alloc(&pwmchip_idr, chip, 0, 0, GFP_KERNEL);
-	if (ret < 0) {
-		mutex_unlock(&pwm_lock);
-		return ret;
-	}
+	if (ret < 0)
+		goto err_idr_alloc;
 
 	chip->id = ret;
-
-	mutex_unlock(&pwm_lock);
+	dev_set_name(&chip->dev, "pwmchip%u", chip->id);
 
 	if (IS_ENABLED(CONFIG_OF))
 		of_pwmchip_add(chip);
 
-	pwmchip_sysfs_export(chip);
+	ret = device_add(&chip->dev);
+	if (ret) {
+		idr_remove(&pwmchip_idr, chip->id);
+err_idr_alloc:
 
-	return 0;
+		module_put(owner);
+	}
+
+	mutex_unlock(&pwm_lock);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(__pwmchip_add);
 
@@ -289,6 +333,10 @@ void pwmchip_remove(struct pwm_chip *chip)
 	idr_remove(&pwmchip_idr, chip->id);
 
 	mutex_unlock(&pwm_lock);
+
+	module_put(chip->owner);
+
+	device_del(&chip->dev);
 }
 EXPORT_SYMBOL_GPL(pwmchip_remove);
 
@@ -385,18 +433,18 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
 
 	if (s2.polarity != state->polarity &&
 	    state->duty_cycle < state->period)
-		dev_warn(chip->dev, ".apply ignored .polarity\n");
+		dev_warn(chip->dev.parent, ".apply ignored .polarity\n");
 
 	if (state->enabled &&
 	    last->polarity == state->polarity &&
 	    last->period > s2.period &&
 	    last->period <= state->period)
-		dev_warn(chip->dev,
+		dev_warn(&chip->dev,
 			 ".apply didn't pick the best available period (requested: %llu, applied: %llu, possible: %llu)\n",
 			 state->period, s2.period, last->period);
 
 	if (state->enabled && state->period < s2.period)
-		dev_warn(chip->dev,
+		dev_warn(chip->dev.parent,
 			 ".apply is supposed to round down period (requested: %llu, applied: %llu)\n",
 			 state->period, s2.period);
 
@@ -405,20 +453,20 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
 	    last->period == s2.period &&
 	    last->duty_cycle > s2.duty_cycle &&
 	    last->duty_cycle <= state->duty_cycle)
-		dev_warn(chip->dev,
+		dev_warn(&chip->dev,
 			 ".apply didn't pick the best available duty cycle (requested: %llu/%llu, applied: %llu/%llu, possible: %llu/%llu)\n",
 			 state->duty_cycle, state->period,
 			 s2.duty_cycle, s2.period,
 			 last->duty_cycle, last->period);
 
 	if (state->enabled && state->duty_cycle < s2.duty_cycle)
-		dev_warn(chip->dev,
+		dev_warn(&chip->dev,
 			 ".apply is supposed to round down duty_cycle (requested: %llu/%llu, applied: %llu/%llu)\n",
 			 state->duty_cycle, state->period,
 			 s2.duty_cycle, s2.period);
 
 	if (!state->enabled && s2.enabled && s2.duty_cycle > 0)
-		dev_warn(chip->dev,
+		dev_warn(&chip->dev,
 			 "requested disabled, but yielded enabled with duty > 0\n");
 
 	/* reapply the state that the driver reported being configured. */
@@ -426,7 +474,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
 	trace_pwm_apply(pwm, &s1, err);
 	if (err) {
 		*last = s1;
-		dev_err(chip->dev, "failed to reapply current setting\n");
+		dev_err(&chip->dev, "failed to reapply current setting\n");
 		return;
 	}
 
@@ -441,7 +489,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
 	    s1.polarity != last->polarity ||
 	    (s1.enabled && s1.period != last->period) ||
 	    (s1.enabled && s1.duty_cycle != last->duty_cycle)) {
-		dev_err(chip->dev,
+		dev_err(&chip->dev,
 			".apply is not idempotent (ena=%d pol=%d %llu/%llu) -> (ena=%d pol=%d %llu/%llu)\n",
 			s1.enabled, s1.polarity, s1.duty_cycle, s1.period,
 			last->enabled, last->polarity, last->duty_cycle,
@@ -589,7 +637,7 @@ static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
 	mutex_lock(&pwm_lock);
 
 	idr_for_each_entry_ul(&pwmchip_idr, chip, tmp, id)
-		if (chip->dev && device_match_fwnode(chip->dev, fwnode)) {
+		if (device_match_fwnode(chip->dev.parent, fwnode)) {
 			mutex_unlock(&pwm_lock);
 			return chip;
 		}
@@ -610,15 +658,15 @@ static struct device_link *pwm_device_link_add(struct device *dev,
 		 * impact the PM sequence ordering: the PWM supplier may get
 		 * suspended before the consumer.
 		 */
-		dev_warn(pwm->chip->dev,
+		dev_warn(&pwm->chip->dev,
 			 "No consumer device specified to create a link to\n");
 		return NULL;
 	}
 
-	dl = device_link_add(dev, pwm->chip->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+	dl = device_link_add(dev, pwm->chip->dev.parent, DL_FLAG_AUTOREMOVE_CONSUMER);
 	if (!dl) {
 		dev_err(dev, "failed to create device link to %s\n",
-			dev_name(pwm->chip->dev));
+			dev_name(pwm->chip->dev.parent));
 		return ERR_PTR(-EINVAL);
 	}
 
@@ -940,7 +988,7 @@ void pwm_put(struct pwm_device *pwm)
 
 	pwm->label = NULL;
 
-	module_put(pwm->chip->owner);
+	put_device(&pwm->chip->dev);
 out:
 	mutex_unlock(&pwm_lock);
 }
@@ -1080,8 +1128,8 @@ static int pwm_seq_show(struct seq_file *s, void *v)
 
 	seq_printf(s, "%s%d: %s/%s, %d PWM device%s\n",
 		   (char *)s->private, chip->id,
-		   chip->dev->bus ? chip->dev->bus->name : "no-bus",
-		   dev_name(chip->dev), chip->npwm,
+		   chip->dev.parent->bus ? chip->dev.parent->bus->name : "no-bus",
+		   dev_name(chip->dev.parent), chip->npwm,
 		   (chip->npwm != 1) ? "s" : "");
 
 	pwm_dbg_show(chip, s);
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 4edb994fa2e1..3a438b29c777 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -311,7 +311,7 @@ static ssize_t export_store(struct device *parent,
 			    struct device_attribute *attr,
 			    const char *buf, size_t len)
 {
-	struct pwm_chip *chip = dev_get_drvdata(parent);
+	struct pwm_chip *chip = container_of(parent, struct pwm_chip, dev);
 	struct pwm_device *pwm;
 	unsigned int hwpwm;
 	int ret;
@@ -339,7 +339,7 @@ static ssize_t unexport_store(struct device *parent,
 			      struct device_attribute *attr,
 			      const char *buf, size_t len)
 {
-	struct pwm_chip *chip = dev_get_drvdata(parent);
+	struct pwm_chip *chip = container_of(parent, struct pwm_chip, dev);
 	unsigned int hwpwm;
 	int ret;
 
@@ -359,7 +359,7 @@ static DEVICE_ATTR_WO(unexport);
 static ssize_t npwm_show(struct device *parent, struct device_attribute *attr,
 			 char *buf)
 {
-	const struct pwm_chip *chip = dev_get_drvdata(parent);
+	const struct pwm_chip *chip = container_of(parent, struct pwm_chip, dev);
 
 	return sysfs_emit(buf, "%u\n", chip->npwm);
 }
@@ -411,7 +411,7 @@ static int pwm_class_apply_state(struct pwm_export *export,
 
 static int pwm_class_resume_npwm(struct device *parent, unsigned int npwm)
 {
-	struct pwm_chip *chip = dev_get_drvdata(parent);
+	struct pwm_chip *chip = container_of(parent, struct pwm_chip, dev);
 	unsigned int i;
 	int ret = 0;
 
@@ -442,7 +442,7 @@ static int pwm_class_resume_npwm(struct device *parent, unsigned int npwm)
 
 static int pwm_class_suspend(struct device *parent)
 {
-	struct pwm_chip *chip = dev_get_drvdata(parent);
+	struct pwm_chip *chip = container_of(parent, struct pwm_chip, dev);
 	unsigned int i;
 	int ret = 0;
 
@@ -483,59 +483,30 @@ static int pwm_class_suspend(struct device *parent)
 
 static int pwm_class_resume(struct device *parent)
 {
-	struct pwm_chip *chip = dev_get_drvdata(parent);
+	struct pwm_chip *chip = container_of(parent, struct pwm_chip, dev);
 
 	return pwm_class_resume_npwm(parent, chip->npwm);
 }
 
 static DEFINE_SIMPLE_DEV_PM_OPS(pwm_class_pm_ops, pwm_class_suspend, pwm_class_resume);
 
-static struct class pwm_class = {
+struct class pwm_class = {
 	.name = "pwm",
 	.dev_groups = pwm_chip_groups,
 	.pm = pm_sleep_ptr(&pwm_class_pm_ops),
 };
 
-static int pwmchip_sysfs_match(struct device *parent, const void *data)
-{
-	return dev_get_drvdata(parent) == data;
-}
-
-void pwmchip_sysfs_export(struct pwm_chip *chip)
-{
-	struct device *parent;
-
-	/*
-	 * If device_create() fails the pwm_chip is still usable by
-	 * the kernel it's just not exported.
-	 */
-	parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
-			       "pwmchip%d", chip->id);
-	if (IS_ERR(parent)) {
-		dev_warn(chip->dev,
-			 "device_create failed for pwm_chip sysfs export\n");
-	}
-}
-
 void pwmchip_sysfs_unexport(struct pwm_chip *chip)
 {
-	struct device *parent;
+	struct device *parent = &chip->dev;
 	unsigned int i;
 
-	parent = class_find_device(&pwm_class, NULL, chip,
-				   pwmchip_sysfs_match);
-	if (!parent)
-		return;
-
 	for (i = 0; i < chip->npwm; i++) {
 		struct pwm_device *pwm = &chip->pwms[i];
 
 		if (test_bit(PWMF_EXPORTED, &pwm->flags))
 			pwm_unexport_child(parent, pwm);
 	}
-
-	put_device(parent);
-	device_unregister(parent);
 }
 
 static int __init pwm_sysfs_init(void)
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index fbcba204de44..3dd46b89ab8b 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -2,6 +2,7 @@
 #ifndef __LINUX_PWM_H
 #define __LINUX_PWM_H
 
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
@@ -290,7 +291,7 @@ struct pwm_ops {
  * @pwms: array of PWM devices allocated by the framework
  */
 struct pwm_chip {
-	struct device *dev;
+	struct device dev;
 	const struct pwm_ops *ops;
 	struct module *owner;
 	int id;
@@ -570,17 +571,7 @@ static inline void pwm_remove_table(struct pwm_lookup *table, size_t num)
 }
 #endif
 
-#ifdef CONFIG_PWM_SYSFS
-void pwmchip_sysfs_export(struct pwm_chip *chip);
+extern struct class pwm_class;
 void pwmchip_sysfs_unexport(struct pwm_chip *chip);
-#else
-static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
-{
-}
-
-static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
-{
-}
-#endif /* CONFIG_PWM_SYSFS */
 
 #endif /* __LINUX_PWM_H */
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* [PATCH v1 101/101] pwm: Add more locking
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (99 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used Uwe Kleine-König
@ 2023-08-08 17:19 ` Uwe Kleine-König
  2023-10-06 10:09   ` Thierry Reding
  2023-09-26 10:06 ` [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
  2023-10-06  9:20 ` Thierry Reding
  102 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-08 17:19 UTC (permalink / raw)
  To: Thierry Reding; +Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

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 was not expected to be a problem in the
presence of device links, but still it can happen with the command
sequence mentioned in the previous commit. Even if this should turn out
to be a problem that could be fixed by improving device links, this is a
necessary preparation to create race-free pwmchip character devices.

A not so nice side effect is that all calls to the PWM API are
serialized now. If this turns out to be problematic this can be replaced
by per-pwm_chip locking later. As long as this bottleneck isn't known to
be a problem in practise, the simpler approach of a single lock is used
here.

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

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index fcf30f77da34..66743ded66f6 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -230,6 +230,7 @@ static struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm,
 	dev->release = pwmchip_release;
 
 	chip->npwm = npwm;
+	chip->ready = false;
 
 	for (i = 0; i < chip->npwm; i++) {
 		struct pwm_device *pwm = &chip->pwms[i];
@@ -309,6 +310,8 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
 		module_put(owner);
 	}
 
+	chip->ready = true;
+
 	mutex_unlock(&pwm_lock);
 
 	return ret;
@@ -324,12 +327,25 @@ 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);
 
+	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);
+		}
+	}
+
+	chip->ready = false;
+
 	idr_remove(&pwmchip_idr, chip->id);
 
 	mutex_unlock(&pwm_lock);
@@ -505,7 +521,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
@@ -522,17 +538,24 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
 
 	chip = pwm->chip;
 
+	mutex_lock(&pwm_lock);
+
+	if (!chip->ready) {
+		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;
 
@@ -542,7 +565,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
 	 */
 	pwm_apply_state_debug(pwm, state);
 
-	return 0;
+out_unlock:
+	mutex_unlock(&pwm_lock);
+
+	return err;
 }
 EXPORT_SYMBOL_GPL(pwm_apply_state);
 
@@ -566,7 +592,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->ready)
+		err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
+	else
+		err = -ENXIO;
+
 	mutex_unlock(&pwm_lock);
 
 	return err;
@@ -978,18 +1009,17 @@ void pwm_put(struct pwm_device *pwm)
 
 	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)
+	if (pwm->chip->ready && 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 3dd46b89ab8b..f5b65994a30e 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -289,6 +289,7 @@ struct pwm_ops {
  * @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
  * @list: list node for internal use
  * @pwms: array of PWM devices allocated by the framework
+ * @ready: tracks if the chip is operational
  */
 struct pwm_chip {
 	struct device dev;
@@ -302,6 +303,7 @@ struct pwm_chip {
 	unsigned int of_pwm_n_cells;
 
 	/* only used internally by the PWM framework */
+	bool ready;
 	struct pwm_device pwms[];
 };
 
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 080/101] pwm: lpss: Store parent device in driver data
  2023-08-08 17:19 ` [PATCH v1 080/101] pwm: lpss: Store parent device " Uwe Kleine-König
@ 2023-08-08 17:49   ` Andy Shevchenko
  2023-08-09  6:10     ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Andy Shevchenko @ 2023-08-08 17:49 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Thierry Reding, linux-pwm, kernel, Bartosz Golaszewski

On Tue, Aug 08, 2023 at 07:19:10PM +0200, Uwe Kleine-König wrote:
> struct pwm_chip::dev is about to change. To not have to touch this
> driver in the same commit as struct pwm_chip::dev, store a pointer to
> the parent device in driver data.

I'm not against this change, so
Acked-by: Andy Shevchenko <andy@kernel.org>
bu see some comments below.

I think ideally pwm_chip should be an opaque to the driver
(or something near to it). OTOH it may be I understood that
wrong.

...

>  	if (state->enabled) {
>  		if (!pwm_is_enabled(pwm)) {
> -			pm_runtime_get_sync(chip->dev);
> +			pm_runtime_get_sync(lpwm->parent);
>  			ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
>  			if (ret)
> -				pm_runtime_put(chip->dev);
> +				pm_runtime_put(lpwm->parent);
>  		} else {
>  			ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
>  		}
>  	} else if (pwm_is_enabled(pwm)) {
>  		pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
> -		pm_runtime_put(chip->dev);
> +		pm_runtime_put(lpwm->parent);
>  	}

I'm wondering why PM runtime calls can't be part of PWM core?
We may cleanup a lot of code with it, no?

...

> -	pm_runtime_get_sync(chip->dev);
> +	pm_runtime_get_sync(lpwm->parent);


> -	pm_runtime_put(chip->dev);
> +	pm_runtime_put(lpwm->parent);

Ditto.

...

>  struct pwm_lpss_chip {
> +	struct device *parent;

Have you checked IIO approach with the public and private members
(under private the opaque pointer is meant)? Maybe something of that
can be applied to PWM code as well, dunno.

>  	void __iomem *regs;
>  	const struct pwm_lpss_boardinfo *info;
>  };

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 080/101] pwm: lpss: Store parent device in driver data
  2023-08-08 17:49   ` Andy Shevchenko
@ 2023-08-09  6:10     ` Uwe Kleine-König
  0 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-08-09  6:10 UTC (permalink / raw)
  To: Andy Shevchenko; +Cc: linux-pwm, Bartosz Golaszewski, Thierry Reding, kernel

[-- Attachment #1: Type: text/plain, Size: 2925 bytes --]

Hello Andy,

On Tue, Aug 08, 2023 at 08:49:53PM +0300, Andy Shevchenko wrote:
> On Tue, Aug 08, 2023 at 07:19:10PM +0200, Uwe Kleine-König wrote:
> > struct pwm_chip::dev is about to change. To not have to touch this
> > driver in the same commit as struct pwm_chip::dev, store a pointer to
> > the parent device in driver data.
> 
> I'm not against this change, so
> Acked-by: Andy Shevchenko <andy@kernel.org>
> bu see some comments below.
> 
> I think ideally pwm_chip should be an opaque to the driver
> (or something near to it). OTOH it may be I understood that
> wrong.

What would be the benefit of making it opaque? True, the drivers only
use .ops which could be added to devm_pwmchip_alloc() as a parameter to
drop the need to assign .ops, but the benefit of hiding the details
isn't clear to me.

> >  	if (state->enabled) {
> >  		if (!pwm_is_enabled(pwm)) {
> > -			pm_runtime_get_sync(chip->dev);
> > +			pm_runtime_get_sync(lpwm->parent);
> >  			ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
> >  			if (ret)
> > -				pm_runtime_put(chip->dev);
> > +				pm_runtime_put(lpwm->parent);
> >  		} else {
> >  			ret = pwm_lpss_prepare_enable(lpwm, pwm, state);
> >  		}
> >  	} else if (pwm_is_enabled(pwm)) {
> >  		pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
> > -		pm_runtime_put(chip->dev);
> > +		pm_runtime_put(lpwm->parent);
> >  	}
> 
> I'm wondering why PM runtime calls can't be part of PWM core?
> We may cleanup a lot of code with it, no?

Yes, I wondered about that one during the conversion, too. One thing at
a time. (There are also a few drivers using SET_SYSTEM_SLEEP_PM_OPS /
SET_RUNTIME_PM_OPS which could be converted to moderner variants.)

> > -	pm_runtime_get_sync(chip->dev);
> > +	pm_runtime_get_sync(lpwm->parent);
> 
> 
> > -	pm_runtime_put(chip->dev);
> > +	pm_runtime_put(lpwm->parent);
> 
> Ditto.
> 
> ...
> 
> >  struct pwm_lpss_chip {
> > +	struct device *parent;
> 
> Have you checked IIO approach with the public and private members
> (under private the opaque pointer is meant)? Maybe something of that
> can be applied to PWM code as well, dunno.

Not sure I see what you mean. I guess it's about iio_device_alloc() and
how the size calculations are done there? I didn't do any measurements
if aligning the priv data helps. ISTR that for net the aligning is done
because some drivers do DMA to/from their priv data area. That's not the
case for PWMs. So I kept that simple. I'm open to address that, but
unless there is an obvious reason that doesn't involve extensive runtime
testing, I'd postpone that for a later time and concentrate on getting
the groundwork for my character device plans done.

Thanks for your feedback
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (100 preceding siblings ...)
  2023-08-08 17:19 ` [PATCH v1 101/101] pwm: Add more locking Uwe Kleine-König
@ 2023-09-26 10:06 ` Uwe Kleine-König
  2023-10-01 11:10   ` Uwe Kleine-König
  2023-10-06  9:20 ` Thierry Reding
  102 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-09-26 10:06 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 1879 bytes --]

Hello Thierry,

On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> this series addresses the issues I reported already earlier to this
> list[1]. It is based on pwm/for-next and several patches I already sent
> out, too. Maybe some of these have to be reworked (e.g. Thierry already
> signalled not to like the patches dropping runtime error messages) but
> in the expectation that I will have to create a v2 for this series, too
> and it actually fixes a race condition, I sent the patches out for
> review anyhow. For the same reason I didn't Cc: all the individual
> maintainers.
> 
> If you want to actually test I suggest you fetch my complete history
> from
> 
> 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> 
> . 
> 
> In the end drivers have to allocate their pwm_chip using
> pwmchip_alloc(). This is important for the memory backing the pwm_chip
> being able to have a longer life than the driver.
> 
> The motivation for this series is to prepare the pwm framework to add a
> character device for each pwm_chip for easier and faster access to PWMs
> from userspace compared to the sysfs API. For such an extension proper
> lifetime tracking is important, too, as such a device can still be open
> if a PWM disappears.

I wonder how this topic will continue. This series fixes a lifetime
issue that can result in a userspace triggered oops and it builds the
base for my efforts to create a /dev/pwmchipX for faster control of PWMs
from userspace (compared to sysfs). (Currently in the prototype stage.)

I'd like to get this in during the next merge window, please tell me
what needs to be done to make this happen.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-09-26 10:06 ` [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
@ 2023-10-01 11:10   ` Uwe Kleine-König
  2023-10-06 10:15     ` Thierry Reding
  0 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-01 11:10 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel, Sean Young

[-- Attachment #1: Type: text/plain, Size: 3464 bytes --]

Hello again,

On Tue, Sep 26, 2023 at 12:06:25PM +0200, Uwe Kleine-König wrote:
> On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> > this series addresses the issues I reported already earlier to this
> > list[1]. It is based on pwm/for-next and several patches I already sent
> > out, too. Maybe some of these have to be reworked (e.g. Thierry already
> > signalled not to like the patches dropping runtime error messages) but
> > in the expectation that I will have to create a v2 for this series, too
> > and it actually fixes a race condition, I sent the patches out for
> > review anyhow. For the same reason I didn't Cc: all the individual
> > maintainers.
> > 
> > If you want to actually test I suggest you fetch my complete history
> > from
> > 
> > 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> > 
> > . 
> > 
> > In the end drivers have to allocate their pwm_chip using
> > pwmchip_alloc(). This is important for the memory backing the pwm_chip
> > being able to have a longer life than the driver.
> > 
> > The motivation for this series is to prepare the pwm framework to add a
> > character device for each pwm_chip for easier and faster access to PWMs
> > from userspace compared to the sysfs API. For such an extension proper
> > lifetime tracking is important, too, as such a device can still be open
> > if a PWM disappears.
> 
> I wonder how this topic will continue. This series fixes a lifetime
> issue that can result in a userspace triggered oops and it builds the
> base for my efforts to create a /dev/pwmchipX for faster control of PWMs
> from userspace (compared to sysfs). (Currently in the prototype stage.)
> 
> I'd like to get this in during the next merge window, please tell me
> what needs to be done to make this happen.

One problem I noticed yesterday is that this series depends on patch
"drm/ssd130x: Print the PWM's label instead of its number" that
currently waits in drm-misc-next for getting in the main line. The
series could for sure be reworked to not rely on this patch, but I'd
prefer to wait until after the next merge window instead of reworking
it.

Still, getting some feedback here in the mean time would be nice. The
questions I wonder about myself are:

 - In patch #1, devm_pwmchip_alloc() could get another parameter for the
   .ops member. This would save a line per driver like

   	chip->ops = &pwm_clk_ops;

   in return for an additional parameter that yields longer lines in the
   drivers.

 - In patch #101 instead of using &pwm_lock a per-pwmchip lock could be
   used for pwm_apply_state(). This would allow to parallelize pwm calls
   for different chips; I don't know how much this matters. Maybe the
   sensible option here is to keep it simple for now (i.e. how I
   implemented it now) until someone complains? (But see also the next
   item.)

 - A further complication is the requirement of pwm-ir-tx for faster
   pwm_apply_state() calls, see

	https://lore.kernel.org/linux-pwm/ZRb5OWvx3GxYWf9g@gofer.mess.org
   	https://lore.kernel.org/linux-pwm/1bd5241d584ceb4d6b731c4dc3203fb9686ee1d1.1696156485.git.sean@mess.org

   . This complicates the locking scheme, I didn't try to address that
   yet.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
                   ` (101 preceding siblings ...)
  2023-09-26 10:06 ` [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
@ 2023-10-06  9:20 ` Thierry Reding
  2023-10-06 10:41   ` Uwe Kleine-König
  102 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06  9:20 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 1838 bytes --]

On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> Hello,
> 
> this series addresses the issues I reported already earlier to this
> list[1]. It is based on pwm/for-next and several patches I already sent
> out, too. Maybe some of these have to be reworked (e.g. Thierry already
> signalled not to like the patches dropping runtime error messages) but
> in the expectation that I will have to create a v2 for this series, too
> and it actually fixes a race condition, I sent the patches out for
> review anyhow. For the same reason I didn't Cc: all the individual
> maintainers.
> 
> If you want to actually test I suggest you fetch my complete history
> from
> 
> 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> 
> . 
> 
> In the end drivers have to allocate their pwm_chip using
> pwmchip_alloc(). This is important for the memory backing the pwm_chip
> being able to have a longer life than the driver.

Couldn't we achieve the same thing by just making sure that drivers
don't use any of the device-managed APIs to do this? That seems like a
slightly less intrusive way of doing things.

> The motivation for this series is to prepare the pwm framework to add a
> character device for each pwm_chip for easier and faster access to PWMs
> from userspace compared to the sysfs API. For such an extension proper
> lifetime tracking is important, too, as such a device can still be open
> if a PWM disappears.

As I mentioned before, I'd like to see at least a prototype of the
character device patches before I merge this series. There's a whole lot
of churn here and without the character device support it's hard to
justify.

I have a couple more detailed comments, but I'll leave those in response
to some of the other patches for better context.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function
  2023-08-08 17:17 ` [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function Uwe Kleine-König
@ 2023-10-06  9:23   ` Thierry Reding
  2023-10-06 10:56     ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06  9:23 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 5834 bytes --]

On Tue, Aug 08, 2023 at 07:17:51PM +0200, Uwe Kleine-König wrote:
> This function allocates a struct pwm_chip and driver data. Compared to
> the status quo the split into pwm_chip and driver data is new, otherwise
> it doesn't change anything relevant (yet).
> 
> The intention is that after all drivers are switched to use this
> allocation function, its possible to add a struct device to struct
> pwm_chip to properly track the latter's lifetime without touching all
> drivers again. Proper lifetime tracking is a necessary precondition to
> introduce character device support for PWMs (that implements atomic
> setting and doesn't suffer from the sysfs overhead of the /sys/class/pwm
> userspace support).
> 
> The new function pwmchip_priv() (obviously?) only works for chips
> allocated with devm_pwmchip_alloc().
> 
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>  .../driver-api/driver-model/devres.rst        |  1 +
>  Documentation/driver-api/pwm.rst              | 10 +++----
>  drivers/pwm/core.c                            | 30 ++++++++++++++++---
>  include/linux/pwm.h                           |  5 ++++
>  4 files changed, 37 insertions(+), 9 deletions(-)
> 
> diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst
> index 8be086b3f829..73a9ee074737 100644
> --- a/Documentation/driver-api/driver-model/devres.rst
> +++ b/Documentation/driver-api/driver-model/devres.rst
> @@ -414,6 +414,7 @@ POWER
>    devm_reboot_mode_unregister()
>  
>  PWM
> +  devm_pwmchip_alloc()
>    devm_pwmchip_add()
>    devm_pwm_get()
>    devm_fwnode_pwm_get()
> diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst
> index 3fdc95f7a1d1..a3824bd58e4c 100644
> --- a/Documentation/driver-api/pwm.rst
> +++ b/Documentation/driver-api/pwm.rst
> @@ -134,11 +134,11 @@ to implement the pwm_*() functions itself. This means that it's impossible
>  to have multiple PWM drivers in the system. For this reason it's mandatory
>  for new drivers to use the generic PWM framework.
>  
> -A new PWM controller/chip can be added using pwmchip_add() and removed
> -again with pwmchip_remove(). pwmchip_add() takes a filled in struct
> -pwm_chip as argument which provides a description of the PWM chip, the
> -number of PWM devices provided by the chip and the chip-specific
> -implementation of the supported PWM operations to the framework.
> +A new PWM controller/chip can be allocated using devm_pwmchip_alloc, then added
> +using pwmchip_add() and removed again with pwmchip_remove(). pwmchip_add()
> +takes a filled in struct pwm_chip as argument which provides a description of
> +the PWM chip, the number of PWM devices provided by the chip and the
> +chip-specific implementation of the supported PWM operations to the framework.
>  
>  When implementing polarity support in a PWM driver, make sure to respect the
>  signal conventions in the PWM framework. By definition, normal polarity
> diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> index 8aa3feec12a9..cfcddf62ab01 100644
> --- a/drivers/pwm/core.c
> +++ b/drivers/pwm/core.c
> @@ -196,6 +196,31 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
>  	return true;
>  }
>  
> +void *pwmchip_priv(struct pwm_chip *chip)
> +{
> +	return &chip[1];
> +}
> +EXPORT_SYMBOL_GPL(pwmchip_priv);
> +
> +struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
> +{
> +	struct pwm_chip *chip;
> +	size_t alloc_size;
> +	unsigned int i;
> +
> +	alloc_size = sizeof(*chip) + sizeof_priv;
> +
> +	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);

Are you sure this works the way you want it to? If you allocate using
device-managed functions, this memory will be released when the driver
is unbound from the device, so we're basically back to square one,
aren't we?

> +	if (!chip)
> +		return ERR_PTR(-ENOMEM);
> +
> +	chip->dev = parent;
> +	chip->npwm = npwm;
> +
> +	return chip;
> +}
> +EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
> +
>  /**
>   * __pwmchip_add() - register a new PWM chip
>   * @chip: the PWM chip to add
> @@ -208,8 +233,6 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
>   */
>  int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
>  {
> -	struct pwm_device *pwm;
> -	unsigned int i;

Am I missing something? You seem to be using this variable in the for
loop below, so how can you remove it?

Thierry

>  	int ret;
>  
>  	if (!chip || !chip->dev || !chip->ops || !chip->npwm)
> @@ -234,9 +257,8 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
>  	}
>  
>  	chip->id = ret;
> -
>  	for (i = 0; i < chip->npwm; i++) {
> -		pwm = &chip->pwms[i];
> +		struct pwm_device *pwm = &chip->pwms[i];
>  
>  		pwm->chip = chip;
>  		pwm->hwpwm = i;
> diff --git a/include/linux/pwm.h b/include/linux/pwm.h
> index 6f139784d6f5..3c0da17e193c 100644
> --- a/include/linux/pwm.h
> +++ b/include/linux/pwm.h
> @@ -5,6 +5,7 @@
>  #include <linux/err.h>
>  #include <linux/mutex.h>
>  #include <linux/of.h>
> +#include <linux/compiler_attributes.h>
>  
>  struct pwm_chip;
>  
> @@ -380,6 +381,10 @@ static inline void pwm_disable(struct pwm_device *pwm)
>  int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
>  		unsigned long timeout);
>  
> +void *pwmchip_priv(struct pwm_chip *chip) __attribute_const__;
> +
> +struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv);
> +
>  int __pwmchip_add(struct pwm_chip *chip, struct module *owner);
>  #define pwmchip_add(chip) __pwmchip_add(chip, THIS_MODULE)
>  void pwmchip_remove(struct pwm_chip *chip);
> -- 
> 2.40.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip
  2023-08-08 17:19 ` [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip Uwe Kleine-König
@ 2023-10-06  9:38   ` Thierry Reding
  2023-10-06 11:04     ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06  9:38 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 4488 bytes --]

On Tue, Aug 08, 2023 at 07:19:00PM +0200, Uwe Kleine-König wrote:
> It's required to not free the memory underlying a requested PWM
> while a consumer still has a reference to it. While currently a pwm_chip
> doesn't life long enough in all cases, linking the struct pwm to the
> pwm_chip results in the right lifetime as soon as the pwmchip is living
> long enough. This happens with the following commits.
> 
> Note this is a breaking change for all pwm drivers that don't use
> pwmchip_alloc().
> 
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>  drivers/pwm/core.c  | 24 +++++++++---------------
>  include/linux/pwm.h |  2 +-
>  2 files changed, 10 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> index cfcddf62ab01..3b8d41fdda1b 100644
> --- a/drivers/pwm/core.c
> +++ b/drivers/pwm/core.c
> @@ -198,7 +198,7 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
>  
>  void *pwmchip_priv(struct pwm_chip *chip)
>  {
> -	return &chip[1];
> +	return &chip->pwms[chip->npwm];

I already disliked &chip[1] and this isn't making things any better. I
fully realize that this is going to give us the right address, but it
just looks wrong. Can we not do something like:

	return (void *)chip + sizeof(*chip);

instead? That would make it more explict that we're trying to get at the
extra data that was allocated. It also makes things a bit more robust
and doesn't explode when somebody decides to add fields after "pwms".

>  }
>  EXPORT_SYMBOL_GPL(pwmchip_priv);
>  
> @@ -208,7 +208,7 @@ struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
>  	size_t alloc_size;
>  	unsigned int i;
>  
> -	alloc_size = sizeof(*chip) + sizeof_priv;
> +	alloc_size = sizeof(*chip) + npwm * sizeof(struct pwm_device) + sizeof_priv;
>  
>  	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
>  	if (!chip)
> @@ -217,6 +217,13 @@ struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
>  	chip->dev = parent;
>  	chip->npwm = npwm;
>  
> +	for (i = 0; i < chip->npwm; i++) {
> +		struct pwm_device *pwm = &chip->pwms[i];
> +
> +		pwm->chip = chip;
> +		pwm->hwpwm = i;
> +	}
> +
>  	return chip;
>  }
>  EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
> @@ -243,26 +250,15 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
>  
>  	chip->owner = owner;
>  
> -	chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL);

I think the structure of this patch series is a bit weird. Basically
you're not actually improving things until the very end, at which point
all questions get resolved.

What this patch does isn't actually changing anything about the object
lifetimes. chip->pwms still goes away at the same time (effectively)
because the chip's memory allocation will be released shortly after
pwmchip_remove() is called.

It isn't until the very end of the series that you actually fix up the
lifetime problem. So I read through the entire series trying to make
sense of all this and commenting where things aren't going to work as
expected, only to realize it isn't all going to fall in place until the
very end.

So I think you should either make this clearer in the commit message or
make sure that things like pwmchip_alloc() do the right things from the
start.

Thierry

> -	if (!chip->pwms)
> -		return -ENOMEM;
> -
>  	mutex_lock(&pwm_lock);
>  
>  	ret = idr_alloc(&pwmchip_idr, chip, 0, 0, GFP_KERNEL);
>  	if (ret < 0) {
>  		mutex_unlock(&pwm_lock);
> -		kfree(chip->pwms);
>  		return ret;
>  	}
>  
>  	chip->id = ret;
> -	for (i = 0; i < chip->npwm; i++) {
> -		struct pwm_device *pwm = &chip->pwms[i];
> -
> -		pwm->chip = chip;
> -		pwm->hwpwm = i;
> -	}
>  
>  	mutex_unlock(&pwm_lock);
>  
> @@ -293,8 +289,6 @@ void pwmchip_remove(struct pwm_chip *chip)
>  	idr_remove(&pwmchip_idr, chip->id);
>  
>  	mutex_unlock(&pwm_lock);
> -
> -	kfree(chip->pwms);
>  }
>  EXPORT_SYMBOL_GPL(pwmchip_remove);
>  
> diff --git a/include/linux/pwm.h b/include/linux/pwm.h
> index 3c0da17e193c..fbcba204de44 100644
> --- a/include/linux/pwm.h
> +++ b/include/linux/pwm.h
> @@ -301,7 +301,7 @@ struct pwm_chip {
>  	unsigned int of_pwm_n_cells;
>  
>  	/* only used internally by the PWM framework */
> -	struct pwm_device *pwms;
> +	struct pwm_device pwms[];
>  };
>  
>  #if IS_ENABLED(CONFIG_PWM)
> -- 
> 2.40.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data
  2023-08-08 17:19 ` [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data Uwe Kleine-König
@ 2023-10-06  9:41   ` Thierry Reding
  2023-10-06 11:09     ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06  9:41 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 3955 bytes --]

On Tue, Aug 08, 2023 at 07:19:01PM +0200, Uwe Kleine-König wrote:
> struct pwm_chip::dev is about to change. To not have to touch this
> driver in the same commit as struct pwm_chip::dev, store a pointer to
> the parent device in driver data.
> 
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>  drivers/pwm/pwm-ab8500.c | 16 +++++++++-------
>  1 file changed, 9 insertions(+), 7 deletions(-)

You're basically adding a parent device to all driver-private data
structures in this and the following patches, so why not keep in in
struct pwm_chip and simply rename chip->dev to chip->parent?

As Andy has commented, this would eventually allow the PWM core to
take care of certain things like runtime PM, or even only for stuff
like using the parent device name in info/debug/error messages.

Also, you could then just make this a single large patch that renames
dev to parent in one go rather than making this large set even larger
with this kind of trivial changes.

Thierry

> 
> diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c
> index f64f3fd251e7..663fdfe90bb6 100644
> --- a/drivers/pwm/pwm-ab8500.c
> +++ b/drivers/pwm/pwm-ab8500.c
> @@ -24,6 +24,7 @@
>  #define AB8500_PWM_CLKRATE 9600000
>  
>  struct ab8500_pwm_chip {
> +	struct device *parent;
>  	unsigned int hwid;
>  };
>  
> @@ -91,7 +92,7 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
>  	 * when disabled.
>  	 */
>  	if (!state->enabled || duty_steps == 0) {
> -		ret = abx500_mask_and_set_register_interruptible(chip->dev,
> +		ret = abx500_mask_and_set_register_interruptible(ab8500->parent,
>  					AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
>  					1 << ab8500->hwid, 0);
>  
> @@ -111,18 +112,18 @@ static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
>  
>  	reg = AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2);
>  
> -	ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
> +	ret = abx500_set_register_interruptible(ab8500->parent, AB8500_MISC,
>  			reg, lower_val);
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
> +	ret = abx500_set_register_interruptible(ab8500->parent, AB8500_MISC,
>  			(reg + 1), higher_val);
>  	if (ret < 0)
>  		return ret;
>  
>  	/* enable */
> -	ret = abx500_mask_and_set_register_interruptible(chip->dev,
> +	ret = abx500_mask_and_set_register_interruptible(ab8500->parent,
>  				AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
>  				1 << ab8500->hwid, 1 << ab8500->hwid);
>  
> @@ -137,7 +138,7 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
>  	struct ab8500_pwm_chip *ab8500 = ab8500_pwm_from_chip(chip);
>  	unsigned int div, duty_steps;
>  
> -	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
> +	ret = abx500_get_register_interruptible(ab8500->parent, AB8500_MISC,
>  						AB8500_PWM_OUT_CTRL7_REG,
>  						&ctrl7);
>  	if (ret)
> @@ -150,13 +151,13 @@ static int ab8500_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
>  		return 0;
>  	}
>  
> -	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
> +	ret = abx500_get_register_interruptible(ab8500->parent, AB8500_MISC,
>  						AB8500_PWM_OUT_CTRL1_REG + (ab8500->hwid * 2),
>  						&lower_val);
>  	if (ret)
>  		return ret;
>  
> -	ret = abx500_get_register_interruptible(chip->dev, AB8500_MISC,
> +	ret = abx500_get_register_interruptible(ab8500->parent, AB8500_MISC,
>  						AB8500_PWM_OUT_CTRL2_REG + (ab8500->hwid * 2),
>  						&higher_val);
>  	if (ret)
> @@ -196,6 +197,7 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
>  	ab8500 = pwmchip_priv(chip);
>  
>  	chip->ops = &ab8500_pwm_ops;
> +	ab8500->parent = &pdev->dev;
>  	ab8500->hwid = pdev->id - 1;
>  
>  	err = devm_pwmchip_add(&pdev->dev, chip);
> -- 
> 2.40.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 101/101] pwm: Add more locking
  2023-08-08 17:19 ` [PATCH v1 101/101] pwm: Add more locking Uwe Kleine-König
@ 2023-10-06 10:09   ` Thierry Reding
  2023-10-06 11:14     ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06 10:09 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 6149 bytes --]

On Tue, Aug 08, 2023 at 07:19:31PM +0200, Uwe Kleine-König wrote:
> 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 was not expected to be a problem in the
> presence of device links, but still it can happen with the command
> sequence mentioned in the previous commit. Even if this should turn out
> to be a problem that could be fixed by improving device links, this is a
> necessary preparation to create race-free pwmchip character devices.
> 
> A not so nice side effect is that all calls to the PWM API are
> serialized now. If this turns out to be problematic this can be replaced
> by per-pwm_chip locking later. As long as this bottleneck isn't known to
> be a problem in practise, the simpler approach of a single lock is used
> here.
> 
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>  drivers/pwm/core.c  | 50 ++++++++++++++++++++++++++++++++++++---------
>  include/linux/pwm.h |  2 ++
>  2 files changed, 42 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> index fcf30f77da34..66743ded66f6 100644
> --- a/drivers/pwm/core.c
> +++ b/drivers/pwm/core.c
> @@ -230,6 +230,7 @@ static struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm,
>  	dev->release = pwmchip_release;
>  
>  	chip->npwm = npwm;
> +	chip->ready = false;
>  
>  	for (i = 0; i < chip->npwm; i++) {
>  		struct pwm_device *pwm = &chip->pwms[i];
> @@ -309,6 +310,8 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
>  		module_put(owner);
>  	}
>  
> +	chip->ready = true;
> +
>  	mutex_unlock(&pwm_lock);
>  
>  	return ret;
> @@ -324,12 +327,25 @@ EXPORT_SYMBOL_GPL(__pwmchip_add);
>  void pwmchip_remove(struct pwm_chip *chip)
>  {
>  	pwmchip_sysfs_unexport(chip);
> +	unsigned int i;

This looks weird, mixing declarations and code.

>  
>  	if (IS_ENABLED(CONFIG_OF))
>  		of_pwmchip_remove(chip);
>  
>  	mutex_lock(&pwm_lock);
>  
> +	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);

s/pwm #%u/PWM #%u/

> +			if (pwm->chip->ops->free)
> +				pwm->chip->ops->free(pwm->chip, pwm);
> +		}
> +	}
> +
> +	chip->ready = false;
> +
>  	idr_remove(&pwmchip_idr, chip->id);
>  
>  	mutex_unlock(&pwm_lock);
> @@ -505,7 +521,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
> @@ -522,17 +538,24 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
>  
>  	chip = pwm->chip;
>  
> +	mutex_lock(&pwm_lock);
> +
> +	if (!chip->ready) {
> +		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;
>  
> @@ -542,7 +565,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
>  	 */
>  	pwm_apply_state_debug(pwm, state);
>  
> -	return 0;
> +out_unlock:
> +	mutex_unlock(&pwm_lock);
> +
> +	return err;
>  }
>  EXPORT_SYMBOL_GPL(pwm_apply_state);
>  
> @@ -566,7 +592,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->ready)
> +		err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
> +	else
> +		err = -ENXIO;
> +
>  	mutex_unlock(&pwm_lock);
>  
>  	return err;
> @@ -978,18 +1009,17 @@ void pwm_put(struct pwm_device *pwm)
>  
>  	mutex_lock(&pwm_lock);
>  
> -	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
> -		pr_warn("PWM device already freed\n");

Don't we want to keep this message? We do want to make sure that we're
always calling things in the right order and this might help catch
errors.

> +	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags))
>  		goto out;
> -	}
>  
> -	if (pwm->chip->ops->free)
> +	if (pwm->chip->ready && pwm->chip->ops->free)
>  		pwm->chip->ops->free(pwm->chip, pwm);

These callbacks may do things like decrease internal reference counts or
free memory, etc. Don't we want to run those even if the PWM chip isn't
operational anymore? Wouldn't we otherwise risk leaking memory and/or
other resources?

>  
>  	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 3dd46b89ab8b..f5b65994a30e 100644
> --- a/include/linux/pwm.h
> +++ b/include/linux/pwm.h
> @@ -289,6 +289,7 @@ struct pwm_ops {
>   * @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
>   * @list: list node for internal use
>   * @pwms: array of PWM devices allocated by the framework
> + * @ready: tracks if the chip is operational
>   */
>  struct pwm_chip {
>  	struct device dev;
> @@ -302,6 +303,7 @@ struct pwm_chip {
>  	unsigned int of_pwm_n_cells;
>  
>  	/* only used internally by the PWM framework */
> +	bool ready;

Can we find a better name for this? Maybe something like "available" or
"operational"? Those are a bit longer, but I feel like they convey more
accurately what's going on. In other words, "ready" is very vague.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-10-01 11:10   ` Uwe Kleine-König
@ 2023-10-06 10:15     ` Thierry Reding
  2023-10-06 17:05       ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06 10:15 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel, Sean Young

[-- Attachment #1: Type: text/plain, Size: 4031 bytes --]

On Sun, Oct 01, 2023 at 01:10:24PM +0200, Uwe Kleine-König wrote:
> Hello again,
> 
> On Tue, Sep 26, 2023 at 12:06:25PM +0200, Uwe Kleine-König wrote:
> > On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> > > this series addresses the issues I reported already earlier to this
> > > list[1]. It is based on pwm/for-next and several patches I already sent
> > > out, too. Maybe some of these have to be reworked (e.g. Thierry already
> > > signalled not to like the patches dropping runtime error messages) but
> > > in the expectation that I will have to create a v2 for this series, too
> > > and it actually fixes a race condition, I sent the patches out for
> > > review anyhow. For the same reason I didn't Cc: all the individual
> > > maintainers.
> > > 
> > > If you want to actually test I suggest you fetch my complete history
> > > from
> > > 
> > > 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> > > 
> > > . 
> > > 
> > > In the end drivers have to allocate their pwm_chip using
> > > pwmchip_alloc(). This is important for the memory backing the pwm_chip
> > > being able to have a longer life than the driver.
> > > 
> > > The motivation for this series is to prepare the pwm framework to add a
> > > character device for each pwm_chip for easier and faster access to PWMs
> > > from userspace compared to the sysfs API. For such an extension proper
> > > lifetime tracking is important, too, as such a device can still be open
> > > if a PWM disappears.
> > 
> > I wonder how this topic will continue. This series fixes a lifetime
> > issue that can result in a userspace triggered oops and it builds the
> > base for my efforts to create a /dev/pwmchipX for faster control of PWMs
> > from userspace (compared to sysfs). (Currently in the prototype stage.)
> > 
> > I'd like to get this in during the next merge window, please tell me
> > what needs to be done to make this happen.
> 
> One problem I noticed yesterday is that this series depends on patch
> "drm/ssd130x: Print the PWM's label instead of its number" that
> currently waits in drm-misc-next for getting in the main line. The
> series could for sure be reworked to not rely on this patch, but I'd
> prefer to wait until after the next merge window instead of reworking
> it.
> 
> Still, getting some feedback here in the mean time would be nice. The
> questions I wonder about myself are:
> 
>  - In patch #1, devm_pwmchip_alloc() could get another parameter for the
>    .ops member. This would save a line per driver like
> 
>    	chip->ops = &pwm_clk_ops;
> 
>    in return for an additional parameter that yields longer lines in the
>    drivers.
> 
>  - In patch #101 instead of using &pwm_lock a per-pwmchip lock could be
>    used for pwm_apply_state(). This would allow to parallelize pwm calls
>    for different chips; I don't know how much this matters. Maybe the
>    sensible option here is to keep it simple for now (i.e. how I
>    implemented it now) until someone complains? (But see also the next
>    item.)
> 
>  - A further complication is the requirement of pwm-ir-tx for faster
>    pwm_apply_state() calls, see
> 
> 	https://lore.kernel.org/linux-pwm/ZRb5OWvx3GxYWf9g@gofer.mess.org
>    	https://lore.kernel.org/linux-pwm/1bd5241d584ceb4d6b731c4dc3203fb9686ee1d1.1696156485.git.sean@mess.org
> 
>    . This complicates the locking scheme, I didn't try to address that
>    yet.

Frankly, I think per-chip locking is the only way to support slow
busses. If we use the subsystem-wide lock, effectively all chips become
slow and unusable for things like pwm-ir-tx.

Perhaps we can draw some inspiration from how the IRQ infrastructure
deals with this? IRQ chips have irq_bus_lock() and irq_bus_sync_unlock()
callbacks to deal with this. We could have something similar for PWM
chips. Perhaps that's even something that could be handled in the core
by checking a "might_sleep" flag for the chip.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-10-06  9:20 ` Thierry Reding
@ 2023-10-06 10:41   ` Uwe Kleine-König
  2023-10-06 11:50     ` Thierry Reding
  0 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 10:41 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 3772 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 11:20:03AM +0200, Thierry Reding wrote:
> On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> > this series addresses the issues I reported already earlier to this
> > list[1]. It is based on pwm/for-next and several patches I already sent
> > out, too. Maybe some of these have to be reworked (e.g. Thierry already
> > signalled not to like the patches dropping runtime error messages) but
> > in the expectation that I will have to create a v2 for this series, too
> > and it actually fixes a race condition, I sent the patches out for
> > review anyhow. For the same reason I didn't Cc: all the individual
> > maintainers.
> > 
> > If you want to actually test I suggest you fetch my complete history
> > from
> > 
> > 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> > 
> > . 
> > 
> > In the end drivers have to allocate their pwm_chip using
> > pwmchip_alloc(). This is important for the memory backing the pwm_chip
> > being able to have a longer life than the driver.
> 
> Couldn't we achieve the same thing by just making sure that drivers
> don't use any of the device-managed APIs to do this? That seems like a
> slightly less intrusive way of doing things.

The device-managed APIs are not the problem here. If you allocate in
.probe and free in .remove there is a problem. (And that's exactly what
the device managed APIs do.)

So no, you cannot. The thing is the struct pwm_chip must stay around until
the last reference is dropped. So you need some kind of reference
counting. The canonical way to do that is using a struct device.

You can try to hide it from the low-level drivers (as gpio does) at the
cost that you have the driver allocated structure separate from the
reference counted memory under framework control. The cost is more
overhead because you have >1 memory chunk (memory fragmentation, less
cache locality) and more pointers. IMHO the cleaner way is to not hide
it and have the explicit handling needed in the drivers be not error
prone (as spi does).

I agree the switch suggested here is intrusive, but the "new way" a
driver has to look like is fine, so I'd not hesitate here.

> > The motivation for this series is to prepare the pwm framework to add a
> > character device for each pwm_chip for easier and faster access to PWMs
> > from userspace compared to the sysfs API. For such an extension proper
> > lifetime tracking is important, too, as such a device can still be open
> > if a PWM disappears.
> 
> As I mentioned before, I'd like to see at least a prototype of the
> character device patches before I merge this series. There's a whole lot
> of churn here and without the character device support it's hard to
> justify.

The character device stuff is only one reason to get the lifetime
tracking right. See that oops I can trigger today that is fixed by this
series.

> I have a couple more detailed comments, but I'll leave those in response
> to some of the other patches for better context.

Earlier today I managed to get this character support working enough to
be able to trigger pwm_apply_state calls. My test case looks
(simplified) like this:

	state.period = 50000;
	for (state.duty_cycle = 0; state.duty_cycle <= state.period; ++state.duty_cycle)
		pwm_apply_state(pwm, &state);

With a naive sysfs backend that takes approx. a minute. With an
optimized version (that only writes the duty_cycle file in the above
case) it goes down to 20s. With the character device it takes 4.7s.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function
  2023-10-06  9:23   ` Thierry Reding
@ 2023-10-06 10:56     ` Uwe Kleine-König
  2023-10-06 11:08       ` Thierry Reding
  0 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 10:56 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 2291 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 11:23:49AM +0200, Thierry Reding wrote:
> On Tue, Aug 08, 2023 at 07:17:51PM +0200, Uwe Kleine-König wrote:
> > +struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
> > +{
> > +	struct pwm_chip *chip;
> > +	size_t alloc_size;
> > +	unsigned int i;
> > +
> > +	alloc_size = sizeof(*chip) + sizeof_priv;
> > +
> > +	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
> 
> Are you sure this works the way you want it to? If you allocate using
> device-managed functions, this memory will be released when the driver
> is unbound from the device, so we're basically back to square one,
> aren't we?

After this patch the problem with broken lifetimes isn't fixed. Today
the way the pwm_chip is allocated is a problem in each driver. With this
function (that indeed suffers from the same problem) the issue can be
shifted from each individual driver to this function (patches #2 - #69).
Then the lifetime tracking can get fixed in a single place without
touching all drivers in one single commit (patches #70, #100 and #101).
With the whole series applied this devm_kzalloc is indeed gone -- this
can however only happen when all drivers use devm_pwmchip_alloc().

If you have a better idea how to split such a conversion in managable
and reviewable patches, I'm all ears.

> > +	if (!chip)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	chip->dev = parent;
> > +	chip->npwm = npwm;
> > +
> > +	return chip;
> > +}
> > +EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
> > +
> >  /**
> >   * __pwmchip_add() - register a new PWM chip
> >   * @chip: the PWM chip to add
> > @@ -208,8 +233,6 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
> >   */
> >  int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
> >  {
> > -	struct pwm_device *pwm;
> > -	unsigned int i;
> 
> Am I missing something? You seem to be using this variable in the for
> loop below, so how can you remove it?

Yeah, that series might not be bisectable. This will be fixed in the
next iteration.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip
  2023-10-06  9:38   ` Thierry Reding
@ 2023-10-06 11:04     ` Uwe Kleine-König
  2023-10-06 11:16       ` Thierry Reding
  0 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 11:04 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 4634 bytes --]

On Fri, Oct 06, 2023 at 11:38:12AM +0200, Thierry Reding wrote:
> On Tue, Aug 08, 2023 at 07:19:00PM +0200, Uwe Kleine-König wrote:
> > It's required to not free the memory underlying a requested PWM
> > while a consumer still has a reference to it. While currently a pwm_chip
> > doesn't life long enough in all cases, linking the struct pwm to the
> > pwm_chip results in the right lifetime as soon as the pwmchip is living
> > long enough. This happens with the following commits.
> > 
> > Note this is a breaking change for all pwm drivers that don't use
> > pwmchip_alloc().
> > 
> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > ---
> >  drivers/pwm/core.c  | 24 +++++++++---------------
> >  include/linux/pwm.h |  2 +-
> >  2 files changed, 10 insertions(+), 16 deletions(-)
> > 
> > diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> > index cfcddf62ab01..3b8d41fdda1b 100644
> > --- a/drivers/pwm/core.c
> > +++ b/drivers/pwm/core.c
> > @@ -198,7 +198,7 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
> >  
> >  void *pwmchip_priv(struct pwm_chip *chip)
> >  {
> > -	return &chip[1];
> > +	return &chip->pwms[chip->npwm];
> 
> I already disliked &chip[1] and this isn't making things any better. I
> fully realize that this is going to give us the right address, but it
> just looks wrong. Can we not do something like:
> 
> 	return (void *)chip + sizeof(*chip);

In practise this works, but I'm not 100% confident that the compiler
might not add padding that breaks this. I don't particularly like this
function either and will think a bit more about it for v2.

> instead? That would make it more explict that we're trying to get at the
> extra data that was allocated. It also makes things a bit more robust
> and doesn't explode when somebody decides to add fields after "pwms".

Things will explode if the flexible array member isn't at the end of
struct pwm_chip no matter how you implement pwmchip_priv.

> >  }
> >  EXPORT_SYMBOL_GPL(pwmchip_priv);
> >  
> > @@ -208,7 +208,7 @@ struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
> >  	size_t alloc_size;
> >  	unsigned int i;
> >  
> > -	alloc_size = sizeof(*chip) + sizeof_priv;
> > +	alloc_size = sizeof(*chip) + npwm * sizeof(struct pwm_device) + sizeof_priv;
> >  
> >  	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
> >  	if (!chip)
> > @@ -217,6 +217,13 @@ struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, si
> >  	chip->dev = parent;
> >  	chip->npwm = npwm;
> >  
> > +	for (i = 0; i < chip->npwm; i++) {
> > +		struct pwm_device *pwm = &chip->pwms[i];
> > +
> > +		pwm->chip = chip;
> > +		pwm->hwpwm = i;
> > +	}
> > +
> >  	return chip;
> >  }
> >  EXPORT_SYMBOL_GPL(devm_pwmchip_alloc);
> > @@ -243,26 +250,15 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
> >  
> >  	chip->owner = owner;
> >  
> > -	chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL);
> 
> I think the structure of this patch series is a bit weird. Basically
> you're not actually improving things until the very end, at which point
> all questions get resolved.
> 
> What this patch does isn't actually changing anything about the object
> lifetimes. chip->pwms still goes away at the same time (effectively)
> because the chip's memory allocation will be released shortly after
> pwmchip_remove() is called.
> 
> It isn't until the very end of the series that you actually fix up the
> lifetime problem. So I read through the entire series trying to make
> sense of all this and commenting where things aren't going to work as
> expected, only to realize it isn't all going to fall in place until the
> very end.
> 
> So I think you should either make this clearer in the commit message or
> make sure that things like pwmchip_alloc() do the right things from the
> start.

The commit log for the function introducing pwmchip_alloc() has:

	Compared to the status quo [...] it doesn't change anything
	relevant (yet).

	The intention is that after all drivers are switched to use this
	allocation function, its possible to add a struct device to struct
	pwm_chip to properly track the latter's lifetime without touching all
	drivers again.

The intention of this text is exactly what you asked for. If you have a
better wording I'm open to hear your suggestions.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function
  2023-10-06 10:56     ` Uwe Kleine-König
@ 2023-10-06 11:08       ` Thierry Reding
  2023-10-06 12:36         ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06 11:08 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 1831 bytes --]

On Fri, Oct 06, 2023 at 12:56:26PM +0200, Uwe Kleine-König wrote:
> Hello Thierry,
> 
> On Fri, Oct 06, 2023 at 11:23:49AM +0200, Thierry Reding wrote:
> > On Tue, Aug 08, 2023 at 07:17:51PM +0200, Uwe Kleine-König wrote:
> > > +struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
> > > +{
> > > +	struct pwm_chip *chip;
> > > +	size_t alloc_size;
> > > +	unsigned int i;
> > > +
> > > +	alloc_size = sizeof(*chip) + sizeof_priv;
> > > +
> > > +	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
> > 
> > Are you sure this works the way you want it to? If you allocate using
> > device-managed functions, this memory will be released when the driver
> > is unbound from the device, so we're basically back to square one,
> > aren't we?
> 
> After this patch the problem with broken lifetimes isn't fixed. Today
> the way the pwm_chip is allocated is a problem in each driver. With this
> function (that indeed suffers from the same problem) the issue can be
> shifted from each individual driver to this function (patches #2 - #69).
> Then the lifetime tracking can get fixed in a single place without
> touching all drivers in one single commit (patches #70, #100 and #101).
> With the whole series applied this devm_kzalloc is indeed gone -- this
> can however only happen when all drivers use devm_pwmchip_alloc().
> 
> If you have a better idea how to split such a conversion in managable
> and reviewable patches, I'm all ears.

Is there anything that would prevent us from merging the really
interesting bits from patch 100 into this first patch? It might make
the first patch a bit larger, but at the same time it would immediately
become clear why this is useful rather than 99 patches of churn without
actual improvements.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data
  2023-10-06  9:41   ` Thierry Reding
@ 2023-10-06 11:09     ` Uwe Kleine-König
  2023-10-06 11:20       ` Thierry Reding
  0 siblings, 1 reply; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 11:09 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 1767 bytes --]

Hello,

On Fri, Oct 06, 2023 at 11:41:51AM +0200, Thierry Reding wrote:
> On Tue, Aug 08, 2023 at 07:19:01PM +0200, Uwe Kleine-König wrote:
> > struct pwm_chip::dev is about to change. To not have to touch this
> > driver in the same commit as struct pwm_chip::dev, store a pointer to
> > the parent device in driver data.
> > 
> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > ---
> >  drivers/pwm/pwm-ab8500.c | 16 +++++++++-------
> >  1 file changed, 9 insertions(+), 7 deletions(-)
> 
> You're basically adding a parent device to all driver-private data
> structures in this and the following patches, so why not keep in in
> struct pwm_chip and simply rename chip->dev to chip->parent?
> 
> As Andy has commented, this would eventually allow the PWM core to
> take care of certain things like runtime PM, or even only for stuff
> like using the parent device name in info/debug/error messages.
> 
> Also, you could then just make this a single large patch that renames
> dev to parent in one go rather than making this large set even larger
> with this kind of trivial changes.

The idea here is (again) that I don't have to touch all drivers in the
commit that changes struct pwm_chip.

In the end there is such a parent pointer (pwmchip.dev.parent). Would
you prefer a macro (say) pwmchip_parentdev that can be defined as

	#define pwmchip_parentdev(chip) (chip)->dev

at the beginning and then be changed to

	#define pwmchip_parentdev(chip) (chip)->dev.parent

in the right moment? That's the best idea I have here.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 101/101] pwm: Add more locking
  2023-10-06 10:09   ` Thierry Reding
@ 2023-10-06 11:14     ` Uwe Kleine-König
  0 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 11:14 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 6876 bytes --]

On Fri, Oct 06, 2023 at 12:09:59PM +0200, Thierry Reding wrote:
> On Tue, Aug 08, 2023 at 07:19:31PM +0200, Uwe Kleine-König wrote:
> > 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 was not expected to be a problem in the
> > presence of device links, but still it can happen with the command
> > sequence mentioned in the previous commit. Even if this should turn out
> > to be a problem that could be fixed by improving device links, this is a
> > necessary preparation to create race-free pwmchip character devices.
> > 
> > A not so nice side effect is that all calls to the PWM API are
> > serialized now. If this turns out to be problematic this can be replaced
> > by per-pwm_chip locking later. As long as this bottleneck isn't known to
> > be a problem in practise, the simpler approach of a single lock is used
> > here.
> > 
> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > ---
> >  drivers/pwm/core.c  | 50 ++++++++++++++++++++++++++++++++++++---------
> >  include/linux/pwm.h |  2 ++
> >  2 files changed, 42 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> > index fcf30f77da34..66743ded66f6 100644
> > --- a/drivers/pwm/core.c
> > +++ b/drivers/pwm/core.c
> > @@ -230,6 +230,7 @@ static struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm,
> >  	dev->release = pwmchip_release;
> >  
> >  	chip->npwm = npwm;
> > +	chip->ready = false;
> >  
> >  	for (i = 0; i < chip->npwm; i++) {
> >  		struct pwm_device *pwm = &chip->pwms[i];
> > @@ -309,6 +310,8 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
> >  		module_put(owner);
> >  	}
> >  
> > +	chip->ready = true;
> > +
> >  	mutex_unlock(&pwm_lock);
> >  
> >  	return ret;
> > @@ -324,12 +327,25 @@ EXPORT_SYMBOL_GPL(__pwmchip_add);
> >  void pwmchip_remove(struct pwm_chip *chip)
> >  {
> >  	pwmchip_sysfs_unexport(chip);
> > +	unsigned int i;
> 
> This looks weird, mixing declarations and code.
> 
> >  
> >  	if (IS_ENABLED(CONFIG_OF))
> >  		of_pwmchip_remove(chip);
> >  
> >  	mutex_lock(&pwm_lock);
> >  
> > +	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);
> 
> s/pwm #%u/PWM #%u/
> 
> > +			if (pwm->chip->ops->free)
> > +				pwm->chip->ops->free(pwm->chip, pwm);
> > +		}
> > +	}
> > +
> > +	chip->ready = false;
> > +
> >  	idr_remove(&pwmchip_idr, chip->id);
> >  
> >  	mutex_unlock(&pwm_lock);
> > @@ -505,7 +521,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
> > @@ -522,17 +538,24 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
> >  
> >  	chip = pwm->chip;
> >  
> > +	mutex_lock(&pwm_lock);
> > +
> > +	if (!chip->ready) {
> > +		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;
> >  
> > @@ -542,7 +565,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
> >  	 */
> >  	pwm_apply_state_debug(pwm, state);
> >  
> > -	return 0;
> > +out_unlock:
> > +	mutex_unlock(&pwm_lock);
> > +
> > +	return err;
> >  }
> >  EXPORT_SYMBOL_GPL(pwm_apply_state);
> >  
> > @@ -566,7 +592,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->ready)
> > +		err = pwm->chip->ops->capture(pwm->chip, pwm, result, timeout);
> > +	else
> > +		err = -ENXIO;
> > +
> >  	mutex_unlock(&pwm_lock);
> >  
> >  	return err;
> > @@ -978,18 +1009,17 @@ void pwm_put(struct pwm_device *pwm)
> >  
> >  	mutex_lock(&pwm_lock);
> >  
> > -	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags)) {
> > -		pr_warn("PWM device already freed\n");
> 
> Don't we want to keep this message? We do want to make sure that we're
> always calling things in the right order and this might help catch
> errors.

No, if this triggers we already got

	dev_alert(&chip->dev, "Freeing requested PWM #%u\n", i);

in pwmchip_remove() before.

> 
> > +	if (!test_and_clear_bit(PWMF_REQUESTED, &pwm->flags))
> >  		goto out;
> > -	}
> >  
> > -	if (pwm->chip->ops->free)
> > +	if (pwm->chip->ready && pwm->chip->ops->free)
> >  		pwm->chip->ops->free(pwm->chip, pwm);
> 
> These callbacks may do things like decrease internal reference counts or
> free memory, etc. Don't we want to run those even if the PWM chip isn't
> operational anymore? Wouldn't we otherwise risk leaking memory and/or
> other resources?

It is run, in pwmchip_remove().

> > diff --git a/include/linux/pwm.h b/include/linux/pwm.h
> > index 3dd46b89ab8b..f5b65994a30e 100644
> > --- a/include/linux/pwm.h
> > +++ b/include/linux/pwm.h
> > @@ -289,6 +289,7 @@ struct pwm_ops {
> >   * @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
> >   * @list: list node for internal use
> >   * @pwms: array of PWM devices allocated by the framework
> > + * @ready: tracks if the chip is operational
> >   */
> >  struct pwm_chip {
> >  	struct device dev;
> > @@ -302,6 +303,7 @@ struct pwm_chip {
> >  	unsigned int of_pwm_n_cells;
> >  
> >  	/* only used internally by the PWM framework */
> > +	bool ready;
> 
> Can we find a better name for this? Maybe something like "available" or
> "operational"? Those are a bit longer, but I feel like they convey more
> accurately what's going on. In other words, "ready" is very vague.

I don't think that "available" or "operational" is relevant better than
"ready", but I don't care much. I'd pick "operational" over "available".

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip
  2023-10-06 11:04     ` Uwe Kleine-König
@ 2023-10-06 11:16       ` Thierry Reding
  2023-10-06 17:04         ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06 11:16 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 2892 bytes --]

On Fri, Oct 06, 2023 at 01:04:51PM +0200, Uwe Kleine-König wrote:
> On Fri, Oct 06, 2023 at 11:38:12AM +0200, Thierry Reding wrote:
> > On Tue, Aug 08, 2023 at 07:19:00PM +0200, Uwe Kleine-König wrote:
> > > It's required to not free the memory underlying a requested PWM
> > > while a consumer still has a reference to it. While currently a pwm_chip
> > > doesn't life long enough in all cases, linking the struct pwm to the
> > > pwm_chip results in the right lifetime as soon as the pwmchip is living
> > > long enough. This happens with the following commits.
> > > 
> > > Note this is a breaking change for all pwm drivers that don't use
> > > pwmchip_alloc().
> > > 
> > > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > > ---
> > >  drivers/pwm/core.c  | 24 +++++++++---------------
> > >  include/linux/pwm.h |  2 +-
> > >  2 files changed, 10 insertions(+), 16 deletions(-)
> > > 
> > > diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> > > index cfcddf62ab01..3b8d41fdda1b 100644
> > > --- a/drivers/pwm/core.c
> > > +++ b/drivers/pwm/core.c
> > > @@ -198,7 +198,7 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
> > >  
> > >  void *pwmchip_priv(struct pwm_chip *chip)
> > >  {
> > > -	return &chip[1];
> > > +	return &chip->pwms[chip->npwm];
> > 
> > I already disliked &chip[1] and this isn't making things any better. I
> > fully realize that this is going to give us the right address, but it
> > just looks wrong. Can we not do something like:
> > 
> > 	return (void *)chip + sizeof(*chip);
> 
> In practise this works, but I'm not 100% confident that the compiler
> might not add padding that breaks this. I don't particularly like this
> function either and will think a bit more about it for v2.

I'm not at all a fan of this whole pwmchip_alloc() business and I would
prefer if we could somehow just keep embedding this into the driver-
specific structures and take care of the lifetime management with less
intrusion.

However, I don't see how that could easily be done. It would be slightly
easier if we didn't use the flexible array, I suppose.

> 
> > instead? That would make it more explict that we're trying to get at the
> > extra data that was allocated. It also makes things a bit more robust
> > and doesn't explode when somebody decides to add fields after "pwms".
> 
> Things will explode if the flexible array member isn't at the end of
> struct pwm_chip no matter how you implement pwmchip_priv.

Perhaps one more reason to avoid the flexible array member. It's not
that big a deal, but I'm all for keeping things simple, and that whole
business of computing the allocation size and then making sure we point
at the right offsets just doesn't seem like the optimal way to do
things, even though I'm well aware that it's common practice elsewhere.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data
  2023-10-06 11:09     ` Uwe Kleine-König
@ 2023-10-06 11:20       ` Thierry Reding
  2023-10-06 21:16         ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06 11:20 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 2181 bytes --]

On Fri, Oct 06, 2023 at 01:09:51PM +0200, Uwe Kleine-König wrote:
> Hello,
> 
> On Fri, Oct 06, 2023 at 11:41:51AM +0200, Thierry Reding wrote:
> > On Tue, Aug 08, 2023 at 07:19:01PM +0200, Uwe Kleine-König wrote:
> > > struct pwm_chip::dev is about to change. To not have to touch this
> > > driver in the same commit as struct pwm_chip::dev, store a pointer to
> > > the parent device in driver data.
> > > 
> > > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > > ---
> > >  drivers/pwm/pwm-ab8500.c | 16 +++++++++-------
> > >  1 file changed, 9 insertions(+), 7 deletions(-)
> > 
> > You're basically adding a parent device to all driver-private data
> > structures in this and the following patches, so why not keep in in
> > struct pwm_chip and simply rename chip->dev to chip->parent?
> > 
> > As Andy has commented, this would eventually allow the PWM core to
> > take care of certain things like runtime PM, or even only for stuff
> > like using the parent device name in info/debug/error messages.
> > 
> > Also, you could then just make this a single large patch that renames
> > dev to parent in one go rather than making this large set even larger
> > with this kind of trivial changes.
> 
> The idea here is (again) that I don't have to touch all drivers in the
> commit that changes struct pwm_chip.
> 
> In the end there is such a parent pointer (pwmchip.dev.parent). Would
> you prefer a macro (say) pwmchip_parentdev that can be defined as
> 
> 	#define pwmchip_parentdev(chip) (chip)->dev
> 
> at the beginning and then be changed to
> 
> 	#define pwmchip_parentdev(chip) (chip)->dev.parent
> 
> in the right moment? That's the best idea I have here.

No, that's not necessarily better. So I think either we live with the
duplicated parent pointer (which is the same whether we keep it in the
core structure or the driver-private structure), or we just change all
the occurrences at once when the new parent is introduced. I personally
much prefer a single big patch with a lot of small one-line fixups over
30 patches that exist purely for the purpose of making patch 31 smaller.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-10-06 10:41   ` Uwe Kleine-König
@ 2023-10-06 11:50     ` Thierry Reding
  2023-10-06 17:35       ` Uwe Kleine-König
  0 siblings, 1 reply; 129+ messages in thread
From: Thierry Reding @ 2023-10-06 11:50 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 4860 bytes --]

On Fri, Oct 06, 2023 at 12:41:02PM +0200, Uwe Kleine-König wrote:
> Hello Thierry,
> 
> On Fri, Oct 06, 2023 at 11:20:03AM +0200, Thierry Reding wrote:
> > On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> > > this series addresses the issues I reported already earlier to this
> > > list[1]. It is based on pwm/for-next and several patches I already sent
> > > out, too. Maybe some of these have to be reworked (e.g. Thierry already
> > > signalled not to like the patches dropping runtime error messages) but
> > > in the expectation that I will have to create a v2 for this series, too
> > > and it actually fixes a race condition, I sent the patches out for
> > > review anyhow. For the same reason I didn't Cc: all the individual
> > > maintainers.
> > > 
> > > If you want to actually test I suggest you fetch my complete history
> > > from
> > > 
> > > 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> > > 
> > > . 
> > > 
> > > In the end drivers have to allocate their pwm_chip using
> > > pwmchip_alloc(). This is important for the memory backing the pwm_chip
> > > being able to have a longer life than the driver.
> > 
> > Couldn't we achieve the same thing by just making sure that drivers
> > don't use any of the device-managed APIs to do this? That seems like a
> > slightly less intrusive way of doing things.
> 
> The device-managed APIs are not the problem here. If you allocate in
> .probe and free in .remove there is a problem. (And that's exactly what
> the device managed APIs do.)

Heh... so you're saying that device-managed APIs are the problem here.
Yes, without device-managed APIs you still need to make sure you don't
free while the PWM devices are still in use, but at least you then have
that option.

My point was that with device-managed APIs, freeing memory at ->remove()
comes built-in. Hence why it's confusing to see that this series keeps
using device-managed APIs while claiming to address lifetime issues.

> So no, you cannot. The thing is the struct pwm_chip must stay around until
> the last reference is dropped. So you need some kind of reference
> counting. The canonical way to do that is using a struct device.
> 
> You can try to hide it from the low-level drivers (as gpio does) at the
> cost that you have the driver allocated structure separate from the
> reference counted memory under framework control. The cost is more
> overhead because you have >1 memory chunk (memory fragmentation, less
> cache locality) and more pointers. IMHO the cleaner way is to not hide

Single-chunk allocations can also lead to less cache locality, depending
on the size of your allocations. For instance if you primarily use small
driver-specific data structures, those may fit into the cache while a
combined data structure that consists of the core structure plus driver-
private data may need to be split across multiple cache lines, and you
may not end up using something like the core structure a lot of the
time.

Anyway, I'm not sure PWM is the kind of subsystem where cache locality
is something we need to be concerned about.

> it and have the explicit handling needed in the drivers be not error
> prone (as spi does).
> 
> I agree the switch suggested here is intrusive, but the "new way" a
> driver has to look like is fine, so I'd not hesitate here.
> 
> > > The motivation for this series is to prepare the pwm framework to add a
> > > character device for each pwm_chip for easier and faster access to PWMs
> > > from userspace compared to the sysfs API. For such an extension proper
> > > lifetime tracking is important, too, as such a device can still be open
> > > if a PWM disappears.
> > 
> > As I mentioned before, I'd like to see at least a prototype of the
> > character device patches before I merge this series. There's a whole lot
> > of churn here and without the character device support it's hard to
> > justify.
> 
> The character device stuff is only one reason to get the lifetime
> tracking right. See that oops I can trigger today that is fixed by this
> series.

My recollection is that you need to inject a 5 second sleep into an
apply function in order to trigger this, which is not something you
would usually do, or that someone could trigger by accident. Yes, it
might be theoretically possible to run into this, but so far nobody
has reported this to be an actual problem in practice.

Also, as you have mentioned before, other mechanisms should already
take care of tearing things down properly. If that's not happening for
some reason, that's probably what we should investigate. It'd probably
be less intrusive than 100 patches with churn in every driver.

I'm not saying we don't need this, just trying to put it into
perspective.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function
  2023-10-06 11:08       ` Thierry Reding
@ 2023-10-06 12:36         ` Uwe Kleine-König
  0 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 12:36 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 2539 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 01:08:18PM +0200, Thierry Reding wrote:
> On Fri, Oct 06, 2023 at 12:56:26PM +0200, Uwe Kleine-König wrote:
> > On Fri, Oct 06, 2023 at 11:23:49AM +0200, Thierry Reding wrote:
> > > On Tue, Aug 08, 2023 at 07:17:51PM +0200, Uwe Kleine-König wrote:
> > > > +struct pwm_chip *devm_pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
> > > > +{
> > > > +	struct pwm_chip *chip;
> > > > +	size_t alloc_size;
> > > > +	unsigned int i;
> > > > +
> > > > +	alloc_size = sizeof(*chip) + sizeof_priv;
> > > > +
> > > > +	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
> > > 
> > > Are you sure this works the way you want it to? If you allocate using
> > > device-managed functions, this memory will be released when the driver
> > > is unbound from the device, so we're basically back to square one,
> > > aren't we?
> > 
> > After this patch the problem with broken lifetimes isn't fixed. Today
> > the way the pwm_chip is allocated is a problem in each driver. With this
> > function (that indeed suffers from the same problem) the issue can be
> > shifted from each individual driver to this function (patches #2 - #69).
> > Then the lifetime tracking can get fixed in a single place without
> > touching all drivers in one single commit (patches #70, #100 and #101).
> > With the whole series applied this devm_kzalloc is indeed gone -- this
> > can however only happen when all drivers use devm_pwmchip_alloc().
> > 
> > If you have a better idea how to split such a conversion in managable
> > and reviewable patches, I'm all ears.
> 
> Is there anything that would prevent us from merging the really
> interesting bits from patch 100 into this first patch?

The main part of patch #100 is that struct pwm_chip gets a member of
type struct device. Sure, we *could* do that (and replace all usages of
chip->dev by chip->dev.parent), but I see no benefit in that, because
you only can use the embedded dev once all drivers don't place it in
memory obtained by devm_kzalloc(). So it would only make patch #1 more
strange (because why would you use a struct device only to use the
parent pointer?).

So unless I miss something (which I think I don't) there is nothing that
can sensibly be moved in pwmchip_alloc() before all drivers are
converted.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used
  2023-08-08 17:19 ` [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used Uwe Kleine-König
@ 2023-10-06 12:37   ` Thierry Reding
  2023-10-06 13:16     ` Uwe Kleine-König
  2023-10-06 13:35     ` Andy Shevchenko
  0 siblings, 2 replies; 129+ messages in thread
From: Thierry Reding @ 2023-10-06 12:37 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-pwm, kernel, Bartosz Golaszewski, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 1257 bytes --]

On Tue, Aug 08, 2023 at 07:19:30PM +0200, Uwe Kleine-König wrote:
[...]
> +static struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
>  {
>  	struct pwm_chip *chip;
> +	struct device *dev;
>  	size_t alloc_size;
>  	unsigned int i;
>  
>  	alloc_size = sizeof(*chip) + npwm * sizeof(struct pwm_device) + sizeof_priv;
>  
> -	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
> +	chip = kzalloc(alloc_size, GFP_KERNEL);
>  	if (!chip)
>  		return ERR_PTR(-ENOMEM);
>  
> -	chip->dev = parent;
> +	dev = &chip->dev;
> +
> +	device_initialize(dev);
> +	dev->class = &pwm_class;
> +	dev->parent = parent;
> +	dev->release = pwmchip_release;

We could potentially make this a lot simpler if we add the new struct
device and all of that and add it during pwmchip_add(). Really the only
thing that we need to make sure is that struct pwm_chip is the first
field in driver-specific structures and then all of this should work the
same way.

And of course we'd have to eliminate device-managed allocations as well.
For cases where pwmchip_release() needs to do more than just free the
memory, we could add a new pwm_ops.release callback that drivers can
implement if needed.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used
  2023-10-06 12:37   ` Thierry Reding
@ 2023-10-06 13:16     ` Uwe Kleine-König
  2023-10-06 13:35     ` Andy Shevchenko
  1 sibling, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 13:16 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 2471 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 02:37:14PM +0200, Thierry Reding wrote:
> On Tue, Aug 08, 2023 at 07:19:30PM +0200, Uwe Kleine-König wrote:
> [...]
> > +static struct pwm_chip *pwmchip_alloc(struct device *parent, unsigned int npwm, size_t sizeof_priv)
> >  {
> >  	struct pwm_chip *chip;
> > +	struct device *dev;
> >  	size_t alloc_size;
> >  	unsigned int i;
> >  
> >  	alloc_size = sizeof(*chip) + npwm * sizeof(struct pwm_device) + sizeof_priv;
> >  
> > -	chip = devm_kzalloc(parent, alloc_size, GFP_KERNEL);
> > +	chip = kzalloc(alloc_size, GFP_KERNEL);
> >  	if (!chip)
> >  		return ERR_PTR(-ENOMEM);
> >  
> > -	chip->dev = parent;
> > +	dev = &chip->dev;
> > +
> > +	device_initialize(dev);
> > +	dev->class = &pwm_class;
> > +	dev->parent = parent;
> > +	dev->release = pwmchip_release;
> 
> We could potentially make this a lot simpler if we add the new struct
> device and all of that and add it during pwmchip_add(). Really the only
> thing that we need to make sure is that struct pwm_chip is the first
> field in driver-specific structures and then all of this should work the
> same way.
>
> And of course we'd have to eliminate device-managed allocations as well.
> For cases where pwmchip_release() needs to do more than just free the
> memory, we could add a new pwm_ops.release callback that drivers can
> implement if needed.

It took me a while to understand what you want here, I think I did that
now.

Once the driver is unbound, you cannot rely on any function, that the
driver might want to call, still being around -- the module containing
the driver might be unloaded. The idea is that the struct pwm_chip is
just enough for the core to check if the chip is still functional or
not. And if the driver is gone, all calls to the driver are suppressed.
So I don't see a valid (and possible) use case for a driver specific
release callback.

A drawback of your idea (if it worked at all) is that there is some
added complexity in each driver (the requirement to have struct pwm_chip
first, the unusual memory allocation/free pattern, having to care for
lifetime at all).

The pattern I suggested here works fine for spi, net devices, iio and
probably others. Sticking to that seems beneficial to me.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used
  2023-10-06 12:37   ` Thierry Reding
  2023-10-06 13:16     ` Uwe Kleine-König
@ 2023-10-06 13:35     ` Andy Shevchenko
  1 sibling, 0 replies; 129+ messages in thread
From: Andy Shevchenko @ 2023-10-06 13:35 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Uwe Kleine-König, linux-pwm, kernel, Bartosz Golaszewski

On Fri, Oct 06, 2023 at 02:37:14PM +0200, Thierry Reding wrote:
> On Tue, Aug 08, 2023 at 07:19:30PM +0200, Uwe Kleine-König wrote:

[...]

> For cases where pwmchip_release() needs to do more than just free the
> memory, we could add a new pwm_ops.release callback that drivers can
> implement if needed.

Definitely not the best idea. Many drivers want to have PM runtime to
be called, or clocks to be handled (and w/o devm it makes it a lot
more verbose and prone to ordering issues with subtle bugs that may
appear 1 per 10 years.

So, I'm definitely on the Uwe's side in this discussion.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip
  2023-10-06 11:16       ` Thierry Reding
@ 2023-10-06 17:04         ` Uwe Kleine-König
  0 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 17:04 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 3868 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 01:16:35PM +0200, Thierry Reding wrote:
> On Fri, Oct 06, 2023 at 01:04:51PM +0200, Uwe Kleine-König wrote:
> > On Fri, Oct 06, 2023 at 11:38:12AM +0200, Thierry Reding wrote:
> > > On Tue, Aug 08, 2023 at 07:19:00PM +0200, Uwe Kleine-König wrote:
> > > > It's required to not free the memory underlying a requested PWM
> > > > while a consumer still has a reference to it. While currently a pwm_chip
> > > > doesn't life long enough in all cases, linking the struct pwm to the
> > > > pwm_chip results in the right lifetime as soon as the pwmchip is living
> > > > long enough. This happens with the following commits.
> > > > 
> > > > Note this is a breaking change for all pwm drivers that don't use
> > > > pwmchip_alloc().
> > > > 
> > > > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> > > > ---
> > > >  drivers/pwm/core.c  | 24 +++++++++---------------
> > > >  include/linux/pwm.h |  2 +-
> > > >  2 files changed, 10 insertions(+), 16 deletions(-)
> > > > 
> > > > diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
> > > > index cfcddf62ab01..3b8d41fdda1b 100644
> > > > --- a/drivers/pwm/core.c
> > > > +++ b/drivers/pwm/core.c
> > > > @@ -198,7 +198,7 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
> > > >  
> > > >  void *pwmchip_priv(struct pwm_chip *chip)
> > > >  {
> > > > -	return &chip[1];
> > > > +	return &chip->pwms[chip->npwm];
> > > 
> > > I already disliked &chip[1] and this isn't making things any better. I
> > > fully realize that this is going to give us the right address, but it
> > > just looks wrong. Can we not do something like:
> > > 
> > > 	return (void *)chip + sizeof(*chip);
> > 
> > In practise this works, but I'm not 100% confident that the compiler
> > might not add padding that breaks this. I don't particularly like this
> > function either and will think a bit more about it for v2.
> 
> I'm not at all a fan of this whole pwmchip_alloc() business and I would
> prefer if we could somehow just keep embedding this into the driver-
> specific structures and take care of the lifetime management with less
> intrusion.
> 
> However, I don't see how that could easily be done. It would be slightly
> easier if we didn't use the flexible array, I suppose.

Without that flexible array member you'd need a pointer instead of the
struct pwm_device pwms[] in struct pwm_chip and a separate allocation.

While handling the flexible array isn't exactly pretty, I prefer it
compared to the consequences of the alternative (two allocation instead
of one, so more memory management cruft, less cache locality, more
pointer dereferences). Also given that the ugliness of the flexible
array approach is limited to this one function it's IMHO easily possible
to get over it.

The idea used by the counter core (in drivers/counter/counter-core.c)
with a struct counter_device_allochelper doesn't work in combination
with the flexible array. netdev_priv uses a similar approach to what you
suggested (and adds some complexity by adding an alignment). Anyhow, if
we continue to have a single allocation for struct pwm_chip, the array
of pwm_devices belonging to the chip and priv data (which I think is a
good idea), then we cannot avoid some memory address calculation because
the array size and the size of private data differs per driver (or even
per chip). Something like
https://lore.kernel.org/linux-iio/20230724110204.46285-3-andriy.shevchenko@linux.intel.com
could be used (but I'm unsure if this makes things prettier). The
struct_size macro from include/linux/overflow.h could be beneficial
though?

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-10-06 10:15     ` Thierry Reding
@ 2023-10-06 17:05       ` Uwe Kleine-König
  0 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 17:05 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, Sean Young, kernel

[-- Attachment #1: Type: text/plain, Size: 4533 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 12:15:55PM +0200, Thierry Reding wrote:
> On Sun, Oct 01, 2023 at 01:10:24PM +0200, Uwe Kleine-König wrote:
> > On Tue, Sep 26, 2023 at 12:06:25PM +0200, Uwe Kleine-König wrote:
> > > On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> > > > this series addresses the issues I reported already earlier to this
> > > > list[1]. It is based on pwm/for-next and several patches I already sent
> > > > out, too. Maybe some of these have to be reworked (e.g. Thierry already
> > > > signalled not to like the patches dropping runtime error messages) but
> > > > in the expectation that I will have to create a v2 for this series, too
> > > > and it actually fixes a race condition, I sent the patches out for
> > > > review anyhow. For the same reason I didn't Cc: all the individual
> > > > maintainers.
> > > > 
> > > > If you want to actually test I suggest you fetch my complete history
> > > > from
> > > > 
> > > > 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> > > > 
> > > > . 
> > > > 
> > > > In the end drivers have to allocate their pwm_chip using
> > > > pwmchip_alloc(). This is important for the memory backing the pwm_chip
> > > > being able to have a longer life than the driver.
> > > > 
> > > > The motivation for this series is to prepare the pwm framework to add a
> > > > character device for each pwm_chip for easier and faster access to PWMs
> > > > from userspace compared to the sysfs API. For such an extension proper
> > > > lifetime tracking is important, too, as such a device can still be open
> > > > if a PWM disappears.
> > > 
> > > I wonder how this topic will continue. This series fixes a lifetime
> > > issue that can result in a userspace triggered oops and it builds the
> > > base for my efforts to create a /dev/pwmchipX for faster control of PWMs
> > > from userspace (compared to sysfs). (Currently in the prototype stage.)
> > > 
> > > I'd like to get this in during the next merge window, please tell me
> > > what needs to be done to make this happen.
> > 
> > One problem I noticed yesterday is that this series depends on patch
> > "drm/ssd130x: Print the PWM's label instead of its number" that
> > currently waits in drm-misc-next for getting in the main line. The
> > series could for sure be reworked to not rely on this patch, but I'd
> > prefer to wait until after the next merge window instead of reworking
> > it.
> > 
> > Still, getting some feedback here in the mean time would be nice. The
> > questions I wonder about myself are:
> > 
> >  - In patch #1, devm_pwmchip_alloc() could get another parameter for the
> >    .ops member. This would save a line per driver like
> > 
> >    	chip->ops = &pwm_clk_ops;
> > 
> >    in return for an additional parameter that yields longer lines in the
> >    drivers.
> > 
> >  - In patch #101 instead of using &pwm_lock a per-pwmchip lock could be
> >    used for pwm_apply_state(). This would allow to parallelize pwm calls
> >    for different chips; I don't know how much this matters. Maybe the
> >    sensible option here is to keep it simple for now (i.e. how I
> >    implemented it now) until someone complains? (But see also the next
> >    item.)
> > 
> >  - A further complication is the requirement of pwm-ir-tx for faster
> >    pwm_apply_state() calls, see
> > 
> > 	https://lore.kernel.org/linux-pwm/ZRb5OWvx3GxYWf9g@gofer.mess.org
> >    	https://lore.kernel.org/linux-pwm/1bd5241d584ceb4d6b731c4dc3203fb9686ee1d1.1696156485.git.sean@mess.org
> > 
> >    . This complicates the locking scheme, I didn't try to address that
> >    yet.
> 
> Frankly, I think per-chip locking is the only way to support slow
> busses. If we use the subsystem-wide lock, effectively all chips become
> slow and unusable for things like pwm-ir-tx.
> 
> Perhaps we can draw some inspiration from how the IRQ infrastructure
> deals with this? IRQ chips have irq_bus_lock() and irq_bus_sync_unlock()
> callbacks to deal with this. We could have something similar for PWM
> chips. Perhaps that's even something that could be handled in the core
> by checking a "might_sleep" flag for the chip.

I'll invest some time to work on that, also considering that we might
not want sleep at all for "fast" PWMs.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips
  2023-10-06 11:50     ` Thierry Reding
@ 2023-10-06 17:35       ` Uwe Kleine-König
  0 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 17:35 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 6967 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 01:50:57PM +0200, Thierry Reding wrote:
> On Fri, Oct 06, 2023 at 12:41:02PM +0200, Uwe Kleine-König wrote:
> > On Fri, Oct 06, 2023 at 11:20:03AM +0200, Thierry Reding wrote:
> > > On Tue, Aug 08, 2023 at 07:17:50PM +0200, Uwe Kleine-König wrote:
> > > > this series addresses the issues I reported already earlier to this
> > > > list[1]. It is based on pwm/for-next and several patches I already sent
> > > > out, too. Maybe some of these have to be reworked (e.g. Thierry already
> > > > signalled not to like the patches dropping runtime error messages) but
> > > > in the expectation that I will have to create a v2 for this series, too
> > > > and it actually fixes a race condition, I sent the patches out for
> > > > review anyhow. For the same reason I didn't Cc: all the individual
> > > > maintainers.
> > > > 
> > > > If you want to actually test I suggest you fetch my complete history
> > > > from
> > > > 
> > > > 	https://git.pengutronix.de/git/ukl/linux pwm-lifetime-tracking
> > > > 
> > > > . 
> > > > 
> > > > In the end drivers have to allocate their pwm_chip using
> > > > pwmchip_alloc(). This is important for the memory backing the pwm_chip
> > > > being able to have a longer life than the driver.
> > > 
> > > Couldn't we achieve the same thing by just making sure that drivers
> > > don't use any of the device-managed APIs to do this? That seems like a
> > > slightly less intrusive way of doing things.
> > 
> > The device-managed APIs are not the problem here. If you allocate in
> > .probe and free in .remove there is a problem. (And that's exactly what
> > the device managed APIs do.)
> 
> Heh... so you're saying that device-managed APIs are the problem here.

No, I'm just saying that replacing devm_kzalloc by kzalloc in .probe and
free in .remove (and .probe's error path) doesn't help, because that's
what devm_kzalloc does under the cover.

> Yes, without device-managed APIs you still need to make sure you don't
> free while the PWM devices are still in use, but at least you then have
> that option.

The big downside I see then is that each driver must cope to get the
free at the right place. Using devm_pwmchip_alloc() puts that complexity
into a single place in the core instead.

> My point was that with device-managed APIs, freeing memory at ->remove()
> comes built-in. Hence why it's confusing to see that this series keeps
> using device-managed APIs while claiming to address lifetime issues.

This is only part of the preparations. In the end there is no
devm_kzalloc() any more. (And the cleanup handler of
devm_pwmchip_alloc() calls put_device() which only triggers kfree() once
all references are gone.)
 
> > So no, you cannot. The thing is the struct pwm_chip must stay around until
> > the last reference is dropped. So you need some kind of reference
> > counting. The canonical way to do that is using a struct device.
> > 
> > You can try to hide it from the low-level drivers (as gpio does) at the
> > cost that you have the driver allocated structure separate from the
> > reference counted memory under framework control. The cost is more
> > overhead because you have >1 memory chunk (memory fragmentation, less
> > cache locality) and more pointers. IMHO the cleaner way is to not hide
> 
> Single-chunk allocations can also lead to less cache locality, depending
> on the size of your allocations. For instance if you primarily use small
> driver-specific data structures, those may fit into the cache while a
> combined data structure that consists of the core structure plus driver-
> private data may need to be split across multiple cache lines, and you
> may not end up using something like the core structure a lot of the
> time.

I think this is wrong. Two memory chunks of size A and B are never
better than a single memory chunk of size A+B for caching. Those small
driver-specific data structures all live in the B part. For cache
locality of this driver struct it doesn't matter if A is directly in
front of that or somewhere else. But with having these in a single chunk
you might benefit from better caching when accessing both A and B, and
simpler page handling and less memory management overhead.

> Anyway, I'm not sure PWM is the kind of subsystem where cache locality
> is something we need to be concerned about.

pwm-ir-tx is concerned about timing, and my customer controlling a motor
wants little overhead, too. I don't have hard numbers, but I tend to
invest that effort.

> > it and have the explicit handling needed in the drivers be not error
> > prone (as spi does).
> > 
> > I agree the switch suggested here is intrusive, but the "new way" a
> > driver has to look like is fine, so I'd not hesitate here.
> > 
> > > > The motivation for this series is to prepare the pwm framework to add a
> > > > character device for each pwm_chip for easier and faster access to PWMs
> > > > from userspace compared to the sysfs API. For such an extension proper
> > > > lifetime tracking is important, too, as such a device can still be open
> > > > if a PWM disappears.
> > > 
> > > As I mentioned before, I'd like to see at least a prototype of the
> > > character device patches before I merge this series. There's a whole lot
> > > of churn here and without the character device support it's hard to
> > > justify.
> > 
> > The character device stuff is only one reason to get the lifetime
> > tracking right. See that oops I can trigger today that is fixed by this
> > series.
> 
> My recollection is that you need to inject a 5 second sleep into an
> apply function in order to trigger this, which is not something you
> would usually do, or that someone could trigger by accident.
> 
> Yes, it might be theoretically possible to run into this, but so far
> nobody has reported this to be an actual problem in practice.

It is theoretically possible, and in my book that's a good enough reason
to fix it. A use-after-free is relevant for the security of the whole
system, so nobody telling us to have hit that problem isn't an excuse.

> Also, as you have mentioned before, other mechanisms should already
> take care of tearing things down properly. If that's not happening for
> some reason, that's probably what we should investigate. It'd probably
> be less intrusive than 100 patches with churn in every driver.

Let's do some work sharing: I continue with the lifetime stuff (that we
need for the character device stuff anyway) and the character device
code and you check why device links don't work as expected? I cannot
cope for every potential bug I notice, at least not always on the front
of my todo list :-)

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

* Re: [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data
  2023-10-06 11:20       ` Thierry Reding
@ 2023-10-06 21:16         ` Uwe Kleine-König
  0 siblings, 0 replies; 129+ messages in thread
From: Uwe Kleine-König @ 2023-10-06 21:16 UTC (permalink / raw)
  To: Thierry Reding; +Cc: Andy Shevchenko, linux-pwm, Bartosz Golaszewski, kernel

[-- Attachment #1: Type: text/plain, Size: 1934 bytes --]

Hello Thierry,

On Fri, Oct 06, 2023 at 01:20:18PM +0200, Thierry Reding wrote:
> On Fri, Oct 06, 2023 at 01:09:51PM +0200, Uwe Kleine-König wrote:
> > On Fri, Oct 06, 2023 at 11:41:51AM +0200, Thierry Reding wrote:
> > > Also, you could then just make this a single large patch that renames
> > > dev to parent in one go rather than making this large set even larger
> > > with this kind of trivial changes.
> > 
> > The idea here is (again) that I don't have to touch all drivers in the
> > commit that changes struct pwm_chip.
> > 
> > In the end there is such a parent pointer (pwmchip.dev.parent). Would
> > you prefer a macro (say) pwmchip_parentdev that can be defined as
> > 
> > 	#define pwmchip_parentdev(chip) (chip)->dev
> > 
> > at the beginning and then be changed to
> > 
> > 	#define pwmchip_parentdev(chip) (chip)->dev.parent
> > 
> > in the right moment? That's the best idea I have here.
> 
> No, that's not necessarily better. So I think either we live with the
> duplicated parent pointer (which is the same whether we keep it in the
> core structure or the driver-private structure), or we just change all
> the occurrences at once when the new parent is introduced. I personally
> much prefer a single big patch with a lot of small one-line fixups over
> 30 patches that exist purely for the purpose of making patch 31 smaller.

I find that a surprising attitude. We're quite different here, I'd even
ask a contributor who sends a such a change in a single patch to split
it. I'll rework this part of the series to the above described macro,
which opens the opportunity to squash it all into a single patch in the
end without those (admittedly ugly) added extra pointers in driver
private data.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 129+ messages in thread

end of thread, other threads:[~2023-10-06 21:16 UTC | newest]

Thread overview: 129+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-08 17:17 [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 001/101] pwm: Provide devm_pwmchip_alloc() function Uwe Kleine-König
2023-10-06  9:23   ` Thierry Reding
2023-10-06 10:56     ` Uwe Kleine-König
2023-10-06 11:08       ` Thierry Reding
2023-10-06 12:36         ` Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 002/101] pwm: ab8500: Make use of " Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 003/101] pwm: apple: " Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 004/101] pwm: atmel-hlcdc: " Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 005/101] pwm: atmel: " Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 006/101] pwm: atmel-tcb: " Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 007/101] pwm: bcm2835: " Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 008/101] pwm: bcm-iproc: " Uwe Kleine-König
2023-08-08 17:17 ` [PATCH v1 009/101] pwm: bcm-kona: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 010/101] pwm: berlin: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 011/101] pwm: brcmstb: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 012/101] pwm: clk: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 013/101] pwm: clps711x: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 014/101] pwm: crc: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 015/101] pwm: cros-ec: Change prototype of helper to prepare further changes Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 016/101] pwm: cros-ec: Make use of devm_pwmchip_alloc() function Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 017/101] pwm: dwc: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 018/101] pwm: ep93xx: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 019/101] pwm: fsl-ftm: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 020/101] pwm: hibvt: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 021/101] pwm: img: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 022/101] pwm: imx1: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 023/101] pwm: imx27: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 024/101] pwm: imx-tpm: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 025/101] pwm: intel-lgm: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 026/101] pwm: iqs620a: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 027/101] pwm: jz4740: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 028/101] pwm: keembay: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 029/101] pwm: lp3943: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 030/101] pwm: lpc18xx-sct: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 031/101] pwm: lpc32xx: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 032/101] pwm: lpss-*: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 033/101] pwm: mediatek: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 034/101] pwm: meson: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 035/101] pwm: microchip-core: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 036/101] pwm: mtk-disp: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 037/101] pwm: mxs: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 038/101] pwm: ntxec: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 039/101] pwm: omap-dmtimer: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 040/101] pwm: pca9685: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 041/101] pwm: pxa: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 042/101] pwm: raspberrypi-poe: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 043/101] pwm: rcar: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 044/101] pwm: renesas-tpu: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 045/101] pwm: rockchip: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 046/101] pwm: rz-mtu3: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 047/101] pwm: samsung: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 048/101] pwm: sifive: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 049/101] pwm: sl28cpld: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 050/101] pwm: spear: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 051/101] pwm: sprd: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 052/101] pwm: sti: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 053/101] pwm: stm32-lp: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 054/101] pwm: stm32: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 055/101] pwm: stmpe: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 056/101] pwm: sun4i: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 057/101] pwm: sunplus: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 058/101] pwm: tegra: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 059/101] pwm: tiecap: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 060/101] pwm: tiehrpwm: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 061/101] pwm: twl-led: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 062/101] pwm: twl: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 063/101] pwm: visconti: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 064/101] pwm: vt8500: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 065/101] pwm: xilinx: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 066/101] gpio: mvebu: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 067/101] drm/bridge: ti-sn65dsi86: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 068/101] leds: qcom-lpg: " Uwe Kleine-König
2023-08-08 17:18 ` [PATCH v1 069/101] staging: greybus: pwm: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 070/101] pwm: Ensure a struct pwm have the same lifetime as its pwm_chip Uwe Kleine-König
2023-10-06  9:38   ` Thierry Reding
2023-10-06 11:04     ` Uwe Kleine-König
2023-10-06 11:16       ` Thierry Reding
2023-10-06 17:04         ` Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 071/101] pwm: ab8500: Store parent device in driver data Uwe Kleine-König
2023-10-06  9:41   ` Thierry Reding
2023-10-06 11:09     ` Uwe Kleine-König
2023-10-06 11:20       ` Thierry Reding
2023-10-06 21:16         ` Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 072/101] pwm: atmel: Stop using struct pwm_chip::dev Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 073/101] pwm: dwc: Store parent device in driver data Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 074/101] pwm: ep93xx: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 075/101] pwm: fsl-ftm: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 076/101] pwm: img: Make use of parent device pointer " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 077/101] pwm: imx27: Store parent device " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 078/101] pwm: jz4740: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 079/101] pwm: lpc18xx-sct: Make use of parent device pointer " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 080/101] pwm: lpss: Store parent device " Uwe Kleine-König
2023-08-08 17:49   ` Andy Shevchenko
2023-08-09  6:10     ` Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 081/101] pwm: mediatek: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 082/101] pwm: meson: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 083/101] pwm: mtk-disp: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 084/101] pwm: omap: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 085/101] pwm: pca9685: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 086/101] pwm: raspberrypi-poe: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 087/101] pwm: rcar: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 088/101] pwm: rz-mtu3: Make use of parent device pointer " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 089/101] pwm: samsung: Store parent device " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 090/101] pwm: sifive: Make use of parent device pointer " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 091/101] pwm: stm32: Store parent device " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 092/101] pwm: stmpe: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 093/101] pwm: sun4i: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 094/101] pwm: tiecap: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 095/101] pwm: tiehrpwm: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 096/101] pwm: twl: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 097/101] pwm: twl-led: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 098/101] pwm: vt8500: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 099/101] staging: greybus: pwm: " Uwe Kleine-König
2023-08-08 17:19 ` [PATCH v1 100/101] pwm: Ensure the memory backing a PWM chip isn't freed while used Uwe Kleine-König
2023-10-06 12:37   ` Thierry Reding
2023-10-06 13:16     ` Uwe Kleine-König
2023-10-06 13:35     ` Andy Shevchenko
2023-08-08 17:19 ` [PATCH v1 101/101] pwm: Add more locking Uwe Kleine-König
2023-10-06 10:09   ` Thierry Reding
2023-10-06 11:14     ` Uwe Kleine-König
2023-09-26 10:06 ` [PATCH v1 000/101] pwm: Fix lifetime issues for pwm_chips Uwe Kleine-König
2023-10-01 11:10   ` Uwe Kleine-König
2023-10-06 10:15     ` Thierry Reding
2023-10-06 17:05       ` Uwe Kleine-König
2023-10-06  9:20 ` Thierry Reding
2023-10-06 10:41   ` Uwe Kleine-König
2023-10-06 11:50     ` Thierry Reding
2023-10-06 17:35       ` Uwe Kleine-König

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.