net: ethernet: ti: cpts: add support for ext rftclk selection
Some CPTS instances, which can be found on KeyStone 2 1G Ethernet Switch Subsystems, can control an external multiplexer that selects one of up to 32 clocks as time sync reference (RFTCLK) clock. This feature can be configured through CPTS_RFTCLK_SEL register (offset: x08) in CPTS module and can be represented as multiplexer clock. Hence, introduce support for optional cpts-refclk-mux clock, which, once defined will allow to select required CPTS RFTCLK by using assigned-clock-parents DT property in board files. Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
c8ad145143
Коммит
a3047a81ba
|
@ -5,6 +5,7 @@
|
|||
* Copyright (C) 2012 Richard Cochran <richardcochran@gmail.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/hrtimer.h>
|
||||
|
@ -532,6 +533,82 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
|
|||
freq, cpts->cc.mult, cpts->cc.shift, (ns - NSEC_PER_SEC));
|
||||
}
|
||||
|
||||
static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
|
||||
{
|
||||
struct device_node *refclk_np;
|
||||
const char **parent_names;
|
||||
unsigned int num_parents;
|
||||
struct clk_hw *clk_hw;
|
||||
int ret = -EINVAL;
|
||||
u32 *mux_table;
|
||||
|
||||
refclk_np = of_get_child_by_name(node, "cpts-refclk-mux");
|
||||
if (!refclk_np)
|
||||
/* refclk selection supported not for all SoCs */
|
||||
return 0;
|
||||
|
||||
num_parents = of_clk_get_parent_count(refclk_np);
|
||||
if (num_parents < 1) {
|
||||
dev_err(cpts->dev, "mux-clock %s must have parents\n",
|
||||
refclk_np->name);
|
||||
goto mux_fail;
|
||||
}
|
||||
|
||||
parent_names = devm_kzalloc(cpts->dev, (sizeof(char *) * num_parents),
|
||||
GFP_KERNEL);
|
||||
|
||||
mux_table = devm_kzalloc(cpts->dev, sizeof(*mux_table) * num_parents,
|
||||
GFP_KERNEL);
|
||||
if (!mux_table || !parent_names) {
|
||||
ret = -ENOMEM;
|
||||
goto mux_fail;
|
||||
}
|
||||
|
||||
of_clk_parent_fill(refclk_np, parent_names, num_parents);
|
||||
|
||||
ret = of_property_read_variable_u32_array(refclk_np, "ti,mux-tbl",
|
||||
mux_table,
|
||||
num_parents, num_parents);
|
||||
if (ret < 0)
|
||||
goto mux_fail;
|
||||
|
||||
clk_hw = clk_hw_register_mux_table(cpts->dev, refclk_np->name,
|
||||
parent_names, num_parents,
|
||||
0,
|
||||
&cpts->reg->rftclk_sel, 0, 0x1F,
|
||||
0, mux_table, NULL);
|
||||
if (IS_ERR(clk_hw)) {
|
||||
ret = PTR_ERR(clk_hw);
|
||||
goto mux_fail;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(cpts->dev,
|
||||
(void(*)(void *))clk_hw_unregister_mux,
|
||||
clk_hw);
|
||||
if (ret) {
|
||||
dev_err(cpts->dev, "add clkmux unreg action %d", ret);
|
||||
goto mux_fail;
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(refclk_np, of_clk_hw_simple_get, clk_hw);
|
||||
if (ret)
|
||||
goto mux_fail;
|
||||
|
||||
ret = devm_add_action_or_reset(cpts->dev,
|
||||
(void(*)(void *))of_clk_del_provider,
|
||||
refclk_np);
|
||||
if (ret) {
|
||||
dev_err(cpts->dev, "add clkmux provider unreg action %d", ret);
|
||||
goto mux_fail;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
mux_fail:
|
||||
of_node_put(refclk_np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
@ -547,7 +624,7 @@ static int cpts_of_parse(struct cpts *cpts, struct device_node *node)
|
|||
(!cpts->cc.mult && cpts->cc.shift))
|
||||
goto of_error;
|
||||
|
||||
return 0;
|
||||
return cpts_of_mux_clk_setup(cpts, node);
|
||||
|
||||
of_error:
|
||||
dev_err(cpts->dev, "CPTS: Missing property in the DT.\n");
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
struct cpsw_cpts {
|
||||
u32 idver; /* Identification and version */
|
||||
u32 control; /* Time sync control */
|
||||
u32 res1;
|
||||
u32 rftclk_sel; /* Reference Clock Select Register */
|
||||
u32 ts_push; /* Time stamp event push */
|
||||
u32 ts_load_val; /* Time stamp load value */
|
||||
u32 ts_load_en; /* Time stamp load enable */
|
||||
|
|
Загрузка…
Ссылка в новой задаче