/*
 * Copyright 2005 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

#ifndef __CLOCK_H

#define __CLOCK_H

/*!
 * @defgroup CLOCKS Clocking Setup and Retrieving
 * @ingroup MSL
 */

/*!
 * @file clock.h
 *
 * @brief API for setting up and retrieving clocks.
 *
 * This file contains API for setting up and retrieving clocks.
 *
 * @ingroup CLOCKS
 */

#include <asm/arch/platform.h>

/* PLL Register Offsets */
#define MXC_PLL_DP_CTL                  0x00
#define MXC_PLL_DP_CONFIG               0x04
#define MXC_PLL_DP_OP                   0x08
#define MXC_PLL_DP_MFD                  0x0C
#define MXC_PLL_DP_MFN                  0x10
#define MXC_PLL_DP_HFS_OP               0x1C
#define MXC_PLL_DP_HFS_MFD              0x20
#define MXC_PLL_DP_HFS_MFN              0x24

/* PLL Register Bit definitions */
#define MXC_PLL_DP_CTL_DPDCK0_2_EN      0x1000
#define MXC_PLL_DP_CTL_ADE              0x800
#define MXC_PLL_DP_CTL_REF_CLK_DIV      0x400
#define MXC_PLL_DP_CTL_HFSM             0x80
#define MXC_PLL_DP_CTL_PRE              0x40
#define MXC_PLL_DP_CTL_UPEN             0x20
#define MXC_PLL_DP_CTL_RST              0x10
#define MXC_PLL_DP_CTL_RCP              0x8
#define MXC_PLL_DP_CTL_PLM              0x4
#define MXC_PLL_DP_CTL_BRM0             0x2
#define MXC_PLL_DP_CTL_LRF              0x1

#define MXC_PLL_DP_OP_MFI_OFFSET        4
#define MXC_PLL_DP_OP_MFI_MASK          0xF
#define MXC_PLL_DP_OP_PDF_OFFSET        0
#define MXC_PLL_DP_OP_PDF_MASK          0xF

#define MXC_PLL_DP_MFD_OFFSET           0
#define MXC_PLL_DP_MFD_MASK             0x7FFFFFF

#define MXC_PLL_DP_MFN_OFFSET           0
#define MXC_PLL_DP_MFN_MASK             0x7FFFFFF

/* CRM AP Register Offsets */
#define MXC_CRMAP_ASCSR                 0x00
#define MXC_CRMAP_ACDR                  0x04
#define MXC_CRMAP_ACDER1                0x08
#define MXC_CRMAP_ACDER2                0x0C
#define MXC_CRMAP_ACGCR                 0x10
#define MXC_CRMAP_ACCGCR                0x14
#define MXC_CRMAP_AMLPMRA               0x18
#define MXC_CRMAP_AMLPMRB               0x1C
#define MXC_CRMAP_AMLPMRC               0x20
#define MXC_CRMAP_AMLPMRD               0x24
#define MXC_CRMAP_AMLPMRE1              0x28
#define MXC_CRMAP_AMLPMRE2              0x2C
#define MXC_CRMAP_AMLPMRF               0x30
#define MXC_CRMAP_AMLPMRG               0x34
#define MXC_CRMAP_APGCR                 0x38
#define MXC_CRMAP_ACSR                  0x3C
#define MXC_CRMAP_ADCR                  0x40
#define MXC_CRMAP_ACR                   0x44
#define MXC_CRMAP_AMCR                  0x48
#define MXC_CRMAP_APCR                  0x4C
#define MXC_CRMAP_AMORA                 0x50
#define MXC_CRMAP_AMORB                 0x54
#define MXC_CRMAP_AGPR                  0x58
#define MXC_CRMAP_APRA                  0x5C
#define MXC_CRMAP_APRB                  0x60
#define MXC_CRMAP_APOR                  0x64

