Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v3 8/8] iio: temperature: ltc2983: Add support for ADT7604
From: Jonathan Cameron @ 2026-05-22 17:31 UTC (permalink / raw)
  To: Stan, Liviu
  Cc: David Lechner, Sa, Nuno, Andy Shevchenko, Hennerich, Michael,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Miclaus, Antoniu,
	Francesco Lavra, linux-iio@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux, devicetree@vger.kernel.org
In-Reply-To: <LV9PR03MB8366C36D83A00FFCC166E333F60F2@LV9PR03MB8366.namprd03.prod.outlook.com>

On Fri, 22 May 2026 14:24:27 +0000
"Stan, Liviu" <Liviu.Stan@analog.com> wrote:

> On Fri, 22 May 2026 14:34:44 +0100 Jonathan Cameron <jic23@kernel.org> wrote:
> 
> > On Thu, 21 May 2026 19:43:01 +0300
> > Liviu Stan <liviu.stan@analog.com> wrote:
> >   
> ...
> > 
> > The sashiko comment about the completion race looks real to me.
> > Can you take a look at that. Might be some odd reason why we can't
> > reinit_completion() before triggering the capture but that would
> > be very unusual.
> >   
> 
> I don't see any reason why we couldn't put it before the regmap_write,
> it has also already been done in ltc2983_eeprom_cmd(). So, I will change
> it in v4.
> 
> > Otherwise just two really small things I missed in earlier reviews.
> > If everything else was ready to go I'd have tweaked these whilst
> > applying but seems you'll be doing a v4 so over to you!  
> 
> Understood, will change them in v4!:) Thanks!
> 
> On Fri, 22 May 2026 09:09:33 -0500 David Lechner <dlechner@baylibre.com> wrote:
> 
> > On 5/22/26 8:23 AM, Liviu Stan wrote:  
> > > On Thu, 21 May 2026 19:18:28 +0000 sashiko-bot@kernel.org wrote:
> > >   
> > >> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:  
> ...
> > >> [Severity: High]
> > >> This is a pre-existing issue, but can this function experience spurious
> > >> read timeouts due to a race condition with the completion?
> > >>
> > >> Looking at the rest of this function:
> > >>
> > >>     ret = regmap_write(st->regmap, LTC2983_STATUS_REG, start_conversion);
> > >>     if (ret)
> > >>         return ret;
> > >>
> > >>     reinit_completion(&st->completion);
> > >>
> > >> If the hardware conversion finishes very quickly after regmap_write(),
> > >> could the interrupt fire and call complete() before the CPU executes
> > >> reinit_completion()? This would overwrite the completion event, causing the
> > >> subsequent wait_for_completion_timeout() to spuriously time out.
> > >>
> > >> Would it be safer to call reinit_completion() before initiating the hardware
> > >> action?  
> > > 
> > > This is theoretically valid but in practice, the conversion requires at minimum
> > > two 82ms cycles (167ms), so there is no realistic window for the interrupt to
> > > race with reinit_completion(). What do you guys think?  
> > 
> > I would still move it before the write so that it looks correct
> > and others can copy/paste the logic on other devices.  
> 
> That makes sense. Thanks!
> 
> Would this be considered a fix?
Yes, though not an urgent one given no particular reports of it being hit.
Just put it at the start of the series and I'll apply it with the rest.
Can get backported after next merge window.

Thanks,

Jonathan
> 
> Liviu


^ permalink raw reply

* [PATCH V2 3/3] phy: qcom-qmp-ufs: Add UFS PHY support on Hawi
From: palash.kambar @ 2026-05-22 17:27 UTC (permalink / raw)
  To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
	bvanassche, andersson, dmitry.baryshkov, abel.vesa, luca.weiss
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
	Palash Kambar
In-Reply-To: <20260522172716.820490-1-palash.kambar@oss.qualcomm.com>

From: Palash Kambar <palash.kambar@oss.qualcomm.com>

Add the init sequence tables and config for the UFS QMP phy found in
the Hawi SoC.

Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
 .../phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h    |  24 +++
 .../phy-qcom-qmp-qserdes-txrx-ufs-v8.h        |  37 +++++
 drivers/phy/qualcomm/phy-qcom-qmp-ufs.c       | 140 ++++++++++++++++++
 3 files changed, 201 insertions(+)
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
new file mode 100644
index 000000000000..e80d3dd6a190
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_PCS_UFS_V7_H_
+#define QCOM_PHY_QMP_PCS_UFS_V7_H_
+
+/* Only for QMP V7 PHY - UFS PCS registers */
+#define QPHY_V7_PCS_UFS_PHY_START			0x000
+#define QPHY_V7_PCS_UFS_POWER_DOWN_CONTROL		0x004
+#define QPHY_V7_PCS_UFS_SW_RESET			0x008
+#define QPHY_V7_PCS_UFS_PCS_CTRL1			0x01C
+#define QPHY_V7_PCS_UFS_PLL_CNTL			0x028
+#define QPHY_V7_PCS_UFS_TX_LARGE_AMP_DRV_LVL		0x02C
+#define QPHY_V7_PCS_UFS_TX_HSGEAR_CAPABILITY		0x060
+#define QPHY_V7_PCS_UFS_RX_HSGEAR_CAPABILITY		0x094
+#define QPHY_V7_PCS_UFS_LINECFG_DISABLE			0x140
+#define QPHY_V7_PCS_UFS_RX_SIGDET_CTRL2			0x150
+#define QPHY_V7_PCS_UFS_READY_STATUS			0x16c
+#define QPHY_V7_PCS_UFS_TX_MID_TERM_CTRL1		0x1b8
+#define QPHY_V7_PCS_UFS_MULTI_LANE_CTRL1		0x1c0
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
new file mode 100644
index 000000000000..5f923c3e64ec
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_UFS_V8_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_UFS_V8_H_
+
+#define QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_TX		(0x34)
+#define QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_RX		(0x38)
+#define QSERDES_UFS_V8_TX_LANE_MODE_1				(0x80)
+#define QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE2			(0x1BC)
+#define QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE4			(0x1C4)
+#define QSERDES_UFS_V8_RX_UCDR_SO_GAIN_RATE4			(0x1DC)
+#define QSERDES_UFS_V8_RX_EQ_OFFSET_ADAPTOR_CNTRL1		(0x2C8)
+#define QSERDES_UFS_V8_RX_UCDR_PI_CONTROLS			(0x1E4)
+#define QSERDES_UFS_V8_RX_OFFSET_ADAPTOR_CNTRL3			(0x2D0)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4	(0x120)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_FO_GAIN_RATE4		(0xD4)
+#define QSERDES_UFS_V8_RX_UCDR_FASTLOCK_SO_GAIN_RATE4		(0xEC)
+#define QSERDES_UFS_V8_RX_VGA_CAL_MAN_VAL			(0x288)
+#define QSERDES_UFS_V8_RX_EQU_ADAPTOR_CNTRL4			(0x2B0)
+#define QSERDES_UFS_V8_RX_MODE_RATE_0_1_B4			(0x324)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SA_B7			(0x3B4)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SA_B9			(0x3BC)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SB_B7			(0x3E0)
+#define QSERDES_UFS_V8_RX_MODE_RATE4_SB_B9			(0x3E8)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SA_B7			(0x40C)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SA_B9			(0x414)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SB_B7			(0x438)
+#define QSERDES_UFS_V8_RX_MODE_RATE5_SB_B9			(0x440)
+#define QSERDES_UFS_V8_RX_UCDR_SO_SATURATION			(0xF4)
+#define QSERDES_UFS_V8_RX_TERM_BW_CTRL0				(0x1AC)
+#define QSERDES_UFS_V8_RX_DLL0_FTUNE_CTRL			(0x498)
+#define QSERDES_UFS_V8_RX_SIGDET_CAL_TRIM			(0x4d0)
+
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 771bc7c2ab50..538f1b947c87 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -29,9 +29,11 @@
 #include "phy-qcom-qmp-pcs-ufs-v4.h"
 #include "phy-qcom-qmp-pcs-ufs-v5.h"
 #include "phy-qcom-qmp-pcs-ufs-v6.h"
+#include "phy-qcom-qmp-pcs-ufs-v7.h"
 
 #include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h"
 #include "phy-qcom-qmp-qserdes-txrx-ufs-v7.h"
+#include "phy-qcom-qmp-qserdes-txrx-ufs-v8.h"
 
 /* QPHY_PCS_READY_STATUS bit */
 #define PCS_READY				BIT(0)
@@ -84,6 +86,13 @@ static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = {
 	[QPHY_PCS_POWER_DOWN_CONTROL]	= QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL,
 };
 
+static const unsigned int ufsphy_v7_regs_layout[QPHY_LAYOUT_SIZE] = {
+	[QPHY_START_CTRL]		= QPHY_V7_PCS_UFS_PHY_START,
+	[QPHY_PCS_READY_STATUS]		= QPHY_V7_PCS_UFS_READY_STATUS,
+	[QPHY_SW_RESET]			= QPHY_V7_PCS_UFS_SW_RESET,
+	[QPHY_PCS_POWER_DOWN_CONTROL]	= QPHY_V7_PCS_UFS_POWER_DOWN_CONTROL,
+};
+
 static const struct qmp_phy_init_tbl milos_ufsphy_serdes[] = {
 	QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
 	QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
@@ -1306,6 +1315,12 @@ static const struct regulator_bulk_data sm8750_ufsphy_vreg_l[] = {
 	{ .supply = "vdda-pll", .init_load_uA = 18300 },
 };
 
+static const struct regulator_bulk_data hawi_ufsphy_vreg_l[] = {
+	{ .supply = "vdda-phy", .init_load_uA = 324000 },
+	{ .supply = "vdda-pll", .init_load_uA = 27000 },
+
+};
+
 static const struct qmp_ufs_offsets qmp_ufs_offsets = {
 	.serdes		= 0,
 	.pcs		= 0xc00,
@@ -1324,6 +1339,15 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = {
 	.rx2		= 0x1a00,
 };
 
+static const struct qmp_ufs_offsets qmp_ufs_offsets_v7 = {
+	.serdes		= 0,
+	.pcs		= 0x0400,
+	.tx		= 0x2000,
+	.rx		= 0x2000,
+	.tx2		= 0x3000,
+	.rx2		= 0x3000,
+};
+
 static const struct qmp_phy_cfg milos_ufsphy_cfg = {
 	.lanes			= 2,
 
@@ -1844,6 +1868,119 @@ static const struct qmp_phy_cfg sm8750_ufsphy_cfg = {
 
 };
 
+static const struct qmp_phy_init_tbl hawi_ufsphy_serdes[] = {
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_SYSCLK_EN_SEL, 0xd9),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_CONFIG_1, 0x16),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_HSCLK_SEL_1, 0x11),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP_EN, 0x01),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP_CFG, 0x60),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_IVCO, 0x1f),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_IVCO_MODE1, 0x1f),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_IETRIM, 0x07),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_CMN_IPTRIM, 0x20),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE_MAP, 0x04),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_VCO_TUNE_CTRL, 0x40),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_ADAPTIVE_ANALOG_CONFIG, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE0, 0x41),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE0, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE0, 0x18),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE0, 0x14),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_ADAPTIVE_MODE0, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCCTRL_ADAPTIVE_MODE0, 0x18),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_ADAPTIVE_MODE0, 0x14),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE0, 0x7f),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE0, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x92),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_DEC_START_MODE1, 0x4c),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_MODE1, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCTRL_MODE1, 0x18),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_MODE1, 0x14),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_CP_CTRL_ADAPTIVE_MODE1, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_RCCTRL_ADAPTIVE_MODE1, 0x18),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_PLL_CCTRL_ADAPTIVE_MODE1, 0x14),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP1_MODE1, 0x99),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_LOCK_CMP2_MODE1, 0x07),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xbe),
+	QMP_PHY_INIT_CFG(QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_tx[] = {
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_LANE_MODE_1, 0x0c),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_TX_RES_CODE_LANE_OFFSET_RX, 0x17),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_rx[] = {
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FO_GAIN_RATE4, 0x0c),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_SO_GAIN_RATE4, 0x04),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_PI_CONTROLS, 0x07),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_VGA_CAL_MAN_VAL, 0x8e),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_EQU_ADAPTOR_CNTRL4, 0x0f),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE_0_1_B4, 0xb8),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SA_B7, 0x66),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SA_B9, 0x1f),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SB_B7, 0x66),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE4_SB_B9, 0x1f),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SA_B7, 0x66),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SA_B9, 0x1f),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SB_B7, 0x66),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_MODE_RATE5_SB_B9, 0x1f),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_UCDR_SO_SATURATION, 0x1f),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_TERM_BW_CTRL0, 0xfa),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_DLL0_FTUNE_CTRL, 0x30),
+	QMP_PHY_INIT_CFG(QSERDES_UFS_V8_RX_SIGDET_CAL_TRIM, 0x77),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_pcs[] = {
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_PCS_CTRL1, 0x42),
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+};
+
+static const struct qmp_phy_init_tbl hawi_ufsphy_g5_pcs[] = {
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_PLL_CNTL, 0x3b),
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x06),
+	QMP_PHY_INIT_CFG(QPHY_V7_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x06),
+};
+
+static const struct qmp_phy_cfg hawi_ufsphy_cfg = {
+	.lanes			= 2,
+
+	.offsets		= &qmp_ufs_offsets_v7,
+	.max_supported_gear	= UFS_HS_G5,
+
+	.tbls = {
+		.serdes		= hawi_ufsphy_serdes,
+		.serdes_num	= ARRAY_SIZE(hawi_ufsphy_serdes),
+		.tx		= hawi_ufsphy_tx,
+		.tx_num		= ARRAY_SIZE(hawi_ufsphy_tx),
+		.rx		= hawi_ufsphy_rx,
+		.rx_num		= ARRAY_SIZE(hawi_ufsphy_rx),
+		.pcs		= hawi_ufsphy_pcs,
+		.pcs_num	= ARRAY_SIZE(hawi_ufsphy_pcs),
+	},
+
+	.tbls_hs_overlay[0] = {
+		.pcs		= hawi_ufsphy_g5_pcs,
+		.pcs_num	= ARRAY_SIZE(hawi_ufsphy_g5_pcs),
+		.max_gear	= UFS_HS_G5,
+	},
+
+	.vreg_list		= hawi_ufsphy_vreg_l,
+	.num_vregs		= ARRAY_SIZE(hawi_ufsphy_vreg_l),
+	.regs			= ufsphy_v7_regs_layout,
+};
+
 static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
 {
 	void __iomem *serdes = qmp->serdes;
@@ -2258,6 +2395,9 @@ static int qmp_ufs_probe(struct platform_device *pdev)
 
 static const struct of_device_id qmp_ufs_of_match_table[] = {
 	{
+		.compatible = "qcom,hawi-qmp-ufs-phy",
+		.data = &hawi_ufsphy_cfg,
+	}, {
 		.compatible = "qcom,milos-qmp-ufs-phy",
 		.data = &milos_ufsphy_cfg,
 	}, {
-- 
2.34.1


^ permalink raw reply related

* [PATCH V2 2/3] scsi: ufs: qcom :dt-bindings: Document the Hawi UFS controller
From: palash.kambar @ 2026-05-22 17:27 UTC (permalink / raw)
  To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
	bvanassche, andersson, dmitry.baryshkov, abel.vesa, luca.weiss
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
	Palash Kambar
In-Reply-To: <20260522172716.820490-1-palash.kambar@oss.qualcomm.com>

From: Palash Kambar <palash.kambar@oss.qualcomm.com>

Document the UFS Controller on the Hawi Platform.

Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml
index f28641c6e68f..3de00affa4c6 100644
--- a/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml
+++ b/Documentation/devicetree/bindings/ufs/qcom,sm8650-ufshc.yaml
@@ -16,6 +16,7 @@ select:
       contains:
         enum:
           - qcom,eliza-ufshc
+          - qcom,hawi-ufshc
           - qcom,kaanapali-ufshc
           - qcom,sm8650-ufshc
           - qcom,sm8750-ufshc
@@ -27,6 +28,7 @@ properties:
     items:
       - enum:
           - qcom,eliza-ufshc
+          - qcom,hawi-ufshc
           - qcom,kaanapali-ufshc
           - qcom,sm8650-ufshc
           - qcom,sm8750-ufshc
-- 
2.34.1


^ permalink raw reply related

* [PATCH V2 1/3] dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Add Hawi UFS PHY compatible
From: palash.kambar @ 2026-05-22 17:27 UTC (permalink / raw)
  To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
	bvanassche, andersson, dmitry.baryshkov, abel.vesa, luca.weiss
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
	Palash Kambar
In-Reply-To: <20260522172716.820490-1-palash.kambar@oss.qualcomm.com>

From: Palash Kambar <palash.kambar@oss.qualcomm.com>

Document QMP UFS PHY compatible for Hawi SoC.

Signed-off-by: Palash Kambar <palash.kambar@oss.qualcomm.com>
---
 .../devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml      | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
index 9616c736b6d4..b75015f3ea70 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
@@ -37,6 +37,7 @@ properties:
               - qcom,kaanapali-qmp-ufs-phy
           - const: qcom,sm8750-qmp-ufs-phy
       - enum:
+          - qcom,hawi-qmp-ufs-phy
           - qcom,milos-qmp-ufs-phy
           - qcom,msm8996-qmp-ufs-phy
           - qcom,msm8998-qmp-ufs-phy
@@ -107,6 +108,7 @@ allOf:
         compatible:
           contains:
             enum:
+              - qcom,hawi-qmp-ufs-phy
               - qcom,milos-qmp-ufs-phy
               - qcom,msm8998-qmp-ufs-phy
               - qcom,sa8775p-qmp-ufs-phy
-- 
2.34.1


^ permalink raw reply related

* [PATCH V2 0/3] Add Hawi UFS PHY and Controller support
From: palash.kambar @ 2026-05-22 17:27 UTC (permalink / raw)
  To: vkoul, neil.armstrong, robh, krzk+dt, conor+dt, mani, alim.akhtar,
	bvanassche, andersson, dmitry.baryshkov, abel.vesa, luca.weiss
  Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, linux-scsi,
	Palash Kambar

From: Palash Kambar <palash.kambar@oss.qualcomm.com>

This series introduces devicetree binding documentation and PHY
initialization support required to enable UFS on this platform.

  1. Devicetree binding documentation for the QMP UFS PHY
     used on Qualcomm Hawi.
  2. Devicetree binding documentation for the UFS controller
     instance present on the Hawi platform.
  3. Initialization sequence tables and configuration required
     for the QMP UFS PHY on Hawi SoC.

---
changes from V1
1) Addressed Dmitry's comments to fix versioning for PCS and qserdes.
2) Addressed Mani's comments and fixed missed compatible string and
   binding name correction.

Palash Kambar (3):
  dt-bindings: phy: qcom,sc8280xp-qmp-ufs-phy: Add Hawi UFS PHY
    compatible
  scsi: ufs: qcom :dt-bindings: Document the Hawi UFS controller
  phy: qcom-qmp-ufs: Add UFS PHY support on Hawi

 .../phy/qcom,sc8280xp-qmp-ufs-phy.yaml        |   2 +
 .../bindings/ufs/qcom,sm8650-ufshc.yaml       |   2 +
 .../phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h    |  24 +++
 .../phy-qcom-qmp-qserdes-txrx-ufs-v8.h        |  37 +++++
 drivers/phy/qualcomm/phy-qcom-qmp-ufs.c       | 140 ++++++++++++++++++
 5 files changed, 205 insertions(+)
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v7.h
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v8.h

-- 
2.34.1


^ permalink raw reply

* Re: [PATCH v3 2/2] iio: dac: Add AD5529R DAC driver support
From: Jonathan Cameron @ 2026-05-22 17:24 UTC (permalink / raw)
  To: Janani Sunil
  Cc: Lars-Peter Clausen, Michael Hennerich, David Lechner,
	Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
	linux-iio, devicetree, linux-kernel, linux-doc, Janani Sunil
In-Reply-To: <20260519-ad5529r-driver-v3-2-267c0731aa68@analog.com>

On Tue, 19 May 2026 17:42:59 +0200
Janani Sunil <janani.sunil@analog.com> wrote:

> Add support for AD5529R 16-channel, 12/16 bit Digital to Analog Converter
> 
> Signed-off-by: Janani Sunil <janani.sunil@analog.com>
Hi Janani,

A few more things inline from a fresh read.

Have a good weekend

Jonathan


> diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
> index 003431798498..f35e060b3643 100644
> --- a/drivers/iio/dac/Makefile
> +++ b/drivers/iio/dac/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_AD5446) += ad5446.o
>  obj-$(CONFIG_AD5446_SPI) += ad5446-spi.o
>  obj-$(CONFIG_AD5446_I2C) += ad5446-i2c.o
>  obj-$(CONFIG_AD5449) += ad5449.o
> +obj-$(CONFIG_AD5529R) += ad5529r.o
>  obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
>  obj-$(CONFIG_AD5592R) += ad5592r.o
>  obj-$(CONFIG_AD5593R) += ad5593r.o
> diff --git a/drivers/iio/dac/ad5529r.c b/drivers/iio/dac/ad5529r.c
> new file mode 100644
> index 000000000000..9bb63030db95
> --- /dev/null
> +++ b/drivers/iio/dac/ad5529r.c
> @@ -0,0 +1,527 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * AD5529R Digital-to-Analog Converter Driver
> + * 16-Channel, 12/16-Bit, 40V High Voltage Precision DAC
> + *
> + * Copyright 2026 Analog Devices Inc.
> + * Author: Janani Sunil <janani.sunil@analog.com>
> + */
> +
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>

