|
|
|
/*
|
|
|
|
* Freescale i.MX23/i.MX28 clock setup code
|
|
|
|
*
|
|
|
|
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
|
|
|
* on behalf of DENX Software Engineering GmbH
|
|
|
|
*
|
|
|
|
* Based on code from LTIB:
|
|
|
|
* Copyright (C) 2010 Freescale Semiconductor, Inc.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/arch/clock.h>
|
|
|
|
#include <asm/arch/imx-regs.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The PLL frequency is 480MHz and XTAL frequency is 24MHz
|
|
|
|
* iMX23: datasheet section 4.2
|
|
|
|
* iMX28: datasheet section 10.2
|
|
|
|
*/
|
|
|
|
#define PLL_FREQ_KHZ 480000
|
|
|
|
#define PLL_FREQ_COEF 18
|
|
|
|
#define XTAL_FREQ_KHZ 24000
|
|
|
|
|
|
|
|
#define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000)
|
|
|
|
#define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000)
|
|
|
|
|
|
|
|
#if defined(CONFIG_MX23)
|
|
|
|
#define MXC_SSPCLK_MAX MXC_SSPCLK0
|
|
|
|
#elif defined(CONFIG_MX28)
|
|
|
|
#define MXC_SSPCLK_MAX MXC_SSPCLK3
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static uint32_t mxs_get_pclk(void)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
|
|
|
|
uint32_t clkctrl, clkseq, div;
|
|
|
|
uint8_t clkfrac, frac;
|
|
|
|
|
|
|
|
clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu);
|
|
|
|
|
|
|
|
/* No support of fractional divider calculation */
|
|
|
|
if (clkctrl &
|
|
|
|
(CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
|
|
|
|
|
|
|
/* XTAL Path */
|
|
|
|
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) {
|
|
|
|
div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >>
|
|
|
|
CLKCTRL_CPU_DIV_XTAL_OFFSET;
|
|
|
|
return XTAL_FREQ_MHZ / div;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* REF Path */
|
|
|
|
clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]);
|
|
|
|
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
|
|
|
|
div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK;
|
|
|
|
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t mxs_get_hclk(void)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
|
|
|
|
uint32_t div;
|
|
|
|
uint32_t clkctrl;
|
|
|
|
|
|
|
|
clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus);
|
|
|
|
|
|
|
|
/* No support of fractional divider calculation */
|
|
|
|
if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
div = clkctrl & CLKCTRL_HBUS_DIV_MASK;
|
|
|
|
return mxs_get_pclk() / div;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t mxs_get_emiclk(void)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
|
|
|
|
uint32_t clkctrl, clkseq, div;
|
|
|
|
uint8_t clkfrac, frac;
|
|
|
|
|
|
|
|
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
|
|
|
clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi);
|
|
|
|
|
|
|
|
/* XTAL Path */
|
|
|
|
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) {
|
|
|
|
div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >>
|
|
|
|
CLKCTRL_EMI_DIV_XTAL_OFFSET;
|
|
|
|
return XTAL_FREQ_MHZ / div;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* REF Path */
|
|
|
|
clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]);
|
|
|
|
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
|
|
|
|
div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK;
|
|
|
|
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t mxs_get_gpmiclk(void)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
#if defined(CONFIG_MX23)
|
|
|
|
uint8_t *reg =
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU];
|
|
|
|
#elif defined(CONFIG_MX28)
|
|
|
|
uint8_t *reg =
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI];
|
|
|
|
#endif
|
|
|
|
uint32_t clkctrl, clkseq, div;
|
|
|
|
uint8_t clkfrac, frac;
|
|
|
|
|
|
|
|
clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
|
|
|
clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi);
|
|
|
|
|
|
|
|
/* XTAL Path */
|
|
|
|
if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) {
|
|
|
|
div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
|
|
|
|
return XTAL_FREQ_MHZ / div;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* REF Path */
|
|
|
|
clkfrac = readb(reg);
|
|
|
|
frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK;
|
|
|
|
div = clkctrl & CLKCTRL_GPMI_DIV_MASK;
|
|
|
|
return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set IO clock frequency, in kHz
|
|
|
|
*/
|
|
|
|
void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
uint32_t div;
|
|
|
|
int io_reg;
|
|
|
|
|
|
|
|
if (freq == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
|
|
|
|
return;
|
|
|
|
|
|
|
|
div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq;
|
|
|
|
|
|
|
|
if (div < 18)
|
|
|
|
div = 18;
|
|
|
|
|
|
|
|
if (div > 35)
|
|
|
|
div = 35;
|
|
|
|
|
|
|
|
io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac0_set[io_reg]);
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK),
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac0[io_reg]);
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get IO clock, returns IO clock in kHz
|
|
|
|
*/
|
|
|
|
static uint32_t mxs_get_ioclk(enum mxs_ioclock io)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
uint8_t ret;
|
|
|
|
int io_reg;
|
|
|
|
|
|
|
|
if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */
|
|
|
|
|
|
|
|
ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) &
|
|
|
|
CLKCTRL_FRAC_FRAC_MASK;
|
|
|
|
|
|
|
|
return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure SSP clock frequency, in kHz
|
|
|
|
*/
|
|
|
|
void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
uint32_t clk, clkreg;
|
|
|
|
|
|
|
|
if (ssp > MXC_SSPCLK_MAX)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
|
|
|
|
(ssp * sizeof(struct mxs_register_32));
|
|
|
|
|
|
|
|
clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE);
|
|
|
|
while (readl(clkreg) & CLKCTRL_SSP_CLKGATE)
|
|
|
|
;
|
|
|
|
|
|
|
|
if (xtal)
|
|
|
|
clk = XTAL_FREQ_KHZ;
|
|
|
|
else
|
|
|
|
clk = mxs_get_ioclk(ssp >> 1);
|
|
|
|
|
|
|
|
if (freq > clk)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Calculate the divider and cap it if necessary */
|
|
|
|
clk /= freq;
|
|
|
|
if (clk > CLKCTRL_SSP_DIV_MASK)
|
|
|
|
clk = CLKCTRL_SSP_DIV_MASK;
|
|
|
|
|
|
|
|
clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk);
|
|
|
|
while (readl(clkreg) & CLKCTRL_SSP_BUSY)
|
|
|
|
;
|
|
|
|
|
|
|
|
if (xtal)
|
|
|
|
writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
|
|
|
|
&clkctrl_regs->hw_clkctrl_clkseq_set);
|
|
|
|
else
|
|
|
|
writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp,
|
|
|
|
&clkctrl_regs->hw_clkctrl_clkseq_clr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return SSP frequency, in kHz
|
|
|
|
*/
|
|
|
|
static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
uint32_t clkreg;
|
|
|
|
uint32_t clk, tmp;
|
|
|
|
|
|
|
|
if (ssp > MXC_SSPCLK_MAX)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq);
|
|
|
|
if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp))
|
|
|
|
return XTAL_FREQ_KHZ;
|
|
|
|
|
|
|
|
clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) +
|
|
|
|
(ssp * sizeof(struct mxs_register_32));
|
|
|
|
|
|
|
|
tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK;
|
|
|
|
|
|
|
|
if (tmp == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
clk = mxs_get_ioclk(ssp >> 1);
|
|
|
|
|
|
|
|
return clk / tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set SSP/MMC bus frequency, in kHz)
|
|
|
|
*/
|
|
|
|
void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq)
|
|
|
|
{
|
|
|
|
struct mxs_ssp_regs *ssp_regs;
|
mxs: mmc: spi: dma: Better wrap the MXS differences
This patch streamlines the differences between the MX23 and MX28 by
implementing a few helper functions to handle different DMA channel
mapping, different clock domain for SSP block and fixes a few minor
bugs.
First of all, the DMA channel mapping is now fixed in dma.h by defining
the actual channel map for both MX23 and MX28. Thus, MX23 now does no
longer use MX28 channel map which was wrong. Also, there is a fix for
MX28 DMA channel map, where the last four channels were incorrect.
Next, because correct DMA channel map is in place, the mxs_dma_init_channel()
call now bases the channel ID starting from SSP port #0. This removes the
need for DMA channel offset being added and cleans up the code. For the
same reason, the SSP0 offset can now be used in mxs_dma_desc_append(), thus
no need to adjust dma channel number in the driver either.
Lastly, the SSP clock ID is now retrieved by calling mxs_ssp_clock_by_bus()
which handles the fact that MX23 has shared SSP clock for both ports, while
MX28 has per-port SSP clock.
Finally, the mxs_ssp_bus_id_valid() pulls out two implementations of the
same functionality from MMC and SPI driver into common code.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Fabio Estevam <fabio.estevam@freescale.com>
Cc: Otavio Salvador <otavio@ossystems.com.br>
Cc: Stefano Babic <sbabic@denx.de>
12 years ago
|
|
|
const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus);
|
|
|
|
const uint32_t sspclk = mxs_get_sspclk(clk);
|
|
|
|
uint32_t reg;
|
|
|
|
uint32_t divide, rate, tgtclk;
|
|
|
|
|
|
|
|
ssp_regs = mxs_ssp_regs_by_bus(bus);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)),
|
|
|
|
* CLOCK_DIVIDE has to be an even value from 2 to 254, and
|
|
|
|
* CLOCK_RATE could be any integer from 0 to 255.
|
|
|
|
*/
|
|
|
|
for (divide = 2; divide < 254; divide += 2) {
|
|
|
|
rate = sspclk / freq / divide;
|
|
|
|
if (rate <= 256)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
tgtclk = sspclk / divide / rate;
|
|
|
|
while (tgtclk > freq) {
|
|
|
|
rate++;
|
|
|
|
tgtclk = sspclk / divide / rate;
|
|
|
|
}
|
|
|
|
if (rate > 256)
|
|
|
|
rate = 256;
|
|
|
|
|
|
|
|
/* Always set timeout the maximum */
|
|
|
|
reg = SSP_TIMING_TIMEOUT_MASK |
|
|
|
|
(divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) |
|
|
|
|
((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET);
|
|
|
|
writel(reg, &ssp_regs->hw_ssp_timing);
|
|
|
|
|
|
|
|
debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n",
|
|
|
|
bus, tgtclk, freq);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mxs_set_lcdclk(uint32_t __maybe_unused lcd_base, uint32_t freq)
|
|
|
|
{
|
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
uint32_t fp, x, k_rest, k_best, x_best, tk;
|
|
|
|
int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff;
|
|
|
|
|
|
|
|
if (freq == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#if defined(CONFIG_MX23)
|
|
|
|
writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr);
|
|
|
|
#elif defined(CONFIG_MX28)
|
|
|
|
writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* / 18 \ 1 1
|
|
|
|
* freq kHz = | 480000000 Hz * -- | * --- * ------
|
|
|
|
* \ x / k 1000
|
|
|
|
*
|
|
|
|
* 480000000 Hz 18
|
|
|
|
* ------------ * --
|
|
|
|
* freq kHz x
|
|
|
|
* k = -------------------
|
|
|
|
* 1000
|
|
|
|
*/
|
|
|
|
|
|
|
|
fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18;
|
|
|
|
|
|
|
|
for (x = 18; x <= 35; x++) {
|
|
|
|
tk = fp / x;
|
|
|
|
if ((tk / 1000 == 0) || (tk / 1000 > 255))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
k_rest = tk % 1000;
|
|
|
|
|
|
|
|
if (k_rest < (k_best_l % 1000)) {
|
|
|
|
k_best_l = tk;
|
|
|
|
x_best_l = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k_rest > (k_best_t % 1000)) {
|
|
|
|
k_best_t = tk;
|
|
|
|
x_best_t = x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) {
|
|
|
|
k_best = k_best_l;
|
|
|
|
x_best = x_best_l;
|
|
|
|
} else {
|
|
|
|
k_best = k_best_t;
|
|
|
|
x_best = x_best_t;
|
|
|
|
}
|
|
|
|
|
|
|
|
k_best /= 1000;
|
|
|
|
|
|
|
|
#if defined(CONFIG_MX23)
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]);
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]);
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]);
|
|
|
|
|
|
|
|
writel(CLKCTRL_PIX_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_pix_set);
|
|
|
|
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix,
|
|
|
|
CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE,
|
|
|
|
k_best << CLKCTRL_PIX_DIV_OFFSET);
|
|
|
|
|
|
|
|
while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY)
|
|
|
|
;
|
|
|
|
#elif defined(CONFIG_MX28)
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]);
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK),
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]);
|
|
|
|
writeb(CLKCTRL_FRAC_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]);
|
|
|
|
|
|
|
|
writel(CLKCTRL_DIS_LCDIF_CLKGATE,
|
|
|
|
&clkctrl_regs->hw_clkctrl_lcdif_set);
|
|
|
|
clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif,
|
|
|
|
CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE,
|
|
|
|
k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET);
|
|
|
|
|
|
|
|
while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY)
|
|
|
|
;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t mxc_get_clock(enum mxc_clock clk)
|
|
|
|
{
|
|
|
|
switch (clk) {
|
|
|
|
case MXC_ARM_CLK:
|
|
|
|
return mxs_get_pclk() * 1000000;
|
|
|
|
case MXC_GPMI_CLK:
|
|
|
|
return mxs_get_gpmiclk() * 1000000;
|
|
|
|
case MXC_AHB_CLK:
|
|
|
|
case MXC_IPG_CLK:
|
|
|
|
return mxs_get_hclk() * 1000000;
|
|
|
|
case MXC_EMI_CLK:
|
|
|
|
return mxs_get_emiclk();
|
|
|
|
case MXC_IO0_CLK:
|
|
|
|
return mxs_get_ioclk(MXC_IOCLK0);
|
|
|
|
case MXC_IO1_CLK:
|
|
|
|
return mxs_get_ioclk(MXC_IOCLK1);
|
|
|
|
case MXC_XTAL_CLK:
|
|
|
|
return XTAL_FREQ_KHZ * 1000;
|
|
|
|
case MXC_SSP0_CLK:
|
|
|
|
return mxs_get_sspclk(MXC_SSPCLK0);
|
|
|
|
#ifdef CONFIG_MX28
|
|
|
|
case MXC_SSP1_CLK:
|
|
|
|
return mxs_get_sspclk(MXC_SSPCLK1);
|
|
|
|
case MXC_SSP2_CLK:
|
|
|
|
return mxs_get_sspclk(MXC_SSPCLK2);
|
|
|
|
case MXC_SSP3_CLK:
|
|
|
|
return mxs_get_sspclk(MXC_SSPCLK3);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|