|
@@ -11,6 +11,7 @@
|
|
|
|
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/clk.h>
|
|
|
|
+#include <linux/clk/davinci.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/err.h>
|
|
#include <linux/err.h>
|
|
#include <linux/io.h>
|
|
#include <linux/io.h>
|
|
@@ -223,6 +224,7 @@ static const struct clk_ops dm365_pll_ops = {
|
|
|
|
|
|
/**
|
|
/**
|
|
* davinci_pll_div_register - common *DIV clock implementation
|
|
* davinci_pll_div_register - common *DIV clock implementation
|
|
|
|
+ * @dev: The PLL platform device or NULL
|
|
* @name: the clock name
|
|
* @name: the clock name
|
|
* @parent_name: the parent clock name
|
|
* @parent_name: the parent clock name
|
|
* @reg: the *DIV register
|
|
* @reg: the *DIV register
|
|
@@ -240,17 +242,21 @@ static struct clk *davinci_pll_div_register(struct device *dev,
|
|
const struct clk_ops *divider_ops = &clk_divider_ops;
|
|
const struct clk_ops *divider_ops = &clk_divider_ops;
|
|
struct clk_gate *gate;
|
|
struct clk_gate *gate;
|
|
struct clk_divider *divider;
|
|
struct clk_divider *divider;
|
|
|
|
+ struct clk *clk;
|
|
|
|
+ int ret;
|
|
|
|
|
|
- gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
|
|
|
|
|
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
|
if (!gate)
|
|
if (!gate)
|
|
return ERR_PTR(-ENOMEM);
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
gate->reg = reg;
|
|
gate->reg = reg;
|
|
gate->bit_idx = DIV_ENABLE_SHIFT;
|
|
gate->bit_idx = DIV_ENABLE_SHIFT;
|
|
|
|
|
|
- divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
|
|
|
- if (!divider)
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ divider = kzalloc(sizeof(*divider), GFP_KERNEL);
|
|
|
|
+ if (!divider) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_free_gate;
|
|
|
|
+ }
|
|
|
|
|
|
divider->reg = reg;
|
|
divider->reg = reg;
|
|
divider->shift = DIV_RATIO_SHIFT;
|
|
divider->shift = DIV_RATIO_SHIFT;
|
|
@@ -261,9 +267,22 @@ static struct clk *davinci_pll_div_register(struct device *dev,
|
|
divider_ops = &clk_divider_ro_ops;
|
|
divider_ops = &clk_divider_ro_ops;
|
|
}
|
|
}
|
|
|
|
|
|
- return clk_register_composite(dev, name, parent_names, num_parents,
|
|
|
|
- NULL, NULL, ÷r->hw, divider_ops,
|
|
|
|
- &gate->hw, &clk_gate_ops, flags);
|
|
|
|
|
|
+ clk = clk_register_composite(dev, name, parent_names, num_parents,
|
|
|
|
+ NULL, NULL, ÷r->hw, divider_ops,
|
|
|
|
+ &gate->hw, &clk_gate_ops, flags);
|
|
|
|
+ if (IS_ERR(clk)) {
|
|
|
|
+ ret = PTR_ERR(clk);
|
|
|
|
+ goto err_free_divider;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return clk;
|
|
|
|
+
|
|
|
|
+err_free_divider:
|
|
|
|
+ kfree(divider);
|
|
|
|
+err_free_gate:
|
|
|
|
+ kfree(gate);
|
|
|
|
+
|
|
|
|
+ return ERR_PTR(ret);
|
|
}
|
|
}
|
|
|
|
|
|
struct davinci_pllen_clk {
|
|
struct davinci_pllen_clk {
|
|
@@ -321,36 +340,17 @@ static int davinci_pllen_rate_change(struct notifier_block *nb,
|
|
return NOTIFY_OK;
|
|
return NOTIFY_OK;
|
|
}
|
|
}
|
|
|
|
|
|
-static struct davinci_pll_platform_data *davinci_pll_get_pdata(struct device *dev)
|
|
|
|
-{
|
|
|
|
- struct davinci_pll_platform_data *pdata = dev_get_platdata(dev);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Platform data is optional, so allocate a new struct if one was not
|
|
|
|
- * provided. For device tree, this will always be the case.
|
|
|
|
- */
|
|
|
|
- if (!pdata)
|
|
|
|
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
|
- if (!pdata)
|
|
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
- /* for device tree, we need to fill in the struct */
|
|
|
|
- if (dev->of_node)
|
|
|
|
- pdata->cfgchip =
|
|
|
|
- syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");
|
|
|
|
-
|
|
|
|
- return pdata;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static struct notifier_block davinci_pllen_notifier = {
|
|
static struct notifier_block davinci_pllen_notifier = {
|
|
.notifier_call = davinci_pllen_rate_change,
|
|
.notifier_call = davinci_pllen_rate_change,
|
|
};
|
|
};
|
|
|
|
|
|
/**
|
|
/**
|
|
* davinci_pll_clk_register - Register a PLL clock
|
|
* davinci_pll_clk_register - Register a PLL clock
|
|
|
|
+ * @dev: The PLL platform device or NULL
|
|
* @info: The device-specific clock info
|
|
* @info: The device-specific clock info
|
|
* @parent_name: The parent clock name
|
|
* @parent_name: The parent clock name
|
|
* @base: The PLL's memory region
|
|
* @base: The PLL's memory region
|
|
|
|
+ * @cfgchip: CFGCHIP syscon regmap for info->unlock_reg or NULL
|
|
*
|
|
*
|
|
* This creates a series of clocks that represent the PLL.
|
|
* This creates a series of clocks that represent the PLL.
|
|
*
|
|
*
|
|
@@ -366,9 +366,9 @@ static struct notifier_block davinci_pllen_notifier = {
|
|
struct clk *davinci_pll_clk_register(struct device *dev,
|
|
struct clk *davinci_pll_clk_register(struct device *dev,
|
|
const struct davinci_pll_clk_info *info,
|
|
const struct davinci_pll_clk_info *info,
|
|
const char *parent_name,
|
|
const char *parent_name,
|
|
- void __iomem *base)
|
|
|
|
|
|
+ void __iomem *base,
|
|
|
|
+ struct regmap *cfgchip)
|
|
{
|
|
{
|
|
- struct davinci_pll_platform_data *pdata;
|
|
|
|
char prediv_name[MAX_NAME_SIZE];
|
|
char prediv_name[MAX_NAME_SIZE];
|
|
char pllout_name[MAX_NAME_SIZE];
|
|
char pllout_name[MAX_NAME_SIZE];
|
|
char postdiv_name[MAX_NAME_SIZE];
|
|
char postdiv_name[MAX_NAME_SIZE];
|
|
@@ -376,11 +376,12 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
|
struct clk_init_data init;
|
|
struct clk_init_data init;
|
|
struct davinci_pll_clk *pllout;
|
|
struct davinci_pll_clk *pllout;
|
|
struct davinci_pllen_clk *pllen;
|
|
struct davinci_pllen_clk *pllen;
|
|
- struct clk *pllout_clk, *clk;
|
|
|
|
-
|
|
|
|
- pdata = davinci_pll_get_pdata(dev);
|
|
|
|
- if (!pdata)
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ struct clk *oscin_clk = NULL;
|
|
|
|
+ struct clk *prediv_clk = NULL;
|
|
|
|
+ struct clk *pllout_clk;
|
|
|
|
+ struct clk *postdiv_clk = NULL;
|
|
|
|
+ struct clk *pllen_clk;
|
|
|
|
+ int ret;
|
|
|
|
|
|
if (info->flags & PLL_HAS_CLKMODE) {
|
|
if (info->flags & PLL_HAS_CLKMODE) {
|
|
/*
|
|
/*
|
|
@@ -392,10 +393,10 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
|
* a number of different things. In this driver we use it to
|
|
* a number of different things. In this driver we use it to
|
|
* mean the signal after the PLLCTL[CLKMODE] switch.
|
|
* mean the signal after the PLLCTL[CLKMODE] switch.
|
|
*/
|
|
*/
|
|
- clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME,
|
|
|
|
- parent_name, 0, 1, 1);
|
|
|
|
- if (IS_ERR(clk))
|
|
|
|
- return clk;
|
|
|
|
|
|
+ oscin_clk = clk_register_fixed_factor(dev, OSCIN_CLK_NAME,
|
|
|
|
+ parent_name, 0, 1, 1);
|
|
|
|
+ if (IS_ERR(oscin_clk))
|
|
|
|
+ return oscin_clk;
|
|
|
|
|
|
parent_name = OSCIN_CLK_NAME;
|
|
parent_name = OSCIN_CLK_NAME;
|
|
}
|
|
}
|
|
@@ -411,30 +412,34 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
|
|
|
|
|
/* Some? DM355 chips don't correctly report the PREDIV value */
|
|
/* Some? DM355 chips don't correctly report the PREDIV value */
|
|
if (info->flags & PLL_PREDIV_FIXED8)
|
|
if (info->flags & PLL_PREDIV_FIXED8)
|
|
- clk = clk_register_fixed_factor(dev, prediv_name,
|
|
|
|
- parent_name, flags, 1, 8);
|
|
|
|
|
|
+ prediv_clk = clk_register_fixed_factor(dev, prediv_name,
|
|
|
|
+ parent_name, flags, 1, 8);
|
|
else
|
|
else
|
|
- clk = davinci_pll_div_register(dev, prediv_name,
|
|
|
|
|
|
+ prediv_clk = davinci_pll_div_register(dev, prediv_name,
|
|
parent_name, base + PREDIV, fixed, flags);
|
|
parent_name, base + PREDIV, fixed, flags);
|
|
- if (IS_ERR(clk))
|
|
|
|
- return clk;
|
|
|
|
|
|
+ if (IS_ERR(prediv_clk)) {
|
|
|
|
+ ret = PTR_ERR(prediv_clk);
|
|
|
|
+ goto err_unregister_oscin;
|
|
|
|
+ }
|
|
|
|
|
|
parent_name = prediv_name;
|
|
parent_name = prediv_name;
|
|
}
|
|
}
|
|
|
|
|
|
/* Unlock writing to PLL registers */
|
|
/* Unlock writing to PLL registers */
|
|
if (info->unlock_reg) {
|
|
if (info->unlock_reg) {
|
|
- if (IS_ERR_OR_NULL(pdata->cfgchip))
|
|
|
|
|
|
+ if (IS_ERR_OR_NULL(cfgchip))
|
|
dev_warn(dev, "Failed to get CFGCHIP (%ld)\n",
|
|
dev_warn(dev, "Failed to get CFGCHIP (%ld)\n",
|
|
- PTR_ERR(pdata->cfgchip));
|
|
|
|
|
|
+ PTR_ERR(cfgchip));
|
|
else
|
|
else
|
|
- regmap_write_bits(pdata->cfgchip, info->unlock_reg,
|
|
|
|
|
|
+ regmap_write_bits(cfgchip, info->unlock_reg,
|
|
info->unlock_mask, 0);
|
|
info->unlock_mask, 0);
|
|
}
|
|
}
|
|
|
|
|
|
- pllout = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL);
|
|
|
|
- if (!pllout)
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ pllout = kzalloc(sizeof(*pllout), GFP_KERNEL);
|
|
|
|
+ if (!pllout) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_unregister_prediv;
|
|
|
|
+ }
|
|
|
|
|
|
snprintf(pllout_name, MAX_NAME_SIZE, "%s_pllout", info->name);
|
|
snprintf(pllout_name, MAX_NAME_SIZE, "%s_pllout", info->name);
|
|
|
|
|
|
@@ -456,9 +461,11 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
|
pllout->pllm_min = info->pllm_min;
|
|
pllout->pllm_min = info->pllm_min;
|
|
pllout->pllm_max = info->pllm_max;
|
|
pllout->pllm_max = info->pllm_max;
|
|
|
|
|
|
- pllout_clk = devm_clk_register(dev, &pllout->hw);
|
|
|
|
- if (IS_ERR(pllout_clk))
|
|
|
|
- return pllout_clk;
|
|
|
|
|
|
+ pllout_clk = clk_register(dev, &pllout->hw);
|
|
|
|
+ if (IS_ERR(pllout_clk)) {
|
|
|
|
+ ret = PTR_ERR(pllout_clk);
|
|
|
|
+ goto err_free_pllout;
|
|
|
|
+ }
|
|
|
|
|
|
clk_hw_set_rate_range(&pllout->hw, info->pllout_min_rate,
|
|
clk_hw_set_rate_range(&pllout->hw, info->pllout_min_rate,
|
|
info->pllout_max_rate);
|
|
info->pllout_max_rate);
|
|
@@ -474,17 +481,21 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
|
if (info->flags & PLL_POSTDIV_ALWAYS_ENABLED)
|
|
if (info->flags & PLL_POSTDIV_ALWAYS_ENABLED)
|
|
flags |= CLK_IS_CRITICAL;
|
|
flags |= CLK_IS_CRITICAL;
|
|
|
|
|
|
- clk = davinci_pll_div_register(dev, postdiv_name, parent_name,
|
|
|
|
- base + POSTDIV, fixed, flags);
|
|
|
|
- if (IS_ERR(clk))
|
|
|
|
- return clk;
|
|
|
|
|
|
+ postdiv_clk = davinci_pll_div_register(dev, postdiv_name,
|
|
|
|
+ parent_name, base + POSTDIV, fixed, flags);
|
|
|
|
+ if (IS_ERR(postdiv_clk)) {
|
|
|
|
+ ret = PTR_ERR(postdiv_clk);
|
|
|
|
+ goto err_unregister_pllout;
|
|
|
|
+ }
|
|
|
|
|
|
parent_name = postdiv_name;
|
|
parent_name = postdiv_name;
|
|
}
|
|
}
|
|
|
|
|
|
- pllen = devm_kzalloc(dev, sizeof(*pllout), GFP_KERNEL);
|
|
|
|
- if (!pllen)
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ pllen = kzalloc(sizeof(*pllout), GFP_KERNEL);
|
|
|
|
+ if (!pllen) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_unregister_postdiv;
|
|
|
|
+ }
|
|
|
|
|
|
snprintf(pllen_name, MAX_NAME_SIZE, "%s_pllen", info->name);
|
|
snprintf(pllen_name, MAX_NAME_SIZE, "%s_pllen", info->name);
|
|
|
|
|
|
@@ -497,17 +508,35 @@ struct clk *davinci_pll_clk_register(struct device *dev,
|
|
pllen->hw.init = &init;
|
|
pllen->hw.init = &init;
|
|
pllen->base = base;
|
|
pllen->base = base;
|
|
|
|
|
|
- clk = devm_clk_register(dev, &pllen->hw);
|
|
|
|
- if (IS_ERR(clk))
|
|
|
|
- return clk;
|
|
|
|
|
|
+ pllen_clk = clk_register(dev, &pllen->hw);
|
|
|
|
+ if (IS_ERR(pllen_clk)) {
|
|
|
|
+ ret = PTR_ERR(pllen_clk);
|
|
|
|
+ goto err_free_pllen;
|
|
|
|
+ }
|
|
|
|
|
|
- clk_notifier_register(clk, &davinci_pllen_notifier);
|
|
|
|
|
|
+ clk_notifier_register(pllen_clk, &davinci_pllen_notifier);
|
|
|
|
|
|
return pllout_clk;
|
|
return pllout_clk;
|
|
|
|
+
|
|
|
|
+err_free_pllen:
|
|
|
|
+ kfree(pllen);
|
|
|
|
+err_unregister_postdiv:
|
|
|
|
+ clk_unregister(postdiv_clk);
|
|
|
|
+err_unregister_pllout:
|
|
|
|
+ clk_unregister(pllout_clk);
|
|
|
|
+err_free_pllout:
|
|
|
|
+ kfree(pllout);
|
|
|
|
+err_unregister_prediv:
|
|
|
|
+ clk_unregister(prediv_clk);
|
|
|
|
+err_unregister_oscin:
|
|
|
|
+ clk_unregister(oscin_clk);
|
|
|
|
+
|
|
|
|
+ return ERR_PTR(ret);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* davinci_pll_auxclk_register - Register bypass clock (AUXCLK)
|
|
* davinci_pll_auxclk_register - Register bypass clock (AUXCLK)
|
|
|
|
+ * @dev: The PLL platform device or NULL
|
|
* @name: The clock name
|
|
* @name: The clock name
|
|
* @base: The PLL memory region
|
|
* @base: The PLL memory region
|
|
*/
|
|
*/
|
|
@@ -521,6 +550,7 @@ struct clk *davinci_pll_auxclk_register(struct device *dev,
|
|
|
|
|
|
/**
|
|
/**
|
|
* davinci_pll_sysclkbp_clk_register - Register bypass divider clock (SYSCLKBP)
|
|
* davinci_pll_sysclkbp_clk_register - Register bypass divider clock (SYSCLKBP)
|
|
|
|
+ * @dev: The PLL platform device or NULL
|
|
* @name: The clock name
|
|
* @name: The clock name
|
|
* @base: The PLL memory region
|
|
* @base: The PLL memory region
|
|
*/
|
|
*/
|
|
@@ -535,6 +565,7 @@ struct clk *davinci_pll_sysclkbp_clk_register(struct device *dev,
|
|
|
|
|
|
/**
|
|
/**
|
|
* davinci_pll_obsclk_register - Register oscillator divider clock (OBSCLK)
|
|
* davinci_pll_obsclk_register - Register oscillator divider clock (OBSCLK)
|
|
|
|
+ * @dev: The PLL platform device or NULL
|
|
* @info: The clock info
|
|
* @info: The clock info
|
|
* @base: The PLL memory region
|
|
* @base: The PLL memory region
|
|
*/
|
|
*/
|
|
@@ -546,9 +577,11 @@ davinci_pll_obsclk_register(struct device *dev,
|
|
struct clk_mux *mux;
|
|
struct clk_mux *mux;
|
|
struct clk_gate *gate;
|
|
struct clk_gate *gate;
|
|
struct clk_divider *divider;
|
|
struct clk_divider *divider;
|
|
|
|
+ struct clk *clk;
|
|
u32 oscdiv;
|
|
u32 oscdiv;
|
|
|
|
+ int ret;
|
|
|
|
|
|
- mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
|
|
|
|
|
|
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
|
|
if (!mux)
|
|
if (!mux)
|
|
return ERR_PTR(-ENOMEM);
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
@@ -556,16 +589,20 @@ davinci_pll_obsclk_register(struct device *dev,
|
|
mux->table = info->table;
|
|
mux->table = info->table;
|
|
mux->mask = info->ocsrc_mask;
|
|
mux->mask = info->ocsrc_mask;
|
|
|
|
|
|
- gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
|
|
|
- if (!gate)
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
|
|
|
+ if (!gate) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_free_mux;
|
|
|
|
+ }
|
|
|
|
|
|
gate->reg = base + CKEN;
|
|
gate->reg = base + CKEN;
|
|
gate->bit_idx = CKEN_OBSCLK_SHIFT;
|
|
gate->bit_idx = CKEN_OBSCLK_SHIFT;
|
|
|
|
|
|
- divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
|
|
|
- if (!divider)
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ divider = kzalloc(sizeof(*divider), GFP_KERNEL);
|
|
|
|
+ if (!divider) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_free_gate;
|
|
|
|
+ }
|
|
|
|
|
|
divider->reg = base + OSCDIV;
|
|
divider->reg = base + OSCDIV;
|
|
divider->shift = DIV_RATIO_SHIFT;
|
|
divider->shift = DIV_RATIO_SHIFT;
|
|
@@ -576,11 +613,27 @@ davinci_pll_obsclk_register(struct device *dev,
|
|
oscdiv |= BIT(DIV_ENABLE_SHIFT);
|
|
oscdiv |= BIT(DIV_ENABLE_SHIFT);
|
|
writel(oscdiv, base + OSCDIV);
|
|
writel(oscdiv, base + OSCDIV);
|
|
|
|
|
|
- return clk_register_composite(dev, info->name, info->parent_names,
|
|
|
|
- info->num_parents,
|
|
|
|
- &mux->hw, &clk_mux_ops,
|
|
|
|
- ÷r->hw, &clk_divider_ops,
|
|
|
|
- &gate->hw, &clk_gate_ops, 0);
|
|
|
|
|
|
+ clk = clk_register_composite(dev, info->name, info->parent_names,
|
|
|
|
+ info->num_parents,
|
|
|
|
+ &mux->hw, &clk_mux_ops,
|
|
|
|
+ ÷r->hw, &clk_divider_ops,
|
|
|
|
+ &gate->hw, &clk_gate_ops, 0);
|
|
|
|
+
|
|
|
|
+ if (IS_ERR(clk)) {
|
|
|
|
+ ret = PTR_ERR(clk);
|
|
|
|
+ goto err_free_divider;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return clk;
|
|
|
|
+
|
|
|
|
+err_free_divider:
|
|
|
|
+ kfree(divider);
|
|
|
|
+err_free_gate:
|
|
|
|
+ kfree(gate);
|
|
|
|
+err_free_mux:
|
|
|
|
+ kfree(mux);
|
|
|
|
+
|
|
|
|
+ return ERR_PTR(ret);
|
|
}
|
|
}
|
|
|
|
|
|
/* The PLL SYSCLKn clocks have a mechanism for synchronizing rate changes. */
|
|
/* The PLL SYSCLKn clocks have a mechanism for synchronizing rate changes. */
|
|
@@ -616,6 +669,7 @@ static struct notifier_block davinci_pll_sysclk_notifier = {
|
|
|
|
|
|
/**
|
|
/**
|
|
* davinci_pll_sysclk_register - Register divider clocks (SYSCLKn)
|
|
* davinci_pll_sysclk_register - Register divider clocks (SYSCLKn)
|
|
|
|
+ * @dev: The PLL platform device or NULL
|
|
* @info: The clock info
|
|
* @info: The clock info
|
|
* @base: The PLL memory region
|
|
* @base: The PLL memory region
|
|
*/
|
|
*/
|
|
@@ -630,6 +684,7 @@ davinci_pll_sysclk_register(struct device *dev,
|
|
struct clk *clk;
|
|
struct clk *clk;
|
|
u32 reg;
|
|
u32 reg;
|
|
u32 flags = 0;
|
|
u32 flags = 0;
|
|
|
|
+ int ret;
|
|
|
|
|
|
/* PLLDIVn registers are not entirely consecutive */
|
|
/* PLLDIVn registers are not entirely consecutive */
|
|
if (info->id < 4)
|
|
if (info->id < 4)
|
|
@@ -637,16 +692,18 @@ davinci_pll_sysclk_register(struct device *dev,
|
|
else
|
|
else
|
|
reg = PLLDIV4 + 4 * (info->id - 4);
|
|
reg = PLLDIV4 + 4 * (info->id - 4);
|
|
|
|
|
|
- gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
|
|
|
|
|
|
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
|
if (!gate)
|
|
if (!gate)
|
|
return ERR_PTR(-ENOMEM);
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
gate->reg = base + reg;
|
|
gate->reg = base + reg;
|
|
gate->bit_idx = DIV_ENABLE_SHIFT;
|
|
gate->bit_idx = DIV_ENABLE_SHIFT;
|
|
|
|
|
|
- divider = devm_kzalloc(dev, sizeof(*divider), GFP_KERNEL);
|
|
|
|
- if (!divider)
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
+ divider = kzalloc(sizeof(*divider), GFP_KERNEL);
|
|
|
|
+ if (!divider) {
|
|
|
|
+ ret = -ENOMEM;
|
|
|
|
+ goto err_free_gate;
|
|
|
|
+ }
|
|
|
|
|
|
divider->reg = base + reg;
|
|
divider->reg = base + reg;
|
|
divider->shift = DIV_RATIO_SHIFT;
|
|
divider->shift = DIV_RATIO_SHIFT;
|
|
@@ -668,22 +725,31 @@ davinci_pll_sysclk_register(struct device *dev,
|
|
clk = clk_register_composite(dev, info->name, &info->parent_name, 1,
|
|
clk = clk_register_composite(dev, info->name, &info->parent_name, 1,
|
|
NULL, NULL, ÷r->hw, divider_ops,
|
|
NULL, NULL, ÷r->hw, divider_ops,
|
|
&gate->hw, &clk_gate_ops, flags);
|
|
&gate->hw, &clk_gate_ops, flags);
|
|
- if (IS_ERR(clk))
|
|
|
|
- return clk;
|
|
|
|
|
|
+ if (IS_ERR(clk)) {
|
|
|
|
+ ret = PTR_ERR(clk);
|
|
|
|
+ goto err_free_divider;
|
|
|
|
+ }
|
|
|
|
|
|
clk_notifier_register(clk, &davinci_pll_sysclk_notifier);
|
|
clk_notifier_register(clk, &davinci_pll_sysclk_notifier);
|
|
|
|
|
|
return clk;
|
|
return clk;
|
|
|
|
+
|
|
|
|
+err_free_divider:
|
|
|
|
+ kfree(divider);
|
|
|
|
+err_free_gate:
|
|
|
|
+ kfree(gate);
|
|
|
|
+
|
|
|
|
+ return ERR_PTR(ret);
|
|
}
|
|
}
|
|
|
|
|
|
-int of_davinci_pll_init(struct device *dev,
|
|
|
|
|
|
+int of_davinci_pll_init(struct device *dev, struct device_node *node,
|
|
const struct davinci_pll_clk_info *info,
|
|
const struct davinci_pll_clk_info *info,
|
|
const struct davinci_pll_obsclk_info *obsclk_info,
|
|
const struct davinci_pll_obsclk_info *obsclk_info,
|
|
const struct davinci_pll_sysclk_info **div_info,
|
|
const struct davinci_pll_sysclk_info **div_info,
|
|
u8 max_sysclk_id,
|
|
u8 max_sysclk_id,
|
|
- void __iomem *base)
|
|
|
|
|
|
+ void __iomem *base,
|
|
|
|
+ struct regmap *cfgchip)
|
|
{
|
|
{
|
|
- struct device_node *node = dev->of_node;
|
|
|
|
struct device_node *child;
|
|
struct device_node *child;
|
|
const char *parent_name;
|
|
const char *parent_name;
|
|
struct clk *clk;
|
|
struct clk *clk;
|
|
@@ -693,7 +759,7 @@ int of_davinci_pll_init(struct device *dev,
|
|
else
|
|
else
|
|
parent_name = OSCIN_CLK_NAME;
|
|
parent_name = OSCIN_CLK_NAME;
|
|
|
|
|
|
- clk = davinci_pll_clk_register(dev, info, parent_name, base);
|
|
|
|
|
|
+ clk = davinci_pll_clk_register(dev, info, parent_name, base, cfgchip);
|
|
if (IS_ERR(clk)) {
|
|
if (IS_ERR(clk)) {
|
|
dev_err(dev, "failed to register %s\n", info->name);
|
|
dev_err(dev, "failed to register %s\n", info->name);
|
|
return PTR_ERR(clk);
|
|
return PTR_ERR(clk);
|
|
@@ -711,13 +777,15 @@ int of_davinci_pll_init(struct device *dev,
|
|
int n_clks = max_sysclk_id + 1;
|
|
int n_clks = max_sysclk_id + 1;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL);
|
|
|
|
|
|
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
|
|
if (!clk_data)
|
|
if (!clk_data)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- clks = devm_kmalloc_array(dev, n_clks, sizeof(*clks), GFP_KERNEL);
|
|
|
|
- if (!clks)
|
|
|
|
|
|
+ clks = kmalloc_array(n_clks, sizeof(*clks), GFP_KERNEL);
|
|
|
|
+ if (!clks) {
|
|
|
|
+ kfree(clk_data);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
|
|
clk_data->clks = clks;
|
|
clk_data->clks = clks;
|
|
clk_data->clk_num = n_clks;
|
|
clk_data->clk_num = n_clks;
|
|
@@ -770,32 +838,73 @@ int of_davinci_pll_init(struct device *dev,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static struct davinci_pll_platform_data *davinci_pll_get_pdata(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ struct davinci_pll_platform_data *pdata = dev_get_platdata(dev);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Platform data is optional, so allocate a new struct if one was not
|
|
|
|
+ * provided. For device tree, this will always be the case.
|
|
|
|
+ */
|
|
|
|
+ if (!pdata)
|
|
|
|
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
|
|
|
+ if (!pdata)
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ /* for device tree, we need to fill in the struct */
|
|
|
|
+ if (dev->of_node)
|
|
|
|
+ pdata->cfgchip =
|
|
|
|
+ syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");
|
|
|
|
+
|
|
|
|
+ return pdata;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* needed in early boot for clocksource/clockevent */
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DA850
|
|
|
|
+CLK_OF_DECLARE(da850_pll0, "ti,da850-pll0", of_da850_pll0_init);
|
|
|
|
+#endif
|
|
|
|
+
|
|
static const struct of_device_id davinci_pll_of_match[] = {
|
|
static const struct of_device_id davinci_pll_of_match[] = {
|
|
- { .compatible = "ti,da850-pll0", .data = of_da850_pll0_init },
|
|
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DA850
|
|
{ .compatible = "ti,da850-pll1", .data = of_da850_pll1_init },
|
|
{ .compatible = "ti,da850-pll1", .data = of_da850_pll1_init },
|
|
|
|
+#endif
|
|
{ }
|
|
{ }
|
|
};
|
|
};
|
|
|
|
|
|
static const struct platform_device_id davinci_pll_id_table[] = {
|
|
static const struct platform_device_id davinci_pll_id_table[] = {
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DA830
|
|
{ .name = "da830-pll", .driver_data = (kernel_ulong_t)da830_pll_init },
|
|
{ .name = "da830-pll", .driver_data = (kernel_ulong_t)da830_pll_init },
|
|
|
|
+#endif
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DA850
|
|
{ .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init },
|
|
{ .name = "da850-pll0", .driver_data = (kernel_ulong_t)da850_pll0_init },
|
|
{ .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init },
|
|
{ .name = "da850-pll1", .driver_data = (kernel_ulong_t)da850_pll1_init },
|
|
|
|
+#endif
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DM355
|
|
{ .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init },
|
|
{ .name = "dm355-pll1", .driver_data = (kernel_ulong_t)dm355_pll1_init },
|
|
{ .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init },
|
|
{ .name = "dm355-pll2", .driver_data = (kernel_ulong_t)dm355_pll2_init },
|
|
|
|
+#endif
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DM365
|
|
{ .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init },
|
|
{ .name = "dm365-pll1", .driver_data = (kernel_ulong_t)dm365_pll1_init },
|
|
{ .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init },
|
|
{ .name = "dm365-pll2", .driver_data = (kernel_ulong_t)dm365_pll2_init },
|
|
|
|
+#endif
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DM644x
|
|
{ .name = "dm644x-pll1", .driver_data = (kernel_ulong_t)dm644x_pll1_init },
|
|
{ .name = "dm644x-pll1", .driver_data = (kernel_ulong_t)dm644x_pll1_init },
|
|
{ .name = "dm644x-pll2", .driver_data = (kernel_ulong_t)dm644x_pll2_init },
|
|
{ .name = "dm644x-pll2", .driver_data = (kernel_ulong_t)dm644x_pll2_init },
|
|
|
|
+#endif
|
|
|
|
+#ifdef CONFIG_ARCH_DAVINCI_DM646x
|
|
{ .name = "dm646x-pll1", .driver_data = (kernel_ulong_t)dm646x_pll1_init },
|
|
{ .name = "dm646x-pll1", .driver_data = (kernel_ulong_t)dm646x_pll1_init },
|
|
{ .name = "dm646x-pll2", .driver_data = (kernel_ulong_t)dm646x_pll2_init },
|
|
{ .name = "dm646x-pll2", .driver_data = (kernel_ulong_t)dm646x_pll2_init },
|
|
|
|
+#endif
|
|
{ }
|
|
{ }
|
|
};
|
|
};
|
|
|
|
|
|
-typedef int (*davinci_pll_init)(struct device *dev, void __iomem *base);
|
|
|
|
|
|
+typedef int (*davinci_pll_init)(struct device *dev, void __iomem *base,
|
|
|
|
+ struct regmap *cfgchip);
|
|
|
|
|
|
static int davinci_pll_probe(struct platform_device *pdev)
|
|
static int davinci_pll_probe(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct device *dev = &pdev->dev;
|
|
|
|
+ struct davinci_pll_platform_data *pdata;
|
|
const struct of_device_id *of_id;
|
|
const struct of_device_id *of_id;
|
|
davinci_pll_init pll_init = NULL;
|
|
davinci_pll_init pll_init = NULL;
|
|
struct resource *res;
|
|
struct resource *res;
|
|
@@ -812,12 +921,18 @@ static int davinci_pll_probe(struct platform_device *pdev)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ pdata = davinci_pll_get_pdata(dev);
|
|
|
|
+ if (!pdata) {
|
|
|
|
+ dev_err(dev, "missing platform data\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
base = devm_ioremap_resource(dev, res);
|
|
base = devm_ioremap_resource(dev, res);
|
|
if (IS_ERR(base))
|
|
if (IS_ERR(base))
|
|
return PTR_ERR(base);
|
|
return PTR_ERR(base);
|
|
|
|
|
|
- return pll_init(dev, base);
|
|
|
|
|
|
+ return pll_init(dev, base, pdata->cfgchip);
|
|
}
|
|
}
|
|
|
|
|
|
static struct platform_driver davinci_pll_driver = {
|
|
static struct platform_driver davinci_pll_driver = {
|