/* CRM AP Register Bit definitions */
#define MXC_CRMAP_ASCSR_CRS                     0x10000
#define MXC_CRMAP_ASCSR_AP_PATDIV2_OFFSET       15
#define MXC_CRMAP_ASCSR_AP_PATREF_DIV2          0x8000
#define MXC_CRMAP_ASCSR_USBSEL_OFFSET           13
#define MXC_CRMAP_ASCSR_USBSEL_MASK             (0x3 << 13)
#define MXC_CRMAP_ASCSR_CSISEL_OFFSET           11
#define MXC_CRMAP_ASCSR_CSISEL_MASK             (0x3 << 11)
#define MXC_CRMAP_ASCSR_SSI2SEL_OFFSET          7
#define MXC_CRMAP_ASCSR_SSI2SEL_MASK            (0x3 << 7)
#define MXC_CRMAP_ASCSR_SSI1SEL_OFFSET          5
#define MXC_CRMAP_ASCSR_SSI1SEL_MASK            (0x3 << 5)
#define MXC_CRMAP_ASCSR_APSEL_OFFSET            3
#define MXC_CRMAP_ASCSR_APSEL_MASK              (0x3 << 3)
#define MXC_CRMAP_ASCSR_AP_PATDIV1_OFFSET       2
#define MXC_CRMAP_ASCSR_AP_PATREF_DIV1          0x4
#define MXC_CRMAP_ASCSR_APISEL                  0x1

#define MXC_CRMAP_ACDR_ARMDIV_OFFSET            8
#define MXC_CRMAP_ACDR_ARMDIV_MASK              (0xF << 8)
#define MXC_CRMAP_ACDR_AHBDIV_OFFSET            4
#define MXC_CRMAP_ACDR_AHBDIV_MASK              (0xF << 4)
#define MXC_CRMAP_ACDR_IPDIV_OFFSET             0
#define MXC_CRMAP_ACDR_IPDIV_MASK               0xF

#define MXC_CRMAP_ACDER1_CSIEN                  0x10000000
#define MXC_CRMAP_ACDER1_CSIDIV_OFFSET          24
#define MXC_CRMAP_ACDER1_CSIDIV_MASK            (0xF << 24)
#define MXC_CRMAP_ACDER1_SSI2EN                 0x4000
#define MXC_CRMAP_ACDER1_SSI2DIV_OFFSET         8
#define MXC_CRMAP_ACDER1_SSI2DIV_MASK           (0x3F << 8)
#define MXC_CRMAP_ACDER1_SSI1EN                 0x40
#define MXC_CRMAP_ACDER1_SSI1DIV_OFFSET         0
#define MXC_CRMAP_ACDER1_SSI1DIV_MASK           0x3F

#define MXC_CRMAP_ACDER2_NFCEN                  0x00100000
#define MXC_CRMAP_ACDER2_NFCDIV_OFFSET          16
#define MXC_CRMAP_ACDER2_NFCDIV_MASK            (0xF << 16)
#define MXC_CRMAP_ACDER2_USBEN                  0x1000
#define MXC_CRMAP_ACDER2_USBDIV_OFFSET          8
#define MXC_CRMAP_ACDER2_USBDIV_MASK            (0xF << 8)
#define MXC_CRMAP_ACDER2_BAUDDIV_OFFSET         0
#define MXC_CRMAP_ACDER2_BAUDDIV_MASK           0xF

#define MXC_CRMAP_AMLPMRA_MLPMA6_OFFSET         19  
#define MXC_CRMAP_AMLPMRA_MLPMA6_MASK           (0x7 << 19)
#define MXC_CRMAP_AMLPMRA_MLPMA4_OFFSET         12
#define MXC_CRMAP_AMLPMRA_MLPMA4_MASK           (0x7 << 12)
#define MXC_CRMAP_AMLPMRA_MLPMA3_OFFSET         9
#define MXC_CRMAP_AMLPMRA_MLPMA3_MASK           (0x7 << 9)
#define MXC_CRMAP_AMLPMRA_MLPMA2_OFFSET         6
#define MXC_CRMAP_AMLPMRA_MLPMA2_MASK           (0x7 << 6)
#define MXC_CRMAP_AMLPMRA_MLPMA1_OFFSET         3
#define MXC_CRMAP_AMLPMRA_MLPMA1_MASK           (0x7 << 3)

