18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/mach-sa1100/clock.c 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/kernel.h> 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/err.h> 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <mach/hardware.h> 158c2ecf20Sopenharmony_ci#include <mach/generic.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic const char * const clk_tucr_parents[] = { 188c2ecf20Sopenharmony_ci "clk32768", "clk3686400", 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(tucr_lock); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic int clk_gpio27_enable(struct clk_hw *hw) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci unsigned long flags; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci /* 288c2ecf20Sopenharmony_ci * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: 298c2ecf20Sopenharmony_ci * (SA-1110 Developer's Manual, section 9.1.2.1) 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci local_irq_save(flags); 328c2ecf20Sopenharmony_ci GAFR |= GPIO_32_768kHz; 338c2ecf20Sopenharmony_ci GPDR |= GPIO_32_768kHz; 348c2ecf20Sopenharmony_ci local_irq_restore(flags); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return 0; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void clk_gpio27_disable(struct clk_hw *hw) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci unsigned long flags; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci local_irq_save(flags); 448c2ecf20Sopenharmony_ci GPDR &= ~GPIO_32_768kHz; 458c2ecf20Sopenharmony_ci GAFR &= ~GPIO_32_768kHz; 468c2ecf20Sopenharmony_ci local_irq_restore(flags); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic const struct clk_ops clk_gpio27_ops = { 508c2ecf20Sopenharmony_ci .enable = clk_gpio27_enable, 518c2ecf20Sopenharmony_ci .disable = clk_gpio27_disable, 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const char * const clk_gpio27_parents[] = { 558c2ecf20Sopenharmony_ci "tucr-mux", 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic const struct clk_init_data clk_gpio27_init_data __initconst = { 598c2ecf20Sopenharmony_ci .name = "gpio27", 608c2ecf20Sopenharmony_ci .ops = &clk_gpio27_ops, 618c2ecf20Sopenharmony_ci .parent_names = clk_gpio27_parents, 628c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(clk_gpio27_parents), 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* 668c2ecf20Sopenharmony_ci * Derived from the table 8-1 in the SA1110 manual, the MPLL appears to 678c2ecf20Sopenharmony_ci * multiply its input rate by 4 x (4 + PPCR). This calculation gives 688c2ecf20Sopenharmony_ci * the exact rate. The figures given in the table are the rates rounded 698c2ecf20Sopenharmony_ci * to 100kHz. Stick with sa11x0_getspeed() for the time being. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistatic unsigned long clk_mpll_recalc_rate(struct clk_hw *hw, 728c2ecf20Sopenharmony_ci unsigned long prate) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci return sa11x0_getspeed(0) * 1000; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const struct clk_ops clk_mpll_ops = { 788c2ecf20Sopenharmony_ci .recalc_rate = clk_mpll_recalc_rate, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const char * const clk_mpll_parents[] = { 828c2ecf20Sopenharmony_ci "clk3686400", 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic const struct clk_init_data clk_mpll_init_data __initconst = { 868c2ecf20Sopenharmony_ci .name = "mpll", 878c2ecf20Sopenharmony_ci .ops = &clk_mpll_ops, 888c2ecf20Sopenharmony_ci .parent_names = clk_mpll_parents, 898c2ecf20Sopenharmony_ci .num_parents = ARRAY_SIZE(clk_mpll_parents), 908c2ecf20Sopenharmony_ci .flags = CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL, 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciint __init sa11xx_clk_init(void) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct clk_hw *hw; 968c2ecf20Sopenharmony_ci int ret; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_rate(NULL, "clk32768", NULL, 0, 32768); 998c2ecf20Sopenharmony_ci if (IS_ERR(hw)) 1008c2ecf20Sopenharmony_ci return PTR_ERR(hw); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, NULL, "sa1100-rtc"); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_rate(NULL, "clk3686400", NULL, 0, 3686400); 1058c2ecf20Sopenharmony_ci if (IS_ERR(hw)) 1068c2ecf20Sopenharmony_ci return PTR_ERR(hw); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, "OSTIMER0", NULL); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci hw = kzalloc(sizeof(*hw), GFP_KERNEL); 1118c2ecf20Sopenharmony_ci if (!hw) 1128c2ecf20Sopenharmony_ci return -ENOMEM; 1138c2ecf20Sopenharmony_ci hw->init = &clk_mpll_init_data; 1148c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 1158c2ecf20Sopenharmony_ci if (ret) { 1168c2ecf20Sopenharmony_ci kfree(hw); 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, NULL, "sa11x0-fb"); 1218c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia"); 1228c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.0"); 1238c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.1"); 1248c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, NULL, "1800"); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci hw = clk_hw_register_mux(NULL, "tucr-mux", clk_tucr_parents, 1278c2ecf20Sopenharmony_ci ARRAY_SIZE(clk_tucr_parents), 0, 1288c2ecf20Sopenharmony_ci (void __iomem *)&TUCR, FShft(TUCR_TSEL), 1298c2ecf20Sopenharmony_ci FAlnMsk(TUCR_TSEL), 0, &tucr_lock); 1308c2ecf20Sopenharmony_ci clk_set_rate(hw->clk, 3686400); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci hw = kzalloc(sizeof(*hw), GFP_KERNEL); 1338c2ecf20Sopenharmony_ci if (!hw) 1348c2ecf20Sopenharmony_ci return -ENOMEM; 1358c2ecf20Sopenharmony_ci hw->init = &clk_gpio27_init_data; 1368c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 1378c2ecf20Sopenharmony_ci if (ret) { 1388c2ecf20Sopenharmony_ci kfree(hw); 1398c2ecf20Sopenharmony_ci return ret; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci clk_hw_register_clkdev(hw, NULL, "sa1111.0"); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 146