From: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
Add optional clock 'ipg' and 'lin' support to NXP LINFlexD UART driver,
which is used by S32G2 and S32G3 SoCs.
LINFlex driver should perform clock management and not rely on a previous
bootloader configuration.
Clocking support is added as optional in order to not break existing
support for S32V234 SoC. Therefore, there should be no impact if not
providing LINFlexD clocks and continue to rely on a bootloader clock
configuration and enablement.
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 95 ++++++++++++++++++++++++----
1 file changed, 81 insertions(+), 14 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index e972df4b188d..394c2f66d4a2 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -3,9 +3,10 @@
* Freescale LINFlexD UART serial port driver
*
* Copyright 2012-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2019 NXP
+ * Copyright 2017-2019, 2024 NXP
*/
+#include <linux/clk.h>
#include <linux/console.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -120,9 +121,29 @@
#define PREINIT_DELAY 2000 /* us */
+struct linflex_devtype_data {
+ const char * const *clks_names;
+ int n_clks;
+};
+
+struct linflex_port {
+ struct uart_port port;
+ struct clk_bulk_data *clks;
+ const struct linflex_devtype_data *devtype_data;
+};
+
+static const char * const s32v234_clk_names[] = {
+ "ipg", "lin",
+};
+
+static const struct linflex_devtype_data s32v234_data = {
+ .clks_names = s32v234_clk_names,
+ .n_clks = ARRAY_SIZE(s32v234_clk_names),
+};
+
static const struct of_device_id linflex_dt_ids[] = {
{
- .compatible = "fsl,s32v234-linflexuart",
+ .compatible = "fsl,s32v234-linflexuart", .data = &s32v234_data,
},
{ /* sentinel */ }
};
@@ -776,6 +797,14 @@ static void linflex_earlycon_write(struct console *con, const char *s,
uart_console_write(&dev->port, s, n, linflex_earlycon_putchar);
}
+static void linflex_disable_clks(void *data)
+{
+ struct linflex_port *lfport = data;
+
+ clk_bulk_disable_unprepare(lfport->devtype_data->n_clks,
+ lfport->clks);
+}
+
static int __init linflex_early_console_setup(struct earlycon_device *device,
const char *options)
{
@@ -807,12 +836,13 @@ static struct uart_driver linflex_reg = {
static int linflex_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct linflex_port *lfport;
struct uart_port *sport;
struct resource *res;
- int ret;
+ int i, ret;
- sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
- if (!sport)
+ lfport = devm_kzalloc(&pdev->dev, sizeof(*lfport), GFP_KERNEL);
+ if (!lfport)
return -ENOMEM;
ret = of_alias_get_id(np, "serial");
@@ -826,8 +856,14 @@ static int linflex_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ sport = &lfport->port;
sport->line = ret;
+ lfport->devtype_data = of_device_get_match_data(&pdev->dev);
+ if (!lfport->devtype_data)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "Failed to get linflexuart driver data\n");
+
sport->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(sport->membase))
return PTR_ERR(sport->membase);
@@ -844,37 +880,68 @@ static int linflex_probe(struct platform_device *pdev)
sport->flags = UPF_BOOT_AUTOCONF;
sport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE);
- linflex_ports[sport->line] = sport;
+ lfport->clks = devm_kmalloc_array(&pdev->dev, lfport->devtype_data->n_clks,
+ sizeof(*lfport->clks), GFP_KERNEL);
+ if (!lfport->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < lfport->devtype_data->n_clks; i++)
+ lfport->clks[i].id = lfport->devtype_data->clks_names[i];
+
+ ret = devm_clk_bulk_get_optional(&pdev->dev,
+ lfport->devtype_data->n_clks, lfport->clks);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to get linflexuart clocks\n");
- platform_set_drvdata(pdev, sport);
+ ret = clk_bulk_prepare_enable(lfport->devtype_data->n_clks,
+ lfport->clks);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to enable linflexuart clocks\n");
+
+ ret = devm_add_action_or_reset(&pdev->dev,
+ linflex_disable_clks, lfport);
+ if (ret)
+ return ret;
+
+ linflex_ports[sport->line] = sport;
+ platform_set_drvdata(pdev, lfport);
return uart_add_one_port(&linflex_reg, sport);
}
static void linflex_remove(struct platform_device *pdev)
{
- struct uart_port *sport = platform_get_drvdata(pdev);
+ struct linflex_port *lfport = platform_get_drvdata(pdev);
- uart_remove_one_port(&linflex_reg, sport);
+ uart_remove_one_port(&linflex_reg, &lfport->port);
}
#ifdef CONFIG_PM_SLEEP
static int linflex_suspend(struct device *dev)
{
- struct uart_port *sport = dev_get_drvdata(dev);
+ struct linflex_port *lfport = dev_get_drvdata(dev);
- uart_suspend_port(&linflex_reg, sport);
+ uart_suspend_port(&linflex_reg, &lfport->port);
+
+ clk_bulk_disable_unprepare(lfport->devtype_data->n_clks,
+ lfport->clks);
return 0;
}
static int linflex_resume(struct device *dev)
{
- struct uart_port *sport = dev_get_drvdata(dev);
+ struct linflex_port *lfport = dev_get_drvdata(dev);
+ int ret;
- uart_resume_port(&linflex_reg, sport);
+ ret = clk_bulk_prepare_enable(lfport->devtype_data->n_clks,
+ lfport->clks);
+ if (ret)
+ return ret;
- return 0;
+ return uart_resume_port(&linflex_reg, &lfport->port);
}
#endif
--
2.45.2
Hi Ciprian, kernel test robot noticed the following build errors: [auto build test ERROR on tty/tty-testing] [also build test ERROR on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus robh/for-next linus/master v6.12 next-20241121] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Ciprian-Costea/dt-bindings-serial-fsl-linflexuart-add-clock-definitions/20241121-130303 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing patch link: https://lore.kernel.org/r/20241118154449.3895692-3-ciprianmarian.costea%40oss.nxp.com patch subject: [PATCH v5 2/2] serial: fsl_linflexuart: add clock management config: arm64-randconfig-001-20241122 (https://download.01.org/0day-ci/archive/20241122/202411220621.UfubUV0X-lkp@intel.com/config) compiler: aarch64-linux-gcc (GCC) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241122/202411220621.UfubUV0X-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202411220621.UfubUV0X-lkp@intel.com/ All errors (new ones prefixed by >>): In file included from include/linux/platform_device.h:13, from drivers/tty/serial/fsl_linflexuart.c:15: drivers/tty/serial/fsl_linflexuart.c: In function 'linflex_probe': >> drivers/tty/serial/fsl_linflexuart.c:904:40: error: 'linflex_disable_clks' undeclared (first use in this function) 904 | linflex_disable_clks, lfport); | ^~~~~~~~~~~~~~~~~~~~ include/linux/device.h:421:41: note: in definition of macro 'devm_add_action_or_reset' 421 | __devm_add_action_or_reset(dev, action, data, #action) | ^~~~~~ drivers/tty/serial/fsl_linflexuart.c:904:40: note: each undeclared identifier is reported only once for each function it appears in 904 | linflex_disable_clks, lfport); | ^~~~~~~~~~~~~~~~~~~~ include/linux/device.h:421:41: note: in definition of macro 'devm_add_action_or_reset' 421 | __devm_add_action_or_reset(dev, action, data, #action) | ^~~~~~ vim +/linflex_disable_clks +904 drivers/tty/serial/fsl_linflexuart.c 835 836 static int linflex_probe(struct platform_device *pdev) 837 { 838 struct device_node *np = pdev->dev.of_node; 839 struct linflex_port *lfport; 840 struct uart_port *sport; 841 struct resource *res; 842 int i, ret; 843 844 lfport = devm_kzalloc(&pdev->dev, sizeof(*lfport), GFP_KERNEL); 845 if (!lfport) 846 return -ENOMEM; 847 848 ret = of_alias_get_id(np, "serial"); 849 if (ret < 0) { 850 dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); 851 return ret; 852 } 853 if (ret >= UART_NR) { 854 dev_err(&pdev->dev, "driver limited to %d serial ports\n", 855 UART_NR); 856 return -ENOMEM; 857 } 858 859 sport = &lfport->port; 860 sport->line = ret; 861 862 lfport->devtype_data = of_device_get_match_data(&pdev->dev); 863 if (!lfport->devtype_data) 864 return dev_err_probe(&pdev->dev, -ENODEV, 865 "Failed to get linflexuart driver data\n"); 866 867 sport->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 868 if (IS_ERR(sport->membase)) 869 return PTR_ERR(sport->membase); 870 sport->mapbase = res->start; 871 872 ret = platform_get_irq(pdev, 0); 873 if (ret < 0) 874 return ret; 875 876 sport->dev = &pdev->dev; 877 sport->iotype = UPIO_MEM; 878 sport->irq = ret; 879 sport->ops = &linflex_pops; 880 sport->flags = UPF_BOOT_AUTOCONF; 881 sport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE); 882 883 lfport->clks = devm_kmalloc_array(&pdev->dev, lfport->devtype_data->n_clks, 884 sizeof(*lfport->clks), GFP_KERNEL); 885 if (!lfport->clks) 886 return -ENOMEM; 887 888 for (i = 0; i < lfport->devtype_data->n_clks; i++) 889 lfport->clks[i].id = lfport->devtype_data->clks_names[i]; 890 891 ret = devm_clk_bulk_get_optional(&pdev->dev, 892 lfport->devtype_data->n_clks, lfport->clks); 893 if (ret) 894 return dev_err_probe(&pdev->dev, ret, 895 "Failed to get linflexuart clocks\n"); 896 897 ret = clk_bulk_prepare_enable(lfport->devtype_data->n_clks, 898 lfport->clks); 899 if (ret) 900 return dev_err_probe(&pdev->dev, ret, 901 "Failed to enable linflexuart clocks\n"); 902 903 ret = devm_add_action_or_reset(&pdev->dev, > 904 linflex_disable_clks, lfport); 905 if (ret) 906 return ret; 907 908 linflex_ports[sport->line] = sport; 909 platform_set_drvdata(pdev, lfport); 910 911 return uart_add_one_port(&linflex_reg, sport); 912 } 913 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2024 Red Hat, Inc.