Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 05/32] pinctrl: mediatek: mt7981: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 6c83b2d94fcc ("pinctrl: add mt7981 pinctrl driver")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt7981.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 77f974bdfe90..a2bc1bfb1035 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -209,7 +209,7 @@ config PINCTRL_MT7622
 	select PINCTRL_MTK_MOORE
 
 config PINCTRL_MT7981
-	bool "MediaTek MT7981 pin control"
+	tristate "MediaTek MT7981 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
index 22c8f2480346..b537fea707cc 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c
@@ -1058,3 +1058,6 @@ static int __init mt7981_pinctrl_init(void)
 	return platform_driver_register(&mt7981_pinctrl_driver);
 }
 arch_initcall(mt7981_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT7981 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 06/32] pinctrl: mediatek: mt7986: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 360de6728064 ("pinctrl: mediatek: add support for MT7986 SoC")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt7986.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index a2bc1bfb1035..f0bc125cfb2a 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -216,7 +216,7 @@ config PINCTRL_MT7981
 	select PINCTRL_MTK_MOORE
 
 config PINCTRL_MT7986
-	bool "MediaTek MT7986 pin control"
+	tristate "MediaTek MT7986 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7986.c b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
index 5dda4b7467fd..1ed2528cd51f 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7986.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7986.c
@@ -1009,3 +1009,6 @@ static int __init mt7986b_pinctrl_init(void)
 
 arch_initcall(mt7986a_pinctrl_init);
 arch_initcall(mt7986b_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT7986 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 25/32] pinctrl: mediatek: mt76x8: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: dc6ae2057c9c ("pinctrl: ralink: move to mediatek as mtmips")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt76x8.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 96cc4345d6bf..6ae373b84c58 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -62,7 +62,7 @@ config PINCTRL_MT7621
 	select PINCTRL_MTK_MTMIPS
 
 config PINCTRL_MT76X8
-	bool "MediaTek MT76X8 pin control"
+	tristate "MediaTek MT76X8 pin control"
 	depends on SOC_MT7620 || COMPILE_TEST
 	depends on RALINK
 	default SOC_MT7620
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt76x8.c b/drivers/pinctrl/mediatek/pinctrl-mt76x8.c
index 2bc8d4409ca2..080deedf2cf3 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt76x8.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt76x8.c
@@ -247,3 +247,6 @@ static int __init mt76x8_pinctrl_init(void)
 	return platform_driver_register(&mt76x8_pinctrl_driver);
 }
 core_initcall_sync(mt76x8_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT76X8 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 18/32] pinctrl: mediatek: mt2701: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 148b95eea00b ("pinctrl: mediatek: Add Pinctrl/GPIO/EINT driver for mt2701")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt2701.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 4be557ea7341..730d645c536f 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -91,7 +91,7 @@ config PINCTRL_RT3883
 
 # For ARMv7 SoCs
 config PINCTRL_MT2701
-	bool "MediaTek MT2701 pin control"
+	tristate "MediaTek MT2701 pin control"
 	depends on MACH_MT7623 || MACH_MT2701 || COMPILE_TEST
 	depends on OF
 	default MACH_MT2701
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
index 6b1c7122b0fb..12452e16cb68 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -542,3 +542,6 @@ static int __init mtk_pinctrl_init(void)
 	return platform_driver_register(&mtk_pinctrl_driver);
 }
 arch_initcall(mtk_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT2701 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 11/32] pinctrl: mediatek: mt8186: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 8b483bda1e46 ("pinctrl: add pinctrl driver on mt8186")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt8186.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 7c88eccc33c2..2a4c5d5555dd 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -251,7 +251,7 @@ config PINCTRL_MT8183
 	select PINCTRL_MTK_PARIS
 
 config PINCTRL_MT8186
-	bool "MediaTek MT8186 pin control"
+	tristate "MediaTek MT8186 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8186.c b/drivers/pinctrl/mediatek/pinctrl-mt8186.c
index dd19e74856a9..29c8ab1482a0 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8186.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8186.c
@@ -1265,3 +1265,6 @@ static int __init mt8186_pinctrl_init(void)
 }
 
 arch_initcall(mt8186_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT8186 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 02/32] pinctrl: mediatek: mt6878: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 89c13ea3ab6d ("pinctrl: mediatek: Add support for MT6878 pinctrl")

Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt6878.c | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index a75434e7e989..2859ac27dbfd 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -182,7 +182,7 @@ config PINCTRL_MT6797
 	select PINCTRL_MTK_PARIS
 
 config PINCTRL_MT6878
-	bool "MediaTek MT6878 pin control"
+	tristate "MediaTek MT6878 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6878.c b/drivers/pinctrl/mediatek/pinctrl-mt6878.c
index b59ae089128a..e188d124b837 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6878.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6878.c
@@ -1476,3 +1476,4 @@ static int __init mt6878_pinctrl_init(void)
 arch_initcall(mt6878_pinctrl_init);
 
 MODULE_DESCRIPTION("MediaTek MT6878 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 12/32] pinctrl: mediatek: mt8188: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 11b918d90aeb ("pinctrl: mediatek: add mt8188 driver")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt8188.c | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 2a4c5d5555dd..c62024d75593 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -258,7 +258,7 @@ config PINCTRL_MT8186
 	select PINCTRL_MTK_PARIS
 
 config PINCTRL_MT8188
-	bool "MediaTek MT8188 pin control"
+	tristate "MediaTek MT8188 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8188.c b/drivers/pinctrl/mediatek/pinctrl-mt8188.c
index 3975e99d9cf4..cc55c28671f8 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8188.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8188.c
@@ -1671,3 +1671,4 @@ static int __init mt8188_pinctrl_init(void)
 arch_initcall(mt8188_pinctrl_init);
 
 MODULE_DESCRIPTION("MediaTek MT8188 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 10/32] pinctrl: mediatek: mt8183: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 750cd15d9081 ("pinctrl: mediatek: add MT8183 pinctrl driver")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt8183.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 8cdba1f719ef..7c88eccc33c2 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -244,7 +244,7 @@ config PINCTRL_MT8173
 	select PINCTRL_MTK
 
 config PINCTRL_MT8183
-	bool "MediaTek MT8183 pin control"
+	tristate "MediaTek MT8183 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8183.c b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
index 93e482c6b5fd..0dabecd8e20b 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8183.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
@@ -586,3 +586,6 @@ static int __init mt8183_pinctrl_init(void)
 	return platform_driver_register(&mt8183_pinctrl_driver);
 }
 arch_initcall(mt8183_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT8183 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 16/32] pinctrl: mediatek: mt8365: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: e94d8b6fb83a ("pinctrl: mediatek: add support for mt8365 SoC")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt8365.c | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 7bb9cb15dfba..5d0d96fd75d5 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -308,7 +308,7 @@ config PINCTRL_MT8196
 	  map specific eint which doesn't have real gpio pin.
 
 config PINCTRL_MT8365
-	bool "MediaTek MT8365 pin control"
+	tristate "MediaTek MT8365 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8365.c b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
index c20b9e2e02dd..d41d99ab8c36 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8365.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
@@ -494,4 +494,5 @@ static int __init mtk_pinctrl_init(void)
 arch_initcall(mtk_pinctrl_init);
 
 MODULE_DESCRIPTION("MediaTek MT8365 Pinctrl Driver");
+MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 01/32] pinctrl: mediatek: mt8189: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: a3fe1324c3c5 ("pinctrl: mediatek: Add pinctrl driver for mt8189")

Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt8189.c | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 4819617d9368..a75434e7e989 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -270,7 +270,7 @@ config PINCTRL_MT8188
 	  map specific eint which doesn't have real gpio pin.
 
 config PINCTRL_MT8189
-        bool "MediaTek MT8189 pin control"
+        tristate "MediaTek MT8189 pin control"
         depends on OF
         depends on ARM64 || COMPILE_TEST
         default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8189.c b/drivers/pinctrl/mediatek/pinctrl-mt8189.c
index cd4cdff309a1..67ae7170670c 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8189.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8189.c
@@ -1696,3 +1696,4 @@ static int __init mt8189_pinctrl_init(void)
 arch_initcall(mt8189_pinctrl_init);
 
 MODULE_DESCRIPTION("MediaTek MT8189 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 09/32] pinctrl: mediatek: mt8173: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 30f010f5c4cf ("arm64: mediatek: Add Pinctrl/GPIO/EINT driver for mt8173.")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt8173.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 20d84d6bd9d1..8cdba1f719ef 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -237,7 +237,7 @@ config PINCTRL_MT8167
 	select PINCTRL_MTK
 
 config PINCTRL_MT8173
-	bool "MediaTek MT8173 pin control"
+	tristate "MediaTek MT8173 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index b214deeafbf1..a6d1e4aedb5e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -356,3 +356,6 @@ static int __init mtk_pinctrl_init(void)
 	return platform_driver_register(&mtk_pinctrl_driver);
 }
 arch_initcall(mtk_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT8173 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 04/32] pinctrl: mediatek: mt7622: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: d6ed93551320 ("pinctrl: mediatek: add pinctrl driver for MT7622 SoC")
Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt7622.c | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 3e4002a6ce78..77f974bdfe90 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -202,7 +202,7 @@ config PINCTRL_MT6893
 	  on the MediaTek Dimensity 1200 MT6893 Smartphone SoC.
 
 config PINCTRL_MT7622
-	bool "MediaTek MT7622 pin control"
+	tristate "MediaTek MT7622 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7622.c b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
index d5777889448a..5516656e630b 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt7622.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt7622.c
@@ -893,3 +893,6 @@ static int __init mt7622_pinctrl_init(void)
 	return platform_driver_register(&mt7622_pinctrl_driver);
 }
 arch_initcall(mt7622_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT7622 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 03/32] pinctrl: mediatek: mt6893: Enable module build support
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh
In-Reply-To: <20260626013217.2373808-1-justin.yeh@mediatek.com>

Add MODULE_LICENSE("GPL") macro and change Kconfig option from
bool to tristate to allow building as a loadable kernel module.

This is required for Android GKI + vendor_dlkm deployments where
vendor-specific drivers must be kept separate from the GKI vmlinux.

Fixes: 8004507179c8 ("pinctrl: mediatek: Add pinctrl driver for MT6893 Dimensity 1200")

Signed-off-by: Justin Yeh <justin.yeh@mediatek.com>
---
 drivers/pinctrl/mediatek/Kconfig          | 2 +-
 drivers/pinctrl/mediatek/pinctrl-mt6893.c | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 2859ac27dbfd..3e4002a6ce78 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -192,7 +192,7 @@ config PINCTRL_MT6878
 	  on the MediaTek MT6878 SoC.
 
 config PINCTRL_MT6893
-	bool "MediaTek Dimensity MT6893 pin control"
+	tristate "MediaTek Dimensity MT6893 pin control"
 	depends on OF
 	depends on ARM64 || COMPILE_TEST
 	default ARM64 && ARCH_MEDIATEK
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6893.c b/drivers/pinctrl/mediatek/pinctrl-mt6893.c
index 468ce0109b07..b4d8bec8a481 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6893.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6893.c
@@ -877,3 +877,4 @@ static int __init mt6893_pinctrl_init(void)
 arch_initcall(mt6893_pinctrl_init);
 
 MODULE_DESCRIPTION("MediaTek MT6893 Pinctrl Driver");
+MODULE_LICENSE("GPL");
-- 
2.45.2



^ permalink raw reply related

