162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk-provider.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/of_address.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <dt-bindings/clock/lpc18xx-cgu.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Clock Generation Unit (CGU) registers */ 1862306a36Sopenharmony_ci#define LPC18XX_CGU_XTAL_OSC_CTRL 0x018 1962306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0USB_STAT 0x01c 2062306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0USB_CTRL 0x020 2162306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0USB_MDIV 0x024 2262306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0USB_NP_DIV 0x028 2362306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0AUDIO_STAT 0x02c 2462306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0AUDIO_CTRL 0x030 2562306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0AUDIO_MDIV 0x034 2662306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0AUDIO_NP_DIV 0x038 2762306a36Sopenharmony_ci#define LPC18XX_CGU_PLL0AUDIO_FRAC 0x03c 2862306a36Sopenharmony_ci#define LPC18XX_CGU_PLL1_STAT 0x040 2962306a36Sopenharmony_ci#define LPC18XX_CGU_PLL1_CTRL 0x044 3062306a36Sopenharmony_ci#define LPC18XX_PLL1_CTRL_FBSEL BIT(6) 3162306a36Sopenharmony_ci#define LPC18XX_PLL1_CTRL_DIRECT BIT(7) 3262306a36Sopenharmony_ci#define LPC18XX_CGU_IDIV_CTRL(n) (0x048 + (n) * sizeof(u32)) 3362306a36Sopenharmony_ci#define LPC18XX_CGU_BASE_CLK(id) (0x05c + (id) * sizeof(u32)) 3462306a36Sopenharmony_ci#define LPC18XX_CGU_PLL_CTRL_OFFSET 0x4 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* PLL0 bits common to both audio and USB PLL */ 3762306a36Sopenharmony_ci#define LPC18XX_PLL0_STAT_LOCK BIT(0) 3862306a36Sopenharmony_ci#define LPC18XX_PLL0_CTRL_PD BIT(0) 3962306a36Sopenharmony_ci#define LPC18XX_PLL0_CTRL_BYPASS BIT(1) 4062306a36Sopenharmony_ci#define LPC18XX_PLL0_CTRL_DIRECTI BIT(2) 4162306a36Sopenharmony_ci#define LPC18XX_PLL0_CTRL_DIRECTO BIT(3) 4262306a36Sopenharmony_ci#define LPC18XX_PLL0_CTRL_CLKEN BIT(4) 4362306a36Sopenharmony_ci#define LPC18XX_PLL0_MDIV_MDEC_MASK 0x1ffff 4462306a36Sopenharmony_ci#define LPC18XX_PLL0_MDIV_SELP_SHIFT 17 4562306a36Sopenharmony_ci#define LPC18XX_PLL0_MDIV_SELI_SHIFT 22 4662306a36Sopenharmony_ci#define LPC18XX_PLL0_MSEL_MAX BIT(15) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Register value that gives PLL0 post/pre dividers equal to 1 */ 4962306a36Sopenharmony_ci#define LPC18XX_PLL0_NP_DIVS_1 0x00302062 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cienum { 5262306a36Sopenharmony_ci CLK_SRC_OSC32, 5362306a36Sopenharmony_ci CLK_SRC_IRC, 5462306a36Sopenharmony_ci CLK_SRC_ENET_RX_CLK, 5562306a36Sopenharmony_ci CLK_SRC_ENET_TX_CLK, 5662306a36Sopenharmony_ci CLK_SRC_GP_CLKIN, 5762306a36Sopenharmony_ci CLK_SRC_RESERVED1, 5862306a36Sopenharmony_ci CLK_SRC_OSC, 5962306a36Sopenharmony_ci CLK_SRC_PLL0USB, 6062306a36Sopenharmony_ci CLK_SRC_PLL0AUDIO, 6162306a36Sopenharmony_ci CLK_SRC_PLL1, 6262306a36Sopenharmony_ci CLK_SRC_RESERVED2, 6362306a36Sopenharmony_ci CLK_SRC_RESERVED3, 6462306a36Sopenharmony_ci CLK_SRC_IDIVA, 6562306a36Sopenharmony_ci CLK_SRC_IDIVB, 6662306a36Sopenharmony_ci CLK_SRC_IDIVC, 6762306a36Sopenharmony_ci CLK_SRC_IDIVD, 6862306a36Sopenharmony_ci CLK_SRC_IDIVE, 6962306a36Sopenharmony_ci CLK_SRC_MAX 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic const char *clk_src_names[CLK_SRC_MAX] = { 7362306a36Sopenharmony_ci [CLK_SRC_OSC32] = "osc32", 7462306a36Sopenharmony_ci [CLK_SRC_IRC] = "irc", 7562306a36Sopenharmony_ci [CLK_SRC_ENET_RX_CLK] = "enet_rx_clk", 7662306a36Sopenharmony_ci [CLK_SRC_ENET_TX_CLK] = "enet_tx_clk", 7762306a36Sopenharmony_ci [CLK_SRC_GP_CLKIN] = "gp_clkin", 7862306a36Sopenharmony_ci [CLK_SRC_OSC] = "osc", 7962306a36Sopenharmony_ci [CLK_SRC_PLL0USB] = "pll0usb", 8062306a36Sopenharmony_ci [CLK_SRC_PLL0AUDIO] = "pll0audio", 8162306a36Sopenharmony_ci [CLK_SRC_PLL1] = "pll1", 8262306a36Sopenharmony_ci [CLK_SRC_IDIVA] = "idiva", 8362306a36Sopenharmony_ci [CLK_SRC_IDIVB] = "idivb", 8462306a36Sopenharmony_ci [CLK_SRC_IDIVC] = "idivc", 8562306a36Sopenharmony_ci [CLK_SRC_IDIVD] = "idivd", 8662306a36Sopenharmony_ci [CLK_SRC_IDIVE] = "idive", 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const char *clk_base_names[BASE_CLK_MAX] = { 9062306a36Sopenharmony_ci [BASE_SAFE_CLK] = "base_safe_clk", 9162306a36Sopenharmony_ci [BASE_USB0_CLK] = "base_usb0_clk", 9262306a36Sopenharmony_ci [BASE_PERIPH_CLK] = "base_periph_clk", 9362306a36Sopenharmony_ci [BASE_USB1_CLK] = "base_usb1_clk", 9462306a36Sopenharmony_ci [BASE_CPU_CLK] = "base_cpu_clk", 9562306a36Sopenharmony_ci [BASE_SPIFI_CLK] = "base_spifi_clk", 9662306a36Sopenharmony_ci [BASE_SPI_CLK] = "base_spi_clk", 9762306a36Sopenharmony_ci [BASE_PHY_RX_CLK] = "base_phy_rx_clk", 9862306a36Sopenharmony_ci [BASE_PHY_TX_CLK] = "base_phy_tx_clk", 9962306a36Sopenharmony_ci [BASE_APB1_CLK] = "base_apb1_clk", 10062306a36Sopenharmony_ci [BASE_APB3_CLK] = "base_apb3_clk", 10162306a36Sopenharmony_ci [BASE_LCD_CLK] = "base_lcd_clk", 10262306a36Sopenharmony_ci [BASE_ADCHS_CLK] = "base_adchs_clk", 10362306a36Sopenharmony_ci [BASE_SDIO_CLK] = "base_sdio_clk", 10462306a36Sopenharmony_ci [BASE_SSP0_CLK] = "base_ssp0_clk", 10562306a36Sopenharmony_ci [BASE_SSP1_CLK] = "base_ssp1_clk", 10662306a36Sopenharmony_ci [BASE_UART0_CLK] = "base_uart0_clk", 10762306a36Sopenharmony_ci [BASE_UART1_CLK] = "base_uart1_clk", 10862306a36Sopenharmony_ci [BASE_UART2_CLK] = "base_uart2_clk", 10962306a36Sopenharmony_ci [BASE_UART3_CLK] = "base_uart3_clk", 11062306a36Sopenharmony_ci [BASE_OUT_CLK] = "base_out_clk", 11162306a36Sopenharmony_ci [BASE_AUDIO_CLK] = "base_audio_clk", 11262306a36Sopenharmony_ci [BASE_CGU_OUT0_CLK] = "base_cgu_out0_clk", 11362306a36Sopenharmony_ci [BASE_CGU_OUT1_CLK] = "base_cgu_out1_clk", 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic u32 lpc18xx_cgu_pll0_src_ids[] = { 11762306a36Sopenharmony_ci CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, 11862306a36Sopenharmony_ci CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, 11962306a36Sopenharmony_ci CLK_SRC_PLL1, CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC, 12062306a36Sopenharmony_ci CLK_SRC_IDIVD, CLK_SRC_IDIVE, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic u32 lpc18xx_cgu_pll1_src_ids[] = { 12462306a36Sopenharmony_ci CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, 12562306a36Sopenharmony_ci CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, 12662306a36Sopenharmony_ci CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_IDIVA, 12762306a36Sopenharmony_ci CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic u32 lpc18xx_cgu_idiva_src_ids[] = { 13162306a36Sopenharmony_ci CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, 13262306a36Sopenharmony_ci CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, 13362306a36Sopenharmony_ci CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic u32 lpc18xx_cgu_idivbcde_src_ids[] = { 13762306a36Sopenharmony_ci CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, 13862306a36Sopenharmony_ci CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, 13962306a36Sopenharmony_ci CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA, 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic u32 lpc18xx_cgu_base_irc_src_ids[] = {CLK_SRC_IRC}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic u32 lpc18xx_cgu_base_usb0_src_ids[] = {CLK_SRC_PLL0USB}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic u32 lpc18xx_cgu_base_common_src_ids[] = { 14762306a36Sopenharmony_ci CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, 14862306a36Sopenharmony_ci CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, 14962306a36Sopenharmony_ci CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, CLK_SRC_IDIVA, 15062306a36Sopenharmony_ci CLK_SRC_IDIVB, CLK_SRC_IDIVC, CLK_SRC_IDIVD, CLK_SRC_IDIVE, 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic u32 lpc18xx_cgu_base_all_src_ids[] = { 15462306a36Sopenharmony_ci CLK_SRC_OSC32, CLK_SRC_IRC, CLK_SRC_ENET_RX_CLK, 15562306a36Sopenharmony_ci CLK_SRC_ENET_TX_CLK, CLK_SRC_GP_CLKIN, CLK_SRC_OSC, 15662306a36Sopenharmony_ci CLK_SRC_PLL0USB, CLK_SRC_PLL0AUDIO, CLK_SRC_PLL1, 15762306a36Sopenharmony_ci CLK_SRC_IDIVA, CLK_SRC_IDIVB, CLK_SRC_IDIVC, 15862306a36Sopenharmony_ci CLK_SRC_IDIVD, CLK_SRC_IDIVE, 15962306a36Sopenharmony_ci}; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistruct lpc18xx_cgu_src_clk_div { 16262306a36Sopenharmony_ci u8 clk_id; 16362306a36Sopenharmony_ci u8 n_parents; 16462306a36Sopenharmony_ci struct clk_divider div; 16562306a36Sopenharmony_ci struct clk_mux mux; 16662306a36Sopenharmony_ci struct clk_gate gate; 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci#define LPC1XX_CGU_SRC_CLK_DIV(_id, _width, _table) \ 17062306a36Sopenharmony_ci{ \ 17162306a36Sopenharmony_ci .clk_id = CLK_SRC_ ##_id, \ 17262306a36Sopenharmony_ci .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ 17362306a36Sopenharmony_ci .div = { \ 17462306a36Sopenharmony_ci .shift = 2, \ 17562306a36Sopenharmony_ci .width = _width, \ 17662306a36Sopenharmony_ci }, \ 17762306a36Sopenharmony_ci .mux = { \ 17862306a36Sopenharmony_ci .mask = 0x1f, \ 17962306a36Sopenharmony_ci .shift = 24, \ 18062306a36Sopenharmony_ci .table = lpc18xx_cgu_ ##_table, \ 18162306a36Sopenharmony_ci }, \ 18262306a36Sopenharmony_ci .gate = { \ 18362306a36Sopenharmony_ci .bit_idx = 0, \ 18462306a36Sopenharmony_ci .flags = CLK_GATE_SET_TO_DISABLE, \ 18562306a36Sopenharmony_ci }, \ 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic struct lpc18xx_cgu_src_clk_div lpc18xx_cgu_src_clk_divs[] = { 18962306a36Sopenharmony_ci LPC1XX_CGU_SRC_CLK_DIV(IDIVA, 2, idiva_src_ids), 19062306a36Sopenharmony_ci LPC1XX_CGU_SRC_CLK_DIV(IDIVB, 4, idivbcde_src_ids), 19162306a36Sopenharmony_ci LPC1XX_CGU_SRC_CLK_DIV(IDIVC, 4, idivbcde_src_ids), 19262306a36Sopenharmony_ci LPC1XX_CGU_SRC_CLK_DIV(IDIVD, 4, idivbcde_src_ids), 19362306a36Sopenharmony_ci LPC1XX_CGU_SRC_CLK_DIV(IDIVE, 8, idivbcde_src_ids), 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistruct lpc18xx_cgu_base_clk { 19762306a36Sopenharmony_ci u8 clk_id; 19862306a36Sopenharmony_ci u8 n_parents; 19962306a36Sopenharmony_ci struct clk_mux mux; 20062306a36Sopenharmony_ci struct clk_gate gate; 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci#define LPC1XX_CGU_BASE_CLK(_id, _table, _flags) \ 20462306a36Sopenharmony_ci{ \ 20562306a36Sopenharmony_ci .clk_id = BASE_ ##_id ##_CLK, \ 20662306a36Sopenharmony_ci .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ 20762306a36Sopenharmony_ci .mux = { \ 20862306a36Sopenharmony_ci .mask = 0x1f, \ 20962306a36Sopenharmony_ci .shift = 24, \ 21062306a36Sopenharmony_ci .table = lpc18xx_cgu_ ##_table, \ 21162306a36Sopenharmony_ci .flags = _flags, \ 21262306a36Sopenharmony_ci }, \ 21362306a36Sopenharmony_ci .gate = { \ 21462306a36Sopenharmony_ci .bit_idx = 0, \ 21562306a36Sopenharmony_ci .flags = CLK_GATE_SET_TO_DISABLE, \ 21662306a36Sopenharmony_ci }, \ 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic struct lpc18xx_cgu_base_clk lpc18xx_cgu_base_clks[] = { 22062306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(SAFE, base_irc_src_ids, CLK_MUX_READ_ONLY), 22162306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(USB0, base_usb0_src_ids, 0), 22262306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(PERIPH, base_common_src_ids, 0), 22362306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(USB1, base_all_src_ids, 0), 22462306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(CPU, base_common_src_ids, 0), 22562306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(SPIFI, base_common_src_ids, 0), 22662306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(SPI, base_common_src_ids, 0), 22762306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(PHY_RX, base_common_src_ids, 0), 22862306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(PHY_TX, base_common_src_ids, 0), 22962306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(APB1, base_common_src_ids, 0), 23062306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(APB3, base_common_src_ids, 0), 23162306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(LCD, base_common_src_ids, 0), 23262306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(ADCHS, base_common_src_ids, 0), 23362306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(SDIO, base_common_src_ids, 0), 23462306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(SSP0, base_common_src_ids, 0), 23562306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(SSP1, base_common_src_ids, 0), 23662306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(UART0, base_common_src_ids, 0), 23762306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(UART1, base_common_src_ids, 0), 23862306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(UART2, base_common_src_ids, 0), 23962306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(UART3, base_common_src_ids, 0), 24062306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(OUT, base_all_src_ids, 0), 24162306a36Sopenharmony_ci { /* 21 reserved */ }, 24262306a36Sopenharmony_ci { /* 22 reserved */ }, 24362306a36Sopenharmony_ci { /* 23 reserved */ }, 24462306a36Sopenharmony_ci { /* 24 reserved */ }, 24562306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(AUDIO, base_common_src_ids, 0), 24662306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(CGU_OUT0, base_all_src_ids, 0), 24762306a36Sopenharmony_ci LPC1XX_CGU_BASE_CLK(CGU_OUT1, base_all_src_ids, 0), 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistruct lpc18xx_pll { 25162306a36Sopenharmony_ci struct clk_hw hw; 25262306a36Sopenharmony_ci void __iomem *reg; 25362306a36Sopenharmony_ci spinlock_t *lock; 25462306a36Sopenharmony_ci u8 flags; 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci#define to_lpc_pll(hw) container_of(hw, struct lpc18xx_pll, hw) 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistruct lpc18xx_cgu_pll_clk { 26062306a36Sopenharmony_ci u8 clk_id; 26162306a36Sopenharmony_ci u8 n_parents; 26262306a36Sopenharmony_ci u8 reg_offset; 26362306a36Sopenharmony_ci struct clk_mux mux; 26462306a36Sopenharmony_ci struct clk_gate gate; 26562306a36Sopenharmony_ci struct lpc18xx_pll pll; 26662306a36Sopenharmony_ci const struct clk_ops *pll_ops; 26762306a36Sopenharmony_ci}; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#define LPC1XX_CGU_CLK_PLL(_id, _table, _pll_ops) \ 27062306a36Sopenharmony_ci{ \ 27162306a36Sopenharmony_ci .clk_id = CLK_SRC_ ##_id, \ 27262306a36Sopenharmony_ci .n_parents = ARRAY_SIZE(lpc18xx_cgu_ ##_table), \ 27362306a36Sopenharmony_ci .reg_offset = LPC18XX_CGU_ ##_id ##_STAT, \ 27462306a36Sopenharmony_ci .mux = { \ 27562306a36Sopenharmony_ci .mask = 0x1f, \ 27662306a36Sopenharmony_ci .shift = 24, \ 27762306a36Sopenharmony_ci .table = lpc18xx_cgu_ ##_table, \ 27862306a36Sopenharmony_ci }, \ 27962306a36Sopenharmony_ci .gate = { \ 28062306a36Sopenharmony_ci .bit_idx = 0, \ 28162306a36Sopenharmony_ci .flags = CLK_GATE_SET_TO_DISABLE, \ 28262306a36Sopenharmony_ci }, \ 28362306a36Sopenharmony_ci .pll_ops = &lpc18xx_ ##_pll_ops, \ 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* 28762306a36Sopenharmony_ci * PLL0 uses a special register value encoding. The compute functions below 28862306a36Sopenharmony_ci * are taken or derived from the LPC1850 user manual (section 12.6.3.3). 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* Compute PLL0 multiplier from decoded version */ 29262306a36Sopenharmony_cistatic u32 lpc18xx_pll0_mdec2msel(u32 x) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci int i; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci switch (x) { 29762306a36Sopenharmony_ci case 0x18003: return 1; 29862306a36Sopenharmony_ci case 0x10003: return 2; 29962306a36Sopenharmony_ci default: 30062306a36Sopenharmony_ci for (i = LPC18XX_PLL0_MSEL_MAX + 1; x != 0x4000 && i > 0; i--) 30162306a36Sopenharmony_ci x = ((x ^ x >> 14) & 1) | (x << 1 & 0x7fff); 30262306a36Sopenharmony_ci return i; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci/* Compute PLL0 decoded multiplier from binary version */ 30662306a36Sopenharmony_cistatic u32 lpc18xx_pll0_msel2mdec(u32 msel) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci u32 i, x = 0x4000; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci switch (msel) { 31162306a36Sopenharmony_ci case 0: return 0; 31262306a36Sopenharmony_ci case 1: return 0x18003; 31362306a36Sopenharmony_ci case 2: return 0x10003; 31462306a36Sopenharmony_ci default: 31562306a36Sopenharmony_ci for (i = msel; i <= LPC18XX_PLL0_MSEL_MAX; i++) 31662306a36Sopenharmony_ci x = ((x ^ x >> 1) & 1) << 14 | (x >> 1 & 0xffff); 31762306a36Sopenharmony_ci return x; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci/* Compute PLL0 bandwidth SELI reg from multiplier */ 32262306a36Sopenharmony_cistatic u32 lpc18xx_pll0_msel2seli(u32 msel) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci u32 tmp; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (msel > 16384) return 1; 32762306a36Sopenharmony_ci if (msel > 8192) return 2; 32862306a36Sopenharmony_ci if (msel > 2048) return 4; 32962306a36Sopenharmony_ci if (msel >= 501) return 8; 33062306a36Sopenharmony_ci if (msel >= 60) { 33162306a36Sopenharmony_ci tmp = 1024 / (msel + 9); 33262306a36Sopenharmony_ci return ((1024 == (tmp * (msel + 9))) == 0) ? tmp * 4 : (tmp + 1) * 4; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return (msel & 0x3c) + 4; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci/* Compute PLL0 bandwidth SELP reg from multiplier */ 33962306a36Sopenharmony_cistatic u32 lpc18xx_pll0_msel2selp(u32 msel) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci if (msel < 60) 34262306a36Sopenharmony_ci return (msel >> 1) + 1; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 31; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic unsigned long lpc18xx_pll0_recalc_rate(struct clk_hw *hw, 34862306a36Sopenharmony_ci unsigned long parent_rate) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct lpc18xx_pll *pll = to_lpc_pll(hw); 35162306a36Sopenharmony_ci u32 ctrl, mdiv, msel, npdiv; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci ctrl = readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); 35462306a36Sopenharmony_ci mdiv = readl(pll->reg + LPC18XX_CGU_PLL0USB_MDIV); 35562306a36Sopenharmony_ci npdiv = readl(pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (ctrl & LPC18XX_PLL0_CTRL_BYPASS) 35862306a36Sopenharmony_ci return parent_rate; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (npdiv != LPC18XX_PLL0_NP_DIVS_1) { 36162306a36Sopenharmony_ci pr_warn("%s: pre/post dividers not supported\n", __func__); 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci msel = lpc18xx_pll0_mdec2msel(mdiv & LPC18XX_PLL0_MDIV_MDEC_MASK); 36662306a36Sopenharmony_ci if (msel) 36762306a36Sopenharmony_ci return 2 * msel * parent_rate; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci pr_warn("%s: unable to calculate rate\n", __func__); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic long lpc18xx_pll0_round_rate(struct clk_hw *hw, unsigned long rate, 37562306a36Sopenharmony_ci unsigned long *prate) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci unsigned long m; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (*prate < rate) { 38062306a36Sopenharmony_ci pr_warn("%s: pll dividers not supported\n", __func__); 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci m = DIV_ROUND_UP_ULL(*prate, rate * 2); 38562306a36Sopenharmony_ci if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { 38662306a36Sopenharmony_ci pr_warn("%s: unable to support rate %lu\n", __func__, rate); 38762306a36Sopenharmony_ci return -EINVAL; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return 2 * *prate * m; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int lpc18xx_pll0_set_rate(struct clk_hw *hw, unsigned long rate, 39462306a36Sopenharmony_ci unsigned long parent_rate) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct lpc18xx_pll *pll = to_lpc_pll(hw); 39762306a36Sopenharmony_ci u32 ctrl, stat, m; 39862306a36Sopenharmony_ci int retry = 3; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (parent_rate < rate) { 40162306a36Sopenharmony_ci pr_warn("%s: pll dividers not supported\n", __func__); 40262306a36Sopenharmony_ci return -EINVAL; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci m = DIV_ROUND_UP_ULL(parent_rate, rate * 2); 40662306a36Sopenharmony_ci if (m <= 0 && m > LPC18XX_PLL0_MSEL_MAX) { 40762306a36Sopenharmony_ci pr_warn("%s: unable to support rate %lu\n", __func__, rate); 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci m = lpc18xx_pll0_msel2mdec(m); 41262306a36Sopenharmony_ci m |= lpc18xx_pll0_msel2selp(m) << LPC18XX_PLL0_MDIV_SELP_SHIFT; 41362306a36Sopenharmony_ci m |= lpc18xx_pll0_msel2seli(m) << LPC18XX_PLL0_MDIV_SELI_SHIFT; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Power down PLL, disable clk output and dividers */ 41662306a36Sopenharmony_ci ctrl = readl(pll->reg + LPC18XX_CGU_PLL0USB_CTRL); 41762306a36Sopenharmony_ci ctrl |= LPC18XX_PLL0_CTRL_PD; 41862306a36Sopenharmony_ci ctrl &= ~(LPC18XX_PLL0_CTRL_BYPASS | LPC18XX_PLL0_CTRL_DIRECTI | 41962306a36Sopenharmony_ci LPC18XX_PLL0_CTRL_DIRECTO | LPC18XX_PLL0_CTRL_CLKEN); 42062306a36Sopenharmony_ci writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Configure new PLL settings */ 42362306a36Sopenharmony_ci writel(m, pll->reg + LPC18XX_CGU_PLL0USB_MDIV); 42462306a36Sopenharmony_ci writel(LPC18XX_PLL0_NP_DIVS_1, pll->reg + LPC18XX_CGU_PLL0USB_NP_DIV); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* Power up PLL and wait for lock */ 42762306a36Sopenharmony_ci ctrl &= ~LPC18XX_PLL0_CTRL_PD; 42862306a36Sopenharmony_ci writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); 42962306a36Sopenharmony_ci do { 43062306a36Sopenharmony_ci udelay(10); 43162306a36Sopenharmony_ci stat = readl(pll->reg + LPC18XX_CGU_PLL0USB_STAT); 43262306a36Sopenharmony_ci if (stat & LPC18XX_PLL0_STAT_LOCK) { 43362306a36Sopenharmony_ci ctrl |= LPC18XX_PLL0_CTRL_CLKEN; 43462306a36Sopenharmony_ci writel(ctrl, pll->reg + LPC18XX_CGU_PLL0USB_CTRL); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci } while (retry--); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci pr_warn("%s: unable to lock pll\n", __func__); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic const struct clk_ops lpc18xx_pll0_ops = { 44662306a36Sopenharmony_ci .recalc_rate = lpc18xx_pll0_recalc_rate, 44762306a36Sopenharmony_ci .round_rate = lpc18xx_pll0_round_rate, 44862306a36Sopenharmony_ci .set_rate = lpc18xx_pll0_set_rate, 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic unsigned long lpc18xx_pll1_recalc_rate(struct clk_hw *hw, 45262306a36Sopenharmony_ci unsigned long parent_rate) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct lpc18xx_pll *pll = to_lpc_pll(hw); 45562306a36Sopenharmony_ci u16 msel, nsel, psel; 45662306a36Sopenharmony_ci bool direct, fbsel; 45762306a36Sopenharmony_ci u32 ctrl; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ctrl = readl(pll->reg + LPC18XX_CGU_PLL1_CTRL); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci direct = (ctrl & LPC18XX_PLL1_CTRL_DIRECT) ? true : false; 46262306a36Sopenharmony_ci fbsel = (ctrl & LPC18XX_PLL1_CTRL_FBSEL) ? true : false; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci msel = ((ctrl >> 16) & 0xff) + 1; 46562306a36Sopenharmony_ci nsel = ((ctrl >> 12) & 0x3) + 1; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (direct || fbsel) 46862306a36Sopenharmony_ci return msel * (parent_rate / nsel); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci psel = (ctrl >> 8) & 0x3; 47162306a36Sopenharmony_ci psel = 1 << psel; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return (msel / (2 * psel)) * (parent_rate / nsel); 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic const struct clk_ops lpc18xx_pll1_ops = { 47762306a36Sopenharmony_ci .recalc_rate = lpc18xx_pll1_recalc_rate, 47862306a36Sopenharmony_ci}; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int lpc18xx_cgu_gate_enable(struct clk_hw *hw) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci return clk_gate_ops.enable(hw); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic void lpc18xx_cgu_gate_disable(struct clk_hw *hw) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci clk_gate_ops.disable(hw); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic int lpc18xx_cgu_gate_is_enabled(struct clk_hw *hw) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci const struct clk_hw *parent; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* 49562306a36Sopenharmony_ci * The consumer of base clocks needs know if the 49662306a36Sopenharmony_ci * base clock is really enabled before it can be 49762306a36Sopenharmony_ci * accessed. It is therefore necessary to verify 49862306a36Sopenharmony_ci * this all the way up. 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_ci parent = clk_hw_get_parent(hw); 50162306a36Sopenharmony_ci if (!parent) 50262306a36Sopenharmony_ci return 0; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (!clk_hw_is_enabled(parent)) 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return clk_gate_ops.is_enabled(hw); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic const struct clk_ops lpc18xx_gate_ops = { 51162306a36Sopenharmony_ci .enable = lpc18xx_cgu_gate_enable, 51262306a36Sopenharmony_ci .disable = lpc18xx_cgu_gate_disable, 51362306a36Sopenharmony_ci .is_enabled = lpc18xx_cgu_gate_is_enabled, 51462306a36Sopenharmony_ci}; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic struct lpc18xx_cgu_pll_clk lpc18xx_cgu_src_clk_plls[] = { 51762306a36Sopenharmony_ci LPC1XX_CGU_CLK_PLL(PLL0USB, pll0_src_ids, pll0_ops), 51862306a36Sopenharmony_ci LPC1XX_CGU_CLK_PLL(PLL0AUDIO, pll0_src_ids, pll0_ops), 51962306a36Sopenharmony_ci LPC1XX_CGU_CLK_PLL(PLL1, pll1_src_ids, pll1_ops), 52062306a36Sopenharmony_ci}; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic void lpc18xx_fill_parent_names(const char **parent, const u32 *id, int size) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci int i; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci for (i = 0; i < size; i++) 52762306a36Sopenharmony_ci parent[i] = clk_src_names[id[i]]; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic struct clk *lpc18xx_cgu_register_div(struct lpc18xx_cgu_src_clk_div *clk, 53162306a36Sopenharmony_ci void __iomem *base, int n) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci void __iomem *reg = base + LPC18XX_CGU_IDIV_CTRL(n); 53462306a36Sopenharmony_ci const char *name = clk_src_names[clk->clk_id]; 53562306a36Sopenharmony_ci const char *parents[CLK_SRC_MAX]; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci clk->div.reg = reg; 53862306a36Sopenharmony_ci clk->mux.reg = reg; 53962306a36Sopenharmony_ci clk->gate.reg = reg; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci return clk_register_composite(NULL, name, parents, clk->n_parents, 54462306a36Sopenharmony_ci &clk->mux.hw, &clk_mux_ops, 54562306a36Sopenharmony_ci &clk->div.hw, &clk_divider_ops, 54662306a36Sopenharmony_ci &clk->gate.hw, &lpc18xx_gate_ops, 0); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic struct clk *lpc18xx_register_base_clk(struct lpc18xx_cgu_base_clk *clk, 55162306a36Sopenharmony_ci void __iomem *reg_base, int n) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci void __iomem *reg = reg_base + LPC18XX_CGU_BASE_CLK(n); 55462306a36Sopenharmony_ci const char *name = clk_base_names[clk->clk_id]; 55562306a36Sopenharmony_ci const char *parents[CLK_SRC_MAX]; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (clk->n_parents == 0) 55862306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci clk->mux.reg = reg; 56162306a36Sopenharmony_ci clk->gate.reg = reg; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* SAFE_CLK can not be turned off */ 56662306a36Sopenharmony_ci if (n == BASE_SAFE_CLK) 56762306a36Sopenharmony_ci return clk_register_composite(NULL, name, parents, clk->n_parents, 56862306a36Sopenharmony_ci &clk->mux.hw, &clk_mux_ops, 56962306a36Sopenharmony_ci NULL, NULL, NULL, NULL, 0); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return clk_register_composite(NULL, name, parents, clk->n_parents, 57262306a36Sopenharmony_ci &clk->mux.hw, &clk_mux_ops, 57362306a36Sopenharmony_ci NULL, NULL, 57462306a36Sopenharmony_ci &clk->gate.hw, &lpc18xx_gate_ops, 0); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic struct clk *lpc18xx_cgu_register_pll(struct lpc18xx_cgu_pll_clk *clk, 57962306a36Sopenharmony_ci void __iomem *base) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci const char *name = clk_src_names[clk->clk_id]; 58262306a36Sopenharmony_ci const char *parents[CLK_SRC_MAX]; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci clk->pll.reg = base; 58562306a36Sopenharmony_ci clk->mux.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; 58662306a36Sopenharmony_ci clk->gate.reg = base + clk->reg_offset + LPC18XX_CGU_PLL_CTRL_OFFSET; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci lpc18xx_fill_parent_names(parents, clk->mux.table, clk->n_parents); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return clk_register_composite(NULL, name, parents, clk->n_parents, 59162306a36Sopenharmony_ci &clk->mux.hw, &clk_mux_ops, 59262306a36Sopenharmony_ci &clk->pll.hw, clk->pll_ops, 59362306a36Sopenharmony_ci &clk->gate.hw, &lpc18xx_gate_ops, 0); 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic void __init lpc18xx_cgu_register_source_clks(struct device_node *np, 59762306a36Sopenharmony_ci void __iomem *base) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci const char *parents[CLK_SRC_MAX]; 60062306a36Sopenharmony_ci struct clk *clk; 60162306a36Sopenharmony_ci int i; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* Register the internal 12 MHz RC oscillator (IRC) */ 60462306a36Sopenharmony_ci clk = clk_register_fixed_rate(NULL, clk_src_names[CLK_SRC_IRC], 60562306a36Sopenharmony_ci NULL, 0, 12000000); 60662306a36Sopenharmony_ci if (IS_ERR(clk)) 60762306a36Sopenharmony_ci pr_warn("%s: failed to register irc clk\n", __func__); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Register crystal oscillator controller */ 61062306a36Sopenharmony_ci parents[0] = of_clk_get_parent_name(np, 0); 61162306a36Sopenharmony_ci clk = clk_register_gate(NULL, clk_src_names[CLK_SRC_OSC], parents[0], 61262306a36Sopenharmony_ci 0, base + LPC18XX_CGU_XTAL_OSC_CTRL, 61362306a36Sopenharmony_ci 0, CLK_GATE_SET_TO_DISABLE, NULL); 61462306a36Sopenharmony_ci if (IS_ERR(clk)) 61562306a36Sopenharmony_ci pr_warn("%s: failed to register osc clk\n", __func__); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Register all PLLs */ 61862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_plls); i++) { 61962306a36Sopenharmony_ci clk = lpc18xx_cgu_register_pll(&lpc18xx_cgu_src_clk_plls[i], 62062306a36Sopenharmony_ci base); 62162306a36Sopenharmony_ci if (IS_ERR(clk)) 62262306a36Sopenharmony_ci pr_warn("%s: failed to register pll (%d)\n", __func__, i); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Register all clock dividers A-E */ 62662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lpc18xx_cgu_src_clk_divs); i++) { 62762306a36Sopenharmony_ci clk = lpc18xx_cgu_register_div(&lpc18xx_cgu_src_clk_divs[i], 62862306a36Sopenharmony_ci base, i); 62962306a36Sopenharmony_ci if (IS_ERR(clk)) 63062306a36Sopenharmony_ci pr_warn("%s: failed to register div %d\n", __func__, i); 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic struct clk *clk_base[BASE_CLK_MAX]; 63562306a36Sopenharmony_cistatic struct clk_onecell_data clk_base_data = { 63662306a36Sopenharmony_ci .clks = clk_base, 63762306a36Sopenharmony_ci .clk_num = BASE_CLK_MAX, 63862306a36Sopenharmony_ci}; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic void __init lpc18xx_cgu_register_base_clks(void __iomem *reg_base) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci int i; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci for (i = BASE_SAFE_CLK; i < BASE_CLK_MAX; i++) { 64562306a36Sopenharmony_ci clk_base[i] = lpc18xx_register_base_clk(&lpc18xx_cgu_base_clks[i], 64662306a36Sopenharmony_ci reg_base, i); 64762306a36Sopenharmony_ci if (IS_ERR(clk_base[i]) && PTR_ERR(clk_base[i]) != -ENOENT) 64862306a36Sopenharmony_ci pr_warn("%s: register base clk %d failed\n", __func__, i); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void __init lpc18xx_cgu_init(struct device_node *np) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci void __iomem *reg_base; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci reg_base = of_iomap(np, 0); 65762306a36Sopenharmony_ci if (!reg_base) { 65862306a36Sopenharmony_ci pr_warn("%s: failed to map address range\n", __func__); 65962306a36Sopenharmony_ci return; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci lpc18xx_cgu_register_source_clks(np, reg_base); 66362306a36Sopenharmony_ci lpc18xx_cgu_register_base_clks(reg_base); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci of_clk_add_provider(np, of_clk_src_onecell_get, &clk_base_data); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ciCLK_OF_DECLARE(lpc18xx_cgu, "nxp,lpc1850-cgu", lpc18xx_cgu_init); 668