diff options
Diffstat (limited to 'drivers/clk/clk-wm831x.c')
| -rw-r--r-- | drivers/clk/clk-wm831x.c | 79 |
1 files changed, 34 insertions, 45 deletions
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index 1b3f8c9b98cc..263e927138c2 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -1,18 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * WM831x clock control * * Copyright 2011-2 Wolfson Microelectronics PLC. * * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * */ -#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/module.h> @@ -25,13 +19,10 @@ struct wm831x_clk { struct clk_hw xtal_hw; struct clk_hw fll_hw; struct clk_hw clkout_hw; - struct clk *xtal; - struct clk *fll; - struct clk *clkout; bool xtal_ena; }; -static int wm831x_xtal_is_enabled(struct clk_hw *hw) +static int wm831x_xtal_is_prepared(struct clk_hw *hw) { struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, xtal_hw); @@ -52,14 +43,13 @@ static unsigned long wm831x_xtal_recalc_rate(struct clk_hw *hw, } static const struct clk_ops wm831x_xtal_ops = { - .is_enabled = wm831x_xtal_is_enabled, + .is_prepared = wm831x_xtal_is_prepared, .recalc_rate = wm831x_xtal_recalc_rate, }; -static struct clk_init_data wm831x_xtal_init = { +static const struct clk_init_data wm831x_xtal_init = { .name = "xtal", .ops = &wm831x_xtal_ops, - .flags = CLK_IS_ROOT, }; static const unsigned long wm831x_fll_auto_rates[] = { @@ -73,7 +63,7 @@ static const unsigned long wm831x_fll_auto_rates[] = { 24576000, }; -static int wm831x_fll_is_enabled(struct clk_hw *hw) +static int wm831x_fll_is_prepared(struct clk_hw *hw) { struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, fll_hw); @@ -102,7 +92,8 @@ static int wm831x_fll_prepare(struct clk_hw *hw) if (ret != 0) dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret); - usleep_range(2000, 2000); + /* wait 2-3 ms for new frequency taking effect */ + usleep_range(2000, 3000); return ret; } @@ -142,18 +133,20 @@ static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw, return 0; } -static long wm831x_fll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *unused) +static int wm831x_fll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int best = 0; int i; for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++) - if (abs(wm831x_fll_auto_rates[i] - rate) < - abs(wm831x_fll_auto_rates[best] - rate)) + if (abs(wm831x_fll_auto_rates[i] - req->rate) < + abs(wm831x_fll_auto_rates[best] - req->rate)) best = i; - return wm831x_fll_auto_rates[best]; + req->rate = wm831x_fll_auto_rates[best]; + + return 0; } static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -170,7 +163,7 @@ static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate, if (i == ARRAY_SIZE(wm831x_fll_auto_rates)) return -EINVAL; - if (wm831x_fll_is_enabled(hw)) + if (wm831x_fll_is_prepared(hw)) return -EPERM; return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2, @@ -220,16 +213,16 @@ static u8 wm831x_fll_get_parent(struct clk_hw *hw) } static const struct clk_ops wm831x_fll_ops = { - .is_enabled = wm831x_fll_is_enabled, + .is_prepared = wm831x_fll_is_prepared, .prepare = wm831x_fll_prepare, .unprepare = wm831x_fll_unprepare, - .round_rate = wm831x_fll_round_rate, + .determine_rate = wm831x_fll_determine_rate, .recalc_rate = wm831x_fll_recalc_rate, .set_rate = wm831x_fll_set_rate, .get_parent = wm831x_fll_get_parent, }; -static struct clk_init_data wm831x_fll_init = { +static const struct clk_init_data wm831x_fll_init = { .name = "fll", .ops = &wm831x_fll_ops, .parent_names = wm831x_fll_parents, @@ -237,7 +230,7 @@ static struct clk_init_data wm831x_fll_init = { .flags = CLK_SET_RATE_GATE, }; -static int wm831x_clkout_is_enabled(struct clk_hw *hw) +static int wm831x_clkout_is_prepared(struct clk_hw *hw) { struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk, clkout_hw); @@ -248,7 +241,7 @@ static int wm831x_clkout_is_enabled(struct clk_hw *hw) if (ret < 0) { dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n", ret); - return true; + return false; } return (ret & WM831X_CLKOUT_ENA) != 0; @@ -335,14 +328,15 @@ static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent) } static const struct clk_ops wm831x_clkout_ops = { - .is_enabled = wm831x_clkout_is_enabled, + .is_prepared = wm831x_clkout_is_prepared, .prepare = wm831x_clkout_prepare, .unprepare = wm831x_clkout_unprepare, + .determine_rate = clk_hw_determine_rate_no_reparent, .get_parent = wm831x_clkout_get_parent, .set_parent = wm831x_clkout_set_parent, }; -static struct clk_init_data wm831x_clkout_init = { +static const struct clk_init_data wm831x_clkout_init = { .name = "clkout", .ops = &wm831x_clkout_ops, .parent_names = wm831x_clkout_parents, @@ -360,6 +354,8 @@ static int wm831x_clk_probe(struct platform_device *pdev) if (!clkdata) return -ENOMEM; + clkdata->wm831x = wm831x; + /* XTAL_ENA can only be set via OTP/InstantConfig so just read once */ ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2); if (ret < 0) { @@ -370,36 +366,29 @@ static int wm831x_clk_probe(struct platform_device *pdev) clkdata->xtal_ena = ret & WM831X_XTAL_ENA; clkdata->xtal_hw.init = &wm831x_xtal_init; - clkdata->xtal = devm_clk_register(&pdev->dev, &clkdata->xtal_hw); - if (IS_ERR(clkdata->xtal)) - return PTR_ERR(clkdata->xtal); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->xtal_hw); + if (ret) + return ret; clkdata->fll_hw.init = &wm831x_fll_init; - clkdata->fll = devm_clk_register(&pdev->dev, &clkdata->fll_hw); - if (IS_ERR(clkdata->fll)) - return PTR_ERR(clkdata->fll); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->fll_hw); + if (ret) + return ret; clkdata->clkout_hw.init = &wm831x_clkout_init; - clkdata->clkout = devm_clk_register(&pdev->dev, &clkdata->clkout_hw); - if (IS_ERR(clkdata->clkout)) - return PTR_ERR(clkdata->clkout); + ret = devm_clk_hw_register(&pdev->dev, &clkdata->clkout_hw); + if (ret) + return ret; platform_set_drvdata(pdev, clkdata); return 0; } -static int wm831x_clk_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver wm831x_clk_driver = { .probe = wm831x_clk_probe, - .remove = wm831x_clk_remove, .driver = { .name = "wm831x-clk", - .owner = THIS_MODULE, }, }; |