* [PATCH v2 00/32] pinctrl: mediatek: Enable module build support for all drivers
From: Justin Yeh @ 2026-06-26  1:31 UTC (permalink / raw)
  To: Sean Wang, Linus Walleij, Matthias Brugger,
	AngeloGioacchino Del Regno
  Cc: Project_Global_Chrome_Upstream_Group, linux-mediatek, linux-gpio,
	linux-kernel, linux-arm-kernel, Justin Yeh

This series enables all MediaTek pinctrl drivers to be built as loadable
kernel modules. This is required for Android GKI (Generic Kernel Image) +
vendor_dlkm deployments where vendor-specific drivers must be kept separate
from the GKI vmlinux.

Each patch adds MODULE_LICENSE("GPL") and MODULE_DESCRIPTION() macros where
missing, and changes the Kconfig option from bool to tristate. This allows
these drivers to be properly packaged as vendor kernel modules while
maintaining the existing built-in option.

Changes in v2:
  * Squash MODULE_LICENSE and tristate changes into single patch per driver
  * Extend fix to all MediaTek pinctrl drivers (32 total), not just MT8189
  * Add Android GKI + vendor_dlkm context to cover letter
  * Add MODULE_DESCRIPTION() where it was missing
  * Add Fixes: tags referencing the original commits that added each driver

Justin Yeh (32):
  pinctrl: mediatek: mt8189: Enable module build support
  pinctrl: mediatek: mt6878: Enable module build support
  pinctrl: mediatek: mt6893: Enable module build support
  pinctrl: mediatek: mt7622: Enable module build support
  pinctrl: mediatek: mt7981: Enable module build support
  pinctrl: mediatek: mt7986: Enable module build support
  pinctrl: mediatek: mt7988: Enable module build support
  pinctrl: mediatek: mt8167: Enable module build support
  pinctrl: mediatek: mt8173: Enable module build support
  pinctrl: mediatek: mt8183: Enable module build support
  pinctrl: mediatek: mt8186: Enable module build support
  pinctrl: mediatek: mt8188: Enable module build support
  pinctrl: mediatek: mt8192: Enable module build support
  pinctrl: mediatek: mt8195: Enable module build support
  pinctrl: mediatek: mt8196: Enable module build support
  pinctrl: mediatek: mt8365: Enable module build support
  pinctrl: mediatek: mt8516: Enable module build support
  pinctrl: mediatek: mt2701: Enable module build support
  pinctrl: mediatek: mt7623: Enable module build support
  pinctrl: mediatek: mt7629: Enable module build support
  pinctrl: mediatek: mt8135: Enable module build support
  pinctrl: mediatek: mt8127: Enable module build support
  pinctrl: mediatek: mt7620: Enable module build support
  pinctrl: mediatek: mt7621: Enable module build support
  pinctrl: mediatek: mt76x8: Enable module build support
  pinctrl: mediatek: rt2880: Enable module build support
  pinctrl: mediatek: rt305x: Enable module build support
  pinctrl: mediatek: rt3883: Enable module build support
  pinctrl: mediatek: mt6397: Enable module build support
  pinctrl: mediatek: mt2712: Enable module build support
  pinctrl: mediatek: mt6795: Enable module build support
  pinctrl: mediatek: mt6797: Enable module build support

 drivers/pinctrl/mediatek/Kconfig          | 64 +++++++++++------------
 drivers/pinctrl/mediatek/pinctrl-mt2701.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt2712.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt6397.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt6795.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt6797.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt6878.c |  1 +
 drivers/pinctrl/mediatek/pinctrl-mt6893.c |  1 +
 drivers/pinctrl/mediatek/pinctrl-mt7620.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt7621.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt7622.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt7623.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt7629.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt76x8.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt7981.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt7986.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt7988.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8127.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8135.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8167.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8173.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8183.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8186.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8188.c |  1 +
 drivers/pinctrl/mediatek/pinctrl-mt8189.c |  1 +
 drivers/pinctrl/mediatek/pinctrl-mt8192.c |  1 +
 drivers/pinctrl/mediatek/pinctrl-mt8195.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-mt8196.c |  1 +
 drivers/pinctrl/mediatek/pinctrl-mt8365.c |  1 +
 drivers/pinctrl/mediatek/pinctrl-mt8516.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-rt2880.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-rt305x.c |  3 ++
 drivers/pinctrl/mediatek/pinctrl-rt3883.c |  3 ++
 33 files changed, 114 insertions(+), 32 deletions(-)

-- 
2.45.2



^ permalink raw reply

* [PATCH] arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()
From: Anshuman Khandual @ 2026-06-26  1:28 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Anshuman Khandual, Catalin Marinas, Will Deacon, Ryan Roberts,
	David Hildenbrand, linux-kernel, Ben Hutchings

flush_tlb_kernel_range() could flush down an entire block mapping just with
a single PAGE_SIZE stride. This capability was being used umapping PMD and
PUD based block mappings in unmap_hotplug_[pmd|pud]_range().