Generally don't include this in drivers unless you actually use
stuff in that header.  dev_printk.h etc are preferred.

> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/iio/iio.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/spi/spi.h>
> +
> +#define AD5529R_REG_INTERFACE_CONFIG_A		0x00
> +#define AD5529R_REG_DEVICE_CONFIG		0x02
> +#define AD5529R_REG_CHIP_GRADE			0x06
> +#define AD5529R_REG_SCRATCH_PAD			0x0A
> +#define AD5529R_REG_SPI_REVISION		0x0B
> +#define AD5529R_REG_VENDOR_H			0x0D
> +#define AD5529R_REG_STREAM_MODE			0x0E
> +#define AD5529R_REG_INTERFACE_STATUS_A		0x11
> +#define AD5529R_REG_MULTI_DAC_CH_SEL		0x14
> +#define AD5529R_REG_OUT_RANGE_BASE		0x3C
> +#define AD5529R_REG_OUT_RANGE(ch)		(AD5529R_REG_OUT_RANGE_BASE + (ch) * 2)
> +#define AD5529R_REG_DAC_INPUT_A_BASE		0x148
> +#define AD5529R_REG_DAC_INPUT_A(ch)		(AD5529R_REG_DAC_INPUT_A_BASE + (ch) * 2)
> +#define AD5529R_REG_DAC_DATA_READBACK_BASE	0x16A
> +#define AD5529R_REG_TSENS_ALERT_FLAG		0x18C
> +#define AD5529R_REG_TSENS_SHTD_FLAG		0x18E
> +#define AD5529R_REG_FUNC_BUSY			0x1A0
> +#define AD5529R_REG_REF_SEL			0x1A2
> +#define AD5529R_REG_INIT_CRC_ERR_STAT		0x1A4
> +#define AD5529R_REG_MULTI_DAC_HOTPATH_SW_LDAC	0x1A8
> +
> +#define   AD5529R_INTERFACE_CONFIG_A_SW_RESET	(BIT(7) | BIT(0))
> +#define   AD5529R_INTERFACE_CONFIG_A_ADDR_ASCENSION	BIT(5)
> +#define   AD5529R_INTERFACE_CONFIG_A_SDO_ENABLE	BIT(4)
> +#define   AD5529R_REF_SEL_MASK			BIT(0)
Often when it's a single bit we don't call it MASK, but instead express
what the value with the bit set means.

> +#define   AD5529R_MAX_REGISTER			0x232
> +#define   AD5529R_8BIT_REG_MAX			0x13
> +#define   AD5529R_SPI_READ_FLAG			0x80

> +static int ad5529r_reset(struct ad5529r_state *st)
> +{
> +	struct reset_control *rst;
> +	int ret;
> +
> +	rst = devm_reset_control_get_optional_exclusive(&st->spi->dev, NULL);
> +	if (IS_ERR(rst))
> +		return PTR_ERR(rst);
> +
> +	if (rst) {
> +		ret = reset_control_deassert(rst);
> +		if (ret)
> +			return ret;
> +	} else {
> +		ret = regmap_write(st->regmap_8bit, AD5529R_REG_INTERFACE_CONFIG_A,
> +				   AD5529R_INTERFACE_CONFIG_A_SW_RESET);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	fsleep(10000);

Comment on why this value - typically a datasheet reference.

> +
> +	return regmap_write(st->regmap_8bit, AD5529R_REG_INTERFACE_CONFIG_A,
> +			    AD5529R_INTERFACE_CONFIG_A_SDO_ENABLE |
> +			    AD5529R_INTERFACE_CONFIG_A_ADDR_ASCENSION);
> +}
> +
> +static int ad5529r_read_raw(struct iio_dev *indio_dev,
> +			    struct iio_chan_spec const *chan,
> +			    int *val, int *val2, long mask)
> +{
> +	struct ad5529r_state *st = iio_priv(indio_dev);
> +	unsigned int reg_addr, reg_val_h;
> +	int ret, range_idx, span_mv;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		reg_addr = AD5529R_REG_DAC_INPUT_A(chan->channel);

Sashiko made an interesting point here about whether the readback register
makes more sense here. I think not but maybe we should add a comment on
why.  My understanding is we are only dealing with the A value of the
toggle for now and this therefore always reflects the value set.

> +		ret = regmap_read(st->regmap_16bit, reg_addr, &reg_val_h);
> +		if (ret)
> +			return ret;
> +
> +		*val = reg_val_h;
> +
> +		return IIO_VAL_INT;


> +
> +static int ad5529r_find_output_range(const s32 *vals)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(ad5529r_output_ranges_mv); i++) {
	for (unsigned int i = 0; ...

> +		if (vals[0] == ad5529r_output_ranges_mv[i][0] * 1000 &&
> +		    vals[1] == ad5529r_output_ranges_mv[i][1] * 1000)
> +			return i;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int ad5529r_parse_channel_ranges(struct device *dev,
> +					struct ad5529r_state *st)
> +{
> +	int ret, ch, range_idx;
> +	s32 vals[2];
> +
> +	device_for_each_child_node_scoped(dev, child) {
> +		range_idx = AD5529R_RANGE_0V_5V;
> +
> +		ret = fwnode_property_read_u32(child, "reg", &ch);

Another sashiko one. Type is wrong. Need to pass in a u32 point. In practice
unlikely to be a problem but lets match what is expected.

> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Missing reg property in channel node\n");
> +
> +		if (ch >= 16)
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Invalid channel number: %d\n", ch);
> +
> +		if (!fwnode_property_read_u32_array(child,
> +						    "adi,output-range-microvolt",
> +						    vals, 2)) {

Here I think it is deliberately reading into signed storage.  Add a comment on that.
Might get the bot to leave it alone ;)  ARRAY_SIZE(vals) instead of 2.

> +			range_idx = ad5529r_find_output_range(vals);
> +			if (range_idx < 0)
> +				return dev_err_probe(dev, range_idx,
> +						     "Invalid range [%d %d] for ch %d\n",
> +						     vals[0], vals[1], ch);
> +		}
> +
> +		st->output_range_idx[ch] = range_idx;
> +		ret = regmap_write(st->regmap_16bit,
> +				   AD5529R_REG_OUT_RANGE(ch), range_idx);
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Failed to configure range for ch %d\n",
> +					     ch);
> +	}
> +
> +	return 0;
> +}
> +
> +static int ad5529r_debugfs_reg_read(struct ad5529r_state *st, unsigned int reg,
> +				    unsigned int *val)
> +{
> +	return regmap_read(ad5529r_get_regmap(st, reg), reg, val);
> +}
> +
> +static int ad5529r_debugfs_reg_write(struct ad5529r_state *st, unsigned int reg,
> +				     unsigned int val)
> +{
> +	return regmap_write(ad5529r_get_regmap(st, reg), reg, val);
> +}

These two helpers don't seem worth having over putting the calls inline.
Particularly as both are getting the regmap.

> +
> +static int ad5529r_reg_access(struct iio_dev *indio_dev,
> +			      unsigned int reg,
> +			      unsigned int writeval,
> +			      unsigned int *readval)
> +{
> +	struct ad5529r_state *st = iio_priv(indio_dev);
> +
> +	if (readval)
> +		return ad5529r_debugfs_reg_read(st, reg, readval);
> +
> +	return ad5529r_debugfs_reg_write(st, reg, writeval);
> +}

> +static int ad5529r_probe(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct iio_dev *indio_dev;
> +	struct ad5529r_state *st;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	st = iio_priv(indio_dev);
> +
> +	st->spi = spi;
> +
> +	st->model_data = spi_get_device_match_data(spi);
> +	if (!st->model_data)
> +		return dev_err_probe(dev, -EINVAL, "Failed to identify device variant\n");
> +
> +	ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad5529r_supply_names),
> +					     ad5529r_supply_names);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to get and enable regulators\n");
> +
> +	ret = devm_regulator_get_enable_optional(dev, "hvss");

Sashiko spotted this.   Try dropping hvss from your dt and see what return value you get.

> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to get and enable hvss regulator\n");
> +
> +	st->vref_regulator = devm_regulator_get_optional(dev, "vref");
> +	if (IS_ERR(st->vref_regulator)) {
> +		if (PTR_ERR(st->vref_regulator) != -ENODEV)
> +			return dev_err_probe(dev, PTR_ERR(st->vref_regulator),
> +					     "Failed to get vref regulator\n");
> +		st->vref_regulator = NULL;
> +	}
> +
> +	if (st->vref_regulator) {
> +		ret = regulator_enable(st->vref_regulator);
If you aren't going to use it except to enable, use
devm_regulator_get_optional_enabled() and a bool flag.

Sashiko had a comment about the oddity of not reading the voltage, but I think
that's fine as the datasheet seems pretty insistent it must be 4.096V to work
correctly. Bit odd as it also provides a range of values.  Ah well.
Perhaps add a comment somewhere to remind us of this assumption.

> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Failed to enable vref regulator\n");
> +
> +		ret = devm_add_action_or_reset(dev, ad5529r_disable_regulator,
> +					       st->vref_regulator);
> +		if (ret)
> +			return dev_err_probe(dev, ret,
> +					     "Failed to add vref regulator cleanup\n");
> +	}

> +
> +	ret = regmap_update_bits(st->regmap_16bit, AD5529R_REG_REF_SEL,
> +				 AD5529R_REF_SEL_MASK,
> +				 st->vref_regulator ? 0 : AD5529R_REF_SEL_MASK);

regmap_assign_bits() using a flag for vref presence as mentioned above

> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to configure reference\n");


