18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Sysctrl clock implementation for ux500 platform. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 ST-Ericsson SA 68c2ecf20Sopenharmony_ci * Author: Ulf Hansson <ulf.hansson@linaro.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 108c2ecf20Sopenharmony_ci#include <linux/mfd/abx500/ab8500-sysctrl.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include "clk.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define SYSCTRL_MAX_NUM_PARENTS 4 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define to_clk_sysctrl(_hw) container_of(_hw, struct clk_sysctrl, hw) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct clk_sysctrl { 238c2ecf20Sopenharmony_ci struct clk_hw hw; 248c2ecf20Sopenharmony_ci struct device *dev; 258c2ecf20Sopenharmony_ci u8 parent_index; 268c2ecf20Sopenharmony_ci u16 reg_sel[SYSCTRL_MAX_NUM_PARENTS]; 278c2ecf20Sopenharmony_ci u8 reg_mask[SYSCTRL_MAX_NUM_PARENTS]; 288c2ecf20Sopenharmony_ci u8 reg_bits[SYSCTRL_MAX_NUM_PARENTS]; 298c2ecf20Sopenharmony_ci unsigned long rate; 308c2ecf20Sopenharmony_ci unsigned long enable_delay_us; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Sysctrl clock operations. */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int clk_sysctrl_prepare(struct clk_hw *hw) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci int ret; 388c2ecf20Sopenharmony_ci struct clk_sysctrl *clk = to_clk_sysctrl(hw); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ret = ab8500_sysctrl_write(clk->reg_sel[0], clk->reg_mask[0], 418c2ecf20Sopenharmony_ci clk->reg_bits[0]); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!ret && clk->enable_delay_us) 448c2ecf20Sopenharmony_ci usleep_range(clk->enable_delay_us, clk->enable_delay_us + 458c2ecf20Sopenharmony_ci (clk->enable_delay_us >> 2)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return ret; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void clk_sysctrl_unprepare(struct clk_hw *hw) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct clk_sysctrl *clk = to_clk_sysctrl(hw); 538c2ecf20Sopenharmony_ci if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0])) 548c2ecf20Sopenharmony_ci dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n", 558c2ecf20Sopenharmony_ci __func__, clk_hw_get_name(hw)); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw, 598c2ecf20Sopenharmony_ci unsigned long parent_rate) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct clk_sysctrl *clk = to_clk_sysctrl(hw); 628c2ecf20Sopenharmony_ci return clk->rate; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int clk_sysctrl_set_parent(struct clk_hw *hw, u8 index) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct clk_sysctrl *clk = to_clk_sysctrl(hw); 688c2ecf20Sopenharmony_ci u8 old_index = clk->parent_index; 698c2ecf20Sopenharmony_ci int ret = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (clk->reg_sel[old_index]) { 728c2ecf20Sopenharmony_ci ret = ab8500_sysctrl_clear(clk->reg_sel[old_index], 738c2ecf20Sopenharmony_ci clk->reg_mask[old_index]); 748c2ecf20Sopenharmony_ci if (ret) 758c2ecf20Sopenharmony_ci return ret; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (clk->reg_sel[index]) { 798c2ecf20Sopenharmony_ci ret = ab8500_sysctrl_write(clk->reg_sel[index], 808c2ecf20Sopenharmony_ci clk->reg_mask[index], 818c2ecf20Sopenharmony_ci clk->reg_bits[index]); 828c2ecf20Sopenharmony_ci if (ret) { 838c2ecf20Sopenharmony_ci if (clk->reg_sel[old_index]) 848c2ecf20Sopenharmony_ci ab8500_sysctrl_write(clk->reg_sel[old_index], 858c2ecf20Sopenharmony_ci clk->reg_mask[old_index], 868c2ecf20Sopenharmony_ci clk->reg_bits[old_index]); 878c2ecf20Sopenharmony_ci return ret; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci clk->parent_index = index; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return ret; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic u8 clk_sysctrl_get_parent(struct clk_hw *hw) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct clk_sysctrl *clk = to_clk_sysctrl(hw); 988c2ecf20Sopenharmony_ci return clk->parent_index; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic const struct clk_ops clk_sysctrl_gate_ops = { 1028c2ecf20Sopenharmony_ci .prepare = clk_sysctrl_prepare, 1038c2ecf20Sopenharmony_ci .unprepare = clk_sysctrl_unprepare, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic const struct clk_ops clk_sysctrl_gate_fixed_rate_ops = { 1078c2ecf20Sopenharmony_ci .prepare = clk_sysctrl_prepare, 1088c2ecf20Sopenharmony_ci .unprepare = clk_sysctrl_unprepare, 1098c2ecf20Sopenharmony_ci .recalc_rate = clk_sysctrl_recalc_rate, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic const struct clk_ops clk_sysctrl_set_parent_ops = { 1138c2ecf20Sopenharmony_ci .set_parent = clk_sysctrl_set_parent, 1148c2ecf20Sopenharmony_ci .get_parent = clk_sysctrl_get_parent, 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic struct clk *clk_reg_sysctrl(struct device *dev, 1188c2ecf20Sopenharmony_ci const char *name, 1198c2ecf20Sopenharmony_ci const char **parent_names, 1208c2ecf20Sopenharmony_ci u8 num_parents, 1218c2ecf20Sopenharmony_ci u16 *reg_sel, 1228c2ecf20Sopenharmony_ci u8 *reg_mask, 1238c2ecf20Sopenharmony_ci u8 *reg_bits, 1248c2ecf20Sopenharmony_ci unsigned long rate, 1258c2ecf20Sopenharmony_ci unsigned long enable_delay_us, 1268c2ecf20Sopenharmony_ci unsigned long flags, 1278c2ecf20Sopenharmony_ci const struct clk_ops *clk_sysctrl_ops) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct clk_sysctrl *clk; 1308c2ecf20Sopenharmony_ci struct clk_init_data clk_sysctrl_init; 1318c2ecf20Sopenharmony_ci struct clk *clk_reg; 1328c2ecf20Sopenharmony_ci int i; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (!dev) 1358c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (!name || (num_parents > SYSCTRL_MAX_NUM_PARENTS)) { 1388c2ecf20Sopenharmony_ci dev_err(dev, "clk_sysctrl: invalid arguments passed\n"); 1398c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); 1438c2ecf20Sopenharmony_ci if (!clk) 1448c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* set main clock registers */ 1478c2ecf20Sopenharmony_ci clk->reg_sel[0] = reg_sel[0]; 1488c2ecf20Sopenharmony_ci clk->reg_bits[0] = reg_bits[0]; 1498c2ecf20Sopenharmony_ci clk->reg_mask[0] = reg_mask[0]; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* handle clocks with more than one parent */ 1528c2ecf20Sopenharmony_ci for (i = 1; i < num_parents; i++) { 1538c2ecf20Sopenharmony_ci clk->reg_sel[i] = reg_sel[i]; 1548c2ecf20Sopenharmony_ci clk->reg_bits[i] = reg_bits[i]; 1558c2ecf20Sopenharmony_ci clk->reg_mask[i] = reg_mask[i]; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci clk->parent_index = 0; 1598c2ecf20Sopenharmony_ci clk->rate = rate; 1608c2ecf20Sopenharmony_ci clk->enable_delay_us = enable_delay_us; 1618c2ecf20Sopenharmony_ci clk->dev = dev; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci clk_sysctrl_init.name = name; 1648c2ecf20Sopenharmony_ci clk_sysctrl_init.ops = clk_sysctrl_ops; 1658c2ecf20Sopenharmony_ci clk_sysctrl_init.flags = flags; 1668c2ecf20Sopenharmony_ci clk_sysctrl_init.parent_names = parent_names; 1678c2ecf20Sopenharmony_ci clk_sysctrl_init.num_parents = num_parents; 1688c2ecf20Sopenharmony_ci clk->hw.init = &clk_sysctrl_init; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci clk_reg = devm_clk_register(clk->dev, &clk->hw); 1718c2ecf20Sopenharmony_ci if (IS_ERR(clk_reg)) 1728c2ecf20Sopenharmony_ci dev_err(dev, "clk_sysctrl: clk_register failed\n"); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return clk_reg; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistruct clk *clk_reg_sysctrl_gate(struct device *dev, 1788c2ecf20Sopenharmony_ci const char *name, 1798c2ecf20Sopenharmony_ci const char *parent_name, 1808c2ecf20Sopenharmony_ci u16 reg_sel, 1818c2ecf20Sopenharmony_ci u8 reg_mask, 1828c2ecf20Sopenharmony_ci u8 reg_bits, 1838c2ecf20Sopenharmony_ci unsigned long enable_delay_us, 1848c2ecf20Sopenharmony_ci unsigned long flags) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci const char **parent_names = (parent_name ? &parent_name : NULL); 1878c2ecf20Sopenharmony_ci u8 num_parents = (parent_name ? 1 : 0); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return clk_reg_sysctrl(dev, name, parent_names, num_parents, 1908c2ecf20Sopenharmony_ci ®_sel, ®_mask, ®_bits, 0, enable_delay_us, 1918c2ecf20Sopenharmony_ci flags, &clk_sysctrl_gate_ops); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistruct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev, 1958c2ecf20Sopenharmony_ci const char *name, 1968c2ecf20Sopenharmony_ci const char *parent_name, 1978c2ecf20Sopenharmony_ci u16 reg_sel, 1988c2ecf20Sopenharmony_ci u8 reg_mask, 1998c2ecf20Sopenharmony_ci u8 reg_bits, 2008c2ecf20Sopenharmony_ci unsigned long rate, 2018c2ecf20Sopenharmony_ci unsigned long enable_delay_us, 2028c2ecf20Sopenharmony_ci unsigned long flags) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci const char **parent_names = (parent_name ? &parent_name : NULL); 2058c2ecf20Sopenharmony_ci u8 num_parents = (parent_name ? 1 : 0); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return clk_reg_sysctrl(dev, name, parent_names, num_parents, 2088c2ecf20Sopenharmony_ci ®_sel, ®_mask, ®_bits, 2098c2ecf20Sopenharmony_ci rate, enable_delay_us, flags, 2108c2ecf20Sopenharmony_ci &clk_sysctrl_gate_fixed_rate_ops); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistruct clk *clk_reg_sysctrl_set_parent(struct device *dev, 2148c2ecf20Sopenharmony_ci const char *name, 2158c2ecf20Sopenharmony_ci const char **parent_names, 2168c2ecf20Sopenharmony_ci u8 num_parents, 2178c2ecf20Sopenharmony_ci u16 *reg_sel, 2188c2ecf20Sopenharmony_ci u8 *reg_mask, 2198c2ecf20Sopenharmony_ci u8 *reg_bits, 2208c2ecf20Sopenharmony_ci unsigned long flags) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci return clk_reg_sysctrl(dev, name, parent_names, num_parents, 2238c2ecf20Sopenharmony_ci reg_sel, reg_mask, reg_bits, 0, 0, flags, 2248c2ecf20Sopenharmony_ci &clk_sysctrl_set_parent_ops); 2258c2ecf20Sopenharmony_ci} 226