diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2011-12-28 14:21:16 +0530 |
---|---|---|
committer | Varun Wadekar <vwadekar@nvidia.com> | 2012-01-04 11:44:57 +0530 |
commit | f24c4131ebf2a59e7d6c81fb338a856b36432691 (patch) | |
tree | 4e2cdf6363549fa0c47b384927adf01ed82a1d9f /arch/arm/mach-tegra/tegra3_clocks.c | |
parent | f37e8ecb37b05ec0794d17bb1e7f461135d387f6 (diff) |
tegra3: clock: Support for divisor 15.1
Uart clock source has divisor of 16 bits where
LSB is 0.5.
Adding support for divisor 15.1 and configuring uart
for use the 15.1 type divisor.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Change-Id: Ifdd77041e7abb43026bbfb273f6e12923d64d607
Reviewed-on: http://git-master/r/70324
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Tested-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Bitan Biswas <bbiswas@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_clocks.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_clocks.c | 89 |
1 files changed, 64 insertions, 25 deletions
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c index 743e8eeeabc4..39a1712c7225 100644 --- a/arch/arm/mach-tegra/tegra3_clocks.c +++ b/arch/arm/mach-tegra/tegra3_clocks.c @@ -414,28 +414,44 @@ unsigned long clk_measure_input_freq(void) } } -static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate, - u32 flags, u32 round_mode) +static int clk_div_x1_get_divider(unsigned long parent_rate, unsigned long rate, + u32 max_x, u32 flags, u32 round_mode) { - s64 divider_u71 = parent_rate; + s64 divider_ux1 = parent_rate; if (!rate) return -EINVAL; if (!(flags & DIV_U71_INT)) - divider_u71 *= 2; + divider_ux1 *= 2; + if (round_mode == ROUND_DIVIDER_UP) - divider_u71 += rate - 1; - do_div(divider_u71, rate); + divider_ux1 += rate - 1; + do_div(divider_ux1, rate); + if (flags & DIV_U71_INT) - divider_u71 *= 2; + divider_ux1 *= 2; - if (divider_u71 - 2 < 0) + if (divider_ux1 - 2 < 0) return 0; - if (divider_u71 - 2 > 255) + if (divider_ux1 - 2 > max_x) return -EINVAL; - return divider_u71 - 2; + return divider_ux1 - 2; +} + +static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate, + u32 flags, u32 round_mode) +{ + return clk_div_x1_get_divider(parent_rate, rate, 0xFF, + flags, round_mode); +} + +static int clk_div151_get_divider(unsigned long parent_rate, unsigned long rate, + u32 flags, u32 round_mode) +{ + return clk_div_x1_get_divider(parent_rate, rate, 0xFFFF, + flags, round_mode); } static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) @@ -1947,10 +1963,6 @@ static void tegra3_periph_clk_init(struct clk *c) if (c->flags & DIV_U71) { u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; - if ((c->flags & DIV_U71_UART) && - (!(val & PERIPH_CLK_UART_DIV_ENB))) { - divu71 = 0; - } if (c->flags & DIV_U71_IDLE) { val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK << PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); @@ -1960,6 +1972,14 @@ static void tegra3_periph_clk_init(struct clk *c) } c->div = divu71 + 2; c->mul = 2; + } else if (c->flags & DIV_U151) { + u32 divu151 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; + if ((c->flags & DIV_U151_UART) && + (!(val & PERIPH_CLK_UART_DIV_ENB))) { + divu151 = 0; + } + c->div = divu151 + 2; + c->mul = 2; } else if (c->flags & DIV_U16) { u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; c->div = divu16 + 1; @@ -2085,7 +2105,19 @@ static int tegra3_periph_clk_set_rate(struct clk *c, unsigned long rate) val = clk_readl(c->reg); val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; val |= divider; - if (c->flags & DIV_U71_UART) { + clk_writel_delay(val, c->reg); + c->div = divider + 2; + c->mul = 2; + return 0; + } + } else if (c->flags & DIV_U151) { + divider = clk_div151_get_divider( + parent_rate, rate, c->flags, ROUND_DIVIDER_UP); + if (divider >= 0) { + val = clk_readl(c->reg); + val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; + val |= divider; + if (c->flags & DIV_U151_UART) { if (divider) val |= PERIPH_CLK_UART_DIV_ENB; else @@ -2129,6 +2161,13 @@ static long tegra3_periph_clk_round_rate(struct clk *c, return divider; return DIV_ROUND_UP(parent_rate * 2, divider + 2); + } else if (c->flags & DIV_U151) { + divider = clk_div151_get_divider( + parent_rate, rate, c->flags, ROUND_DIVIDER_UP); + if (divider < 0) + return divider; + + return DIV_ROUND_UP(parent_rate * 2, divider + 2); } else if (c->flags & DIV_U16) { divider = clk_div16_get_divider(parent_rate, rate); if (divider < 0) @@ -4046,16 +4085,16 @@ struct clk tegra_list_clks[] = { PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), PERIPH_CLK("i2c4", "tegra-i2c.3", NULL, 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), PERIPH_CLK("i2c5", "tegra-i2c.4", NULL, 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), - PERIPH_CLK("uarta", "tegra_uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartb", "tegra_uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartc", "tegra_uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartd", "tegra_uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uarte", "tegra_uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uarta_dbg", "serial8250.0", "uarta",6, 0x178, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartb_dbg", "serial8250.0", "uartb",7, 0x17c, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartc_dbg", "serial8250.0", "uartc",55, 0x1a0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartd_dbg", "serial8250.0", "uartd",65, 0x1c0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uarte_dbg", "serial8250.0", "uarte",66, 0x1c4, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), + PERIPH_CLK("uarta", "tegra_uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartb", "tegra_uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartc", "tegra_uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartd", "tegra_uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uarte", "tegra_uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uarta_dbg", "serial8250.0", "uarta",6, 0x178, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartb_dbg", "serial8250.0", "uartb",7, 0x17c, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartc_dbg", "serial8250.0", "uartc",55, 0x1a0, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartd_dbg", "serial8250.0", "uartd",65, 0x1c0, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uarte_dbg", "serial8250.0", "uarte",66, 0x1c4, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), PERIPH_CLK_EX("vi", "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops), PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET), PERIPH_CLK("3d2", "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET), |