> +static const struct spi_device_id ad5529r_id[] = {
> +	{ "ad5529r-16", .driver_data = (kernel_ulong_t)&ad5529r_16bit_model_data },
> +	{ "ad5529r-12", .driver_data = (kernel_ulong_t)&ad5529r_12bit_model_data },
.name =  

Might be long enough you need to do.
	{
		.name = ....
		.driver_data = (kernel_ulong_t)&...
 
> +	{ }
> +};



^ permalink raw reply

* Re: [PATCH v2 7/7] arm64: dts: renesas: r8a779md: Add support for R-Car M3Le R8A779MD Geist
From: Marek Vasut @ 2026-05-22 17:21 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: linux-arm-kernel, Nguyen Tran, Brian Masney, Conor Dooley,
	Geert Uytterhoeven, Krzysztof Kozlowski, Kuninori Morimoto,
	Magnus Damm, Michael Turquette, Rob Herring, Stephen Boyd,
	Ulf Hansson, Wolfram Sang, devicetree, linux-clk, linux-kernel,
	linux-mmc, linux-renesas-soc
In-Reply-To: <CAMuHMdWwantdbvPSFoYm=+_OoQQkKwz+K=qwWgy-7tSp1BNJBw@mail.gmail.com>

On 5/22/26 5:47 PM, Geert Uytterhoeven wrote:

Hello Geert,

>> +++ b/arch/arm64/boot/dts/renesas/r8a779md-geist.dts
> 
>> +&avb {
>> +       pinctrl-0 = <&avb_pins>;
>> +       pinctrl-names = "default";
>> +       phy-handle = <&phy0>;
>> +       tx-internal-delay-ps = <2000>;
>> +       status = "okay";
>> +
>> +       phy0: ethernet-phy@0 {
>> +               compatible = "ethernet-phy-id0022.1622";
>> +               rxc-skew-ps = <1500>;
>> +               reg = <0>;
>> +               interrupts-extended = <&gpio2 11 IRQ_TYPE_LEVEL_LOW>;
>> +               reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
>> +               reset-assert-us = <100>;
> 
> 10000?
> 
>> +               reset-deassert-us = <100>;
> 
> 300?
> 
>> +       };
>> +};
> 
>> +&pfc {
> 
>> +       pwm2_pins: pwm2 {
>> +               groups = "pwm2_a";
>> +               function = "pwm2";
>> +       };
> 
> Shall I drop this while applying?
> 
>> +&pwm2 {
>> +       pinctrl-0 = <&pwm2_pins>;
>> +       pinctrl-names = "default";
>> +
>> +       status = "okay";
>> +};
> 
> Shall I drop this while applying?
> 
> With the above fixed:
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
I sent a V3 only of the 7/7 In-Reply-To this message, I hope it helps.

Thank you for the reviews !

^ permalink raw reply

* [PATCH v3] arm64: dts: renesas: r8a779md: Add support for R-Car M3Le R8A779MD Geist
From: Marek Vasut @ 2026-05-22 17:19 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Nguyen Tran, Geert Uytterhoeven, Marek Vasut, Brian Masney,
	Conor Dooley, Krzysztof Kozlowski, Kuninori Morimoto, Magnus Damm,
	Michael Turquette, Rob Herring, Stephen Boyd, Ulf Hansson,
	Wolfram Sang, devicetree, linux-clk, linux-kernel, linux-mmc,
	linux-renesas-soc
In-Reply-To: <CAMuHMdWwantdbvPSFoYm=+_OoQQkKwz+K=qwWgy-7tSp1BNJBw@mail.gmail.com>

From: Nguyen Tran <nguyen.tran.pz@bp.renesas.com>

Add support for the Geist board based on the Renesas R-Car R8A779MD (M3Le)
SoC, a register-compatible variant of the R8A77965 (M3-N) with reduced set
of peripherals.

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Nguyen Tran <nguyen.tran.pz@bp.renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: Brian Masney <bmasney@redhat.com>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Cc: Magnus Damm <magnus.damm@gmail.com>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Ulf Hansson <ulfh@kernel.org>
Cc: Wolfram Sang <wsa+renesas@sang-engineering.com>
Cc: devicetree@vger.kernel.org
Cc: linux-clk@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-mmc@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
V2: - Drop CS2500 variant suffix
    - Drop cells from rcar_sound ports {}
    - Drop ehci1, ohci1, usb2_phy1
    - Drop Salvator-X reference from commit message
    - Split panel DTO into separate patch
    - Drop FCNL node
    - Add another memory node for the second 2 GiB of DRAM,
      although the DRAM layout is patched in by U-Boot
    - Drop FIXME from audio-clkout {}
    - Sort nodes without unit address
    - Rename regulators, use npmv suffix for n.m V regulators
    - Rename x12 node to x12-clock node
    - Add PHY compatible string
    - Use interrupts-extended in PHY node
    - Rename clk_multiplier/clock-generator to clock-controller
    - Use interrupts-extended
    - Reinstate port@0 to rsound
    - Drop iommus from SDHI2
    - Drop DU until it can be tested
V3: - Drop pwm2 and pwm2_pins
    - Follow KSZ9031RNX tSR for reset assert time,
      FIGURE 7-5 Note 2 for reset post-deassert time
    - Add RB from Geert
---
 arch/arm64/boot/dts/renesas/Makefile          |   1 +
 .../arm64/boot/dts/renesas/r8a779md-geist.dts | 720 ++++++++++++++++++
 2 files changed, 721 insertions(+)
 create mode 100644 arch/arm64/boot/dts/renesas/r8a779md-geist.dts

diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile
index ca45d2857ea7f..8bf155badd111 100644
--- a/arch/arm64/boot/dts/renesas/Makefile
+++ b/arch/arm64/boot/dts/renesas/Makefile
@@ -60,6 +60,7 @@ r8a77965-salvator-xs-panel-aa104xd12-dtbs := r8a77965-salvator-xs.dtb salvator-p
 dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-salvator-xs-panel-aa104xd12.dtb
 dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-ulcb.dtb
 dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-ulcb-kf.dtb
+dtb-$(CONFIG_ARCH_R8A77965) += r8a779md-geist.dtb
 
 dtb-$(CONFIG_ARCH_R8A77970) += r8a77970-eagle.dtb
 dtb-$(CONFIG_ARCH_R8A77970) += r8a77970-eagle-function-expansion.dtbo
diff --git a/arch/arm64/boot/dts/renesas/r8a779md-geist.dts b/arch/arm64/boot/dts/renesas/r8a779md-geist.dts
new file mode 100644
index 0000000000000..11024bd12eb63
--- /dev/null
+++ b/arch/arm64/boot/dts/renesas/r8a779md-geist.dts
@@ -0,0 +1,720 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Device Tree Source for the Geist board with R-Car M3Le
+ *
+ * Copyright (C) 2025-2026 Renesas Electronics Corp.
+ */
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include "r8a779md.dtsi"
+
+/ {
+	model = "Renesas Geist board based on r8a779md";
+	compatible = "renesas,geist", "renesas,r8a779md", "renesas,r8a77965";
+
+	aliases {
+		serial0 = &scif2;
+		serial1 = &hscif1;
+		ethernet0 = &avb;
+		mmc0 = &sdhi2;
+		mmc1 = &sdhi0;
+	};
+
+	chosen {
+		bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
+		stdout-path = "serial0:115200n8";
+	};
+
+	audio_clkout: audio-clkout {
+		/*
+		 * This is same as <&rcar_sound 0>
+		 * but needed to avoid cs2500/rcar_sound probe dead-lock
+		 */
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <12288000>;
+	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm1 0 50000>;
+
+		brightness-levels = <256 128 64 16 8 4 0>;
+		default-brightness-level = <6>;
+
+		power-supply = <&reg_12v>;
+		enable-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>;
+	};
+
+	cvbs-in {
+		compatible = "composite-video-connector";
+		label = "CVBS IN";
+
+		port {
+			cvbs_con: endpoint {
+				remote-endpoint = <&adv7482_ain7>;
+			};
+		};
+	};
+
+	hdmi-in {
+		compatible = "hdmi-connector";
+		label = "HDMI IN";
+		type = "a";
+
+		port {
+			hdmi_in_con: endpoint {
+				remote-endpoint = <&adv7482_hdmi>;
+			};
+		};
+	};
+
+	keys {
+		compatible = "gpio-keys";
+
+		pinctrl-0 = <&keys_pins>;
+		pinctrl-names = "default";
+
+		key-1 {
+			gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_1>;
+			label = "SW4-1";
+			wakeup-source;
+			debounce-interval = <20>;
+		};
+
+		key-2 {
+			gpios = <&gpio5 20 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_2>;
+			label = "SW4-2";
+			wakeup-source;
+			debounce-interval = <20>;
+		};
+
+		key-3 {
+			gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_3>;
+			label = "SW4-3";
+			wakeup-source;
+			debounce-interval = <20>;
+		};
+
+		key-4 {
+			gpios = <&gpio5 23 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_4>;
+			label = "SW4-4";
+			wakeup-source;
+			debounce-interval = <20>;
+		};
+
+		key-a {
+			gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_A>;
+			label = "TSW0";
+			wakeup-source;
+			debounce-interval = <20>;
+		};
+
+		key-b {
+			gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_B>;
+			label = "TSW1";
+			wakeup-source;
+			debounce-interval = <20>;
+		};
+
+		key-c {
+			gpios = <&gpio6 13 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_C>;
+			label = "TSW2";
+			wakeup-source;
+			debounce-interval = <20>;
+		};
+	};
+
+	memory@48000000 {
+		device_type = "memory";
+		/* first 128MB is reserved for secure area. */
+		reg = <0x0 0x48000000 0x0 0x78000000>;
+	};
+
+	memory@480000000 {
+		device_type = "memory";
+		reg = <0x4 0x80000000 0x0 0x80000000>;
+	};
+
+	reg_1p8v: regulator-1p8v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-1.8V";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_3p3v: regulator-3p3v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-3.3V";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	reg_12v: regulator-12v {
+		compatible = "regulator-fixed";
+		regulator-name = "fixed-12V";
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+
+	vbus0_usb2: regulator-vbus0-usb2 {
+		compatible = "regulator-fixed";
+
+		regulator-name = "USB20_VBUS0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+
+		gpio = <&gpio6 16 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	vcc_sdhi0: regulator-vcc-sdhi0 {
+		compatible = "regulator-fixed";
+
+		regulator-name = "SDHI0 Vcc";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
+
+	vccq_sdhi0: regulator-vccq-sdhi0 {
+		compatible = "regulator-gpio";
+
+		regulator-name = "SDHI0 VccQ";
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <3300000>;
+
+		gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
+		gpios-states = <1>;
+		states = <3300000 1>, <1800000 0>;
+	};
+
+	sound_card: sound {
+		compatible = "audio-graph-card";
+
+		label = "rcar-sound";
+		dais = <&rsnd_port0>; /* AK4619 Audio Codec */
+	};
+
+	x12_clk: x12-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <24576000>;
+	};
+
+	/* External DU dot clocks */
+	x21_clk: x21-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <33000000>;
+	};
+
+	x22_clk: x22-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <33000000>;
+	};
+
+	x23_clk: x23-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
+
+	x3013_clk: x3013-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <25000000>;
+	};
+};
+
+&audio_clk_a {
+	clock-frequency = <22579200>;
+};
+
+&avb {
+	pinctrl-0 = <&avb_pins>;
+	pinctrl-names = "default";
+	phy-handle = <&phy0>;
+	tx-internal-delay-ps = <2000>;
+	status = "okay";
+
+	phy0: ethernet-phy@0 {
+		compatible = "ethernet-phy-id0022.1622";
+		rxc-skew-ps = <1500>;
+		reg = <0>;
+		interrupts-extended = <&gpio2 11 IRQ_TYPE_LEVEL_LOW>;
+		reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <300>;
+	};
+};
+
+&csi40 {
+	status = "okay";
+
+	ports {
+		port@0 {
+			csi40_in: endpoint {
+				clock-lanes = <0>;
+				data-lanes = <1 2 3 4>;
+				remote-endpoint = <&adv7482_txa>;
+			};
+		};
+	};
+};
+
+&ehci0 {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&extalr_clk {
+	clock-frequency = <32768>;
+};
+
+&extal_clk {
+	clock-frequency = <16666666>;
+};
+
+&hscif1 {
+	pinctrl-0 = <&hscif1_pins>;
+	pinctrl-names = "default";
+
+	uart-has-rtscts;
+	/* Please only enable hscif1 or scif1 */
+	status = "okay";
+};
+
+&hsusb {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&i2c2 {
+	pinctrl-0 = <&i2c2_pins>;
+	pinctrl-names = "default";
+	clock-frequency = <100000>;
+	status = "okay";
+
+	ak4619: codec@10 {
+		compatible = "asahi-kasei,ak4619";
+		reg = <0x10>;
+		clocks = <&rcar_sound 3>;
+		clock-names = "mclk";
+		#sound-dai-cells = <0>;
+
+		port {
+			ak4619_endpoint: endpoint {
+				remote-endpoint = <&rsnd_endpoint0>;
+			};
+		};
+	};
+
+	/* Pin-to-pin, register map, and control compatible with CS2000 and CS2200 */
+	cs2500: clock-controller@4f {
+		#clock-cells = <0>;
+		compatible = "cirrus,cs2500", "cirrus,cs2000-cp";
+		reg = <0x4f>;
+		clocks = <&audio_clkout>, <&x12_clk>;
+		clock-names = "clk_in", "ref_clk";
+
+		assigned-clocks = <&cs2500>;
+		assigned-clock-rates = <24576000>; /* 1/1 divide */
+	};
+};
+
+&i2c4 {
+	clock-frequency = <400000>;
+	status = "okay";
+
+	versaclock3: clock-controller@68 {
+		compatible = "renesas,5p35023";
+		reg = <0x68>;
+		#clock-cells = <1>;
+		clocks = <&x3013_clk>;
+		assigned-clocks = <&versaclock3 4>, <&versaclock3 5>;
+		assigned-clock-rates = <100000000>, <100000000>;
+	};
+
+	versaclock5: clock-controller@6a {
+		compatible = "idt,5p49v5923";
+		reg = <0x6a>;
+		#clock-cells = <1>;
+		clocks = <&x23_clk>;
+		clock-names = "xin";
+	};
+
+	video-receiver@70 {
+		compatible = "adi,adv7482";
+		reg = <0x70 0x71 0x72 0x73 0x74 0x75
+		       0x60 0x61 0x62 0x63 0x64 0x65>;
+		reg-names = "main", "dpll", "cp", "hdmi", "edid", "repeater",
+			    "infoframe", "cbus", "cec", "sdp", "txa", "txb" ;
+
+		interrupts-extended = <&gpio6 30 IRQ_TYPE_LEVEL_LOW>,
+				      <&gpio6 31 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-names = "intrq1", "intrq2";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@7 {
+				reg = <7>;
+
+				adv7482_ain7: endpoint {
+					remote-endpoint = <&cvbs_con>;
+				};
+			};
+
+			port@8 {
+				reg = <8>;
+
+				adv7482_hdmi: endpoint {
+					remote-endpoint = <&hdmi_in_con>;
+				};
+			};
+
+			port@a {
+				reg = <10>;
+
+				adv7482_txa: endpoint {
+					clock-lanes = <0>;
+					data-lanes = <1 2 3 4>;
+					remote-endpoint = <&csi40_in>;
+				};
+			};
+		};
+	};
+
+	csa_vdd: adc@7c {
+		compatible = "maxim,max9611";
+		reg = <0x7c>;
+
+		shunt-resistor-micro-ohms = <5000>;
+	};
+
+	csa_dvfs: adc@7f {
+		compatible = "maxim,max9611";
+		reg = <0x7f>;
+
+		shunt-resistor-micro-ohms = <5000>;
+	};
+};
+
+&i2c_dvfs {
+	status = "okay";
+
+	clock-frequency = <400000>;
+
+	eeprom@50 {
+		compatible = "rohm,br24t01", "atmel,24c01";
+		reg = <0x50>;
+		pagesize = <8>;
+	};
+};
+
+&ohci0 {
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&pcie_bus_clk {
+	status = "disabled";
+};
+
+&pciec0 {
+	clocks = <&cpg CPG_MOD 319>, <&versaclock3 4>;
+	status = "okay";
+};
+
+&pciec0_rp {
+	clocks = <&versaclock3 5>;
+};
+
+&pfc {
+	pinctrl-0 = <&scif_clk_pins>;
+	pinctrl-names = "default";
+
+	avb_pins: avb {
+		mux {
+			groups = "avb_link", "avb_mdio", "avb_mii";
+			function = "avb";
+		};
+
+		pins_mdio {
+			groups = "avb_mdio";
+			drive-strength = <24>;
+		};
+
+		pins_mii_tx {
+			pins = "PIN_AVB_TX_CTL", "PIN_AVB_TXC", "PIN_AVB_TD0",
+			       "PIN_AVB_TD1", "PIN_AVB_TD2", "PIN_AVB_TD3";
+			drive-strength = <12>;
+		};
+	};
+
+	hscif1_pins: hscif1 {
+		groups = "hscif1_data_a", "hscif1_ctrl_a";
+		function = "hscif1";
+	};
+
+	i2c2_pins: i2c2 {
+		groups = "i2c2_a";
+		function = "i2c2";
+	};
+
+	irq0_pins: irq0 {
+		groups = "intc_ex_irq0";
+		function = "intc_ex";
+	};
+
+	keys_pins: keys {
+		pins = "GP_5_17", "GP_5_20", "GP_5_22";
+		bias-pull-up;
+	};
+
+	pwm1_pins: pwm1 {
+		groups = "pwm1_a";
+		function = "pwm1";
+	};
+
+	scif1_pins: scif1 {
+		groups = "scif1_data_a", "scif1_ctrl";
+		function = "scif1";
+	};
+
+	scif2_pins: scif2 {
+		groups = "scif2_data_a";
+		function = "scif2";
+	};
+
+	scif_clk_pins: scif_clk {
+		groups = "scif_clk_a";
+		function = "scif_clk";
+	};
+
+	sdhi0_pins: sd0 {
+		groups = "sdhi0_data4", "sdhi0_ctrl";
+		function = "sdhi0";
+		power-source = <3300>;
+	};
+
+	sdhi0_pins_uhs: sd0_uhs {
+		groups = "sdhi0_data4", "sdhi0_ctrl";
+		function = "sdhi0";
+		power-source = <1800>;
+	};
+
+	sdhi2_pins: sd2 {
+		groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds";
+		function = "sdhi2";
+		power-source = <1800>;
+	};
+
+	sound_pins: sound {
+		groups = "ssi01239_ctrl", "ssi0_data", "ssi1_data_a";
+		function = "ssi";
+	};
+
+	sound_clk_pins: sound_clk {
+		groups = "audio_clk_a_a", "audio_clk_b_a", "audio_clk_c_a",
+			 "audio_clkout_a", "audio_clkout3_a";
+		function = "audio_clk";
+	};
+
+	usb0_pins: usb0 {
+		groups = "usb0";
+		function = "usb0";
+	};
+};
+
+&pwm1 {
+	pinctrl-0 = <&pwm1_pins>;
+	pinctrl-names = "default";
+
+	status = "okay";
+};
+
+&rcar_sound {
+	pinctrl-0 = <&sound_pins>, <&sound_clk_pins>;
+	pinctrl-names = "default";
+
+	/* Single DAI */
+	#sound-dai-cells = <0>;
+
+	/* audio_clkout0/1/2/3 */
+	#clock-cells = <1>;
+	clock-frequency = <12288000 11289600>;
+
+	status = "okay";
+
+	/* update <audio_clk_b> to <cs2500> */
+	clocks = <&cpg CPG_MOD 1005>,
+		 <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
+		 <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
+		 <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
+		 <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
+		 <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
+		 <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
+		 <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
+		 <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
+		 <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
+		 <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
+		 <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
+		 <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
+		 <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
+		 <&audio_clk_a>, <&cs2500>,
+		 <&audio_clk_c>,
+		 <&cpg CPG_MOD 922>;
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		rsnd_port0: port@0 {
+			reg = <0>;
+
+			rsnd_endpoint0: endpoint {
+				remote-endpoint = <&ak4619_endpoint>;
+				dai-format = "left_j";
+				bitclock-master = <&rsnd_endpoint0>;
+				frame-master = <&rsnd_endpoint0>;
+				playback = <&ssi0>, <&src0>, <&dvc0>;
+				capture = <&ssi1>, <&src1>, <&dvc1>;
+			};
+		};
+	};
+};
+
+&rwdt {
+	timeout-sec = <60>;
+	status = "okay";
+};
+
+&scif1 {
+	pinctrl-0 = <&scif1_pins>;
+	pinctrl-names = "default";
+
+	uart-has-rtscts;
+	/* Please only enable hscif1 or scif1 */
+	/* status = "okay"; */
+};
+
+&scif2 {
+	pinctrl-0 = <&scif2_pins>;
+	pinctrl-names = "default";
+
+	status = "okay";
+};
+
+&scif_clk {
+	clock-frequency = <14745600>;
+};
+
+&sdhi0 {
+	pinctrl-0 = <&sdhi0_pins>;
+	pinctrl-1 = <&sdhi0_pins_uhs>;
+	pinctrl-names = "default", "state_uhs";
+
+	vmmc-supply = <&vcc_sdhi0>;
+	vqmmc-supply = <&vccq_sdhi0>;
+	cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
+	wp-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
+	bus-width = <4>;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	status = "okay";
+};
+
+&sdhi2 {
+	/* used for on-board 8bit eMMC */
+	pinctrl-0 = <&sdhi2_pins>;
+	pinctrl-1 = <&sdhi2_pins>;
+	pinctrl-names = "default", "state_uhs";
+
+	vmmc-supply = <&reg_3p3v>;
+	vqmmc-supply = <&reg_1p8v>;
+	bus-width = <8>;
+	mmc-hs200-1_8v;
+	no-sd;
+	no-sdio;
+	non-removable;
+	fixed-emmc-driver-type = <1>;
+	full-pwr-cycle-in-suspend;
+	status = "okay";
+};
+
+&ssi1 {
+	shared-pin;
+};
+
+&usb_extal_clk {
+	clock-frequency = <50000000>;
+};
+
+&usb2_phy0 {
+	pinctrl-0 = <&usb0_pins>;
+	pinctrl-names = "default";
+
+	vbus-supply = <&vbus0_usb2>;
+	status = "okay";
+};
+
+&vin0 {
+	status = "okay";
+};
+
+&vin1 {
+	status = "okay";
+};
+
+&vin2 {
+	status = "okay";
+};
+
+&vin3 {
+	status = "okay";
+};
+
+&vin4 {
+	status = "okay";
+};
+
+&vin5 {
+	status = "okay";
+};
+
+&vin6 {
+	status = "okay";
+};
+
+&vin7 {
+	status = "okay";
+};
+
+&vspb {
+	status = "okay";
+};
+
+&vspi0 {
+	status = "okay";
+};
-- 
2.53.0


^ permalink raw reply related

* [PATCH] rust: kernel: use strict provenance APIs
From: Tamir Duberstein @ 2026-05-22 17:19 UTC (permalink / raw)
  To: Danilo Krummrich, Lorenzo Stoakes, Vlastimil Babka,
	Liam R. Howlett, Uladzislau Rezki, Miguel Ojeda, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Alice Ryhl, Trevor Gross, Greg Kroah-Hartman, Rafael J. Wysocki,
	Daniel Almeida, Rob Herring, Saravana Kannan, Bjorn Helgaas,
	Krzysztof Wilczyński
  Cc: rust-for-linux, linux-kernel, driver-core, devicetree, linux-pci,
	Tamir Duberstein, Benno Lossin

Replace existing pointer-to-integer and integer-to-pointer conversions
with calls to the strict provenance APIs.

The strict provenance APIs were stabilized in Rust 1.84.0 [1]. Since
commit f32fb9c58a5b ("rust: bump Rust minimum supported version to
1.85.0 (Debian Trixie)"), the minimum supported Rust version is 1.85.0,
so no polyfills are needed.

Link: https://blog.rust-lang.org/2025/01/09/Rust-1.84.0.html#strict-provenance-apis [1]
Suggested-by: Benno Lossin <benno.lossin@proton.me>
Link: https://lore.kernel.org/all/D8EIXDMRXMJP.36TFCGWZBRS3Y@proton.me/
Signed-off-by: Tamir Duberstein <tamird@kernel.org>
---
 rust/kernel/alloc.rs           |  2 +-
 rust/kernel/alloc/allocator.rs |  2 +-
 rust/kernel/devres.rs          |  4 ++--
 rust/kernel/error.rs           |  2 +-
 rust/kernel/io.rs              | 10 ++++++----
 rust/kernel/io/mem.rs          |  4 ++--
 rust/kernel/of.rs              |  2 +-
 rust/kernel/pci/io.rs          |  4 ++--
 rust/kernel/str.rs             | 16 ++++++----------
 rust/kernel/uaccess.rs         |  2 +-
 10 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index e38720349dcf..332e7fff15c4 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -262,7 +262,7 @@ unsafe fn free(ptr: NonNull<u8>, layout: Layout) {
 
 /// Returns a properly aligned dangling pointer from the given `layout`.
 pub(crate) fn dangling_from_layout(layout: Layout) -> NonNull<u8> {
-    let ptr = layout.align() as *mut u8;
+    let ptr = core::ptr::without_provenance_mut(layout.align());
 
     // SAFETY: `layout.align()` (and hence `ptr`) is guaranteed to be non-zero.
     unsafe { NonNull::new_unchecked(ptr) }
diff --git a/rust/kernel/alloc/allocator.rs b/rust/kernel/alloc/allocator.rs
index 63bfb91b3671..9a56d2407d8f 100644
--- a/rust/kernel/alloc/allocator.rs
+++ b/rust/kernel/alloc/allocator.rs
@@ -280,7 +280,7 @@ fn new() -> Result<Self> {
             fn is_aligned_to(&self, align: usize) -> bool {
                 assert!(align.is_power_of_two());
 
-                let addr = self.0.as_ptr() as usize;
+                let addr = self.0.as_ptr().addr();
                 addr & (align - 1) == 0
             }
         }
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 9e5f93aed20c..ecba524e41df 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -93,14 +93,14 @@ struct Inner<T> {
 ///             return Err(ENOMEM);
 ///         }
 ///
-///         Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?))
+///         Ok(IoMem(MmioRaw::new(addr.expose_provenance(), SIZE)?))
 ///     }
 /// }
 ///
 /// impl<const SIZE: usize> Drop for IoMem<SIZE> {
 ///     fn drop(&mut self) {
 ///         // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
-///         unsafe { bindings::iounmap(self.0.addr() as *mut c_void); };
+///         unsafe { bindings::iounmap(core::ptr::with_exposed_provenance_mut(self.0.addr())); };
 ///     }
 /// }
 ///
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 05cf869ac090..37eb14c71fb0 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -483,7 +483,7 @@ pub fn to_result(err: crate::ffi::c_int) -> Result {
 /// #         core::ptr::null_mut()
 /// #     }
 /// #     pub(super) unsafe fn non_null_ptr() -> *mut kernel::ffi::c_void {
-/// #         0x1234 as *mut kernel::ffi::c_void
+/// #         core::ptr::without_provenance_mut(0x1234)
 /// #     }
 /// # }
 /// // SAFETY: ...
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index fcc7678fd9e3..a416221fb4a5 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -109,14 +109,14 @@ pub fn maxsize(&self) -> usize {
 ///             return Err(ENOMEM);
 ///         }
 ///
-///         Ok(IoMem(MmioRaw::new(addr as usize, SIZE)?))
+///         Ok(IoMem(MmioRaw::new(addr.expose_provenance(), SIZE)?))
 ///     }
 /// }
 ///
 /// impl<const SIZE: usize> Drop for IoMem<SIZE> {
 ///     fn drop(&mut self) {
 ///         // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
-///         unsafe { bindings::iounmap(self.0.addr() as *mut c_void); };
+///         unsafe { bindings::iounmap(core::ptr::with_exposed_provenance_mut(self.0.addr())); };
 ///     }
 /// }
 ///
@@ -733,12 +733,14 @@ macro_rules! impl_mmio_io_capable {
         impl<const SIZE: usize> IoCapable<$ty> for $mmio<SIZE> {
             unsafe fn io_read(&self, address: usize) -> $ty {
                 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations.
-                unsafe { bindings::$read_fn(address as *const c_void) }
+                unsafe { bindings::$read_fn(core::ptr::with_exposed_provenance(address)) }
             }
 
             unsafe fn io_write(&self, value: $ty, address: usize) {
                 // SAFETY: By the trait invariant `address` is a valid address for MMIO operations.
-                unsafe { bindings::$write_fn(value, address as *mut c_void) }
+                unsafe {
+                    bindings::$write_fn(value, core::ptr::with_exposed_provenance_mut(address))
+                }
             }
         }
     };
diff --git a/rust/kernel/io/mem.rs b/rust/kernel/io/mem.rs
index 7dc78d547f7a..e7e909c6bb2d 100644
--- a/rust/kernel/io/mem.rs
+++ b/rust/kernel/io/mem.rs
@@ -266,7 +266,7 @@ fn ioremap(resource: &Resource) -> Result<Self> {
             return Err(ENOMEM);
         }
 
-        let io = MmioRaw::new(addr as usize, size)?;
+        let io = MmioRaw::new(addr.expose_provenance(), size)?;
         let io = IoMem { io };
 
         Ok(io)
@@ -284,7 +284,7 @@ pub fn new<'a>(io_request: IoRequest<'a>) -> impl PinInit<Devres<Self>, Error> +
 impl<const SIZE: usize> Drop for IoMem<SIZE> {
     fn drop(&mut self) {
         // SAFETY: Safe as by the invariant of `Io`.
-        unsafe { bindings::iounmap(self.io.addr() as *mut c_void) }
+        unsafe { bindings::iounmap(core::ptr::with_exposed_provenance_mut(self.io.addr())) }
     }
 }
 
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
index 58b20c367f99..95ef14b9a615 100644
--- a/rust/kernel/of.rs
+++ b/rust/kernel/of.rs
@@ -27,7 +27,7 @@ unsafe impl RawDeviceIdIndex for DeviceId {
     const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::of_device_id, data);
 
     fn index(&self) -> usize {
-        self.0.data as usize
+        self.0.data.addr()
     }
 }
 
diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs
index ae78676c927f..b5e3a68a7a11 100644
--- a/rust/kernel/pci/io.rs
+++ b/rust/kernel/pci/io.rs
@@ -175,7 +175,7 @@ pub(super) fn new(pdev: &Device, num: u32, name: &CStr) -> Result<Self> {
         // `pdev` is valid by the invariants of `Device`.
         // `num` is checked for validity by a previous call to `Device::resource_len`.
         // `name` is always valid.
-        let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize;
+        let ioptr = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) }.expose_provenance();
         if ioptr == 0 {
             // SAFETY:
             // `pdev` is valid by the invariants of `Device`.
@@ -212,7 +212,7 @@ unsafe fn do_release(pdev: &Device, ioptr: usize, num: i32) {
         // `ioptr` is valid by the safety requirements.
         // `num` is valid by the safety requirements.
         unsafe {
-            bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut c_void);
+            bindings::pci_iounmap(pdev.as_raw(), core::ptr::with_exposed_provenance_mut(ioptr));
             bindings::pci_release_region(pdev.as_raw(), num);
         }
     }
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 8311d91549e1..67aba11c9702 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -564,9 +564,9 @@ fn new() -> Self {
     pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
         // INVARIANT: The safety requirements guarantee the type invariants.
         Self {
-            beg: pos as usize,
-            pos: pos as usize,
-            end: end as usize,
+            beg: pos.expose_provenance(),
+            pos: pos.expose_provenance(),
+            end: end.expose_provenance(),
         }
     }
 
@@ -577,7 +577,7 @@ pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
     /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
     /// for the lifetime of the returned [`RawFormatter`].
     pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
-        let pos = buf as usize;
+        let pos = buf.expose_provenance();
         // INVARIANT: We ensure that `end` is never less than `buf`, and the safety requirements
         // guarantees that the memory region is valid for writes.
         Self {
@@ -591,7 +591,7 @@ pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
     ///
     /// N.B. It may point to invalid memory.
     pub(crate) fn pos(&self) -> *mut u8 {
-        self.pos as *mut u8
+        core::ptr::with_exposed_provenance_mut(self.pos)
     }
 
     /// Returns the number of bytes written to the formatter.
@@ -613,11 +613,7 @@ fn write_str(&mut self, s: &str) -> fmt::Result {
             // SAFETY: If `len_to_copy` is non-zero, then we know `pos` has not gone past `end`
             // yet, so it is valid for write per the type invariants.
             unsafe {
-                core::ptr::copy_nonoverlapping(
-                    s.as_bytes().as_ptr(),
-                    self.pos as *mut u8,
-                    len_to_copy,
-                )
+                core::ptr::copy_nonoverlapping(s.as_bytes().as_ptr(), self.pos(), len_to_copy)
             };
         }
 
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 5f6c4d7a1a51..f06b4c1637ca 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -28,7 +28,7 @@ impl UserPtr {
     /// Create a `UserPtr` from an integer representing the userspace address.
     #[inline]
     pub fn from_addr(addr: usize) -> Self {
-        Self(addr as *mut c_void)
+        Self(core::ptr::without_provenance_mut(addr))
     }
 
     /// Create a `UserPtr` from a pointer representing the userspace address.

---
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
change-id: 20260521-strict-provenance-redux-d58178caada3

Best regards,
--  
Tamir Duberstein <tamird@kernel.org>


^ permalink raw reply related

* Re: [PATCH v2 4/4] arm64: dts: qcom: x1-dell-thena: bump linux,cma to 256 MiB
From: Michael Scott @ 2026-05-22 17:16 UTC (permalink / raw)
  To: Bryan O'Donoghue, linux-arm-msm
  Cc: vkoul, neil.armstrong, dmitry.baryshkov, wesley.cheng, abelvesa,
	faisal.hassan, linux-phy, andersson, konradybcio, robh, krzk+dt,
	conor+dt, devicetree, val, laurentiu.tudor1, alex.vinarskis,
	linux-kernel
In-Reply-To: <ac559877-f4f2-48d7-b00c-4cf24fc64489@linaro.org>

On 5/21/26 5:04 AM, Bryan O'Donoghue wrote:
> On 21/05/2026 02:09, Michael Scott wrote:
>> The 128 MiB linux,cma reserved-memory pool on dell-thena is too small
>> to support the camera pipeline in parallel with the normal Linux
>> desktop. On a freshly-booted system with GNOME running, the typical
>> runtime consumers — msm DRM framebuffers (Wayland triple buffering on
>> the eDP panel), qcom_iris video codec buffers, qcom_camss VFE
>> pre-allocated buffers — already occupy ~100 MiB of the pool, leaving
>> only ~25 MiB free.
>>
>> The libcamera "simple" pipeline handler used by /dev/media0 on
>> dell-thena allocates four ABGR8888 frames at 1920×1088 = 32 MiB total.
>> That request fails on the fourth frame:
>>
>>      ERROR DmaBufAllocator: dma-heap allocation failure for frame-3
>>      ERROR Allocator: Stream is not part of /base/.../camera@10 
>> active configuration
>>      Can't allocate buffers
>>      Failed to start camera session
>>
>> resulting in gnome-snapshot's "Could not play camera stream" and any
>> other libcamera-mediated app being unable to actually stream.
>>
>> Bumping linux,cma to 256 MiB (a 0.9% reservation on these laptops'
>> typical 27 GiB RAM) leaves ~150 MiB free at runtime — sufficient for
>> the libcamera buffer set plus headroom for video playback or other
>> CMA-hungry workloads in parallel.
>>
>> Tested on Dell Latitude 7455: with the 256 MiB pool, CmaFree at
>> GNOME-desktop idle is ~150 MiB, gnome-snapshot streams the OV02E10
>> camera cleanly, and `cam -c 1 --capture=2` succeeds.
>>
>> The companion board files dell-inspiron-14-plus-7441 and the upstream
>> .dts variants inherit from x1-dell-thena.dtsi, so this changes the
>> pool size for every dell-thena-based laptop in one place.
>>
>> Signed-off-by: Michael Scott <mike.scott@oss.qualcomm.com>
>> ---
>>   arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi 
>> b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
>> index d6de4da02dcd..714988a81384 100644
>> --- a/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
>> +++ b/arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi
>> @@ -167,7 +167,7 @@ led-camera-indicator {
>>       reserved-memory {
>>           linux,cma {
>>               compatible = "shared-dma-pool";
>> -            size = <0x0 0x8000000>;
>> +            size = <0x0 0x10000000>;
>>               reusable;
>>               linux,cma-default;
>>           };
>
> How old is your version of libcamera ?
>
> With CONFIG_UDMA=y you don't need a contiguous memory area at all and 
> you will get juicy and delicious GPUISP.

I have CONFIG_UDMABUF=y enabled.

>
> Instead of allocating in the kernel just use a better version of 
> libcamera
>
> ┌─[deckard@inspiron14p-linux] - [~/Development/libcamera] - [Thu May 
> 21, 13:03]
> └─[$] <git:(0.7.0-multipass-v0*)> zcat /proc/config.gz | grep UDMA
> CONFIG_UDMABUF=y
> ┌─[deckard@inspiron14p-linux] - [~/Development/libcamera] - [Thu May 
> 21, 13:03]
> └─[$] <git:(0.7.0-multipass-v0*)> cam -v
> libcamera version v0.7.1
> ┌─[deckard@inspiron14p-linux] - [~/Development/libcamera] - [Thu May 
> 21, 13:03]
> └─[$] <git:(0.7.0-multipass-v0*)> qcam
> [68:50:10.493478857] [438859]  INFO Camera camera_manager.cpp:340 
> libcamera v0.7.1
> [68:50:10.511134091] [438863] ERROR V4L2 v4l2_subdevice.cpp:1192 
> 'ov02e10 10-0010': Unable to get rectangle 2 on pad 0/0: Inappropriate 
> ioctl for device
> [68:50:10.511201590] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:402 'ov02e10 10-0010': The PixelArraySize 
> property has been defaulted to 1928x1088
> [68:50:10.511206069] [438863] ERROR V4L2 v4l2_subdevice.cpp:1192 
> 'ov02e10 10-0010': Unable to get rectangle 1 on pad 0/0: Inappropriate 
> ioctl for device
> [68:50:10.511209559] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:413 'ov02e10 10-0010': The 
> PixelArrayActiveAreas property has been defaulted to (0, 0)/1928x1088
> [68:50:10.511213778] [438863] ERROR V4L2 v4l2_subdevice.cpp:1192 
> 'ov02e10 10-0010': Unable to get rectangle 0 on pad 0/0: Inappropriate 
> ioctl for device
> [68:50:10.511216590] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:421 'ov02e10 10-0010': Failed to retrieve the 
> sensor crop rectangle
> [68:50:10.511219559] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:427 'ov02e10 10-0010': The sensor kernel 
> driver needs to be fixed
> [68:50:10.511221746] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:429 'ov02e10 10-0010': See 
> Documentation/sensor_driver_requirements.rst in the libcamera sources 
> for more information
> [68:50:10.511327474] [438863]  WARN CameraSensorProperties 
> camera_sensor_properties.cpp:538 No static properties available for 
> 'ov02e10'
> [68:50:10.511330599] [438863]  WARN CameraSensorProperties 
> camera_sensor_properties.cpp:540 Please consider updating the camera 
> sensor properties database
> [68:50:10.511334089] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:617 'ov02e10 10-0010': Rotation control not 
> available, default to 0 degrees
> [68:50:10.511340912] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:502 'ov02e10 10-0010': No sensor delays found 
> in static properties. Assuming unverified defaults.
> [68:50:10.512362985] [438863]  WARN IPAProxy ipa_proxy.cpp:196 
> Configuration file 'ov02e10.yaml' not found for IPA module 'simple', 
> falling back to '/usr/share/libcamera/ipa/simple/uncalibrated.yaml'
> [68:50:10.512372828] [438863] ERROR V4L2 v4l2_subdevice.cpp:1192 
> 'ov02e10 10-0010': Unable to get rectangle 0 on pad 0/0: Inappropriate 
> ioctl for device
> [68:50:10.512377464] [438863]  WARN CameraSensor 
> camera_sensor_legacy.cpp:881 'ov02e10 10-0010': The analogue crop 
> rectangle has been defaulted to the active area size
> [68:50:10.512386578] [438863]  WARN IPASoft soft_simple.cpp:104 
> IPASoft: Failed to create camera sensor helper for ov02e10
> [68:50:10.512505275] [438863]  INFO Camera camera_manager.cpp:223 
> Adding camera '/base/soc@0/cci@ac16000/i2c-bus@1/camera@10' for 
> pipeline handler simple
> [68:50:10.548026157] [438859]  INFO Camera camera.cpp:1216 configuring 
> streams: (0) 1920x1088-ABGR8888/sRGB
> [68:50:10.548323081] [438863]  INFO IPASoft soft_simple.cpp:258 
> IPASoft: Exposure 1-2242, gain 16-248 (1)
> [68:50:10.548402247] [438863]  INFO SoftwareIsp software_isp.cpp:278 
> Input 1928x1088-GRBG-10-CSI2P stride 2416
> Zero-copy enabled
> [68:50:10.636862424] [438866]  INFO eGL egl.cpp:288 EGL: EGL_VERSION: 1.5
> [68:50:10.636899299] [438866]  INFO eGL egl.cpp:289 EGL: EGL_VENDOR: 
> Mesa Project
> [68:50:10.636902112] [438866]  INFO eGL egl.cpp:290 EGL: 
> EGL_CLIENT_APIS: OpenGL OpenGL_ES
> [68:50:10.636904768] [438866]  INFO eGL egl.cpp:291 EGL: 
> EGL_EXTENSIONS: EGL_ANDROID_blob_cache EGL_ANDROID_native_fence_sync 
> EGL_EXT_config_select_group EGL_EXT_create_context_robustness 
> EGL_EXT_image_dma_buf_import EGL_EXT_image_dma_buf_import_modifiers 
> EGL_EXT_query_reset_notification_strategy EGL_EXT_surface_compression 
> EGL_IMG_context_priority EGL_KHR_cl_event2 EGL_KHR_config_attribs 
> EGL_KHR_context_flush_control EGL_KHR_create_context 
> EGL_KHR_create_context_no_error EGL_KHR_fence_sync 
> EGL_KHR_get_all_proc_addresses EGL_KHR_gl_colorspace 
> EGL_KHR_gl_renderbuffer_image EGL_KHR_gl_texture_2D_image 
> EGL_KHR_gl_texture_3D_image EGL_KHR_gl_texture_cubemap_image 
> EGL_KHR_image_base EGL_KHR_no_config_context EGL_KHR_reusable_sync 
> EGL_KHR_surfaceless_context EGL_EXT_pixel_format_float 
> EGL_KHR_wait_sync EGL_MESA_configless_context EGL_MESA_gl_interop 
> EGL_MESA_image_dma_buf_export EGL_MESA_query_driver 
> EGL_MESA_x11_native_visual_id EGL_NV_context_priority_realtime
> [68:50:10.643064652] [438866]  INFO eGL egl.cpp:332 EGL: GL_VERSION: 
> OpenGL ES 3.2 Mesa 26.0.6-arch1.1
> [68:50:12.667202273] [438866]  INFO Benchmark benchmark.cpp:89 Debayer 
> processed 30 frames in 228802us, 7626 us/frame
> ┌─[deckard@inspiron14p-linux] - [~/Development/libcamera] - [Thu May 
> 21, 13:03]
> └─[$] <git:(0.7.0-multipass-v0*)>

Good point about the libcamera version. I debugged this on Ubuntu 26.04 
(v0.7.0+patches). I tried testing v0.7.1, but it caused a crash due to 
API changes with other parts of the subsystem.  I checked the diff of 
upstream between v0.7.0 and v0.7.1 for the dma allocator code and I 
didn't see any changes, but I wasn't looking at the software ISP changes.

This highlights that "I'm doing this wrong". I'll move to a cleaner 
rolling distro where staying current is a lot easier.

The GPUISP support looks great!

Dropping this patch as I'm not understanding the full allocator story.  
Sorry for the noise.


^ permalink raw reply

* Re: [PATCH v3 00/11] arm64: dts: ti: k3-am62-verdin: Add display and peripheral overlays
From: Francesco Dolcini @ 2026-05-22 17:05 UTC (permalink / raw)
  To: Vitor Soares
  Cc: Laurent Pinchart, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Lad Prabhakar,
	Thierry Reding, Vitor Soares, dri-devel, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260522161105.277519-13-ivitro@gmail.com>

On Fri, May 22, 2026 at 05:11:04PM +0100, Vitor Soares wrote:
> From: Vitor Soares <vitor.soares@toradex.com>
> 
> This series adds device tree overlays, expanding the hardware support for
> the Toradex Verdin AM62 SoM. The overlays target displays, cameras, audio,
> and peripherals available through Toradex carrier boards and the accessory
> ecosystem.

...

Reviewed-by: Francesco Dolcini <francesco.dolcini@toradex.com>


^ permalink raw reply

* Re: [PATCH v3 1/2] dt-bindings: iio: dac: Add AD5529R
From: Jonathan Cameron @ 2026-05-22 17:02 UTC (permalink / raw)
  To: Janani Sunil
  Cc: Lars-Peter Clausen, Michael Hennerich, David Lechner,
	Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Jonathan Corbet, Shuah Khan,
	linux-iio, devicetree, linux-kernel, linux-doc, Janani Sunil
In-Reply-To: <20260519-ad5529r-driver-v3-1-267c0731aa68@analog.com>

On Tue, 19 May 2026 17:42:58 +0200
Janani Sunil <janani.sunil@analog.com> wrote:

> Devicetree bindings for AD5529R 16 channel 12/16 bit high voltage,
> buffered voltage output digital-to-analog converter (DAC) with an
> integrated precision reference.

Note that I'm seeing this as Changes Requested in the DT-binding patchwork
but didn't see any replies.

Seems I didn't get the sashiko reply - nor did the IIO patchwork.
Hopefully Janani did!
https://patchwork.kernel.org/project/devicetree/patch/20260519-ad5529r-driver-v3-1-267c0731aa68@analog.com/

> 
> Signed-off-by: Janani Sunil <janani.sunil@analog.com>
> ---
>  .../devicetree/bindings/iio/dac/adi,ad5529r.yaml   | 217 +++++++++++++++++++++
>  MAINTAINERS                                        |   7 +
>  2 files changed, 224 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
> new file mode 100644
> index 000000000000..eb66f6ca063d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5529r.yaml
> @@ -0,0 +1,217 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/dac/adi,ad5529r.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Analog Devices AD5529R 16-Channel 12/16-bit High Voltage DAC
> +
> +maintainers:
> +  - Janani Sunil <janani.sunil@analog.com>
> +
> +description: |
> +  The AD5529R is a 16-channel, 12-bit or 16-bit, high voltage, buffered voltage output

Long line. Check the wrap.

> +  digital-to-analog converter (DAC) with an integrated precision reference.
> +  The device operates from unipolar and bipolar supplies. It is guaranteed
> +  monotonic and has built-in rail-to-rail output buffers that can source or
> +  sink up to 25mA.
> +
> +  Specifications:
> +  * 16 independent 12-bit or 16-bit DAC channels
> +  * Independently programmable output ranges: 0V to 5V, 0V to 10V, 0V to 20V,
> +    0V to 40V, ±5V, ±10V, ±15V, and ±20V
> +  * The device supports SPI communication with Mode 0 and Mode 3.
> +  * 4.096V precision reference, 12ppm/°C maximum
> +  * Built-in function generation: Toggle, Sinusoidal Dither, and Ramp waveforms
> +  * Multiplexer for output voltage, load current sense and die temperature
> +
> +  Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ad5529r.pdf
> +

> +patternProperties:
> +  "^channel@([0-9]|1[0-5])$":

Sashiko commented that this should be hex.  Why the forcing to decimal?


^ permalink raw reply

* Re: [PATCH v3 2/2] media: i2c: imx678: Add driver for Sony IMX678
From: Tarang Raval @ 2026-05-22 17:01 UTC (permalink / raw)
  To: Jai Luthra, Mauro Carvalho Chehab, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sakari Ailus, Laurent Pinchart,
	Kieran Bingham
  Cc: Lachlan Michael, Ryuichi Tadano, Kengo Hayasaka,
	linux-media@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <20260520-imx678-v3-2-8b5f9676486e@ideasonboard.com>

Hi Jai,

I noticed a few issues and also have one question. Could you please help me
understand that part?

Please check the comments below.

> Add a V4L2 subdev driver for the Sony IMX678 image sensor.
>
> IMX678 is a diagonal 8.86 mm (Type 1/1.8) CMOS active pixel type
> solid-state image sensor with a square pixel array and 8.40 M effective
> pixels.
>
> The following features are supported by the driver:
> - Monochrome and Color (Bayer filter) variants
> - Multiple input clock frequencies supported
> - Multiple link frequencies supported
> - VBLANK and HBLANK control for variable framerate
> - Freely configurable crop rectangle through S_SELECTION ioctl
> - Configurable resolution with 2x2 binning (for the current crop)
>   through S_FMT ioctl
> - VFLIP and HFLIP control for flipping readout
> - Test pattern control support
> - Exposure and gain control
> - MIPI RAW12 output
>
> Following features are not currently supported but may be added later:
> - Pixel-perfect crop reporting, account for the shift-by-1 when flipping
>   using HFLIP/VFLIP, which maintains the bayer readout order
> - Increased framerate (lower HMAX/VMAX) when cropping
> - MIPI RAW10 output mode
> - Embedded data stream
>
> Signed-off-by: Jai Luthra <jai.luthra@ideasonboard.com>
> ---

...

> +#define IMX678_REG_INCK_SEL             CCI_REG8(0x3014)
> +
> +/* Link Speed */
> +#define IMX678_REG_DATARATE_SEL         CCI_REG8(0x3015)
> +
> +/* Lane Count */
> +#define IMX678_REG_LANEMODE             CCI_REG8(0x3040)
> +
> +/*
> + * The internal readout clock runs at 74.25 Hz. In one cycle the AD reads 8

I think it's 74.25 MHz.

> + * pixels, thus giving us a rate of 74.25 * 8 = 594 MPix/s
> + */
> +#define IMX678_PIXEL_RATE              594000000
> +#define IMX678_PIX_PER_CLK             8
> +
> +/* VMAX - Frame Length in Lines */
> +#define IMX678_REG_VMAX                 CCI_REG24_LE(0x3028)
> +#define IMX678_VMAX_MAX                 0xfffff
> +#define IMX678_VMAX_DEFAULT             2250

...

> +static const int imx678_tpg_val[] = {
> +       IMX678_TPG_ALL_000,
> +       IMX678_TPG_ALL_000,
> +       IMX678_TPG_ALL_FFF,
> +       IMX678_TPG_ALL_555,
> +       IMX678_TPG_ALL_AAA,
> +       IMX678_TPG_TOG_555_AAA,
> +       IMX678_TPG_TOG_AAA_555,
> +       IMX678_TPG_TOG_000_555,
> +       IMX678_TPG_TOG_555_000,
> +       IMX678_TPG_TOG_000_FFF,
> +       IMX678_TPG_TOG_FFF_000,
> +       IMX678_TPG_H_COLOR_BARS,
> +       IMX678_TPG_V_COLOR_BARS,
> +};
> +
> +/* IMX678 Register List */
> +/* Common Modes */

You can remove these comments or keep only one of them.

> +static const struct cci_reg_sequence common_regs[] = {
> +       {IMX678_REG_THIN_V_EN, 0x00},
> +       {IMX678_REG_VCMODE, 0x01},
> +       {CCI_REG8(0x306B), 0x00},
> +       {IMX678_REG_GAIN_PGC_FIDMD, 0x01},
> +       {CCI_REG8(0x3460), 0x22},
> +       {CCI_REG8(0x355A), 0x64},

...

> +static void imx678_set_framing_limits(struct imx678 *imx678,
> +                                     struct v4l2_subdev_state *state)
> +{
> +       const struct v4l2_mbus_framefmt *format = imx678_state_format(state);
> +       s64 min_hblank, default_hblank, max_hblank, vblank;
> +       const u32 hmax_4lane = min_hmax_4lane[__ffs(imx678->link_freq_bitmap)];
> +       const u32 lane_scale = imx678->lane_mode == IMX678_LANEMODE_2L ? 2 : 1;
> +       const bool binning = imx678_state_binning(state);
> +       const u8 bpp = binning ? 10 : 12;
> +       u32 hmax, min_hmax;
> +
> +       imx678->vmax = IMX678_VMAX_DEFAULT;
> +       hmax = hmax_4lane * lane_scale;
> +
> +       /* HMAX can go lower when using 10bit AD for binning */
> +       min_hmax = (hmax * bpp) / 12;
> +       min_hblank = min_hmax * IMX678_PIX_PER_CLK - format->width;
> +       default_hblank = hmax * IMX678_PIX_PER_CLK - format->width;
> +       max_hblank = IMX678_HMAX_MAX * IMX678_PIX_PER_CLK - format->width;
> +
> +       __v4l2_ctrl_modify_range(imx678->hblank, min_hblank, max_hblank,
> +                                IMX678_PIX_PER_CLK, default_hblank);
> +       __v4l2_ctrl_s_ctrl(imx678->hblank, default_hblank);
> +
> +       vblank = imx678->vmax - format->height;
> +       __v4l2_ctrl_modify_range(imx678->vblank, vblank,
> +                                IMX678_VMAX_MAX - format->height, 2, vblank);
> +       __v4l2_ctrl_s_ctrl(imx678->vblank, IMX678_VMAX_DEFAULT - format->height);
> +
> +       __v4l2_ctrl_modify_range(imx678->exposure, IMX678_EXPOSURE_MIN,
> +                                imx678->vmax - IMX678_SHR_MIN, 1,
> +                                IMX678_EXPOSURE_DEFAULT);

This control operation can fail, so please check the error value.

Also, return the error by changing the return type accordingly.

> +}
> +
> +static int imx678_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +       struct imx678 *imx678 = container_of(ctrl->handler, struct imx678, ctrl_handler);
> +       struct v4l2_subdev_state *state;
> +       struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd);
> +       const struct v4l2_mbus_framefmt *format;
> +       int ret = 0;
> +
> +       state = v4l2_subdev_get_locked_active_state(&imx678->sd);
> +       format = imx678_state_format(state);
> +
> +       if (ctrl->id == V4L2_CID_VBLANK) {
> +               u32 current_exposure = imx678->exposure->cur.val;
> +
> +               imx678->vmax = format->height + ctrl->val;
> +
> +               current_exposure = clamp_t(u32, current_exposure, IMX678_EXPOSURE_MIN,
> +                                          imx678->vmax - IMX678_SHR_MIN);
> +               __v4l2_ctrl_modify_range(imx678->exposure, IMX678_EXPOSURE_MIN,
> +                                        imx678->vmax - IMX678_SHR_MIN, 1,
> +                                        current_exposure);

Same here, please check the error value.

> +       }
> +
> +       /*
> +        * Applying V4L2 control value only happens
> +        * when power is up for streaming
> +        */
> +       if (pm_runtime_get_if_in_use(&client->dev) == 0)

Use pm_runtime_get_if_active.

> +               return 0;
> +
> +       switch (ctrl->id) {
> +       case V4L2_CID_VBLANK:
> +               cci_write(imx678->cci, IMX678_REG_VMAX, imx678->vmax, &ret);
> +               fallthrough; /* SHR = VMAX - exposure, so update it */
> +       case V4L2_CID_EXPOSURE: {
> +               u32 shr = imx678->vmax - imx678->exposure->val;
> +
> +               cci_write(imx678->cci, IMX678_REG_SHR, shr, &ret);
> +               break;
> +       }
> +       case V4L2_CID_ANALOGUE_GAIN:
> +               cci_write(imx678->cci, IMX678_REG_ANALOG_GAIN, ctrl->val, &ret);
> +               break;
> +       case V4L2_CID_HBLANK: {
> +               u32 hmax = (format->width + ctrl->val) / IMX678_PIX_PER_CLK;
> +
> +               cci_write(imx678->cci, IMX678_REG_HMAX, hmax, &ret);
> +               break;
> +       }
> +       case V4L2_CID_TEST_PATTERN: {
> +               cci_write(imx678->cci, IMX678_REG_TPG_COLORWIDTH,
> +                         IMX678_TPG_COLORWIDTH_160PIX, &ret);
> +               cci_write(imx678->cci, IMX678_REG_TPG_PATSEL_DUOUT,
> +                         imx678_tpg_val[ctrl->val], &ret);
> +               cci_write(imx678->cci, IMX678_REG_TPG_EN_DUOUT, (ctrl->val) ? 1 : 0,
> +                         &ret);
> +               break;
> +       }
> +       case V4L2_CID_HFLIP:
> +               cci_write(imx678->cci, IMX678_REG_WINMODEH, ctrl->val, &ret);
> +               break;
> +       case V4L2_CID_VFLIP:
> +               cci_write(imx678->cci, IMX678_REG_WINMODEV, ctrl->val, &ret);
> +               break;
> +       default:
> +               dev_warn(&client->dev,
> +                        "ctrl(id:0x%x,val:0x%x) is not handled\n",
> +                        ctrl->id, ctrl->val);
> +               break;
> +       }
> +
> +       pm_runtime_put(&client->dev);
> +
> +       return ret;
> +}
> +
> +static const struct v4l2_ctrl_ops imx678_ctrl_ops = {
> +       .s_ctrl = imx678_set_ctrl,
> +};

...

> +static int imx678_set_selection(struct v4l2_subdev *sd,
> +                               struct v4l2_subdev_state *sd_state,
> +                               struct v4l2_subdev_selection *sel)
> +{
> +       struct imx678 *imx678 = to_imx678(sd);
> +       struct v4l2_rect *crop;
> +       struct v4l2_rect rect;
> +
> +       if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != 0)
> +               return -EINVAL;
> +
> +       if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
> +           v4l2_subdev_is_streaming(sd))
> +               return -EBUSY;
> +
> +       /* Align left, top to 4 */
> +       rect.left = clamp_t(s32, ALIGN(sel->r.left, IMX678_CROP_HST_ALIGN),
> +                           imx678_active_area.left,
> +                           imx678_active_area.width - IMX678_PIXEL_ARRAY_MIN_WIDTH);

You are ignoring the active_area offset here; please correct it.

In imx296, crop bounds start at (0, 0), so no offset handling is needed there.

You can refer to my patch:
https://lore.kernel.org/linux-media/20260424092554.26130-4-elgin.perumbilly@siliconsignals.io/#t

> +       rect.top = clamp_t(s32, ALIGN(sel->r.top, IMX678_CROP_VST_ALIGN),
> +                          imx678_active_area.top,
> +                          imx678_active_area.height - IMX678_PIXEL_ARRAY_MIN_HEIGHT);
> +       /* Align width to 16 and height to 4 */
> +       rect.width = clamp_t(u32, ALIGN(sel->r.width, IMX678_CROP_HWIDTH_ALIGN),
> +                            IMX678_PIXEL_ARRAY_MIN_WIDTH, imx678_active_area.width);
> +       rect.height = clamp_t(u32, ALIGN(sel->r.height, IMX678_CROP_VWIDTH_ALIGN),
> +                             IMX678_PIXEL_ARRAY_MIN_HEIGHT, imx678_active_area.height);
> +
> +       rect.width = min_t(u32, rect.width, imx678_native_area.width - rect.left);
> +       rect.height = min_t(u32, rect.height, imx678_native_area.height - rect.top);
> +
> +       crop = v4l2_subdev_state_get_crop(sd_state, sel->pad);
> +
> +       if (rect.width != crop->width || rect.height != crop->height) {
> +               struct v4l2_mbus_framefmt *format =
> +                       v4l2_subdev_state_get_format(sd_state, sel->pad);
> +               format->width = rect.width;
> +               format->height = rect.height;

Why are we not checking here whether binning mode is currently enabled?

Suppose binning mode is enabled, and then userspace changes the crop.

With the below lines:

format->width = rect.width;
format->height = rect.height;

the format size becomes equal to the crop size, which silently disables binning.

Am I missing something here?

> +       }
> +
> +       *crop = rect;
> +       sel->r = *crop;
> +
> +       if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
> +               imx678_set_framing_limits(imx678, sd_state);
> +
> +       return 0;
> +}
> +
> +static int imx678_init_state(struct v4l2_subdev *sd,
> +                            struct v4l2_subdev_state *state)
> +{
> +       struct imx678 *imx678 = to_imx678(sd);
> +       struct v4l2_subdev_selection sel = {
> +               .which = V4L2_SUBDEV_FORMAT_TRY,
> +               .target = V4L2_SEL_TGT_CROP,
> +               .r = imx678_active_area,
> +       };
> +       struct v4l2_subdev_format fmt = {
> +               .which = V4L2_SUBDEV_FORMAT_TRY,
> +               .pad = 0,
> +               .format = {
> +                       .code = imx678_default_mbus_code(imx678),
> +                       .width = imx678_active_area.width,
> +                       .height = imx678_active_area.height,
> +               },
> +       };
> +
> +       imx678_set_selection(sd, state, &sel);
> +       imx678_set_pad_format(sd, state, &fmt);
> +
> +       return 0;
> +}

...

> +static int imx678_enable_streams(struct v4l2_subdev *sd,
> +                                struct v4l2_subdev_state *state, u32 pad,
> +                                u64 mask)
> +{
> +       struct i2c_client *client = v4l2_get_subdevdata(sd);
> +       struct imx678 *imx678 = to_imx678(sd);
> +       const struct v4l2_rect *crop = imx678_state_crop(state);
> +       const bool binning = imx678_state_binning(state);
> +       int ret = 0;

You can omit the initialization here.

> +
> +       ret = pm_runtime_resume_and_get(&client->dev);
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = imx678_program_window(imx678, crop, binning);
> +       if (ret) {
> +               dev_err(&client->dev, "%s failed to set mode\n", __func__);
> +               goto err_rpm_put;
> +       }
> +
> +       ret = __v4l2_ctrl_handler_setup(imx678->sd.ctrl_handler);
> +       if (ret) {
> +               dev_err(&client->dev, "%s failed to apply user values\n", __func__);
> +               goto err_rpm_put;
> +       }
> +
> +       cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STREAMING, &ret);
> +       usleep_range(IMX678_STREAM_DELAY_US, IMX678_STREAM_DELAY_US +
> +                    IMX678_STREAM_DELAY_RANGE_US);
> +       cci_write(imx678->cci, IMX678_REG_XMSTA, 0x00, &ret);
> +
> +       if (ret) {
> +               dev_err(&client->dev, "%s failed to start streaming\n", __func__);
> +               goto err_rpm_put;
> +       }
> +
> +       return 0;
> +
> +err_rpm_put:
> +       pm_runtime_put(&client->dev);
> +
> +       return ret;
> +}

...

> +static const struct v4l2_subdev_core_ops imx678_core_ops = {
> +       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
> +       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
> +};

Drop this

See: https://lore.kernel.org/linux-media/20241029162106.3005800-1-tomm.merciai@gmail.com/

> +static const struct v4l2_subdev_video_ops imx678_video_ops = {
> +       .s_stream = v4l2_subdev_s_stream_helper,
> +};
> +
> +static const struct v4l2_subdev_pad_ops imx678_pad_ops = {
> +       .enum_mbus_code = imx678_enum_mbus_code,
> +       .get_fmt = v4l2_subdev_get_fmt,
> +       .set_fmt = imx678_set_pad_format,
> +       .get_selection = imx678_get_selection,
> +       .set_selection = imx678_set_selection,
> +       .enum_frame_size = imx678_enum_frame_size,
> +       .enable_streams = imx678_enable_streams,
> +       .disable_streams = imx678_disable_streams,
> +};

...

> +static int imx678_probe(struct i2c_client *client)
> +{
> +       struct device *dev = &client->dev;
> +       struct imx678 *imx678;
> +       int ret, i;
> +
> +       imx678 = devm_kzalloc(&client->dev, sizeof(*imx678), GFP_KERNEL);
> +       if (!imx678)
> +               return -ENOMEM;
> +
> +       v4l2_i2c_subdev_init(&imx678->sd, client, &imx678_subdev_ops);
> +
> +       imx678->cci = devm_cci_regmap_init_i2c(client, 16);
> +       if (IS_ERR(imx678->cci))
> +               return dev_err_probe(dev, PTR_ERR(imx678->cci),
> +                                    "failed to init CCI\n");
> +
> +       if (imx678_check_hwcfg(dev, imx678))
> +               return -EINVAL;
> +
> +       imx678->xclk = devm_v4l2_sensor_clk_get(dev, NULL);
> +       if (IS_ERR(imx678->xclk))
> +               return dev_err_probe(dev, PTR_ERR(imx678->xclk),
> +                                    "failed to get xclk\n");
> +
> +       imx678->xclk_freq = clk_get_rate(imx678->xclk);
> +
> +       for (i = 0; i < ARRAY_SIZE(imx678_inck_table); ++i) {
> +               if (imx678_inck_table[i].xclk_hz == imx678->xclk_freq) {
> +                       imx678->inck_sel_val = imx678_inck_table[i].inck_sel;
> +                       break;
> +               }
> +       }
> +
> +       if (i == ARRAY_SIZE(imx678_inck_table))
> +               return dev_err_probe(dev, -EINVAL,
> +                                    "unsupported XCLK rate %u Hz\n",
> +                                    imx678->xclk_freq);
> +
> +       ret = imx678_get_regulators(imx678);
> +       if (ret)
> +               return dev_err_probe(dev, ret, "failed to get regulators\n");
> +
> +       imx678->reset_gpio = devm_gpiod_get_optional(dev, "reset",
> +                                                    GPIOD_OUT_HIGH);
> +       if (IS_ERR(imx678->reset_gpio))
> +               return dev_err_probe(dev, PTR_ERR(imx678->reset_gpio),
> +                                    "failed to get reset GPIO\n");
> +
> +       ret = imx678_power_on(dev);
> +       if (ret)
> +               return ret;
> +
> +       ret = imx678_identify_model(imx678);
> +       if (ret)
> +               goto error_power_off;
> +
> +       pm_runtime_set_active(dev);
> +       pm_runtime_enable(dev);
> +
> +       ret = imx678_init_controls(imx678);
> +       if (ret)
> +               goto error_pm_runtime;
> +
> +       imx678->sd.internal_ops = &imx678_internal_ops;
> +       imx678->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> +                               V4L2_SUBDEV_FL_HAS_EVENTS;
> +       imx678->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
> +
> +       imx678->pad.flags = MEDIA_PAD_FL_SOURCE;
> +
> +       ret = media_entity_pads_init(&imx678->sd.entity, 1, &imx678->pad);
> +       if (ret) {
> +               dev_err(dev, "failed to init entity pads: %d\n", ret);

Use dev_err_probe.

> +               goto error_handler_free;
> +       }
> +
> +       imx678->sd.state_lock = imx678->ctrl_handler.lock;
> +       ret = v4l2_subdev_init_finalize(&imx678->sd);
> +       if (ret < 0) {
> +               dev_err(dev, "subdev init error\n");

Use dev_err_probe.

> +               goto error_media_entity;
> +       }
> +
> +       ret = v4l2_async_register_subdev_sensor(&imx678->sd);
> +       if (ret < 0) {
> +               dev_err(dev, "failed to register sensor sub-device: %d\n", ret);

Use dev_err_probe.

> +               goto error_subdev_cleanup;
> +       }
> +
> +       pm_runtime_idle(dev);
> +
> +       return 0;
> +
> +error_subdev_cleanup:
> +       v4l2_subdev_cleanup(&imx678->sd);
> +
> +error_media_entity:
> +       media_entity_cleanup(&imx678->sd.entity);
> +
> +error_handler_free:
> +       imx678_free_controls(imx678);
> +
> +error_pm_runtime:
> +       pm_runtime_disable(&client->dev);
> +       pm_runtime_set_suspended(&client->dev);
> +
> +error_power_off:
> +       imx678_power_off(&client->dev);
> +
> +       return ret;
> +}
> +
> +static void imx678_remove(struct i2c_client *client)
> +{
> +       struct v4l2_subdev *sd = i2c_get_clientdata(client);
> +       struct imx678 *imx678 = to_imx678(sd);
> +
> +       v4l2_async_unregister_subdev(sd);
> +       v4l2_subdev_cleanup(sd);
> +       media_entity_cleanup(&sd->entity);
> +       imx678_free_controls(imx678);
> +
> +       pm_runtime_disable(&client->dev);
> +       if (!pm_runtime_status_suspended(&client->dev))
> +               imx678_power_off(&client->dev);
> +       pm_runtime_set_suspended(&client->dev);
> +}
> +
> +static const struct dev_pm_ops imx678_pm_ops = {
> +       SET_RUNTIME_PM_OPS(imx678_power_off, imx678_power_on, NULL)
> +};
> +
> +static const struct of_device_id imx678_of_match[] = {
> +       { .compatible = "sony,imx678" },
> +       { .compatible = "sony,imx678-aamr", .data = &imx678_aamr_info },
> +       { .compatible = "sony,imx678-aaqr", .data = &imx678_aaqr_info },
> +       { /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, imx678_of_match);
> +
> +static struct i2c_driver imx678_i2c_driver = {
> +       .driver = {
> +               .name = "imx678",
> +               .of_match_table = imx678_of_match,
> +               .pm = &imx678_pm_ops,
> +       },
> +       .probe = imx678_probe,
> +       .remove = imx678_remove,
> +};
> +
> +module_i2c_driver(imx678_i2c_driver);
> +
> +MODULE_AUTHOR("Will Whang <will@willwhang.com>");
> +MODULE_AUTHOR("Tetsuya NOMURA <tetsuya.nomura@soho-enterprise.com>");
> +MODULE_AUTHOR("Jai Luthra <jai.luthra@ideasonboard.com>");
> +MODULE_DESCRIPTION("Sony imx678 sensor driver");
> +MODULE_LICENSE("GPL");
>
> --
> 2.54.0

Best Regards,
Tarang

^ permalink raw reply

* Re: [PATCH v7 1/2] dt-bindings: phy: qcom: Add CSI2 C-PHY/DPHY schema
From: Rob Herring (Arm) @ 2026-05-22 16:49 UTC (permalink / raw)
  To: Bryan O'Donoghue
  Cc: linux-kernel, Bryan O'Donoghue, Kishon Vijay Abraham I,
	Neil Armstrong, linux-phy, linux-media, Krzysztof Kozlowski,
	Conor Dooley, linux-arm-msm, Vinod Koul, devicetree,
	Vladimir Zapolskiy
In-Reply-To: <20260522-x1e-csi2-phy-v7-1-79cb1280fad6@linaro.org>


On Fri, 22 May 2026 15:45:09 +0100, Bryan O'Donoghue wrote:
> Add a base schema initially compatible with x1e80100 to describe MIPI CSI2
> PHY devices.
> 
> The hardware can support both CPHY, DPHY and a special split-mode DPHY.
> 
> The schema here defines three ports:
> 
> port@0:
>     The first input port where a sensor is always required.
> 
> port@1:
>     A second optional input port which if present implies DPHY split-mode.
> 
> port@2:
>     A third always required output port which connects to the controller.
> 
> The CSIPHY devices have their own pinouts on the SoC as well as their own
> individual voltage rails.
> 
> The need to model voltage rails on a per-PHY basis leads us to define
> CSIPHY devices as individual nodes.
> 
> Two nice outcomes in terms of schema and DT arise from this change.
> 
> 1. The ability to define on a per-PHY basis voltage rails.
> 2. The ability to require those voltage.
> 
> We have had a complete bodge upstream for this where a single set of
> voltage rail for all CSIPHYs has been buried inside of CAMSS.
> 
> Much like the I2C bus which is dedicated to Camera sensors - the CCI bus in
> CAMSS parlance, the CSIPHY devices should be individually modelled.
> 
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> ---
>  .../bindings/phy/qcom,x1e80100-csi2-phy.yaml       | 208 +++++++++++++++++++++
>  1 file changed, 208 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml: port@0: Missing additionalProperties/unevaluatedProperties constraint
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml: port@1: Missing additionalProperties/unevaluatedProperties constraint
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.yaml: port@2: Missing additionalProperties/unevaluatedProperties constraint
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/phy/qcom,x1e80100-csi2-phy.example.dtb: csiphy@ace4000 (qcom,x1e80100-csi2-phy): ports:port@2:endpoint: Unevaluated properties are not allowed ('clock-lanes', 'data-lanes' were unexpected)
	from schema $id: http://devicetree.org/schemas/phy/qcom,x1e80100-csi2-phy.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20260522-x1e-csi2-phy-v7-1-79cb1280fad6@linaro.org

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply

* Re: [PATCH v3 06/11] arm64: dts: ti: k3-am62-verdin: Add Toradex Capacitive Touch Display 7" DSI
From: sashiko-bot @ 2026-05-22 16:42 UTC (permalink / raw)
  To: Vitor Soares; +Cc: devicetree, robh, conor+dt
In-Reply-To: <20260522161105.277519-19-ivitro@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The touchscreen controller interrupt is incorrectly configured as `IRQ_TYPE_EDGE_RISING` for an active-low hardware signal (`TOUCH_INT#`).
--

commit 6d0e51f377bc6e97b677eab7ee35406d648f228c
Author: Vitor Soares <vitor.soares@toradex.com>

arm64: dts: ti: k3-am62-verdin: Add Toradex Capacitive Touch Display 7" DSI

This commit adds a device tree overlay for the Toradex Capacitive Touch
Display 7" DSI on the Verdin DSI_1 interface. The display uses an SN65DSI83
bridge and an Ilitek ILI2132 capacitive touch controller.

Link: https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-7inch-dsi
Link: https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter/

> diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-7inch-dsi.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-7inch-dsi.dtso
> new file mode 100644
> index 0000000000000..1f44133f9ca66
> --- /dev/null
> +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-7inch-dsi.dtso

[ ... ]

> +	touchscreen@41 {
> +		compatible = "ilitek,ili2132";
> +		reg = <0x41>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_dsi1_int>, <&pinctrl_i2s_2_bclk_gpio>;
> +		/* Verdin GPIO_9_DSI (SODIMM 17) - TOUCH_INT# */
> +		interrupt-parent = <&main_gpio1>;
> +		interrupts = <49 IRQ_TYPE_EDGE_RISING>;

[Severity: Medium]
Does this interrupt type cause a deadlock with the touchscreen controller?

The comment indicates the hardware signal is active-low (TOUCH_INT#), which
is typical for I2C touch controllers like the ILI213x series. If the touch
controller asserts the interrupt by driving the line low and waits for the
host to read the data via I2C before releasing the line high, configuring
the host to wait for a rising edge could result in the interrupt handler
never being invoked.

Should this use an active-low or falling edge trigger instead?

> +		/* Verdin I2S_2_BCLK (SODIMM 42) - TOUCH_RESET# */
> +		reset-gpios = <&main_gpio0 35 GPIO_ACTIVE_LOW>;
> +	};
> +};

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260522161105.277519-13-ivitro@gmail.com?part=6

^ permalink raw reply

* Re: [PATCH v3 05/11] arm64: dts: ti: k3-am62-verdin: Add Toradex Capacitive Touch Display 10.1" DSI
From: sashiko-bot @ 2026-05-22 16:36 UTC (permalink / raw)
  To: Vitor Soares; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260522161105.277519-18-ivitro@gmail.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Incorrect interrupt trigger edge configured for the active-low touch controller interrupt.
--

commit fab3f681a92c02497462fd11a6e8c83f2e40950e
Author: Vitor Soares <vitor.soares@toradex.com>

arm64: dts: ti: k3-am62-verdin: Add Toradex Capacitive Touch Display 10.1" DSI

This commit adds a device tree overlay for the Toradex Capacitive Touch
Display 10.1" on the Verdin DSI_1 interface. It configures the SN65DSI83
bridge, Riverdi LCD panel, and Ilitek ILI2132 touch controller, while
providing combined DTBs in the Makefile.

Link: https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-101inch-dsi
Link: https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter/

> diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-10inch-dsi.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-10inch-dsi.dtso
> new file mode 100644
> index 0000000000000..ed66feec94624
> --- /dev/null
> +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-10inch-dsi.dtso

[ ... ]

> +	touchscreen@41 {
> +		compatible = "ilitek,ili2132";
> +		reg = <0x41>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&pinctrl_dsi1_int>, <&pinctrl_i2s_2_bclk_gpio>;
> +		/* Verdin GPIO_9_DSI (SODIMM 17) - TOUCH_INT# */
> +		interrupt-parent = <&main_gpio1>;
> +		interrupts = <49 IRQ_TYPE_EDGE_RISING>;

[Severity: Medium]
The comment indicates the interrupt pin is TOUCH_INT#, which typically denotes
an active-low signal.

Is IRQ_TYPE_EDGE_RISING the correct trigger here?

Triggering on a rising edge for an active-low signal means the interrupt will
fire only upon de-assertion. If the touch controller holds the line low until
the event is read via I2C, waiting for a rising edge could delay or prevent
the touch input event from being processed. Should this be configured as
IRQ_TYPE_EDGE_FALLING instead?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260522161105.277519-13-ivitro@gmail.com?part=5

^ permalink raw reply

* Re: [PATCH RFC 2/3] iio: osf: add Open Sensor Fusion UART IIO driver
From: Jonathan Cameron @ 2026-05-22 16:24 UTC (permalink / raw)
  To: Jinseob Kim
  Cc: linux-iio, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	linux-kernel
In-Reply-To: <20260520072843.3593-3-kimjinseob88@gmail.com>

On Wed, 20 May 2026 16:28:42 +0900
Jinseob Kim <kimjinseob88@gmail.com> wrote:

> Add the initial Open Sensor Fusion UART IIO driver.
> 
> This includes the protocol v0 parser, OSF0 stream assembler, core
> capability/sample cache, serdev UART transport, IIO read_raw path, and
> software kfifo buffer support.
> 
> The first RFC keeps the driver code in one patch to avoid intermediate
> non-buildable states. The internal files still separate protocol, stream,
> core, transport, and IIO code.
> 
> The tested path is STM32F405 test firmware OSF UART stream to Raspberry Pi
> serdev, then IIO read_raw and buffered userspace reads.
> 
> Not included here: real sensor reads, USB transport, fusion/AHRS/Kalman,
> runtime capability removal, or production timestamp correlation.
> 
There are several things in here I don't follow.  Why do we not
push the data directly to the iio devices when it shows up?
There seems to be a queue in between that I don't understand the purpose
of - that just seems to mean async handling where synchronous should
be fine.

Anyhow, as I mentioned this review is somewhat superficial given the driver
needs a lot of work to get it into a more reviewable state.
In particular break it up into more sensible sized chunks, building up
functionality from device discovery to actually registering IIO devices and then
adding additional features on that base.

> Signed-off-by: Jinseob Kim <kimjinseob88@gmail.com>

> diff --git a/drivers/iio/opensensorfusion/osf_core.c b/drivers/iio/opensensorfusion/osf_core.c
> new file mode 100644
> index 000000000..fd2eccefc
> --- /dev/null
> +++ b/drivers/iio/opensensorfusion/osf_core.c
> @@ -0,0 +1,334 @@

> +
> +static int osf_core_handle_sensor_sample(struct osf_device *osf,
> +					 const struct osf_frame *frame)
> +{
> +	osf_sample_callback_t callback;
> +	void *callback_context;
> +	struct osf_latest_sample *latest;
> +	struct osf_sample_event event = { };
> +	struct osf_sensor_sample sample;
> +	s32 values[OSF_MAX_SAMPLE_CHANNELS] = { };
> +	unsigned long flags;
> +	unsigned int i;
> +	int ret;
> +
> +	ret = osf_protocol_decode_sensor_sample(frame, &sample);
> +	if (ret)
> +		return ret;
> +
> +	if (sample.channel_count > OSF_MAX_SAMPLE_CHANNELS)
> +		return -E2BIG;
> +
> +	for (i = 0; i < sample.channel_count; i++) {
> +		ret = osf_protocol_sensor_sample_value(&sample, i, &values[i]);
This converts to CPU endian. That's fine but then your channels aren't little endian.
> +		if (ret)
> +			return ret;
> +	}
> +
> +	event.sensor_type = sample.sensor_type;
> +	event.sensor_index = sample.sensor_index;
> +	event.channel_count = sample.channel_count;
> +	event.sample_format = sample.sample_format;
> +	event.scale_nano = sample.scale_nano;
> +	event.sequence = frame->sequence;
> +	event.timestamp_us = frame->timestamp_us;
> +	event.host_timestamp_ns = ktime_get_ns();

For IIO stuff we have (for weird historical reasons) rather complex clock
handling for timestamps. Please follow that.

> +	for (i = 0; i < sample.channel_count; i++)
> +		event.values[i] = values[i];
> +
> +	spin_lock_irqsave(&osf->lock, flags);
> +	latest = osf_core_find_latest_sample(osf, sample.sensor_type,
> +					     sample.sensor_index, true);
> +	if (!latest) {
> +		spin_unlock_irqrestore(&osf->lock, flags);
> +		return -ENOSPC;
> +	}
> +
> +	osf_core_store_latest_sample(latest, &sample, values, frame);
> +	osf_core_store_latest_sample(&osf->latest_sample, &sample, values,
> +				     frame);
> +	osf->last_sequence = frame->sequence;
> +	callback = osf->sample_callback;
> +	callback_context = osf->sample_callback_context;
> +	spin_unlock_irqrestore(&osf->lock, flags);
> +
> +	if (callback)
> +		callback(callback_context, &event);
> +
> +	return 0;
> +}

> +
> +int osf_core_read_latest_sample(struct osf_device *osf, u16 sensor_type,
> +				u16 sensor_index, unsigned int channel,
> +				s32 *value)
> +{
> +	const struct osf_latest_sample *latest;
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	if (!osf || !value)
> +		return -EINVAL;
> +
> +	spin_lock_irqsave(&osf->lock, flags);

Use guard() and see if you can relax to a mutex. I haven't really worked
out the flow in here yet so maybe you can't.

> +	latest = osf_core_find_latest_sample(osf, sensor_type,
> +					     sensor_index, false);
> +	if (!latest)
> +		latest = &osf->latest_sample;
> +
> +	if (!latest->valid) {
> +		ret = -ENODATA;
> +		goto out_unlock;
> +	}
> +
> +	if (latest->sensor_type != sensor_type ||
> +	    latest->sensor_index != sensor_index) {
> +		ret = -ENODATA;
> +		goto out_unlock;
> +	}
> +
> +	if (channel >= latest->channel_count) {
> +		ret = -ENODATA;
> +		goto out_unlock;
> +	}
> +
> +	*value = latest->values[channel];
> +
> +out_unlock:
> +	spin_unlock_irqrestore(&osf->lock, flags);
> +
> +	return ret;
> +}

> +
> +bool osf_core_capability_sequence(struct osf_device *osf, u64 *sequence)
> +{
> +	unsigned long flags;
> +	bool valid;
> +
> +	if (!osf || !sequence)
> +		return false;
> +
> +	spin_lock_irqsave(&osf->lock, flags);
> +	valid = osf->capability_cache.valid;
> +	if (valid)
> +		*sequence = osf->capability_cache.sequence;
use guard() above
and 	if (valid)
		return false;

	*sequence = ..
	return true;

That way the 'error' path is out of line and can be quickly ignored by readers.
> +	spin_unlock_irqrestore(&osf->lock, flags);
> +
> +	return valid;
> +}
> +
> +void osf_core_set_sample_callback(struct osf_device *osf,
> +				  osf_sample_callback_t callback,
> +				  void *context)
> +{
> +	unsigned long flags;
> +
> +	if (!osf)
> +		return;
> +
> +	spin_lock_irqsave(&osf->lock, flags);
Use guard() for these probably.
> +	osf->sample_callback = callback;
> +	osf->sample_callback_context = context;
> +	spin_unlock_irqrestore(&osf->lock, flags);
> +}
> +
> +static int __init osf_core_init(void)
> +{
> +	return osf_serdev_register_driver();
> +}
> +
> +static void __exit osf_core_exit(void)
> +{
> +	osf_serdev_unregister_driver();
> +}
This smells like code break out not making sense. I'd
expect to see the driver_structure right next to these.

> +
> +module_init(osf_core_init);
> +module_exit(osf_core_exit);

> diff --git a/drivers/iio/opensensorfusion/osf_iio.c b/drivers/iio/opensensorfusion/osf_iio.c
> new file mode 100644
> index 000000000..3d2674e43
> --- /dev/null
> +++ b/drivers/iio/opensensorfusion/osf_iio.c
> @@ -0,0 +1,268 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/bitops.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/kfifo_buf.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +
> +#include "osf_core.h"
> +#include "osf_iio.h"
> +
> +#define OSF_SCALE_NANO		1000000000U
NANO is defined in the kernel headers.

> +#define OSF_IIO_SCAN_BYTES						\
> +	(ALIGN(OSF_MAX_SAMPLE_CHANNELS * sizeof(s32), sizeof(s64)) +	\
> +	 sizeof(s64))
> +
> +struct osf_iio_sensor_spec {
> +	u16 sensor_type;
> +	u16 channel_count;
> +	const char *name;
> +	const struct iio_chan_spec *channels;
> +	unsigned int num_channels;
> +};
> +
> +struct osf_iio_state {
> +	const struct osf_iio_sensor_spec *spec;
> +	u32 scale_nano;
> +	u16 sensor_index;
> +	struct osf_device *osf;
> +};


> +int osf_iio_push_sample(struct iio_dev *indio_dev,
> +			const struct osf_sample_event *event)
> +{
> +	struct osf_iio_state *state;
> +	u8 scan[OSF_IIO_SCAN_BYTES] __aligned(8) = { };
we have macros for this. 
IIO_DECLARE_BUFFER_WITH_TS() which will give you a suitable sized
s32 array so you don't need the cast that follows.

Mind you the buffer is described as little endian so maybe
should be __le32


> +	s32 *scan_values = (s32 *)scan;
> +	unsigned int i;
> +
> +	if (!indio_dev || !event)
> +		return -EINVAL;
> +
> +	if (!iio_buffer_enabled(indio_dev))

I haven't checked, but this feels insufficient. Probably want to force the
device to stay in buffered mode.  iio_device_try_claim_buffer_mode()
(rarely used, but this may be one place that needs it).


> +		return 0;
> +
> +	state = iio_priv(indio_dev);
> +	if (event->sensor_type != state->spec->sensor_type ||
> +	    event->sensor_index != state->sensor_index)
> +		return -EINVAL;
> +
> +	if (event->sample_format != OSF_SAMPLE_FORMAT_S32 ||
> +	    event->channel_count != state->spec->channel_count ||
> +	    event->channel_count > OSF_MAX_SAMPLE_CHANNELS)
> +		return -EINVAL;
> +
> +	for (i = 0; i < event->channel_count; i++)
> +		scan_values[i] = event->values[i];
> +
> +	return iio_push_to_buffers_with_timestamp(indio_dev, scan,
> +						  event->host_timestamp_ns);

For new code iio_push_to_buffers_with_ts()   It has a bounds check that
this version doesn't have.

> +}
> +
> +int osf_iio_register_sensor(struct device *dev,
> +			    const struct osf_capability_entry *entry,
> +			    void *driver_data, struct iio_dev **indio_dev)
> +{
> +	const struct osf_iio_sensor_spec *spec;
> +	struct osf_iio_state *state;
> +	struct iio_dev *iio_dev;
> +	int ret;
> +
> +	if (!dev || !entry)
> +		return -EINVAL;
> +
> +	spec = osf_iio_find_sensor_spec(entry->sensor_type,
> +					entry->channel_count);
> +	if (!spec)
> +		return -EOPNOTSUPP;
> +
> +	if (entry->sample_format != OSF_SAMPLE_FORMAT_S32)
> +		return -EOPNOTSUPP;
> +
> +	iio_dev = devm_iio_device_alloc(dev, sizeof(*state));
> +	if (!iio_dev)
> +		return -ENOMEM;
> +
> +	state = iio_priv(iio_dev);
> +	state->spec = spec;
> +	state->scale_nano = entry->scale_nano;
> +	state->sensor_index = entry->sensor_index;
> +	state->osf = driver_data;
> +
> +	iio_dev->name = spec->name;

What does this end up as?  Should be something close to a part number
though in multifunction parts can include something about the type.

> +	iio_dev->info = &osf_iio_info;
> +	iio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;

Look at devm_iio_kfifo_buffer_setup() and what it does to this.

> +	iio_dev->channels = spec->channels;
> +	iio_dev->num_channels = spec->num_channels;
> +
> +	ret = devm_iio_kfifo_buffer_setup(dev, iio_dev, NULL);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_iio_device_register(dev, iio_dev);
> +	if (ret)
> +		return ret;
> +
> +	if (indio_dev)
> +		*indio_dev = iio_dev;

why would you call this function without?
For kernel code we don't defined against nonsensical parameters.
Catch those in review rather than complicating the code.

> +
> +	return 0;
> +}

> +#endif
> diff --git a/drivers/iio/opensensorfusion/osf_protocol.c b/drivers/iio/opensensorfusion/osf_protocol.c
> new file mode 100644
> index 000000000..8235d3af5
> --- /dev/null
> +++ b/drivers/iio/opensensorfusion/osf_protocol.c
> @@ -0,0 +1,234 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/crc32.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
> +#include "osf_protocol.h"
> +
> +#define OSF_CRC32_INIT		0xffffffffU
> +#define OSF_CRC32_XOROUT	0xffffffffU
GENMASK(31, 0)

No one likes counting fs.
> +
> +static u16 osf_get_le16(const u8 *buf)
> +{
> +	return buf[0] | buf[1] << 8;
> +}
> +
> +static u32 osf_get_le32(const u8 *buf)
> +{
> +	return (u32)buf[0] | (u32)buf[1] << 8 |
> +	       (u32)buf[2] << 16 | (u32)buf[3] << 24;
> +}
Another copy?  See comments on the one in osf_stream.c

> +
> +static u64 osf_get_le64(const u8 *buf)
> +{
> +	return (u64)osf_get_le32(buf) | (u64)osf_get_le32(buf + 4) << 32;
Looks like
get_unaligned_le64()?


> +}
>

> +int osf_protocol_decode_capability_entry(const struct osf_capability_report *report,
> +					 unsigned int index,
> +					 struct osf_capability_entry *entry)
> +{
> +	const u8 *payload;
> +
> +	if (!report || !report->entries || !entry)
> +		return -EINVAL;
> +
> +	if (index >= report->capability_count)
> +		return -ERANGE;
> +
> +	payload = report->entries + index * OSF_CAP_SENSOR_ENTRY_LEN;
> +	entry->sensor_type = osf_get_le16(payload);
> +	entry->sensor_index = osf_get_le16(payload + 2);
> +	entry->channel_count = osf_get_le16(payload + 4);
> +	entry->sample_format = osf_get_le16(payload + 6);
> +	entry->scale_nano = osf_get_le32(payload + 8);
> +	entry->flags = osf_get_le32(payload + 12);
> +	entry->reserved = osf_get_le32(payload + 16);

Easier to read as
	*entry = (struct osf_capability_entry) {
		.sensor_type = get_unaligned_le16(payload),
		.sensor_index = get_unaligned_le16(payload + 2),
	....

	};

Probably can apply similar in other places.

> +
> +	if (!osf_sensor_type_valid(entry->sensor_type))
> +		return -EPROTO;
> +
> +	if (entry->sample_format != OSF_SAMPLE_FORMAT_S32)
> +		return -EPROTO;
> +
> +	if (entry->flags & ~OSF_CAPABILITY_FLAGS_MASK)
> +		return -EPROTO;
> +
> +	if (entry->reserved)
> +		return -EPROTO;
> +
> +	return 0;
> +}


> diff --git a/drivers/iio/opensensorfusion/osf_serdev.c b/drivers/iio/opensensorfusion/osf_serdev.c
> new file mode 100644
> index 000000000..1827760c2
> --- /dev/null
> +++ b/drivers/iio/opensensorfusion/osf_serdev.c
> @@ -0,0 +1,354 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/atomic.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>

Not seeing this used. Maybe I missed something of specific.
I wouldn't expect there to be anything in a driver like this.


> +#include <linux/serdev.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <linux/workqueue.h>


> +
> +static int osf_serdev_register_iio(struct osf_serdev *osf_uart,
> +				   const struct osf_capability_entry *entry)
> +{
> +	struct device *dev = &osf_uart->serdev->dev;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +
> +	if (osf_serdev_iio_registered(osf_uart, entry))
> +		return 0;
> +
> +	if (!osf_iio_sensor_supported(entry->sensor_type, entry->channel_count) ||
> +	    entry->sample_format != OSF_SAMPLE_FORMAT_S32) {
> +		dev_dbg(dev,
> +			"ignoring unsupported capability sensor=%u index=%u channels=%u format=%u\n",
> +			entry->sensor_type, entry->sensor_index,
> +			entry->channel_count, entry->sample_format);
> +		return 0;
> +	}
> +
> +	if (osf_uart->iio_count >= ARRAY_SIZE(osf_uart->iio)) {
> +		dev_warn(dev, "IIO registration table full, ignoring sensor=%u index=%u\n",
> +			 entry->sensor_type, entry->sensor_index);
> +		return 0;
> +	}
> +
> +	ret = osf_iio_register_sensor(dev, entry, &osf_uart->osf, &indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	osf_uart->iio[osf_uart->iio_count].sensor_type = entry->sensor_type;
> +	osf_uart->iio[osf_uart->iio_count].sensor_index = entry->sensor_index;
> +	osf_uart->iio[osf_uart->iio_count].indio_dev = indio_dev;

	osf_uart->iio[osf_uart->iio_count++] = (struct osf_serdev_iio) {
		.sensor_type = entry->sensor_type,
		.sensor_index = entry->sensor_index,
		.indio_dev = indio_dev,
	};

> +	osf_uart->iio_count++;
> +
> +	return 1;
> +}
> +
> +static void osf_serdev_iio_register_work(struct work_struct *work)
> +{
> +	struct osf_serdev *osf_uart =
> +		container_of(work, struct osf_serdev, iio_register_work);
> +	struct device *dev = &osf_uart->serdev->dev;
> +	struct osf_capability_cache cache;
> +	unsigned int registered = 0;
> +	unsigned int i;
> +	int ret;
> +
> +	if (!osf_core_copy_capability_cache(&osf_uart->osf, &cache))
> +		return;
> +
> +	mutex_lock(&osf_uart->iio_lock);
I'd use guard(mutex)(); here

> +	for (i = 0; i < cache.capability_count; i++) {
> +		ret = osf_serdev_register_iio(osf_uart, &cache.entries[i]);
> +		if (ret) {
> +			if (ret > 0) {
> +				registered++;
> +				continue;
> +			}
> +
			Then

			if (ret < 0) {
				dev_err();
				return ret;
			}

			registered++;

> +			dev_err(dev,
> +				"failed to register IIO sensor=%u index=%u: %d\n",
> +				cache.entries[i].sensor_type,
> +				cache.entries[i].sensor_index, ret);
> +		}
> +	}
> +	mutex_unlock(&osf_uart->iio_lock);
> +
> +	if (registered)
With above, this only doesn't happen if the count was 0.  Maybe check that separately
so you can then do this unconditionally.

> +		dev_info(dev,
> +			 "registered %u Open Sensor Fusion IIO devices from capability report seq=%llu\n",
> +			 registered, (unsigned long long)cache.sequence);
> +}

> +
> +static int osf_serdev_probe(struct serdev_device *serdev)
> +{
> +	struct osf_serdev *osf_uart;
> +	unsigned int baudrate;
> +	int ret;
> +
> +	osf_uart = devm_kzalloc(&serdev->dev, sizeof(*osf_uart), GFP_KERNEL);
> +	if (!osf_uart)
> +		return -ENOMEM;
> +
> +	osf_uart->serdev = serdev;
> +	osf_core_init_device(&osf_uart->osf);
> +	osf_stream_init(&osf_uart->stream, &osf_uart->osf);
> +	INIT_WORK(&osf_uart->iio_register_work, osf_serdev_iio_register_work);
> +	INIT_WORK(&osf_uart->buffer_push_work, osf_serdev_buffer_push_work);
> +	mutex_init(&osf_uart->iio_lock);
> +	spin_lock_init(&osf_uart->sample_lock);
> +	atomic64_set(&osf_uart->capability_sequence_scheduled, -1);
> +	osf_core_set_sample_callback(&osf_uart->osf, osf_serdev_sample_ready,
> +				     osf_uart);
> +
> +	serdev_device_set_drvdata(serdev, osf_uart);
> +	serdev_device_set_client_ops(serdev, &osf_serdev_ops);
> +
> +	ret = serdev_device_open(serdev);
> +	if (ret)
> +		return ret;
> +
> +	baudrate = serdev_device_set_baudrate(serdev, OSF_SERDEV_BAUD);
> +	if (baudrate != OSF_SERDEV_BAUD)
> +		dev_warn(&serdev->dev, "requested %u baud, controller set %u\n",
> +			 OSF_SERDEV_BAUD, baudrate);
> +
> +	serdev_device_set_flow_control(serdev, false);
> +
> +	dev_info(&serdev->dev, "Open Sensor Fusion UART opened at %u baud\n",
> +		 OSF_SERDEV_BAUD);

Generally we try to avoid prints like this.  Is it useful to know the baud rate?
It's easy to tell if the rest worked.

> +
> +	return 0;
> +}
> +
> +static void osf_serdev_remove(struct serdev_device *serdev)
> +{
> +	struct osf_serdev *osf_uart = serdev_device_get_drvdata(serdev);
> +
> +	osf_core_set_sample_callback(&osf_uart->osf, NULL, NULL);
> +	serdev_device_close(serdev);
> +	cancel_work_sync(&osf_uart->iio_register_work);
> +	cancel_work_sync(&osf_uart->buffer_push_work);
> +	osf_stream_reset(&osf_uart->stream);
> +}

> +
> +int osf_serdev_register_driver(void)
> +{
> +	return serdev_device_driver_register(&osf_serdev_driver);
> +}
> +
> +void osf_serdev_unregister_driver(void)
> +{
> +	serdev_device_driver_unregister(&osf_serdev_driver);
> +}
As above, feels like the file break up is making this more complex.
These should be next to module_init and allow us of the macros
that generate that code for us.


> +#endif
> diff --git a/drivers/iio/opensensorfusion/osf_stream.c b/drivers/iio/opensensorfusion/osf_stream.c
> new file mode 100644
> index 000000000..e9addf70e
> --- /dev/null
> +++ b/drivers/iio/opensensorfusion/osf_stream.c
> @@ -0,0 +1,212 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <linux/types.h>
> +
> +#include "osf_core.h"
> +#include "osf_protocol.h"
> +#include "osf_stream.h"
> +
> +#define OSF_STREAM_MAGIC_LEN	4
> +#define OSF_STREAM_MAX_PAYLOAD_LEN				\
> +	(OSF_STREAM_MAX_FRAME_LEN - OSF_FRAME_HEADER_LEN - OSF_FRAME_CRC_LEN)
> +
> +static const u8 osf_stream_magic[OSF_STREAM_MAGIC_LEN] = {
> +	'O', 'S', 'F', '0',
> +};
> +
> +static u16 osf_stream_get_le16(const u8 *buf)
> +{
> +	return buf[0] | buf[1] << 8;
We have standard functions in the kernel for this. Don't reinvent the wheel.

get_unaligned_le16()

> +}
> +
> +static u32 osf_stream_get_le32(const u8 *buf)

Likewise.

> +{
> +	return (u32)buf[0] | (u32)buf[1] << 8 |
> +	       (u32)buf[2] << 16 | (u32)buf[3] << 24;
> +}

> +
> +static bool osf_stream_magic_match(const u8 *buf, size_t len)
> +{
> +	return !memcmp(buf, osf_stream_magic, len);

Just do this inline.  If it was stand alone the length match
would belong in here not at the caller.


> +}
> +
> +static size_t osf_stream_resync(struct osf_stream *stream)
> +{
> +	size_t old_len = stream->len;
> +	size_t match_len;
> +	size_t i;
> +
> +	for (i = 0; i < stream->len; i++) {
In modern kernel code can do something like:
	for (size_t i = 0; i < stream->len; i++)

> +		match_len = stream->len - i;
> +		if (match_len > OSF_STREAM_MAGIC_LEN)
> +			match_len = OSF_STREAM_MAGIC_LEN;

		match_len = min(match_len, OSF_STREAM_MAGIC_LEN);

> +
> +		if (osf_stream_magic_match(stream->buf + i, match_len)) {
> +			if (i)
> +				osf_stream_discard(stream, i);
I'd special case 0 as that's your 'good' path.
			if (i == 0)
				return 0; 

			osf_stream_discard(stream, i);
			return i;

> +			return i;
> +		}
> +	}
> +
> +	stream->len = 0;
Whilst this is a short cut, I'd still call osf_stream_discard() as then it
is obvious that this is also discarding. Failing that add a comment 
/* Discard the lot */


> +	return old_len;
Why is it useful to return old_len if failed to resync?
That's non obvious enough I think this needs documentation on what
the return value is.

I'd be tempted to return a bool for whether it succeeded and
pass a pointer to put how much was discarded in.  That
will make the condition below simpler.

> +}
> +
> +static int osf_stream_process(struct osf_stream *stream)
> +{
> +	struct osf_frame frame;
> +	size_t decoded_len;
> +	size_t discarded;
> +	size_t frame_len;
> +	u32 payload_len;
> +	int first_err = 0;
> +	int ret;
> +
> +	while (stream->len) {
> +		discarded = osf_stream_resync(stream);
> +		if (discarded) {
> +			stream->stats.bad_magic_resyncs++;
> +			stream->stats.dropped_bytes += discarded;
> +			if (!first_err)
> +				first_err = -EPROTO;
So if we resynced but discarded a few 
> +		}
> +
> +		if (!stream->len)

This took a bit of figuring out. It's the resync failed path. I'd rather
see an explicit return bool for that. The discarded variable can be
parameter as mentioned above.


> +			break;
> +
> +		if (stream->len < OSF_FRAME_HEADER_LEN) {
> +			stream->stats.partial_frames++;
> +			break;
> +		}
> +
> +		if (osf_stream_get_le16(stream->buf + 6) !=

		if (get_unaligned_le16(stream->buf + 6) != OSF_FRAME_HEADER_LEN) {

Slightly long lines are fine in IIO as long as they aren't too much past 80
and improve readability.


> +		    OSF_FRAME_HEADER_LEN) {
> +			stream->stats.dropped_bytes++;
> +			osf_stream_discard(stream, 1);

Needs a comment I think. Not obvious to me at all why you'd drop 1 byte.
Is the idea it forces a resync?  Might as well drop the magic string
in that case.  I'd add a helper for this so you can do something like..

osf_force_resync(stream); in all these cases or something easier
to follow than a 1 byte drop.


> +			if (!first_err)
> +				first_err = -EPROTO;
> +			continue;
> +		}
> +
> +		payload_len = osf_stream_get_le32(stream->buf + 10);

get_unaligned_le32()

> +		if (payload_len > OSF_STREAM_MAX_PAYLOAD_LEN) {
> +			stream->stats.dropped_bytes++;
> +			osf_stream_discard(stream, 1);
> +			if (!first_err)
> +				first_err = -EMSGSIZE;
> +			continue;
> +		}
> +
> +		frame_len = OSF_FRAME_HEADER_LEN + payload_len + OSF_FRAME_CRC_LEN;
> +		if (stream->len < frame_len) {
> +			stream->stats.partial_frames++;
> +			break;
> +		}
> +
> +		ret = osf_protocol_decode_frame(stream->buf, frame_len, &frame,
> +						&decoded_len);
> +		if (ret) {
> +			if (ret == -EBADMSG)
> +				stream->stats.bad_crc_frames++;
> +			stream->stats.dropped_bytes++;
> +			osf_stream_discard(stream, 1);
> +			if (!first_err)
> +				first_err = ret;
> +			continue;
> +		}
> +
> +		if (decoded_len != frame_len) {
> +			stream->stats.dropped_bytes++;
> +			osf_stream_discard(stream, 1);
> +			if (!first_err)
> +				first_err = -EMSGSIZE;
> +			continue;
> +		}
> +
> +		ret = osf_core_receive_frame(stream->osf, stream->buf, frame_len);
> +		if (ret) {
> +			osf_stream_discard(stream, frame_len);
> +			if (!first_err)
> +				first_err = ret;
> +			continue;
> +		}
> +
> +		stream->stats.valid_frames++;
> +		osf_stream_discard(stream, frame_len);
> +	}
> +
> +	return first_err;
> +}
> +
> +void osf_stream_init(struct osf_stream *stream, struct osf_device *osf)
> +{
> +	if (!stream)
> +		return;
> +
> +	stream->osf = osf;
> +	stream->len = 0;
> +	memset(&stream->stats, 0, sizeof(stream->stats));
> +}
> +
> +void osf_stream_reset(struct osf_stream *stream)
> +{
> +	if (stream) {
> +		stream->len = 0;
> +		memset(&stream->stats, 0, sizeof(stream->stats));
> +	}
> +}
> +
> +int osf_stream_receive_bytes(struct osf_stream *stream, const u8 *buf,
> +			     size_t len)
> +{
> +	size_t copy_len;
> +	size_t space;
> +	int first_err = 0;
> +	int ret;
> +
> +	if (!stream || !stream->osf || (!buf && len))
> +		return -EINVAL;
> +
> +	if (!len) {
> +		ret = osf_stream_process(stream);
> +		if (ret && !first_err)
> +			first_err = ret;
> +		return first_err;
> +	}
> +
> +	while (len) {
> +		space = OSF_STREAM_MAX_FRAME_LEN - stream->len;
> +		if (!space) {
> +			stream->stats.dropped_bytes++;
> +			osf_stream_discard(stream, 1);
> +			if (!first_err)
> +				first_err = -EMSGSIZE;
> +			continue;
> +		}
> +
> +		copy_len = len < space ? len : space;
> +		memcpy(stream->buf + stream->len, buf, copy_len);
> +		stream->len += copy_len;
> +		buf += copy_len;
> +		len -= copy_len;
> +
> +		ret = osf_stream_process(stream);
> +		if (ret && !first_err)
> +			first_err = ret;
> +	}
> +
> +	return first_err;
> +}


^ permalink raw reply

* Re: [PATCH V8 05/10] iio: imu: inv_icm42607: Add PM support for icm42607
From: Chris Morgan @ 2026-05-22 16:23 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Chris Morgan, linux-iio, andy, nuno.sa, dlechner,
	jean-baptiste.maneyrol, linux-rockchip, devicetree, heiko,
	conor+dt, krzk+dt, robh, andriy.shevchenko
In-Reply-To: <20260522120515.652661ed@jic23-huawei>

On Fri, May 22, 2026 at 12:05:15PM +0100, Jonathan Cameron wrote:
> 
> > >   
> > > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > index e9c81b52f9ef..bc0cefa2fb77 100644
> > > > --- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > @@ -9,6 +9,7 @@
> > > >  #include <linux/irq.h>
> > > >  #include <linux/module.h>
> > > >  #include <linux/mutex.h>
> > > > +#include <linux/pm_runtime.h>
> > > >  #include <linux/property.h>
> > > >  #include <linux/regmap.h>
> > > >  #include <linux/regulator/consumer.h>
> > > > @@ -72,6 +73,62 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
> > > >  };
> > > >  EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
> > > >  
> > > > +static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
> > > > +				      enum inv_icm42607_sensor_mode gyro,
> > > > +				      enum inv_icm42607_sensor_mode accel,
> > > > +				      bool temp, unsigned int *sleep_ms)
> > > > +{
> > > > +	enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode;
> > > > +	enum inv_icm42607_sensor_mode oldaccel = st->conf.accel.mode;
> > > > +	bool oldtemp = st->conf.temp_en;
> > > > +	unsigned int sleepval;
> > > > +	unsigned int val;
> > > > +	int ret;
> > > > +
> > > > +	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
> > > > +		return 0;
> > > > +
> > > > +	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro);
> > > > +	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
> > > > +	if (!temp)
> > > > +		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
> > > > +	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	st->conf.gyro.mode = gyro;
> > > > +	st->conf.accel.mode = accel;
> > > > +	st->conf.temp_en = temp;
> > > > +
> > > > +	sleepval = 0;
> > > > +	if (temp && !oldtemp) {
> > > > +		if (sleepval < INV_ICM42607_TEMP_STARTUP_TIME_MS)
> > > > +			sleepval = INV_ICM42607_TEMP_STARTUP_TIME_MS;  
> > > 		sleepval = max(sleepval,)
> > > or just assign it here if not later patches add stuff in between
> > > the assignment to 0 and here.  
> Wow I write some garbage English sometimes (no excuse, it is my
> native language!) 
> > 
> > I'm going to assign it to 0 here (unless you think I should define it
> > at the beginning as 0) and then tweak as needed. I think this code
> > here can be further optimized, especially if we make the assumption
> > that START and STOP time for each sensor is comparable (the datasheet
> > doesn't say, so I'm going to go with yes since that greatly simplifies
> > things).
> 
> I'm a bit lost. Suggestion was just to do
> 		sleepval = INV_ICM42607_TEMP_STARTUP_TIME_MS;
> as we know it is 0.   Probably not worth it though as ends up with fragile
> code.  Fine to keep it to what you have but use max() rather than
> if()
> 
> ...
> 
> > > > +static int inv_icm42607_resume(struct device *dev)
> > > > +{
> > > > +	struct inv_icm42607_state *st = dev_get_drvdata(dev);
> > > > +	int ret;
> > > > +
> > > > +	guard(mutex)(&st->lock);
> > > > +  
> > > Given the bunch of stuff we've run into recently around these
> > > I'm getting more paranoid.
> > > Similar to above, could you use pm_runtime_force_resume()
> > > You would need to gate stuff added later to not occur
> > > though if it wasn't runtime suspended.  
> > 
> > This I'm having trouble understanding. If I use
> > pm_force_runtime_resume() I'm assuming that either I got an error (in
> > which case I'd return the error) or the device is runtime resumed
> > after the call completes. If that's the case, wouldn't my suspend and
> > resume steps just be pm_force_runtime_suspend/resume, and enabling the
> > regulator (first for resume) or disabling the regulator (last for
> > suspend) as needed?
> 
> If you call pm_runtime_force_resume() it will do the right thing
> wrt to runtime PM state prior to suspend.  If it wasn't runtime suspended
> it will runtime resume - if it was it'll no do anything. It won't
> directly tell you which one it did though.
> 
> The extra stuff that you know can't be the case if runtime pm is on
> will need some sort of gating.  However, looking again it may already
> be protected by more specific checks.
> 
> 
> 	pm_runtime_force_resume();
> 
> 	if (st->fifo.on) { //I'd failed to look at what was added.
> 		ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
> 				   INV_ICM42607_FIFO_CONFIG1_MODE);
> 		if (ret)
> 			return ret;
> 	}
> 
> That if (st->fifo.on) previously didn't get checked if we were runtime
> suspended because in fifo mode we never are.  So I was thinking you'd
> need that check to be
> 	if (!pm_runtime_suspended(dev) && st->fifo.on)
> but the fifo.on check is sufficient by the same argument that if fifo.on
> is true we aren't in runtime suspend.
> 
> Basically I overthought it and didn't check what got added where the
> comment is in this patch.

I'm still lost here... are you saying the existing logic is sufficient or
that we need to do something more (like force the runtime resume/suspend
in different places).

Thank you again for all of your help, you've been amazing.

Chris

> 
>  
> > 
> > > 
> > >   
> > > > +	if (pm_runtime_suspended(dev))
> > > > +		return 0;
> > > > +
> > > > +	ret = inv_icm42607_enable_vddio_reg(st);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	/* Nothing else to restore at this time. */
> > > > +
> > > > +	return 0;
> > > > +}
> 

^ permalink raw reply

* Re: [PATCH 1/3] dt-bindings: riscv: spacemit: Add Banana Pi BPI-CM6 compatible
From: Conor Dooley @ 2026-05-22 16:11 UTC (permalink / raw)
  To: Junhui Liu
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Yixun Lan,
	Vivian Wang, Paolo Abeni, Guodong Xu, Yangyu Chen, devicetree,
	linux-riscv, spacemit, linux-kernel
In-Reply-To: <20260522-bpi-cm6-v1-1-707ef1917a30@pigmoral.tech>

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

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

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

^ permalink raw reply

* [PATCH v3 11/11] arm64: dts: ti: k3-am62-verdin: Add Mezzanine with Toradex Display 10.1" LVDS
From: Vitor Soares @ 2026-05-22 16:11 UTC (permalink / raw)
  To: Laurent Pinchart, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Lad Prabhakar,
	Thierry Reding
  Cc: Vitor Soares, dri-devel, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260522161105.277519-13-ivitro@gmail.com>

From: Vitor Soares <vitor.soares@toradex.com>

Add a device tree overlay enabling the Toradex Capacitive Touch Display
10.1" LVDS on the Verdin Development Board with Verdin AM62 Mezzanine
expansion board. The panel connects via the AM62 OLDI0 on the Mezzanine
LVDS interface (J10). The panel is a LogicTechno LT170410-2WHC 10.1" WXGA
IPS LCD and the touch input is provided by an Atmel MaxTouch capacitive
touch controller.

Link: https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-101inch-lvds
Assisted-by: Claude:claude-sonnet-4.6
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
Changes in v3:
- Add missing regulator-name property on fixed regulators
- Simplify regulator labels
- Rename touch@ nodes to touchscreen@

Changes in v2:
- Use panel-simple compatible form

 arch/arm64/boot/dts/ti/Makefile               |  5 +
 ...mezzanine-panel-cap-touch-10inch-lvds.dtso | 98 +++++++++++++++++++
 2 files changed, 103 insertions(+)
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-panel-cap-touch-10inch-lvds.dtso

diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 90bb3b0522d3..371f9a043fe5 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -30,6 +30,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-tqma62xx-mba62xx.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dev-mezzanine-can.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dev-mezzanine-panel-cap-touch-10inch-lvds.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dev-nau8822-btl.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dsi-to-hdmi.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
@@ -231,6 +232,9 @@ k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := \
 	k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
 k3-am625-verdin-wifi-dev-mezzanine-can-dtbs := k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-dev-mezzanine-can.dtbo
+k3-am625-verdin-wifi-dev-mezzanine-panel-cap-touch-10inch-lvds-dtbs := \
+	k3-am625-verdin-wifi-dev.dtb \
+	k3-am625-verdin-dev-mezzanine-panel-cap-touch-10inch-lvds.dtbo
 k3-am625-verdin-wifi-dev-nau8822-btl-dtbs := k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-dev-nau8822-btl.dtbo
 k3-am625-verdin-wifi-dev-ov5640-24mhz-dtbs := k3-am625-verdin-wifi-dev.dtb \
@@ -348,6 +352,7 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
 	k3-am625-sk-hdmi-audio.dtb \
 	k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb \
 	k3-am625-verdin-wifi-dev-mezzanine-can.dtb \
+	k3-am625-verdin-wifi-dev-mezzanine-panel-cap-touch-10inch-lvds.dtb \
 	k3-am625-verdin-wifi-dev-nau8822-btl.dtb \
 	k3-am625-verdin-wifi-dev-ov5640-24mhz.dtb \
 	k3-am625-verdin-wifi-dev-ov5640.dtb \
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-panel-cap-touch-10inch-lvds.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-panel-cap-touch-10inch-lvds.dtso
new file mode 100644
index 000000000000..83fc4f3a24f5
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-panel-cap-touch-10inch-lvds.dtso
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex Capacitive Touch Display 10.1" LVDS on the Verdin AM62 Mezzanine
+ * LVDS interface (J10), used with the Verdin Development Board.
+ *
+ * https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-101inch-lvds
+ * https://www.toradex.com/accessories/capacitive-touch-display-10.1-inch-lvds
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+
+&{/} {
+	backlight_pwm2: backlight-pwm2 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 45 63 88 119 158 203 255>;
+		default-brightness-level = <4>;
+		/* Verdin GPIO_4 (SODIMM 212) - LVDS_BKL_EN */
+		enable-gpios = <&mcu_gpio0 4 GPIO_ACTIVE_HIGH>;
+		/* Verdin PWM_2 (SODIMM 16) - LVDS_PWM */
+		pwms = <&epwm0 1 6666667 PWM_POLARITY_INVERTED>;
+	};
+
+	panel-lvds-native {
+		compatible = "logictechno,lt170410-2whc";
+		backlight = <&backlight_pwm2>;
+		power-supply = <&reg_3v3_lvds>;
+
+		port {
+			panel_lvds_native_in: endpoint {
+				remote-endpoint = <&oldi0_out>;
+			};
+		};
+	};
+
+	reg_3v3_lvds: regulator-3v3-lvds {
+		compatible = "regulator-fixed";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "+V3.3_LVDS";
+	};
+};
+
+&dss {
+	status = "okay";
+};
+
+&dss_ports {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	/* DSS VP1: internal DPI output to OLDIx */
+	port@0 {
+		reg = <0>;
+
+		dss0_out: endpoint {
+			remote-endpoint = <&oldi0_in>;
+		};
+	};
+};
+
+/* Verdin I2C_2_DSI */
+&main_i2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	touchscreen@4a {
+		compatible = "atmel,maxtouch";
+		reg = <0x4a>;
+		/* Verdin GPIO_3 (SODIMM 210) - LVDS_TOUCH_INT# */
+		interrupt-parent = <&mcu_gpio0>;
+		interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+		/* Verdin GPIO_2 (SODIMM 208) - LVDS_TOUCH_RST# */
+		reset-gpios = <&mcu_gpio0 2 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&oldi0 {
+	status = "okay";
+};
+
+&oldi0_port0 {
+	oldi0_in: endpoint {
+		remote-endpoint = <&dss0_out>;
+	};
+};
+
+&oldi0_port1 {
+	oldi0_out: endpoint {
+		remote-endpoint = <&panel_lvds_native_in>;
+	};
+};
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 10/11] arm64: dts: ti: k3-am62-verdin: Add Toradex Verdin Mezzanine CAN
From: Vitor Soares @ 2026-05-22 16:11 UTC (permalink / raw)
  To: Laurent Pinchart, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Lad Prabhakar,
	Thierry Reding
  Cc: Vitor Soares, dri-devel, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260522161105.277519-13-ivitro@gmail.com>

From: Vitor Soares <vitor.soares@toradex.com>

Add a device tree overlay enabling AM62 MCU_MCAN1 on the Toradex Verdin
Development Board with Verdin AM62 Mezzanine expansion board. MCU_MCAN1
is exposed on the Mezzanine CAN Header (J13), Pin 3 (CAN1_CONN_N) and
Pin 4 (CAN1_CONN_P).

Assisted-by: Claude:claude-sonnet-4.6
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
 arch/arm64/boot/dts/ti/Makefile               |  4 +++
 .../ti/k3-am625-verdin-dev-mezzanine-can.dtso | 28 +++++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-can.dtso

diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 60844951c9ce..90bb3b0522d3 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -29,6 +29,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-tevi-ov5640.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-tqma62xx-mba62xx.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dev-mezzanine-can.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dev-nau8822-btl.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dsi-to-hdmi.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
@@ -228,6 +229,8 @@ k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo
 k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := \
 	k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
+k3-am625-verdin-wifi-dev-mezzanine-can-dtbs := k3-am625-verdin-wifi-dev.dtb \
+	k3-am625-verdin-dev-mezzanine-can.dtbo
 k3-am625-verdin-wifi-dev-nau8822-btl-dtbs := k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-dev-nau8822-btl.dtbo
 k3-am625-verdin-wifi-dev-ov5640-24mhz-dtbs := k3-am625-verdin-wifi-dev.dtb \
@@ -344,6 +347,7 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
 	k3-am625-sk-csi2-tevi-ov5640.dtb \
 	k3-am625-sk-hdmi-audio.dtb \
 	k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb \
+	k3-am625-verdin-wifi-dev-mezzanine-can.dtb \
 	k3-am625-verdin-wifi-dev-nau8822-btl.dtb \
 	k3-am625-verdin-wifi-dev-ov5640-24mhz.dtb \
 	k3-am625-verdin-wifi-dev-ov5640.dtb \
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-can.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-can.dtso
new file mode 100644
index 000000000000..7ebf60d27c3c
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-mezzanine-can.dtso
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Enable AM62 MCU_MCAN1 exposed on Toradex Verdin Development Board with
+ * Verdin AM62 Mezzanine expansion board on CAN Header (J13),
+ * Pin 3 (CAN1_CONN_N) and Pin 4 (CAN1_CONN_P).
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "k3-pinctrl.h"
+
+&mcu_pmx0 {
+	pinctrl_mcu_mcan1: mcu-mcan1-default-pins {
+		pinctrl-single,pins = <
+			AM62X_MCU_IOPAD(0x0040, PIN_INPUT,  0) /* (D4) MCU_MCAN1_RX (SODIMM 116) */
+			AM62X_MCU_IOPAD(0x003c, PIN_OUTPUT, 0) /* (E5) MCU_MCAN1_TX (SODIMM 128) */
+		>;
+	};
+};
+
+&mcu_mcan1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_mcu_mcan1>;
+	status = "okay";
+};
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 09/11] arm64: dts: ti: k3-am62-verdin: Add Toradex OV5640 CSI Cameras
From: Vitor Soares @ 2026-05-22 16:11 UTC (permalink / raw)
  To: Laurent Pinchart, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Lad Prabhakar,
	Thierry Reding
  Cc: Vitor Soares, dri-devel, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260522161105.277519-13-ivitro@gmail.com>

From: Vitor Soares <vitor.soares@toradex.com>

Add device tree overlays for the Toradex OV5640 CSI Cameras on Verdin
CSI_1. Two variants are supported: the current CSI Camera Set 5MP OV5640
with a 27 MHz oscillator and the legacy CSI Camera Module 5MP OV5640
with a 24 MHz oscillator.

Link: https://developer.toradex.com/hardware/accessories/cameras/csi-camera-module-5mp-ov5640-arducam
Link: https://developer.toradex.com/hardware/legacy-products/other/csi-camera-module-5mp-ov5640/
Assisted-by: Claude:claude-sonnet-4.6
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
 arch/arm64/boot/dts/ti/Makefile               |  8 +++
 .../dts/ti/k3-am625-verdin-ov5640-24mhz.dtso  | 17 +++++
 .../boot/dts/ti/k3-am625-verdin-ov5640.dtsi   | 71 +++++++++++++++++++
 .../boot/dts/ti/k3-am625-verdin-ov5640.dtso   | 18 +++++
 4 files changed, 114 insertions(+)
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640-24mhz.dtso
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtsi
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtso

diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 31c9bc1d48b1..60844951c9ce 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -41,6 +41,8 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-ivy.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-mallow.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-yavia.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-zinnia.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-ov5640-24mhz.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-ov5640.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-dsi.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-lvds.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
@@ -228,6 +230,10 @@ k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := \
 	k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
 k3-am625-verdin-wifi-dev-nau8822-btl-dtbs := k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-dev-nau8822-btl.dtbo
+k3-am625-verdin-wifi-dev-ov5640-24mhz-dtbs := k3-am625-verdin-wifi-dev.dtb \
+	k3-am625-verdin-ov5640-24mhz.dtbo
+k3-am625-verdin-wifi-dev-ov5640-dtbs := k3-am625-verdin-wifi-dev.dtb \
+	k3-am625-verdin-ov5640.dtbo
 k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := \
 	k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
@@ -339,6 +345,8 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
 	k3-am625-sk-hdmi-audio.dtb \
 	k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb \
 	k3-am625-verdin-wifi-dev-nau8822-btl.dtb \
+	k3-am625-verdin-wifi-dev-ov5640-24mhz.dtb \
+	k3-am625-verdin-wifi-dev-ov5640.dtb \
 	k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb \
 	k3-am625-verdin-wifi-dev-uart4-mcu.dtb \
 	k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds.dtb \
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640-24mhz.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640-24mhz.dtso
new file mode 100644
index 000000000000..7089336fa5b4
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640-24mhz.dtso
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex CSI Camera Module 5MP OV5640 on Verdin CSI_1.
+ *
+ * https://developer.toradex.com/hardware/legacy-products/other/csi-camera-module-5mp-ov5640/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "k3-am625-verdin-ov5640.dtsi"
+
+&clk_ov5640_osc {
+	clock-frequency = <24000000>;
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtsi b/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtsi
new file mode 100644
index 000000000000..eb3df9d85517
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtsi
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Common device tree include for Toradex OV5640 CSI camera on Verdin CSI_1.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+	clk_ov5640_osc: ov5640-xclk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+	};
+
+	regulator_camera: regulator-camera {
+		compatible = "regulator-fixed";
+		/* Verdin GPIO_8_CSI (SODIMM 222) - CAM_1_CON_PWRCTRL */
+		gpio = <&main_gpio0 42 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		regulator-name = "V_CSI";
+		startup-delay-us = <5000>;
+	};
+};
+
+&csi0_port0 {
+	status = "okay";
+
+	csi2rx0_in_sensor: endpoint {
+		remote-endpoint = <&csi2_cam0>;
+		bus-type = <4>; /* CSI2 DPHY */
+		clock-lanes = <0>;
+		data-lanes = <1 2>;
+	};
+};
+
+&dphy0 {
+	status = "okay";
+};
+
+&main_i2c3 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	camera@3c {
+		compatible = "ovti,ov5640";
+		reg = <0x3c>;
+
+		clocks = <&clk_ov5640_osc>;
+		clock-names = "xclk";
+		AVDD-supply = <&regulator_camera>;
+		DOVDD-supply = <&regulator_camera>;
+		DVDD-supply = <&regulator_camera>;
+		/* Verdin GPIO_6 (SODIMM 218) - CAM_1_CON_PWRDWN */
+		powerdown-gpios = <&main_gpio0 36 GPIO_ACTIVE_HIGH>;
+		/* Verdin GPIO_5 (SODIMM 216) - CAM_1_CON_RST */
+		reset-gpios = <&main_gpio0 40 GPIO_ACTIVE_LOW>;
+
+		port {
+			csi2_cam0: endpoint {
+				remote-endpoint = <&csi2rx0_in_sensor>;
+				clock-lanes = <0>;
+				data-lanes = <1 2>;
+			};
+		};
+	};
+};
+
+&ti_csi2rx0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtso
new file mode 100644
index 000000000000..e7f02cfaa94f
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-ov5640.dtso
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex CSI Camera Set 5MP OV5640 on Verdin CSI_1.
+ *
+ * https://developer.toradex.com/hardware/accessories/cameras/csi-camera-module-5mp-ov5640-arducam
+ * https://www.toradex.com/accessories/csi-camera-ov5640
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include "k3-am625-verdin-ov5640.dtsi"
+
+&clk_ov5640_osc {
+	clock-frequency = <27000000>;
+};
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 08/11] arm64: dts: ti: k3-am62-verdin: Reserve UART_4 for Cortex-M4F
From: Vitor Soares @ 2026-05-22 16:11 UTC (permalink / raw)
  To: Laurent Pinchart, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Lad Prabhakar,
	Thierry Reding
  Cc: Vitor Soares, dri-devel, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260522161105.277519-13-ivitro@gmail.com>

