mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									c8ad145143
								
							
						
					
					
						commit
						a3047a81ba
					
				
					 2 changed files with 79 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue