cregit-Linux how code gets into the kernel

Release 4.7 drivers/clk/nxp/clk-lpc18xx-cgu.c

Directory: drivers/clk/nxp
/*
 * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU)
 *
 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
 *
 * This file is licensed under the terms of the GNU General Public
 * License version 2. This program is licensed "as is" without any
 * warranty of any kind, whether express or implied.
 */

#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>

#include <dt-bindings/clock/lpc18xx-cgu.h>

/* Clock Generation Unit (CGU) registers */

#define LPC18XX_CGU_XTAL_OSC_CTRL	0x018

#define LPC18XX_CGU_PLL0USB_STAT	0x01c

#define LPC18XX_CGU_PLL0USB_CTRL	0x020

#define LPC18XX_CGU_PLL0USB_MDIV	0x024

#define LPC18XX_CGU_PLL0USB_NP_DIV	0x028

#define LPC18XX_CGU_PLL0AUDIO_STAT	0x02c

#define LPC18XX_CGU_PLL0AUDIO_CTRL	0x030

#define LPC18XX_CGU_PLL0AUDIO_MDIV	0x034

#define LPC18XX_CGU_PLL0AUDIO_NP_DIV	0x038

#define LPC18XX_CGU_PLL0AUDIO_FRAC	0x03c

#define LPC18XX_CGU_PLL1_STAT		0x040

#define LPC18XX_CGU_PLL1_CTRL		0x044

#define  LPC18XX_PLL1_CTRL_FBSEL	BIT(6)

#define  LPC18XX_PLL1_CTRL_DIRECT	BIT(7)

#define LPC18XX_CGU_IDIV_CTRL(n)	(0x048 + (n) * sizeof(u32))

#define LPC18XX_CGU_BASE_CLK(id)	(0x05c + (id) * sizeof(u32))

#define LPC18XX_CGU_PLL_CTRL_OFFSET	0x4

/* PLL0 bits common to both audio and USB PLL */

#define LPC18XX_PLL0_STAT_LOCK		BIT(0)

#define LPC18XX_PLL0_CTRL_PD		BIT(0)

#define LPC18XX_PLL0_CTRL_BYPASS	BIT(1)

#define LPC18XX_PLL0_CTRL_DIRECTI	BIT(2)

#define LPC18XX_PLL0_CTRL_DIRECTO	BIT(3)

#define LPC18XX_PLL0_CTRL_CLKEN		BIT(4)

#define LPC18XX_PLL0_MDIV_MDEC_MASK	0x1ffff

#define LPC18XX_PLL0_MDIV_SELP_SHIFT	17

#define LPC18XX_PLL0_MDIV_SELI_SHIFT	22

#define LPC18XX_PLL0_MSEL_MAX		BIT(15)

/* Register value that gives PLL0 post/pre dividers equal to 1 */

#define LPC18XX_PLL0_NP_DIVS_1		0x00302062

enum {
	
CLK_SRC_OSC32,
	
CLK_SRC_IRC,
	
CLK_SRC_ENET_RX_CLK,
	
CLK_SRC_ENET_TX_CLK,
	
CLK_SRC_GP_CLKIN,
	
CLK_SRC_RESERVED1,
	
CLK_SRC_OSC,
	
CLK_SRC_PLL0USB,
	
CLK_SRC_PLL0AUDIO,
	
CLK_SRC_PLL1,
	
CLK_SRC_RESERVED2,
	
CLK_SRC_RESERVED3,
	
CLK_SRC_IDIVA,
	
CLK_SRC_IDIVB,
	
CLK_SRC_IDIVC,
	
CLK_SRC_IDIVD,
	
CLK_SRC_IDIVE,
	
CLK_SRC_MAX
};


static const char *clk_src_names[CLK_SRC_MAX] = {
	[CLK_SRC_OSC32]		= "osc32",
	[CLK_SRC_IRC]		= "irc",
	[CLK_SRC_ENET_RX_CLK]	= "enet_rx_clk",
	[CLK_SRC_ENET_TX_CLK]	= "enet_tx_clk",
	[CLK_SRC_GP_CLKIN]	= "gp_clkin",
	[CLK_SRC_OSC]		= "osc",
	[CLK_SRC_PLL0USB]	= "pll0usb",
	[CLK_SRC_PLL0AUDIO]	= "pll0audio",
	[CLK_SRC_PLL1]		= "pll1",
	[CLK_SRC_IDIVA]		= "idiva",
	[CLK_SRC_IDIVB]		= "idivb",
	[CLK_SRC_IDIVC]		= "idivc",
	[CLK_SRC_IDIVD]		= "idivd",
	[CLK_SRC_IDIVE]		= "idive",
};