From: Vitor Soares <vitor.soares@toradex.com>

Add a device tree overlay reserving AM62 MCU_UART0 (Verdin UART_4) for
use by the Cortex-M4F co-processor as its debug UART.

Assisted-by: Claude:claude-sonnet-4.6
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
 arch/arm64/boot/dts/ti/Makefile                     |  4 ++++
 .../boot/dts/ti/k3-am625-verdin-uart4-mcu.dtso      | 13 +++++++++++++
 2 files changed, 17 insertions(+)
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-uart4-mcu.dtso

diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index a1083c0b2502..31c9bc1d48b1 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -44,6 +44,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-zinnia.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-dsi.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-lvds.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-uart4-mcu.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia-panel-cap-touch-10inch-dsi.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb
@@ -230,6 +231,8 @@ k3-am625-verdin-wifi-dev-nau8822-btl-dtbs := k3-am625-verdin-wifi-dev.dtb \
 k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := \
 	k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
+k3-am625-verdin-wifi-dev-uart4-mcu-dtbs := k3-am625-verdin-wifi-dev.dtb \
+	k3-am625-verdin-uart4-mcu.dtbo
 k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds-dtbs := \
 	k3-am625-verdin-wifi-mallow.dtb \
 	k3-am625-verdin-panel-cap-touch-10inch-lvds.dtbo
