All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dimitri Fedrau <dima.fedrau@gmail.com>
To: "Uwe Kleine-König" <ukleinek@kernel.org>
Cc: Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Conor Dooley <conor+dt@kernel.org>,
	linux-pwm@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v7 2/2] pwm: add support for NXPs high-side switch MC33XS2410
Date: Thu, 9 Jan 2025 17:21:24 +0100	[thread overview]
Message-ID: <20250109162124.GA46029@debian> (raw)
In-Reply-To: <5msw2ptk2ip5h5ovqe2ficgofqmaryq2qf5h7qendygaa23lp4@gy754ev7cnqm>

Hello Uwe,

Am Wed, Jan 08, 2025 at 09:01:07AM +0100 schrieb Uwe Kleine-König:
> Hello Dimitri,
> 
> thanks for your patience. I'm mostly happy now. Just a few minor
> comments below:
> 
> On Sat, Nov 09, 2024 at 06:41:35PM +0100, Dimitri Fedrau wrote:
> > The MC33XS2410 is a four channel high-side switch. Featuring advanced
> > monitoring and control function, the device is operational from 3.0 V to
> > 60 V. The device is controlled by SPI port for configuration.
> > 
> > Signed-off-by: Dimitri Fedrau <dima.fedrau@gmail.com>
> > ---
> >  drivers/pwm/Kconfig          |  12 ++
> >  drivers/pwm/Makefile         |   1 +
> >  drivers/pwm/pwm-mc33xs2410.c | 388 +++++++++++++++++++++++++++++++++++
> >  3 files changed, 401 insertions(+)
> >  create mode 100644 drivers/pwm/pwm-mc33xs2410.c
> > 
> > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> > index 0915c1e7df16..f513513f9b2f 100644
> > --- a/drivers/pwm/Kconfig
> > +++ b/drivers/pwm/Kconfig
> > @@ -411,6 +411,18 @@ config PWM_LPSS_PLATFORM
> >  	  To compile this driver as a module, choose M here: the module
> >  	  will be called pwm-lpss-platform.
> >  
> > +config PWM_MC33XS2410
> > +	tristate "MC33XS2410 PWM support"
> > +	depends on OF
> > +	depends on SPI
> > +	help
> > +	  NXP MC33XS2410 high-side switch driver. The MC33XS2410 is a four
> > +	  channel high-side switch. The device is operational from 3.0 V
> > +	  to 60 V. The device is controlled by SPI port for configuration.
> > +
> > +	  To compile this driver as a module, choose M here: the module
> > +	  will be called pwm-mc33xs2410.
> > +
> >  config PWM_MESON
> >  	tristate "Amlogic Meson PWM driver"
> >  	depends on ARCH_MESON || COMPILE_TEST
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 9081e0c0e9e0..c75deeeace40 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -36,6 +36,7 @@ obj-$(CONFIG_PWM_LPC32XX)	+= pwm-lpc32xx.o
> >  obj-$(CONFIG_PWM_LPSS)		+= pwm-lpss.o
> >  obj-$(CONFIG_PWM_LPSS_PCI)	+= pwm-lpss-pci.o
> >  obj-$(CONFIG_PWM_LPSS_PLATFORM)	+= pwm-lpss-platform.o
> > +obj-$(CONFIG_PWM_MC33XS2410)	+= pwm-mc33xs2410.o
> >  obj-$(CONFIG_PWM_MESON)		+= pwm-meson.o
> >  obj-$(CONFIG_PWM_MEDIATEK)	+= pwm-mediatek.o
> >  obj-$(CONFIG_PWM_MICROCHIP_CORE)	+= pwm-microchip-core.o
> > diff --git a/drivers/pwm/pwm-mc33xs2410.c b/drivers/pwm/pwm-mc33xs2410.c
> > new file mode 100644
> > index 000000000000..97cf31ef608a
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-mc33xs2410.c
> > @@ -0,0 +1,388 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
> > + *
> > + * Reference Manual : https://www.nxp.com/docs/en/data-sheet/MC33XS2410.pdf
> > + *
> > + * Limitations:
> > + * - Supports frequencies between 0.5Hz and 2048Hz with following steps:
> > + *   - 0.5 Hz steps from 0.5 Hz to 32 Hz
> > + *   - 2 Hz steps from 2 Hz to 128 Hz
> > + *   - 8 Hz steps from 8 Hz to 512 Hz
> > + *   - 32 Hz steps from 32 Hz to 2048 Hz
> > + * - Cannot generate a 0 % duty cycle.
> > + * - Always produces low output if disabled.
> > + * - Configuration isn't atomic. When changing polarity, duty cycle or period
> > + *   the data is taken immediately, counters not being affected, resulting in a
> > + *   behavior of the output pin that is neither the old nor the new state,
> > + *   rather something in between.
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/math64.h>
> > +#include <linux/minmax.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/pwm.h>
> > +
> > +#include <linux/spi/spi.h>
> > +
> > +#define MC33XS2410_GLB_CTRL		0x00
> > +#define MC33XS2410_GLB_CTRL_MODE	GENMASK(7, 6)
> > +#define MC33XS2410_GLB_CTRL_MODE_NORMAL	FIELD_PREP(MC33XS2410_GLB_CTRL_MODE, 1)
> > +
> > +#define MC33XS2410_PWM_CTRL1		0x05
> > +/* x in { 1 ... 4 } */
> 
> Here x ranges over the 4 output channels, right? Maybe call it "chan" or
> similar instead of "x"?
> 
I will call it chan and do the same for MC33XS2410_PWM_CTRL3_EN,
MC33XS2410_PWM_FREQ and MC33XS2410_PWM_DC.