static const char *clk_base_names[BASE_CLK_MAX] = {
	[BASE_SAFE_CLK]		= "base_safe_clk",
	[BASE_USB0_CLK]		= "base_usb0_clk",
	[BASE_PERIPH_CLK]	= "base_periph_clk",
	[BASE_USB1_CLK]		= "base_usb1_clk",
	[BASE_CPU_CLK]		= "base_cpu_clk",
	[BASE_SPIFI_CLK]	= "base_spifi_clk",
	[BASE_SPI_CLK]		= "base_spi_clk",
	[BASE_PHY_RX_CLK]	= "base_phy_rx_clk",
	[BASE_PHY_TX_CLK]	= "base_phy_tx_clk",
	[BASE_APB1_CLK]		= "base_apb1_clk",
	[BASE_APB3_CLK]		= "base_apb3_clk",
	[BASE_LCD_CLK]		= "base_lcd_clk",
	[BASE_ADCHS_CLK]	= "base_adchs_clk",
	[BASE_SDIO_CLK]		= "base_sdio_clk",
	[BASE_SSP0_CLK]		= "base_ssp0_clk",
	[BASE_SSP1_CLK]		= "base_ssp1_clk",
	[BASE_UART0_CLK]	= "base_uart0_clk",
	[BASE_UART1_CLK]	= "base_uart1_clk",
	[BASE_UART2_CLK]	= "base_uart2_clk",
	[BASE_UART3_CLK]	= "base_uart3_clk",
	[BASE_OUT_CLK]		= "base_out_clk",
	[BASE_AUDIO_CLK]	= "base_audio_clk",
	[BASE_CGU_OUT0_CLK]	= "base_cgu_out0_clk",
	[BASE_CGU_OUT1_CLK]	= "base_cgu_out1_clk",
};


static u32 lpc18xx_cgu_pll0_src_ids[] = {
	CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
	CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
	CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
	CLK_SRC_IDIVD, CLK_SRC_IDIVE,
};


static u32 lpc18xx_cgu_pll1_src_ids[] = {
	CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
	CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
	CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA,
	CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
};


static u32 lpc18xx_cgu_idiva_src_ids[] = {
	CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
	CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
	CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1
};


static u32 lpc18xx_cgu_idivbcde_src_ids[] = {
	CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
	CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
	CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
};


static u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC};


static u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB};


static u32 lpc18xx_cgu_base_common_src_ids[] = {
	CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
	CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
	CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA,
	CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE,
};


static u32 lpc18xx_cgu_base_all_src_ids[] = {
	CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK,
	CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC,
	CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1,
	CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC,
	CLK_SRC_IDIVD, CLK_SRC_IDIVE,
};


struct lpc18xx_cgu_src_clk_div {
	
u8 clk_id;
	
u8 n_parents;
	
struct clk_divider	div;
	
struct clk_mux		mux;
	
struct clk_gate		gate;
};


#define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table)	\
{                                                       \
        .clk_id = CLK_SRC_ ##_id,                       \
        .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
        .div = {                                        \
                .shift = 2,                             \
                .width = _width,                        \
        },                                              \
        .mux = {                                        \
                .mask = 0x1f,                           \
                .shift = 24,                            \
                .table = lpc18xx_cgu_ ##_table,         \
        },                                              \
        .gate = {                                       \
                .bit_idx = 0,                           \
                .flags = CLK_GATE_SET_TO_DISABLE,       \
        },                                              \
}


static struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = {
	LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids),
	LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids),
	LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids),
	LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids),
	LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids),
};


struct lpc18xx_cgu_base_clk {
	
u8 clk_id;
	
u8 n_parents;
	
struct clk_mux mux;
	
struct clk_gate gate;
};


#define LPC1XX_CGU_BASE_CLK(_id, _table, _flags)	\
{                                                       \
        .clk_id = BASE_ ##_id ##_CLK,                   \
        .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
        .mux = {                                        \
                .mask = 0x1f,                           \
                .shift = 24,                            \
                .table = lpc18xx_cgu_ ##_table,         \
                .flags = _flags,                        \
        },                                              \
        .gate = {                                       \
                .bit_idx = 0,                           \
                .flags = CLK_GATE_SET_TO_DISABLE,       \
        },                                              \
}


static struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = {
	LPC1XX_CGU_BASE_CLK(SAFE,	base_irc_src_ids, CLK_MUX_READ_ONLY),
	LPC1XX_CGU_BASE_CLK(USB0,	base_usb0_src_ids,   0),
	LPC1XX_CGU_BASE_CLK(PERIPH,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(USB1,	base_all_src_ids,    0),
	LPC1XX_CGU_BASE_CLK(CPU,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(SPIFI,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(SPI,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(PHY_RX,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(PHY_TX,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(APB1,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(APB3,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(LCD,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(ADCHS,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(SDIO,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(SSP0,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(SSP1,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(UART0,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(UART1,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(UART2,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(UART3,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(OUT,	base_all_src_ids,    0),
	{ /* 21 reserved */ },
	{ /* 22 reserved */ },
	{ /* 23 reserved */ },
	{ /* 24 reserved */ },
	LPC1XX_CGU_BASE_CLK(AUDIO,	base_common_src_ids, 0),
	LPC1XX_CGU_BASE_CLK(CGU_OUT0,	base_all_src_ids,    0),
	LPC1XX_CGU_BASE_CLK(CGU_OUT1,	base_all_src_ids,    0),
};


struct lpc18xx_pll {
	
struct		clk_hw hw;
	
void __iomem	*reg;
	
spinlock_t	*lock;
	
u8		flags;
};


#define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw)


struct lpc18xx_cgu_pll_clk {
	
u8 clk_id;
	
u8 n_parents;
	
u8 reg_offset;
	
struct clk_mux mux;
	
struct clk_gate gate;
	
struct lpc18xx_pll pll;
	
const struct clk_ops *pll_ops;
};


#define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops)	\
{                                                       \
        .clk_id = CLK_SRC_ ##_id,                       \
        .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \
        .reg_offset = LPC18XX_CGU_ ##_id ##_STAT,       \
        .mux = {                                        \
                .mask = 0x1f,                           \
                .shift = 24,                            \
                .table = lpc18xx_cgu_ ##_table,         \
        },                                              \
        .gate = {                                       \
                .bit_idx = 0,                           \
                .flags = CLK_GATE_SET_TO_DISABLE,       \
        },                                              \
        .pll_ops = &lpc18xx_ ##_pll_ops,                \
}

/*
 * PLL0 uses a special register value encoding. The compute functions below
 * are taken or derived from the LPC1850 user manual (section 12.6.3.3).
 */

/* Compute PLL0 multiplier from decoded version */

static u32 lpc18xx_pll0_mdec2msel(u32 x) { int i; switch (x) { case 0x18003: return 1; case 0x10003: return 2; default: for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--) x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff); return i; } }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood75100.00%1100.00%
Total75100.00%1100.00%

/* Compute PLL0 decoded multiplier from binary version */
static u32 lpc18xx_pll0_msel2mdec(u32 msel) { u32 i, x = 0x4000; switch (msel) { case 0: return 0; case 1: return 0x18003; case 2: return 0x10003; default: for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++) x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff); return x; } }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood81100.00%1100.00%
Total81100.00%1100.00%

/* Compute PLL0 bandwidth SELI reg from multiplier */
static u32 lpc18xx_pll0_msel2seli(u32 msel) { u32 tmp; if (msel > 16384) return 1; if (msel > 8192) return 2; if (msel > 2048) return 4; if (msel >= 501) return 8; if (msel >= 60) { tmp = 1024 / (msel + 9); return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4; } return (msel & 0x3c) + 4; }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood106100.00%1100.00%
Total106100.00%1100.00%

/* Compute PLL0 bandwidth SELP reg from multiplier */
static u32 lpc18xx_pll0_msel2selp(u32 msel) { if (msel < 60) return (msel >> 1) + 1; return 31; }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood27100.00%1100.00%
Total27100.00%1100.00%


static unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct lpc18xx_pll *pll = to_lpc_pll(hw); u32 ctrl, mdiv, msel, npdiv; ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); mdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV); npdiv = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); if (ctrl & LPC18XX_PLL0_CTRL_BYPASS) return parent_rate; if (npdiv != LPC18XX_PLL0_NP_DIVS_1) { pr_warn("%s: pre/post dividers not supported\n", __func__); return 0; } msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK); if (msel) return 2 * msel * parent_rate; pr_warn("%s: unable to calculate rate\n", __func__); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood125100.00%1100.00%
Total125100.00%1100.00%


static long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { unsigned long m; if (*prate < rate) { pr_warn("%s: pll dividers not supported\n", __func__); return -EINVAL; } m = DIV_ROUND_UP_ULL(*prate, rate * 2); if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { pr_warn("%s: unable to support rate %lu\n", __func__, rate); return -EINVAL; } return 2 * *prate * m; }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood89100.00%1100.00%
Total89100.00%1100.00%


static int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct lpc18xx_pll *pll = to_lpc_pll(hw); u32 ctrl, stat, m; int retry = 3; if (parent_rate < rate) { pr_warn("%s: pll dividers not supported\n", __func__); return -EINVAL; } m = DIV_ROUND_UP_ULL(parent_rate, rate * 2); if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { pr_warn("%s: unable to support rate %lu\n", __func__, rate); return -EINVAL; } m = lpc18xx_pll0_msel2mdec(m); m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT; m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT; /* Power down PLL, disable clk output and dividers */ ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); ctrl |= LPC18XX_PLL0_CTRL_PD; ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI | LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN); clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); /* Configure new PLL settings */ clk_writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV); clk_writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); /* Power up PLL and wait for lock */ ctrl &= ~LPC18XX_PLL0_CTRL_PD; clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); do { udelay(10); stat = clk_readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT); if (stat & LPC18XX_PLL0_STAT_LOCK) { ctrl |= LPC18XX_PLL0_CTRL_CLKEN; clk_writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); return 0; } } while (retry--); pr_warn("%s: unable to lock pll\n", __func__); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood263100.00%1100.00%
Total263100.00%1100.00%

static const struct clk_ops lpc18xx_pll0_ops = { .recalc_rate = lpc18xx_pll0_recalc_rate, .round_rate = lpc18xx_pll0_round_rate, .set_rate = lpc18xx_pll0_set_rate, };
static unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct lpc18xx_pll *pll = to_lpc_pll(hw); u16 msel, nsel, psel; bool direct, fbsel; u32 stat, ctrl; stat = clk_readl(pll->reg + LPC18XX_CGU_PLL1_STAT); ctrl = clk_readl(pll->reg + LPC18XX_CGU_PLL1_CTRL); direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false; fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false; msel = ((ctrl >> 16) & 0xff) + 1; nsel = ((ctrl >> 12) & 0x3) + 1; if (direct || fbsel) return msel * (parent_rate / nsel); psel = (ctrl >> 8) & 0x3; psel = 1 << psel; return (msel / (2 * psel)) * (parent_rate / nsel); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood165100.00%1100.00%
Total165100.00%1100.00%

static const struct clk_ops lpc18xx_pll1_ops = { .recalc_rate = lpc18xx_pll1_recalc_rate, };
static int lpc18xx_cgu_gate_enable(struct clk_hw *hw) { return clk_gate_ops.enable(hw); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood19100.00%1100.00%
Total19100.00%1100.00%


static void lpc18xx_cgu_gate_disable(struct clk_hw *hw) { clk_gate_ops.disable(hw); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood18100.00%1100.00%
Total18100.00%1100.00%


static int lpc18xx_cgu_gate_is_enabled(struct clk_hw *hw) { const struct clk_hw *parent; /* * The consumer of base clocks needs know if the * base clock is really enabled before it can be * accessed. It is therefore necessary to verify * this all the way up. */ parent = clk_hw_get_parent(hw); if (!parent) return 0; if (!clk_hw_is_enabled(parent)) return 0; return clk_gate_ops.is_enabled(hw); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood52100.00%1100.00%
Total52100.00%1100.00%

static const struct clk_ops lpc18xx_gate_ops = { .enable = lpc18xx_cgu_gate_enable, .disable = lpc18xx_cgu_gate_disable, .is_enabled = lpc18xx_cgu_gate_is_enabled, }; static struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = { LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops), LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops), LPC1XX_CGU_CLK_PLL(PLL1, pll1_src_ids, pll1_ops), };
static void lpc18xx_fill_parent_names(const char **parent, u32 *id, int size) { int i; for (i = 0; i < size; i++) parent[i] = clk_src_names[id[i]]; }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood48100.00%1100.00%
Total48100.00%1100.00%


static struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk, void __iomem *base, int n) { void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n); const char *name = clk_src_names[clk->clk_id]; const char *parents[CLK_SRC_MAX]; clk->div.reg = reg; clk->mux.reg = reg; clk->gate.reg = reg; lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); return clk_register_composite(NULL, name, parents, clk->n_parents, &clk->mux.hw, &clk_mux_ops, &clk->div.hw, &clk_divider_ops, &clk->gate.hw, &lpc18xx_gate_ops, 0); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood138100.00%2100.00%
Total138100.00%2100.00%


static struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk, void __iomem *reg_base, int n) { void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n); const char *name = clk_base_names[clk->clk_id]; const char *parents[CLK_SRC_MAX]; if (clk->n_parents == 0) return ERR_PTR(-ENOENT); clk->mux.reg = reg; clk->gate.reg = reg; lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); /* SAFE_CLK can not be turned off */ if (n == BASE_SAFE_CLK) return clk_register_composite(NULL, name, parents, clk->n_parents, &clk->mux.hw, &clk_mux_ops, NULL, NULL, NULL, NULL, 0); return clk_register_composite(NULL, name, parents, clk->n_parents, &clk->mux.hw, &clk_mux_ops, NULL, NULL, &clk->gate.hw, &lpc18xx_gate_ops, 0); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood180100.00%2100.00%
Total180100.00%2100.00%


static struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk, void __iomem *base) { const char *name = clk_src_names[clk->clk_id]; const char *parents[CLK_SRC_MAX]; clk->pll.reg = base; clk->mux.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); return clk_register_composite(NULL, name, parents, clk->n_parents, &clk->mux.hw, &clk_mux_ops, &clk->pll.hw, clk->pll_ops, &clk->gate.hw, &lpc18xx_gate_ops, 0); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood136100.00%2100.00%
Total136100.00%2100.00%