@@ -337,6 +340,7 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
 	k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb \
 	k3-am625-verdin-wifi-dev-nau8822-btl.dtb \
 	k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb \
+	k3-am625-verdin-wifi-dev-uart4-mcu.dtb \
 	k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds.dtb \
 	k3-am62-lp-sk-hdmi-audio.dtb \
 	k3-am62-lp-sk-nand.dtb \
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-uart4-mcu.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-uart4-mcu.dtso
new file mode 100644
index 000000000000..e263809cdf74
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-uart4-mcu.dtso
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Verdin AM62 Cortex-M4F debug UART
+ */
+
+/dts-v1/;
+/plugin/;
+
+&mcu_uart0 {
+	status = "reserved";
+};
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 07/11] arm64: dts: ti: k3-am62-verdin: Add NAU8822 Bridge Tied Load
From: Vitor Soares @ 2026-05-22 16:11 UTC (permalink / raw)
  To: Laurent Pinchart, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Lad Prabhakar,
	Thierry Reding
  Cc: Vitor Soares, dri-devel, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260522161105.277519-13-ivitro@gmail.com>

From: Vitor Soares <vitor.soares@toradex.com>

Add a device tree overlay enabling Bridge Tied Load (BTL) mode on the
Nuvoton NAU8822 audio codec present on the Verdin Development Board.
In BTL mode, the two loudspeaker outputs are bridged to deliver higher
output power on the X28 speaker connector.