> > +#define MC33XS2410_PWM_CTRL1_POL_INV(x)	BIT((x - 1))
> 
> BIT((x) - 1)
> 
Will fix it for others too.

> > +
> > +#define MC33XS2410_PWM_CTRL3		0x07
> > +/* x in { 1 ... 4 } */
> > +#define MC33XS2410_PWM_CTRL3_EN(x)	BIT(4 + (x - 1))
> > +
> > +/* x in { 1 ... 4 } */
> > +#define MC33XS2410_PWM_FREQ(x)		(0x08 + (x - 1))
> > +#define MC33XS2410_PWM_FREQ_STEP	GENMASK(7, 6)
> > +#define MC33XS2410_PWM_FREQ_COUNT	GENMASK(5, 0)
> > +
> > +/* x in { 1 ... 4 } */
> > +#define MC33XS2410_PWM_DC(x)		(0x0c + (x - 1))
> > +
> > +#define MC33XS2410_WDT			0x14
> > +
> > +#define MC33XS2410_PWM_MIN_PERIOD	488282
> > +/* x in { 0 ... 3 } */
> > +#define MC33XS2410_PWM_MAX_PERIOD(x)	(2000000000 >> (2 * x))
> 
> Here x ranges over the four period intervals. I suggest to call this x
> "step" instead. Also the parameter needs bracketing.
> 
Ok.

