diff options
-rw-r--r-- | drivers/clk/clk-eyeq.c | 81 |
1 files changed, 73 insertions, 8 deletions
diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c index ed4dab303d91..85beec6b5b46 100644 --- a/drivers/clk/clk-eyeq.c +++ b/drivers/clk/clk-eyeq.c @@ -2,11 +2,14 @@ /* * PLL clock driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms. * - * This controller handles read-only PLLs, all derived from the same main - * crystal clock. It also exposes divider clocks, those are children to PLLs. - * Parent clock is expected to be constant. This driver's registers live in - * a shared region called OLB. Some PLLs are initialised early by of_clk_init(); - * if so, two clk providers are registered. + * This controller handles: + * - Read-only PLLs, all derived from the same main crystal clock. + * - It also exposes divider clocks, those are children to PLLs. + * - Fixed factor clocks, children to PLLs. + * + * Parent clock is expected to be constant. This driver's registers live in a + * shared region called OLB. Some PLLs and fixed-factors are initialised early + * by of_clk_init(); if so, two clk providers are registered. * * We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter. * @@ -86,6 +89,14 @@ struct eqc_div { u8 width; }; +struct eqc_fixed_factor { + unsigned int index; + const char *name; + unsigned int mult; + unsigned int div; + unsigned int parent; +}; + struct eqc_match_data { unsigned int pll_count; const struct eqc_pll *plls; @@ -93,6 +104,9 @@ struct eqc_match_data { unsigned int div_count; const struct eqc_div *divs; + unsigned int fixed_factor_count; + const struct eqc_fixed_factor *fixed_factors; + const char *reset_auxdev_name; const char *pinctrl_auxdev_name; @@ -103,6 +117,9 @@ struct eqc_early_match_data { unsigned int early_pll_count; const struct eqc_pll *early_plls; + unsigned int early_fixed_factor_count; + const struct eqc_fixed_factor *early_fixed_factors; + /* * We want our of_xlate callback to EPROBE_DEFER instead of dev_err() * and EINVAL. For that, we must know the total clock count. @@ -276,6 +293,35 @@ static void eqc_probe_init_divs(struct device *dev, const struct eqc_match_data } } +static void eqc_probe_init_fixed_factors(struct device *dev, + const struct eqc_match_data *data, + struct clk_hw_onecell_data *cells) +{ + const struct eqc_fixed_factor *ff; + struct clk_hw *hw, *parent_hw; + unsigned int i; + + for (i = 0; i < data->fixed_factor_count; i++) { + ff = &data->fixed_factors[i]; + parent_hw = cells->hws[ff->parent]; + + if (IS_ERR(parent_hw)) { + /* Parent is in early clk provider. */ + hw = clk_hw_register_fixed_factor_index(dev, ff->name, + ff->parent, 0, ff->mult, ff->div); + } else { + /* Avoid clock lookup when we already have the hw reference. */ + hw = clk_hw_register_fixed_factor_parent_hw(dev, ff->name, + parent_hw, 0, ff->mult, ff->div); + } + + cells->hws[ff->index] = hw; + if (IS_ERR(hw)) + dev_warn(dev, "failed registering %s: %pe\n", + ff->name, hw); + } +} + static void eqc_auxdev_release(struct device *dev) { struct auxiliary_device *adev = to_auxiliary_dev(dev); @@ -349,10 +395,11 @@ static int eqc_probe(struct platform_device *pdev) KBUILD_MODNAME, data->pinctrl_auxdev_name, ret); } - if (data->pll_count + data->div_count == 0) + if (data->pll_count + data->div_count + data->fixed_factor_count == 0) return 0; /* Zero clocks, we are done. */ - clk_count = data->pll_count + data->div_count + data->early_clk_count; + clk_count = data->pll_count + data->div_count + + data->fixed_factor_count + data->early_clk_count; cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL); if (!cells) return -ENOMEM; @@ -367,6 +414,8 @@ static int eqc_probe(struct platform_device *pdev) eqc_probe_init_divs(dev, data, base, cells); + eqc_probe_init_fixed_factors(dev, data, cells); + return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells); } @@ -580,7 +629,8 @@ static void __init eqc_early_init(struct device_node *np, void __iomem *base; int ret; - clk_count = early_data->early_pll_count + early_data->late_clk_count; + clk_count = early_data->early_pll_count + early_data->early_fixed_factor_count + + early_data->late_clk_count; cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL); if (!cells) { ret = -ENOMEM; @@ -633,6 +683,21 @@ static void __init eqc_early_init(struct device_node *np, } } + for (i = 0; i < early_data->early_fixed_factor_count; i++) { + const struct eqc_fixed_factor *ff = &early_data->early_fixed_factors[i]; + struct clk_hw *parent_hw = cells->hws[ff->parent]; + struct clk_hw *hw; + + hw = clk_hw_register_fixed_factor_parent_hw(NULL, ff->name, + parent_hw, 0, ff->mult, ff->div); + cells->hws[ff->index] = hw; + if (IS_ERR(hw)) { + pr_err("failed registering %s: %pe\n", ff->name, hw); + ret = PTR_ERR(hw); + goto err; + } + } + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells); if (ret) { pr_err("failed registering clk provider: %d\n", ret); |