Assisted-by: Claude:claude-sonnet-4.6
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
 arch/arm64/boot/dts/ti/Makefile                    |  4 ++++
 .../dts/ti/k3-am625-verdin-dev-nau8822-btl.dtso    | 14 ++++++++++++++
 2 files changed, 18 insertions(+)
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-dev-nau8822-btl.dtso

diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 14898f8ab0e2..a1083c0b2502 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -29,6 +29,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-tevi-ov5640.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-tqma62xx-mba62xx.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dev-nau8822-btl.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dsi-to-hdmi.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dahlia-dsi-to-hdmi.dtb
@@ -224,6 +225,8 @@ k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo
 k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := \
 	k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
+k3-am625-verdin-wifi-dev-nau8822-btl-dtbs := k3-am625-verdin-wifi-dev.dtb \
+	k3-am625-verdin-dev-nau8822-btl.dtbo
 k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := \
 	k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
@@ -332,6 +335,7 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
 	k3-am625-sk-csi2-tevi-ov5640.dtb \
 	k3-am625-sk-hdmi-audio.dtb \
 	k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb \
+	k3-am625-verdin-wifi-dev-nau8822-btl.dtb \
 	k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb \
 	k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds.dtb \
 	k3-am62-lp-sk-hdmi-audio.dtb \
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-nau8822-btl.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-nau8822-btl.dtso
new file mode 100644
index 000000000000..e4b662519a6b
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-dev-nau8822-btl.dtso
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Enable Bridge Tied Load (BTL) speaker mode on the Verdin Development Board,
+ * combining the two loudspeaker outputs for higher output power.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&nau8822_1a {
+	nuvoton,spk-btl;
+};
-- 
2.54.0