#define MXC_CRMAP_AMLPMRB_MLPMB0_OFFSET         0
#define MXC_CRMAP_AMLPMRB_MLPMB0_MASK           0x7

#define MXC_CRMAP_AMLPMRC_MLPMC9_OFFSET         28
#define MXC_CRMAP_AMLPMRC_MLPMC9_MASK           (0x7 << 28)
#define MXC_CRMAP_AMLPMRC_MLPMC7_OFFSET         22
#define MXC_CRMAP_AMLPMRC_MLPMC7_MASK           (0x7 << 22)
#define MXC_CRMAP_AMLPMRC_MLPMC5_OFFSET         16
#define MXC_CRMAP_AMLPMRC_MLPMC5_MASK           (0x7 << 16)
#define MXC_CRMAP_AMLPMRC_MLPMC4_OFFSET         12
#define MXC_CRMAP_AMLPMRC_MLPMC4_MASK           (0x7 << 12)
#define MXC_CRMAP_AMLPMRC_MLPMC3_OFFSET         9
#define MXC_CRMAP_AMLPMRC_MLPMC3_MASK           (0x7 << 9)
#define MXC_CRMAP_AMLPMRC_MLPMC2_OFFSET         6
#define MXC_CRMAP_AMLPMRC_MLPMC2_MASK           (0x7 << 6)
#define MXC_CRMAP_AMLPMRC_MLPMC1_OFFSET         3
#define MXC_CRMAP_AMLPMRC_MLPMC1_MASK           (0x7 << 3)
#define MXC_CRMAP_AMLPMRC_MLPMC0_OFFSET         0
#define MXC_CRMAP_AMLPMRC_MLPMC0_MASK           0x7 
        
#define MXC_CRMAP_AMLPMRD_MLPMD7_OFFSET         22
#define MXC_CRMAP_AMLPMRD_MLPMD7_MASK           (0x7 << 22) 
#define MXC_CRMAP_AMLPMRD_MLPMD2_OFFSET         6
#define MXC_CRMAP_AMLPMRD_MLPMD2_MASK           (0x7 << 6) 
#define MXC_CRMAP_AMLPMRD_MLPMD0_OFFSET         0
#define MXC_CRMAP_AMLPMRD_MLPMD0_MASK           0x7 

#define MXC_CRMAP_AMLPMRE1_MLPME9_OFFSET        28
#define MXC_CRMAP_AMLPMRE1_MLPME9_MASK          (0x7 << 28)
#define MXC_CRMAP_AMLPMRE1_MLPME8_OFFSET        25
#define MXC_CRMAP_AMLPMRE1_MLPME8_MASK          (0x7 << 25)
#define MXC_CRMAP_AMLPMRE1_MLPME7_OFFSET        22
#define MXC_CRMAP_AMLPMRE1_MLPME7_MASK          (0x7 << 22)
#define MXC_CRMAP_AMLPMRE1_MLPME6_OFFSET        19
#define MXC_CRMAP_AMLPMRE1_MLPME6_MASK          (0x7 << 19)
#define MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET        16
#define MXC_CRMAP_AMLPMRE1_MLPME5_MASK          (0x7 << 16)
#define MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET        12
#define MXC_CRMAP_AMLPMRE1_MLPME4_MASK          (0x7 << 12)
#define MXC_CRMAP_AMLPMRE1_MLPME3_OFFSET        9
#define MXC_CRMAP_AMLPMRE1_MLPME3_MASK          (0x7 << 9)
#define MXC_CRMAP_AMLPMRE1_MLPME1_OFFSET        3
#define MXC_CRMAP_AMLPMRE1_MLPME1_MASK          (0x7 << 3)
#define MXC_CRMAP_AMLPMRE1_MLPME0_OFFSET        0     
#define MXC_CRMAP_AMLPMRE1_MLPME0_MASK          0x7     

#define MXC_CRMAP_AMLPMRE2_MLPME0_OFFSET        0
#define MXC_CRMAP_AMLPMRE2_MLPME0_MASK          0x7

