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:
Grygorii Strashko 2019-06-06 19:30:41 +03:00 коммит произвёл David S. Miller
Родитель c8ad145143
Коммит a3047a81ba
2 изменённых файлов: 79 добавлений и 2 удалений

Просмотреть файл

@ -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 */