Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v4 3/4] PCI: tegra: Add Tegra264 support
From: Manivannan Sadhasivam @ 2026-04-10 16:34 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
	Jonathan Hunter, Karthikeyan Mitran, Hou Zhiqiang,
	Thomas Petazzoni, Pali Rohár, Michal Simek, Kevin Xie,
	linux-pci, devicetree, linux-tegra, linux-kernel,
	linux-arm-kernel, Thierry Reding, Manikanta Maddireddy
In-Reply-To: <adTAVYEzfD9FQl8N@orome>

On Tue, Apr 07, 2026 at 11:38:28AM +0200, Thierry Reding wrote:
> On Thu, Apr 02, 2026 at 11:02:02PM +0530, Manivannan Sadhasivam wrote:
> > On Thu, Apr 02, 2026 at 04:27:37PM +0200, Thierry Reding wrote:
> > > From: Thierry Reding <treding@nvidia.com>
> > > 
> > > Add a driver for the PCIe controller found on NVIDIA Tegra264 SoCs. The
> > > driver is very small, with its main purpose being to set up the address
> > > translation registers and then creating a standard PCI host using ECAM.
> > > 
> > > Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
> > > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > 
> > What is the rationale for adding a new driver? Can't you reuse the existing one?
> > If so, that should be mentioned in the description.
> 
> Which existing one? Tegra PCI controllers for previou generations
> (Tegra194 and Tegra234) were DesignWare IP, but Tegra264 is an internal
> IP, so the programming is entirely different. I'll add something to that
> effect to the commit message.
> 

Yikes! I completely missed that this is a non-dwc driver. Sorry for the noise.

> > > diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
> > > index 5aaed8ac6e44..6ead04f7bd6e 100644
> > > --- a/drivers/pci/controller/Kconfig
> > > +++ b/drivers/pci/controller/Kconfig
> > > @@ -254,7 +254,15 @@ config PCI_TEGRA
> > >  	select IRQ_MSI_LIB
> > >  	help
> > >  	  Say Y here if you want support for the PCIe host controller found
> > > -	  on NVIDIA Tegra SoCs.
> > > +	  on NVIDIA Tegra SoCs (Tegra20 through Tegra186).
> > > +
> > > +config PCIE_TEGRA264
> > > +	bool "NVIDIA Tegra264 PCIe controller"
> > 
> > This driver seems to be using external MSI controller. So it can be built as a
> > module. Also, you have the remove() callback for some reason.
> 
> Okay, I can turn this into a tristate symbol.
> 
> > > +	depends on ARCH_TEGRA || COMPILE_TEST
> > > +	depends on PCI_MSI
> > 
> > Why?
> 
> I suppose it's not necessary in the sense of it being a build
> dependency. At runtime, however, the root complex is not useful if PCI
> MSI is not enabled. We can drop this dependency and rely on .config to
> have it enabled as needed.
> 

Yes. I think the rationale is to depend on the symbols that the driver needs for
build dependency.

> > > diff --git a/drivers/pci/controller/pcie-tegra264.c b/drivers/pci/controller/pcie-tegra264.c
> > > new file mode 100644
> > > index 000000000000..3ce1ad971bdb
> > > --- /dev/null
> > > +++ b/drivers/pci/controller/pcie-tegra264.c
> [...]
> > > +struct tegra264_pcie {
> > > +	struct device *dev;
> > > +	bool link_up;
> > 
> > Keep bool types at the end to avoid holes.
> 
> Done.
> 
> > > +static int tegra264_pcie_parse_dt(struct tegra264_pcie *pcie)
> > > +{
> > > +	int err;
> > > +
> > > +	pcie->wake_gpio = devm_gpiod_get_optional(pcie->dev, "nvidia,pex-wake",
> > 
> > You should switch to standard 'wake-gpios' property.
> 
> Will do.
> 
> > > +						  GPIOD_IN);
> > > +	if (IS_ERR(pcie->wake_gpio))
> > > +		return PTR_ERR(pcie->wake_gpio);
> > > +
> > > +	if (pcie->wake_gpio) {
> > 
> > Since you are bailing out above, you don't need this check.
> 
> I think we still want to have this check to handle the case of optional
> wake GPIOs. Not all controllers may have this wired up and
> devm_gpiod_get_optional() will return NULL (not an ERR_PTR()-encoded
> error) if the wake-gpios property is missing.
> 

Ok. In that case you can just bail out:
	if (!pcie->wake_gpio)
		return 0;

> > > +static void tegra264_pcie_bpmp_set_rp_state(struct tegra264_pcie *pcie)
> > 
> > I don't think this function name is self explanatory. Looks like it is turning
> > off the PCIe controller, so how about tegra264_pcie_power_off()?
> 
> Agreed. The name is a relic from when this was potentially being used to
> toggle on and off the controller. But it's only used for disabling, so
> tegra264_pcie__power_off() sounds much better.
> 
> > > +{
> > > +	struct tegra_bpmp_message msg = {};
> > > +	struct mrq_pcie_request req = {};
> > > +	int err;
> > > +
> > > +	req.cmd = CMD_PCIE_RP_CONTROLLER_OFF;
> > > +	req.rp_ctrlr_off.rp_controller = pcie->ctl_id;
> > > +
> > > +	msg.mrq = MRQ_PCIE;
> > > +	msg.tx.data = &req;
> > > +	msg.tx.size = sizeof(req);
> > > +
> > > +	err = tegra_bpmp_transfer(pcie->bpmp, &msg);
> > > +	if (err)
> > > +		dev_info(pcie->dev, "failed to turn off PCIe #%u: %pe\n",
> > 
> > Why not dev_err()?
> > 
> > > +			 pcie->ctl_id, ERR_PTR(err));
> > > +
> > > +	if (msg.rx.ret)
> > > +		dev_info(pcie->dev, "failed to turn off PCIe #%u: %d\n",
> > 
> > Same here.
> 
> These are not fatal errors and are safe to ignore. dev_err() seemed too
> strong for this. They also really shouldn't happen. Though I now realize
> that's a bad argument, or rather, actually an argument for making them
> dev_err() so that they do stand out if they really should happen.
> 
> > 
> > > +			 pcie->ctl_id, msg.rx.ret);
> > > +}
> > > +
> > > +static void tegra264_pcie_icc_set(struct tegra264_pcie *pcie)
> > > +{
> > > +	u32 value, speed, width, bw;
> > > +	int err;
> > > +
> > > +	value = readw(pcie->ecam + XTL_RC_PCIE_CFG_LINK_STATUS);
> > > +	speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, value);
> > > +	width = FIELD_GET(PCI_EXP_LNKSTA_NLW, value);
> > > +
> > > +	bw = width * (PCIE_SPEED2MBS_ENC(speed) / BITS_PER_BYTE);
> > > +	value = MBps_to_icc(bw);
> > 
> > So this becomes, 'width * (PCIE_SPEED2MBS_ENC(speed) / 8) * 1000 / 8'. But don't
> > you want, 'width * (PCIE_SPEED2MBS_ENC(speed)) * 1000 / 8'?
> 
> This is M*B*ps_to_icc(), not M*b*ps_to_icc(), so we do in fact get the
> latter. I almost fell for this as well because I got confused by some of
> these macros being all-caps and other times the case actually mattering.
> 

Oops, I was misleaded too. But you can simply do:
	bw = Mbps_to_icc(width * PCIE_SPEED2MBS_ENC(speed));

> > > +	err = icc_set_bw(pcie->icc_path, bw, bw);

And here you were setting the MBps, not Kbps.

> > > +	if (err < 0)
> > > +		dev_err(pcie->dev,
> > > +			"failed to request bandwidth (%u MBps): %pe\n",
> > > +			bw, ERR_PTR(err));
> > 
> > So you don't want to error out if this fails?
> 
> No. This is not a fatal error and the system will continue to work,
> albeit perhaps at suboptimal performance. Given that Ethernet and mass
> storage are connected to these, a failure to set the bandwidth and
> erroring out here may leave the system unusable, but continuing on would
> let the system boot and update firmware, kernel or whatever to recover.
> 
> I'll add a comment explaining this.
> 

Yeah, that'll help.

> [...]
> > > +static void tegra264_pcie_init(struct tegra264_pcie *pcie)
> > > +{
> > > +	enum pci_bus_speed speed;
> > > +	unsigned int i;
> > > +	u32 value;
> > > +
> > > +	/* bring the link out of reset */
> > 
> > s/link/controller or endpoint?
> 
> This controls the PERST# signal, so I guess "endpoint" would be more
> correct.
> 

Yes!

> > > +	value = readl(pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);
> > > +	value |= XTL_RC_MGMT_PERST_CONTROL_PERST_O_N;
> > > +	writel(value, pcie->xtl + XTL_RC_MGMT_PERST_CONTROL);
> > > +
> > > +	if (!tegra_is_silicon()) {
> > 
> > This looks like some pre-silicon validation thing. Do you really want it to be
> > present in the upstream driver?
> 
> At this point there is silicon for this chip, but we've been trying to
> get some of the pre-silicon code merged upstream as well because
> occasionally people will want to run upstream on simulation, even after
> silicon is available. At other times we may want to reuse these drivers
> on future chips during pre-silicon validation.
> 
> Obviously there needs to be a balance. We don't want to have excessive
> amounts of code specifically for pre-silicon validation, but in
> relatively simple cases like this it is useful.
> 

Ok, fine with me.

> > 
> > > +		dev_info(pcie->dev,
> > > +			 "skipping link state for PCIe #%u in simulation\n",
> > > +			 pcie->ctl_id);
> > > +		pcie->link_up = true;
> > > +		return;
> > > +	}
> > > +
> > > +	for (i = 0; i < PCIE_LINK_WAIT_MAX_RETRIES; i++) {
> > > +		if (tegra264_pcie_link_up(pcie, NULL))
> > > +			break;
> > > +
> > > +		usleep_range(PCIE_LINK_WAIT_US_MIN, PCIE_LINK_WAIT_US_MAX);
> > > +	}
> > > +

[...]

> > > +	pm_runtime_get_sync(dev);
> > > +
> > > +	/* sanity check that programmed ranges match what's in DT */
> > > +	if (!tegra264_pcie_check_ranges(pdev)) {
> > > +		err = -EINVAL;
> > > +		goto put_pm;
> > > +	}
> > > +
> > > +	pcie->cfg = pci_ecam_create(dev, res, bus->res, &pci_generic_ecam_ops);
> > > +	if (IS_ERR(pcie->cfg)) {
> > > +		err = dev_err_probe(dev, PTR_ERR(pcie->cfg),
> > > +				    "failed to create ECAM\n");
> > > +		goto put_pm;
> > > +	}
> > > +
> > > +	bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
> > > +	bridge->sysdata = pcie->cfg;
> > > +	pcie->ecam = pcie->cfg->win;
> > > +
> > > +	tegra264_pcie_init(pcie);
> > > +
> > > +	if (!pcie->link_up)
> > > +		goto free;
> > 
> > goto free_ecam;
> 
> It's not clear to me, but are you suggesting to rename the existing
> "free" label to "free_ecam"? I can do that.
> 

Yeah, I was just asking for a rename.

> > > +	err = pci_host_probe(bridge);
> > > +	if (err < 0) {
> > > +		dev_err(dev, "failed to register host: %pe\n", ERR_PTR(err));
> > 
> > dev_err_probe()
> 
> Okay.
> 
> > 
> > > +		goto free;
> > > +	}
> > > +
> > > +	return err;
> > 
> > return 0;
> 
> Done.
> 
> [...]
> > > +static int tegra264_pcie_resume_noirq(struct device *dev)
> > > +{
> > > +	struct tegra264_pcie *pcie = dev_get_drvdata(dev);
> > > +	int err;
> > > +
> > > +	if (pcie->wake_gpio && device_may_wakeup(dev)) {
> > > +		err = disable_irq_wake(pcie->wake_irq);
> > > +		if (err < 0)
> > > +			dev_err(dev, "failed to disable wake IRQ: %pe\n",
> > > +				ERR_PTR(err));
> > > +	}
> > > +
> > > +	if (pcie->link_up == false)
> > > +		return 0;
> > > +
> > > +	tegra264_pcie_init(pcie);
> > > +
> > 
> > Why do you need init() here without deinit() in tegra264_pcie_suspend_noirq()?
> 
> That's because when we come out of suspend the link may have gone down
> again, so we need to take the endpoint out of reset to retrigger the
> link training. I think we could possibly explicitly clear that PERST_O_N
> bit in the PERST_CONTROL register in a new tegra264_pcie_deinit() to
> mirror what tegra264_pcie_init() does, but it's automatically done by
> firmware anyway, so not needed.
> 

Hmm, so firmware asserts PERST# at the end of suspend? It is not clear to me why
it is doing so. But for symmetry I'd like to do it in tegra264_pcie_deinit().

Also, I'm not certain about the 'pcie->link_up' check here. If it is 'false',
then probe() should've failed. So why do you need the check here anyway?

Maybe you should get rid of this check and return the link status from
tegra264_pcie_init() directly?

- Mani

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply

* Re: [PATCH v3 2/2] hwmon: (pmbus/q54sj108a2) Add support for q50sn12072 and q54sn120a1
From: Guenter Roeck @ 2026-04-10 16:30 UTC (permalink / raw)
  To: Brian Chiang, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: devicetree, linux-kernel, linux-hwmon, Jack Cheng
In-Reply-To: <20260402-add-support-for-q50sn12072-and-q54sn120a1-v3-2-67a5184e93b8@inventec.com>

On 4/1/26 18:29, Brian Chiang wrote:
> From: Jack Cheng <cheng.jackhy@inventec.com>
> 
> The Q50SN12072 and Q54SN120A1 are high-efficiency, high-density DC-DC power
> module from Delta Power Modules.
> 
> The Q50SN12072, quarter brick, single output 12V. This product provides up
> to 1200 watts of output power at 38~60V. The Q50SN12072 offers peak
> efficiency up to 98.3%@54Vin.
> 
> The Q54SN120A1, quarter brick, single output 12V. This product provides up
> to 1300 watts of output power at 40~60V. The Q54SN120A1 offers peak
> efficiency up to 98.1%@54Vin.
> 
> Add support for them to q54sj108a2 driver.
> 
> Signed-off-by: Jack Cheng <cheng.jackhy@inventec.com>
> Co-developed-by: Brian Chiang <chiang.brian@inventec.com>
> Signed-off-by: Brian Chiang <chiang.brian@inventec.com>
> ---
...
> -	/*
> -	 * The chips support reading PMBUS_MFR_MODEL.
> -	 */
>   	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
>   	if (ret < 0) {
>   		dev_err(dev, "Failed to read Manufacturer Model\n");
>   		return ret;
>   	}
> -	if (ret != 14 || strncmp(buf, "Q54SJ108A2", 10)) {
> +	for (mid = q54sj108a2_id; mid->name[0]; mid++) {
> +		if (!strncasecmp(mid->name, buf, strlen(mid->name)))
> +			break;
> +	}

If ret < strlen(mid->name), this check compares uninitialized data.
Also see Sashiko feedback:

https://sashiko.dev/#/patchset/20260402-add-support-for-q50sn12072-and-q54sn120a1-v3-0-67a5184e93b8%40inventec.com

Thanks,
Guenter


^ permalink raw reply

* Re: (subset) [PATCH v6 00/11] Add support for the TI BQ25792 battery charger
From: Mark Brown @ 2026-04-10 10:52 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chris Morgan, Liam Girdwood, Sebastian Reichel, Alexey Charkov
  Cc: devicetree, linux-kernel, Sebastian Reichel, linux-pm,
	Krzysztof Kozlowski, stable
In-Reply-To: <20260331-bq25792-v6-0-0278fba33eb9@flipper.net>

On Tue, 31 Mar 2026 19:43:37 +0400, Alexey Charkov wrote:
> Add support for the TI BQ25792 battery charger
> 
> This adds support for the TI BQ25792 battery charger, which is similar in
> overall logic to the BQ25703A, but has a different register layout and
> slightly different lower-level programming logic.
> 
> The series is organized as follows:
> - Patch 1 adds the new variant to the existing DT binding, including the
>   changes in electrical characteristics
> - Patches 2-4 are minor cleanups to the existing BQ25703A OTG regulator
>   driver, slimming down the code and making it more reusable for the new
>   BQ25792 variant
> - Patch 5 is a logical fix to the BQ25703A clamping logic for VSYSMIN
>   (this is a standalone fix which can be applied independently and may be
>   backported to stable)
> - Patches 6-8 are slight refactoring of the existing BQ25703A charger
>   driver to make it more reusable for the new BQ25792 variant
> - Patch 9 adds platform data to distinguish between the two variants in
>   the parent MFD driver, and binds it to the new compatible string
> - Patches 10-11 add variant-specific code to support the new BQ25792
>   variant in the regulator part and the charger part respectively,
>   selected by the platform data added in patch 9
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-7.1

Thanks!

[02/11] regulator: bq257xx: Remove reference to the parent MFD's dev
        https://git.kernel.org/broonie/regulator/c/aef4d87f2c1f
[04/11] regulator: bq257xx: Make OTG enable GPIO really optional
        https://git.kernel.org/broonie/regulator/c/de76a763805d

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark


^ permalink raw reply

* Re: [PATCH v12 2/2] hwmon: add support for MCP998X
From: Guenter Roeck @ 2026-04-10 16:22 UTC (permalink / raw)
  To: Victor Duicu
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Corbet,
	linux-hwmon, devicetree, linux-kernel, linux-doc, marius.cristea
In-Reply-To: <20260403-add-mcp9982-hwmon-v12-2-b3bfb26ff136@microchip.com>

On Fri, Apr 03, 2026 at 04:32:17PM +0300, Victor Duicu wrote:
> Add driver for Microchip MCP998X/33 and MCP998XD/33D
> Multichannel Automotive Temperature Monitor Family.
> 
> Signed-off-by: Victor Duicu <victor.duicu@microchip.com>

Applied.

Thanks,
Guenter

^ permalink raw reply

* Re: [PATCH v8 2/3] spi: spacemit: introduce SpacemiT K1 SPI controller driver
From: Mark Brown @ 2026-04-10 16:11 UTC (permalink / raw)
  To: Guodong Xu
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Yixun Lan,
	Alex Elder, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, linux-spi, devicetree, linux-riscv,
	spacemit, linux-kernel, Alex Elder
In-Reply-To: <20260410-spi-spacemit-k1-v8-2-53ebb48a4146@riscstar.com>

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

On Fri, Apr 10, 2026 at 11:04:21PM -0400, Guodong Xu wrote:
> 
> This patch introduces the driver for the SPI controller found in the
> SpacemiT K1 SoC.  Currently the driver supports master mode only.
> The SPI hardware implements RX and TX FIFOs, 32 entries each, and
> supports both PIO and DMA mode transfers.

> +static struct dma_async_tx_descriptor *
> +k1_spi_dma_prep(struct k1_spi_driver_data *drv_data,
> +		struct spi_transfer *transfer, bool tx)
> +{
> +	phys_addr_t addr = drv_data->base_addr + SSP_DATAR;
> +	u32 burst_size = K1_SPI_THRESH * drv_data->bytes;
> +	struct dma_slave_config cfg = { };
> +	enum dma_transfer_direction dir;
> +	enum dma_slave_buswidth width;
> +	struct dma_chan *chan;
> +	struct sg_table *sgt;
> +
> +	width = drv_data->bytes == 1 ? DMA_SLAVE_BUSWIDTH_1_BYTE :
> +		drv_data->bytes == 2 ? DMA_SLAVE_BUSWIDTH_2_BYTES :
> +		/* bytes == 4 */       DMA_SLAVE_BUSWIDTH_4_BYTES;

Please use normal conditional statements (in this case a case statement)
to keep the code legible.

> +static irqreturn_t k1_spi_ssp_isr(int irq, void *dev_id)
> +{
> +	struct k1_spi_driver_data *drv_data = dev_id;
> +	u32 val;

> +	/* Return immediately if we're not expecting any interrupts */
> +	if (!drv_data->transfer)
> +		return IRQ_NONE;

That does't mean the hardware agrees!

> +	/* Get status and clear pending interrupts; all are handled below */
> +	val = readl(drv_data->base + SSP_STATUS);
> +	writel(val, drv_data->base + SSP_STATUS);

Nothing after here can report IRQ_NONE, even if SSP_STATUS didn't flag
anything.  I'd just move the checks for transfer to when we're handling
FIFOs and have the IRQ_NONE report be based on there being something set
in the ISR.

> +	/*
> +	 * For SPI, bytes are transferred in both directions equally, and
> +	 * RX always follows TX.  Start by writing if there is anything to
> +	 * write, then read.  Once there's no more to read, we're done.
> +	 */
> +	if (drv_data->tx_resid && (val & SSP_STATUS_TNF)) {
> +		/* If we finish writing, disable TX interrupts */
> +		if (k1_spi_write(drv_data, val)) {
> +			val = SSP_INT_EN_RX | SSP_INT_EN_ERROR;
> +			writel(val, drv_data->base + SSP_INT_EN);
> +		}
> +	}

This overwrites val...

> +
> +	/* We're not done unless we've read all that was requested */
> +	if (drv_data->rx_resid) {
> +		/* Read more if there FIFO is not empty */
> +		if (val & SSP_STATUS_RNE)
> +			if (k1_spi_read(drv_data, val))
> +				goto done;

...so the read won't see that there's data to read and we'll need
another interrupt.  I would suggest using a more meaingful name for the
actual interrupt status.

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

^ permalink raw reply

* Re: [PATCH v6 1/3] hwmon: emc2305: Validate fan channel index
From: Guenter Roeck @ 2026-04-10 16:05 UTC (permalink / raw)
  To: florin.leotescu, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Michael Shych, linux-hwmon, devicetree, linux-kernel
  Cc: daniel.baluta, viorel.suman, linux-arm-kernel, imx, festevam,
	Florin Leotescu
In-Reply-To: <20260402122514.1811737-2-florin.leotescu@oss.nxp.com>

On 4/2/26 05:25, florin.leotescu@oss.nxp.com wrote:
> From: Florin Leotescu <florin.leotescu@nxp.com>
> 
> The fan channel index is used to access per-channel data structures.
> Validate the index agains the number of available channels
> before use to prevent out-of-bounds access if an invalid
> value is provided.
> 
> Signed-off-by: Florin Leotescu <florin.leotescu@nxp.com>
> ---
>   drivers/hwmon/emc2305.c | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c
> index 64b213e1451e..0b42b82c8e22 100644
> --- a/drivers/hwmon/emc2305.c
> +++ b/drivers/hwmon/emc2305.c
> @@ -548,6 +548,12 @@ static int emc2305_of_parse_pwm_child(struct device *dev,
>   		return ret;
>   	}
>   
> +	if (ch >= data->pwm_num) {
> +		dev_err(dev, "invalid reg %u for node %pOF (valid range 0-%u)\n", ch, child,
> +			data->pwm_num - 1);
> +		return -EINVAL;
> +	}
> +
>   	ret = of_parse_phandle_with_args(child, "pwms", "#pwm-cells", 0, &args);
>   
>   	if (ret)

Please address Sashiko's concerns regarding channel index validation.
It seems valid to me. Feel free to ignore the other comments.

https://sashiko.dev/#/patchset/20260402122514.1811737-1-florin.leotescu%40oss.nxp.com

Thanks,
Guenter


^ permalink raw reply

* Re: [PATCH v2 7/7] clk: qcom: Add support for global clock controller on Hawi
From: Mike Tipton @ 2026-04-10 15:58 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	linux-arm-msm, linux-clk, devicetree, linux-kernel, Konrad Dybcio
In-Reply-To: <20260409-clk-hawi-v2-7-c7a185389d9a@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 01:51:41PM -0700, Vivek Aknurwar wrote:
> Add support for the global clock controller (GCC) on the
> Qualcomm Hawi SoC.
> 
> Reviewed-by: Taniya Das <taniya.das@oss.qualcomm.com>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  drivers/clk/qcom/Kconfig    |    9 +
>  drivers/clk/qcom/Makefile   |    1 +
>  drivers/clk/qcom/gcc-hawi.c | 3657 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 3667 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v2 6/7] clk: qcom: clk-alpha-pll: Add support for Taycan EHA_T PLL
From: Mike Tipton @ 2026-04-10 15:57 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	linux-arm-msm, linux-clk, devicetree, linux-kernel, Konrad Dybcio
In-Reply-To: <20260409-clk-hawi-v2-6-c7a185389d9a@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 01:51:40PM -0700, Vivek Aknurwar wrote:
> Add clock operations and register offsets to enable control of the Taycan
> EHA_T PLL, allowing for proper configuration and management of the PLL.
> 
> Reviewed-by: Taniya Das <taniya.das@oss.qualcomm.com>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  drivers/clk/qcom/clk-alpha-pll.h | 6 ++++++
>  1 file changed, 6 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v2 5/7] clk: qcom: Add Hawi TCSR clock controller driver
From: Mike Tipton @ 2026-04-10 15:57 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	linux-arm-msm, linux-clk, devicetree, linux-kernel
In-Reply-To: <20260409-clk-hawi-v2-5-c7a185389d9a@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 01:51:39PM -0700, Vivek Aknurwar wrote:
> Add support for the TCSR clock controller found on the Qualcomm Hawi SoC.
> This controller provides reference clocks for various peripherals
> including PCIe, UFS, and USB.
> 
> Reviewed-by: Taniya Das <taniya.das@oss.qualcomm.com>
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  drivers/clk/qcom/Kconfig       |   7 ++
>  drivers/clk/qcom/Makefile      |   1 +
>  drivers/clk/qcom/tcsrcc-hawi.c | 158 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 166 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v2 4/7] clk: qcom: rpmh: Add support for Hawi RPMH clocks
From: Mike Tipton @ 2026-04-10 15:56 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	linux-arm-msm, linux-clk, devicetree, linux-kernel, Konrad Dybcio
In-Reply-To: <20260409-clk-hawi-v2-4-c7a185389d9a@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 01:51:38PM -0700, Vivek Aknurwar wrote:
> Add RPMH clocks present in Qualcomm Hawi SoC.
> 
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> Reviewed-by: Taniya Das <taniya.das@oss.qualcomm.com>
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  drivers/clk/qcom/clk-rpmh.c | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v2 3/7] dt-bindings: clock: qcom: Add Hawi global clock controller
From: Mike Tipton @ 2026-04-10 15:56 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	linux-arm-msm, linux-clk, devicetree, linux-kernel
In-Reply-To: <20260409-clk-hawi-v2-3-c7a185389d9a@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 01:51:37PM -0700, Vivek Aknurwar wrote:
> Add device tree bindings for the global clock controller on the
> Qualcomm Hawi SoC.
> 
> Acked-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  .../devicetree/bindings/clock/qcom,hawi-gcc.yaml   |  63 +++++
>  include/dt-bindings/clock/qcom,hawi-gcc.h          | 253 +++++++++++++++++++++
>  2 files changed, 316 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v2 2/7] dt-bindings: clock: qcom: Add Hawi TCSR clock controller
From: Mike Tipton @ 2026-04-10 15:55 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	linux-arm-msm, linux-clk, devicetree, linux-kernel
In-Reply-To: <20260409-clk-hawi-v2-2-c7a185389d9a@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 01:51:36PM -0700, Vivek Aknurwar wrote:
> Add bindings documentation for TCSR clock controller on the
> Qualcomm Hawi SoC.
> 
> Acked-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  .../devicetree/bindings/clock/qcom,sm8550-tcsr.yaml      |  2 ++
>  include/dt-bindings/clock/qcom,hawi-tcsrcc.h             | 16 ++++++++++++++++
>  2 files changed, 18 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v2 1/7] dt-bindings: clock: qcom-rpmhcc: Add RPMHCC bindings for Hawi
From: Mike Tipton @ 2026-04-10 15:54 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Bjorn Andersson, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Taniya Das, Taniya Das,
	linux-arm-msm, linux-clk, devicetree, linux-kernel
In-Reply-To: <20260409-clk-hawi-v2-1-c7a185389d9a@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 01:51:35PM -0700, Vivek Aknurwar wrote:
> Update documentation for the RPMH clock controller on the
> Qualcomm Hawi SoC.
> 
> Acked-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 +
>  include/dt-bindings/clock/qcom,rpmh.h                    | 2 ++
>  2 files changed, 3 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v2 2/3] remoteproc: imx_rproc: Pass bootaddr to SM CPU/LMM reset vector
From: Mathieu Poirier @ 2026-04-10 15:52 UTC (permalink / raw)
  To: Peng Fan
  Cc: Peng Fan, Bjorn Andersson, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Daniel Baluta, linux-remoteproc@vger.kernel.org,
	devicetree@vger.kernel.org, imx@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <adbzPl7ydUvb+MIS@shlinux89>

On Thu, Apr 09, 2026 at 08:30:54AM +0800, Peng Fan wrote:
> On Wed, Apr 08, 2026 at 09:46:32AM -0600, Mathieu Poirier wrote:
> >On Wed, Apr 08, 2026 at 01:30:16AM +0000, Peng Fan wrote:
> >> > Subject: Re: [PATCH v2 2/3] remoteproc: imx_rproc: Pass bootaddr to
> >> > SM CPU/LMM reset vector
> >> > 
> >> [...]
> >> > 
> >> > >
> >> > > Aligning the ELF entry point with the hardware reset base on
> >> > Cortex‑M
> >> > > systems is possible, but it comes with several risks.
> >> > 
> >> > I'm not asking to align the ELF entry point with the hardware reset base.
> >> > All I want is to have the correct start address embedded in the ELF file
> >> > to avoid having to use a mask.
> >> 
> >> I see, per my understanding:
> >> FreeRTOS typically exposes __isr_vector, which corresponds to the hardware
> >> reset / vector table base.
> >> Zephyr (Cortex‑M) exposes _vector_table, which serves the same purpose.
> >> I am not certain about other RTOSes, but the pattern seems consistent:
> >> the vector table base is already available as a named ELF symbol.
> >> 
> >> Given that, if the preferred approach is to parse the ELF and explicitly
> >> retrieve the hardware reset base, I can update the implementation accordingly.
> >> If you prefer to parse the elf file to get the hardware reset base,
> >> I could update to use them.
> >> 
> >> Options1: Something as below:
> >> 1. Include rproc_elf_find_symbol in remoteproc_elf_loader.c
> >> 2. Use below in imx_rproc.c
> >> ret = rproc_elf_find_symbol(rproc, fw, "__isr_vector", &vector_base);
> >> if (ret)
> >>     ret = rproc_elf_find_symbol(rproc, fw, "__vector_table", &vector_base);
> >> 
> >> if (!ret)
> >>     rproc->bootaddr = vector_base
> >> else
> >>    dev_info(dev, "no __isr_vector or __vector_table\n")
> >
> >No
> 
> If your concern is about rproc->bootaddr, I could introduce
> imx_rproc->vector_base for i.MX.  Please help detail a bit.
> 
> >
> >> 
> >> This makes the hardware reset base explicit, avoids masking e_entry.
> >> 
> >> Option 2: User‑provided reset symbol via sysfs 
> >> As an alternative, we could expose a sysfs attribute,
> >> e.g. reset_symbol, allowing users to specify the symbol name
> >> to be used as the reset base:
> >> 
> >> echo __isr_vector > /sys/class/remoteproc/remoteprocX/reset_symbol
> >> 
> >
> >Definitely not.
> >
> >The definition of e_entry in the specification is clear, i.e "the address of the
> >entry point from where the process starts executing".  If masking is required
> >because the tool that puts the image together gets the wrong address, then it
> >should be fixed.
> 
> The hardware reset base is the address from which the hardware fetches the
> initial stack pointer and program counter values and loads them into the SP
> and PC registers.  In contrast, bootaddr (i.e. e_entry) represents the address
> at which the CPU starts executing code (the PC value after reset). As you
> pointed out earlier, this distinction is clear.
> 
> In our case, we need to obtain the hardware reset base and pass that value to
> the system firmware. However, e_entry should not be set to the hardware reset
> base. Doing so would introduce the issues I described in [1]. This means we
> should not modify the Zephyr or FreeRTOS build outputs to make e_entry equal
> to the hardware reset base.


As I said earlier, I am _not_ suggesting to make e_entry equal to the hardware
reset base.

We are going in circles here.

> 
> Given these constraints, the feasible solutions I can see are either:
> - option 1 (explicitly retrieving the hardware reset base), or
> - continuing to use masking.
> 
> Please suggest.
> 
> [1] https://lore.kernel.org/all/acs2PAZq2k3zjmDW@shlinux89/
> 
> Thanks,
> Peng
> 
> >
> >> The remoteproc core would then resolve that symbol from
> >> the ELF and set rproc->bootaddr accordingly.
> >> This provides maximum flexibility but does introduce a new user‑visible ABI,
> >> so I see it more as an opt‑in or fallback mechanism.
> >> 
> >> Please let me know which approach you prefer, and I will update
> >> this series accordingly in v3..
> >> 
> >> Thanks,
> >> Peng.
> >> 
> >> 
> >> > 
> >> > > 1, Semantic mismatch (ELF vs. hardware behavior) 2, Debuggers may
> >> > > attempt to set breakpoints or start execution at the entry symbol
> >> > >

^ permalink raw reply

* Re: [PATCH v9 0/2] Add support for Microchip EMC1812
From: Guenter Roeck @ 2026-04-10 15:51 UTC (permalink / raw)
  To: Marius Cristea, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jonathan Corbet
  Cc: linux-hwmon, devicetree, linux-kernel, linux-doc, Conor Dooley
In-Reply-To: <20260403-hw_mon-emc1812-v9-0-1a798f31cf2e@microchip.com>

On 4/3/26 05:39, Marius Cristea wrote:
> This is the hwmon driver for EMC1812/13/14/15/33 multichannel Low-Voltage
> Remote Diode Sensor Family. The chips in the family have one internal
> and different numbers of external channels, ranging from 1 (EMC1812) to
> 4 channels (EMC1815).
> Reading diodes in anti-parallel connection is supported by EMC1814, EMC1815
> and EMC1833.
> 
> Signed-off-by: Marius Cristea <marius.cristea@microchip.com>

Sashiko still reports numberous issues which I consider valid:

https://sashiko.dev/#/patchset/20260403-hw_mon-emc1812-v9-0-1a798f31cf2e%40microchip.com

Please fix.

Thanks,
Guenter

> ---
> Changes in v9:
> - improve the wording in the Documentation/hwmon/emc1812.rst file
> - add const to variables in the driver
> - initialize the EXT2_BETA_CONFIG only for the pats that support it
> - update the writeble regmap table to exclude read-only registers
> - Link to v8: https://lore.kernel.org/r/20260310-hw_mon-emc1812-v8-0-bc155727e0d2@microchip.com
> 
> Changes in v8:
> - remove "address scan" from emc1812.rst documentation
> - change the second dimension of emc1812_limit_regs_low[][] to 2
> - clamp input value before doing math on it to avoid overflow
> - use rounding instead of truncation for 8 bits limit registers
> - fix misleading comment when HW ID is not recognized
> - Link to v7: https://lore.kernel.org/r/20260223-hw_mon-emc1812-v7-0-51e2676f4e20@microchip.com
> 
> Changes in v7:
> - driver
>    - fix an overflow emc1812_set_hyst
>    - remove unused parameter in emc1812_set_temp
> - devicetree binding:
>    - remove unneeded restrictions not to bloating the binding
> - Link to v6: https://lore.kernel.org/r/20260212-hw_mon-emc1812-v6-0-e37e9b38d898@microchip.com
> 
> Changes in v6:
> - driver
>    - fix an overflow when writing more then 191875 to limits stored on 8
>      bits register
>    - remove "i2c_set_clientdata" from probe
>    - fix discrepancy where writing 16ms and reading it back returns 15ms
>      at update interval
>    - skip setting the ideality factor for channels that are not available
>      on the device
> - devicetree binding:
>    - change the way interrupts are described/used
>    - add "microchip,enable-anti-parallel"
>    - rewrite "allOf" section to be more clear
> - Link to v5: https://lore.kernel.org/r/20260205-hw_mon-emc1812-v5-0-232835aefe8f@microchip.com
> 
> Changes in v5:
> - fix calculation in emc1812_get_limit_temp
> - use i2c_get_match_data cover the case when the driver is instantiated
>    via I2C ID table.
> - replace dev_info with dev_warn
> - remove some unnecessary truncation on 8 bits
> - remove clamping when reading the temerature with hyst
> - not change the conversion rate at probe time
> - use a generic define to remove duplicate channel_info entries
> - Link to v4: https://lore.kernel.org/r/20260127-hw_mon-emc1812-v4-0-6bf636b54847@microchip.com
> 
> Changes in v4:
> - fix file permissions for read only properties
> - fix calculation when the limits are written
> - remove the temp_min_hyst because the part doesn't support it
> - Link to v3: https://lore.kernel.org/r/20251218-hw_mon-emc1812-v3-0-a123ada7b859@microchip.com
> 
> Changes in v3:
> - remove mesages that are not helpfull
> - fix an issue related to NULL labels
> - fix sign/unsign calculation
> - replace E2BIG with EINVAL
> - use BIT() to create mask
> - Link to v2: https://lore.kernel.org/r/20251121-hw_mon-emc1812-v2-0-5b2070f8b778@microchip.com
> 
> Changes in v2:
> - update the interrupt section from yaml file
> - update index.rst
> - remove fault condition from internal sensor
> - remove unused members from structures
> - update the driver to work on systems without device tree or
>    firmware nodes
> - add missing include files
> - make NULL labels to be not visible
> - corect sign/unsign calculations
> - corect possible underflow for limits
> - Link to v1: https://lore.kernel.org/r/20251029-hw_mon-emc1812-v1-0-be4fd8af016a@microchip.com
> 
> ---
> Marius Cristea (2):
>        dt-bindings: hwmon: temperature: add support for EMC1812
>        hwmon: temperature: add support for EMC1812
> 
>   .../bindings/hwmon/microchip,emc1812.yaml          | 184 ++++
>   Documentation/hwmon/emc1812.rst                    |  67 ++
>   Documentation/hwmon/index.rst                      |   1 +
>   MAINTAINERS                                        |   8 +
>   drivers/hwmon/Kconfig                              |  11 +
>   drivers/hwmon/Makefile                             |   1 +
>   drivers/hwmon/emc1812.c                            | 965 +++++++++++++++++++++
>   7 files changed, 1237 insertions(+)
> ---
> base-commit: d2b2fea3503e5e12b2e28784152937e48bcca6ff
> change-id: 20251002-hw_mon-emc1812-f1b806487d10
> 
> Best regards,


^ permalink raw reply

* Re: [PATCH v2] dt-bindings: watchdog: rockchip: Add RV1103B compatible
From: Guenter Roeck @ 2026-04-10 15:49 UTC (permalink / raw)
  To: Fabio Estevam
  Cc: wim, robh, krzk+dt, conor+dt, linux-watchdog, devicetree,
	linux-kernel, heiko, Fabio Estevam
In-Reply-To: <CAOMZO5DFWYUPN9sPzBr-W7fy8ZbrXP7u1sx=HrmUAQVCLrsdjQ@mail.gmail.com>

On 4/8/26 03:28, Fabio Estevam wrote:
> Hi Guenter,
> 
> On Mon, Mar 16, 2026 at 11:14 AM Guenter Roeck <linux@roeck-us.net> wrote:
>>
>> On 3/9/26 17:20, Fabio Estevam wrote:
>>> From: Fabio Estevam <festevam@nabladev.com>
>>>
>>> The RV1103B watchdog is compatible with the existing DesignWare Watchdog
>>> binding. Add the rockchip,rv1103b-wdt compatible string.
>>>
>>> Signed-off-by: Fabio Estevam <festevam@nabladev.com>
>>
>> Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> 
> Could you please apply this one?

Wim applies watchdog subsystem patches.

Guenter


^ permalink raw reply

* Re: [PATCH v5 5/5] watchdog: aaeon: Add watchdog driver for SRG-IMX8P MCU
From: Guenter Roeck @ 2026-04-10 15:49 UTC (permalink / raw)
  To: Thomas Perrot (Schneider Electric), Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Linus Walleij,
	Bartosz Golaszewski, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam,
	Jérémie Dautheribes, Wim Van Sebroeck, Lee Jones
  Cc: devicetree, linux-kernel, linux-gpio, imx, linux-arm-kernel,
	linux-watchdog, Thomas Petazzoni, Miquel Raynal
In-Reply-To: <20260408-dev-b4-aaeon-mcu-driver-v5-5-ad98bd481668@bootlin.com>

On 4/8/26 10:21, Thomas Perrot (Schneider Electric) wrote:
> Add watchdog driver for the Aaeon SRG-IMX8P embedded controller.
> This driver provides system monitoring and recovery capabilities
> through the MCU's watchdog timer.
> 
> The watchdog supports start, stop, and ping operations with a maximum
> hardware heartbeat of 25 seconds and a default timeout of 240 seconds.
> 
> Co-developed-by: Jérémie Dautheribes (Schneider Electric) <jeremie.dautheribes@bootlin.com>
> Signed-off-by: Jérémie Dautheribes (Schneider Electric) <jeremie.dautheribes@bootlin.com>
> Signed-off-by: Thomas Perrot (Schneider Electric) <thomas.perrot@bootlin.com>
> ---
>   MAINTAINERS                      |   1 +
>   drivers/watchdog/Kconfig         |  10 +++
>   drivers/watchdog/Makefile        |   1 +
>   drivers/watchdog/aaeon_mcu_wdt.c | 132 +++++++++++++++++++++++++++++++++++++++
>   4 files changed, 144 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2538f8c4bc14..7b92af42c9fd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -193,6 +193,7 @@ S:	Maintained
>   F:	Documentation/devicetree/bindings/mfd/aaeon,srg-imx8p-mcu.yaml
>   F:	drivers/gpio/gpio-aaeon-mcu.c
>   F:	drivers/mfd/aaeon-mcu.c
> +F:	drivers/watchdog/aaeon_mcu_wdt.c
>   F:	include/linux/mfd/aaeon-mcu.h
>   
>   AAEON UPBOARD FPGA MFD DRIVER
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index d3b9df7d466b..f67a0b453316 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -420,6 +420,16 @@ config SL28CPLD_WATCHDOG
>   
>   # ARM Architecture
>   
> +config AAEON_MCU_WATCHDOG
> +	tristate "Aaeon MCU Watchdog"
> +	depends on MFD_AAEON_MCU
> +	select WATCHDOG_CORE
> +	help
> +	  Select this option to enable watchdog timer support for the Aaeon
> +	  SRG-IMX8P onboard microcontroller (MCU). This driver provides
> +	  watchdog functionality through the MCU, allowing system monitoring
> +	  and automatic recovery from system hangs.
> +
>   config AIROHA_WATCHDOG
>   	tristate "Airoha EN7581 Watchdog"
>   	depends on ARCH_AIROHA || COMPILE_TEST
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index ba52099b1253..2deec425d3ea 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -37,6 +37,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
>   # ALPHA Architecture
>   
>   # ARM Architecture
> +obj-$(CONFIG_AAEON_MCU_WATCHDOG) += aaeon_mcu_wdt.o
>   obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
>   obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o
>   obj-$(CONFIG_ARMADA_37XX_WATCHDOG) += armada_37xx_wdt.o
> diff --git a/drivers/watchdog/aaeon_mcu_wdt.c b/drivers/watchdog/aaeon_mcu_wdt.c
> new file mode 100644
> index 000000000000..949b506d8194
> --- /dev/null
> +++ b/drivers/watchdog/aaeon_mcu_wdt.c
> @@ -0,0 +1,132 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Aaeon MCU Watchdog driver
> + *
> + * Copyright (C) 2026 Bootlin
> + * Author: Jérémie Dautheribes <jeremie.dautheribes@bootlin.com>
> + * Author: Thomas Perrot <thomas.perrot@bootlin.com>
> + */
> +
> +#include <linux/mfd/aaeon-mcu.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/watchdog.h>
> +
> +#define AAEON_MCU_PING_WDT	0x73
> +
> +#define AAEON_MCU_WDT_TIMEOUT         240
> +#define AAEON_MCU_WDT_HEARTBEAT_MS    25000
> +
> +struct aaeon_mcu_wdt {
> +	struct watchdog_device wdt;
> +	struct regmap *regmap;
> +};
> +
> +static int aaeon_mcu_wdt_cmd(struct aaeon_mcu_wdt *data, u8 opcode, u8 arg)
> +{
> +	return regmap_write(data->regmap, AAEON_MCU_REG(opcode, arg), 0);
> +}
> +
> +static int aaeon_mcu_wdt_start(struct watchdog_device *wdt)
> +{
> +	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
> +
> +	return aaeon_mcu_wdt_cmd(data, AAEON_MCU_CONTROL_WDT_OPCODE, 0x01);
> +}
> +
> +static int aaeon_mcu_wdt_status(struct watchdog_device *wdt, bool *enabled)
> +{
> +	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
> +	unsigned int rsp;
> +	int ret;
> +
> +	ret = regmap_read(data->regmap,
> +			  AAEON_MCU_REG(AAEON_MCU_CONTROL_WDT_OPCODE, 0x02),
> +			  &rsp);
> +	if (ret)
> +		return ret;
> +
> +	*enabled = rsp == 0x01;
> +	return 0;
> +}
> +
> +static int aaeon_mcu_wdt_stop(struct watchdog_device *wdt)
> +{
> +	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
> +
> +	return aaeon_mcu_wdt_cmd(data, AAEON_MCU_CONTROL_WDT_OPCODE, 0x00);
> +}
> +
> +static int aaeon_mcu_wdt_ping(struct watchdog_device *wdt)
> +{
> +	struct aaeon_mcu_wdt *data = watchdog_get_drvdata(wdt);
> +
> +	return aaeon_mcu_wdt_cmd(data, AAEON_MCU_PING_WDT, 0x00);
> +}
> +
> +static const struct watchdog_info aaeon_mcu_wdt_info = {
> +	.identity	= "Aaeon MCU Watchdog",
> +	.options	= WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
> +};
> +
> +static const struct watchdog_ops aaeon_mcu_wdt_ops = {
> +	.owner		= THIS_MODULE,
> +	.start		= aaeon_mcu_wdt_start,
> +	.stop		= aaeon_mcu_wdt_stop,
> +	.ping		= aaeon_mcu_wdt_ping,
> +};
> +
> +static int aaeon_mcu_wdt_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct watchdog_device *wdt;
> +	struct aaeon_mcu_wdt *data;
> +	bool enabled;
> +	int ret;
> +
> +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!data->regmap)
> +		return -ENODEV;
> +
> +	wdt = &data->wdt;
> +	wdt->parent = dev;
> +	wdt->info = &aaeon_mcu_wdt_info;
> +	wdt->ops = &aaeon_mcu_wdt_ops;
> +	/*
> +	 * The MCU firmware has a fixed hardware timeout of 25 seconds that
> +	 * cannot be changed. The watchdog core will handle automatic pinging
> +	 * to support longer timeouts. The software timeout of 240 seconds is
> +	 * chosen arbitrarily as a reasonable value and is not user-configurable.
> +	 */

Odd, unusual, unnecessary, I would argue that most people would consider a fixed
timeout of 240s as anything but reasonable, and as the comment says arbitrary.
Since I am sure that I pointed this out before, you still insist, and I am
tired of arguing: Your funeral, so

Acked-by: Guenter Roeck <linux@roeck-us.net>

Guenter

> +	wdt->timeout = AAEON_MCU_WDT_TIMEOUT;
> +	wdt->max_hw_heartbeat_ms = AAEON_MCU_WDT_HEARTBEAT_MS;
> +
> +	watchdog_set_drvdata(wdt, data);
> +
> +	ret = aaeon_mcu_wdt_status(wdt, &enabled);
> +	if (ret)
> +		return ret;
> +
> +	if (enabled)
> +		set_bit(WDOG_HW_RUNNING, &wdt->status);
> +
> +	return devm_watchdog_register_device(dev, wdt);
> +}
> +
> +static struct platform_driver aaeon_mcu_wdt_driver = {
> +	.driver		= {
> +		.name	= "aaeon-mcu-wdt",
> +	},
> +	.probe		= aaeon_mcu_wdt_probe,
> +};
> +
> +module_platform_driver(aaeon_mcu_wdt_driver);
> +
> +MODULE_DESCRIPTION("Aaeon MCU Watchdog Driver");
> +MODULE_AUTHOR("Jérémie Dautheribes <jeremie.dautheribes@bootlin.com>");
> +MODULE_LICENSE("GPL");
> 