#define MXC_CRMAP_AMLPMRF_MLPMF6_OFFSET         19
#define MXC_CRMAP_AMLPMRF_MLPMF6_MASK           (0x7 << 19)
#define MXC_CRMAP_AMLPMRF_MLPMF5_OFFSET         16
#define MXC_CRMAP_AMLPMRF_MLPMF5_MASK           (0x7 << 16)
#define MXC_CRMAP_AMLPMRF_MLPMF3_OFFSET         9
#define MXC_CRMAP_AMLPMRF_MLPMF3_MASK           (0x7 << 9)
#define MXC_CRMAP_AMLPMRF_MLPMF2_OFFSET         6
#define MXC_CRMAP_AMLPMRF_MLPMF2_MASK           (0x7 << 6)
#define MXC_CRMAP_AMLPMRF_MLPMF1_OFFSET         3
#define MXC_CRMAP_AMLPMRF_MLPMF1_MASK           (0x7 << 3)

#define MXC_CRMAP_AMLPMRG_MLPMG9_OFFSET         28
#define MXC_CRMAP_AMLPMRG_MLPMG9_MASK           (0x7 << 28)
#define MXC_CRMAP_AMLPMRG_MLPMG7_OFFSET         22
#define MXC_CRMAP_AMLPMRG_MLPMG7_MASK           (0x7 << 22)
#define MXC_CRMAP_AMLPMRG_MLPMG6_OFFSET         19
#define MXC_CRMAP_AMLPMRG_MLPMG6_MASK           (0x7 << 19)
#define MXC_CRMAP_AMLPMRG_MLPMG5_OFFSET         16
#define MXC_CRMAP_AMLPMRG_MLPMG5_MASK           (0x7 << 16)
#define MXC_CRMAP_AMLPMRG_MLPMG4_OFFSET         12
#define MXC_CRMAP_AMLPMRG_MLPMG4_MASK           (0x7 << 12)
#define MXC_CRMAP_AMLPMRG_MLPMG3_OFFSET         9
#define MXC_CRMAP_AMLPMRG_MLPMG3_MASK           (0x7 << 9)
#define MXC_CRMAP_AMLPMRG_MLPMG2_OFFSET         6
#define MXC_CRMAP_AMLPMRG_MLPMG2_MASK           (0x7 << 6)
#define MXC_CRMAP_AMLPMRG_MLPMG1_OFFSET         3
#define MXC_CRMAP_AMLPMRG_MLPMG1_MASK           (0x7 << 3)
#define MXC_CRMAP_AMLPMRG_MLPMG0_OFFSET         0
#define MXC_CRMAP_AMLPMRG_MLPMG0_MASK           0x7
 
#define MXC_CRMAP_APRA_UART1EN                  0x1
#define MXC_CRMAP_APRA_UART2EN                  0x100
#define MXC_CRMAP_APRA_UART3EN                  0x10000
#define MXC_CRMAP_APRA_SIMEN                    0x1000000
#define MXC_CRMAP_APRA_UART3DIV_OFFSET          17
#define MXC_CRMAP_APRA_UART3DIV_MASK            (0xF << 17)

#define MXC_CRMAP_APRB_SDHC1EN                  0x1
#define MXC_CRMAP_APRB_SDHC2EN                  0x100

#define MXC_CRMAP_ACSR_ACS                      0x1

#define MXC_CRMAP_ADCR_LFDF_OFFSET              8
#define MXC_CRMAP_ADCR_LFDF_MASK                (0x3 << 8)
#define MXC_CRMAP_ADCR_ALT_PLL                  0x80
#define MXC_CRMAP_ADCR_DFS_DIVEN                0x20
#define MXC_CRMAP_ADCR_DIV_BYP                  0x2

#define MXC_PLL_REF_CLK                         26000000
#define NO_UPDATE                               -1

/*!
 * Enumerations for plls
 */
enum plls {
        MCUPLL = 0, // MCU PLL
        USBPLL = 2, // USB PLL
        DSPPLL = 1, // DSP PLL
};

/*!
 * Enumerations for MXC clocks
 */
