* [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk
@ 2026-08-21 9:00 Jingcheng Ji
2026-08-31 17:48 ` Mark Brown
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Jingcheng Ji @ 2026-08-21 9:00 UTC (permalink / raw)
To: Mark Brown, Matthias Brugger, AngeloGioacchino Del Regno
Cc: linux-spi, linux-kernel, linux-arm-kernel, linux-mediatek,
Project_Global_Chrome_Upstream_Group, jarried.lin, vince-wl.liu,
justin.yeh, Jingcheng Ji
The driver currently gets a fixed set of clock inputs by name. This ties
the driver to the clock names used by existing devicetrees and silently
ignores any additional clocks declared by a future platform.
Get every clock described by the devicetree with
devm_clk_bulk_get_all() and enable the resulting set as a group. Keep
looking up the "spi" input to derive the transfer rate, and verify that
the required "sf" input is present. Obtain the clock inputs before
allocating the SPI controller so a deferred clock probe fails early.
This keeps the existing platforms' behavior while allowing the binding to
describe all controller clock inputs without requiring driver changes.
Signed-off-by: Jingcheng Ji <ot_jingcheng.ji@mediatek.com>
---
drivers/spi/spi-mtk-nor.c | 106 +++++++++++++++++---------------------
1 file changed, 46 insertions(+), 60 deletions(-)
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 5e1fdbb40ffb..2a713d27ae8e 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -116,10 +116,8 @@ struct mtk_nor {
void __iomem *base;
u8 *buffer;
dma_addr_t buffer_dma;
- struct clk *spi_clk;
- struct clk *ctlr_clk;
- struct clk *axi_clk;
- struct clk *axi_s_clk;
+ struct clk_bulk_data *clks;
+ int num_clks;
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
@@ -703,42 +701,12 @@ static int mtk_nor_transfer_one_message(struct spi_controller *host,
static void mtk_nor_disable_clk(struct mtk_nor *sp)
{
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- clk_disable_unprepare(sp->axi_s_clk);
+ clk_bulk_disable_unprepare(sp->num_clks, sp->clks);
}
static int mtk_nor_enable_clk(struct mtk_nor *sp)
{
- int ret;
-
- ret = clk_prepare_enable(sp->spi_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(sp->ctlr_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_s_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- return ret;
- }
-
- return 0;
+ return clk_bulk_prepare_enable(sp->num_clks, sp->clks);
}
static void mtk_nor_init(struct mtk_nor *sp)
@@ -807,34 +775,47 @@ static const struct of_device_id mtk_nor_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_nor_match);
+static struct clk *mtk_nor_get_clk(struct clk_bulk_data *clks, int num_clks,
+ const char *id)
+{
+ int i;
+
+ for (i = 0; i < num_clks; i++) {
+ if (clks[i].id && !strcmp(clks[i].id, id))
+ return clks[i].clk;
+ }
+
+ return NULL;
+}
+
static int mtk_nor_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct mtk_nor *sp;
struct mtk_nor_caps *caps;
void __iomem *base;
- struct clk *spi_clk, *ctlr_clk, *axi_clk, *axi_s_clk;
- int ret, irq;
+ struct clk_bulk_data *clks;
+ struct clk *spi_clk;
+ int num_clks, ret, irq;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
- spi_clk = devm_clk_get(&pdev->dev, "spi");
- if (IS_ERR(spi_clk))
- return PTR_ERR(spi_clk);
-
- ctlr_clk = devm_clk_get(&pdev->dev, "sf");
- if (IS_ERR(ctlr_clk))
- return PTR_ERR(ctlr_clk);
-
- axi_clk = devm_clk_get_optional(&pdev->dev, "axi");
- if (IS_ERR(axi_clk))
- return PTR_ERR(axi_clk);
-
- axi_s_clk = devm_clk_get_optional(&pdev->dev, "axi_s");
- if (IS_ERR(axi_s_clk))
- return PTR_ERR(axi_s_clk);
+ num_clks = devm_clk_bulk_get_all(&pdev->dev, &clks);
+ if (num_clks < 0)
+ return dev_err_probe(&pdev->dev, num_clks,
+ "failed to get clocks\n");
+ if (!num_clks)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no clocks defined\n");
+
+ spi_clk = mtk_nor_get_clk(clks, num_clks, "spi");
+ if (!spi_clk)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"spi\" clock\n");
+ if (!mtk_nor_get_clk(clks, num_clks, "sf"))
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"sf\" clock\n");
caps = (struct mtk_nor_caps *)of_device_get_match_data(&pdev->dev);
@@ -867,10 +848,8 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->wbuf_en = false;
sp->ctlr = ctlr;
sp->dev = &pdev->dev;
- sp->spi_clk = spi_clk;
- sp->ctlr_clk = ctlr_clk;
- sp->axi_clk = axi_clk;
- sp->axi_s_clk = axi_s_clk;
+ sp->clks = clks;
+ sp->num_clks = num_clks;
sp->caps = caps;
sp->high_dma = caps->dma_bits > 32;
sp->buffer = dmam_alloc_coherent(&pdev->dev,
@@ -886,9 +865,15 @@ static int mtk_nor_probe(struct platform_device *pdev)
ret = mtk_nor_enable_clk(sp);
if (ret < 0)
- return ret;
-
- sp->spi_freq = clk_get_rate(sp->spi_clk);
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to enable clocks\n");
+
+ sp->spi_freq = clk_get_rate(spi_clk);
+ if (!sp->spi_freq) {
+ dev_err(&pdev->dev, "invalid spi clock rate\n");
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
mtk_nor_init(sp);
@@ -928,6 +913,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
+err_disable_clk:
mtk_nor_disable_clk(sp);
return ret;
--
2.45.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk
2026-08-21 9:00 [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk Jingcheng Ji
@ 2026-08-31 17:48 ` Mark Brown
2026-09-03 6:13 ` Jingcheng Ji (纪京城)
2026-09-03 7:56 ` [PATCH v2] " Jingcheng Ji
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Mark Brown @ 2026-08-31 17:48 UTC (permalink / raw)
To: Jingcheng Ji
Cc: Matthias Brugger, AngeloGioacchino Del Regno, linux-spi,
linux-kernel, linux-arm-kernel, linux-mediatek,
Project_Global_Chrome_Upstream_Group, jarried.lin, vince-wl.liu,
justin.yeh
[-- Attachment #1: Type: text/plain, Size: 341 bytes --]
On Fri, Aug 21, 2026 at 05:00:22PM +0800, Jingcheng Ji wrote:
> The driver currently gets a fixed set of clock inputs by name. This ties
> the driver to the clock names used by existing devicetrees and silently
> ignores any additional clocks declared by a future platform.
This doesn't apply against current code, please check and resend.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk
2026-08-31 17:48 ` Mark Brown
@ 2026-09-03 6:13 ` Jingcheng Ji (纪京城)
0 siblings, 0 replies; 6+ messages in thread
From: Jingcheng Ji (纪京城) @ 2026-09-03 6:13 UTC (permalink / raw)
To: broonie@kernel.org
Cc: linux-spi@vger.kernel.org, Jarried Lin (林裕哲),
Project_Global_Chrome_Upstream_Group, AngeloGioacchino Del Regno,
linux-kernel@vger.kernel.org,
Vince-WL Liu (劉文龍),
linux-arm-kernel@lists.infradead.org,
Justin Yeh (葉英茂),
linux-mediatek@lists.infradead.org, matthias.bgg@gmail.com
On Mon, 2026-08-31 at 18:48 +0100, Mark Brown wrote:
> On Fri, Aug 21, 2026 at 05:00:22PM +0800, Jingcheng Ji wrote:
> > The driver currently gets a fixed set of clock inputs by name. This
> > ties
> > the driver to the clock names used by existing devicetrees and
> > silently
> > ignores any additional clocks declared by a future platform.
>
> This doesn't apply against current code, please check and resend.
Dear Mark:
Thanks for pointing this out. You are right: v1 was based on
an outdated snapshot and does not apply cleanly because current
spi/for-next already contains the err_disable_clk cleanup path added by
the IRQ error handling changes.
The fixed per-name clock lookups are still present in current spi/for-
next.I have rebased the patch onto the current tree, reused the
existing cleanup path, and verified v2 with checkpatch, git apply, git
am --3way, and an ARM64 object build.
I will send v2 shortly.
Best Regards,
Jingcheng Ji.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] spi: spi-mtk-nor: Get clocks from devicetree in bulk
2026-08-21 9:00 [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk Jingcheng Ji
2026-08-31 17:48 ` Mark Brown
@ 2026-09-03 7:56 ` Jingcheng Ji
2026-09-03 8:07 ` Jingcheng Ji
2026-09-03 8:09 ` Jingcheng Ji
3 siblings, 0 replies; 6+ messages in thread
From: Jingcheng Ji @ 2026-09-03 7:56 UTC (permalink / raw)
To: Mark Brown
Cc: Matthias Brugger, AngeloGioacchino Del Regno, linux-spi,
linux-kernel, linux-arm-kernel, linux-mediatek, Jingcheng Ji
The driver currently gets a fixed set of clock inputs by name. This ties
the driver to the clock names used by existing devicetrees. It also means
that a future binding extension which adds controller clock inputs needs a
matching driver change to enable them.
Get every clock described by the devicetree with
devm_clk_bulk_get_all() and enable the resulting set as a group. Keep
looking up the "spi" input to derive the transfer rate, and verify that
the required "sf" input is present. Obtain the clock inputs before
allocating the SPI controller so a deferred clock probe fails early.
For non-DT platform devices, retain the existing named clock lookups so
clkdev users continue to work.
This prepares the driver for future binding extensions without requiring
another driver change. Existing platforms' behavior is unchanged.
Signed-off-by: Jingcheng Ji <ot_jingcheng.ji@mediatek.com>
---
v2:
- Rebase onto current spi/for-next and reuse its existing IRQ error cleanup
path.
- Preserve named clock lookup for non-DT platform devices.
- Clarify that this prepares for a future binding extension.
drivers/spi/spi-mtk-nor.c | 151 +++++++++++++++++++++++---------------
1 file changed, 91 insertions(+), 60 deletions(-)
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 63f5139176c8..c0a47f3a8dbd 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#include <linux/string.h>
@@ -116,10 +117,8 @@ struct mtk_nor {
void __iomem *base;
u8 *buffer;
dma_addr_t buffer_dma;
- struct clk *spi_clk;
- struct clk *ctlr_clk;
- struct clk *axi_clk;
- struct clk *axi_s_clk;
+ struct clk_bulk_data *clks;
+ int num_clks;
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
@@ -703,42 +702,12 @@ static int mtk_nor_transfer_one_message(struct spi_controller *host,
static void mtk_nor_disable_clk(struct mtk_nor *sp)
{
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- clk_disable_unprepare(sp->axi_s_clk);
+ clk_bulk_disable_unprepare(sp->num_clks, sp->clks);
}
static int mtk_nor_enable_clk(struct mtk_nor *sp)
{
- int ret;
-
- ret = clk_prepare_enable(sp->spi_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(sp->ctlr_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_s_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- return ret;
- }
-
- return 0;
+ return clk_bulk_prepare_enable(sp->num_clks, sp->clks);
}
static void mtk_nor_init(struct mtk_nor *sp)
@@ -807,34 +776,92 @@ static const struct of_device_id mtk_nor_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_nor_match);
+static struct clk *mtk_nor_get_clk(struct clk_bulk_data *clks, int num_clks,
+ const char *id)
+{
+ int i;
+
+ for (i = 0; i < num_clks; i++) {
+ if (clks[i].id && !strcmp(clks[i].id, id))
+ return clks[i].clk;
+ }
+
+ return NULL;
+}
+
+static int mtk_nor_get_named_clks(struct device *dev,
+ struct clk_bulk_data **clks)
+{
+ struct clk_bulk_data *bulk;
+ struct clk *clk;
+ int num_clks = 2;
+
+ bulk = devm_kcalloc(dev, 4, sizeof(*bulk), GFP_KERNEL);
+ if (!bulk)
+ return -ENOMEM;
+
+ bulk[0].id = "spi";
+ bulk[0].clk = devm_clk_get(dev, bulk[0].id);
+ if (IS_ERR(bulk[0].clk))
+ return PTR_ERR(bulk[0].clk);
+
+ bulk[1].id = "sf";
+ bulk[1].clk = devm_clk_get(dev, bulk[1].id);
+ if (IS_ERR(bulk[1].clk))
+ return PTR_ERR(bulk[1].clk);
+
+ clk = devm_clk_get_optional(dev, "axi");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ if (clk) {
+ bulk[num_clks].id = "axi";
+ bulk[num_clks++].clk = clk;
+ }
+
+ clk = devm_clk_get_optional(dev, "axi_s");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ if (clk) {
+ bulk[num_clks].id = "axi_s";
+ bulk[num_clks++].clk = clk;
+ }
+
+ *clks = bulk;
+
+ return num_clks;
+}
+
static int mtk_nor_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct mtk_nor *sp;
struct mtk_nor_caps *caps;
void __iomem *base;
- struct clk *spi_clk, *ctlr_clk, *axi_clk, *axi_s_clk;
- int ret, irq;
+ struct clk_bulk_data *clks;
+ struct clk *spi_clk;
+ int num_clks, ret, irq;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
- spi_clk = devm_clk_get(&pdev->dev, "spi");
- if (IS_ERR(spi_clk))
- return PTR_ERR(spi_clk);
-
- ctlr_clk = devm_clk_get(&pdev->dev, "sf");
- if (IS_ERR(ctlr_clk))
- return PTR_ERR(ctlr_clk);
-
- axi_clk = devm_clk_get_optional(&pdev->dev, "axi");
- if (IS_ERR(axi_clk))
- return PTR_ERR(axi_clk);
-
- axi_s_clk = devm_clk_get_optional(&pdev->dev, "axi_s");
- if (IS_ERR(axi_s_clk))
- return PTR_ERR(axi_s_clk);
+ if (dev_of_node(&pdev->dev))
+ num_clks = devm_clk_bulk_get_all(&pdev->dev, &clks);
+ else
+ num_clks = mtk_nor_get_named_clks(&pdev->dev, &clks);
+ if (num_clks < 0)
+ return dev_err_probe(&pdev->dev, num_clks,
+ "failed to get clocks\n");
+ if (!num_clks)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no clocks defined\n");
+
+ spi_clk = mtk_nor_get_clk(clks, num_clks, "spi");
+ if (!spi_clk)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"spi\" clock\n");
+ if (!mtk_nor_get_clk(clks, num_clks, "sf"))
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"sf\" clock\n");
caps = (struct mtk_nor_caps *)of_device_get_match_data(&pdev->dev);
@@ -867,10 +894,8 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->wbuf_en = false;
sp->ctlr = ctlr;
sp->dev = &pdev->dev;
- sp->spi_clk = spi_clk;
- sp->ctlr_clk = ctlr_clk;
- sp->axi_clk = axi_clk;
- sp->axi_s_clk = axi_s_clk;
+ sp->clks = clks;
+ sp->num_clks = num_clks;
sp->caps = caps;
sp->high_dma = caps->dma_bits > 32;
sp->buffer = dmam_alloc_coherent(&pdev->dev,
@@ -886,9 +911,15 @@ static int mtk_nor_probe(struct platform_device *pdev)
ret = mtk_nor_enable_clk(sp);
if (ret < 0)
- return ret;
-
- sp->spi_freq = clk_get_rate(sp->spi_clk);
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to enable clocks\n");
+
+ sp->spi_freq = clk_get_rate(spi_clk);
+ if (!sp->spi_freq) {
+ dev_err(&pdev->dev, "invalid spi clock rate\n");
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
mtk_nor_init(sp);
--
2.45.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2] spi: spi-mtk-nor: Get clocks from devicetree in bulk
2026-08-21 9:00 [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk Jingcheng Ji
2026-08-31 17:48 ` Mark Brown
2026-09-03 7:56 ` [PATCH v2] " Jingcheng Ji
@ 2026-09-03 8:07 ` Jingcheng Ji
2026-09-03 8:09 ` Jingcheng Ji
3 siblings, 0 replies; 6+ messages in thread
From: Jingcheng Ji @ 2026-09-03 8:07 UTC (permalink / raw)
To: Mark Brown
Cc: Matthias Brugger, AngeloGioacchino Del Regno, linux-spi,
linux-kernel, linux-arm-kernel, linux-mediatek, Jingcheng Ji
The driver currently gets a fixed set of clock inputs by name. This ties
the driver to the clock names used by existing devicetrees. It also means
that a future binding extension which adds controller clock inputs needs a
matching driver change to enable them.
Get every clock described by the devicetree with
devm_clk_bulk_get_all() and enable the resulting set as a group. Keep
looking up the "spi" input to derive the transfer rate, and verify that
the required "sf" input is present. Obtain the clock inputs before
allocating the SPI controller so a deferred clock probe fails early.
For non-DT platform devices, retain the existing named clock lookups so
clkdev users continue to work.
This prepares the driver for future binding extensions without requiring
another driver change. Existing platforms' behavior is unchanged.
Signed-off-by: Jingcheng Ji <ot_jingcheng.ji@mediatek.com>
---
v2:
- Rebase onto current spi/for-next and reuse its existing IRQ error cleanup
path.
- Preserve named clock lookup for non-DT platform devices.
- Clarify that this prepares for a future binding extension.
drivers/spi/spi-mtk-nor.c | 151 +++++++++++++++++++++++---------------
1 file changed, 91 insertions(+), 60 deletions(-)
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 63f5139176c8..c0a47f3a8dbd 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#include <linux/string.h>
@@ -116,10 +117,8 @@ struct mtk_nor {
void __iomem *base;
u8 *buffer;
dma_addr_t buffer_dma;
- struct clk *spi_clk;
- struct clk *ctlr_clk;
- struct clk *axi_clk;
- struct clk *axi_s_clk;
+ struct clk_bulk_data *clks;
+ int num_clks;
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
@@ -703,42 +702,12 @@ static int mtk_nor_transfer_one_message(struct spi_controller *host,
static void mtk_nor_disable_clk(struct mtk_nor *sp)
{
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- clk_disable_unprepare(sp->axi_s_clk);
+ clk_bulk_disable_unprepare(sp->num_clks, sp->clks);
}
static int mtk_nor_enable_clk(struct mtk_nor *sp)
{
- int ret;
-
- ret = clk_prepare_enable(sp->spi_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(sp->ctlr_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_s_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- return ret;
- }
-
- return 0;
+ return clk_bulk_prepare_enable(sp->num_clks, sp->clks);
}
static void mtk_nor_init(struct mtk_nor *sp)
@@ -807,34 +776,92 @@ static const struct of_device_id mtk_nor_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_nor_match);
+static struct clk *mtk_nor_get_clk(struct clk_bulk_data *clks, int num_clks,
+ const char *id)
+{
+ int i;
+
+ for (i = 0; i < num_clks; i++) {
+ if (clks[i].id && !strcmp(clks[i].id, id))
+ return clks[i].clk;
+ }
+
+ return NULL;
+}
+
+static int mtk_nor_get_named_clks(struct device *dev,
+ struct clk_bulk_data **clks)
+{
+ struct clk_bulk_data *bulk;
+ struct clk *clk;
+ int num_clks = 2;
+
+ bulk = devm_kcalloc(dev, 4, sizeof(*bulk), GFP_KERNEL);
+ if (!bulk)
+ return -ENOMEM;
+
+ bulk[0].id = "spi";
+ bulk[0].clk = devm_clk_get(dev, bulk[0].id);
+ if (IS_ERR(bulk[0].clk))
+ return PTR_ERR(bulk[0].clk);
+
+ bulk[1].id = "sf";
+ bulk[1].clk = devm_clk_get(dev, bulk[1].id);
+ if (IS_ERR(bulk[1].clk))
+ return PTR_ERR(bulk[1].clk);
+
+ clk = devm_clk_get_optional(dev, "axi");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ if (clk) {
+ bulk[num_clks].id = "axi";
+ bulk[num_clks++].clk = clk;
+ }
+
+ clk = devm_clk_get_optional(dev, "axi_s");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ if (clk) {
+ bulk[num_clks].id = "axi_s";
+ bulk[num_clks++].clk = clk;
+ }
+
+ *clks = bulk;
+
+ return num_clks;
+}
+
static int mtk_nor_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct mtk_nor *sp;
struct mtk_nor_caps *caps;
void __iomem *base;
- struct clk *spi_clk, *ctlr_clk, *axi_clk, *axi_s_clk;
- int ret, irq;
+ struct clk_bulk_data *clks;
+ struct clk *spi_clk;
+ int num_clks, ret, irq;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
- spi_clk = devm_clk_get(&pdev->dev, "spi");
- if (IS_ERR(spi_clk))
- return PTR_ERR(spi_clk);
-
- ctlr_clk = devm_clk_get(&pdev->dev, "sf");
- if (IS_ERR(ctlr_clk))
- return PTR_ERR(ctlr_clk);
-
- axi_clk = devm_clk_get_optional(&pdev->dev, "axi");
- if (IS_ERR(axi_clk))
- return PTR_ERR(axi_clk);
-
- axi_s_clk = devm_clk_get_optional(&pdev->dev, "axi_s");
- if (IS_ERR(axi_s_clk))
- return PTR_ERR(axi_s_clk);
+ if (dev_of_node(&pdev->dev))
+ num_clks = devm_clk_bulk_get_all(&pdev->dev, &clks);
+ else
+ num_clks = mtk_nor_get_named_clks(&pdev->dev, &clks);
+ if (num_clks < 0)
+ return dev_err_probe(&pdev->dev, num_clks,
+ "failed to get clocks\n");
+ if (!num_clks)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no clocks defined\n");
+
+ spi_clk = mtk_nor_get_clk(clks, num_clks, "spi");
+ if (!spi_clk)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"spi\" clock\n");
+ if (!mtk_nor_get_clk(clks, num_clks, "sf"))
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"sf\" clock\n");
caps = (struct mtk_nor_caps *)of_device_get_match_data(&pdev->dev);
@@ -867,10 +894,8 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->wbuf_en = false;
sp->ctlr = ctlr;
sp->dev = &pdev->dev;
- sp->spi_clk = spi_clk;
- sp->ctlr_clk = ctlr_clk;
- sp->axi_clk = axi_clk;
- sp->axi_s_clk = axi_s_clk;
+ sp->clks = clks;
+ sp->num_clks = num_clks;
sp->caps = caps;
sp->high_dma = caps->dma_bits > 32;
sp->buffer = dmam_alloc_coherent(&pdev->dev,
@@ -886,9 +911,15 @@ static int mtk_nor_probe(struct platform_device *pdev)
ret = mtk_nor_enable_clk(sp);
if (ret < 0)
- return ret;
-
- sp->spi_freq = clk_get_rate(sp->spi_clk);
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to enable clocks\n");
+
+ sp->spi_freq = clk_get_rate(spi_clk);
+ if (!sp->spi_freq) {
+ dev_err(&pdev->dev, "invalid spi clock rate\n");
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
mtk_nor_init(sp);
--
2.45.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v2] spi: spi-mtk-nor: Get clocks from devicetree in bulk
2026-08-21 9:00 [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk Jingcheng Ji
` (2 preceding siblings ...)
2026-09-03 8:07 ` Jingcheng Ji
@ 2026-09-03 8:09 ` Jingcheng Ji
3 siblings, 0 replies; 6+ messages in thread
From: Jingcheng Ji @ 2026-09-03 8:09 UTC (permalink / raw)
To: Mark Brown
Cc: Matthias Brugger, AngeloGioacchino Del Regno, linux-spi,
linux-kernel, linux-arm-kernel, linux-mediatek, Jingcheng Ji
The driver currently gets a fixed set of clock inputs by name. This ties
the driver to the clock names used by existing devicetrees. It also means
that a future binding extension which adds controller clock inputs needs a
matching driver change to enable them.
Get every clock described by the devicetree with
devm_clk_bulk_get_all() and enable the resulting set as a group. Keep
looking up the "spi" input to derive the transfer rate, and verify that
the required "sf" input is present. Obtain the clock inputs before
allocating the SPI controller so a deferred clock probe fails early.
For non-DT platform devices, retain the existing named clock lookups so
clkdev users continue to work.
This prepares the driver for future binding extensions without requiring
another driver change. Existing platforms' behavior is unchanged.
Signed-off-by: Jingcheng Ji <ot_jingcheng.ji@mediatek.com>
---
v2:
- Rebase onto current spi/for-next and reuse its existing IRQ error cleanup
path.
- Preserve named clock lookup for non-DT platform devices.
- Clarify that this prepares for a future binding extension.
drivers/spi/spi-mtk-nor.c | 151 +++++++++++++++++++++++---------------
1 file changed, 91 insertions(+), 60 deletions(-)
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index 63f5139176c8..c0a47f3a8dbd 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#include <linux/string.h>
@@ -116,10 +117,8 @@ struct mtk_nor {
void __iomem *base;
u8 *buffer;
dma_addr_t buffer_dma;
- struct clk *spi_clk;
- struct clk *ctlr_clk;
- struct clk *axi_clk;
- struct clk *axi_s_clk;
+ struct clk_bulk_data *clks;
+ int num_clks;
unsigned int spi_freq;
bool wbuf_en;
bool has_irq;
@@ -703,42 +702,12 @@ static int mtk_nor_transfer_one_message(struct spi_controller *host,
static void mtk_nor_disable_clk(struct mtk_nor *sp)
{
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- clk_disable_unprepare(sp->axi_s_clk);
+ clk_bulk_disable_unprepare(sp->num_clks, sp->clks);
}
static int mtk_nor_enable_clk(struct mtk_nor *sp)
{
- int ret;
-
- ret = clk_prepare_enable(sp->spi_clk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(sp->ctlr_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- return ret;
- }
-
- ret = clk_prepare_enable(sp->axi_s_clk);
- if (ret) {
- clk_disable_unprepare(sp->spi_clk);
- clk_disable_unprepare(sp->ctlr_clk);
- clk_disable_unprepare(sp->axi_clk);
- return ret;
- }
-
- return 0;
+ return clk_bulk_prepare_enable(sp->num_clks, sp->clks);
}
static void mtk_nor_init(struct mtk_nor *sp)
@@ -807,34 +776,92 @@ static const struct of_device_id mtk_nor_match[] = {
};
MODULE_DEVICE_TABLE(of, mtk_nor_match);
+static struct clk *mtk_nor_get_clk(struct clk_bulk_data *clks, int num_clks,
+ const char *id)
+{
+ int i;
+
+ for (i = 0; i < num_clks; i++) {
+ if (clks[i].id && !strcmp(clks[i].id, id))
+ return clks[i].clk;
+ }
+
+ return NULL;
+}
+
+static int mtk_nor_get_named_clks(struct device *dev,
+ struct clk_bulk_data **clks)
+{
+ struct clk_bulk_data *bulk;
+ struct clk *clk;
+ int num_clks = 2;
+
+ bulk = devm_kcalloc(dev, 4, sizeof(*bulk), GFP_KERNEL);
+ if (!bulk)
+ return -ENOMEM;
+
+ bulk[0].id = "spi";
+ bulk[0].clk = devm_clk_get(dev, bulk[0].id);
+ if (IS_ERR(bulk[0].clk))
+ return PTR_ERR(bulk[0].clk);
+
+ bulk[1].id = "sf";
+ bulk[1].clk = devm_clk_get(dev, bulk[1].id);
+ if (IS_ERR(bulk[1].clk))
+ return PTR_ERR(bulk[1].clk);
+
+ clk = devm_clk_get_optional(dev, "axi");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ if (clk) {
+ bulk[num_clks].id = "axi";
+ bulk[num_clks++].clk = clk;
+ }
+
+ clk = devm_clk_get_optional(dev, "axi_s");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ if (clk) {
+ bulk[num_clks].id = "axi_s";
+ bulk[num_clks++].clk = clk;
+ }
+
+ *clks = bulk;
+
+ return num_clks;
+}
+
static int mtk_nor_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct mtk_nor *sp;
struct mtk_nor_caps *caps;
void __iomem *base;
- struct clk *spi_clk, *ctlr_clk, *axi_clk, *axi_s_clk;
- int ret, irq;
+ struct clk_bulk_data *clks;
+ struct clk *spi_clk;
+ int num_clks, ret, irq;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
- spi_clk = devm_clk_get(&pdev->dev, "spi");
- if (IS_ERR(spi_clk))
- return PTR_ERR(spi_clk);
-
- ctlr_clk = devm_clk_get(&pdev->dev, "sf");
- if (IS_ERR(ctlr_clk))
- return PTR_ERR(ctlr_clk);
-
- axi_clk = devm_clk_get_optional(&pdev->dev, "axi");
- if (IS_ERR(axi_clk))
- return PTR_ERR(axi_clk);
-
- axi_s_clk = devm_clk_get_optional(&pdev->dev, "axi_s");
- if (IS_ERR(axi_s_clk))
- return PTR_ERR(axi_s_clk);
+ if (dev_of_node(&pdev->dev))
+ num_clks = devm_clk_bulk_get_all(&pdev->dev, &clks);
+ else
+ num_clks = mtk_nor_get_named_clks(&pdev->dev, &clks);
+ if (num_clks < 0)
+ return dev_err_probe(&pdev->dev, num_clks,
+ "failed to get clocks\n");
+ if (!num_clks)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no clocks defined\n");
+
+ spi_clk = mtk_nor_get_clk(clks, num_clks, "spi");
+ if (!spi_clk)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"spi\" clock\n");
+ if (!mtk_nor_get_clk(clks, num_clks, "sf"))
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "missing \"sf\" clock\n");
caps = (struct mtk_nor_caps *)of_device_get_match_data(&pdev->dev);
@@ -867,10 +894,8 @@ static int mtk_nor_probe(struct platform_device *pdev)
sp->wbuf_en = false;
sp->ctlr = ctlr;
sp->dev = &pdev->dev;
- sp->spi_clk = spi_clk;
- sp->ctlr_clk = ctlr_clk;
- sp->axi_clk = axi_clk;
- sp->axi_s_clk = axi_s_clk;
+ sp->clks = clks;
+ sp->num_clks = num_clks;
sp->caps = caps;
sp->high_dma = caps->dma_bits > 32;
sp->buffer = dmam_alloc_coherent(&pdev->dev,
@@ -886,9 +911,15 @@ static int mtk_nor_probe(struct platform_device *pdev)
ret = mtk_nor_enable_clk(sp);
if (ret < 0)
- return ret;
-
- sp->spi_freq = clk_get_rate(sp->spi_clk);
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to enable clocks\n");
+
+ sp->spi_freq = clk_get_rate(spi_clk);
+ if (!sp->spi_freq) {
+ dev_err(&pdev->dev, "invalid spi clock rate\n");
+ ret = -EINVAL;
+ goto err_disable_clk;
+ }
mtk_nor_init(sp);
--
2.45.2
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-03 8:12 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 9:00 [PATCH] spi: spi-mtk-nor: Get clocks from devicetree in bulk Jingcheng Ji
2026-08-31 17:48 ` Mark Brown
2026-09-03 6:13 ` Jingcheng Ji (纪京城)
2026-09-03 7:56 ` [PATCH v2] " Jingcheng Ji
2026-09-03 8:07 ` Jingcheng Ji
2026-09-03 8:09 ` Jingcheng Ji
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox