+static unsigned long exynos5_get_periph_rate(int peripheral)
+{
+ struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
+ unsigned long sclk, sub_clk;
+ unsigned int src, div, sub_div;
+ struct exynos5_clock *clk =
+ (struct exynos5_clock *)samsung_get_base_clock();
+
+ switch (peripheral) {
+ case PERIPH_ID_UART0:
+ case PERIPH_ID_UART1:
+ case PERIPH_ID_UART2:
+ case PERIPH_ID_UART3:
+ src = readl(&clk->src_peric0);
+ div = readl(&clk->div_peric0);
+ break;
+ case PERIPH_ID_PWM0:
+ case PERIPH_ID_PWM1:
+ case PERIPH_ID_PWM2:
+ case PERIPH_ID_PWM3:
+ case PERIPH_ID_PWM4:
+ src = readl(&clk->src_peric0);
+ div = readl(&clk->div_peric3);
+ break;
+ case PERIPH_ID_I2S0:
+ src = readl(&clk->src_mau);
+ div = readl(&clk->div_mau);
+ case PERIPH_ID_SPI0:
+ case PERIPH_ID_SPI1:
+ src = readl(&clk->src_peric1);
+ div = readl(&clk->div_peric1);
+ break;
+ case PERIPH_ID_SPI2:
+ src = readl(&clk->src_peric1);
+ div = readl(&clk->div_peric2);
+ break;
+ case PERIPH_ID_SPI3:
+ case PERIPH_ID_SPI4:
+ src = readl(&clk->sclk_src_isp);
+ div = readl(&clk->sclk_div_isp);
+ break;
+ case PERIPH_ID_SDMMC0:
+ case PERIPH_ID_SDMMC1:
+ case PERIPH_ID_SDMMC2:
+ case PERIPH_ID_SDMMC3:
+ src = readl(&clk->src_fsys);
+ div = readl(&clk->div_fsys1);
+ break;
+ case PERIPH_ID_I2C0:
+ case PERIPH_ID_I2C1:
+ case PERIPH_ID_I2C2:
+ case PERIPH_ID_I2C3:
+ case PERIPH_ID_I2C4:
+ case PERIPH_ID_I2C5:
+ case PERIPH_ID_I2C6:
+ case PERIPH_ID_I2C7:
+ sclk = exynos5_get_pll_clk(MPLL);
+ sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit)
+ & 0x7) + 1;
+ div = ((readl(&clk->div_top0) >> bit_info->prediv_bit)
+ & 0x7) + 1;
+ return (sclk / sub_div) / div;
+ default:
+ debug("%s: invalid peripheral %d", __func__, peripheral);
+ return -1;
+ };
+
+ src = (src >> bit_info->src_bit) & 0xf;
+
+ switch (src) {
+ case EXYNOS_SRC_MPLL:
+ sclk = exynos5_get_pll_clk(MPLL);
+ break;
+ case EXYNOS_SRC_EPLL:
+ sclk = exynos5_get_pll_clk(EPLL);
+ break;
+ case EXYNOS_SRC_VPLL:
+ sclk = exynos5_get_pll_clk(VPLL);
+ break;
+ default:
+ return 0;
+ }
+
+ /* Ratio clock division for this peripheral */
+ sub_div = (div >> bit_info->div_bit) & 0xf;
+ sub_clk = sclk / (sub_div + 1);
+
+ /* Pre-ratio clock division for SDMMC0 and 2 */
+ if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {
+ div = (div >> bit_info->prediv_bit) & 0xff;
+ return sub_clk / (div + 1);
+ }
+
+ return sub_clk;
+}
+
+unsigned long clock_get_periph_rate(int peripheral)
+{
+ if (cpu_is_exynos5())
+ return exynos5_get_periph_rate(peripheral);
+ else
+ return 0;
+}
+
+/* exynos5420: return pll clock frequency */
+static unsigned long exynos5420_get_pll_clk(int pllreg)
+{
+ struct exynos5420_clock *clk =
+ (struct exynos5420_clock *)samsung_get_base_clock();
+ unsigned long r, k = 0;
+
+ switch (pllreg) {
+ case APLL:
+ r = readl(&clk->apll_con0);
+ break;
+ case MPLL:
+ r = readl(&clk->mpll_con0);
+ break;
+ case EPLL:
+ r = readl(&clk->epll_con0);
+ k = readl(&clk->epll_con1);
+ break;
+ case VPLL:
+ r = readl(&clk->vpll_con0);
+ k = readl(&clk->vpll_con1);
+ break;
+ case BPLL:
+ r = readl(&clk->bpll_con0);
+ break;
+ case RPLL:
+ r = readl(&clk->rpll_con0);
+ k = readl(&clk->rpll_con1);
+ break;
+ default:
+ printf("Unsupported PLL (%d)\n", pllreg);
+ return 0;
+ }
+
+ return exynos_get_pll_clk(pllreg, r, k);
+}
+