> > +#define MC33XS2410_FRAME_IN_ADDR	GENMASK(15, 8)
> > +#define MC33XS2410_FRAME_IN_DATA	GENMASK(7, 0)
> > +#define MC33XS2410_FRAME_IN_ADDR_WR	BIT(7)
> > +#define MC33XS2410_FRAME_IN_DATA_RD	BIT(7)
> > +#define MC33XS2410_FRAME_OUT_DATA	GENMASK(13, 0)
> > +
> > +#define MC33XS2410_MAX_TRANSFERS	5
> > +
> > [...]
> > +static int mc33xs2410_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> > +				const struct pwm_state *state)
> > +{
> > +	struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_from_chip(chip);
> > +	struct spi_device *spi = mc33xs2410->spi;
> > +	u8 reg[4] = {
> > +			MC33XS2410_PWM_FREQ(pwm->hwpwm + 1),
> > +			MC33XS2410_PWM_DC(pwm->hwpwm + 1),
> > +			MC33XS2410_PWM_CTRL1,
> > +			MC33XS2410_PWM_CTRL3
> > +		    };
> > +	u64 period, duty_cycle;
> > +	int ret, rel_dc;
> > +	u16 rd_val[2];
> > +	u8 wr_val[4];
> > +	u8 mask;
> > +
> > +	period = min(state->period, MC33XS2410_PWM_MAX_PERIOD(0));
> > +	if (period < MC33XS2410_PWM_MIN_PERIOD)
> > +		return -EINVAL;
> > +
> > +	ret = mc33xs2410_read_regs(spi, &reg[2], MC33XS2410_FRAME_IN_DATA_RD, rd_val, 2);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	/* frequency */
> > +	wr_val[0] = mc33xs2410_pwm_get_freq(period);
> > +	/* Continue calculations with the possibly truncated period */
> > +	period = mc33xs2410_pwm_get_period(wr_val[0]);
> > +
> > +	/* duty cycle */
> > +	duty_cycle = min(period, state->duty_cycle);
> > +	rel_dc = div64_u64(duty_cycle * 256, period) - 1;
> > +	if (rel_dc < 0)
> > +		wr_val[1] = 0;
> > +	else
> > +		wr_val[1] = rel_dc;
> > +
> > +	/* polarity */
> > +	mask = MC33XS2410_PWM_CTRL1_POL_INV(pwm->hwpwm + 1);
> > +	wr_val[2] = (state->polarity == PWM_POLARITY_INVERSED) ?
> > +		    (rd_val[0] | mask) : (rd_val[0] & ~mask);
> > +
> > +	/* enable output */
> 
> /*
>  * As the hardware cannot generate a 0% relative duty cycle but emits a
>  * constant low signal when disabled, also disable in the duty_cycle = 0
>  * case.
>  */
>
Will add the comment as is, thanks.

> > +	mask = MC33XS2410_PWM_CTRL3_EN(pwm->hwpwm + 1);
> > +	wr_val[3] = (state->enabled && rel_dc >= 0) ? (rd_val[1] | mask) :
> > +						      (rd_val[1] & ~mask);
> > +
> > +	return mc33xs2410_write_regs(spi, reg, wr_val, 4);
> > +}
> > +
> > +static int mc33xs2410_pwm_get_state(struct pwm_chip *chip,
> > +				    struct pwm_device *pwm,
> > +				    struct pwm_state *state)
> > +{
> > +	struct mc33xs2410_pwm *mc33xs2410 = mc33xs2410_from_chip(chip);
> > +	struct spi_device *spi = mc33xs2410->spi;
> > +	u8 reg[4] = {
> > +			MC33XS2410_PWM_FREQ(pwm->hwpwm + 1),
> > +			MC33XS2410_PWM_DC(pwm->hwpwm + 1),
> > +			MC33XS2410_PWM_CTRL1,
> > +			MC33XS2410_PWM_CTRL3,
> > +		    };
> > +	u16 val[4];
> > +	int ret;
> > +
> > +	ret = mc33xs2410_read_regs(spi, reg, MC33XS2410_FRAME_IN_DATA_RD, val, 4);
> 
> ARRAY_SIZE(reg) instead of hardcoded 4?
>
I'm not sure, but I can change it.

> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	state->period = mc33xs2410_pwm_get_period(val[0]);
> > +	state->polarity = (val[2] & MC33XS2410_PWM_CTRL1_POL_INV(pwm->hwpwm + 1)) ?
> > +			  PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
> > +	state->enabled = !!(val[3] & MC33XS2410_PWM_CTRL3_EN(pwm->hwpwm + 1));
> > +	state->duty_cycle = DIV_ROUND_UP_ULL((val[1] + 1) * state->period, 256);
> > +
> > +	return 0;
> > +}
> > [...]
> > +static int mc33xs2410_probe(struct spi_device *spi)
> > +{
> > +	struct mc33xs2410_pwm *mc33xs2410;
> > +	struct device *dev = &spi->dev;
> > +	struct pwm_chip *chip;
> > +	int ret;
> > +
> > +	chip = devm_pwmchip_alloc(dev, 4, sizeof(*mc33xs2410));
> > +	if (IS_ERR(chip))
> > +		return PTR_ERR(chip);
> > +
> > +	spi->bits_per_word = 16;
> > +	spi->mode |= SPI_CS_WORD;
> > +	ret = spi_setup(spi);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	mc33xs2410 = mc33xs2410_from_chip(chip);
> > +	mc33xs2410->spi = spi;
> > +	chip->ops = &mc33xs2410_pwm_ops;
> 
> Given that struct mc33xs2410_pwm only has a single member you can pass 0
> as 3rd parameter to devm_pwmchip_alloc(), call pwmchip_set_drvdata(chip,
> spi). Then you can save on indirection.
> 
Yes, that makes sense.

> > +	ret = mc33xs2410_reset(dev);
> > +	if (ret)
> > +		return ret;
> > +
> 
Best regards,
Dimitri


  reply	other threads:[~2025-01-09 16:21 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-09 17:41 [PATCH v7 0/2] pwm: add support for NXPs high-side switch MC33XS2410 Dimitri Fedrau
2024-11-09 17:41 ` [PATCH v7 1/2] dt-bindings: pwm: add support for MC33XS2410 Dimitri Fedrau
2024-11-09 17:41 ` [PATCH v7 2/2] pwm: add support for NXPs high-side switch MC33XS2410 Dimitri Fedrau
2025-01-08  8:01   ` Uwe Kleine-König
2025-01-09 16:21     ` Dimitri Fedrau [this message]
  -- strict thread matches above, loose matches on Subject: below --
2024-11-12 15:02 kernel test robot
2024-11-13  8:37 kernel test robot

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20250109162124.GA46029@debian \
    --to=dima.fedrau@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=ukleinek@kernel.org \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is 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.