enum mxc_clocks {
        CPU_CLK,
        AHB_CLK,
        IPG_CLK,
        NFC_CLK,
        USB_CLK,
        UART1_BAUD,
        UART2_BAUD,
        UART3_BAUD,
        SSI1_BAUD,
        SSI2_BAUD,
        CSI_BAUD,
        I2C_CLK,
        CSPI1_CLK,
        CSPI2_CLK,
        GPT_CLK,
        RTC_CLK,
        EPIT1_CLK,
        EDIO_CLK,
        WDOG_CLK,
        PWM_CLK,
        IPU_CLK,
        SIM1_CLK,
        HAC_CLK,
        GEM_CLK,
        SDHC2_CLK,
        SDHC1_CLK,
        SDMA_CLK,
        RNG_CLK,
        KPP_CLK,
        MU_CLK,
        RTIC_CLK,
        SCC_CLK,
        SPBA_CLK,
        DSM_CLK,
};

/*!
 * This function is used to modify PLL registers to generate the required
 * frequency.
 *
 * @param  pll      the PLL that you wish to modify
 * @param  mfi      multiplication factor integer part
 * @param  pdf      pre-division factor
 * @param  mfd      multiplication factor denominator
 * @param  mfn      multiplication factor numerator
 */
void mxc_pll_set(enum plls pll, unsigned int mfi, unsigned int pdf,
                 unsigned int mfd, unsigned int mfn);

/*!
 * This function is used to get PLL registers values used generate the clock
 * frequency.
 *
 * @param  pll      the PLL that you wish to access
 * @param  mfi      pointer that holds multiplication factor integer part
 * @param  pdf      pointer that holds pre-division factor
 * @param  mfd      pointer that holds multiplication factor denominator
 * @param  mfn      pointer that holds multiplication factor numerator
 */
void mxc_pll_get(enum plls pll, unsigned int *mfi, unsigned int *pdf,
                 unsigned int *mfd, unsigned int *mfn);

/*!
 * This function returns the PLL output value in Hz based on pll.
 *
 * @param       pll     PLL as defined in enum plls
 *
 * @return      PLL value in Hz.
 */
unsigned long mxc_pll_clock(enum plls pll);

/*!
 * This function returns the clock value in Hz for various MXC modules.
 *
 * @param       clk     as defined in enum mxc_clocks
 *
 * @return      clock value in Hz
 */
unsigned long mxc_get_clocks(enum mxc_clocks clk);

/*!
 * This function sets the PLL source for a clock.
 *
 * @param clk     as defined in enum mxc_clocks
 * @param pll_num the PLL that you wish to use as source for this clock
 */
void mxc_set_clocks_pll(enum mxc_clocks clk, enum plls pll_num);

/*!
 * This function sets the division factor for a clock.
 *
 * @param clk as defined in enum mxc_clocks
 * @param div the division factor to be used for the clock (For SSI, pass in
 *            2 times the expected division value to account for FP vals)
 */
void mxc_set_clocks_div(enum mxc_clocks clk, unsigned int div);

/*!
 * This function returns the peripheral clock dividers.
 * Note that for SSI divider, in order to maintain the accuracy, the returned
 * divider is doubled.
 *
 * @param       clk     peripheral clock as defined in enum mxc_clocks
 *
 * @return      divider value
 */
unsigned long mxc_peri_clock_divider(enum mxc_clocks clk);

/*!
 * This function returns the main clock dividers.
 *
 * @param       clk     peripheral clock as defined in enum mxc_clocks
 *
 * @return      divider value
 */
unsigned long mxc_main_clock_divider(enum mxc_clocks clk);

/*!
 * This function returns the DFS block divider - LFDF value
 *
 * @return      Low Voltage frequency Divider Factor value
 */
unsigned int mxc_get_lfdf_value(void);

/*!
 * This function is called to gate off the individual module clocks
 *
 * @param clks     as defined in enum mxc_clocks
 */
void mxc_clks_disable(enum mxc_clocks clks);

/*!
 * This function is called to enable the individual module clocks
 *
 * @param clks     as defined in enum mxc_clocks
 */
void mxc_clks_enable(enum mxc_clocks clks);
#endif /* __CLOCK_H */