static void __init lpc18xx_cgu_register_source_clks(struct device_node *np, void __iomem *base) { const char *parents[CLK_SRC_MAX]; struct clk *clk; int i; /* Register the internal 12 MHz RC oscillator (IRC) */ clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC], NULL, 0, 12000000); if (IS_ERR(clk)) pr_warn("%s: failed to register irc clk\n", __func__); /* Register crystal oscillator controlller */ parents[0] = of_clk_get_parent_name(np, 0); clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0], 0, base + LPC18XX_CGU_XTAL_OSC_CTRL, 0, CLK_GATE_SET_TO_DISABLE, NULL); if (IS_ERR(clk)) pr_warn("%s: failed to register osc clk\n", __func__); /* Register all PLLs */ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) { clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i], base); if (IS_ERR(clk)) pr_warn("%s: failed to register pll (%d)\n", __func__, i); } /* Register all clock dividers A-E */ for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) { clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i], base, i); if (IS_ERR(clk)) pr_warn("%s: failed to register div %d\n", __func__, i); } }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood21999.55%150.00%
stephen boydstephen boyd10.45%150.00%
Total220100.00%2100.00%

static struct clk *clk_base[BASE_CLK_MAX]; static struct clk_onecell_data clk_base_data = { .clks = clk_base, .clk_num = BASE_CLK_MAX, };
static void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base) { int i; for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) { clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i], reg_base, i); if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT) pr_warn("%s: register base clk %d failed\n", __func__, i); } }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood78100.00%1100.00%
Total78100.00%1100.00%


static void __init lpc18xx_cgu_init(struct device_node *np) { void __iomem *reg_base; reg_base = of_iomap(np, 0); if (!reg_base) { pr_warn("%s: failed to map address range\n", __func__); return; } lpc18xx_cgu_register_source_clks(np, reg_base); lpc18xx_cgu_register_base_clks(reg_base); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data); }

Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood63100.00%1100.00%
Total63100.00%1100.00%

CLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
joachim eastwoodjoachim eastwood307699.97%266.67%
stephen boydstephen boyd10.03%133.33%
Total3077100.00%3100.00%
Directory: drivers/clk/nxp
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}