* [PATCHv3 2/6] serial: mxs-auart: rework clock handling in mxs_get_clks and probe
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260611033856.6476-1-rosenp@gmail.com>
Use devm_clk_get_enabled for the AHB clock so its enable/disable
lifetime is managed by the driver model. Move the mod clock
(clk) prepare_enable out of mxs_get_clks and into probe so that
clk_set_rate is called while the clock is still disabled, avoiding
CLK_SET_RATE_GATE failures. Clean up the error labels accordingly.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 47 ++++++++++++----------------------
1 file changed, 17 insertions(+), 30 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index de97c0f74e7d..aa59a48bfad7 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1470,34 +1470,22 @@ static int mxs_get_clks(struct mxs_auart_port *s,
return PTR_ERR(s->clk);
}
- s->clk_ahb = devm_clk_get(s->dev, "ahb");
+ s->clk_ahb = devm_clk_get_enabled(s->dev, "ahb");
if (IS_ERR(s->clk_ahb)) {
dev_err(s->dev, "Failed to get \"ahb\" clk\n");
return PTR_ERR(s->clk_ahb);
}
- err = clk_prepare_enable(s->clk_ahb);
- if (err) {
- dev_err(s->dev, "Failed to enable ahb_clk!\n");
- return err;
- }
-
+ /*
+ * Set mod clock rate while it is still disabled so
+ * CLK_SET_RATE_GATE does not cause clk_set_rate to fail.
+ * The mod clock will be enabled in mxs_auart_startup()
+ * and in probe after mxs_get_clks returns.
+ */
err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
- if (err) {
+ if (err)
dev_err(s->dev, "Failed to set rate!\n");
- goto disable_clk_ahb;
- }
- err = clk_prepare_enable(s->clk);
- if (err) {
- dev_err(s->dev, "Failed to enable clk!\n");
- goto disable_clk_ahb;
- }
-
- return 0;
-
-disable_clk_ahb:
- clk_disable_unprepare(s->clk_ahb);
return err;
}
@@ -1604,17 +1592,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = clk_prepare_enable(s->clk);
+ if (ret)
+ return ret;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
ret = -ENXIO;
- goto out_disable_clks;
+ goto out_disable_clk;
}
s->port.mapbase = r->start;
s->port.membase = ioremap(r->start, resource_size(r));
if (!s->port.membase) {
ret = -ENOMEM;
- goto out_disable_clks;
+ goto out_disable_clk;
}
s->port.ops = &mxs_auart_ops;
s->port.iotype = UPIO_MEM;
@@ -1681,11 +1673,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
out_iounmap:
iounmap(s->port.membase);
-out_disable_clks:
- if (is_asm9260_auart(s)) {
- clk_disable_unprepare(s->clk);
- clk_disable_unprepare(s->clk_ahb);
- }
+out_disable_clk:
+ clk_disable_unprepare(s->clk);
return ret;
}
@@ -1697,10 +1686,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL;
mxs_auart_free_gpio_irq(s);
iounmap(s->port.membase);
- if (is_asm9260_auart(s)) {
+ if (is_asm9260_auart(s))
clk_disable_unprepare(s->clk);
- clk_disable_unprepare(s->clk_ahb);
- }
}
static struct platform_driver mxs_auart_driver = {
--
2.54.0
^ permalink raw reply related
* [PATCHv3 1/6] serial: mxs-auart: fix cast type for of_device_get_match_data
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260611033856.6476-1-rosenp@gmail.com>
of_device_get_match_data returns const void*. Cast to unsigned long to
avoid implicit integer truncation warnings. All the data parameters are
correct anyway.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 697318dbb146..de97c0f74e7d 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1598,7 +1598,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
return -EINVAL;
}
- s->devtype = (enum mxs_auart_type)of_device_get_match_data(&pdev->dev);
+ s->devtype = (unsigned long)of_device_get_match_data(&pdev->dev);
ret = mxs_get_clks(s, pdev);
if (ret)
--
2.54.0
^ permalink raw reply related
* [PATCHv3 0/6] serial: mxs-auart: devm conversion, clock rework, and IRQ ordering fixes
From: Rosen Penev @ 2026-06-11 3:38 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
This series cleans up the mxs-auart driver by converting to devm-managed
resources, fixing clock prepare/enable ordering, and addressing IRQ
registration races.
Patch 1 fixes compilation on 64-bit build with W=1
Patch 2 reworks the clock handling to use devm_clk_get_enabled and
reorders clk_prepare_enable after clk_set_rate to avoid
CLK_SET_RATE_GATE failures.
Patch 3 converts iomem mapping and GPIO IRQ requests to devm,
removing the manual cleanup paths.
Patch 4 moves the main UART IRQ registration after uart_add_one_port
so the port state is initialized before the handler can run, and
manages the module clock for console vs non-console ports correctly.
v3: two more sashiko fixes
v2: split off of_device_get_match_data change.
Rosen Penev (6):
serial: mxs-auart: fix cast type for of_device_get_match_data
serial: mxs-auart: rework clock handling in mxs_get_clks and probe
serial: mxs-auart: use devm resources for iomem and GPIO IRQs
serial: mxs-auart: fix IRQ registration ordering and manage console
clock
serial: mxs-auart: clamp RX DMA count to buffer size
serial: mxs-auart: terminate DMA before releasing channels in exit
drivers/tty/serial/mxs-auart.c | 145 +++++++++++++++------------------
1 file changed, 66 insertions(+), 79 deletions(-)
--
2.54.0
^ permalink raw reply
* Re: [PATCH 2/3] tty: serial: Add UART driver for Cortina-Access platform
From: Randy Dunlap @ 2026-06-10 22:49 UTC (permalink / raw)
To: Jason Li, jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-4-jason.li@cortina-access.com>
On 6/10/26 4:28 AM, Jason Li wrote:
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index cf7dba473b20..99a1c9308395 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -1592,6 +1592,27 @@ config SERIAL_NUVOTON_MA35D1_CONSOLE
> but you can alter that using a kernel command line option such as
> "console=ttyNVTx".
>
> +config SERIAL_CORTINA_ACCESS
> + tristate "Cortina-Access serial port support"
> + depends on OF
> + select SERIAL_CORE
> + help
> + This driver is for the Cortina-Access SoC UART, present in the
> + CA8289 (Venus) and related CAXXXX family of SoCs. If you have a
> + machine based on the Cortina-Access SoC and wish to use the serial
> + port, say 'Y' here. Otherwise, say 'N'.
It could also be 'm' since the kconfig symbol is tristate.
> +
> +config SERIAL_CORTINA_ACCESS_CONSOLE
> + bool "Console on Cortina-Access serial port"
> + depends on SERIAL_CORTINA_ACCESS=y
> + select SERIAL_CORE_CONSOLE
> + select SERIAL_EARLYCON
> + help
> + Say 'Y' here if you wish to use the Cortina-Access UART as the system
> + console (the device which receives all kernel messages and warnings
> + and which allows logins in single user mode).
> + /dev/ttyS* is the default device node.
> +
> endmenu
--
~Randy
^ permalink raw reply
* Re: [PATCH 04/11] treewide: Convert struct kernel_param_ops initializers to DEFINE_KERNEL_PARAM_OPS
From: jim.cromie @ 2026-06-10 21:06 UTC (permalink / raw)
To: Petr Pavlu
Cc: Kees Cook, Luis Chamberlain, Pengpeng Hou, Richard Weinberger,
Anton Ivanov, Johannes Berg, Rafael J. Wysocki, Len Brown,
Corey Minyard, Gabriel Somlo, Michael S. Tsirkin, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, David Airlie,
Simona Vetter, Bart Van Assche, Jason Gunthorpe, Leon Romanovsky,
Laurent Pinchart, Hans de Goede, Mauro Carvalho Chehab,
Bjorn Helgaas, Hannes Reinecke, James E.J. Bottomley,
Martin K. Petersen, Daniel Lezcano, Zhang Rui, Lukasz Luba,
Greg Kroah-Hartman, Jiri Slaby, Alan Stern, Jason Wang, Xuan Zhuo,
Eugenio Pérez, Jason Baron, Tiwei Bie, Benjamin Berg,
Ilpo Järvinen, David E. Box, Maciej W. Rozycki,
Srinivas Pandruvada, Peter Zijlstra, Heiko Carstens,
Vasily Gorbik, Sean Christopherson, Paolo Bonzini,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
H. Peter Anvin, Vinod Koul, Frank Li, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Alexander Potapenko, Marco Elver, Dmitry Vyukov,
Andrew Morton, John Johansen, Paul Moore, James Morris,
Serge E. Hallyn, Andy Shevchenko, Georgia Garcia, kvm, dmaengine,
linux-modules, kasan-dev, linux-mm, apparmor,
linux-security-module, linux-um, linux-acpi, openipmi-developer,
qemu-devel, intel-gfx, dri-devel, linux-rdma, linux-media,
linux-pci, linux-scsi, linux-pm, linuxppc-dev, linux-serial,
linux-usb, usb-storage, virtualization, linux-kernel, linux-arch,
netdev, linux-fsdevel, linux-hardening
In-Reply-To: <da358ae1-91b4-4a16-ac76-ffab99c230b9@suse.com>
On Mon, May 25, 2026 at 7:35 AM Petr Pavlu <petr.pavlu@suse.com> wrote:
>
> On 5/21/26 3:33 PM, Kees Cook wrote:
> > Using Coccinelle, rewrite every struct kernel_param_ops initializer that
> > sets .get into a DEFINE_KERNEL_PARAM_OPS-family macro invocation,
> > for example:
> >
> > @@
> > declarer name DEFINE_KERNEL_PARAM_OPS;
> > identifier OPS;
> > expression SET, GET;
> > @@
> > - const struct kernel_param_ops OPS = {
> > - .set = SET,
> > - .get = GET,
> > - };
> > + DEFINE_KERNEL_PARAM_OPS(OPS, SET, GET);
> >
> > Using the macro for initialization means future changes can manipulate
> > the struct layout and callback prototypes without having to change every
> > initializer.
>
> Nit: For consistency, I suggest also converting the few remaining
> kernel_param_ops instances that specify only .set and no .get, such as
> simdisk_param_ops_filename.
>
> --
> Thanks,
> Petr
for the dynamic-debug changes
Reviewed-by: Jim Cromie <jim.cromie@gmail.com>
^ permalink raw reply
* Re: [PATCH] ARM: footbridge: convert to sparse IRQs
From: Dmitry Torokhov @ 2026-06-10 17:03 UTC (permalink / raw)
To: Ethan Nelson-Moore
Cc: Arnd Bergmann, linux-arm-kernel, linux-input, linux-serial,
Russell King, Greg Kroah-Hartman, Jiri Slaby, Russell King,
Linus Walleij, Kees Cook, Nathan Chancellor,
Sebastian Andrzej Siewior, Steven Rostedt, Thomas Weißschuh,
Peter Zijlstra
In-Reply-To: <CADkSEUhh1NdOMTHVsErhqzyCpDGFA-FkNFaWp94e9LnB3njxqw@mail.gmail.com>
On Mon, Jun 08, 2026 at 10:13:50AM -0700, Ethan Nelson-Moore wrote:
> Hi, Arnd,
>
> On Mon, Jun 8, 2026 at 10:11 AM Arnd Bergmann <arnd@arndb.de> wrote:
> > I think this is correct, as footbridge is the only one that selects
> > CONFIG_ARCH_MIGHT_HAVE_PC_SERIO and defines I8042_KBD_IRQ on arm.
>
> I came to the same conclusion.
I see. In this case:
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> # for input
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v6 6/9] dt-bindings: connector: m2: Add M.2 1620 LGA soldered down connector
From: Manivannan Sadhasivam @ 2026-06-10 16:44 UTC (permalink / raw)
To: Stephan Gerhold
Cc: Mark Pearson, Dmitry Baryshkov, Rob Herring,
Manivannan Sadhasivam, Greg KH, Jiri Slaby, Nathan Chancellor,
Nicolas Schier, Hans de Goede, Ilpo Järvinen,
Derek J . Clark, Krzysztof Kozlowski, Conor Dooley,
Marcel Holtmann, Luiz Augusto von Dentz, Bartosz Golaszewski,
Andy Shevchenko, Bartosz Golaszewski, linux-serial, linux-kernel,
linux-kbuild, platform-driver-x86@vger.kernel.org, linux-pci,
devicetree, linux-arm-msm, linux-bluetooth, linux-pm,
linux-acpi@vger.kernel.org
In-Reply-To: <acv2f1qbqu4PlSL1@linaro.org>
On Tue, Mar 31, 2026 at 06:29:51PM +0200, Stephan Gerhold wrote:
> On Wed, Mar 25, 2026 at 05:36:08PM +0530, Manivannan Sadhasivam wrote:
> > On Mon, Mar 23, 2026 at 01:23:07PM -0400, Mark Pearson wrote:
> > > On Mon, Mar 23, 2026, at 12:52 PM, Manivannan Sadhasivam wrote:
> > > > On Mon, Mar 23, 2026 at 06:45:15PM +0200, Dmitry Baryshkov wrote:
> > > >> On Mon, Mar 23, 2026 at 09:26:04PM +0530, Manivannan Sadhasivam wrote:
> > > >> > On Mon, Mar 23, 2026 at 05:14:30PM +0200, Dmitry Baryshkov wrote:
> > > >> > > On Mon, Mar 23, 2026 at 07:14:25PM +0530, Manivannan Sadhasivam wrote:
> > > >> > > > On Mon, Mar 23, 2026 at 08:39:55AM -0500, Rob Herring wrote:
> > > >> > > > > On Mon, Mar 23, 2026 at 7:16 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > >> > > > > >
> > > >> > > > > > On Sun, Mar 22, 2026 at 06:37:13PM -0500, Rob Herring wrote:
> > > >> > > > > > > On Tue, Mar 17, 2026 at 09:59:56AM +0530, Manivannan Sadhasivam wrote:
> > > >> > > > > > > > Lenovo Thinkpad T14s is found to have a soldered down version of M.2 1620
> > > >> > > > > > > > LGA connector. Though, there is no 1620 LGA form factor defined in the M.2
> > > >> > > > > > > > spec, it looks very similar to the M.2 Key E connector. So add the
> > > >> > > > > > > > "pcie-m2-1620-lga-connector" compatible with "pcie-m2-e-connector" fallback
> > > >> > > > > > > > to reuse the Key E binding.
> > > >> > > > > > >
> > > >> > > > > > > What is LGA?
> > > >> > > > > > >
> > > >> > > > > >
> > > >> > > > > > Land Grid Array
> > > >> > > > > >
> > > >> > > > > > > If not in the spec, is it really something generic?
> > > >> > > > > > >
> > > >> > > > > >
> > > >> > > > > > Good question. Yes and No! LGA is not something that Lenovo only uses. Other
> > > >> > > > > > vendors may also use this form factor. PCIe connectors are full of innovation as
> > > >> > > > > > the spec gives room for hardware designers to be as innovative as possible to
> > > >> > > > > > save the BOM cost.
> > > >> > > > >
> > > >> > > > > innovation == incompatible changes
> > > >> > > > >
> > > >> > > >
> > > >> > > > Yes, I was trying to sound nice :)
> > > >> > > >
> > > >> > > > > > This is why I do not want to make it Lenovo specific. But if you prefer that, I
> > > >> > > > > > can name it as "lenovo,pcie-m2-1620-lga-connector".
> > > >> > > > >
> > > >> > > > > Depends if you think that s/w needs to know the differences. Hard to
> > > >> > > > > say with a sample size of 1.
> > > >> > > > >
> > > >> > > >
> > > >> > > > Sure. Will add the 'lenovo' prefix then.
> > > >> > >
> > > >> > > Is it really Lenovo? Or is it some other module vendor, whose LGAs are
> > > >> > > being used by Lenovo?
> > > >> > >
> > > >> > > I remember that DB820c also used some kind of a module for the WiFi card
> > > >> > > (which might be M.2 compatible or might not, I can't find exact docs at
> > > >> > > this point).
> > > >> > >
> > > >> >
> > > >> > I don't know. These kind of designs might be reused by several vendors. But
> > > >> > considering that we should not make it generic, I'd go with Lenovo as that's
> > > >> > the only vendor we know as of now.
> > > >>
> > > >> ... and later we learn that other vendors use the same idea /pinout,
> > > >> then nothing stops us from still telling that it's a
> > > >> "lenovo,pcie-m2-something-lga".
> > > >>
> > > >
> > > > How do you possibly know whether a single vendor has introduced this form factor
> > > > or reused by multiple ones? Atleast, I don't have access to such a source to
> > > > confirm.
> > > >
> > > I've not really been following this thread/patchset in detail; but want me to try and check with the T14s platform team if this device is specifically made for us (Lenovo) or not?
> > > I doubt it is - we just don't do that usually, but I can go and ask the question if it will help resolve this (with the caveat that it could hold up the review for a bit and I may not be able to get a straight answer)
> > >
> >
> > I can drop this specific patch in the meantime.
> >
> > > My vote (for what little it's worth) would be to make it non-Lenovo specific. Then when the same part causes issues on another vendors platform I won't get asked questions about why Lenovo is breaking <other vendor> :)
> > >
> >
> > Even if Lenovo prefix is used, it won't break other vendors. Just that we will
> > end up adding more compatibles.
> >
> > Anyhow, I'll wait for your reply and drop this patch for next revision.
> >
>
> If you need a vendor prefix, I think "qcom," would be more appropriate
> than Lenovo. This form factor is used by most vendors for recent
> soldered Qualcomm-based wireless cards, not just Lenovo:
>
> - Dell XPS 13 9345 has exactly the same soldered M.2 card, I assume
> there are several other vendors as well.
>
> - https://www.sparklan.com/product/wnsq-290be/ is a third-party
> (Qualcomm-based) M.2 LGA 1620 card, in the block diagram the
> pinout is called "QM.2 1620 LGA 168pin".
>
> - If you press F9 while booting the ThinkPad T14s, you should get to a
> screen with "Regulatory Information". For the T14s, this screen says
> "Contains FCC ID: J9C-QCNCM825". This is the WiFi/BT module in the
> soldered form factor. If you look that up on the FCC website, the
> applicant for this module is "Qualcomm Technologies, Inc.". This
> seems to be some kind of "modular certification" that vendors can
> reuse/adapt without going through the whole process again.
>
> Perhaps you should ask around inside Qualcomm? :-)
>
Sorry for getting back after this long. I did ask around, but our HW folks are
saying that Qcom is not the first one to use LGA M.2 modules. They claim that
other vendors also do that.
But for this specific card, it should be fine to use the 'qcom' prefix as
apparently the module was supplied by Qcom.
I'll submit the bindings patch together with DTS change for T14s.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and platform support
From: Arnd Bergmann @ 2026-06-10 12:50 UTC (permalink / raw)
To: Jason Li, jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, linux-serial, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <20260610112821.3030099-2-jason.li@cortina-access.com>
On Wed, Jun 10, 2026, at 13:28, Jason Li wrote:
> This series adds Linux kernel support for the UART controller integrated
> in Cortina-Access SoCs, with CA8289 (Venus) as the first supported device.
Hi Jason,
Thanks a lot for your submission!
I'm glad to see Cortina Access is getting back to upstreaming
this support, I see that you first tries this in 2021 but
didn't get very far at the time. The last submission was v4,
so it would make sense to cound this one as v5 and continue
with v6 next time.
You have already received a number of comments, so I'll skip
looking at the details for the moment and let you work through
them.
Regarding how to split up the patch series between uart and
soc, I think sending them together during the review phase
as you do here makes sense, but as they are loosely coupled,
I think we will likely merge them separately. For simplicity,
I would then just put the MAINTAINERS entry and the bindings
for the vendor and board into the series for the soc tree.
It would also help me if you could add some more context about
the SoC into the patch description for the patch that adds
the arm64 platform, in particular:
- is this the only one you are planning to upstream at this
point, or do you already have plans for other SoCs in this
family?
- do you expect to see full support for actual end-user
products using these chips?
- is there any shared lineage with the cortina-systems
(storlink/storm, now marvell) gemini 32-bit chips that we
already support, or with any of the Realtek SoCs that
are also being upstreamed now?
Arnd
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: serial: Add binding for Cortina-Access UART
From: Krzysztof Kozlowski @ 2026-06-10 11:51 UTC (permalink / raw)
To: Jason Li, jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-3-jason.li@cortina-access.com>
On 10/06/2026 13:28, Jason Li wrote:
> +
> +allOf:
> + - $ref: serial.yaml#
> +
> +properties:
> + compatible:
> + const: cortina-access,serial
Aren't writing bindings very clear about that? Please, take your time to
read through the docs, so we will not need to repeat basic guidance. It
is documented there on purpose.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: cortina-access: Add DTS for CA8289 SoC and Venus board
From: Krzysztof Kozlowski @ 2026-06-10 11:49 UTC (permalink / raw)
To: Jason Li, jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-5-jason.li@cortina-access.com>
On 10/06/2026 13:28, Jason Li wrote:
> Add SoC DTSI for the Cortina-Access CA8289 (Venus) and a board DTS for
> the Venus engineering board. The description covers the minimum set of
> hardware nodes needed to boot a kernel with an INITRD rootfs: CPUs,
> GIC, timer, PSCI, fixed clock and UART.
>
> Signed-off-by: Jason Li <jason.li@cortina-access.com>
> Assisted-by: Claude:claude-opus-4-8
SoB should be the last tag.
Also, it does not match From field.
> ---
> MAINTAINERS | 1 +
> arch/arm64/Kconfig.platforms | 10 ++
> arch/arm64/boot/dts/Makefile | 1 +
> arch/arm64/boot/dts/cortina-access/Makefile | 2 +
> .../dts/cortina-access/ca8289-engboard.dts | 31 +++++
> .../boot/dts/cortina-access/ca8289-soc.dtsi | 118 ++++++++++++++++++
> 6 files changed, 163 insertions(+)
> create mode 100644 arch/arm64/boot/dts/cortina-access/Makefile
> create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
> create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 515d89d96472..ebfdb9c267cc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2826,6 +2826,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
> S: Maintained
> F: Documentation/devicetree/bindings/arm/cortina-access.yaml
> F: Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
> +F: arch/arm64/boot/dts/cortina-access/
>
> ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
> M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
> diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
> index dc995a732117..ba6dda0660c3 100644
> --- a/arch/arm64/Kconfig.platforms
> +++ b/arch/arm64/Kconfig.platforms
> @@ -134,6 +134,16 @@ config ARCH_CIX
> This enables support for the Cixtech SoC family,
> like P1(sky1).
>
> +config ARCH_CORTINA_ACCESS
> + bool "Cortina-Access SoC Family"
> + select GPIOLIB
> + select PINCTRL
> + help
> + This enables support for Cortina-Access SoCs. The family
> + includes ARMv8-based devices targeting networking and access
> + applications.
> + If you have a Cortina-Access board, say Y here.
> +
> config ARCH_EXYNOS
> bool "Samsung Exynos SoC family"
> select COMMON_CLK_SAMSUNG
> diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
> index 98ec8f1b76e4..a599f525fb9a 100644
> --- a/arch/arm64/boot/dts/Makefile
> +++ b/arch/arm64/boot/dts/Makefile
> @@ -16,6 +16,7 @@ subdir-y += broadcom
> subdir-y += bst
> subdir-y += cavium
> subdir-y += cix
> +subdir-y += cortina-access
> subdir-y += exynos
> subdir-y += freescale
> subdir-y += hisilicon
> diff --git a/arch/arm64/boot/dts/cortina-access/Makefile b/arch/arm64/boot/dts/cortina-access/Makefile
> new file mode 100644
> index 000000000000..554893f381fe
> --- /dev/null
> +++ b/arch/arm64/boot/dts/cortina-access/Makefile
> @@ -0,0 +1,2 @@
> +# SPDX-License-Identifier: GPL-2.0
> +dtb-$(CONFIG_ARCH_CORTINA_ACCESS) += ca8289-engboard.dtb
> diff --git a/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts b/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
> new file mode 100644
> index 000000000000..c8289a0f8269
> --- /dev/null
> +++ b/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
> @@ -0,0 +1,31 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * dts file for Cortina Access Venus Engineering Board
> + *
> + * Copyright (C) 2026, Cortina Access Inc.
> + *
> + */
> +
> +/dts-v1/;
> +
> +#include "ca8289-soc.dtsi"
> +
> +/ {
> + model = "Cortina Access Venus Engineering Board";
> + compatible = "cortina-access,ca8289-engboard";
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + aliases {
> + serial0 = &uart0;
> + };
> +
> + chosen {
> + stdout-path = "serial0:115200n8";
> + };
> +
> + memory@0 { /* 512MB */
> + device_type = "memory";
> + reg = <0x00000000 0x00000000 0x0 0x20000000>;
> + };
> +};
> diff --git a/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi b/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
> new file mode 100644
> index 000000000000..8e7ffcf4ccab
> --- /dev/null
> +++ b/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
> @@ -0,0 +1,118 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * dts file for Cortina Access CA8289 SoC
> + *
> + * Copyright (C) 2026, Cortina Access Inc.
> + */
> +
> +#include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/interrupt-controller/irq.h>
> +
> +/ {
> + cpus {
> + #address-cells = <2>;
> + #size-cells = <0>;
> +
> + cpu0: cpu@0 {
> + compatible = "arm,cortex-a55", "arm,armv8";
> + device_type = "cpu";
> + reg = <0x0 0x0>;
> + enable-method = "psci";
> + };
Missing blank lines. Look at existing code how this is supposed to look
like.
> + cpu1: cpu@100 {
> + compatible = "arm,cortex-a55", "arm,armv8";
> + device_type = "cpu";
> + reg = <0x0 0x100>;
> + enable-method = "psci";
> + };
> + cpu2: cpu@200 {
> + compatible = "arm,cortex-a55", "arm,armv8";
> + device_type = "cpu";
> + reg = <0x0 0x200>;
> + enable-method = "psci";
> + };
> + cpu3: cpu@300 {
> + compatible = "arm,cortex-a55", "arm,armv8";
> + device_type = "cpu";
> + reg = <0x0 0x300>;
> + enable-method = "psci";
> + };
> + cpu-map {
> + cluster0 {
> + core0 {
> + cpu = <&cpu0>;
> + };
> + core1 {
> + cpu = <&cpu1>;
> + };
> + core2 {
> + cpu = <&cpu2>;
> + };
> + core3 {
> + cpu = <&cpu3>;
> + };
> + };
> + };
> + };
> +
> + psci {
> + compatible = "arm,psci-0.2";
> + method = "smc";
> + };
> +
> + gic: interrupt-controller@4f8000000 {
And now you repeat basic mistakes:
1. Pointed out by W=1 dtbs_check build
2. Fixed long time in every source
3. Explicitly documented in writing bindings and DTS coding style
> + compatible = "arm,gic-v3";
> + #interrupt-cells = <3>;
> + interrupt-controller;
> + #redistributor-regions = <1>;
> + reg = <0x00000004 0xF8000000 0 0x10000>,
> + <0x00000004 0xF8040000 0 0x80000>;
Read DTS coding style.
> + };
> +
> + apb_pclk: apb-pclk {
Nope, drop entire node.
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <125000000>;
> + };
> +
> + reserved-memory {
> + #address-cells = <2>;
> + #size-cells = <2>;
> + ranges;
> +
> + /* TrustZone reserved region; must not be mapped by the kernel */
> + tz_pool: tz-buffer@f000000 {
> + reg = <0x0 0x0F000000 0x0 0x1000000>;
> + no-map;
> + };
> + };
> +
> + /* See Documentation/devicetree/bindings/timer/arm,arch_timer.yaml */
> + timer {
> + compatible = "arm,armv8-timer";
> + interrupt-parent = <&gic>;
> + interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
> + <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
> + clock-frequency = <25000000>;
> + };
> +
> + uart0: serial@f4329188 {
> + device_type = "serial";
> + compatible = "cortina-access,serial";
> + reg = <0x00000000 0xf4329188 0x0 0x30>;
This is AI slop. Whatever Claude convinced you to do, it is nothing like
upstream kernel source.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH 1/3] dt-bindings: serial: Add binding for Cortina-Access UART
From: Krzysztof Kozlowski @ 2026-06-10 11:46 UTC (permalink / raw)
To: Jason Li, jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-3-jason.li@cortina-access.com>
On 10/06/2026 13:28, Jason Li wrote:
> Add DT binding schema for the Cortina-Access UART controller.
> This IP is integrated into most CAXXXX SoC family members.
>
> Also add the vendor prefix for Cortina Access, Inc. and the
> top-level ARM board binding document for the CA8289 (Venus) SoC.
>
> Signed-off-by: Jason Li <jason.li@cortina-access.com>
> Assisted-by: Claude:claude-opus-4-8
> ---
> .../bindings/arm/cortina-access.yaml | 29 ++++++++++++
> .../serial/cortina-access,serial.yaml | 46 +++++++++++++++++++
> .../devicetree/bindings/vendor-prefixes.yaml | 2 +
> MAINTAINERS | 7 +++
This is somehow complete mess. serial and arm together?
Please carefully read submitting patches (both documents!) and don't
send AI-assisted slop.
You must not combine independent works together.
> 4 files changed, 84 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/arm/cortina-access.yaml
> create mode 100644 Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
>
> diff --git a/Documentation/devicetree/bindings/arm/cortina-access.yaml b/Documentation/devicetree/bindings/arm/cortina-access.yaml
> new file mode 100644
> index 000000000000..ec0320ed0c0b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/cortina-access.yaml
> @@ -0,0 +1,29 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/arm/cortina-access.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cortina-Access SoC boards
> +
> +maintainers:
> + - Jason Li <jason.li@cortina-access.com>
> +
> +description:
> + Boards based on Cortina-Access ARMv8 SoCs targeting networking and
> + access applications.
> +
> +properties:
> + $nodename:
> + const: /
> + compatible:
> + oneOf:
> + - description: Cortina-Access CA8289 (Venus) engineering board
> + const: cortina-access,ca8289-engboard
> +
> + - description: Cortina-Access CA8289 (Venus) reference board
> + const: cortina-access,ca8289-refboard
Where is the SoC? This looks like very poor contribution. If you opened
any existing recent board binding you would see it is done differently.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH 3/3] arm64: dts: cortina-access: Add DTS for CA8289 SoC and Venus board
From: Jason Li @ 2026-06-10 11:28 UTC (permalink / raw)
To: jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-1-jason.li@cortina-access.com>
Add SoC DTSI for the Cortina-Access CA8289 (Venus) and a board DTS for
the Venus engineering board. The description covers the minimum set of
hardware nodes needed to boot a kernel with an INITRD rootfs: CPUs,
GIC, timer, PSCI, fixed clock and UART.
Signed-off-by: Jason Li <jason.li@cortina-access.com>
Assisted-by: Claude:claude-opus-4-8
---
MAINTAINERS | 1 +
arch/arm64/Kconfig.platforms | 10 ++
arch/arm64/boot/dts/Makefile | 1 +
arch/arm64/boot/dts/cortina-access/Makefile | 2 +
.../dts/cortina-access/ca8289-engboard.dts | 31 +++++
.../boot/dts/cortina-access/ca8289-soc.dtsi | 118 ++++++++++++++++++
6 files changed, 163 insertions(+)
create mode 100644 arch/arm64/boot/dts/cortina-access/Makefile
create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
diff --git a/MAINTAINERS b/MAINTAINERS
index 515d89d96472..ebfdb9c267cc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2826,6 +2826,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/arm/cortina-access.yaml
F: Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
+F: arch/arm64/boot/dts/cortina-access/
ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index dc995a732117..ba6dda0660c3 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -134,6 +134,16 @@ config ARCH_CIX
This enables support for the Cixtech SoC family,
like P1(sky1).
+config ARCH_CORTINA_ACCESS
+ bool "Cortina-Access SoC Family"
+ select GPIOLIB
+ select PINCTRL
+ help
+ This enables support for Cortina-Access SoCs. The family
+ includes ARMv8-based devices targeting networking and access
+ applications.
+ If you have a Cortina-Access board, say Y here.
+
config ARCH_EXYNOS
bool "Samsung Exynos SoC family"
select COMMON_CLK_SAMSUNG
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 98ec8f1b76e4..a599f525fb9a 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -16,6 +16,7 @@ subdir-y += broadcom
subdir-y += bst
subdir-y += cavium
subdir-y += cix
+subdir-y += cortina-access
subdir-y += exynos
subdir-y += freescale
subdir-y += hisilicon
diff --git a/arch/arm64/boot/dts/cortina-access/Makefile b/arch/arm64/boot/dts/cortina-access/Makefile
new file mode 100644
index 000000000000..554893f381fe
--- /dev/null
+++ b/arch/arm64/boot/dts/cortina-access/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_CORTINA_ACCESS) += ca8289-engboard.dtb
diff --git a/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts b/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
new file mode 100644
index 000000000000..c8289a0f8269
--- /dev/null
+++ b/arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dts file for Cortina Access Venus Engineering Board
+ *
+ * Copyright (C) 2026, Cortina Access Inc.
+ *
+ */
+
+/dts-v1/;
+
+#include "ca8289-soc.dtsi"
+
+/ {
+ model = "Cortina Access Venus Engineering Board";
+ compatible = "cortina-access,ca8289-engboard";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory@0 { /* 512MB */
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x0 0x20000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi b/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
new file mode 100644
index 000000000000..8e7ffcf4ccab
--- /dev/null
+++ b/arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dts file for Cortina Access CA8289 SoC
+ *
+ * Copyright (C) 2026, Cortina Access Inc.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a55", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x0>;
+ enable-method = "psci";
+ };
+ cpu1: cpu@100 {
+ compatible = "arm,cortex-a55", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x100>;
+ enable-method = "psci";
+ };
+ cpu2: cpu@200 {
+ compatible = "arm,cortex-a55", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x200>;
+ enable-method = "psci";
+ };
+ cpu3: cpu@300 {
+ compatible = "arm,cortex-a55", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x300>;
+ enable-method = "psci";
+ };
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ core2 {
+ cpu = <&cpu2>;
+ };
+ core3 {
+ cpu = <&cpu3>;
+ };
+ };
+ };
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ gic: interrupt-controller@4f8000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ #redistributor-regions = <1>;
+ reg = <0x00000004 0xF8000000 0 0x10000>,
+ <0x00000004 0xF8040000 0 0x80000>;
+ };
+
+ apb_pclk: apb-pclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <125000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* TrustZone reserved region; must not be mapped by the kernel */
+ tz_pool: tz-buffer@f000000 {
+ reg = <0x0 0x0F000000 0x0 0x1000000>;
+ no-map;
+ };
+ };
+
+ /* See Documentation/devicetree/bindings/timer/arm,arch_timer.yaml */
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ clock-frequency = <25000000>;
+ };
+
+ uart0: serial@f4329188 {
+ device_type = "serial";
+ compatible = "cortina-access,serial";
+ reg = <0x00000000 0xf4329188 0x0 0x30>;
+ clocks = <&apb_pclk>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ uart1: serial@f43291b8 {
+ device_type = "serial";
+ compatible = "cortina-access,serial";
+ reg = <0x00000000 0xf43291b8 0x0 0x30>;
+ clocks = <&apb_pclk>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ };
+};
--
2.39.5
^ permalink raw reply related
* [PATCH 2/3] tty: serial: Add UART driver for Cortina-Access platform
From: Jason Li @ 2026-06-10 11:28 UTC (permalink / raw)
To: jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-1-jason.li@cortina-access.com>
This driver supports Cortina Access UART IP integrated
in most CAXXXX line of SoCs. Earlycon is also supported.
Signed-off-by: Jason Li <jason.li@cortina-access.com>
Assisted-by: Claude:claude-opus-4-8
---
MAINTAINERS | 6 +
drivers/tty/serial/Kconfig | 21 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/serial_cortina-access.c | 755 +++++++++++++++++++++
4 files changed, 783 insertions(+)
create mode 100644 drivers/tty/serial/serial_cortina-access.c
diff --git a/MAINTAINERS b/MAINTAINERS
index cc261888fae0..515d89d96472 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6687,6 +6687,12 @@ S: Maintained
F: Documentation/hwmon/corsair-psu.rst
F: drivers/hwmon/corsair-psu.c
+CORTINA-ACCESS SERIAL CONSOLE DRIVER
+M: Jason Li <jason.li@cortina-access.com>
+L: linux-serial@vger.kernel.org
+S: Supported
+F: drivers/tty/serial/serial_cortina-access.c
+
COUNTER SUBSYSTEM
M: William Breathitt Gray <wbg@kernel.org>
L: linux-iio@vger.kernel.org
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index cf7dba473b20..99a1c9308395 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1592,6 +1592,27 @@ config SERIAL_NUVOTON_MA35D1_CONSOLE
but you can alter that using a kernel command line option such as
"console=ttyNVTx".
+config SERIAL_CORTINA_ACCESS
+ tristate "Cortina-Access serial port support"
+ depends on OF
+ select SERIAL_CORE
+ help
+ This driver is for the Cortina-Access SoC UART, present in the
+ CA8289 (Venus) and related CAXXXX family of SoCs. If you have a
+ machine based on the Cortina-Access SoC and wish to use the serial
+ port, say 'Y' here. Otherwise, say 'N'.
+
+config SERIAL_CORTINA_ACCESS_CONSOLE
+ bool "Console on Cortina-Access serial port"
+ depends on SERIAL_CORTINA_ACCESS=y
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+ help
+ Say 'Y' here if you wish to use the Cortina-Access UART as the system
+ console (the device which receives all kernel messages and warnings
+ and which allows logins in single user mode).
+ /dev/ttyS* is the default device node.
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index bba7b21a4a1d..54866c419714 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -98,3 +98,4 @@ obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o
+obj-$(CONFIG_SERIAL_CORTINA_ACCESS) += serial_cortina-access.o
diff --git a/drivers/tty/serial/serial_cortina-access.c b/drivers/tty/serial/serial_cortina-access.c
new file mode 100644
index 000000000000..f25eae987ccd
--- /dev/null
+++ b/drivers/tty/serial/serial_cortina-access.c
@@ -0,0 +1,755 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UART driver for Cortina-Access SoC platform
+ * Copyright (C) 2026 Cortina-Access Inc.
+ */
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/***************************************
+ * UART Related registers
+ ****************************************/
+/* register definitions */
+#define CFG 0x00
+#define FC 0x04
+#define RX_SAMPLE 0x08
+#define RT_TUNE 0x0C
+#define TX_DAT 0x10
+#define RX_DAT 0x14
+#define INFO 0x18
+#define IE 0x1C
+#define INT 0x24
+#define STATUS 0x2C
+
+/* CFG */
+#define CFG_STOP_2BIT BIT(2)
+#define CFG_PARITY_EVEN BIT(3)
+#define CFG_PARITY_EN BIT(4)
+#define CFG_TX_EN BIT(5)
+#define CFG_RX_EN BIT(6)
+#define CFG_UART_EN BIT(7)
+#define CFG_BAUD_SART_SHIFT 8
+
+/* INFO */
+#define INFO_TX_EMPTY BIT(3)
+#define INFO_TX_FULL BIT(2)
+#define INFO_RX_EMPTY BIT(1)
+#define INFO_RX_FULL BIT(0)
+
+/* Interrupt */
+#define RX_BREAK BIT(7)
+#define RX_FIFO_NONEMPTYE BIT(6)
+#define TX_FIFO_EMPTYE BIT(5)
+#define RX_FIFO_UNDERRUNE BIT(4)
+#define RX_FIFO_OVERRUNE BIT(3)
+#define RX_PARITY_ERRE BIT(2)
+#define RX_STOP_ERRE BIT(1)
+#define TX_FIFO_OVERRUNE BIT(0)
+
+#define TX_TIMEOUT 5000
+#define UART_NR 4
+#define CA_UART_NAME_LEN 32
+
+struct cortina_uart_port {
+ struct uart_port uart;
+ char name[CA_UART_NAME_LEN];
+ char has_bi;
+ unsigned int may_wakeup;
+};
+
+static struct cortina_uart_port *cortina_uart_ports;
+
+static irqreturn_t cortina_uart_interrupt(int irq, void *dev_id);
+static inline void cortina_uart_interrupt_tx_chars(struct uart_port *port);
+
+/* Return uart_port pointer based on index */
+static struct cortina_uart_port *cortina_uart_get_port(unsigned int index)
+{
+ struct cortina_uart_port *pca_port = cortina_uart_ports;
+
+ if (index >= UART_NR)
+ index = 0;
+
+ pca_port += index;
+
+ return pca_port;
+}
+
+/* uart_ops functions */
+static unsigned int cortina_uart_tx_empty(struct uart_port *port)
+{
+ /* Return 0 on FIFO full condition, TIOCSER_TEMT otherwise */
+ return (readl(port->membase + INFO) & INFO_TX_EMPTY) ? TIOCSER_TEMT : 0;
+}
+
+static void cortina_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /*
+ * Even if we do not support configuring the modem control lines, this
+ * function must be provided to the serial core.
+ * port->ops->set_mctrl() is called in uart_configure_port()
+ */
+}
+
+static unsigned int cortina_uart_get_mctrl(struct uart_port *port)
+{
+ /* Unimplemented signals asserted, per Documentation/serial/driver */
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void cortina_uart_stop_tx(struct uart_port *port)
+{
+ /* Turn off Tx interrupts. The port lock is held at this point */
+ unsigned int reg_v;
+
+ reg_v = readl(port->membase + IE);
+ writel(reg_v & ~TX_FIFO_EMPTYE, port->membase + IE);
+}
+
+static void cortina_uart_start_tx(struct uart_port *port)
+{
+ /* Turn on Tx interrupts. The port lock is held at this point */
+ unsigned int reg_v;
+
+ reg_v = readl(port->membase + IE);
+ writel(reg_v | TX_FIFO_EMPTYE, port->membase + IE);
+
+ reg_v = readl(port->membase + CFG);
+ writel(reg_v | CFG_TX_EN, port->membase + CFG);
+
+ /*
+ * If TX FIFO is already empty the TX_FIFO_EMPTY interrupt may be
+ * edge-triggered and won't fire again. Kick-start the transmission
+ * explicitly so the first character is not lost.
+ */
+ if (readl(port->membase + INFO) & INFO_TX_EMPTY)
+ cortina_uart_interrupt_tx_chars(port);
+}
+
+static void cortina_uart_stop_rx(struct uart_port *port)
+{
+ /* Turn off Rx interrupts. The port lock is held at this point */
+ unsigned int reg_v;
+
+ reg_v = readl(port->membase + IE);
+ writel(reg_v & ~RX_FIFO_NONEMPTYE, port->membase + IE);
+}
+
+static void cortina_uart_enable_ms(struct uart_port *port)
+{
+ /* Nope, you really can't hope to attach a modem to this */
+}
+
+static int cortina_uart_startup(struct uart_port *port)
+{
+ unsigned int reg_v;
+ int retval;
+ unsigned long flags;
+
+ /* Disable interrupts */
+ writel(0, port->membase + IE);
+
+ retval = request_irq(port->irq, cortina_uart_interrupt, 0,
+ "cortina_uart", port);
+ if (retval)
+ return retval;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ reg_v = readl(port->membase + CFG);
+ reg_v |= (CFG_UART_EN | CFG_TX_EN | CFG_RX_EN | 0x3 /* 8-bits data */);
+ writel(reg_v, port->membase + CFG);
+ reg_v = readl(port->membase + IE);
+ writel(reg_v | RX_FIFO_NONEMPTYE | TX_FIFO_EMPTYE, port->membase + IE);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+ return 0;
+}
+
+static void cortina_uart_shutdown(struct uart_port *port)
+{
+ cortina_uart_stop_tx(port);
+ cortina_uart_stop_rx(port);
+ free_irq(port->irq, port);
+}
+
+static void cortina_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ const struct ktermios *old)
+{
+ unsigned long flags;
+ int baud;
+ unsigned int reg_v, sample_freq = 0;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+ reg_v = readl(port->membase + CFG);
+ /* mask off the baud settings */
+ reg_v &= 0xff;
+ reg_v |= (port->uartclk / baud) << CFG_BAUD_SART_SHIFT;
+
+ /* Sampling rate should be half of baud count */
+ sample_freq = (reg_v >> CFG_BAUD_SART_SHIFT) / 2;
+
+ /* See include/uapi/asm-generic/termbits.h for CSIZE definition */
+ /* mask off the data width */
+ reg_v &= 0xfffffffc;
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ reg_v |= 0x0;
+ break;
+ case CS6:
+ reg_v |= 0x1;
+ break;
+ case CS7:
+ reg_v |= 0x2;
+ break;
+ case CS8:
+ default:
+ reg_v |= 0x3;
+ break;
+ }
+
+ /* mask off Stop bits */
+ reg_v &= ~(CFG_STOP_2BIT);
+ if (termios->c_cflag & CSTOPB)
+ reg_v |= CFG_STOP_2BIT;
+
+ /* Parity */
+ reg_v &= ~(CFG_PARITY_EN);
+ reg_v |= CFG_PARITY_EVEN;
+ if (termios->c_cflag & PARENB) {
+ reg_v |= CFG_PARITY_EN;
+ if (termios->c_cflag & PARODD)
+ reg_v &= ~(CFG_PARITY_EVEN);
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+ writel(reg_v, port->membase + CFG);
+ writel(sample_freq, port->membase + RX_SAMPLE);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *cortina_uart_type(struct uart_port *port)
+{
+ return container_of(port, struct cortina_uart_port, uart)->name;
+}
+
+static void cortina_uart_config_port(struct uart_port *port, int flags)
+{
+ /*
+ * Driver core for serial ports forces a non-zero value for port type.
+ * Write an arbitrary value here to accommodate the serial core driver,
+ * as ID part of UAPI is redundant.
+ */
+ port->type = 1;
+}
+
+static int cortina_uart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ if (ser->type != PORT_UNKNOWN && ser->type != 1)
+ return -EINVAL;
+ return 0;
+}
+
+static void cortina_access_power(struct uart_port *port, unsigned int state,
+ unsigned int oldstate)
+{
+ unsigned int reg_v;
+
+ reg_v = readl(port->membase + CFG);
+ switch (state) {
+ case UART_PM_STATE_ON:
+ reg_v |= CFG_UART_EN;
+ break;
+ case UART_PM_STATE_OFF:
+ reg_v &= ~CFG_UART_EN;
+ break;
+ default:
+ pr_err("cortina-access serial: Unknown PM state %d\n", state);
+ }
+ writel(reg_v, port->membase + CFG);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int cortina_poll_get_char(struct uart_port *port)
+{
+ if (readl(port->membase + INFO) & INFO_RX_EMPTY)
+ return NO_POLL_CHAR;
+
+ return readl(port->membase + RX_DAT);
+}
+
+static void cortina_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ unsigned long time_out;
+
+ time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT);
+
+ while (time_before(jiffies, time_out) &&
+ (readl(port->membase + INFO) & INFO_TX_FULL))
+ cpu_relax();
+
+ /* Give up if FIFO stuck! */
+ if (readl(port->membase + INFO) & INFO_TX_FULL)
+ return;
+
+ writel(c, port->membase + TX_DAT);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static const struct uart_ops cortina_uart_ops = {
+ .tx_empty = cortina_uart_tx_empty,
+ .set_mctrl = cortina_uart_set_mctrl,
+ .get_mctrl = cortina_uart_get_mctrl,
+ .stop_tx = cortina_uart_stop_tx,
+ .start_tx = cortina_uart_start_tx,
+ .stop_rx = cortina_uart_stop_rx,
+ .enable_ms = cortina_uart_enable_ms,
+ .startup = cortina_uart_startup,
+ .shutdown = cortina_uart_shutdown,
+ .set_termios = cortina_uart_set_termios,
+ .type = cortina_uart_type,
+ .config_port = cortina_uart_config_port,
+ .verify_port = cortina_uart_verify_port,
+ .pm = cortina_access_power,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = cortina_poll_get_char,
+ .poll_put_char = cortina_poll_put_char,
+#endif
+};
+
+static inline void cortina_uart_interrupt_rx_chars(struct uart_port *port,
+ unsigned long status)
+{
+ struct tty_port *ttyport = &port->state->port;
+ unsigned int ch;
+ unsigned int rx, flg;
+ struct cortina_uart_port *pca_port;
+
+ rx = readl(port->membase + INFO);
+ if (INFO_RX_EMPTY & rx)
+ return;
+
+ if (status & RX_FIFO_OVERRUNE)
+ port->icount.overrun++;
+
+ pca_port = cortina_uart_get_port(port->line);
+
+ /* Read characters while FIFO is not empty */
+ do {
+ flg = TTY_NORMAL;
+ port->icount.rx++;
+ ch = readl(port->membase + RX_DAT);
+ if (status & RX_PARITY_ERRE) {
+ port->icount.parity++;
+ flg = TTY_PARITY;
+ }
+
+ if (pca_port->has_bi) {
+ if (status & RX_BREAK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ goto ignore;
+ }
+ } else {
+ /* Treat stop err as BI */
+ if (status & RX_STOP_ERRE) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ goto ignore;
+ }
+ }
+ if (!(ch & 0x100)) /* RX char is not valid */
+ goto ignore;
+
+ if (uart_handle_sysrq_char(port, (unsigned char)ch))
+ goto ignore;
+
+ tty_insert_flip_char(ttyport, ch, flg);
+ignore:
+ rx = readl(port->membase + INFO);
+ } while (!(INFO_RX_EMPTY & rx));
+
+ spin_unlock(&port->lock);
+ tty_flip_buffer_push(ttyport);
+ spin_lock(&port->lock);
+}
+
+static inline void cortina_uart_interrupt_tx_chars(struct uart_port *port)
+{
+ u8 ch;
+
+ /*
+ * uart_port_tx() drains the kfifo xmit buffer, handles x_char,
+ * calls uart_write_wakeup() and stop_tx() when the buffer empties.
+ */
+ uart_port_tx(port, ch,
+ !(readl(port->membase + INFO) & INFO_TX_FULL),
+ writel(ch, port->membase + TX_DAT));
+}
+
+static irqreturn_t cortina_uart_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = (struct uart_port *)dev_id;
+ unsigned int irq_status;
+
+ spin_lock(&port->lock);
+
+ /* Clear interrupt */
+ irq_status = readl(port->membase + INT);
+ writel(irq_status, port->membase + INT);
+
+ /* Process any Rx chars first */
+ cortina_uart_interrupt_rx_chars(port, irq_status);
+ /* Then use any Tx space */
+ cortina_uart_interrupt_tx_chars(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_SERIAL_CORTINA_ACCESS_CONSOLE
+static void cortina_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port;
+ struct cortina_uart_port *pca_port;
+ unsigned int i, previous;
+ unsigned long flags;
+ int locked;
+
+ pca_port = cortina_uart_get_port(co->index);
+ port = &pca_port->uart;
+
+ local_irq_save(flags);
+ if (port->sysrq) {
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&port->lock);
+ } else {
+ spin_lock(&port->lock);
+ locked = 1;
+ }
+
+ /* Save current state */
+ previous = readl(port->membase + IE);
+ /* Disable Tx interrupts so this all goes out in one go */
+ cortina_uart_stop_tx(port);
+
+ /* Write all the chars */
+ for (i = 0; i < count; i++) {
+ /* Wait for the TX buffer to be empty */
+ while (!(readl(port->membase + INFO) & INFO_TX_EMPTY))
+ cpu_relax();
+
+ writel(*s, port->membase + TX_DAT);
+
+ /* CR/LF handling */
+ if (*s++ == '\n') {
+ while (!(readl(port->membase + INFO) & INFO_TX_EMPTY))
+ cpu_relax();
+ writel('\r', port->membase + TX_DAT);
+ }
+ }
+
+ writel(previous, port->membase + IE); /* Restore interrupt state */
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
+}
+
+static int __init cortina_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ struct cortina_uart_port *pca_port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= UART_NR)
+ return -ENODEV;
+
+ pca_port = cortina_uart_get_port(co->index);
+ port = &pca_port->uart;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver cortina_uart_driver;
+
+static struct console cortina_console = {
+ .name = "ttyS",
+ .write = cortina_console_write,
+ .device = uart_console_device,
+ .setup = cortina_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &cortina_uart_driver,
+};
+
+#define CORTINA_CONSOLE (&cortina_console)
+
+/* Support EARLYCON */
+static void cortina_putc(struct uart_port *port, unsigned char c)
+{
+ unsigned int tmout = TX_TIMEOUT;
+
+ /* No jiffies at early boot stage; wait up to TX_TIMEOUT us */
+ while (--tmout) {
+ if (!(readl(port->membase + INFO) & INFO_TX_FULL))
+ break;
+ udelay(1);
+ }
+
+ /* Give up if FIFO stuck */
+ if (readl(port->membase + INFO) & INFO_TX_FULL)
+ return;
+
+ writel(c, port->membase + TX_DAT);
+}
+
+static void cortina_early_write(struct console *con, const char *s,
+ unsigned int n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, cortina_putc);
+}
+
+static int __init cortina_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ u32 reg_v;
+
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = cortina_early_write;
+
+ /*
+ * If the bootloader did not enable the UART, initialise it here
+ * at 115200 baud so that early boot messages are not lost.
+ * The magic constant mirrors the reference BSP setting:
+ * CFG[31:8] = baud divisor for 115200, CFG[7] = UART_EN,
+ * CFG[6:5] = RX_EN|TX_EN, CFG[1:0] = 8-bit data.
+ */
+ reg_v = readl(device->port.membase + CFG);
+ if (!(reg_v & CFG_UART_EN)) {
+ writel(0x00043de3, device->port.membase + CFG);
+ writel(0x00043d / 2, device->port.membase + RX_SAMPLE);
+ }
+
+ return 0;
+}
+
+EARLYCON_DECLARE(ca_serial, cortina_early_console_setup);
+OF_EARLYCON_DECLARE(ca_serial, "cortina-access,serial",
+ cortina_early_console_setup);
+#else
+#define CORTINA_CONSOLE NULL
+#endif /* CONFIG_SERIAL_CORTINA_ACCESS_CONSOLE */
+
+static struct uart_driver cortina_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "cortina-access_uart",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = UART_NR,
+ .cons = CORTINA_CONSOLE,
+};
+
+/* Match table for of_platform binding */
+static const struct of_device_id cortina_uart_of_match[] = {
+ { .compatible = "cortina-access,serial" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cortina_uart_of_match);
+
+static int serial_cortina_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct cortina_uart_port *port;
+ struct resource *res;
+ struct clk *pclk_info;
+ int uart_idx;
+ int irq;
+ int ret;
+
+ if (!cortina_uart_ports) {
+ cortina_uart_ports = kcalloc(UART_NR, sizeof(*cortina_uart_ports),
+ GFP_KERNEL);
+ if (!cortina_uart_ports)
+ return -ENOMEM;
+ }
+
+ port = cortina_uart_ports;
+ for (uart_idx = 0; uart_idx < UART_NR; ++uart_idx) {
+ /* Find first empty slot */
+ if (strlen(port->name) == 0)
+ break;
+ port++;
+ }
+
+ if (uart_idx >= UART_NR)
+ return -ENODEV;
+
+ snprintf(port->name, sizeof(port->name),
+ "Cortina-Access UART%d", uart_idx);
+
+ /* Retrieve HW base address and reserve the I/O region */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ port->uart.mapbase = res->start;
+ port->uart.membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(port->uart.membase))
+ return PTR_ERR(port->uart.membase);
+
+ /* Retrieve IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ port->uart.irq = irq;
+
+ pclk_info = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(pclk_info)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ return PTR_ERR(pclk_info);
+ }
+
+ port->uart.uartclk = clk_get_rate(pclk_info);
+ port->uart.ops = &cortina_uart_ops;
+ port->uart.dev = &pdev->dev;
+ port->uart.line = uart_idx;
+ port->uart.iotype = UPIO_MEM32;
+ port->uart.type = 1;
+ port->uart.has_sysrq = IS_ENABLED(CONFIG_SERIAL_CORTINA_ACCESS_CONSOLE);
+
+ if (of_property_read_bool(np, "wakeup-source"))
+ port->may_wakeup = true;
+ if (of_property_read_bool(np, "break-indicator"))
+ port->has_bi = true;
+
+ if (port->may_wakeup)
+ device_init_wakeup(&pdev->dev, true);
+
+ ret = uart_add_one_port(&cortina_uart_driver, &port->uart);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, port);
+
+ return 0;
+}
+
+static void serial_cortina_remove(struct platform_device *pdev)
+{
+ struct cortina_uart_port *pca_port = platform_get_drvdata(pdev);
+
+ if (pca_port) {
+ memset(pca_port->name, 0, CA_UART_NAME_LEN);
+ uart_remove_one_port(&cortina_uart_driver, &pca_port->uart);
+ }
+
+ platform_set_drvdata(pdev, NULL);
+
+ /*
+ * Free the port array when the last port is removed, i.e. when
+ * all slots are empty again.
+ */
+ if (cortina_uart_ports) {
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ if (strlen(cortina_uart_ports[i].name) != 0)
+ return;
+ }
+ kfree(cortina_uart_ports);
+ cortina_uart_ports = NULL;
+ }
+}
+
+#ifdef CONFIG_PM
+static int serial_cortina_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct cortina_uart_port *p = platform_get_drvdata(pdev);
+
+ uart_suspend_port(&cortina_uart_driver, &p->uart);
+
+ return 0;
+}
+
+static int serial_cortina_resume(struct platform_device *pdev)
+{
+ struct cortina_uart_port *p = platform_get_drvdata(pdev);
+
+ uart_resume_port(&cortina_uart_driver, &p->uart);
+
+ return 0;
+}
+#else
+#define serial_cortina_suspend NULL
+#define serial_cortina_resume NULL
+#endif
+
+static struct platform_driver serial_cortina_driver = {
+ .probe = serial_cortina_probe,
+ .remove = serial_cortina_remove,
+#ifdef CONFIG_PM
+ .suspend = serial_cortina_suspend,
+ .resume = serial_cortina_resume,
+#endif
+ .driver = {
+ .name = "cortina-access_serial",
+ .of_match_table = cortina_uart_of_match,
+ },
+};
+
+static int __init cortina_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&cortina_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&serial_cortina_driver);
+ if (ret)
+ uart_unregister_driver(&cortina_uart_driver);
+
+ return ret;
+}
+
+static void __exit cortina_uart_exit(void)
+{
+ platform_driver_unregister(&serial_cortina_driver);
+ uart_unregister_driver(&cortina_uart_driver);
+}
+
+module_init(cortina_uart_init);
+module_exit(cortina_uart_exit);
+
+MODULE_AUTHOR("Cortina-Access Inc.");
+MODULE_DESCRIPTION("Cortina-Access UART driver");
+MODULE_LICENSE("GPL");
--
2.39.5
^ permalink raw reply related
* [PATCH 1/3] dt-bindings: serial: Add binding for Cortina-Access UART
From: Jason Li @ 2026-06-10 11:28 UTC (permalink / raw)
To: jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-1-jason.li@cortina-access.com>
Add DT binding schema for the Cortina-Access UART controller.
This IP is integrated into most CAXXXX SoC family members.
Also add the vendor prefix for Cortina Access, Inc. and the
top-level ARM board binding document for the CA8289 (Venus) SoC.
Signed-off-by: Jason Li <jason.li@cortina-access.com>
Assisted-by: Claude:claude-opus-4-8
---
.../bindings/arm/cortina-access.yaml | 29 ++++++++++++
.../serial/cortina-access,serial.yaml | 46 +++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 7 +++
4 files changed, 84 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cortina-access.yaml
create mode 100644 Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
diff --git a/Documentation/devicetree/bindings/arm/cortina-access.yaml b/Documentation/devicetree/bindings/arm/cortina-access.yaml
new file mode 100644
index 000000000000..ec0320ed0c0b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/cortina-access.yaml
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/cortina-access.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cortina-Access SoC boards
+
+maintainers:
+ - Jason Li <jason.li@cortina-access.com>
+
+description:
+ Boards based on Cortina-Access ARMv8 SoCs targeting networking and
+ access applications.
+
+properties:
+ $nodename:
+ const: /
+ compatible:
+ oneOf:
+ - description: Cortina-Access CA8289 (Venus) engineering board
+ const: cortina-access,ca8289-engboard
+
+ - description: Cortina-Access CA8289 (Venus) reference board
+ const: cortina-access,ca8289-refboard
+
+additionalProperties: true
+
+...
diff --git a/Documentation/devicetree/bindings/serial/cortina-access,serial.yaml b/Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
new file mode 100644
index 000000000000..5d7fdd954491
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/cortina-access,serial.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cortina-Access UART controller
+
+maintainers:
+ - Jason Li <jason.li@cortina-access.com>
+
+allOf:
+ - $ref: serial.yaml#
+
+properties:
+ compatible:
+ const: cortina-access,serial
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ serial@f4329188 {
+ compatible = "cortina-access,serial";
+ reg = <0 0xf4329188 0 0x30>;
+ interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb_pclk>;
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index dd94c50e97f9..837e2a92e7e8 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -367,6 +367,8 @@ patternProperties:
description: Chengdu Corpro Technology Co., Ltd.
"^corechips,.*":
description: Shenzhen Corechips Microelectronics Co., Ltd.
+ "^cortina-access,.*":
+ description: Cortina Access, Inc.
"^cortina,.*":
description: Cortina Systems, Inc.
"^cosmic,.*":
diff --git a/MAINTAINERS b/MAINTAINERS
index 20bd55913b2d..cc261888fae0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2820,6 +2820,13 @@ F: tools/perf/tests/shell/lib/*coresight*
F: tools/perf/util/cs-etm-decoder/*
F: tools/perf/util/cs-etm.*
+ARM/CORTINA-ACCESS VENUS ARM ARCHITECTURE
+M: Jason Li <jason.li@cortina-access.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/arm/cortina-access.yaml
+F: Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
+
ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
M: Linus Walleij <linusw@kernel.org>
--
2.39.5
^ permalink raw reply related
* [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and platform support
From: Jason Li @ 2026-06-10 11:28 UTC (permalink / raw)
To: jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
In-Reply-To: <20260610112821.3030099-1-jason.li@cortina-access.com>
This series adds Linux kernel support for the UART controller integrated
in Cortina-Access SoCs, with CA8289 (Venus) as the first supported device.
Patch 1 adds the DT binding schema for the UART controller and the
top-level ARM board binding document for the Cortina-Access SoC family,
along with the vendor prefix.
Patch 2 introduces the serial driver (serial_cortina-access.c). The
UART IP has a simple FIFO-based design with a single interrupt line.
The driver uses uart_port_tx() for TX, handles earlycon initialisation
when the bootloader leaves the UART disabled, and provides a TX FIFO
kick-start in start_tx() to work around edge-triggered interrupt
behaviour. Clock frequency is obtained exclusively via the clk
framework.
Patch 3 adds the device tree sources for the CA8289 SoC and its
engineering board, covering the minimal hardware description needed to
boot a kernel with an INITRD rootfs.
Tested on CA8289 engineering board; console and earlycon both verified
at 115200 baud.
Jason Li (3):
dt-bindings: serial: Add binding for Cortina-Access UART
tty: serial: Add UART driver for Cortina-Access platform
arm64: dts: cortina-access: Add DTS for CA8289 SoC and Venus board
.../bindings/arm/cortina-access.yaml | 29 +
.../serial/cortina-access,serial.yaml | 46 ++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 14 +
arch/arm64/Kconfig.platforms | 10 +
arch/arm64/boot/dts/Makefile | 1 +
arch/arm64/boot/dts/cortina-access/Makefile | 2 +
.../dts/cortina-access/ca8289-engboard.dts | 31 +
.../boot/dts/cortina-access/ca8289-soc.dtsi | 118 +++
drivers/tty/serial/Kconfig | 21 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/serial_cortina-access.c | 755 ++++++++++++++++++
12 files changed, 1030 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cortina-access.yaml
create mode 100644 Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
create mode 100644 arch/arm64/boot/dts/cortina-access/Makefile
create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
create mode 100644 drivers/tty/serial/serial_cortina-access.c
--
2.39.5
^ permalink raw reply
* [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and platform support
From: Jason Li @ 2026-06-10 11:28 UTC (permalink / raw)
To: jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, Arnd Bergmann, linux-serial, linux-arm-kernel,
devicetree, linux-kernel
Patch 1 adds the DT binding schema for the UART controller and the
top-level ARM board binding document for the Cortina-Access SoC family,
along with the vendor prefix.
Patch 2 introduces the serial driver (serial_cortina-access.c). The
UART IP has a simple FIFO-based design with a single interrupt line.
The driver uses uart_port_tx() for TX, handles earlycon initialisation
when the bootloader leaves the UART disabled, and provides a TX FIFO
kick-start in start_tx() to work around edge-triggered interrupt
behaviour. Clock frequency is obtained exclusively via the clk
framework.
Patch 3 adds the device tree sources for the CA8289 SoC and its
engineering board, covering the minimal hardware description needed to
boot a kernel with an INITRD rootfs.
Tested on CA8289 engineering board; console and earlycon both verified
at 115200 baud.
Any feedback or comments are highly appreciated.
Jason Li (3):
dt-bindings: serial: Add binding for Cortina-Access UART
tty: serial: Add UART driver for Cortina-Access platform
arm64: dts: cortina-access: Add DTS for CA8289 SoC and Venus board
.../bindings/arm/cortina-access.yaml | 29 +
.../serial/cortina-access,serial.yaml | 46 ++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 14 +
arch/arm64/Kconfig.platforms | 10 +
arch/arm64/boot/dts/Makefile | 1 +
arch/arm64/boot/dts/cortina-access/Makefile | 2 +
.../dts/cortina-access/ca8289-engboard.dts | 31 +
.../boot/dts/cortina-access/ca8289-soc.dtsi | 118 +++
drivers/tty/serial/Kconfig | 21 +
drivers/tty/serial/Makefile | 1 +
drivers/tty/serial/serial_cortina-access.c | 755 ++++++++++++++++++
12 files changed, 1030 insertions(+)
create mode 100644 Documentation/devicetree/bindings/arm/cortina-access.yaml
create mode 100644 Documentation/devicetree/bindings/serial/cortina-access,serial.yaml
create mode 100644 arch/arm64/boot/dts/cortina-access/Makefile
create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-engboard.dts
create mode 100644 arch/arm64/boot/dts/cortina-access/ca8289-soc.dtsi
create mode 100644 drivers/tty/serial/serial_cortina-access.c
--
2.39.5
^ permalink raw reply
* Re: [PATCHv2 1/4] serial: mxs-auart: fix cast type for of_device_get_match_data
From: Rosen Penev @ 2026-06-10 6:06 UTC (permalink / raw)
To: Frank Li
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <aii6RX0321fJV99W@SMW015318>
On Tue, Jun 9, 2026 at 6:13 PM Frank Li <Frank.li@oss.nxp.com> wrote:
>
> On Tue, Jun 09, 2026 at 03:37:14PM -0700, Rosen Penev wrote:
> > of_device_get_match_data returns const void*. Cast to unsigned long to
> > avoid implicit integer truncation warnings. All the data parameters are
> > correct anyway.
>
> It is not worth to fix it by this ways. cast void * to int/long is not good
> at all.
It's just a compilation fix. The same solution is used in many other places.
>
> struct drvdata
> {
> enum mxs_auart_type type;
> }
>
> static const struct drvata chip_imx28;
>
> &chip_imx28 as drv data.
That's a lot of work just to avoid a cast.
>
> Frank
> >
> > Assisted-by: opencode:big-pickle
> > Signed-off-by: Rosen Penev <rosenp@gmail.com>
> > ---
> > drivers/tty/serial/mxs-auart.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> > index 697318dbb146..de97c0f74e7d 100644
> > --- a/drivers/tty/serial/mxs-auart.c
> > +++ b/drivers/tty/serial/mxs-auart.c
> > @@ -1598,7 +1598,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
> > return -EINVAL;
> > }
> >
> > - s->devtype = (enum mxs_auart_type)of_device_get_match_data(&pdev->dev);
> > + s->devtype = (unsigned long)of_device_get_match_data(&pdev->dev);
> >
> > ret = mxs_get_clks(s, pdev);
> > if (ret)
> > --
> > 2.54.0
> >
> >
^ permalink raw reply
* [PATCH] serial: 8250: force synchronous probe for the ISA and PNP drivers
From: Rahul Bukte @ 2026-06-10 5:41 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Ilpo Järvinen, Shashank Balaji, Daniel Palmer, linux-serial,
linux-kernel, Rahul Bukte
On x86_64 defconfig, booting with driver_async_probe=serial hangs in early
init. The 8250 PNP driver is put onto the async probe pool.
serial8250_register_8250_port() runs in a kworker concurrently with the
ISA registration done from the serial8250_init() initcall resulting in a
deadlock or NULL dereference.
- Deadlock: serial_core_register_port() holds port_mutex across
serial_core_add_one_port()
uart_configure_port()
autoconfig_irq()
probe_irq_on()
async_synchronize_full(),
which waits for the async probe pool to drain.
The async PNP worker reaches the "port already in use" check and
tries to unregister it.
serial8250_register_8250_port()
uart_remove_one_port()
serial_core_unregister_port()
This blocks on port_mutex.
The init thread waits for the worker and the worker waits for the
init thread.
- NULL deref: when the worker instead observes a slot whose port.dev
is set but whose port_dev has not yet been populated, it hits the
null pointer on the call to serial_core_get_ctrl_dev() in
serial_core_unregister_port().
Signed-off-by: Rahul Bukte <rahul.bukte@sony.com>
---
Found while experimenting with driver_async_probe=* to improve boot time.
Tested on x86_64 defconfig under QEMU + KVM with driver_async_probe=serial.
drivers/tty/serial/8250/8250_platform.c | 1 +
drivers/tty/serial/8250/8250_pnp.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c
index ad3a7bc31d6f..af946d12e764 100644
--- a/drivers/tty/serial/8250/8250_platform.c
+++ b/drivers/tty/serial/8250/8250_platform.c
@@ -284,6 +284,7 @@ static struct platform_driver serial8250_isa_driver = {
.driver = {
.name = "serial8250",
.acpi_match_table = acpi_platform_serial_table,
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
},
};
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 7a837fdf9df1..3f41a9d6cb27 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -521,6 +521,7 @@ static struct pnp_driver serial_pnp_driver = {
.remove = serial_pnp_remove,
.driver = {
.pm = pm_sleep_ptr(&serial_pnp_pm_ops),
+ .probe_type = PROBE_FORCE_SYNCHRONOUS,
},
.id_table = pnp_dev_table,
};
base-commit: eb3f4b7426cfd2b79d65b7d37155480b32259a11
--
2.43.0
^ permalink raw reply related
* Re: [PATCHv2 4/4] serial: mxs-auart: fix IRQ registration ordering and manage console clock
From: Frank Li @ 2026-06-10 1:32 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260609223717.41670-5-rosenp@gmail.com>
On Tue, Jun 09, 2026 at 03:37:17PM -0700, Rosen Penev wrote:
> Move the main UART IRQ registration after uart_add_one_port so that
> s->port.state and s->port.lock are initialized before the interrupt
> handler can run. Mask all UART interrupts before adding the port to
> prevent spurious IRQs left by the bootloader.
Please use seperate patch to this problem only.
Frank
>
> After probe succeeds, disable the module clock for non-console ports
> since startup will re-enable it on port open. For console ports, keep
> the clock prepared so auart_console_write() can safely call
> clk_enable() from atomic context.
>
> Guard the IRQ handler and get_mctrl with clk_enable/clk_disable since
> GPIO IRQs and serial-core status queries can fire while the clock is
> disabled for non-console ports.
>
> In remove, disable the clock for console ports to balance the enable
> done in probe, preventing a clock leak on unbind.
>
> Assisted-by: opencode:big-pickle
> ---
> drivers/tty/serial/mxs-auart.c | 49 +++++++++++++++++++++++++++-------
> 1 file changed, 39 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index 4499e3206e85..e2b656638ab3 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -738,9 +738,13 @@ static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl)
> static u32 mxs_auart_get_mctrl(struct uart_port *u)
> {
> struct mxs_auart_port *s = to_auart_port(u);
> - u32 stat = mxs_read(s, REG_STAT);
> + u32 stat;
> u32 mctrl = 0;
>
> + clk_enable(s->clk);
> + stat = mxs_read(s, REG_STAT);
> + clk_disable(s->clk);
> +
> if (stat & AUART_STAT_CTS)
> mctrl |= TIOCM_CTS;
>
> @@ -1079,6 +1083,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
> struct mxs_auart_port *s = context;
> u32 mctrl_temp = s->mctrl_prev;
>
> + clk_enable(s->clk);
> uart_port_lock(&s->port);
>
> stat = mxs_read(s, REG_STAT);
> @@ -1118,6 +1123,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
> }
>
> uart_port_unlock(&s->port);
> + clk_disable(s->clk);
>
> return IRQ_HANDLED;
> }
> @@ -1603,10 +1609,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
> }
>
> s->port.irq = irq;
> - ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
> - dev_name(&pdev->dev), s);
> - if (ret)
> - goto out_disable_clk;
>
> platform_set_drvdata(pdev, s);
>
> @@ -1627,9 +1629,28 @@ static int mxs_auart_probe(struct platform_device *pdev)
>
> mxs_auart_reset_deassert(s);
>
> + /* Mask all UART interrupts to prevent spurious IRQs from bootloader */
> + mxs_write(0, s, REG_INTR);
> +
> ret = uart_add_one_port(&auart_driver, &s->port);
> - if (ret)
> - goto out_free_qpio_irq;
> + if (ret) {
> + auart_port[s->port.line] = NULL;
> + goto out_disable_clk;
> + }
> +
> + /*
> + * Request the main IRQ after uart_add_one_port so that
> + * s->port.state and s->port.lock are initialized before
> + * the handler can run in response to a bootloader-left
> + * interrupt.
> + */
> + ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
> + dev_name(&pdev->dev), s);
> + if (ret) {
> + uart_remove_one_port(&auart_driver, &s->port);
> + auart_port[s->port.line] = NULL;
> + goto out_disable_clk;
> + }
>
> /* ASM9260 don't have version reg */
> if (is_asm9260_auart(s)) {
> @@ -1641,10 +1662,16 @@ static int mxs_auart_probe(struct platform_device *pdev)
> (version >> 16) & 0xff, version & 0xffff);
> }
>
> - return 0;
> + /*
> + * Disable clock -- startup will re-enable when the port is opened.
> + * For the console port the clock must stay prepared so that
> + * auart_console_write() can safely call clk_enable() from
> + * atomic context.
> + */
> + if (!uart_console(&s->port))
> + clk_disable_unprepare(s->clk);
>
> -out_free_qpio_irq:
> - auart_port[s->port.line] = NULL;
> + return 0;
>
> out_disable_clk:
> clk_disable_unprepare(s->clk);
> @@ -1657,6 +1684,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
>
> uart_remove_one_port(&auart_driver, &s->port);
> auart_port[s->port.line] = NULL;
> + if (uart_console(&s->port))
> + clk_disable_unprepare(s->clk);
> }
>
> static struct platform_driver mxs_auart_driver = {
> --
> 2.54.0
>
>
^ permalink raw reply
* Re: [PATCHv2 3/4] serial: mxs-auart: use devm resources for iomem and GPIO IRQs
From: Frank Li @ 2026-06-10 1:26 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260609223717.41670-4-rosenp@gmail.com>
On Tue, Jun 09, 2026 at 03:37:16PM -0700, Rosen Penev wrote:
> Replace platform_get_resource + ioremap with
> devm_platform_get_and_ioremap_resource and convert GPIO IRQ
> request_irq/free_irq to devm_request_irq. This eliminates the
> mxs_auart_free_gpio_irq function and its call sites, and the
> out_iounmap error label. Simplify the remove function accordingly.
as my said before, all function need add ()
Frank
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/tty/serial/mxs-auart.c | 53 +++++++---------------------------
> 1 file changed, 11 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index aa59a48bfad7..4499e3206e85 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -1517,15 +1517,6 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
> return 0;
> }
>
> -static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s)
> -{
> - enum mctrl_gpio_idx i;
> -
> - for (i = 0; i < UART_GPIO_MAX; i++)
> - if (s->gpio_irq[i] >= 0)
> - free_irq(s->gpio_irq[i], s);
> -}
> -
> static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
> {
> int *irq = s->gpio_irq;
> @@ -1537,21 +1528,13 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
> continue;
>
> irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
> - err = request_irq(irq[i], mxs_auart_irq_handle,
> - IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
> + err = devm_request_irq(s->dev, irq[i], mxs_auart_irq_handle,
> + IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
> if (err)
> dev_err(s->dev, "%s - Can't get %d irq\n",
> __func__, irq[i]);
> }
>
> - /*
> - * If something went wrong, rollback.
> - * Be careful: i may be unsigned.
> - */
> - while (err && (i-- > 0))
> - if (irq[i] >= 0)
> - free_irq(irq[i], s);
> -
> return err;
> }
>
> @@ -1596,18 +1579,12 @@ static int mxs_auart_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> - r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!r) {
> - ret = -ENXIO;
> + s->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
> + if (IS_ERR(s->port.membase)) {
> + ret = PTR_ERR(s->port.membase);
> goto out_disable_clk;
> }
> -
> s->port.mapbase = r->start;
> - s->port.membase = ioremap(r->start, resource_size(r));
> - if (!s->port.membase) {
> - ret = -ENOMEM;
> - goto out_disable_clk;
> - }
> s->port.ops = &mxs_auart_ops;
> s->port.iotype = UPIO_MEM;
> s->port.fifosize = MXS_AUART_FIFO_SIZE;
> @@ -1622,21 +1599,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
> irq = platform_get_irq(pdev, 0);
> if (irq < 0) {
> ret = irq;
> - goto out_iounmap;
> + goto out_disable_clk;
> }
>
> s->port.irq = irq;
> ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
> dev_name(&pdev->dev), s);
> if (ret)
> - goto out_iounmap;
> + goto out_disable_clk;
>
> platform_set_drvdata(pdev, s);
>
> ret = mxs_auart_init_gpios(s, &pdev->dev);
> if (ret) {
> dev_err(&pdev->dev, "Failed to initialize GPIOs.\n");
> - goto out_iounmap;
> + goto out_disable_clk;
> }
>
> /*
> @@ -1644,7 +1621,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
> */
> ret = mxs_auart_request_gpio_irq(s);
> if (ret)
> - goto out_iounmap;
> + goto out_disable_clk;
>
> auart_port[s->port.line] = s;
>
> @@ -1667,11 +1644,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
> return 0;
>
> out_free_qpio_irq:
> - mxs_auart_free_gpio_irq(s);
> - auart_port[pdev->id] = NULL;
> -
> -out_iounmap:
> - iounmap(s->port.membase);
> + auart_port[s->port.line] = NULL;
>
> out_disable_clk:
> clk_disable_unprepare(s->clk);
> @@ -1683,11 +1656,7 @@ static void mxs_auart_remove(struct platform_device *pdev)
> struct mxs_auart_port *s = platform_get_drvdata(pdev);
>
> uart_remove_one_port(&auart_driver, &s->port);
> - auart_port[pdev->id] = NULL;
> - mxs_auart_free_gpio_irq(s);
> - iounmap(s->port.membase);
> - if (is_asm9260_auart(s))
> - clk_disable_unprepare(s->clk);
> + auart_port[s->port.line] = NULL;
> }
>
> static struct platform_driver mxs_auart_driver = {
> --
> 2.54.0
>
>
^ permalink raw reply
* Re: [PATCHv2 2/4] serial: mxs-auart: rework clock handling in mxs_get_clks and probe
From: Frank Li @ 2026-06-10 1:24 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260609223717.41670-3-rosenp@gmail.com>
On Tue, Jun 09, 2026 at 03:37:15PM -0700, Rosen Penev wrote:
> Use devm_clk_get_enabled for the AHB clock so its enable/disable
> lifetime is managed by the driver model. Move the mod clock
> (clk) prepare_enable out of mxs_get_clks and into probe so that
> clk_set_rate is called while the clock is still disabled, avoiding
> CLK_SET_RATE_GATE failures. Clean up the error labels accordingly.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/tty/serial/mxs-auart.c | 47 ++++++++++++----------------------
> 1 file changed, 17 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index de97c0f74e7d..aa59a48bfad7 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -1470,34 +1470,22 @@ static int mxs_get_clks(struct mxs_auart_port *s,
> return PTR_ERR(s->clk);
> }
>
> - s->clk_ahb = devm_clk_get(s->dev, "ahb");
> + s->clk_ahb = devm_clk_get_enabled(s->dev, "ahb");
> if (IS_ERR(s->clk_ahb)) {
> dev_err(s->dev, "Failed to get \"ahb\" clk\n");
> return PTR_ERR(s->clk_ahb);
> }
>
> - err = clk_prepare_enable(s->clk_ahb);
> - if (err) {
> - dev_err(s->dev, "Failed to enable ahb_clk!\n");
> - return err;
> - }
> -
> + /*
> + * Set mod clock rate while it is still disabled so
> + * CLK_SET_RATE_GATE does not cause clk_set_rate to fail.
> + * The mod clock will be enabled in mxs_auart_startup()
> + * and in probe after mxs_get_clks returns.
> + */
> err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
> - if (err) {
> + if (err)
> dev_err(s->dev, "Failed to set rate!\n");
> - goto disable_clk_ahb;
> - }
>
> - err = clk_prepare_enable(s->clk);
> - if (err) {
> - dev_err(s->dev, "Failed to enable clk!\n");
> - goto disable_clk_ahb;
> - }
> -
> - return 0;
> -
> -disable_clk_ahb:
> - clk_disable_unprepare(s->clk_ahb);
if I understand correct, after apply patch,
if (err)
dev_err(s->dev, ...)
return err;
Perfer method is
if (err)
return dev_err_probe(s->dev, err, ...);
return 0;
Frank
> return err;
> }
>
> @@ -1604,17 +1592,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> + ret = clk_prepare_enable(s->clk);
> + if (ret)
> + return ret;
> +
> r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (!r) {
> ret = -ENXIO;
> - goto out_disable_clks;
> + goto out_disable_clk;
> }
>
> s->port.mapbase = r->start;
> s->port.membase = ioremap(r->start, resource_size(r));
> if (!s->port.membase) {
> ret = -ENOMEM;
> - goto out_disable_clks;
> + goto out_disable_clk;
> }
> s->port.ops = &mxs_auart_ops;
> s->port.iotype = UPIO_MEM;
> @@ -1681,11 +1673,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
> out_iounmap:
> iounmap(s->port.membase);
>
> -out_disable_clks:
> - if (is_asm9260_auart(s)) {
> - clk_disable_unprepare(s->clk);
> - clk_disable_unprepare(s->clk_ahb);
> - }
> +out_disable_clk:
> + clk_disable_unprepare(s->clk);
> return ret;
> }
>
> @@ -1697,10 +1686,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
> auart_port[pdev->id] = NULL;
> mxs_auart_free_gpio_irq(s);
> iounmap(s->port.membase);
> - if (is_asm9260_auart(s)) {
> + if (is_asm9260_auart(s))
> clk_disable_unprepare(s->clk);
> - clk_disable_unprepare(s->clk_ahb);
> - }
> }
>
> static struct platform_driver mxs_auart_driver = {
> --
> 2.54.0
>
>
^ permalink raw reply
* Re: [PATCHv2 1/4] serial: mxs-auart: fix cast type for of_device_get_match_data
From: Frank Li @ 2026-06-10 1:13 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260609223717.41670-2-rosenp@gmail.com>
On Tue, Jun 09, 2026 at 03:37:14PM -0700, Rosen Penev wrote:
> of_device_get_match_data returns const void*. Cast to unsigned long to
> avoid implicit integer truncation warnings. All the data parameters are
> correct anyway.
It is not worth to fix it by this ways. cast void * to int/long is not good
at all.
struct drvdata
{
enum mxs_auart_type type;
}
static const struct drvata chip_imx28;
&chip_imx28 as drv data.
Frank
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/tty/serial/mxs-auart.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index 697318dbb146..de97c0f74e7d 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -1598,7 +1598,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
> return -EINVAL;
> }
>
> - s->devtype = (enum mxs_auart_type)of_device_get_match_data(&pdev->dev);
> + s->devtype = (unsigned long)of_device_get_match_data(&pdev->dev);
>
> ret = mxs_get_clks(s, pdev);
> if (ret)
> --
> 2.54.0
>
>
^ permalink raw reply
* [PATCHv2 4/4] serial: mxs-auart: fix IRQ registration ordering and manage console clock
From: Rosen Penev @ 2026-06-09 22:37 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260609223717.41670-1-rosenp@gmail.com>
Move the main UART IRQ registration after uart_add_one_port so that
s->port.state and s->port.lock are initialized before the interrupt
handler can run. Mask all UART interrupts before adding the port to
prevent spurious IRQs left by the bootloader.
After probe succeeds, disable the module clock for non-console ports
since startup will re-enable it on port open. For console ports, keep
the clock prepared so auart_console_write() can safely call
clk_enable() from atomic context.
Guard the IRQ handler and get_mctrl with clk_enable/clk_disable since
GPIO IRQs and serial-core status queries can fire while the clock is
disabled for non-console ports.
In remove, disable the clock for console ports to balance the enable
done in probe, preventing a clock leak on unbind.
Assisted-by: opencode:big-pickle
---
drivers/tty/serial/mxs-auart.c | 49 +++++++++++++++++++++++++++-------
1 file changed, 39 insertions(+), 10 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 4499e3206e85..e2b656638ab3 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -738,9 +738,13 @@ static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl)
static u32 mxs_auart_get_mctrl(struct uart_port *u)
{
struct mxs_auart_port *s = to_auart_port(u);
- u32 stat = mxs_read(s, REG_STAT);
+ u32 stat;
u32 mctrl = 0;
+ clk_enable(s->clk);
+ stat = mxs_read(s, REG_STAT);
+ clk_disable(s->clk);
+
if (stat & AUART_STAT_CTS)
mctrl |= TIOCM_CTS;
@@ -1079,6 +1083,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
struct mxs_auart_port *s = context;
u32 mctrl_temp = s->mctrl_prev;
+ clk_enable(s->clk);
uart_port_lock(&s->port);
stat = mxs_read(s, REG_STAT);
@@ -1118,6 +1123,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
}
uart_port_unlock(&s->port);
+ clk_disable(s->clk);
return IRQ_HANDLED;
}
@@ -1603,10 +1609,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
}
s->port.irq = irq;
- ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
- dev_name(&pdev->dev), s);
- if (ret)
- goto out_disable_clk;
platform_set_drvdata(pdev, s);
@@ -1627,9 +1629,28 @@ static int mxs_auart_probe(struct platform_device *pdev)
mxs_auart_reset_deassert(s);
+ /* Mask all UART interrupts to prevent spurious IRQs from bootloader */
+ mxs_write(0, s, REG_INTR);
+
ret = uart_add_one_port(&auart_driver, &s->port);
- if (ret)
- goto out_free_qpio_irq;
+ if (ret) {
+ auart_port[s->port.line] = NULL;
+ goto out_disable_clk;
+ }
+
+ /*
+ * Request the main IRQ after uart_add_one_port so that
+ * s->port.state and s->port.lock are initialized before
+ * the handler can run in response to a bootloader-left
+ * interrupt.
+ */
+ ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
+ dev_name(&pdev->dev), s);
+ if (ret) {
+ uart_remove_one_port(&auart_driver, &s->port);
+ auart_port[s->port.line] = NULL;
+ goto out_disable_clk;
+ }
/* ASM9260 don't have version reg */
if (is_asm9260_auart(s)) {
@@ -1641,10 +1662,16 @@ static int mxs_auart_probe(struct platform_device *pdev)
(version >> 16) & 0xff, version & 0xffff);
}
- return 0;
+ /*
+ * Disable clock -- startup will re-enable when the port is opened.
+ * For the console port the clock must stay prepared so that
+ * auart_console_write() can safely call clk_enable() from
+ * atomic context.
+ */
+ if (!uart_console(&s->port))
+ clk_disable_unprepare(s->clk);
-out_free_qpio_irq:
- auart_port[s->port.line] = NULL;
+ return 0;
out_disable_clk:
clk_disable_unprepare(s->clk);
@@ -1657,6 +1684,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
uart_remove_one_port(&auart_driver, &s->port);
auart_port[s->port.line] = NULL;
+ if (uart_console(&s->port))
+ clk_disable_unprepare(s->clk);
}
static struct platform_driver mxs_auart_driver = {
--
2.54.0
^ permalink raw reply related
* [PATCHv2 3/4] serial: mxs-auart: use devm resources for iomem and GPIO IRQs
From: Rosen Penev @ 2026-06-09 22:37 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260609223717.41670-1-rosenp@gmail.com>
Replace platform_get_resource + ioremap with
devm_platform_get_and_ioremap_resource and convert GPIO IRQ
request_irq/free_irq to devm_request_irq. This eliminates the
mxs_auart_free_gpio_irq function and its call sites, and the
out_iounmap error label. Simplify the remove function accordingly.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 53 +++++++---------------------------
1 file changed, 11 insertions(+), 42 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index aa59a48bfad7..4499e3206e85 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1517,15 +1517,6 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
return 0;
}
-static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s)
-{
- enum mctrl_gpio_idx i;
-
- for (i = 0; i < UART_GPIO_MAX; i++)
- if (s->gpio_irq[i] >= 0)
- free_irq(s->gpio_irq[i], s);
-}
-
static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
{
int *irq = s->gpio_irq;
@@ -1537,21 +1528,13 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
continue;
irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
- err = request_irq(irq[i], mxs_auart_irq_handle,
- IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
+ err = devm_request_irq(s->dev, irq[i], mxs_auart_irq_handle,
+ IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
if (err)
dev_err(s->dev, "%s - Can't get %d irq\n",
__func__, irq[i]);
}
- /*
- * If something went wrong, rollback.
- * Be careful: i may be unsigned.
- */
- while (err && (i-- > 0))
- if (irq[i] >= 0)
- free_irq(irq[i], s);
-
return err;
}
@@ -1596,18 +1579,12 @@ static int mxs_auart_probe(struct platform_device *pdev)
if (ret)
return ret;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- ret = -ENXIO;
+ s->port.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
+ if (IS_ERR(s->port.membase)) {
+ ret = PTR_ERR(s->port.membase);
goto out_disable_clk;
}
-
s->port.mapbase = r->start;
- s->port.membase = ioremap(r->start, resource_size(r));
- if (!s->port.membase) {
- ret = -ENOMEM;
- goto out_disable_clk;
- }
s->port.ops = &mxs_auart_ops;
s->port.iotype = UPIO_MEM;
s->port.fifosize = MXS_AUART_FIFO_SIZE;
@@ -1622,21 +1599,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto out_iounmap;
+ goto out_disable_clk;
}
s->port.irq = irq;
ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
dev_name(&pdev->dev), s);
if (ret)
- goto out_iounmap;
+ goto out_disable_clk;
platform_set_drvdata(pdev, s);
ret = mxs_auart_init_gpios(s, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize GPIOs.\n");
- goto out_iounmap;
+ goto out_disable_clk;
}
/*
@@ -1644,7 +1621,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
*/
ret = mxs_auart_request_gpio_irq(s);
if (ret)
- goto out_iounmap;
+ goto out_disable_clk;
auart_port[s->port.line] = s;
@@ -1667,11 +1644,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
return 0;
out_free_qpio_irq:
- mxs_auart_free_gpio_irq(s);
- auart_port[pdev->id] = NULL;
-
-out_iounmap:
- iounmap(s->port.membase);
+ auart_port[s->port.line] = NULL;
out_disable_clk:
clk_disable_unprepare(s->clk);
@@ -1683,11 +1656,7 @@ static void mxs_auart_remove(struct platform_device *pdev)
struct mxs_auart_port *s = platform_get_drvdata(pdev);
uart_remove_one_port(&auart_driver, &s->port);
- auart_port[pdev->id] = NULL;
- mxs_auart_free_gpio_irq(s);
- iounmap(s->port.membase);
- if (is_asm9260_auart(s))
- clk_disable_unprepare(s->clk);
+ auart_port[s->port.line] = NULL;
}
static struct platform_driver mxs_auart_driver = {
--
2.54.0
^ permalink raw reply related
* [PATCHv2 2/4] serial: mxs-auart: rework clock handling in mxs_get_clks and probe
From: Rosen Penev @ 2026-06-09 22:37 UTC (permalink / raw)
To: linux-serial
Cc: Greg Kroah-Hartman, Jiri Slaby, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:TTY LAYER AND SERIAL DRIVERS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20260609223717.41670-1-rosenp@gmail.com>
Use devm_clk_get_enabled for the AHB clock so its enable/disable
lifetime is managed by the driver model. Move the mod clock
(clk) prepare_enable out of mxs_get_clks and into probe so that
clk_set_rate is called while the clock is still disabled, avoiding
CLK_SET_RATE_GATE failures. Clean up the error labels accordingly.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/tty/serial/mxs-auart.c | 47 ++++++++++++----------------------
1 file changed, 17 insertions(+), 30 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index de97c0f74e7d..aa59a48bfad7 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -1470,34 +1470,22 @@ static int mxs_get_clks(struct mxs_auart_port *s,
return PTR_ERR(s->clk);
}
- s->clk_ahb = devm_clk_get(s->dev, "ahb");
+ s->clk_ahb = devm_clk_get_enabled(s->dev, "ahb");
if (IS_ERR(s->clk_ahb)) {
dev_err(s->dev, "Failed to get \"ahb\" clk\n");
return PTR_ERR(s->clk_ahb);
}
- err = clk_prepare_enable(s->clk_ahb);
- if (err) {
- dev_err(s->dev, "Failed to enable ahb_clk!\n");
- return err;
- }
-
+ /*
+ * Set mod clock rate while it is still disabled so
+ * CLK_SET_RATE_GATE does not cause clk_set_rate to fail.
+ * The mod clock will be enabled in mxs_auart_startup()
+ * and in probe after mxs_get_clks returns.
+ */
err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
- if (err) {
+ if (err)
dev_err(s->dev, "Failed to set rate!\n");
- goto disable_clk_ahb;
- }
- err = clk_prepare_enable(s->clk);
- if (err) {
- dev_err(s->dev, "Failed to enable clk!\n");
- goto disable_clk_ahb;
- }
-
- return 0;
-
-disable_clk_ahb:
- clk_disable_unprepare(s->clk_ahb);
return err;
}
@@ -1604,17 +1592,21 @@ static int mxs_auart_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = clk_prepare_enable(s->clk);
+ if (ret)
+ return ret;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
ret = -ENXIO;
- goto out_disable_clks;
+ goto out_disable_clk;
}
s->port.mapbase = r->start;
s->port.membase = ioremap(r->start, resource_size(r));
if (!s->port.membase) {
ret = -ENOMEM;
- goto out_disable_clks;
+ goto out_disable_clk;
}
s->port.ops = &mxs_auart_ops;
s->port.iotype = UPIO_MEM;
@@ -1681,11 +1673,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
out_iounmap:
iounmap(s->port.membase);
-out_disable_clks:
- if (is_asm9260_auart(s)) {
- clk_disable_unprepare(s->clk);
- clk_disable_unprepare(s->clk_ahb);
- }
+out_disable_clk:
+ clk_disable_unprepare(s->clk);
return ret;
}
@@ -1697,10 +1686,8 @@ static void mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL;
mxs_auart_free_gpio_irq(s);
iounmap(s->port.membase);
- if (is_asm9260_auart(s)) {
+ if (is_asm9260_auart(s))
clk_disable_unprepare(s->clk);
- clk_disable_unprepare(s->clk_ahb);
- }
}
static struct platform_driver mxs_auart_driver = {
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox