18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * OMAP3 Clock init 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2013 Texas Instruments, Inc 58c2ecf20Sopenharmony_ci * Tero Kristo (t-kristo@ti.com) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 88c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as 98c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any 128c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty 138c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148c2ecf20Sopenharmony_ci * GNU General Public License for more details. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/list.h> 198c2ecf20Sopenharmony_ci#include <linux/clk.h> 208c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 218c2ecf20Sopenharmony_ci#include <linux/clk/ti.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "clock.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define OMAP3430ES2_ST_DSS_IDLE_SHIFT 1 268c2ecf20Sopenharmony_ci#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT 5 278c2ecf20Sopenharmony_ci#define OMAP3430ES2_ST_SSI_IDLE_SHIFT 8 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define OMAP34XX_CM_IDLEST_VAL 1 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported 338c2ecf20Sopenharmony_ci * in the same register at a bit offset of 0x8. The EN_ACK for ICK is 348c2ecf20Sopenharmony_ci * at an offset of 4 from ICK enable bit. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#define AM35XX_IPSS_ICK_MASK 0xF 378c2ecf20Sopenharmony_ci#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4 388c2ecf20Sopenharmony_ci#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8 398c2ecf20Sopenharmony_ci#define AM35XX_IPSS_CLK_IDLEST_VAL 0 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define AM35XX_ST_IPSS_SHIFT 5 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI 458c2ecf20Sopenharmony_ci * @clk: struct clk * being enabled 468c2ecf20Sopenharmony_ci * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into 478c2ecf20Sopenharmony_ci * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into 488c2ecf20Sopenharmony_ci * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift 518c2ecf20Sopenharmony_ci * from the CM_{I,F}CLKEN bit. Pass back the correct info via 528c2ecf20Sopenharmony_ci * @idlest_reg and @idlest_bit. No return value. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistatic void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk, 558c2ecf20Sopenharmony_ci struct clk_omap_reg *idlest_reg, 568c2ecf20Sopenharmony_ci u8 *idlest_bit, 578c2ecf20Sopenharmony_ci u8 *idlest_val) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg)); 608c2ecf20Sopenharmony_ci idlest_reg->offset &= ~0xf0; 618c2ecf20Sopenharmony_ci idlest_reg->offset |= 0x20; 628c2ecf20Sopenharmony_ci *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT; 638c2ecf20Sopenharmony_ci *idlest_val = OMAP34XX_CM_IDLEST_VAL; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = { 678c2ecf20Sopenharmony_ci .allow_idle = omap2_clkt_iclk_allow_idle, 688c2ecf20Sopenharmony_ci .deny_idle = omap2_clkt_iclk_deny_idle, 698c2ecf20Sopenharmony_ci .find_idlest = omap3430es2_clk_ssi_find_idlest, 708c2ecf20Sopenharmony_ci .find_companion = omap2_clk_dflt_find_companion, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST 758c2ecf20Sopenharmony_ci * @clk: struct clk * being enabled 768c2ecf20Sopenharmony_ci * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into 778c2ecf20Sopenharmony_ci * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into 788c2ecf20Sopenharmony_ci * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * Some OMAP modules on OMAP3 ES2+ chips have both initiator and 818c2ecf20Sopenharmony_ci * target IDLEST bits. For our purposes, we are concerned with the 828c2ecf20Sopenharmony_ci * target IDLEST bits, which exist at a different bit position than 838c2ecf20Sopenharmony_ci * the *CLKEN bit position for these modules (DSS and USBHOST) (The 848c2ecf20Sopenharmony_ci * default find_idlest code assumes that they are at the same 858c2ecf20Sopenharmony_ci * position.) No return value. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic void 888c2ecf20Sopenharmony_ciomap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk, 898c2ecf20Sopenharmony_ci struct clk_omap_reg *idlest_reg, 908c2ecf20Sopenharmony_ci u8 *idlest_bit, u8 *idlest_val) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg)); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci idlest_reg->offset &= ~0xf0; 958c2ecf20Sopenharmony_ci idlest_reg->offset |= 0x20; 968c2ecf20Sopenharmony_ci /* USBHOST_IDLE has same shift */ 978c2ecf20Sopenharmony_ci *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT; 988c2ecf20Sopenharmony_ci *idlest_val = OMAP34XX_CM_IDLEST_VAL; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = { 1028c2ecf20Sopenharmony_ci .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, 1038c2ecf20Sopenharmony_ci .find_companion = omap2_clk_dflt_find_companion, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = { 1078c2ecf20Sopenharmony_ci .allow_idle = omap2_clkt_iclk_allow_idle, 1088c2ecf20Sopenharmony_ci .deny_idle = omap2_clkt_iclk_deny_idle, 1098c2ecf20Sopenharmony_ci .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, 1108c2ecf20Sopenharmony_ci .find_companion = omap2_clk_dflt_find_companion, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/** 1148c2ecf20Sopenharmony_ci * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB 1158c2ecf20Sopenharmony_ci * @clk: struct clk * being enabled 1168c2ecf20Sopenharmony_ci * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into 1178c2ecf20Sopenharmony_ci * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into 1188c2ecf20Sopenharmony_ci * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different 1218c2ecf20Sopenharmony_ci * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via 1228c2ecf20Sopenharmony_ci * @idlest_reg and @idlest_bit. No return value. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_cistatic void 1258c2ecf20Sopenharmony_ciomap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk, 1268c2ecf20Sopenharmony_ci struct clk_omap_reg *idlest_reg, 1278c2ecf20Sopenharmony_ci u8 *idlest_bit, 1288c2ecf20Sopenharmony_ci u8 *idlest_val) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg)); 1318c2ecf20Sopenharmony_ci idlest_reg->offset &= ~0xf0; 1328c2ecf20Sopenharmony_ci idlest_reg->offset |= 0x20; 1338c2ecf20Sopenharmony_ci *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT; 1348c2ecf20Sopenharmony_ci *idlest_val = OMAP34XX_CM_IDLEST_VAL; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = { 1388c2ecf20Sopenharmony_ci .allow_idle = omap2_clkt_iclk_allow_idle, 1398c2ecf20Sopenharmony_ci .deny_idle = omap2_clkt_iclk_deny_idle, 1408c2ecf20Sopenharmony_ci .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, 1418c2ecf20Sopenharmony_ci .find_companion = omap2_clk_dflt_find_companion, 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS 1468c2ecf20Sopenharmony_ci * @clk: struct clk * being enabled 1478c2ecf20Sopenharmony_ci * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into 1488c2ecf20Sopenharmony_ci * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into 1498c2ecf20Sopenharmony_ci * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * The interface clocks on AM35xx IPSS reflects the clock idle status 1528c2ecf20Sopenharmony_ci * in the enable register itsel at a bit offset of 4 from the enable 1538c2ecf20Sopenharmony_ci * bit. A value of 1 indicates that clock is enabled. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_cistatic void am35xx_clk_find_idlest(struct clk_hw_omap *clk, 1568c2ecf20Sopenharmony_ci struct clk_omap_reg *idlest_reg, 1578c2ecf20Sopenharmony_ci u8 *idlest_bit, 1588c2ecf20Sopenharmony_ci u8 *idlest_val) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg)); 1618c2ecf20Sopenharmony_ci *idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET; 1628c2ecf20Sopenharmony_ci *idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * am35xx_clk_find_companion - find companion clock to @clk 1678c2ecf20Sopenharmony_ci * @clk: struct clk * to find the companion clock of 1688c2ecf20Sopenharmony_ci * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in 1698c2ecf20Sopenharmony_ci * @other_bit: u8 ** to return the companion clock bit shift in 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Some clocks don't have companion clocks. For example, modules with 1728c2ecf20Sopenharmony_ci * only an interface clock (such as HECC) don't have a companion 1738c2ecf20Sopenharmony_ci * clock. Right now, this code relies on the hardware exporting a bit 1748c2ecf20Sopenharmony_ci * in the correct companion register that indicates that the 1758c2ecf20Sopenharmony_ci * nonexistent 'companion clock' is active. Future patches will 1768c2ecf20Sopenharmony_ci * associate this type of code with per-module data structures to 1778c2ecf20Sopenharmony_ci * avoid this issue, and remove the casts. No return value. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_cistatic void am35xx_clk_find_companion(struct clk_hw_omap *clk, 1808c2ecf20Sopenharmony_ci struct clk_omap_reg *other_reg, 1818c2ecf20Sopenharmony_ci u8 *other_bit) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci memcpy(other_reg, &clk->enable_reg, sizeof(*other_reg)); 1848c2ecf20Sopenharmony_ci if (clk->enable_bit & AM35XX_IPSS_ICK_MASK) 1858c2ecf20Sopenharmony_ci *other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET; 1868c2ecf20Sopenharmony_ci else 1878c2ecf20Sopenharmony_ci *other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = { 1918c2ecf20Sopenharmony_ci .find_idlest = am35xx_clk_find_idlest, 1928c2ecf20Sopenharmony_ci .find_companion = am35xx_clk_find_companion, 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/** 1968c2ecf20Sopenharmony_ci * am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS 1978c2ecf20Sopenharmony_ci * @clk: struct clk * being enabled 1988c2ecf20Sopenharmony_ci * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into 1998c2ecf20Sopenharmony_ci * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into 2008c2ecf20Sopenharmony_ci * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * The IPSS target CM_IDLEST bit is at a different shift from the 2038c2ecf20Sopenharmony_ci * CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg 2048c2ecf20Sopenharmony_ci * and @idlest_bit. No return value. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_cistatic void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk, 2078c2ecf20Sopenharmony_ci struct clk_omap_reg *idlest_reg, 2088c2ecf20Sopenharmony_ci u8 *idlest_bit, 2098c2ecf20Sopenharmony_ci u8 *idlest_val) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci memcpy(idlest_reg, &clk->enable_reg, sizeof(*idlest_reg)); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci idlest_reg->offset &= ~0xf0; 2148c2ecf20Sopenharmony_ci idlest_reg->offset |= 0x20; 2158c2ecf20Sopenharmony_ci *idlest_bit = AM35XX_ST_IPSS_SHIFT; 2168c2ecf20Sopenharmony_ci *idlest_val = OMAP34XX_CM_IDLEST_VAL; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciconst struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = { 2208c2ecf20Sopenharmony_ci .allow_idle = omap2_clkt_iclk_allow_idle, 2218c2ecf20Sopenharmony_ci .deny_idle = omap2_clkt_iclk_deny_idle, 2228c2ecf20Sopenharmony_ci .find_idlest = am35xx_clk_ipss_find_idlest, 2238c2ecf20Sopenharmony_ci .find_companion = omap2_clk_dflt_find_companion, 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic struct ti_dt_clk omap3xxx_clks[] = { 2278c2ecf20Sopenharmony_ci DT_CLK(NULL, "timer_32k_ck", "omap_32k_fck"), 2288c2ecf20Sopenharmony_ci DT_CLK(NULL, "timer_sys_ck", "sys_ck"), 2298c2ecf20Sopenharmony_ci { .node_name = NULL }, 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic struct ti_dt_clk omap36xx_omap3430es2plus_clks[] = { 2338c2ecf20Sopenharmony_ci DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es2"), 2348c2ecf20Sopenharmony_ci DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es2"), 2358c2ecf20Sopenharmony_ci DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es2"), 2368c2ecf20Sopenharmony_ci DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es2"), 2378c2ecf20Sopenharmony_ci { .node_name = NULL }, 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic struct ti_dt_clk omap3430es1_clks[] = { 2418c2ecf20Sopenharmony_ci DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es1"), 2428c2ecf20Sopenharmony_ci DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es1"), 2438c2ecf20Sopenharmony_ci DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es1"), 2448c2ecf20Sopenharmony_ci DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es1"), 2458c2ecf20Sopenharmony_ci DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es1"), 2468c2ecf20Sopenharmony_ci DT_CLK(NULL, "dss_ick", "dss_ick_3430es1"), 2478c2ecf20Sopenharmony_ci { .node_name = NULL }, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic struct ti_dt_clk omap36xx_am35xx_omap3430es2plus_clks[] = { 2518c2ecf20Sopenharmony_ci DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es2"), 2528c2ecf20Sopenharmony_ci DT_CLK(NULL, "dss_ick", "dss_ick_3430es2"), 2538c2ecf20Sopenharmony_ci { .node_name = NULL }, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic struct ti_dt_clk am35xx_clks[] = { 2578c2ecf20Sopenharmony_ci DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_am35xx"), 2588c2ecf20Sopenharmony_ci DT_CLK(NULL, "hsotgusb_fck", "hsotgusb_fck_am35xx"), 2598c2ecf20Sopenharmony_ci DT_CLK(NULL, "uart4_ick", "uart4_ick_am35xx"), 2608c2ecf20Sopenharmony_ci DT_CLK(NULL, "uart4_fck", "uart4_fck_am35xx"), 2618c2ecf20Sopenharmony_ci { .node_name = NULL }, 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic const char *enable_init_clks[] = { 2658c2ecf20Sopenharmony_ci "sdrc_ick", 2668c2ecf20Sopenharmony_ci "gpmc_fck", 2678c2ecf20Sopenharmony_ci "omapctrl_ick", 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cienum { 2718c2ecf20Sopenharmony_ci OMAP3_SOC_AM35XX, 2728c2ecf20Sopenharmony_ci OMAP3_SOC_OMAP3430_ES1, 2738c2ecf20Sopenharmony_ci OMAP3_SOC_OMAP3430_ES2_PLUS, 2748c2ecf20Sopenharmony_ci OMAP3_SOC_OMAP3630, 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/** 2788c2ecf20Sopenharmony_ci * omap3_clk_lock_dpll5 - locks DPLL5 2798c2ecf20Sopenharmony_ci * 2808c2ecf20Sopenharmony_ci * Locks DPLL5 to a pre-defined frequency. This is required for proper 2818c2ecf20Sopenharmony_ci * operation of USB. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_civoid __init omap3_clk_lock_dpll5(void) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct clk *dpll5_clk; 2868c2ecf20Sopenharmony_ci struct clk *dpll5_m2_clk; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* 2898c2ecf20Sopenharmony_ci * Errata sprz319f advisory 2.1 documents a USB host clock drift issue 2908c2ecf20Sopenharmony_ci * that can be worked around using specially crafted dpll5 settings 2918c2ecf20Sopenharmony_ci * with a dpll5_m2 divider set to 8. Set the dpll5 rate to 8x the USB 2928c2ecf20Sopenharmony_ci * host clock rate, its .set_rate handler() will detect that frequency 2938c2ecf20Sopenharmony_ci * and use the errata settings. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci dpll5_clk = clk_get(NULL, "dpll5_ck"); 2968c2ecf20Sopenharmony_ci clk_set_rate(dpll5_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST * 8); 2978c2ecf20Sopenharmony_ci clk_prepare_enable(dpll5_clk); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Program dpll5_m2_clk divider */ 3008c2ecf20Sopenharmony_ci dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck"); 3018c2ecf20Sopenharmony_ci clk_prepare_enable(dpll5_m2_clk); 3028c2ecf20Sopenharmony_ci clk_set_rate(dpll5_m2_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci clk_disable_unprepare(dpll5_m2_clk); 3058c2ecf20Sopenharmony_ci clk_disable_unprepare(dpll5_clk); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int __init omap3xxx_dt_clk_init(int soc_type) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 || 3118c2ecf20Sopenharmony_ci soc_type == OMAP3_SOC_OMAP3430_ES1 || 3128c2ecf20Sopenharmony_ci soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) 3138c2ecf20Sopenharmony_ci ti_dt_clocks_register(omap3xxx_clks); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (soc_type == OMAP3_SOC_AM35XX) 3168c2ecf20Sopenharmony_ci ti_dt_clocks_register(am35xx_clks); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (soc_type == OMAP3_SOC_OMAP3630 || soc_type == OMAP3_SOC_AM35XX || 3198c2ecf20Sopenharmony_ci soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS) 3208c2ecf20Sopenharmony_ci ti_dt_clocks_register(omap36xx_am35xx_omap3430es2plus_clks); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (soc_type == OMAP3_SOC_OMAP3430_ES1) 3238c2ecf20Sopenharmony_ci ti_dt_clocks_register(omap3430es1_clks); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS || 3268c2ecf20Sopenharmony_ci soc_type == OMAP3_SOC_OMAP3630) 3278c2ecf20Sopenharmony_ci ti_dt_clocks_register(omap36xx_omap3430es2plus_clks); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci omap2_clk_disable_autoidle_all(); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci ti_clk_add_aliases(); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci omap2_clk_enable_init_clocks(enable_init_clks, 3348c2ecf20Sopenharmony_ci ARRAY_SIZE(enable_init_clks)); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n", 3378c2ecf20Sopenharmony_ci (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 1000000), 3388c2ecf20Sopenharmony_ci (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 100000) % 10, 3398c2ecf20Sopenharmony_ci (clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000), 3408c2ecf20Sopenharmony_ci (clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000)); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (soc_type != OMAP3_SOC_OMAP3430_ES1) 3438c2ecf20Sopenharmony_ci omap3_clk_lock_dpll5(); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ciint __init omap3430_dt_clk_init(void) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3430_ES2_PLUS); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ciint __init omap3630_dt_clk_init(void) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3630); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ciint __init am35xx_dt_clk_init(void) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX); 3618c2ecf20Sopenharmony_ci} 362