From c4a34953be5395777b5edef029b02eeaba481251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Sat, 22 Jul 2023 12:40:54 +0200 Subject: [PATCH] [WIP] Convert to a platform driver. This has a few advantages: (1) being able to use .fw_name instead of .anme to refer to clocks, which eliminates the need to set /clock-48mhz/clock-output-names = "ref" in the WPCM450 devicetree. (2) Being able to use devm_ functions to simplify/improve deallocation. --- drivers/clk/nuvoton/clk-wpcm450.c | 131 +++++++++++++++++------------- 1 file changed, 74 insertions(+), 57 deletions(-) diff --git a/drivers/clk/nuvoton/clk-wpcm450.c b/drivers/clk/nuvoton/clk-wpcm450.c index 9dee14d63e1d6a..0ab27c6895e7d5 100644 --- a/drivers/clk/nuvoton/clk-wpcm450.c +++ b/drivers/clk/nuvoton/clk-wpcm450.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include @@ -84,14 +86,14 @@ static const struct clk_ops wpcm450_clk_pll_ops = { }; static struct clk_hw * -wpcm450_clk_register_pll(void __iomem *pllcon, const char *name, +wpcm450_clk_register_pll(struct device *dev, void __iomem *pllcon, const char *name, const struct clk_parent_data *parent, unsigned long flags) { struct wpcm450_clk_pll *pll; struct clk_init_data init = {}; int ret; - pll = kzalloc(sizeof(*pll), GFP_KERNEL); + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); if (!pll) return ERR_PTR(-ENOMEM); @@ -104,9 +106,9 @@ wpcm450_clk_register_pll(void __iomem *pllcon, const char *name, pll->pllcon = pllcon; pll->hw.init = &init; - ret = clk_hw_register(NULL, &pll->hw); + ret = devm_clk_hw_register(dev, &pll->hw); if (ret) { - kfree(pll); + devm_kfree(dev, pll); return ERR_PTR(ret); } @@ -243,13 +245,7 @@ static const struct wpcm450_clken_data clken_data[] = { static DEFINE_SPINLOCK(wpcm450_clk_lock); -/* - * NOTE: Error handling is very rudimentary here. If the clock driver initial- - * ization fails, the system is probably in bigger trouble than what is caused - * by a few leaked resources. - */ - -static void __init wpcm450_clk_init(struct device_node *clk_np) +static int wpcm450_clk_probe(struct platform_device *pdev) { struct clk_hw_onecell_data *clk_data; static struct clk_hw **hws; @@ -257,18 +253,19 @@ static void __init wpcm450_clk_init(struct device_node *clk_np) void __iomem *clk_base; int i, ret; struct reset_simple_data *reset; - - clk_base = of_iomap(clk_np, 0); - if (!clk_base) { - pr_err("%pOFP: failed to map registers\n", clk_np); - of_node_put(clk_np); - return; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + resource_size_t map_size; + + clk_base = devm_of_iomap(dev, np, 0, &map_size); + if (IS_ERR(clk_base)) { + pr_err("%pOFP: failed to map registers\n", np); // TODO: check, dev_err + return PTR_ERR(clk_base); } - of_node_put(clk_np); - clk_data = kzalloc(struct_size(clk_data, hws, WPCM450_NUM_CLKS), GFP_KERNEL); + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, WPCM450_NUM_CLKS), GFP_KERNEL); if (!clk_data) - return; + return -ENOMEM; clk_data->num = WPCM450_NUM_CLKS; hws = clk_data->hws; @@ -280,11 +277,11 @@ static void __init wpcm450_clk_init(struct device_node *clk_np) for (i = 0; i < ARRAY_SIZE(pll_data); i++) { const struct wpcm450_pll_data *data = &pll_data[i]; - hw = wpcm450_clk_register_pll(clk_base + data->reg, data->name, + hw = wpcm450_clk_register_pll(dev, clk_base + data->reg, data->name, &data->parent, data->flags); if (IS_ERR(hw)) { pr_info("Failed to register PLL: %pe\n", hw); - return; + return PTR_ERR(hw); } } @@ -292,14 +289,15 @@ static void __init wpcm450_clk_init(struct device_node *clk_np) for (i = 0; i < ARRAY_SIZE(clkdiv_data_early); i++) { const struct wpcm450_clkdiv_data *data = &clkdiv_data_early[i]; - hw = clk_hw_register_divider_table_parent_data(NULL, data->name, &data->parent, - data->flags, clk_base + REG_CLKDIV, - data->shift, data->width, - data->div_flags, data->table, - &wpcm450_clk_lock); + hw = devm_clk_hw_register_divider_table_parent_data(dev, data->name, &data->parent, + data->flags, clk_base + REG_CLKDIV, + data->shift, data->width, + data->div_flags, data->table, + &wpcm450_clk_lock); + if (IS_ERR(hw)) { pr_err("Failed to register div table: %pe\n", hw); - return; + return PTR_ERR(hw); } } @@ -307,14 +305,15 @@ static void __init wpcm450_clk_init(struct device_node *clk_np) for (i = 0; i < ARRAY_SIZE(clksel_data); i++) { const struct wpcm450_clksel_data *data = &clksel_data[i]; - hw = clk_hw_register_mux_parent_data(NULL, data->name, data->parents, - data->num_parents, data->flags, - clk_base + REG_CLKSEL, data->shift, - data->width, 0, - &wpcm450_clk_lock); + hw = devm_clk_hw_register_mux_parent_data_table(dev, data->name, data->parents, + data->num_parents, data->flags, + clk_base + REG_CLKSEL, data->shift, + data->width, 0, NULL, + &wpcm450_clk_lock); + if (IS_ERR(hw)) { pr_err("Failed to register mux: %pe\n", hw); - return; + return PTR_ERR(hw); } if (data->index >= 0) clk_data->hws[data->index] = hw; @@ -324,14 +323,15 @@ static void __init wpcm450_clk_init(struct device_node *clk_np) for (i = 0; i < ARRAY_SIZE(clkdiv_data); i++) { const struct wpcm450_clkdiv_data *data = &clkdiv_data[i]; - hw = clk_hw_register_divider_table_parent_data(NULL, data->name, &data->parent, - data->flags, clk_base + REG_CLKDIV, - data->shift, data->width, - data->div_flags, data->table, - &wpcm450_clk_lock); + hw = devm_clk_hw_register_divider_table_parent_data(dev, data->name, &data->parent, + data->flags, clk_base + REG_CLKDIV, + data->shift, data->width, + data->div_flags, data->table, + &wpcm450_clk_lock); + if (IS_ERR(hw)) { pr_err("Failed to register divider: %pe\n", hw); - return; + return PTR_ERR(hw); } } @@ -339,34 +339,51 @@ static void __init wpcm450_clk_init(struct device_node *clk_np) for (i = 0; i < ARRAY_SIZE(clken_data); i++) { const struct wpcm450_clken_data *data = &clken_data[i]; - hw = clk_hw_register_gate_parent_data(NULL, data->name, &data->parent, data->flags, - clk_base + REG_CLKEN, data->bitnum, - data->flags, &wpcm450_clk_lock); + hw = devm_clk_hw_register_gate_parent_data(dev, data->name, &data->parent, data->flags, + clk_base + REG_CLKEN, data->bitnum, + data->flags, &wpcm450_clk_lock); if (IS_ERR(hw)) { pr_err("Failed to register gate: %pe\n", hw); - return; + return PTR_ERR(hw); } clk_data->hws[data->bitnum] = hw; } - ret = of_clk_add_hw_provider(clk_np, of_clk_hw_onecell_get, clk_data); + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); if (ret) pr_err("Failed to add DT provider: %pe\n", ERR_PTR(ret)); /* Reset controller */ reset = kzalloc(sizeof(*reset), GFP_KERNEL); - if (!reset) - return; - reset->rcdev.owner = THIS_MODULE; - reset->rcdev.nr_resets = WPCM450_NUM_RESETS; - reset->rcdev.ops = &reset_simple_ops; - reset->rcdev.of_node = clk_np; - reset->membase = clk_base + REG_IPSRST; - ret = reset_controller_register(&reset->rcdev); - if (ret) - pr_err("Failed to register reset controller: %pe\n", ERR_PTR(ret)); + if (reset) { + reset->rcdev.owner = THIS_MODULE; + reset->rcdev.nr_resets = WPCM450_NUM_RESETS; + reset->rcdev.ops = &reset_simple_ops; + reset->rcdev.of_node = np; + reset->membase = clk_base + REG_IPSRST; + ret = devm_reset_controller_register(dev, &reset->rcdev); + if (ret) + pr_err("Failed to register reset controller: %pe\n", ERR_PTR(ret)); + } - of_node_put(clk_np); + return 0; } -CLK_OF_DECLARE(wpcm450_clk_init, "nuvoton,wpcm450-clk", wpcm450_clk_init); +static const struct of_device_id wpcm450_of_match[] = { + { .compatible = "nuvoton,wpcm450-clk" }, + {} +}; +MODULE_DEVICE_TABLE(of, wpcm450_of_match); + +static struct platform_driver wpcm450_clk_driver = { + .driver = { + .name = "wpcm450-clk", + .of_match_table = wpcm450_of_match, + }, + .probe = wpcm450_clk_probe, +}; +module_platform_driver(wpcm450_clk_driver); + +MODULE_AUTHOR("Jonathan Neuschäfer "); +MODULE_DESCRIPTION("Nuvoton WPCM450 clock and reset controller driver"); +MODULE_LICENSE("GPL v2");