Exemple #1
0
/*
 * Converts encoded control register address into a full address
 * On error, *src_addr will be returned as 0.
 */
static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
                      struct clk *src_clk, u32 *field_mask,
                      struct clk *clk, u32 *parent_div)
{
    const struct clksel *clks;
    const struct clksel_rate *clkr;

    *parent_div = 0;
    *src_addr = 0;

    clks = omap2_get_clksel_by_parent(clk, src_clk);
    if (clks == NULL)
        return 0;

    for (clkr = clks->rates; clkr->div; clkr++) {
        if (clkr->flags & (cpu_mask | DEFAULT_RATE))
            break; /* Found the default rate for this platform */
    }

    if (!clkr->div) {
        printk(KERN_ERR "clock: Could not find default rate for "
               "clock %s parent %s\n", clk->name,
               src_clk->parent->name);
        return 0;
    }

    /* Should never happen.  Add a clksel mask to the struct clk. */
    WARN_ON(clk->clksel_mask == 0);

    *field_mask = clk->clksel_mask;
    *src_addr = clk->clksel_reg;
    *parent_div = clkr->div;

    return clkr->val;
}
Exemple #2
0
/**
 * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value
 * @clk: OMAP struct clk to use
 * @div: integer divisor to search for
 *
 * Given a struct clk of a rate-selectable clksel clock, and a clock divisor,
 * find the corresponding register field value.  The return register value is
 * the value before left-shifting.  Returns 0xffffffff on error
 */
u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
{
    const struct clksel *clks;
    const struct clksel_rate *clkr;

    /* should never happen */
    WARN_ON(div == 0);

    clks = omap2_get_clksel_by_parent(clk, clk->parent);
    if (clks == NULL)
        return 0;

    for (clkr = clks->rates; clkr->div; clkr++) {
        if ((clkr->flags & cpu_mask) && (clkr->div == div))
            break;
    }

    if (!clkr->div) {
        printk(KERN_ERR "clock: Could not find divisor %d for "
               "clock %s parent %s\n", div, clk->name,
               clk->parent->name);
        return 0;
    }

    return clkr->val;
}
Exemple #3
0
/*
 * Converts encoded control register address into a full address
 * On error, the return value (parent_div) will be 0.
 */
static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
				       u32 *field_val)
{
	const struct clksel *clks;
	const struct clksel_rate *clkr;

	clks = omap2_get_clksel_by_parent(clk, src_clk);
	if (!clks)
		return 0;

	for (clkr = clks->rates; clkr->div; clkr++) {
		if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE)
			break; /* Found the default rate for this platform */
	}

	if (!clkr->div) {
		printk(KERN_ERR "clock: Could not find default rate for "
		       "clock %s parent %s\n", clk->name,
		       src_clk->parent->name);
		return 0;
	}

	/* Should never happen.  Add a clksel mask to the struct clk. */
	WARN_ON(clk->clksel_mask == 0);

	*field_val = clkr->val;

	return clkr->div;
}
Exemple #4
0
/**
 * omap2_clksel_round_rate_div - find divisor for the given clock and rate
 * @clk: OMAP struct clk to use
 * @target_rate: desired clock rate
 * @new_div: ptr to where we should store the divisor
 *
 * Finds 'best' divider value in an array based on the source and target
 * rates.  The divider array must be sorted with smallest divider first.
 * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
 * they are only settable as part of virtual_prcm set.
 *
 * Returns the rounded clock rate or returns 0xffffffff on error.
 */
u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
                u32 *new_div)
{
    unsigned long test_rate;
    const struct clksel *clks;
    const struct clksel_rate *clkr;
    u32 last_div = 0;

    printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n",
           clk->name, target_rate);

    *new_div = 1;

    clks = omap2_get_clksel_by_parent(clk, clk->parent);
    if (clks == NULL)
        return ~0;

    for (clkr = clks->rates; clkr->div; clkr++) {
        if (!(clkr->flags & cpu_mask))
            continue;

        /* Sanity check */
        if (clkr->div <= last_div)
            printk(KERN_ERR "clock: clksel_rate table not sorted "
                   "for clock %s", clk->name);

        last_div = clkr->div;

        test_rate = clk->parent->rate / clkr->div;

        if (test_rate <= target_rate)
            break; /* found it */
    }

    if (!clkr->div) {
        printk(KERN_ERR "clock: Could not find divisor for target "
               "rate %ld for clock %s parent %s\n", target_rate,
               clk->name, clk->parent->name);
        return ~0;
    }

    *new_div = clkr->div;

    printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div,
           (clk->parent->rate / clkr->div));

    return (clk->parent->rate / clkr->div);
}
Exemple #5
0
/**
 * omap2_clksel_to_divisor() - turn clksel field value into integer divider
 * @clk: OMAP struct clk to use
 * @field_val: register field value to find
 *
 * Given a struct clk of a rate-selectable clksel clock, and a register field
 * value to search for, find the corresponding clock divisor.  The register
 * field value should be pre-masked and shifted down so the LSB is at bit 0
 * before calling.  Returns 0 on error
 */
u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val)
{
    const struct clksel *clks;
    const struct clksel_rate *clkr;

    clks = omap2_get_clksel_by_parent(clk, clk->parent);
    if (clks == NULL)
        return 0;

    for (clkr = clks->rates; clkr->div; clkr++) {
        if ((clkr->flags & cpu_mask) && (clkr->val == field_val))
            break;
    }

    if (!clkr->div) {
        printk(KERN_ERR "clock: Could not find fieldval %d for "
               "clock %s parent %s\n", field_val, clk->name,
               clk->parent->name);
        return 0;
    }

    return clkr->div;
}