^ permalink raw reply related

* [PATCH v3 06/11] arm64: dts: ti: k3-am62-verdin: Add Toradex Capacitive Touch Display 7" DSI
From: Vitor Soares @ 2026-05-22 16:11 UTC (permalink / raw)
  To: Laurent Pinchart, Neil Armstrong, Jessica Zhang, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Nishanth Menon, Vignesh Raghavendra, Tero Kristo, Lad Prabhakar,
	Thierry Reding
  Cc: Vitor Soares, dri-devel, devicetree, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260522161105.277519-13-ivitro@gmail.com>

From: Vitor Soares <vitor.soares@toradex.com>

Add a device tree overlay for the Toradex Capacitive Touch Display 7"
DSI on the Verdin DSI_1 interface. The display features an internal
Texas Instruments SN65DSI83 DSI-to-LVDS bridge driving a Riverdi
RVT70HSLNWCA0 7" WSVGA IPS TFT LCD panel. The touch input is provided
by an Ilitek ILI2132 capacitive touch controller.

Link: https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-7inch-dsi
Link: https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter/
Assisted-by: Claude:claude-sonnet-4.6
Signed-off-by: Vitor Soares <vitor.soares@toradex.com>
---
Changes in v3:
- Rename touch@ nodes to touchscreen@

 arch/arm64/boot/dts/ti/Makefile               |   5 +
 ...m625-verdin-panel-cap-touch-7inch-dsi.dtso | 132 ++++++++++++++++++
 2 files changed, 137 insertions(+)
 create mode 100644 arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-7inch-dsi.dtso

diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index dc397bc693ac..14898f8ab0e2 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -42,6 +42,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-yavia.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-zinnia.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-dsi.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-10inch-lvds.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia-dsi-to-hdmi.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia-panel-cap-touch-10inch-dsi.dtb
 dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb
@@ -223,6 +224,9 @@ k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo
 k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := \
 	k3-am625-verdin-wifi-dev.dtb \
 	k3-am625-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
+k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := \
+	k3-am625-verdin-wifi-dev.dtb \
+	k3-am625-verdin-panel-cap-touch-7inch-dsi.dtbo
 k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds-dtbs := \
 	k3-am625-verdin-wifi-mallow.dtb \
 	k3-am625-verdin-panel-cap-touch-10inch-lvds.dtbo
@@ -328,6 +332,7 @@ dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \
 	k3-am625-sk-csi2-tevi-ov5640.dtb \
 	k3-am625-sk-hdmi-audio.dtb \
 	k3-am625-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb \
+	k3-am625-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb \
 	k3-am625-verdin-wifi-mallow-panel-cap-touch-10inch-lvds.dtb \
 	k3-am62-lp-sk-hdmi-audio.dtb \
 	k3-am62-lp-sk-nand.dtb \
diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-7inch-dsi.dtso b/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-7inch-dsi.dtso
new file mode 100644
index 000000000000..1f44133f9ca6
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-panel-cap-touch-7inch-dsi.dtso
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+/*
+ * Copyright (c) Toradex
+ *
+ * Toradex Capacitive Touch Display 7" on Verdin DSI_1.
+ * On Dahlia (X17) and Development Board (X48), DSI_1 is exposed via a
+ * Samtec LSS-130 connector and requires the Toradex DSI Display Adapter
+ * to convert to FFC/FPC connector.
+ *
+ * https://developer.toradex.com/hardware/accessories/displays/capacitive-touch-display-7inch-dsi
+ * https://www.toradex.com/accessories/capacitive-touch-display-7-inch-dsi
+ * https://developer.toradex.com/hardware/accessories/add-ons/dsi-display-adapter
+ * https://www.toradex.com/accessories/verdin-dsi-display-adapter
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pwm/pwm.h>
+
+&{/} {
+	backlight_pwm3: backlight-pwm3 {
+		compatible = "pwm-backlight";
+		brightness-levels = <0 45 63 88 119 158 203 255>;
+		default-brightness-level = <4>;
+		power-supply = <&reg_3v3>;
+		/* Verdin PWM_3_DSI (SODIMM 19) - PWM_3_DSI_LVDS */
+		pwms = <&epwm1 0 6666667 0>;
+	};
+
+	panel-lvds-bridge {
+		compatible = "riverdi,rvt70hslnwca0", "panel-lvds";
+		backlight = <&backlight_pwm3>;
+		data-mapping = "vesa-24";
+		height-mm = <86>;
+		width-mm = <154>;
+
+		panel-timing {
+			clock-frequency = <51200000>;
+			de-active = <1>;
+			hactive = <1024>;
+			hback-porch = <160 160 160>;
+			hfront-porch = <16 160 216>;
+			hsync-active = <0>;
+			hsync-len = <1 5 140>;
+			pixelclk-active = <1>;
+			vactive = <600>;
+			vback-porch = <23 23 23>;
+			vfront-porch = <1 12 126>;
+			vsync-active = <0>;
+			vsync-len = <1 10 20>;
+		};
+
+		port {
+			panel_lvds_bridge_in: endpoint {
+				remote-endpoint = <&dsi_lvds_bridge_out>;
+			};
+		};
+	};
+};
+
+&dsi_bridge {
+	status = "okay";
+};
+
+&dsi_bridge_ports {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	port@1 {
+		reg = <1>;
+
+		dsi_bridge_out: endpoint {
+			remote-endpoint = <&dsi_lvds_bridge_in>;
+		};
+	};
+};
+
+&dss {
+	status = "okay";
+};
+
+/* Verdin I2C_2_DSI */
+&main_i2c2 {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	bridge@2c {
+		compatible = "ti,sn65dsi83";
+		reg = <0x2c>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_dsi1_bkl_en>;
+		/* Verdin GPIO_10_DSI (SODIMM 21) - DSI_1_BKL_EN */
+		enable-gpios = <&main_gpio0 30 GPIO_ACTIVE_HIGH>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			port@0 {
+				reg = <0>;
+
+				dsi_lvds_bridge_in: endpoint {
+					remote-endpoint = <&dsi_bridge_out>;
+					data-lanes = <1 2 3 4>;
+				};
+			};
+
+			port@2 {
+				reg = <2>;
+
+				dsi_lvds_bridge_out: endpoint {
+					remote-endpoint = <&panel_lvds_bridge_in>;
+				};
+			};
+		};
+	};
+
+	touchscreen@41 {
+		compatible = "ilitek,ili2132";
+		reg = <0x41>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_dsi1_int>, <&pinctrl_i2s_2_bclk_gpio>;
+		/* Verdin GPIO_9_DSI (SODIMM 17) - TOUCH_INT# */
+		interrupt-parent = <&main_gpio1>;
+		interrupts = <49 IRQ_TYPE_EDGE_RISING>;
+		/* Verdin I2S_2_BCLK (SODIMM 42) - TOUCH_RESET# */
+		reset-gpios = <&main_gpio0 35 GPIO_ACTIVE_LOW>;
+	};
+};
-- 
2.54.0


^ permalink raw reply related


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