Commit d96f774b authored by Tero Kristo's avatar Tero Kristo Committed by Michael Turquette
Browse files

clk: ti: divider: add support for legacy divider init



Legacy clock data is initialized slightly differently compared to
DT clocks, thus add support for this.

Signed-off-by: default avatarTero Kristo <t-kristo@ti.com>
Acked-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarMichael Turquette <mturquette@linaro.org>
parent 06524fa4
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -214,6 +214,9 @@ struct clk __init *ti_clk_register_clk(struct ti_clk *setup)
	case TI_CLK_MUX:
		clk = ti_clk_register_mux(setup);
		break;
	case TI_CLK_DIVIDER:
		clk = ti_clk_register_divider(setup);
		break;
	case TI_CLK_FIXED_FACTOR:
		fixed_factor = setup->data;

+2 −0
Original line number Diff line number Diff line
@@ -156,7 +156,9 @@ struct ti_clk_dpll {
struct clk *ti_clk_register_gate(struct ti_clk *setup);
struct clk *ti_clk_register_interface(struct ti_clk *setup);
struct clk *ti_clk_register_mux(struct ti_clk *setup);
struct clk *ti_clk_register_divider(struct ti_clk *setup);

struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup);
struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup);
struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup);

+131 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
#include "clock.h"

#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -300,6 +301,134 @@ static struct clk *_register_divider(struct device *dev, const char *name,
	return clk;
}

static struct clk_div_table *
_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
{
	int valid_div = 0;
	struct clk_div_table *table;
	int i;
	int div;
	u32 val;
	u8 flags;

	if (!setup->num_dividers) {
		/* Clk divider table not provided, determine min/max divs */
		flags = setup->flags;

		if (flags & CLKF_INDEX_STARTS_AT_ONE)
			val = 1;
		else
			val = 0;

		div = 1;

		while (div < setup->max_div) {
			if (flags & CLKF_INDEX_POWER_OF_TWO)
				div <<= 1;
			else
				div++;
			val++;
		}

		*width = fls(val);

		return NULL;
	}

	for (i = 0; i < setup->num_dividers; i++)
		if (setup->dividers[i])
			valid_div++;

	table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL);
	if (!table)
		return ERR_PTR(-ENOMEM);

	valid_div = 0;
	*width = 0;

	for (i = 0; i < setup->num_dividers; i++)
		if (setup->dividers[i]) {
			table[valid_div].div = setup->dividers[i];
			table[valid_div].val = i;
			valid_div++;
			*width = i;
		}

	*width = fls(*width);

	return table;
}

struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
{
	struct clk_divider *div;
	struct clk_omap_reg *reg;

	if (!setup)
		return NULL;

	div = kzalloc(sizeof(*div), GFP_KERNEL);
	if (!div)
		return ERR_PTR(-ENOMEM);

	reg = (struct clk_omap_reg *)&div->reg;
	reg->index = setup->module;
	reg->offset = setup->reg;

	if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
		div->flags |= CLK_DIVIDER_ONE_BASED;

	if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
		div->flags |= CLK_DIVIDER_POWER_OF_TWO;

	div->table = _get_div_table_from_setup(setup, &div->width);

	div->shift = setup->bit_shift;

	return &div->hw;
}

struct clk *ti_clk_register_divider(struct ti_clk *setup)
{
	struct ti_clk_divider *div;
	struct clk_omap_reg *reg_setup;
	u32 reg;
	u8 width;
	u32 flags = 0;
	u8 div_flags = 0;
	struct clk_div_table *table;
	struct clk *clk;

	div = setup->data;

	reg_setup = (struct clk_omap_reg *)&reg;

	reg_setup->index = div->module;
	reg_setup->offset = div->reg;

	if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
		div_flags |= CLK_DIVIDER_ONE_BASED;

	if (div->flags & CLKF_INDEX_POWER_OF_TWO)
		div_flags |= CLK_DIVIDER_POWER_OF_TWO;

	if (div->flags & CLKF_SET_RATE_PARENT)
		flags |= CLK_SET_RATE_PARENT;

	table = _get_div_table_from_setup(div, &width);
	if (IS_ERR(table))
		return (struct clk *)table;

	clk = _register_divider(NULL, setup->name, div->parent,
				flags, (void __iomem *)reg, div->bit_shift,
				width, div_flags, table, NULL);

	if (IS_ERR(clk))
		kfree(table);

	return clk;
}

static struct clk_div_table *
__init ti_clk_get_div_table(struct device_node *node)
{
@@ -455,7 +584,8 @@ static void __init of_ti_divider_clk_setup(struct device_node *node)
		goto cleanup;

	clk = _register_divider(NULL, node->name, parent_name, flags, reg,
				shift, width, clk_divider_flags, table, NULL);
				shift, width, clk_divider_flags, table,
				NULL);

	if (!IS_ERR(clk)) {
		of_clk_add_provider(node, of_clk_src_simple_get, clk);