The UART's input clock rate can change at runtime but this is not
handled by the driver.
Add a clock_notifier callback that updates the divisors when the input
clock is updated. The serial8250_update_uartclk() is used to do so.
PRE_RATE_CHANGE and ABORT_RATE_CHANGE notifications are ignored, only
the POST_RATE_CHANGE is used.
Reorder the #include to match alphabetic order.
It has been tested on a DAVINCI/OMAP-L138 processor.
Signed-off-by: Bastien Curutchet <[email protected]>
---
drivers/tty/serial/8250/8250_of.c | 48 ++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 5d1dd992d8fb..6d570164d906 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -6,18 +6,19 @@
*/
#include <linux/bits.h>
+#include <linux/clk.h>
#include <linux/console.h>
#include <linux/math.h>
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
+#include <linux/notifier.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
-#include <linux/clk.h>
#include <linux/reset.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
#include "8250.h"
@@ -26,6 +27,7 @@ struct of_serial_info {
struct reset_control *rst;
int type;
int line;
+ struct notifier_block clk_notifier;
};
/* Nuvoton NPCM timeout register */
@@ -58,6 +60,29 @@ static int npcm_setup(struct uart_port *port)
return 0;
}
+static inline struct of_serial_info *clk_nb_to_info(struct notifier_block *nb)
+{
+ return container_of(nb, struct of_serial_info, clk_notifier);
+}
+
+static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct of_serial_info *info = clk_nb_to_info(nb);
+ struct uart_8250_port *port8250 = serial8250_get_port(info->line);
+ struct clk_notifier_data *ndata = data;
+
+ if (IS_ERR(info->clk))
+ return NOTIFY_DONE;
+
+ if (event == POST_RATE_CHANGE) {
+ serial8250_update_uartclk(&port8250->port, ndata->new_rate);
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
/*
* Fill a struct uart_port for a given device node
*/
@@ -218,7 +243,19 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
info->type = port_type;
info->line = ret;
platform_set_drvdata(ofdev, info);
+
+ if (info->clk) {
+ info->clk_notifier.notifier_call = of_platform_serial_clk_notifier_cb;
+ ret = clk_notifier_register(info->clk, &info->clk_notifier);
+ if (ret) {
+ dev_err_probe(port8250.port.dev, ret, "Failed to set the clock notifier\n");
+ goto err_unregister;
+ }
+ }
+
return 0;
+err_unregister:
+ serial8250_unregister_port(info->line);
err_dispose:
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
@@ -234,6 +271,9 @@ static void of_platform_serial_remove(struct platform_device *ofdev)
{
struct of_serial_info *info = platform_get_drvdata(ofdev);
+ if (info->clk)
+ clk_notifier_unregister(info->clk, &info->clk_notifier);
+
serial8250_unregister_port(info->line);
reset_control_assert(info->rst);
--
2.44.0
On Thu, Apr 04, 2024 at 09:44:50AM +0200, Bastien Curutchet wrote:
> The UART's input clock rate can change at runtime but this is not
> handled by the driver.
>
> Add a clock_notifier callback that updates the divisors when the input
> clock is updated. The serial8250_update_uartclk() is used to do so.
> PRE_RATE_CHANGE and ABORT_RATE_CHANGE notifications are ignored, only
> the POST_RATE_CHANGE is used.
Why just this one notification? You say they are ignored but do not say
why.
>
> Reorder the #include to match alphabetic order.
That is not needed here, why do that now? And "alphabetic order" is not
an issue for tty drivers, no need to do that, but if you really want to,
a separate patch series is good for that.
thanks,
greg k-h
Hi Greg,
On 4/4/24 09:50, Greg Kroah-Hartman wrote:
> On Thu, Apr 04, 2024 at 09:44:50AM +0200, Bastien Curutchet wrote:
>> The UART's input clock rate can change at runtime but this is not
>> handled by the driver.
>>
>> Add a clock_notifier callback that updates the divisors when the input
>> clock is updated. The serial8250_update_uartclk() is used to do so.
>> PRE_RATE_CHANGE and ABORT_RATE_CHANGE notifications are ignored, only
>> the POST_RATE_CHANGE is used.
>
> Why just this one notification? You say they are ignored but do not say
> why.
>
I don't need to react to PRE_RATE_CHANGE in my use case. A few bytes may
be corrupted during the rate change but it is not a problem for my
application (and I assumed that it would also be ok in many other use
cases).
>>
>> Reorder the #include to match alphabetic order.
>
> That is not needed here, why do that now? And "alphabetic order" is not
> an issue for tty drivers, no need to do that, but if you really want to,
> a separate patch series is good for that.
Ok sorry, I thought it was needed, I'll remove this in next iteration.
Best regards,
Bastien
Hi Bastien,
On Thu, 4 Apr 2024 09:44:50 +0200
Bastien Curutchet <[email protected]> wrote:
> The UART's input clock rate can change at runtime but this is not
> handled by the driver.
>
> Add a clock_notifier callback that updates the divisors when the input
> clock is updated. The serial8250_update_uartclk() is used to do so.
> PRE_RATE_CHANGE and ABORT_RATE_CHANGE notifications are ignored, only
> the POST_RATE_CHANGE is used.
>
> Reorder the #include to match alphabetic order.
>
> It has been tested on a DAVINCI/OMAP-L138 processor.
>
> Signed-off-by: Bastien Curutchet <[email protected]>
..
> +static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
> + void *data)
> +{
> + struct of_serial_info *info = clk_nb_to_info(nb);
> + struct uart_8250_port *port8250 = serial8250_get_port(info->line);
> + struct clk_notifier_data *ndata = data;
> +
> + if (IS_ERR(info->clk))
> + return NOTIFY_DONE;
The info->clk pointer cannot contain an error code.
Can you double check that and remove the test if it is not needed?
Best regards,
Hervé