^ permalink raw reply

* Re: [PATCH v8 1/3] dt-bindings: spi: add SpacemiT K1 SPI support
From: Mark Brown @ 2026-04-10 15:44 UTC (permalink / raw)
  To: Guodong Xu
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Yixun Lan,
	Alex Elder, Philipp Zabel, Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, linux-spi, devicetree, linux-riscv,
	spacemit, linux-kernel, Alex Elder, Conor Dooley, Troy Mitchell
In-Reply-To: <20260410-spi-spacemit-k1-v8-1-53ebb48a4146@riscstar.com>

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

On Fri, Apr 10, 2026 at 11:04:20PM -0400, Guodong Xu wrote:
> From: Alex Elder <elder@riscstar.com>
> 
> Add support for the SPI controller implemented by the SpacemiT K1 SoC.

Please submit patches using subject lines reflecting the style for the
subsystem, this makes it easier for people to identify relevant patches.
Look at what existing commits in the area you're changing are doing and
make sure your subject lines visually resemble what they're doing.
There's no need to resubmit to fix this alone.

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

^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: interconnect: qcom: document the RPMh NoC for Hawi SoC
From: Mike Tipton @ 2026-04-10 15:42 UTC (permalink / raw)
  To: Vivek Aknurwar
  Cc: Georgi Djakov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-arm-msm, linux-pm, devicetree, linux-kernel