But later on the commit 48478b9f7913
("arm64/mm: Enable batched TLB flush in unmap_hotplug_range()") replaced
this PAGE_SIZE stride with [PMD|PUD]_SIZE strides, hence forcing multiple
PAGE_SIZE stride based TLB flushes on platforms where TLB range operation
is not supported. Revert back to the earlier TLB behaviour along with the
required comments that were dropped earlier.

Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Reported-by: Ben Hutchings <ben@decadent.org.uk>
Closes: https://lore.kernel.org/all/b0d5836032ce3135bfc473f6bff791306d086925.camel@decadent.org.uk/
Fixes: 48478b9f7913 ("arm64/mm: Enable batched TLB flush in unmap_hotplug_range()")
Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
---
 arch/arm64/mm/mmu.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 8242f93f05e4..5ff0041f4a5f 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1509,7 +1509,11 @@ static void unmap_hotplug_pmd_range(pud_t *pudp, unsigned long addr,
 			if (free_mapped) {
 				/* CONT blocks are not supported in the vmemmap */
 				WARN_ON(pmd_cont(pmd));
-				flush_tlb_kernel_range(addr, addr + PMD_SIZE);
+				/*
+				 * One TLBI should be sufficient here as the PMD_SIZE
+				 * range is mapped with a single block entry.
+				 */
+				flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
 				free_hotplug_page_range(pmd_page(pmd),
 							PMD_SIZE, altmap);
 			}
@@ -1539,7 +1543,11 @@ static void unmap_hotplug_pud_range(p4d_t *p4dp, unsigned long addr,
 		if (pud_leaf(pud)) {
 			pud_clear(pudp);
 			if (free_mapped) {
-				flush_tlb_kernel_range(addr, addr + PUD_SIZE);
+				/*
+				 * One TLBI should be sufficient here as the PUD_SIZE
+				 * range is mapped with a single block entry.
+				 */
+				flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
 				free_hotplug_page_range(pud_page(pud),
 							PUD_SIZE, altmap);
 			}
-- 
2.30.2



^ permalink raw reply related

* [PATCH RFC 3/4] media: i2c: Add Samsung S5K3L6 image sensor driver
From: Vincent Cloutier @ 2026-06-26  0:06 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel
  Cc: linux-kernel, linux-imx, kernel, Vincent Cloutier,
	Mauro Carvalho Chehab, Sakari Ailus, Hans Verkuil, Hans de Goede,
	Vladimir Zapolskiy, Mehdi Djait, Laurent Pinchart, Xiaolei Wang,
	Walter Werner Schneider, Kate Hsuan, Hardevsinh Palaniya,
	Himanshu Bhavani, Svyatoslav Ryhel
In-Reply-To: <20260626000715.1111803-1-vincent.cloutier@icloud.com>

From: Vincent Cloutier <vincent@cloutier.co>

Add a V4L2 sub-device driver for the Samsung S5K3L6 raw Bayer image
sensor.

The initial driver supports the production path used by the Librem 5 rear
camera: a 25 MHz input clock, two MIPI CSI-2 data lanes, RAW8 and RAW10
Bayer modes derived from the full 4208x3120 active array, runtime PM, CCI
register access, basic exposure/gain/blanking controls, test patterns, and
fwnode orientation controls.

This driver is derived from the Librem 5 downstream S5K3L6 carry, initially
authored by Martin Kepplinger and substantially developed by Dorota
Czaplejewicz and Sebastian Krzyszkowiak. The upstream submission rewrites
and collapses that history into a current V4L2 sensor driver shape.

Signed-off-by: Vincent Cloutier <vincent@cloutier.co>
Assisted-by: OpenCode:gpt-5.5
---
 drivers/media/i2c/Kconfig    |   10 +
 drivers/media/i2c/Makefile   |    1 +
 drivers/media/i2c/s5k3l6.c  | 1055 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1066 insertions(+)

diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5d173e0ecf42..5ec4db05920a 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -781,6 +781,16 @@ config VIDEO_S5K3M5
 	  To compile this driver as a module, choose M here: the
 	  module will be called s5k3m5.
 
+config VIDEO_S5K3L6
+	tristate "Samsung S5K3L6 sensor support"
+	select V4L2_CCI_I2C
+	help
+	  This is a V4L2 sensor driver for Samsung S5K3L6 13MP raw
+	  camera sensor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called s5k3l6.
+
 config VIDEO_S5K5BAF
 	tristate "Samsung S5K5BAF sensor support"
 	help
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index e45359efe0e4..f3360e97aa38 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -128,6 +128,7 @@ obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o
 obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o
 obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
 obj-$(CONFIG_VIDEO_S5K3M5) += s5k3m5.o
+obj-$(CONFIG_VIDEO_S5K3L6) += s5k3l6.o
 obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o
 obj-$(CONFIG_VIDEO_S5K6A3) += s5k6a3.o
 obj-$(CONFIG_VIDEO_S5KJN1) += s5kjn1.o
diff --git a/drivers/media/i2c/s5k3l6.c b/drivers/media/i2c/s5k3l6.c
new file mode 100644
index 000000000000..f70f83e9de17
--- /dev/null
+++ b/drivers/media/i2c/s5k3l6.c
@@ -0,0 +1,1055 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2020-2021 Purism SPC
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define S5K3L6_MCLK_FREQ		(25 * HZ_PER_MHZ)
+#define S5K3L6_DATA_LANES		2
+
+#define S5K3L6_LINK_FREQ_537P5MHZ	(537500ULL * HZ_PER_KHZ)
+#define S5K3L6_LINK_FREQ_600MHZ	(600ULL * HZ_PER_MHZ)
+#define S5K3L6_LINK_FREQ_625MHZ	(625ULL * HZ_PER_MHZ)
+
+/* Downstream mode tables use a fixed 480 MHz VT pixel clock. */
+#define S5K3L6_PIXEL_RATE		(480ULL * HZ_PER_MHZ)
+
+#define S5K3L6_PIXEL_ARRAY_WIDTH	4224
+#define S5K3L6_PIXEL_ARRAY_HEIGHT	3136
+#define S5K3L6_ACTIVE_LEFT		8
+#define S5K3L6_ACTIVE_TOP		8
+#define S5K3L6_ACTIVE_WIDTH		4208
+#define S5K3L6_ACTIVE_HEIGHT		3120
+
+#define S5K3L6_CHIP_ID		0x30c6
+#define S5K3L6_REVISION		0xb0
+
+#define S5K3L6_REG_CHIP_ID		CCI_REG16(0x0000)
+#define S5K3L6_REG_REVISION		CCI_REG8(0x0002)
+#define S5K3L6_REG_MODE_SELECT	CCI_REG8(0x0100)
+#define S5K3L6_MODE_STANDBY		0x00
+#define S5K3L6_MODE_STREAMING		0x01
+
+#define S5K3L6_REG_LANE_MODE		CCI_REG8(0x0114)
+#define S5K3L6_REG_DATA_FORMAT	CCI_REG16(0x0112)
+#define S5K3L6_DATA_FORMAT_RAW8	0x0808
+#define S5K3L6_DATA_FORMAT_RAW10	0x0a0a
+
+#define S5K3L6_REG_OP_PLL_MULTIPLIER	CCI_REG16(0x030e)
+#define S5K3L6_REG_REQUESTED_LINK_RATE	CCI_REG16(0x0820)
+#define S5K3L6_REG_FRAME_LENGTH	CCI_REG16(0x0340)
+#define S5K3L6_REG_LINE_LENGTH	CCI_REG16(0x0342)
+#define S5K3L6_REG_X_ADDR_START	CCI_REG16(0x0344)
+#define S5K3L6_REG_Y_ADDR_START	CCI_REG16(0x0346)
+#define S5K3L6_REG_X_ADDR_END		CCI_REG16(0x0348)
+#define S5K3L6_REG_Y_ADDR_END		CCI_REG16(0x034a)
+#define S5K3L6_REG_X_OUTPUT_SIZE	CCI_REG16(0x034c)
+#define S5K3L6_REG_Y_OUTPUT_SIZE	CCI_REG16(0x034e)
+
+#define S5K3L6_REG_EXPOSURE		CCI_REG16(0x0202)
+#define S5K3L6_EXPOSURE_MIN		2
+#define S5K3L6_EXPOSURE_MARGIN	2
+
+#define S5K3L6_REG_ANALOG_GAIN	CCI_REG16(0x0204)
+#define S5K3L6_ANALOG_GAIN_MIN	0x20
+#define S5K3L6_ANALOG_GAIN_MAX	0x200
+#define S5K3L6_ANALOG_GAIN_DEFAULT	0x20
+
+#define S5K3L6_REG_DIGITAL_GAIN	CCI_REG16(0x020e)
+#define S5K3L6_DIGITAL_GAIN_MIN	0x100
+#define S5K3L6_DIGITAL_GAIN_MAX	0x300
+#define S5K3L6_DIGITAL_GAIN_DEFAULT	0x100
+
+#define S5K3L6_REG_TEST_PATTERN	CCI_REG8(0x0601)
+
+#define S5K3L6_REG_BPC		CCI_REG8(0x3403)
+#define S5K3L6_BPC_FILTER		BIT(0)
+#define S5K3L6_BPC_AF_FILTER		BIT(2)
+
+#define S5K3L6_REG_PLL_PD		CCI_REG8(0x3c1e)
+#define S5K3L6_REG_MIPI_CONTINUOUS	CCI_REG8(0x38a1)
+
+#define to_s5k3l6(_sd)		container_of(_sd, struct s5k3l6, sd)
+
+static const s64 s5k3l6_link_freq_menu[] = {
+	S5K3L6_LINK_FREQ_537P5MHZ,
+	S5K3L6_LINK_FREQ_600MHZ,
+	S5K3L6_LINK_FREQ_625MHZ,
+};
+
+static const char *const s5k3l6_supply_names[] = {
+	"vddio",
+	"vdda",
+	"vddd",
+};
+
+#define S5K3L6_NUM_SUPPLIES	ARRAY_SIZE(s5k3l6_supply_names)
+
+struct s5k3l6_reg_list {
+	const struct cci_reg_sequence *regs;
+	unsigned int num_regs;
+};
+
+struct s5k3l6_mode {
+	u32 width;
+	u32 height;
+	u32 code;
+	u32 hts;
+	u32 vts;
+	u32 data_format;
+	u16 op_pll_multiplier;
+	u8 binning;
+	u8 link_freq_index;
+
+	const struct s5k3l6_reg_list reg_list;
+};
+
+struct s5k3l6 {
+	struct device *dev;
+	struct regmap *regmap;
+	struct clk *mclk;
+	struct gpio_desc *reset_gpio;
+	struct regulator_bulk_data supplies[S5K3L6_NUM_SUPPLIES];
+
+	struct v4l2_subdev sd;
+	struct media_pad pad;
+
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl *link_freq;
+	struct v4l2_ctrl *pixel_rate;
+	struct v4l2_ctrl *hblank;
+	struct v4l2_ctrl *vblank;
+	struct v4l2_ctrl *exposure;
+
+	const struct s5k3l6_mode *mode;
+};
+
+static const struct cci_reg_sequence s5k3l6_binning_4x4[] = {
+	{ CCI_REG8(0x0900), 0x01 },
+	{ CCI_REG8(0x0901), 0x44 },
+	{ CCI_REG8(0x0387), 0x07 },
+	{ CCI_REG16(0x3090), 0x8000 },
+	{ CCI_REG16(0x314a), 0x5f02 },
+	{ CCI_REG16(0x32b2), 0x0006 },
+	{ CCI_REG16(0x32b4), 0x0006 },
+	{ CCI_REG16(0x32b6), 0x0006 },
+	{ CCI_REG16(0x32b8), 0x0006 },
+	{ CCI_REG16(0x3238), 0x000a },
+	{ CCI_REG16(0x380c), 0x003b },
+};
+
+static const struct cci_reg_sequence s5k3l6_binning_2x2[] = {
+	{ CCI_REG8(0x0900), 0x01 },
+	{ CCI_REG8(0x0901), 0x22 },
+	{ CCI_REG8(0x0387), 0x03 },
+	{ CCI_REG16(0x3090), 0x8000 },
+	{ CCI_REG16(0x314a), 0x5f02 },
+	{ CCI_REG16(0x32b2), 0x0003 },
+	{ CCI_REG16(0x32b4), 0x0003 },
+	{ CCI_REG16(0x32b6), 0x0003 },
+	{ CCI_REG16(0x32b8), 0x0003 },
+	{ CCI_REG16(0x3238), 0x000b },
+	{ CCI_REG16(0x380c), 0x0049 },
+};
+
+static const struct cci_reg_sequence s5k3l6_no_binning[] = {
+	{ CCI_REG8(0x0900), 0x00 },
+	{ CCI_REG8(0x0387), 0x01 },
+	{ CCI_REG16(0x3090), 0x8800 },
+	{ CCI_REG16(0x314a), 0x5f00 },
+	{ CCI_REG16(0x32b2), 0x0000 },
+	{ CCI_REG16(0x32b4), 0x0000 },
+	{ CCI_REG16(0x32b6), 0x0000 },
+	{ CCI_REG16(0x32b8), 0x0000 },
+	{ CCI_REG16(0x3238), 0x000c },
+	{ CCI_REG16(0x380c), 0x0090 },
+};
+
+static const struct cci_reg_sequence s5k3l6_common_regs[] = {
+	{ CCI_REG16(0x0136), 0x1900 },
+	{ CCI_REG16(0x0300), 0x0005 },
+	{ CCI_REG16(0x0304), 0x0004 },
+	{ CCI_REG16(0x0306), 0x0060 },
+	{ CCI_REG16(0x030c), 0x0004 },
+	{ CCI_REG16(0x3002), 0x0e00 },
+	{ CCI_REG16(0x3006), 0x1000 },
+	{ CCI_REG16(0x300a), 0x0c00 },
+	{ CCI_REG16(0x3018), 0xc500 },
+	{ CCI_REG16(0x3024), 0x0016 },
+	{ CCI_REG16(0x306a), 0x2f4c },
+	{ CCI_REG16(0x3070), 0x3d00 },
+	{ CCI_REG16(0x3072), 0x0013 },
+	{ CCI_REG16(0x3074), 0x0977 },
+	{ CCI_REG16(0x3076), 0x9411 },
+	{ CCI_REG16(0x307a), 0x0d20 },
+	{ CCI_REG16(0x3084), 0x1314 },
+	{ CCI_REG16(0x309c), 0x0640 },
+	{ CCI_REG16(0x309e), 0x002d },
+	{ CCI_REG16(0x3266), 0x0001 },
+	{ CCI_REG16(0x3452), 0x0000 },
+	{ CCI_REG16(0x345a), 0x0000 },
+	{ CCI_REG16(0x345c), 0x0000 },
+	{ CCI_REG16(0x345e), 0x0000 },
+	{ CCI_REG16(0x3460), 0x0000 },
+	{ CCI_REG16(0x38da), 0x000a },
+	{ CCI_REG16(0x38dc), 0x000b },
+	{ CCI_REG16(0x38d6), 0x000a },
+	{ CCI_REG16(0x3932), 0x1000 },
+	{ CCI_REG16(0x393e), 0x4000 },
+	{ CCI_REG16(0x3c36), 0x2800 },
+	{ CCI_REG16(0x3c38), 0x0028 },
+	{ S5K3L6_REG_MIPI_CONTINUOUS, 0x7e },
+	{ S5K3L6_REG_BPC,
+	  0x42 | S5K3L6_BPC_FILTER | S5K3L6_BPC_AF_FILTER },
+};
+
+static const struct s5k3l6_mode s5k3l6_supported_modes[] = {
+	{
+		.width = 1052,
+		.height = 780,
+		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		.hts = 0x1320,
+		.vts = 0x0331,
+		.data_format = S5K3L6_DATA_FORMAT_RAW8,
+		.op_pll_multiplier = 0x56,
+		.binning = 4,
+		.link_freq_index = 0,
+		.reg_list = {
+			.regs = s5k3l6_binning_4x4,
+			.num_regs = ARRAY_SIZE(s5k3l6_binning_4x4),
+		},
+	}, {
+		.width = 2104,
+		.height = 1560,
+		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		.hts = 0x1320,
+		.vts = 0x0662,
+		.data_format = S5K3L6_DATA_FORMAT_RAW8,
+		.op_pll_multiplier = 0x56,
+		.binning = 2,
+		.link_freq_index = 0,
+		.reg_list = {
+			.regs = s5k3l6_binning_2x2,
+			.num_regs = ARRAY_SIZE(s5k3l6_binning_2x2),
+		},
+	}, {
+		.width = 4208,
+		.height = 3120,
+		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
+		.hts = 0x1ce0,
+		.vts = 0x0cbc,
+		.data_format = S5K3L6_DATA_FORMAT_RAW8,
+		.op_pll_multiplier = 0x64,
+		.binning = 1,
+		.link_freq_index = 2,
+		.reg_list = {
+			.regs = s5k3l6_no_binning,
+			.num_regs = ARRAY_SIZE(s5k3l6_no_binning),
+		},
+	}, {
+		.width = 1052,
+		.height = 780,
+		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		.hts = 0x1320,
+		.vts = 0x0331,
+		.data_format = S5K3L6_DATA_FORMAT_RAW10,
+		.op_pll_multiplier = 0x56,
+		.binning = 4,
+		.link_freq_index = 0,
+		.reg_list = {
+			.regs = s5k3l6_binning_4x4,
+			.num_regs = ARRAY_SIZE(s5k3l6_binning_4x4),
+		},
+	}, {
+		.width = 2104,
+		.height = 1560,
+		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		.hts = 0x1320,
+		.vts = 0x0662,
+		.data_format = S5K3L6_DATA_FORMAT_RAW10,
+		.op_pll_multiplier = 0x60,
+		.binning = 2,
+		.link_freq_index = 1,
+		.reg_list = {
+			.regs = s5k3l6_binning_2x2,
+			.num_regs = ARRAY_SIZE(s5k3l6_binning_2x2),
+		},
+	}, {
+		.width = 4208,
+		.height = 3120,
+		.code = MEDIA_BUS_FMT_SGRBG10_1X10,
+		.hts = 0x2650,
+		.vts = 0x0cbc,
+		.data_format = S5K3L6_DATA_FORMAT_RAW10,
+		.op_pll_multiplier = 0x64,
+		.binning = 1,
+		.link_freq_index = 2,
+		.reg_list = {
+			.regs = s5k3l6_no_binning,
+			.num_regs = ARRAY_SIZE(s5k3l6_no_binning),
+		},
+	},
+};
+
+static const char *const s5k3l6_test_pattern_menu[] = {
+	"Disabled",
+	"Solid color",
+	"Color bars",
+};
+
+static bool s5k3l6_code_supported(u32 code)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(s5k3l6_supported_modes); i++) {
+		if (s5k3l6_supported_modes[i].code == code)
+			return true;
+	}
+
+	return false;
+}
+
+static const struct s5k3l6_mode *s5k3l6_find_mode(u32 code, u32 width,
+						  u32 height)
+{
+	const struct s5k3l6_mode *best = NULL;
+	u32 best_delta = U32_MAX;
+	unsigned int i;
+
+	if (!s5k3l6_code_supported(code))
+		code = s5k3l6_supported_modes[0].code;
+
+	for (i = 0; i < ARRAY_SIZE(s5k3l6_supported_modes); i++) {
+		const struct s5k3l6_mode *mode = &s5k3l6_supported_modes[i];
+		u32 delta;
+
+		if (mode->code != code)
+			continue;
+
+		delta = abs((int)mode->width - (int)width) +
+			abs((int)mode->height - (int)height);
+		if (!best || delta < best_delta) {
+			best = mode;
+			best_delta = delta;
+		}
+	}
+
+	return best;
+}
+
+static void s5k3l6_update_pad_format(const struct s5k3l6_mode *mode,
+				     struct v4l2_mbus_framefmt *fmt)
+{
+	fmt->code = mode->code;
+	fmt->width = mode->width;
+	fmt->height = mode->height;
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = V4L2_COLORSPACE_RAW;
+	fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+	fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+}
+
+static void s5k3l6_update_controls(struct s5k3l6 *s5k3l6,
+				   const struct s5k3l6_mode *mode)
+{
+	u32 hblank = mode->hts - mode->width;
+	u32 vblank = mode->vts - mode->height;
+	u32 exposure_max = mode->vts - S5K3L6_EXPOSURE_MARGIN;
+	u32 exposure_default = min_t(u32, 0x03de, exposure_max);
+
+	__v4l2_ctrl_s_ctrl(s5k3l6->link_freq, mode->link_freq_index);
+	__v4l2_ctrl_modify_range(s5k3l6->hblank, hblank, hblank, 1, hblank);
+	__v4l2_ctrl_modify_range(s5k3l6->vblank, vblank,
+				 0xffff - mode->height, 1, vblank);
+	__v4l2_ctrl_s_ctrl(s5k3l6->vblank, vblank);
+	__v4l2_ctrl_modify_range(s5k3l6->exposure, S5K3L6_EXPOSURE_MIN,
+				 exposure_max, 1, exposure_default);
+	__v4l2_ctrl_s_ctrl(s5k3l6->exposure, exposure_default);
+}
+
+static int s5k3l6_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct s5k3l6 *s5k3l6 =
+		container_of(ctrl->handler, struct s5k3l6, ctrl_handler);
+	const struct s5k3l6_mode *mode = s5k3l6->mode;
+	u32 frame_length;
+	u32 exposure_max;
+	int active;
+	int ret;
+
+	if (ctrl->id == V4L2_CID_VBLANK) {
+		exposure_max =
+			mode->height + ctrl->val - S5K3L6_EXPOSURE_MARGIN;
+		__v4l2_ctrl_modify_range(s5k3l6->exposure,
+					 S5K3L6_EXPOSURE_MIN, exposure_max, 1,
+					 s5k3l6->exposure->default_value);
+	}
+
+	active = pm_runtime_get_if_active(s5k3l6->dev);
+	if (!active)
+		return 0;
+	if (active < 0)
+		return active;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ANALOGUE_GAIN:
+		ret = cci_write(s5k3l6->regmap, S5K3L6_REG_ANALOG_GAIN,
+				ctrl->val, NULL);
+		break;
+	case V4L2_CID_DIGITAL_GAIN:
+		ret = cci_write(s5k3l6->regmap, S5K3L6_REG_DIGITAL_GAIN,
+				ctrl->val, NULL);
+		break;
+	case V4L2_CID_EXPOSURE:
+		ret = cci_write(s5k3l6->regmap, S5K3L6_REG_EXPOSURE,
+				ctrl->val, NULL);
+		break;
+	case V4L2_CID_VBLANK:
+		frame_length = mode->height + ctrl->val;
+		ret = cci_write(s5k3l6->regmap, S5K3L6_REG_FRAME_LENGTH,
+				frame_length, NULL);
+		break;
+	case V4L2_CID_TEST_PATTERN:
+		ret = cci_write(s5k3l6->regmap, S5K3L6_REG_TEST_PATTERN,
+				ctrl->val, NULL);
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	pm_runtime_put(s5k3l6->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops s5k3l6_ctrl_ops = {
+	.s_ctrl = s5k3l6_set_ctrl,
+};
+
+static int s5k3l6_init_controls(struct s5k3l6 *s5k3l6)
+{
+	struct v4l2_ctrl_handler *ctrl_hdlr = &s5k3l6->ctrl_handler;
+	const struct v4l2_ctrl_ops *ops = &s5k3l6_ctrl_ops;
+	const struct s5k3l6_mode *mode = s5k3l6->mode;
+	struct v4l2_fwnode_device_properties props;
+	u32 hblank = mode->hts - mode->width;
+	u32 vblank = mode->vts - mode->height;
+	u32 exposure_max = mode->vts - S5K3L6_EXPOSURE_MARGIN;
+	u32 exposure_default = min_t(u32, 0x03de, exposure_max);
+	int ret;
+
+	v4l2_ctrl_handler_init(ctrl_hdlr, 10);
+
+	s5k3l6->link_freq =
+		v4l2_ctrl_new_int_menu(ctrl_hdlr, &s5k3l6_ctrl_ops,
+				       V4L2_CID_LINK_FREQ,
+				       ARRAY_SIZE(s5k3l6_link_freq_menu) - 1,
+				       mode->link_freq_index,
+				       s5k3l6_link_freq_menu);
+	if (s5k3l6->link_freq)
+		s5k3l6->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	s5k3l6->pixel_rate =
+		v4l2_ctrl_new_std(ctrl_hdlr, &s5k3l6_ctrl_ops,
+				  V4L2_CID_PIXEL_RATE, S5K3L6_PIXEL_RATE,
+				  S5K3L6_PIXEL_RATE, 1, S5K3L6_PIXEL_RATE);
+	if (s5k3l6->pixel_rate)
+		s5k3l6->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	s5k3l6->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3l6_ctrl_ops,
+					   V4L2_CID_HBLANK, hblank, hblank, 1,
+					   hblank);
+	if (s5k3l6->hblank)
+		s5k3l6->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	s5k3l6->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &s5k3l6_ctrl_ops,
+					   V4L2_CID_VBLANK, vblank,
+					   0xffff - mode->height, 1, vblank);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &s5k3l6_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+			  S5K3L6_ANALOG_GAIN_MIN, S5K3L6_ANALOG_GAIN_MAX, 1,
+			  S5K3L6_ANALOG_GAIN_DEFAULT);
+
+	v4l2_ctrl_new_std(ctrl_hdlr, &s5k3l6_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+			  S5K3L6_DIGITAL_GAIN_MIN, S5K3L6_DIGITAL_GAIN_MAX,
+			  1, S5K3L6_DIGITAL_GAIN_DEFAULT);
+
+	s5k3l6->exposure =
+		v4l2_ctrl_new_std(ctrl_hdlr, ops, V4L2_CID_EXPOSURE,
+				  S5K3L6_EXPOSURE_MIN, exposure_max, 1,
+				  exposure_default);
+
+	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &s5k3l6_ctrl_ops,
+				     V4L2_CID_TEST_PATTERN,
+				     ARRAY_SIZE(s5k3l6_test_pattern_menu) - 1,
+				     0, 0, s5k3l6_test_pattern_menu);
+
+	if (ctrl_hdlr->error) {
+		ret = ctrl_hdlr->error;
+		goto error_free_hdlr;
+	}
+
+	ret = v4l2_fwnode_device_parse(s5k3l6->dev, &props);
+	if (ret)
+		goto error_free_hdlr;
+
+	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &s5k3l6_ctrl_ops,
+					      &props);
+	if (ret)
+		goto error_free_hdlr;
+
+	s5k3l6->sd.ctrl_handler = ctrl_hdlr;
+
+	return 0;
+
+error_free_hdlr:
+	v4l2_ctrl_handler_free(ctrl_hdlr);
+
+	return ret;
+}
+
+static int s5k3l6_write_mode(struct s5k3l6 *s5k3l6)
+{
+	const struct s5k3l6_mode *mode = s5k3l6->mode;
+	u64 link_freq = s5k3l6_link_freq_menu[mode->link_freq_index];
+	/*
+	 * Match downstream integer-MHz programming. The 537.5 MHz mode uses
+	 * 1074 here, not the rounded 1075 Mb/s DDR lane rate.
+	 */
+	u16 link_rate = div_u64(link_freq, HZ_PER_MHZ) * 2;
+	u32 crop_width = mode->width * mode->binning;
+	u32 crop_height = mode->height * mode->binning;
+	u32 x_start = S5K3L6_ACTIVE_LEFT;
+	u32 y_start = S5K3L6_ACTIVE_TOP;
+	u32 x_end = x_start + crop_width - 1;
+	u32 y_end = y_start + crop_height - 1;
+	struct cci_reg_sequence crop_regs[] = {
+		{ S5K3L6_REG_X_OUTPUT_SIZE, mode->width },
+		{ S5K3L6_REG_Y_OUTPUT_SIZE, mode->height },
+		{ S5K3L6_REG_Y_ADDR_START, y_start },
+		{ S5K3L6_REG_Y_ADDR_END, y_end },
+		{ S5K3L6_REG_X_ADDR_START, x_start },
+		{ S5K3L6_REG_X_ADDR_END, x_end },
+	};
+	struct cci_reg_sequence format_regs[] = {
+		{ S5K3L6_REG_DATA_FORMAT, mode->data_format },
+		{ S5K3L6_REG_LANE_MODE, S5K3L6_DATA_LANES - 1 },
+		{ S5K3L6_REG_OP_PLL_MULTIPLIER, mode->op_pll_multiplier },
+		{ S5K3L6_REG_REQUESTED_LINK_RATE, link_rate },
+		{ S5K3L6_REG_LINE_LENGTH, mode->hts },
+	};
+	int ret = 0;
+
+	cci_multi_reg_write(s5k3l6->regmap, crop_regs, ARRAY_SIZE(crop_regs),
+			    &ret);
+	cci_multi_reg_write(s5k3l6->regmap, mode->reg_list.regs,
+			    mode->reg_list.num_regs, &ret);
+	cci_multi_reg_write(s5k3l6->regmap, s5k3l6_common_regs,
+			    ARRAY_SIZE(s5k3l6_common_regs), &ret);
+	cci_multi_reg_write(s5k3l6->regmap, format_regs,
+			    ARRAY_SIZE(format_regs), &ret);
+
+	return ret;
+}
+
+static int s5k3l6_enable_streams(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state, u32 pad,
+				 u64 streams_mask)
+{
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(s5k3l6->dev);
+	if (ret)
+		return ret;
+
+	cci_write(s5k3l6->regmap, S5K3L6_REG_PLL_PD, 0x01, &ret);
+	if (ret)
+		goto error;
+
+	ret = s5k3l6_write_mode(s5k3l6);
+	if (ret)
+		goto error;
+
+	ret = __v4l2_ctrl_handler_setup(s5k3l6->sd.ctrl_handler);
+	if (ret)
+		goto error;
+
+	cci_write(s5k3l6->regmap, S5K3L6_REG_MODE_SELECT,
+		  S5K3L6_MODE_STREAMING, &ret);
+	cci_write(s5k3l6->regmap, S5K3L6_REG_PLL_PD, 0x00, &ret);
+	if (ret)
+		goto error;
+
+	return 0;
+
+error:
+	dev_err(s5k3l6->dev, "failed to start streaming: %d\n", ret);
+	pm_runtime_put_autosuspend(s5k3l6->dev);
+
+	return ret;
+}
+
+static int s5k3l6_disable_streams(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state, u32 pad,
+				  u64 streams_mask)
+{
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+	int ret;
+
+	ret = cci_write(s5k3l6->regmap, S5K3L6_REG_MODE_SELECT,
+			S5K3L6_MODE_STANDBY, NULL);
+	if (ret)
+		dev_err(s5k3l6->dev, "failed to stop streaming: %d\n", ret);
+
+	pm_runtime_put_autosuspend(s5k3l6->dev);
+
+	return ret;
+}
+
+static int s5k3l6_set_pad_format(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state,
+				 struct v4l2_subdev_format *fmt)
+{
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+	const struct s5k3l6_mode *mode;
+
+	mode = s5k3l6_find_mode(fmt->format.code, fmt->format.width,
+				fmt->format.height);
+	s5k3l6_update_pad_format(mode, &fmt->format);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && s5k3l6->mode != mode) {
+		s5k3l6->mode = mode;
+		s5k3l6_update_controls(s5k3l6, mode);
+	}
+
+	*v4l2_subdev_state_get_format(state, 0) = fmt->format;
+
+	return 0;
+}
+
+static int s5k3l6_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_state *state,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	static const u32 codes[] = {
+		MEDIA_BUS_FMT_SGRBG8_1X8,
+		MEDIA_BUS_FMT_SGRBG10_1X10,
+	};
+
+	if (code->index >= ARRAY_SIZE(codes))
+		return -EINVAL;
+
+	code->code = codes[code->index];
+
+	return 0;
+}
+
+static int s5k3l6_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_state *state,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	unsigned int index = 0;
+	unsigned int i;
+
+	if (!s5k3l6_code_supported(fse->code))
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(s5k3l6_supported_modes); i++) {
+		const struct s5k3l6_mode *mode = &s5k3l6_supported_modes[i];
+
+		if (mode->code != fse->code)
+			continue;
+
+		if (index++ != fse->index)
+			continue;
+
+		fse->min_width = mode->width;
+		fse->max_width = mode->width;
+		fse->min_height = mode->height;
+		fse->max_height = mode->height;
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int s5k3l6_get_selection(struct v4l2_subdev *sd,
+				struct v4l2_subdev_state *state,
+				struct v4l2_subdev_selection *sel)
+{
+	switch (sel->target) {
+	case V4L2_SEL_TGT_NATIVE_SIZE:
+		sel->r.left = 0;
+		sel->r.top = 0;
+		sel->r.width = S5K3L6_PIXEL_ARRAY_WIDTH;
+		sel->r.height = S5K3L6_PIXEL_ARRAY_HEIGHT;
+		return 0;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP:
+		sel->r.left = S5K3L6_ACTIVE_LEFT;
+		sel->r.top = S5K3L6_ACTIVE_TOP;
+		sel->r.width = S5K3L6_ACTIVE_WIDTH;
+		sel->r.height = S5K3L6_ACTIVE_HEIGHT;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int s5k3l6_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+				  struct v4l2_mbus_config *config)
+{
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+	const struct s5k3l6_mode *mode = s5k3l6->mode;
+
+	if (pad)
+		return -EINVAL;
+
+	*config = (struct v4l2_mbus_config) {
+		.type = V4L2_MBUS_CSI2_DPHY,
+		.link_freq = s5k3l6_link_freq_menu[mode->link_freq_index],
+	};
+	config->bus.mipi_csi2.num_data_lanes = S5K3L6_DATA_LANES;
+
+	return 0;
+}
+
+static int s5k3l6_init_state(struct v4l2_subdev *sd,
+			     struct v4l2_subdev_state *state)
+{
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+	struct v4l2_subdev_format fmt = {
+		.which = V4L2_SUBDEV_FORMAT_TRY,
+		.pad = 0,
+		.format = {
+			.code = s5k3l6->mode->code,
+			.width = s5k3l6->mode->width,
+			.height = s5k3l6->mode->height,
+		},
+	};
+
+	s5k3l6_set_pad_format(sd, state, &fmt);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_video_ops s5k3l6_video_ops = {
+	.s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops s5k3l6_pad_ops = {
+	.set_fmt = s5k3l6_set_pad_format,
+	.get_fmt = v4l2_subdev_get_fmt,
+	.get_selection = s5k3l6_get_selection,
+	.get_mbus_config = s5k3l6_get_mbus_config,
+	.enum_mbus_code = s5k3l6_enum_mbus_code,
+	.enum_frame_size = s5k3l6_enum_frame_size,
+	.enable_streams = s5k3l6_enable_streams,
+	.disable_streams = s5k3l6_disable_streams,
+};
+
+static const struct v4l2_subdev_ops s5k3l6_subdev_ops = {
+	.video = &s5k3l6_video_ops,
+	.pad = &s5k3l6_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops s5k3l6_internal_ops = {
+	.init_state = s5k3l6_init_state,
+};
+
+static const struct media_entity_operations s5k3l6_entity_ops = {
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+static int s5k3l6_identify_sensor(struct s5k3l6 *s5k3l6)
+{
+	u64 val;
+	int ret;
+
+	ret = cci_read(s5k3l6->regmap, S5K3L6_REG_CHIP_ID, &val, NULL);
+	if (ret)
+		return dev_err_probe(s5k3l6->dev, ret,
+				     "failed to read chip id\n");
+
+	if (val != S5K3L6_CHIP_ID)
+		return dev_err_probe(s5k3l6->dev, -ENODEV,
+				     "chip id mismatch: %x != %llx\n",
+				     S5K3L6_CHIP_ID, val);
+
+	ret = cci_read(s5k3l6->regmap, S5K3L6_REG_REVISION, &val, NULL);
+	if (ret)
+		return dev_err_probe(s5k3l6->dev, ret,
+				     "failed to read revision\n");
+
+	if (val != S5K3L6_REVISION)
+		return dev_err_probe(s5k3l6->dev, -ENODEV,
+				     "revision mismatch: %x != %llx\n",
+				     S5K3L6_REVISION, val);
+
+	return 0;
+}
+
+static int s5k3l6_check_hwcfg(struct s5k3l6 *s5k3l6)
+{
+	struct fwnode_handle *fwnode = dev_fwnode(s5k3l6->dev);
+	struct v4l2_fwnode_endpoint bus_cfg = {
+		.bus = {
+			.mipi_csi2 = {
+				.num_data_lanes = S5K3L6_DATA_LANES,
+			},
+		},
+		.bus_type = V4L2_MBUS_CSI2_DPHY,
+	};
+	struct fwnode_handle *ep;
+	unsigned long freq_bitmap;
+	unsigned long expected_bitmap;
+	int ret;
+
+	if (!fwnode)
+		return -ENODEV;
+
+	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+	if (!ep)
+		return -EINVAL;
+
+	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+	fwnode_handle_put(ep);
+	if (ret)
+		return ret;
+
+	if (bus_cfg.bus.mipi_csi2.num_data_lanes != S5K3L6_DATA_LANES) {
+		dev_err(s5k3l6->dev, "only %u data lanes are supported\n",
+			S5K3L6_DATA_LANES);
+		ret = -EINVAL;
+		goto endpoint_free;
+	}
+
+	ret = v4l2_link_freq_to_bitmap(s5k3l6->dev, bus_cfg.link_frequencies,
+				       bus_cfg.nr_of_link_frequencies,
+				       s5k3l6_link_freq_menu,
+				       ARRAY_SIZE(s5k3l6_link_freq_menu),
+				       &freq_bitmap);
+	if (ret)
+		goto endpoint_free;
+
+	expected_bitmap = GENMASK(ARRAY_SIZE(s5k3l6_link_freq_menu) - 1, 0);
+	if (freq_bitmap != expected_bitmap) {
+		dev_err(s5k3l6->dev, "not all link frequencies are listed\n");
+		ret = -EINVAL;
+	}
+
+endpoint_free:
+	v4l2_fwnode_endpoint_free(&bus_cfg);
+
+	return ret;
+}
+
+static int s5k3l6_power_on(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+	int ret;
+
+	ret = regulator_bulk_enable(S5K3L6_NUM_SUPPLIES, s5k3l6->supplies);
+	if (ret)
+		return ret;
+
+	usleep_range(10, 20);
+
+	ret = clk_prepare_enable(s5k3l6->mclk);
+	if (ret)
+		goto disable_regulators;
+
+	gpiod_set_value_cansleep(s5k3l6->reset_gpio, 0);
+	usleep_range(USEC_PER_MSEC, 1200);
+
+	gpiod_set_value_cansleep(s5k3l6->reset_gpio, 1);
+	usleep_range(400, 800);
+	gpiod_set_value_cansleep(s5k3l6->reset_gpio, 0);
+
+	usleep_range(10 * USEC_PER_MSEC, 11 * USEC_PER_MSEC);
+
+	return 0;
+
+disable_regulators:
+	regulator_bulk_disable(S5K3L6_NUM_SUPPLIES, s5k3l6->supplies);
+
+	return ret;
+}
+
+static int s5k3l6_power_off(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+
+	gpiod_set_value_cansleep(s5k3l6->reset_gpio, 1);
+	clk_disable_unprepare(s5k3l6->mclk);
+
+	return regulator_bulk_disable(S5K3L6_NUM_SUPPLIES,
+				      s5k3l6->supplies);
+}
+
+static int s5k3l6_probe(struct i2c_client *client)
+{
+	struct s5k3l6 *s5k3l6;
+	unsigned long freq;
+	unsigned int i;
+	int ret;
+
+	s5k3l6 = devm_kzalloc(&client->dev, sizeof(*s5k3l6), GFP_KERNEL);
+	if (!s5k3l6)
+		return -ENOMEM;
+
+	s5k3l6->dev = &client->dev;
+	v4l2_i2c_subdev_init(&s5k3l6->sd, client, &s5k3l6_subdev_ops);
+
+	s5k3l6->regmap = devm_cci_regmap_init_i2c(client, 16);
+	if (IS_ERR(s5k3l6->regmap))
+		return dev_err_probe(s5k3l6->dev, PTR_ERR(s5k3l6->regmap),
+				     "failed to init CCI\n");
+
+	s5k3l6->mclk = devm_v4l2_sensor_clk_get(s5k3l6->dev, NULL);
+	if (IS_ERR(s5k3l6->mclk))
+		return dev_err_probe(s5k3l6->dev, PTR_ERR(s5k3l6->mclk),
+				     "failed to get clock\n");
+
+	freq = clk_get_rate(s5k3l6->mclk);
+	if (freq != S5K3L6_MCLK_FREQ)
+		return dev_err_probe(s5k3l6->dev, -EINVAL,
+				     "clock frequency %lu is not supported\n",
+				     freq);
+
+	ret = s5k3l6_check_hwcfg(s5k3l6);
+	if (ret)
+		return dev_err_probe(s5k3l6->dev, ret,
+				     "failed to check HW configuration\n");
+
+	s5k3l6->reset_gpio =
+		devm_gpiod_get_optional(s5k3l6->dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(s5k3l6->reset_gpio))
+		return dev_err_probe(s5k3l6->dev,
+				     PTR_ERR(s5k3l6->reset_gpio),
+				     "failed to get reset GPIO\n");
+
+	for (i = 0; i < S5K3L6_NUM_SUPPLIES; i++)
+		s5k3l6->supplies[i].supply = s5k3l6_supply_names[i];
+
+	ret = devm_regulator_bulk_get(s5k3l6->dev, S5K3L6_NUM_SUPPLIES,
+				      s5k3l6->supplies);
+	if (ret)
+		return dev_err_probe(s5k3l6->dev, ret,
+				     "failed to get supplies\n");
+
+	ret = s5k3l6_power_on(s5k3l6->dev);
+	if (ret)
+		return ret;
+
+	ret = s5k3l6_identify_sensor(s5k3l6);
+	if (ret)
+		goto power_off;
+
+	s5k3l6->mode = &s5k3l6_supported_modes[0];
+	ret = s5k3l6_init_controls(s5k3l6);
+	if (ret)
+		goto power_off;
+
+	s5k3l6->sd.state_lock = s5k3l6->ctrl_handler.lock;
+	s5k3l6->sd.internal_ops = &s5k3l6_internal_ops;
+	s5k3l6->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	s5k3l6->sd.entity.ops = &s5k3l6_entity_ops;
+	s5k3l6->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	s5k3l6->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&s5k3l6->sd.entity, 1, &s5k3l6->pad);
+	if (ret)
+		goto free_ctrls;
+
+	ret = v4l2_subdev_init_finalize(&s5k3l6->sd);
+	if (ret)
+		goto cleanup_entity;
+
+	pm_runtime_set_active(s5k3l6->dev);
+	pm_runtime_enable(s5k3l6->dev);
+
+	ret = v4l2_async_register_subdev_sensor(&s5k3l6->sd);
+	if (ret)
+		goto cleanup_subdev;
+
+	pm_runtime_set_autosuspend_delay(s5k3l6->dev, 1000);
+	pm_runtime_use_autosuspend(s5k3l6->dev);
+	pm_runtime_idle(s5k3l6->dev);
+
+	return 0;
+
+cleanup_subdev:
+	v4l2_subdev_cleanup(&s5k3l6->sd);
+	pm_runtime_disable(s5k3l6->dev);
+	pm_runtime_set_suspended(s5k3l6->dev);
+
+cleanup_entity:
+	media_entity_cleanup(&s5k3l6->sd.entity);
+
+free_ctrls:
+	v4l2_ctrl_handler_free(s5k3l6->sd.ctrl_handler);
+
+power_off:
+	s5k3l6_power_off(s5k3l6->dev);
+
+	return ret;
+}
+
+static void s5k3l6_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct s5k3l6 *s5k3l6 = to_s5k3l6(sd);
+
+	v4l2_async_unregister_subdev(sd);
+	v4l2_subdev_cleanup(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(sd->ctrl_handler);
+	pm_runtime_disable(s5k3l6->dev);
+
+	if (!pm_runtime_status_suspended(s5k3l6->dev)) {
+		s5k3l6_power_off(s5k3l6->dev);
+		pm_runtime_set_suspended(s5k3l6->dev);
+	}
+}
+
+static const struct dev_pm_ops s5k3l6_pm_ops = {
+	SET_RUNTIME_PM_OPS(s5k3l6_power_off, s5k3l6_power_on, NULL)
+};
+
+static const struct of_device_id s5k3l6_of_match[] = {
+	{ .compatible = "samsung,s5k3l6" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s5k3l6_of_match);
+
+static struct i2c_driver s5k3l6_i2c_driver = {
+	.driver = {
+		.name = "s5k3l6",
+		.pm = &s5k3l6_pm_ops,
+		.of_match_table = s5k3l6_of_match,
+	},
+	.probe = s5k3l6_probe,
+	.remove = s5k3l6_remove,
+};
+
+module_i2c_driver(s5k3l6_i2c_driver);
+
+MODULE_DESCRIPTION("Samsung S5K3L6 image sensor driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0


^ permalink raw reply related

* [PATCH RFC 4/4] arm64: dts: imx8mq-librem5: Add rear camera
From: Vincent Cloutier @ 2026-06-26  0:07 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel
  Cc: linux-kernel, linux-imx, kernel, Vincent Cloutier, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, imx
In-Reply-To: <20260626000715.1111803-1-vincent.cloutier@icloud.com>

From: Vincent Cloutier <vincent@cloutier.co>

Add the Librem 5 rear camera sensor node and enable the second CSI-2
capture path that receives data from it.

Describe the Samsung S5K3L6 sensor with the upstream binding property
names, including reset-gpios and the link frequencies used by the initial
two-lane RAW8/RAW10 driver modes.

Signed-off-by: Vincent Cloutier <vincent@cloutier.co>
Assisted-by: OpenCode:gpt-5.5
---
 arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi | 51 +++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
index f5d529c5baf3..12d5fb3440c5 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
@@ -318,6 +318,10 @@ &csi1 {
 	status = "okay";
 };
 
+&csi2 {
+	status = "okay";
+};
+
 &ddrc {
 	operating-points-v2 = <&ddrc_opp_table>;
 	status = "okay";
@@ -434,6 +438,13 @@ MX8MQ_IOMUXC_ENET_RXC_GPIO1_IO25	0x83
 		>;
 	};
 
+	pinctrl_csi2: csi2grp {
+		fsl,pins = <
+			/* CSI2_NRST */
+			MX8MQ_IOMUXC_ENET_RD0_GPIO1_IO26	0x83
+		>;
+	};
+
 	pinctrl_charger_in: chargeringrp {
 		fsl,pins = <
 			/* CHRG_INT */
@@ -1175,6 +1186,31 @@ vcm@c {
 		vcc-supply = <&reg_csi_1v8>;
 	};
 
+	camera_rear: camera@2d {
+		compatible = "samsung,s5k3l6";
+		reg = <0x2d>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_csi2>;
+		clocks = <&clk IMX8MQ_CLK_CLKO2>;
+		assigned-clocks = <&clk IMX8MQ_CLK_CLKO2>;
+		assigned-clock-rates = <25000000>;
+		reset-gpios = <&gpio1 26 GPIO_ACTIVE_LOW>;
+		vdda-supply = <&reg_vcam_2v8>;
+		vddd-supply = <&reg_vcam_1v2>;
+		vddio-supply = <&reg_csi_1v8>;
+		rotation = <270>;
+		orientation = <1>;
+
+		port {
+			camera2_ep: endpoint {
+				data-lanes = <1 2>;
+				link-frequencies = /bits/ 64
+					<537500000 600000000 625000000>;
+				remote-endpoint = <&mipi2_sensor_ep>;
+			};
+		};
+	};
+
 	bat: fuel-gauge@36 {
 		compatible = "maxim,max17055";
 		reg = <0x36>;
@@ -1226,6 +1262,21 @@ mipi1_sensor_ep: endpoint {
 	};
 };
 
+&mipi_csi2 {
+	status = "okay";
+
+	ports {
+		port@0 {
+			reg = <0>;
+
+			mipi2_sensor_ep: endpoint {
+				remote-endpoint = <&camera2_ep>;
+				data-lanes = <1 2>;
+			};
+		};
+	};
+};
+
 &mipi_dsi {
 	#address-cells = <1>;
 	#size-cells = <0>;
-- 
2.53.0


^ permalink raw reply related

* [PATCH RFC 2/4] dt-bindings: media: i2c: Add Samsung S5K3L6 image sensor
From: Vincent Cloutier @ 2026-06-26  0:06 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel
  Cc: linux-kernel, linux-imx, kernel, Vincent Cloutier,
	Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
In-Reply-To: <20260626000715.1111803-1-vincent.cloutier@icloud.com>

From: Vincent Cloutier <vincent@cloutier.co>

Add a devicetree binding for the Samsung S5K3L6 13MP raw Bayer image
sensor.

This starts the upstreaming work for the Librem 5 rear camera path. The
binding describes the validated two-lane MIPI CSI-2 configuration.

Signed-off-by: Vincent Cloutier <vincent@cloutier.co>
Assisted-by: OpenCode:gpt-5.5
---
 .../bindings/media/i2c/samsung,s5k3l6.yaml         | 117 +++++++++++++++++++++
 1 file changed, 117 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/samsung,s5k3l6.yaml b/Documentation/devicetree/bindings/media/i2c/samsung,s5k3l6.yaml
new file mode 100644
index 000000000000..96150764b341
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/samsung,s5k3l6.yaml
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/samsung,s5k3l6.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S5K3L6 13MP MIPI CSI-2 image sensor
+
+maintainers:
+  - Vincent Cloutier <vincent@cloutier.co>
+  - Purism Kernel Team <kernel@puri.sm>
+
+description: |-
+  The Samsung S5K3L6 is a raw Bayer image sensor with a MIPI CSI-2 image
+  data interface and an I2C-compatible control bus.
+
+allOf:
+  - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+  compatible:
+    const: samsung,s5k3l6
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description: Reference to the sensor input clock.
+    maxItems: 1
+
+  reset-gpios:
+    description: Active-low reset GPIO.
+    maxItems: 1
+
+  vdda-supply:
+    description: Analog power supply.
+
+  vddd-supply:
+    description: Digital core power supply.
+
+  vddio-supply:
+    description: Digital I/O power supply.
+
+  port:
+    $ref: /schemas/graph.yaml#/$defs/port-base
+    unevaluatedProperties: false
+
+    properties:
+      endpoint:
+        $ref: /schemas/media/video-interfaces.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          data-lanes:
+            items:
+              - const: 1
+              - const: 2
+
+          link-frequencies:
+            minItems: 3
+            maxItems: 3
+            items:
+              - const: 537500000
+              - const: 600000000
+              - const: 625000000
+
+        required:
+          - data-lanes
+          - link-frequencies
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - vdda-supply
+  - vddd-supply
+  - vddio-supply
+  - port
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/imx8mq-clock.h>
+    #include <dt-bindings/gpio/gpio.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        camera@2d {
+            compatible = "samsung,s5k3l6";
+            reg = <0x2d>;
+
+            clocks = <&clk IMX8MQ_CLK_CLKO2>;
+            assigned-clocks = <&clk IMX8MQ_CLK_CLKO2>;
+            assigned-clock-rates = <25000000>;
+
+            reset-gpios = <&gpio1 26 GPIO_ACTIVE_LOW>;
+            vdda-supply = <&reg_camera_vdda>;
+            vddd-supply = <&reg_camera_vddd>;
+            vddio-supply = <&reg_camera_vddio>;
+
+            orientation = <1>;
+            rotation = <270>;
+
+            port {
+                camera_out: endpoint {
+                    data-lanes = <1 2>;
+                    link-frequencies = /bits/ 64
+                        <537500000 600000000 625000000>;
+                    remote-endpoint = <&mipi_csi2_in>;
+                };
+            };
+        };
+    };
+...
-- 
2.53.0


^ permalink raw reply related

* [PATCH RFC 1/4] media: imx8mq-mipi-csi2: Make reset release SoC-specific
From: Vincent Cloutier @ 2026-06-26  0:06 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel
  Cc: linux-kernel, linux-imx, kernel, Vincent Cloutier,
	Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
	Rui Miguel Silva, Mauro Carvalho Chehab, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Philipp Zabel, imx
In-Reply-To: <20260626000715.1111803-1-vincent.cloutier@icloud.com>

From: Vincent Cloutier <vincent@cloutier.co>

The CSI-2 software reset helper currently asserts the reset control and
then releases it again unconditionally.

That release step is required by the i.MX8QXP path, but it changes the
reset sequence used by i.MX8MQ. On Librem 5r4, which is i.MX8MQ-based,
the unconditional release step prevents the camera pipeline from producing
frames after reset; captures time out waiting for EOF from the CSI bridge.

This series enables the Librem 5 rear camera on the second i.MX8MQ CSI-2
receiver. Keep the i.MX8MQ path on the known-working assert-only software
reset sequence while preserving the explicit release step for i.MX8QXP.

Make reset release opt-in through platform data.

Tested on Librem 5r4 with the existing HI846 front camera and the S5K3L6
rear camera added by this series.

Signed-off-by: Vincent Cloutier <vincent@cloutier.co>
Assisted-by: OpenCode:gpt-5.5
---
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index 950793297496..xxxxxxxxxxxx 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -76,6 +76,7 @@ struct imx8mq_plat_data {
 	int (*enable)(struct csi_state *state, u32 hs_settle);
 	void (*disable)(struct csi_state *state);
 	bool use_reg_csr;
+	bool needs_reset_deassert;
 };
 
 /*
@@ -244,6 +245,7 @@ static const struct imx8mq_plat_data imx8qxp_data = {
 	.enable = imx8qxp_gpr_enable,
 	.disable = imx8qxp_gpr_disable,
 	.use_reg_csr = true,
+	.needs_reset_deassert = true,
 };
 
 static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = {
@@ -363,8 +365,12 @@ static int imx8mq_mipi_csi_sw_reset(struct csi_state *state)
 		return ret;
 	}
 
-	/* Explicitly release reset to make sure reset bits are cleared. */
-	return reset_control_deassert(state->rst);
+	/*
+	 * Some SoC integrations require an explicit release after reset
+	 * assertion. Keep this SoC-specific so i.MX8MQ retains its
+	 * known-working assert-only sequence.
+	 */
+	if (!state->pdata->needs_reset_deassert)
+		return 0;
+
+	return reset_control_deassert(state->rst);
 }
 
 static void imx8mq_mipi_csi_set_params(struct csi_state *state)
-- 
2.53.0


^ permalink raw reply

* [PATCH RFC 0/4] media: i2c: Add Samsung S5K3L6 and Librem 5 rear camera
From: Vincent Cloutier @ 2026-06-26  0:06 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel
  Cc: linux-kernel, linux-imx, kernel, Vincent Cloutier

From: Vincent Cloutier <vincent@cloutier.co>

This RFC fixes the i.MX8MQ CSI-2 reset path needed by Librem 5 camera
capture, adds initial upstream support for the Samsung S5K3L6 image
sensor, and wires it up as the rear camera on the Purism Librem 5.

This is intentionally a rewrite, not a direct forwarding of the Librem 5
downstream S5K3L6 carry. The downstream history is a long bring-up
series with debugfs register overrides, debug-frame plumbing, commented-out
old subdev code, FIXME/TODO scaffolding, and several API-era migrations.
This RFC collapses the usable production path into a current V4L2 sensor
driver using CCI regmap, runtime PM, fwnode endpoint validation, and the
current subdev stream API.

Many thanks to Martin Kepplinger, Dorota Czaplejewicz, and Sebastian
Krzyszkowiak for the original Librem 5 S5K3L6 driver work and rear-camera
bring-up. Martin authored the initial downstream driver, and Dorota and
Sebastian substantially developed the mode tables, controls, power-up
sequence, and sensor tuning that this rewrite is based on.

This series covers:

- 25 MHz input clock, matching the Librem 5 downstream configuration
- two MIPI CSI-2 data lanes
- RAW8 and RAW10 SGRBG modes at 1052x780, 2104x1560, and 4208x3120
- exposure, analogue gain, digital gain, blanking, pixel-rate,
  link-frequency, test-pattern, orientation, and rotation controls
- Librem 5 DTS integration for the rear sensor and second CSI-2 path

The rewritten driver and DTS path have now been tested on Librem 5r4
hardware in a v7.1.1 carry build, with the i.MX8MQ CSI-2 reset fix from this
series applied.

Patch 1 keeps the i.MX8MQ CSI-2 software reset sequence compatible with
the Librem 5 camera pipeline by making the post-assert reset release
SoC-specific. This is included as an RFC prerequisite for the Librem 5
rear-camera enablement; if preferred, it can be split out and handled as
a separate media/platform fix.

Vincent Cloutier (4):
  media: imx8mq-mipi-csi2: Keep i.MX8MQ reset assert-only
  dt-bindings: media: i2c: Add Samsung S5K3L6 image sensor
  media: i2c: Add Samsung S5K3L6 image sensor driver
  arm64: dts: imx8mq-librem5: Add rear camera

 .../bindings/media/i2c/samsung,s5k3l6.yaml    | 117 ++
 arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi |  51 +
 drivers/media/i2c/Kconfig                         |  10 +
 drivers/media/i2c/Makefile                        |   1 +
 drivers/media/i2c/s5k3l6.c                         | 1055 +++++++++++++++++
 drivers/media/platform/nxp/imx8mq-mipi-csi2.c     |   9 +-
 6 files changed, 1241 insertions(+), 2 deletions(-)

-- 
2.53.0


^ permalink raw reply

* Re: [PATCH v4 2/2] tracing: Remove trace_printk.h from kernel.h
From: Nathan Chancellor @ 2026-06-25 23:41 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, linux-trace-kernel, Masami Hiramatsu, Mark Rutland,
	Mathieu Desnoyers, Andrew Morton, Linus Torvalds,
	Sebastian Andrzej Siewior, John Ogness, Thomas Gleixner,
	Peter Zijlstra, Julia Lawall, Yury Norov, linux-doc, linux-kbuild,
	linuxppc-dev, dri-devel, linux-stm32, linux-arm-kernel,
	linux-rdma, linux-usb, linux-ext4, linux-nfs, kvm, intel-gfx
In-Reply-To: <20260625104402.210473477@kernel.org>

Hi Steve,

On Thu, Jun 25, 2026 at 06:40:09AM -0400, Steven Rostedt wrote:
> From: Steven Rostedt <rostedt@goodmis.org>
> 
> There have been complaints about trace_printk.h causing more build time
> for being in kernel.h if it changes. There is also an effort to clean up
> kernel.h to have it not include unneeded header files. Move trace_printk.h
> out of kernel.h and place it in the headers and C files that use it.
> 
> Link: https://lore.kernel.org/all/CAHk-=wikCBeVFjVXiY4o-oepdbjAoir5+TcAgtL12c4u1TpZLQ@mail.gmail.com/
> 
> Suggested-by: Yury Norov <yury.norov@gmail.com>
> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

This patch breaks lib/test_context-analysis.c for me in several
configurations:

  In file included from lib/test_context-analysis.c:9:
  In file included from include/linux/local_lock.h:5:
  include/linux/local_lock_internal.h:46:2: error: use of undeclared identifier '_THIS_IP_'
     46 |         lock_map_acquire(&l->dep_map);
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  include/linux/lockdep.h:541:69: note: expanded from macro 'lock_map_acquire'
    541 | #define lock_map_acquire(l)                     lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_)
        |                                                                                       ^~~~~~~~~
  In file included from lib/test_context-analysis.c:9:
  In file included from include/linux/local_lock.h:5:
  include/linux/local_lock_internal.h:53:2: error: use of undeclared identifier '_THIS_IP_'
     53 |         lock_map_acquire_try(&l->dep_map);
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  include/linux/lockdep.h:542:73: note: expanded from macro 'lock_map_acquire_try'
    542 | #define lock_map_acquire_try(l)                 lock_acquire_exclusive(l, 0, 1, NULL, _THIS_IP_)
        |                                                                                       ^~~~~~~~~
  In file included from lib/test_context-analysis.c:9:
  In file included from include/linux/local_lock.h:5:
  include/linux/local_lock_internal.h:62:2: error: use of undeclared identifier '_THIS_IP_'
     62 |         lock_map_release(&l->dep_map);
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  include/linux/lockdep.h:545:47: note: expanded from macro 'lock_map_release'
    545 | #define lock_map_release(l)                     lock_release(l, _THIS_IP_)
        |                                                                 ^~~~~~~~~
  3 errors generated.

The following diff resolves it for me, should I send it as a separate
patch or do you want to just fold it in with a note?

diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 621566345406..2301a701ffbb 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -10,6 +10,7 @@
 #ifndef __LINUX_LOCKDEP_H
 #define __LINUX_LOCKDEP_H
 
+#include <linux/instruction_pointer.h>
 #include <linux/lockdep_types.h>
 #include <linux/smp.h>
 #include <asm/percpu.h>
-- 
Cheers,
Nathan


^ permalink raw reply related

* Re: [PATCH net] net: airoha: dma map xmit frags with skb_frag_dma_map()
From: Harshitha Ramamurthy @ 2026-06-25 22:59 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260625-airoha-eth-skb_frag_dma_map-v1-1-31d9e460aae6@kernel.org>

On Thu, Jun 25, 2026 at 2:43 AM Lorenzo Bianconi <lorenzo@kernel.org> wrote:
>
> Map xmit skb fragments using skb_frag_dma_map() instead of
> dma_map_single(skb_frag_address()). skb_frag_address() relies on
> page_address() to obtain a kernel virtual address, which is not
> guaranteed to work for all page types (e.g. highmem pages or
> user-pinned pages from MSG_ZEROCOPY).
> skb_frag_dma_map() maps the fragment directly via its struct page and
> offset through dma_map_page(), avoiding the need for a kernel virtual
> address entirely.
> Introduce an enum airoha_dma_map_type to track how each queue entry was
> mapped (single vs page), so that the matching unmap function is called
> on completion and in error paths.
>
> Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>

Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>

> ---
>  drivers/net/ethernet/airoha/airoha_eth.c | 61 ++++++++++++++++++++------------
>  drivers/net/ethernet/airoha/airoha_eth.h |  7 ++++
>  2 files changed, 45 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 932b3a3df2e5..1caf6766f2c0 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -944,6 +944,25 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
>         q->txq_stopped = false;
>  }
>
> +static void airoha_unmap_xmit_buf(struct airoha_eth *eth,
> +                                 struct airoha_queue_entry *e)
> +{
> +       switch (e->dma_type) {
> +       case AIROHA_DMA_MAP_PAGE:
> +               dma_unmap_page(eth->dev, e->dma_addr, e->dma_len,
> +                              DMA_TO_DEVICE);
> +               break;
> +       case AIROHA_DMA_MAP_SINGLE:
> +               dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
> +                                DMA_TO_DEVICE);
> +               break;
> +       case AIROHA_DMA_UNMAPPED:
> +       default:
> +               break;
> +       }
> +       e->dma_type = AIROHA_DMA_UNMAPPED;
> +}
> +
>  static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
>  {
>         struct airoha_tx_irq_queue *irq_q;
> @@ -1006,9 +1025,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
>                 skb = e->skb;
>                 e->skb = NULL;
>
> -               dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
> -                                DMA_TO_DEVICE);
> -               e->dma_addr = 0;
> +               airoha_unmap_xmit_buf(eth, e);
>                 list_add_tail(&e->list, &q->tx_list);
>
>                 WRITE_ONCE(desc->msg0, 0);
> @@ -1177,12 +1194,10 @@ static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma)
>                         struct airoha_qdma_desc *desc = &q->desc[j];
>                         struct sk_buff *skb = e->skb;
>
> -                       if (!e->dma_addr)
> +                       if (e->dma_type == AIROHA_DMA_UNMAPPED)
>                                 continue;
>
> -                       dma_unmap_single(qdma->eth->dev, e->dma_addr,
> -                                        e->dma_len, DMA_TO_DEVICE);
> -                       e->dma_addr = 0;
> +                       airoha_unmap_xmit_buf(qdma->eth, e);
>                         list_add_tail(&e->list, &q->tx_list);
>
>                         WRITE_ONCE(desc->ctrl, 0);
> @@ -2193,8 +2208,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>         struct netdev_queue *txq;
>         struct airoha_queue *q;
>         LIST_HEAD(tx_list);
> +       dma_addr_t addr;
>         int i = 0, qid;
> -       void *data;
>         u16 index;
>         u8 fport;
>
> @@ -2250,24 +2265,22 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>                 return NETDEV_TX_BUSY;
>         }
>
> -       len = skb_headlen(skb);
> -       data = skb->data;
> -
>         e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
>                              list);
> +       len = skb_headlen(skb);
> +       addr = dma_map_single(netdev->dev.parent, skb->data, len,
> +                             DMA_TO_DEVICE);
> +       if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
> +               goto error_unlock;
> +
> +       e->dma_type = AIROHA_DMA_MAP_SINGLE;
>         index = e - q->entry;
>
>         while (true) {
>                 struct airoha_qdma_desc *desc = &q->desc[index];
>                 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
> -               dma_addr_t addr;
>                 u32 val;
>
> -               addr = dma_map_single(netdev->dev.parent, data, len,
> -                                     DMA_TO_DEVICE);
> -               if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
> -                       goto error_unmap;
> -
>                 list_move_tail(&e->list, &tx_list);
>                 e->skb = i == nr_frags - 1 ? skb : NULL;
>                 e->dma_addr = addr;
> @@ -2291,8 +2304,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>                 if (++i == nr_frags)
>                         break;
>
> -               data = skb_frag_address(frag);
>                 len = skb_frag_size(frag);
> +               addr = skb_frag_dma_map(netdev->dev.parent, frag, 0, len,
> +                                       DMA_TO_DEVICE);
> +               if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
> +                       goto error_unmap;
> +
> +               e->dma_type = AIROHA_DMA_MAP_PAGE;
>         }
>         q->queued += i;
>
> @@ -2313,11 +2331,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
>         return NETDEV_TX_OK;
>
>  error_unmap:
> -       list_for_each_entry(e, &tx_list, list) {
> -               dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len,
> -                                DMA_TO_DEVICE);
> -               e->dma_addr = 0;
> -       }
> +       list_for_each_entry(e, &tx_list, list)
> +               airoha_unmap_xmit_buf(dev->eth, e);
>         list_splice(&tx_list, &q->tx_list);
>  error_unlock:
>         spin_unlock_bh(&q->lock);
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> index d7ff8c5200e2..2765244d937c 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.h
> +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> @@ -170,12 +170,19 @@ enum trtcm_param {
>  #define TRTCM_TOKEN_RATE_MASK                  GENMASK(23, 6)
>  #define TRTCM_TOKEN_RATE_FRACTION_MASK         GENMASK(5, 0)
>
> +enum airoha_dma_map_type {
> +       AIROHA_DMA_UNMAPPED,
> +       AIROHA_DMA_MAP_SINGLE,
> +       AIROHA_DMA_MAP_PAGE,
> +};
> +
>  struct airoha_queue_entry {
>         union {
>                 void *buf;
>                 struct {
>                         struct list_head list;
>                         struct sk_buff *skb;
> +                       enum airoha_dma_map_type dma_type;
>                 };
>         };
>         dma_addr_t dma_addr;
>
> ---
> base-commit: 232c4ca2343d1181cbfc061f9856d9591e397579
> change-id: 20260625-airoha-eth-skb_frag_dma_map-bcccd5d6e4b1
>
> Best regards,
> --
> Lorenzo Bianconi <lorenzo@kernel.org>
>
>


^ permalink raw reply

* Re: [PATCH v14 4/5] gpio: rpmsg: add generic rpmsg GPIO driver
From: Julian Braha @ 2026-06-25 22:17 UTC (permalink / raw)
  To: Shenwei Wang, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Mathieu Poirier, Frank Li, Sascha Hauer
  Cc: Shuah Khan, linux-gpio, linux-doc, linux-kernel,
	Pengutronix Kernel Team, Fabio Estevam, Shenwei Wang, Peng Fan,
	devicetree, linux-remoteproc, imx, linux-arm-kernel, linux-imx,
	Arnaud POULIQUEN, b-padhi, Andrew Lunn, Bartosz Golaszewski
In-Reply-To: <20260625155432.815185-5-shenwei.wang@oss.nxp.com>

Hi Shenwei,

On 6/25/26 16:54, Shenwei Wang wrote:
> +config GPIO_RPMSG
> +	tristate "Generic RPMSG GPIO support"
> +	depends on OF && REMOTEPROC
> +	select GPIOLIB_IRQCHIP
> +	default REMOTEPROC
> +	help
> +	  Say yes here to support the generic GPIO functions over the RPMSG
> +	  bus. Currently supported devices: i.MX7ULP, i.MX8ULP, i.MX8x, and
> +	  i.MX9x.
> +
> +	  If unsure, say N.

You've got GPIO_RPMSG defaulting to REMOTEPROC, which is also a
dependency, so it's effectively the same as using 'default y'.

But then you've got "If unsure, say N" in the help text. Usually this is
used when the default is N.

- Julian Braha


^ permalink raw reply

* Re: [PATCH v3 2/3] selftests/resctrl: Replace counter index references with pointers
From: Reinette Chatre @ 2026-06-25 22:14 UTC (permalink / raw)
  To: Yifan Wu, tony.luck, Dave.Martin, james.morse, babu.moger, shuah,
	tan.shaopeng, fenghuay, ben.horgan, zengheng4, linux-kernel,
	linux-arm-kernel, linux-kselftest, linuxarm
  Cc: xiaqinxin, prime.zeng, wangyushan12, xuwei5, fanghao11, wangzhou1
In-Reply-To: <20260522090540.444554-3-wuyifan50@huawei.com>

Hi Yifan,

Thank you. I just have a few style fixup comments ...

On 5/22/26 2:05 AM, Yifan Wu wrote:
> Replace direct counter number references with pointers to remove the
> dependency on fixed array indexing and enable the use of different
> data structures for counter management.
> 
> Signed-off-by: Yifan Wu <wuyifan50@huawei.com>
> ---
>  tools/testing/selftests/resctrl/resctrl_val.c | 62 +++++++++----------
>  1 file changed, 31 insertions(+), 31 deletions(-)
> 
> diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
> index a72dc4ae61fe..3d2b6919717a 100644
> --- a/tools/testing/selftests/resctrl/resctrl_val.c
> +++ b/tools/testing/selftests/resctrl/resctrl_val.c
> @@ -42,40 +42,40 @@ static struct imc_counter_config imc_counters_config[MAX_IMCS];
>  LIST_HEAD(imc_counters_list);
>  static const struct resctrl_test *current_test;
>  
> -static void read_mem_bw_initialize_perf_event_attr(int i)
> +static void read_mem_bw_initialize_perf_event_attr(struct imc_counter_config *imc_counter)
>  {
> -	memset(&imc_counters_config[i].pe, 0,
> +	memset(&imc_counter->pe, 0,
>  	       sizeof(struct perf_event_attr));

nit: above can fit on a single line

> -	imc_counters_config[i].pe.type = imc_counters_config[i].type;
> -	imc_counters_config[i].pe.size = sizeof(struct perf_event_attr);
> -	imc_counters_config[i].pe.disabled = 1;
> -	imc_counters_config[i].pe.inherit = 1;
> -	imc_counters_config[i].pe.exclude_guest = 0;
> -	imc_counters_config[i].pe.config =
> -		imc_counters_config[i].umask << 8 |
> -		imc_counters_config[i].event;
> -	imc_counters_config[i].pe.sample_type = PERF_SAMPLE_IDENTIFIER;
> -	imc_counters_config[i].pe.read_format =
> +	imc_counter->pe.type = imc_counter->type;
> +	imc_counter->pe.size = sizeof(struct perf_event_attr);
> +	imc_counter->pe.disabled = 1;
> +	imc_counter->pe.inherit = 1;
> +	imc_counter->pe.exclude_guest = 0;
> +	imc_counter->pe.config =
> +		imc_counter->umask << 8 |
> +		imc_counter->event;

nit: above can fit on a single line

> +	imc_counter->pe.sample_type = PERF_SAMPLE_IDENTIFIER;
> +	imc_counter->pe.read_format =
>  		PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
>  }
>  

...

> @@ -89,21 +89,21 @@ static void get_read_event_and_umask(char *cas_count_cfg, unsigned int count)
>  		if (!token[i])
>  			break;
>  		if (strcmp(token[i], "event") == 0)
> -			imc_counters_config[count].event = strtol(token[i + 1], NULL, 16);
> +			imc_counter->event = strtol(token[i + 1], NULL, 16);
>  		if (strcmp(token[i], "umask") == 0)
> -			imc_counters_config[count].umask = strtol(token[i + 1], NULL, 16);
> +			imc_counter->umask = strtol(token[i + 1], NULL, 16);
>  	}
>  }
>  
> -static int open_perf_read_event(int i, int cpu_no)
> +static int open_perf_read_event(int cpu_no, struct imc_counter_config *imc_counter)
>  {
> -	imc_counters_config[i].fd =
> -		perf_event_open(&imc_counters_config[i].pe, -1, cpu_no, -1,
> +	imc_counter->fd =
> +		perf_event_open(&imc_counter->pe, -1, cpu_no, -1,
>  				PERF_FLAG_FD_CLOEXEC);

Please improve readibility here by moving the above two lines up while ensuring alignment with
open parenthesis. Specifically:
	imc_counter->fd = perf_event_open(&imc_counter->pe, -1, cpu_no, -1,
					  PERF_FLAG_FD_CLOEXEC);
...

With the style fixups:
| Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>

Reinette


^ permalink raw reply

* Re: [PATCH v3 1/3] selftests/resctrl: Introduce linked list management for IMC counters
From: Reinette Chatre @ 2026-06-25 22:14 UTC (permalink / raw)
  To: Yifan Wu, tony.luck, Dave.Martin, james.morse, babu.moger, shuah,
	tan.shaopeng, fenghuay, ben.horgan, zengheng4, linux-kernel,
	linux-arm-kernel, linux-kselftest, linuxarm
  Cc: xiaqinxin, prime.zeng, wangyushan12, xuwei5, fanghao11, wangzhou1
In-Reply-To: <20260522090540.444554-2-wuyifan50@huawei.com>

Hi Yifan,

On 5/22/26 2:05 AM, Yifan Wu wrote:
> The static array approach to managing IMC counters has fixed size
> constraints and limited compatibility and scalability. Introduce
> a linked list-based dynamic management infrastructure to address
> these limitations. Add the core data structure definitions and
> memory allocation and cleanup functions for dynamic counter
> configurations.
> 
> Signed-off-by: Yifan Wu <wuyifan50@huawei.com>
> ---

Thank you.

Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>

Reinette



^ permalink raw reply


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