summaryrefslogtreecommitdiff
path: root/arch/blackfin/include/asm/clock.h
blob: fc84fe43f12be1977ecd6afdcb54ce379cb9a951 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/*
 * Copyright (C) 2012 Analog Devices Inc.
 * Licensed under the GPL-2 or later.
 */

#ifndef __CLOCK_H__
#define __CLOCK_H__

#include <asm/blackfin.h>
#ifdef PLL_CTL
#include <asm/mach-common/bits/pll.h>
# define pll_is_bypassed() (bfin_read_PLL_CTL() & BYPASS)
#else
#include <asm/mach-common/bits/cgu.h>
# define pll_is_bypassed() (bfin_read_CGU_STAT() & PLLBP)
# define bfin_read_PLL_CTL() bfin_read_CGU_CTL()
# define bfin_read_PLL_DIV() bfin_read_CGU_DIV()
# define SSEL SYSSEL
# define SSEL_P SYSSEL_P
#endif

__attribute__((always_inline))
static inline uint32_t early_division(uint32_t dividend, uint32_t divisor)
{
	uint32_t quotient;
	uint32_t i, j;

	for (quotient = 1, i = 1; dividend > divisor; ++i) {
		j = divisor << i;
		if (j > dividend || (j & 0x80000000)) {
			--i;
			quotient += (1 << i);
			dividend -= (divisor << i);
			i = 0;
		}
	}

	return quotient;
}

__attribute__((always_inline))
static inline uint32_t early_get_uart_clk(void)
{
	uint32_t msel, pll_ctl, vco;
	uint32_t div, ssel, sclk, uclk;

	pll_ctl = bfin_read_PLL_CTL();
	msel = (pll_ctl & MSEL) >> MSEL_P;
	if (msel == 0)
		msel = (MSEL >> MSEL_P) + 1;

	vco = (CONFIG_CLKIN_HZ >> (pll_ctl & DF)) * msel;
	sclk = vco;
	if (!pll_is_bypassed()) {
		div = bfin_read_PLL_DIV();
		ssel = (div & SSEL) >> SSEL_P;
#if CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_BYPASS
		sclk = vco/ssel;
#else
		sclk = early_division(vco, ssel);
#endif
	}
	uclk = sclk;
#ifdef CGU_DIV
	ssel = (div & S0SEL) >> S0SEL_P;
	uclk = early_division(sclk, ssel);
#endif
	return uclk;
}

#ifdef CGU_DIV
# define get_uart_clk get_sclk0
#else
# define get_uart_clk get_sclk
#endif

#endif