In-Reply-To: <20260409-icc-hawi-v3-1-851cac12a81d@oss.qualcomm.com>

On Thu, Apr 09, 2026 at 02:01:37PM -0700, Vivek Aknurwar wrote:
> Document the RPMh Network-On-Chip interconnect for the Qualcomm Hawi SoC.
> 
> Signed-off-by: Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
> ---
>  .../bindings/interconnect/qcom,hawi-rpmh.yaml      | 131 ++++++++++++++++
>  include/dt-bindings/interconnect/qcom,hawi-rpmh.h  | 164 +++++++++++++++++++++
>  2 files changed, 295 insertions(+)

Reviewed-by: Mike Tipton <mike.tipton@oss.qualcomm.com>

Thanks,
Mike

^ permalink raw reply

* Re: [PATCH v5 2/2] hwmon: pmbus: Add support for Sony APS-379
From: Guenter Roeck @ 2026-04-10 15:27 UTC (permalink / raw)
  To: Chris Packham
  Cc: robh, krzk+dt, conor+dt, devicetree, linux-hwmon, linux-kernel
In-Reply-To: <20260410012414.2818829-3-chris.packham@alliedtelesis.co.nz>

On Fri, Apr 10, 2026 at 01:24:12PM +1200, Chris Packham wrote:
> Add pmbus support for Sony APS-379 power supplies. There are a few PMBUS
> commands that return data that is undocumented/invalid so these need to
> be rejected with -ENXIO. The READ_VOUT command returns data in linear11
> format instead of linear16 so we need to workaround this.
> 
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>

Applied.

Thanks,
Guenter

^ permalink raw reply

* Re: [PATCH v5 1/2] dt-bindings: trivial-devices: Add sony,aps-379
From: Guenter Roeck @ 2026-04-10 15:23 UTC (permalink / raw)
  To: Chris Packham
  Cc: robh, krzk+dt, conor+dt, devicetree, linux-hwmon, linux-kernel
In-Reply-To: <20260410012414.2818829-2-chris.packham@alliedtelesis.co.nz>

On Fri, Apr 10, 2026 at 01:24:11PM +1200, Chris Packham wrote:
> Add the compatible string for the sony,aps-379. This is a simple PMBus
> (I2C) device that requires no additional attributes.
> 
> Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Applied.

Thanks,
Guenter

^ permalink raw reply

* [PATCH v8 3/3] riscv: dts: spacemit: define a SPI controller node
From: Guodong Xu @ 2026-04-11  3:04 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, Alex Elder, Philipp Zabel, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-spi, devicetree, linux-riscv, spacemit, linux-kernel,
	Guodong Xu, Alex Elder, Yixun Lan
In-Reply-To: <20260410-spi-spacemit-k1-v8-0-53ebb48a4146@riscstar.com>

From: Alex Elder <elder@riscstar.com>

Define a node for the fourth SoC SPI controller (number 3) on the
SpacemiT K1 SoC.

Enable it on the Banana Pi BPI-F3 board, which exposes this feature
via its GPIO block:
  GPIO PIN 19:  MOSI
  GPIO PIN 21:  MISO
  GPIO PIN 23:  SCLK
  GPIO PIN 24:  SS (inverted)

Define pincontrol configurations for the pins as used on that board.

(This was tested using a GigaDevice GD25Q64E SPI NOR chip.)

Reviewed-by: Yixun Lan <dlan@gentoo.org>
Signed-off-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Guodong Xu <guodong@riscstar.com>
---
 arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts |  7 +++++++
 arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi    | 20 ++++++++++++++++++++
 arch/riscv/boot/dts/spacemit/k1.dtsi            | 15 +++++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
index 5971605754b35..61b93765f42cf 100644
--- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
@@ -14,6 +14,7 @@ aliases {
 		ethernet0 = &eth0;
 		ethernet1 = &eth1;
 		serial0 = &uart0;
+		spi3 = &spi3;
 		i2c2 = &i2c2;
 		i2c8 = &i2c8;
 	};
@@ -327,6 +328,12 @@ &pcie2 {
 	status = "okay";
 };
 
+&spi3 {
+	pinctrl-0 = <&ssp3_0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
 &uart0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart0_2_cfg>;
diff --git a/arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi b/arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi
index b13dcb10f4d66..34d88334e95e4 100644
--- a/arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi
@@ -570,4 +570,24 @@ pwm14-1-pins {
 			drive-strength = <32>;
 		};
 	};
+
+	ssp3_0_cfg: ssp3-0-cfg {
+		ssp3-0-pins {
+			pinmux = <K1_PADCONF(75, 2)>,	/* SCLK */
+				 <K1_PADCONF(77, 2)>,	/* MOSI  */
+				 <K1_PADCONF(78, 2)>;	/* MISO */
+
+			bias-disable;
+			drive-strength = <19>;
+			power-source = <3300>;
+		};
+
+		ssp3-0-frm-pins {
+			pinmux = <K1_PADCONF(76, 2)>;	/* FRM (frame) */
+
+			bias-pull-up = <0>;
+			drive-strength = <19>;
+			power-source = <3300>;
+		};
+	};
 };
diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index 529ec68e9c23e..1ecb09e58042f 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -983,6 +983,21 @@ qspi: spi@d420c000 {
 				status = "disabled";
 			};
 
+			spi3: spi@d401c000 {
+				compatible = "spacemit,k1-spi";
+				reg = <0x0 0xd401c000 0x0 0x30>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+				clocks = <&syscon_apbc CLK_SSP3>,
+					 <&syscon_apbc CLK_SSP3_BUS>;
+				clock-names = "core", "bus";
+				resets = <&syscon_apbc RESET_SSP3>;
+				interrupts = <55>;
+				dmas = <&pdma 20>, <&pdma 19>;
+				dma-names = "rx", "tx";
+				status = "disabled";
+			};
+
 			/* sec_uart1: 0xf0612000, not available from Linux */
 		};
 

-- 
2.43.0


^ permalink raw reply related

* [PATCH v8 2/3] spi: spacemit: introduce SpacemiT K1 SPI controller driver
From: Guodong Xu @ 2026-04-11  3:04 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, Alex Elder, Philipp Zabel, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-spi, devicetree, linux-riscv, spacemit, linux-kernel,
	Guodong Xu, Alex Elder
In-Reply-To: <20260410-spi-spacemit-k1-v8-0-53ebb48a4146@riscstar.com>

From: Alex Elder <elder@riscstar.com>

This patch introduces the driver for the SPI controller found in the
SpacemiT K1 SoC.  Currently the driver supports master mode only.
The SPI hardware implements RX and TX FIFOs, 32 entries each, and
supports both PIO and DMA mode transfers.

Signed-off-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Guodong Xu <guodong@riscstar.com>
---
v8: Addressing Mark Brown's v7 review:
  - Use C++ style (//) comments for the entire file header
  - Remove all open-coded DMA mapping; rely on the SPI core to
    handle DMA mapping via transfer->tx_sg/rx_sg
  - Implement can_dma() callback, replacing open-coded transfer
    length checks
  - Implement set_cs() callback for chip select control via the
    TOP_HOLD_FRAME_LOW register bit
  - Switch from transfer_one_message() to transfer_one(), letting
    the SPI core handle message-level flow control
  - DMA completion now calls spi_finalize_current_transfer()
    directly instead of using a completion
  - Add SSP_STATUS_BCE (bit count error) to error detection
  - Interrupt handler returns IRQ_NONE early if no transfer is
    active, before acknowledging interrupts
  - Update copyright year to 2026
---
 drivers/spi/Kconfig           |   9 +
 drivers/spi/Makefile          |   1 +
 drivers/spi/spi-spacemit-k1.c | 782 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 792 insertions(+)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index c3b2f02f5912e..b50d9ae1a498b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -1085,6 +1085,15 @@ config SPI_SG2044_NOR
 	  also supporting 3Byte address devices and 4Byte address
 	  devices.
 
+config SPI_SPACEMIT_K1
+	tristate "K1 SPI Controller"
+	depends on ARCH_SPACEMIT || COMPILE_TEST
+	depends on OF
+	imply MMP_PDMA if ARCH_SPACEMIT
+	default m if ARCH_SPACEMIT
+	help
+	  Enable support for the SpacemiT K1 SPI controller.
+
 config SPI_SPRD
 	tristate "Spreadtrum SPI controller"
 	depends on ARCH_SPRD || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 9d36190a98848..9fa12498ce8c0 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -143,6 +143,7 @@ obj-$(CONFIG_SPI_SIFIVE)		+= spi-sifive.o
 obj-$(CONFIG_SPI_SLAVE_MT27XX)          += spi-slave-mt27xx.o
 obj-$(CONFIG_SPI_SN_F_OSPI)		+= spi-sn-f-ospi.o
 obj-$(CONFIG_SPI_SG2044_NOR)	+= spi-sg2044-nor.o
+obj-$(CONFIG_SPI_SPACEMIT_K1)		+= spi-spacemit-k1.o
 obj-$(CONFIG_SPI_SPRD)			+= spi-sprd.o
 obj-$(CONFIG_SPI_SPRD_ADI)		+= spi-sprd-adi.o
 obj-$(CONFIG_SPI_STM32) 		+= spi-stm32.o
diff --git a/drivers/spi/spi-spacemit-k1.c b/drivers/spi/spi-spacemit-k1.c
new file mode 100644
index 0000000000000..8cef633144954
--- /dev/null
+++ b/drivers/spi/spi-spacemit-k1.c
@@ -0,0 +1,782 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// SpacemiT K1 SPI controller driver
+//
+// Copyright (C) 2026, RISCstar Solutions Corporation
+// Copyright (C) 2023, SpacemiT Corporation
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/scatterlist.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#include "internals.h"
+
+/* This is the range of transfer rates supported by the K1 SoC */
+#define K1_SPI_MIN_SPEED_HZ		6250
+#define K1_SPI_MAX_SPEED_HZ		51200000
+
+/* DMA constraints */
+#define K1_SPI_DMA_ALIGNMENT		64
+#define K1_SPI_MAX_DMA_LEN		SZ_512K
+
+/* SSP Top Control Register */
+#define SSP_TOP_CTRL		0x00
+#define TOP_SSE				BIT(0)		/* Enable port */
+#define TOP_FRF_MASK			GENMASK(2, 1)	/* Frame format */
+#define TOP_FRF_MOTOROLA			0	/* Motorola SPI */
+#define TOP_DSS_MASK			GENMASK(9, 5)	/* Data size (1-32) */
+#define TOP_SPO				BIT(10)		/* Polarity: 0=low */
+#define TOP_SPH				BIT(11)		/* Half-cycle phase */
+#define TOP_LBM				BIT(12)		/* Loopback mode */
+#define TOP_TRAIL			BIT(13)		/* Trailing bytes */
+#define TOP_HOLD_FRAME_LOW		BIT(14)		/* Chip select */
+
+/* SSP FIFO Control Register */
+#define SSP_FIFO_CTRL		0x04
+#define FIFO_TFT_MASK			GENMASK(4, 0)	/* TX FIFO threshold */
+#define FIFO_RFT_MASK			GENMASK(9, 5)	/* RX FIFO threshold */
+#define FIFO_TSRE			BIT(10)		/* TX service request */
+#define FIFO_RSRE			BIT(11)		/* RX service request */
+
+/* SSP Interrupt Enable Register */
+#define SSP_INT_EN		0x08
+#define SSP_INT_EN_TINTE		BIT(1)		/* RX timeout */
+#define SSP_INT_EN_RIE			BIT(2)		/* RX FIFO */
+#define SSP_INT_EN_TIE			BIT(3)		/* TX FIFO */
+#define SSP_INT_EN_RIM			BIT(4)		/* RX FIFO overrun */
+#define SSP_INT_EN_TIM			BIT(5)		/* TX FIFO underrun */
+#define SSP_INT_EN_EBCEI		BIT(6)		/* Bit count error */
+
+/* TX interrupts, RX interrupts, and error interrupts */
+#define SSP_INT_EN_TX		SSP_INT_EN_TIE
+#define SSP_INT_EN_RX \
+		(SSP_INT_EN_TINTE | SSP_INT_EN_RIE)
+#define SSP_INT_EN_ERROR \
+		(SSP_INT_EN_RIM | SSP_INT_EN_TIM | SSP_INT_EN_EBCEI)
+
+/* SSP Time Out Register */
+#define SSP_TIMEOUT		0x0c
+#define SSP_TIMEOUT_MASK		GENMASK(23, 0)
+
+/* SSP Data Register */
+#define SSP_DATAR		0x10
+
+/* SSP Status Register */
+#define SSP_STATUS		0x14
+#define SSP_STATUS_BSY			BIT(0)		/* SPI/I2S busy */
+#define SSP_STATUS_TNF			BIT(6)		/* TX FIFO not full */
+#define SSP_STATUS_TFL			GENMASK(11, 7)	/* TX FIFO level */
+#define SSP_STATUS_TUR			BIT(12)		/* TX FIFO underrun */
+#define SSP_STATUS_RNE			BIT(14)		/* RX FIFO not empty */
+#define SSP_STATUS_RFL			GENMASK(19, 15)	/* RX FIFO level */
+#define SSP_STATUS_ROR			BIT(20)		/* RX FIFO overrun */
+#define SSP_STATUS_BCE			BIT(21)		/* Bit count error */
+
+/* Error status mask */
+#define SSP_STATUS_ERROR \
+		(SSP_STATUS_TUR | SSP_STATUS_ROR | SSP_STATUS_BCE)
+
+/* The FIFO sizes and thresholds are the same for RX and TX */
+#define K1_SPI_FIFO_SIZE	32
+#define K1_SPI_THRESH		(K1_SPI_FIFO_SIZE / 2)
+
+struct k1_spi_driver_data {
+	struct spi_controller *host;
+	void __iomem *base;
+	phys_addr_t base_addr;
+	unsigned long bus_rate;
+	struct clk *clk;
+	unsigned long rate;
+	int irq;
+
+	/* Current transfer information; not valid if message is null */
+	u32 bytes;			/* Bytes used for bits_per_word */
+	unsigned int rx_resid;		/* RX bytes left in transfer */
+	unsigned int tx_resid;		/* TX bytes left in transfer */
+	struct spi_transfer *transfer;	/* Current transfer */
+
+	bool dma_enabled;
+};
+
+/* Set our registers to a known initial state */
+static void
+k1_spi_register_reset(struct k1_spi_driver_data *drv_data, bool initial)
+{
+	u32 val = 0;
+
+	writel(0, drv_data->base + SSP_TOP_CTRL);
+
+	if (initial) {
+		/*
+		 * The TX and RX FIFO thresholds are the same no matter
+		 * what the speed or bits per word, so we can just set
+		 * them once.  The thresholds are one more than the values
+		 * in the register.
+		 */
+		val = FIELD_PREP(FIFO_RFT_MASK, K1_SPI_THRESH - 1);
+		val |= FIELD_PREP(FIFO_TFT_MASK, K1_SPI_THRESH - 1);
+	}
+	writel(val, drv_data->base + SSP_FIFO_CTRL);
+
+	writel(0, drv_data->base + SSP_INT_EN);
+	writel(0, drv_data->base + SSP_TIMEOUT);
+
+	/* Clear any pending interrupt conditions */
+	writel(~0, drv_data->base + SSP_STATUS);
+}
+
+/*
+ * The client can call the setup function multiple times, and each call
+ * can specify a different SPI mode (and transfer speed).  Each transfer
+ * can specify its own speed though, and the core code ensures each
+ * transfer's speed is set to something nonzero and supported by both
+ * the controller and the device.  We just set the speed for each transfer.
+ */
+static int k1_spi_setup(struct spi_device *spi)
+{
+	struct k1_spi_driver_data *drv_data;
+	u32 val;
+
+	drv_data = spi_controller_get_devdata(spi->controller);
+
+	/*
+	 * Configure the message format for this device.  We only
+	 * support Motorola SPI format in master mode.
+	 */
+	val = FIELD_PREP(TOP_FRF_MASK, TOP_FRF_MOTOROLA);
+
+	/* Translate the mode into the value used to program the hardware. */
+	if (spi->mode & SPI_CPHA)
+		val |= TOP_SPH;		/* 1/2 cycle */
+	if (spi->mode & SPI_CPOL)
+		val |= TOP_SPO;		/* active low */
+	if (spi->mode & SPI_LOOP)
+		val |= TOP_LBM;		/* enable loopback */
+	writel(val, drv_data->base + SSP_TOP_CTRL);
+
+	return 0;
+}
+
+static void k1_spi_cleanup(struct spi_device *spi)
+{
+	struct k1_spi_driver_data *drv_data;
+
+	drv_data = spi_controller_get_devdata(spi->controller);
+	k1_spi_register_reset(drv_data, false);
+}
+
+static bool k1_spi_can_dma(struct spi_controller *host, struct spi_device *spi,
+			   struct spi_transfer *transfer)
+{
+	struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host);
+	u32 burst_size;
+
+	if (!drv_data->dma_enabled)
+		return false;
+
+	if (transfer->len > SZ_2K)
+		return false;
+
+	/* Don't bother with DMA if we can't do even a single burst */
+	burst_size = K1_SPI_THRESH * spi_bpw_to_bytes(transfer->bits_per_word);
+
+	return transfer->len >= burst_size;
+}
+
+static void k1_spi_dma_callback(void *param)
+{
+	struct k1_spi_driver_data *drv_data = param;
+	u32 val;
+
+	val = readl(drv_data->base + SSP_FIFO_CTRL);
+	val &= ~(FIFO_TSRE | FIFO_RSRE);
+	writel(val, drv_data->base + SSP_FIFO_CTRL);
+
+	val = readl(drv_data->base + SSP_TOP_CTRL);
+	val &= ~TOP_TRAIL;
+	writel(val, drv_data->base + SSP_TOP_CTRL);
+
+	/* Check for any error conditions */
+	val = readl(drv_data->base + SSP_STATUS);
+	if (val & SSP_STATUS_ERROR)
+		drv_data->transfer->error |= SPI_TRANS_FAIL_IO;
+
+	/* Disable the port */
+	val = readl(drv_data->base + SSP_TOP_CTRL);
+	val &= ~TOP_SSE;
+	writel(val, drv_data->base + SSP_TOP_CTRL);
+
+	drv_data->transfer = NULL;
+
+	spi_finalize_current_transfer(drv_data->host);
+}
+
+/* Prepare a descriptor for TX or RX DMA */
+static struct dma_async_tx_descriptor *
+k1_spi_dma_prep(struct k1_spi_driver_data *drv_data,
+		struct spi_transfer *transfer, bool tx)
+{
+	phys_addr_t addr = drv_data->base_addr + SSP_DATAR;
+	u32 burst_size = K1_SPI_THRESH * drv_data->bytes;
+	struct dma_slave_config cfg = { };
+	enum dma_transfer_direction dir;
+	enum dma_slave_buswidth width;
+	struct dma_chan *chan;
+	struct sg_table *sgt;
+
+	width = drv_data->bytes == 1 ? DMA_SLAVE_BUSWIDTH_1_BYTE :
+		drv_data->bytes == 2 ? DMA_SLAVE_BUSWIDTH_2_BYTES :
+		/* bytes == 4 */       DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+	if (tx) {
+		chan = drv_data->host->dma_tx;
+		sgt = &transfer->tx_sg;
+		dir = DMA_MEM_TO_DEV;
+
+		cfg.dst_addr = addr;
+		cfg.dst_addr_width = width;
+		cfg.dst_maxburst = burst_size;
+	} else {
+		chan = drv_data->host->dma_rx;
+		sgt = &transfer->rx_sg;
+		dir = DMA_DEV_TO_MEM;
+
+		cfg.src_addr = addr;
+		cfg.src_addr_width = width;
+		cfg.src_maxburst = burst_size;
+	}
+	cfg.direction = dir;
+
+	if (dmaengine_slave_config(chan, &cfg))
+		return NULL;
+
+	return dmaengine_prep_slave_sg(chan, sgt->sgl, sgt->nents, dir,
+				       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+}
+
+static int k1_spi_dma_one(struct spi_controller *host, struct spi_device *spi,
+			  struct spi_transfer *transfer)
+{
+	struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host);
+	struct dma_async_tx_descriptor *desc;
+	u32 val;
+
+	/* Prepare the TX descriptor and submit it */
+	desc = k1_spi_dma_prep(drv_data, transfer, true);
+	if (!desc)
+		goto fallback;
+	dmaengine_submit(desc);
+
+	/* Prepare the RX descriptor and submit it */
+	desc = k1_spi_dma_prep(drv_data, transfer, false);
+	if (!desc)
+		goto fallback;
+
+	/* When RX is complete we also know TX has completed */
+	desc->callback = k1_spi_dma_callback;
+	desc->callback_param = drv_data;
+
+	dmaengine_submit(desc);
+
+	val = readl(drv_data->base + SSP_TOP_CTRL);
+	val |= TOP_TRAIL;		/* Trailing bytes handled by DMA */
+	writel(val, drv_data->base + SSP_TOP_CTRL);
+
+	val = readl(drv_data->base + SSP_FIFO_CTRL);
+	val |= FIFO_TSRE | FIFO_RSRE;
+	writel(val, drv_data->base + SSP_FIFO_CTRL);
+
+	/* Start RX first so we're ready the instant we start transmitting */
+	dma_async_issue_pending(host->dma_rx);
+	dma_async_issue_pending(host->dma_tx);
+
+	return 1;
+fallback:
+	transfer->error |= SPI_TRANS_FAIL_NO_START;
+
+	return -EAGAIN;
+}
+
+/* Flush the RX FIFO of any leftover data before processing a message */
+static int k1_spi_prepare_message(struct spi_controller *host,
+				  struct spi_message *message)
+{
+	struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host);
+	u32 val = readl(drv_data->base + SSP_STATUS);
+	u32 count;
+
+	/* If there's nothing in the FIFO, we're done */
+	if (!(val & SSP_STATUS_RNE))
+		return 0;
+
+	/* Read and discard what's there (one more than what the field says) */
+	count = FIELD_GET(SSP_STATUS_RFL, val) + 1;
+	do
+		(void)readl(drv_data->base + SSP_DATAR);
+	while (--count);
+
+	return 0;
+}
+
+/* Set logic level of chip select line (high=true means CS deasserted) */
+static void k1_spi_set_cs(struct spi_device *spi, bool high)
+{
+	struct k1_spi_driver_data *drv_data;
+	u32 val;
+
+	drv_data = spi_controller_get_devdata(spi->controller);
+
+	val = readl(drv_data->base + SSP_TOP_CTRL);
+	if (high)
+		val &= ~TOP_HOLD_FRAME_LOW;
+	else
+		val |= TOP_HOLD_FRAME_LOW;
+	writel(val, drv_data->base + SSP_TOP_CTRL);
+}
+
+/* Set the transfer speed; the SPI core code ensures it is supported */
+static int k1_spi_set_speed(struct k1_spi_driver_data *drv_data,
+			    struct spi_transfer *transfer)
+{
+	struct clk *clk = drv_data->clk;
+	u64 nsec_per_word;
+	u64 bus_ticks;
+	u32 timeout;
+	u32 val;
+	int ret;
+
+	ret = clk_set_rate(clk, transfer->speed_hz);
+	if (ret)
+		return ret;
+
+	drv_data->rate = clk_get_rate(clk);
+
+	/* No need for RX FIFO timeout if we're not receiving anything */
+	if (!transfer->rx_buf)
+		return 0;
+
+	/*
+	 * Compute the RX FIFO inactivity timeout value that should be used.
+	 * The inactivity timer restarts with each word that lands in the
+	 * FIFO.  If several "word transfer times" pass without any new data
+	 * in the RX FIFO, we might as well read what's there.
+	 *
+	 * The rate at which words land in the FIFO is determined by the
+	 * word size and the transfer rate.  One bit is transferred per
+	 * clock tick, and 8 (or 16 or 32) bits are transferred per word.
+	 *
+	 * So we can get word transfer time (in nanoseconds) from:
+	 *   nsec_per_tick = NSEC_PER_SEC / drv_data->rate;
+	 *   ticks_per_word = BITS_PER_BYTE * drv_data->bytes;
+	 * We do the divide last for better accuracy.
+	 */
+	nsec_per_word = NSEC_PER_SEC * BITS_PER_BYTE * drv_data->bytes;
+	nsec_per_word = DIV_ROUND_UP_ULL(nsec_per_word, drv_data->rate);
+
+	/*
+	 * The timeout (which we'll set to three word transfer times) is
+	 * expressed as a number of APB clock ticks.
+	 *   bus_ticks = 3 * nsec * (drv_data->bus_rate / NSEC_PER_SEC)
+	 */
+	bus_ticks = 3 * nsec_per_word * drv_data->bus_rate;
+	timeout = DIV_ROUND_UP_ULL(bus_ticks, NSEC_PER_SEC);
+
+	/* Set the RX timeout period (required for both DMA and PIO) */
+	val = FIELD_PREP(SSP_TIMEOUT_MASK, timeout);
+	writel(val, drv_data->base + SSP_TIMEOUT);
+
+	return 0;
+}
+
+static int k1_spi_transfer_one(struct spi_controller *host,
+			       struct spi_device *spi,
+			       struct spi_transfer *transfer)
+{
+	struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host);
+	u32 count;
+	u32 ctrl;
+	u32 val;
+	int ret;
+
+	/* Bits per word can change on a per-transfer basis */
+	drv_data->bytes = spi_bpw_to_bytes(transfer->bits_per_word);
+
+	/* Each transfer can also specify a different rate */
+	ret = k1_spi_set_speed(drv_data, transfer);
+	if (ret) {
+		dev_err(&host->dev,
+			"failed to set transfer speed: %d\n", ret);
+		return ret;
+	}
+
+	/* Record how many words the len bytes represent */
+	count = transfer->len / drv_data->bytes;
+	drv_data->rx_resid = count;
+	drv_data->tx_resid = count;
+
+	drv_data->transfer = transfer;
+
+	/* Clear any existing interrupt conditions */
+	writel(~0, drv_data->base + SSP_STATUS);
+
+	/* Set the data (word) size, and enable the port */
+	ctrl = readl(drv_data->base + SSP_TOP_CTRL);
+	ctrl &= ~TOP_DSS_MASK;
+	ctrl |= FIELD_PREP(TOP_DSS_MASK, transfer->bits_per_word - 1);
+	ctrl |= TOP_SSE;
+	writel(ctrl, drv_data->base + SSP_TOP_CTRL);
+
+	if (spi_xfer_is_dma_mapped(host, spi, transfer))
+		return k1_spi_dma_one(host, spi, transfer);
+
+	/* An interrupt will initiate the transfer */
+	val = SSP_INT_EN_TX | SSP_INT_EN_RX | SSP_INT_EN_ERROR;
+	writel(val, drv_data->base + SSP_INT_EN);
+
+	return 1;	/* We will call spi_finalize_current_transfer() */
+}
+
+static void
+k1_spi_handle_err(struct spi_controller *host, struct spi_message *message)
+{
+	struct k1_spi_driver_data *drv_data = spi_controller_get_devdata(host);
+
+	if (drv_data->dma_enabled) {
+		dmaengine_terminate_sync(host->dma_rx);
+		dmaengine_terminate_sync(host->dma_tx);
+	}
+}
+
+static void k1_spi_write_word(struct k1_spi_driver_data *drv_data)
+{
+	struct spi_transfer *transfer = drv_data->transfer;
+	u32 bytes = drv_data->bytes;
+	u32 val;
+
+	if (transfer->tx_buf) {
+		const void *buf;
+
+		buf = transfer->tx_buf + (transfer->len - drv_data->tx_resid);
+		if (bytes == 1)
+			val = *(u8 *)buf;
+		else if (bytes == 2)
+			val = *(u16 *)buf;
+		else	/* bytes == 4 */
+			val = *(u32 *)buf;
+	} else {
+		val = 0;	/* Null writer; write 1, 2, or 4 zero bytes */
+	}
+	/* Fill the next TX FIFO entry */
+	writel(val, drv_data->base + SSP_DATAR);
+
+	drv_data->tx_resid -= bytes;
+}
+
+/* The last-read status value is provided; we know SSP_STATUS_TNF is set */
+static bool k1_spi_write(struct k1_spi_driver_data *drv_data, u32 val)
+{
+	unsigned int count;
+
+	/* Get the number of open slots in the FIFO; zero means all */
+	count = FIELD_GET(SSP_STATUS_TFL, val) ? : K1_SPI_FIFO_SIZE;
+
+	/*
+	 * Limit how much we try to send at a time, to reduce the
+	 * chance the other side can overrun our RX FIFO.
+	 */
+	count = min3(count, K1_SPI_THRESH, drv_data->tx_resid);
+	do
+		k1_spi_write_word(drv_data);
+	while (--count);
+
+	return !drv_data->tx_resid;
+}
+
+static void k1_spi_read_word(struct k1_spi_driver_data *drv_data)
+{
+	struct spi_transfer *transfer = drv_data->transfer;
+	u32 bytes = drv_data->bytes;
+	u32 val;
+
+	/* Consume the next RX FIFO entry */
+	val = readl(drv_data->base + SSP_DATAR);
+	if (transfer->rx_buf) {
+		void *buf;
+
+		buf = transfer->rx_buf + (transfer->len - drv_data->rx_resid);
+
+		if (bytes == 1)
+			*(u8 *)buf = val;
+		else if (bytes == 2)
+			*(u16 *)buf = val;
+		else	/* bytes == 4 */
+			*(u32 *)buf = val;
+	}	/* Otherwise null reader: discard the data */
+
+	drv_data->rx_resid -= bytes;
+}
+
+/* The last-read status value is provided; we know SSP_STATUS_RNE is set */
+static bool k1_spi_read(struct k1_spi_driver_data *drv_data, u32 val)
+{
+	do {
+		unsigned int count = FIELD_GET(SSP_STATUS_RFL, val) + 1;
+
+		/* Only read what we need */
+		count = min(count, drv_data->rx_resid);
+		do
+			k1_spi_read_word(drv_data);
+		while (--count);
+
+		/* If there's no more to read, we're done */
+		if (!drv_data->rx_resid)
+			return true;
+
+		/* Check again in case more became available to read */
+		val = readl(drv_data->base + SSP_STATUS);
+		if (val & SSP_STATUS_RNE)
+			writel(SSP_STATUS_RNE, drv_data->base + SSP_STATUS);
+		else
+			return false;
+	} while (true);
+}
+
+static irqreturn_t k1_spi_ssp_isr(int irq, void *dev_id)
+{
+	struct k1_spi_driver_data *drv_data = dev_id;
+	u32 val;
+
+	/* Return immediately if we're not expecting any interrupts */
+	if (!drv_data->transfer)
+		return IRQ_NONE;
+
+	/* Get status and clear pending interrupts; all are handled below */
+	val = readl(drv_data->base + SSP_STATUS);
+	writel(val, drv_data->base + SSP_STATUS);
+
+	/* Check for any error conditions first */
+	if (val & SSP_STATUS_ERROR) {
+		drv_data->transfer->error |= SPI_TRANS_FAIL_IO;
+		goto done;
+	}
+
+	/*
+	 * For SPI, bytes are transferred in both directions equally, and
+	 * RX always follows TX.  Start by writing if there is anything to
+	 * write, then read.  Once there's no more to read, we're done.
+	 */
+	if (drv_data->tx_resid && (val & SSP_STATUS_TNF)) {
+		/* If we finish writing, disable TX interrupts */
+		if (k1_spi_write(drv_data, val)) {
+			val = SSP_INT_EN_RX | SSP_INT_EN_ERROR;
+			writel(val, drv_data->base + SSP_INT_EN);
+		}
+	}
+
+	/* We're not done unless we've read all that was requested */
+	if (drv_data->rx_resid) {
+		/* Read more if there FIFO is not empty */
+		if (val & SSP_STATUS_RNE)
+			if (k1_spi_read(drv_data, val))
+				goto done;
+
+		return IRQ_HANDLED;
+	}
+done:
+	/* Disable the port */
+	val = readl(drv_data->base + SSP_TOP_CTRL);
+	val &= ~TOP_SSE;
+	writel(val, drv_data->base + SSP_TOP_CTRL);
+
+	/* Disable all interrupts */
+	writel(0, drv_data->base + SSP_INT_EN);
+
+	drv_data->transfer = NULL;
+
+	spi_finalize_current_transfer(drv_data->host);
+
+	return IRQ_HANDLED;
+}
+
+static int
+k1_spi_dma_setup(struct k1_spi_driver_data *drv_data, struct device *dev)
+{
+	struct spi_controller *host = drv_data->host;
+	struct dma_chan *chan;
+
+	chan = dma_request_chan(dev, "tx");
+	if (IS_ERR(chan))
+		return PTR_ERR(chan);
+	host->dma_tx = chan;
+
+	chan = dma_request_chan(dev, "rx");
+	if (IS_ERR(chan)) {
+		dma_release_channel(host->dma_tx);
+		host->dma_tx = NULL;
+		return PTR_ERR(chan);
+	}
+	host->dma_rx = chan;
+
+	drv_data->dma_enabled = true;
+
+	return 0;
+}
+
+static void k1_spi_dma_cleanup(struct device *dev, void *res)
+{
+	struct k1_spi_driver_data **ptr = res;
+	struct k1_spi_driver_data *drv_data = *ptr;
+	struct spi_controller *host = drv_data->host;
+
+	if (!drv_data->dma_enabled)
+		return;
+
+	drv_data->dma_enabled = false;
+
+	dma_release_channel(host->dma_rx);
+	host->dma_rx = NULL;
+	dma_release_channel(host->dma_tx);
+	host->dma_tx = NULL;
+}
+
+static int
+devm_k1_spi_dma_setup(struct k1_spi_driver_data *drv_data, struct device *dev)
+{
+	struct k1_spi_driver_data **ptr;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_MMP_PDMA)) {
+		dev_info(dev, "DMA not available; using PIO\n");
+		return 0;
+	}
+
+	ptr = devres_alloc(k1_spi_dma_cleanup, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return -ENOMEM;
+
+	ret = k1_spi_dma_setup(drv_data, dev);
+	if (ret) {
+		devres_free(ptr);
+		return ret;
+	}
+
+	*ptr = drv_data;
+	devres_add(dev, ptr);
+
+	return 0;
+}
+
+static int k1_spi_probe(struct platform_device *pdev)
+{
+	struct k1_spi_driver_data *drv_data;
+	struct device *dev = &pdev->dev;
+	struct reset_control *reset;
+	struct spi_controller *host;
+	struct resource *iores;
+	struct clk *clk_bus;
+	int ret;
+
+	host = devm_spi_alloc_host(dev, sizeof(*drv_data));
+	if (!host)
+		return -ENOMEM;
+	drv_data = spi_controller_get_devdata(host);
+	drv_data->host = host;
+	platform_set_drvdata(pdev, drv_data);
+
+	ret = devm_k1_spi_dma_setup(drv_data, dev);
+	if (ret == -EPROBE_DEFER)
+		return ret;
+	if (ret)
+		dev_warn(dev, "DMA setup failed (%d), falling back to PIO\n", ret);
+
+	drv_data->base = devm_platform_get_and_ioremap_resource(pdev, 0,
+								&iores);
+	if (IS_ERR(drv_data->base))
+		return dev_err_probe(dev, PTR_ERR(drv_data->base),
+				     "error mapping memory\n");
+	drv_data->base_addr = iores->start;
+
+	clk_bus = devm_clk_get_enabled(dev, "bus");
+	if (IS_ERR(clk_bus))
+		return dev_err_probe(dev, PTR_ERR(clk_bus),
+				     "error getting/enabling bus clock\n");
+	drv_data->bus_rate = clk_get_rate(clk_bus);
+
+	drv_data->clk = devm_clk_get_enabled(dev, "core");
+	if (IS_ERR(drv_data->clk))
+		return dev_err_probe(dev, PTR_ERR(drv_data->clk),
+				     "error getting/enabling core clock\n");
+
+	reset = devm_reset_control_get_exclusive_deasserted(dev, NULL);
+	if (IS_ERR(reset))
+		return dev_err_probe(dev, PTR_ERR(reset),
+				     "error getting/deasserting reset\n");
+
+	k1_spi_register_reset(drv_data, true);
+
+	drv_data->irq = platform_get_irq(pdev, 0);
+	if (drv_data->irq < 0)
+		return dev_err_probe(dev, drv_data->irq, "error getting IRQ\n");
+
+	ret = devm_request_irq(dev, drv_data->irq, k1_spi_ssp_isr,
+			       IRQF_SHARED, dev_name(dev), drv_data);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "error requesting IRQ\n");
+
+	/* Initialize the host structure, then register it */
+	host->dev.of_node = dev_of_node(dev);
+	host->dev.parent = dev;
+	host->num_chipselect = 1;
+	if (drv_data->dma_enabled)
+		host->dma_alignment = K1_SPI_DMA_ALIGNMENT;
+	host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
+	host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+	host->min_speed_hz = K1_SPI_MIN_SPEED_HZ;
+	host->max_speed_hz = K1_SPI_MAX_SPEED_HZ;
+	host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
+	host->max_dma_len = K1_SPI_MAX_DMA_LEN;
+
+	host->setup = k1_spi_setup;
+	host->cleanup = k1_spi_cleanup;
+	host->can_dma = k1_spi_can_dma;
+	host->prepare_message = k1_spi_prepare_message;
+	host->set_cs = k1_spi_set_cs;
+	host->transfer_one = k1_spi_transfer_one;
+	host->handle_err = k1_spi_handle_err;
+
+	ret = devm_spi_register_controller(dev, host);
+	if (ret)
+		dev_err(dev, "error registering controller\n");
+
+	return ret;
+}
+
+static const struct of_device_id k1_spi_dt_ids[] = {
+	{ .compatible = "spacemit,k1-spi", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, k1_spi_dt_ids);
+
+static struct platform_driver k1_spi_driver = {
+	.probe = k1_spi_probe,
+	.driver = {
+		.name		= "k1-spi",
+		.of_match_table	= k1_spi_dt_ids,
+	},
+};
+module_platform_driver(k1_spi_driver);
+
+MODULE_DESCRIPTION("SpacemiT K1 SPI controller driver");
+MODULE_LICENSE("GPL");

-- 
2.43.0


^ permalink raw reply related

* [PATCH v8 1/3] dt-bindings: spi: add SpacemiT K1 SPI support
From: Guodong Xu @ 2026-04-11  3:04 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, Alex Elder, Philipp Zabel, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-spi, devicetree, linux-riscv, spacemit, linux-kernel,
	Guodong Xu, Alex Elder, Conor Dooley, Troy Mitchell
In-Reply-To: <20260410-spi-spacemit-k1-v8-0-53ebb48a4146@riscstar.com>

From: Alex Elder <elder@riscstar.com>

Add support for the SPI controller implemented by the SpacemiT K1 SoC.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Acked-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Guodong Xu <guodong@riscstar.com>
---
 .../devicetree/bindings/spi/spacemit,k1-spi.yaml   | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml b/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml
new file mode 100644
index 0000000000000..e82c7f8d0b981
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spacemit,k1-spi.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spacemit,k1-spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SpacemiT K1 SoC Serial Peripheral Interface (SPI)
+
+maintainers:
+  - Alex Elder <elder@kernel.org>
+
+description:
+  The SpacemiT K1 SoC implements a SPI controller that has two 32-entry
+  FIFOs, for transmit and receive.  Details are currently available in
+  section 18.2.1 of the K1 User Manual, found in the SpacemiT Keystone
+  K1 Documentation[1].  The controller transfers words using PIO.  DMA
+  transfers are supported as well, if both TX and RX DMA channels are
+  specified,
+
+  [1] https://developer.spacemit.com/documentation
+
+allOf:
+  - $ref: /schemas/spi/spi-controller.yaml#
+
+properties:
+  compatible:
+    const: spacemit,k1-spi
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Core clock
+      - description: Bus clock
+
+  clock-names:
+    items:
+      - const: core
+      - const: bus
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  dmas:
+    items:
+      - description: RX DMA channel
+      - description: TX DMA channel
+
+  dma-names:
+    items:
+      - const: rx
+      - const: tx
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - interrupts
+
+unevaluatedProperties: false
+
+examples:
+  - |
+
+    #include <dt-bindings/clock/spacemit,k1-syscon.h>
+    spi@d401c000 {
+        compatible = "spacemit,k1-spi";
+        reg = <0xd401c000 0x30>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        clocks = <&syscon_apbc CLK_SSP3>,
+                 <&syscon_apbc CLK_SSP3_BUS>;
+        clock-names = "core", "bus";
+        resets = <&syscon_apbc RESET_SSP3>;
+        interrupts = <55>;
+        dmas = <&pdma 20>, <&pdma 19>;
+        dma-names = "rx", "tx";
+    };

-- 
2.43.0


^ permalink raw reply related

* [PATCH v8 0/3] spi: support the SpacemiT K1 SPI controller
From: Guodong Xu @ 2026-04-11  3:04 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Yixun Lan, Alex Elder, Philipp Zabel, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-spi, devicetree, linux-riscv, spacemit, linux-kernel,
	Guodong Xu, Alex Elder, Conor Dooley, Troy Mitchell, Yixun Lan

This series adds support for the SPI controller found in the SpacemiT
K1 SoC.  The driver currently supports only master mode.  The controller
has two 32-entry FIFOs and supports PIO and DMA for transfers.

Starting with v8, I am taking over from Alex Elder to shepherd this
series upstream.  Alex developed versions 1 through 7.

Version 8 reworks the driver based on Mark Brown's review of v7, making
much better use of the SPI core framework.

(Note, this is a distinct series from the QSPI driver, which was
merged recently.)

 -
 Guodong

Between version 7 and version 8:
  - Use // comments for the file header (Mark Brown)
  - Remove open-coded DMA mapping (k1_spi_map_dma_buffer(),
    k1_spi_unmap_dma_buffer(), k1_spi_map_dma_buffers(), the dummy
    buffer, k1_spi_io struct); use SPI core DMA mapping via
    transfer->tx_sg/rx_sg instead
  - Add can_dma() callback, replacing open-coded transfer length
    checks
  - Add set_cs() callback for chip select control via the
    TOP_HOLD_FRAME_LOW bit
  - Switch from transfer_one_message() to transfer_one()
  - DMA completion calls spi_finalize_current_transfer() directly
    instead of using a completion
  - Add SSP_STATUS_BCE (bit count error) to error detection
  - Return IRQ_NONE early if no transfer is active, before
    acknowledging interrupts
  - Simplify k1_spi_driver_data struct
  - ~160 fewer lines of code

Here is version 7 of this series:
  https://lore.kernel.org/lkml/20251114185745.2838358-1-elder@riscstar.com/

Between version 6 and version 7:
  - DIV_ROUND_UP_ULL() is now used when setting the speed, to address
    two errors reported by the Intel kernel test robot on 32-bit builds
  - Fixed a bug interpreting the resource pointer in k1_spi_dma_cleanup()
  - The driver is now built as a module by default, if ARCH_SPACEMIT
    is defined

Here is version 6 of this series:
  https://lore.kernel.org/lkml/20251027125504.297033-1-elder@riscstar.com/

Between version 5 and version 6:
  - Rebase only

Here is version 5 of this series:
  https://lore.kernel.org/lkml/20251013123309.2252042-1-elder@riscstar.com/

Between version 4 and version 5:
  - Added Yixun's Reviewed-by tag on patch 3

Here is version 4 of this series:
  https://lore.kernel.org/lkml/20250925121714.2514932-1-elder@riscstar.com/

Between version 3 and version 4 (all suggested by Yixun):
  - Fixed an underrun/overrun comment error
  - Renamed a pinctrl node
  - Formatted dmas and dma-names properties on one line

Here is version 3 of this series:
  https://lore.kernel.org/lkml/20250922161717.1590690-1-elder@riscstar.com/

Between version 2 and version 3:
  - Add Conor's Acked-by to patch 1
  - Add Rob's Reviewed-by to patch 1
  - Added imply_PDMA to the SPI_SPACEMIT_K1 Kconfig option
  - Fixed a bug pointed out by Vivian (and Troy) in word-sized reads
  - Added a comment stating we use 1, 2, or 4 bytes per word
  - Cleaned up DMA channels properly in case of failure setting up
  - No longer use devm_*() for allocating DMA channels or buffer
  - Moved the SPI controller into the dma-bus memory region

Here is version 2 of this series:
  https://lore.kernel.org/lkml/20250919155914.935608-1-elder@riscstar.com/

Between version 1 and version 2:
  - Use enum rather than const for the binding compatible string
  - Omit the label and status property in the binding example
  - The spi-spacemit-k1.o make target is now added in sorted order
  - The SPI_SPACEMIT_K1 config option is added in sorted order
  - The SPI_SPACEMIT_K1 config does *not* depend on MMP_PDMA,
    however MMP_PDMA is checked at runtime, and if not enabled,
    DMA will not be used
  - Read/modify/writes of registers no longer use an additional
    "virt" variable to hold the address accessed
  - The k1_spi_driver_data->ioaddr field has been renamed base
  - The DMA address for the base address is maintained, rather than
    saving the DMA address of the data register
  - The spi-max-frequency property value is now bounds checked
  - A local variable is now initialized to 0 in k1_spi_write_word()
  - The driver name is now "k1-spi"
  - DT aliases are used rather than spacemit,k1-ssp-id for bus number
  - The order of two pin control properties was changed as requested
  - Clock names and DMA names are now on one line in the "k1.dtsi"
  - The interrupts property is used rather than interrupts-extended

Here is version 1 of this series:
  https://lore.kernel.org/lkml/20250917220724.288127-1-elder@riscstar.com/

Alex Elder (3):
  dt-bindings: spi: add SpacemiT K1 SPI support
  spi: spacemit: introduce SpacemiT K1 SPI controller driver
  riscv: dts: spacemit: define a SPI controller node

Signed-off-by: Guodong Xu <guodong@riscstar.com>
---
Alex Elder (3):
      dt-bindings: spi: add SpacemiT K1 SPI support
      spi: spacemit: introduce SpacemiT K1 SPI controller driver
      riscv: dts: spacemit: define a SPI controller node

 .../devicetree/bindings/spi/spacemit,k1-spi.yaml   |  84 +++
 arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts    |   7 +
 arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi       |  20 +
 arch/riscv/boot/dts/spacemit/k1.dtsi               |  15 +
 drivers/spi/Kconfig                                |   9 +
 drivers/spi/Makefile                               |   1 +
 drivers/spi/spi-spacemit-k1.c                      | 782 +++++++++++++++++++++
 7 files changed, 918 insertions(+)
---
base-commit: 7aaa8047eafd0bd628065b15757d9b48c5f9c07d
change-id: 20260407-spi-spacemit-k1-e0957c311152

Best regards,
--  
Guodong Xu <guodong@riscstar.com>


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox