162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * abx500 clock implementation for ux500 platform. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 ST-Ericsson SA 662306a36Sopenharmony_ci * Author: Ulf Hansson <ulf.hansson@linaro.org> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/device.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500.h> 1562306a36Sopenharmony_ci#include <linux/mfd/abx500/ab8500-sysctrl.h> 1662306a36Sopenharmony_ci#include <linux/clkdev.h> 1762306a36Sopenharmony_ci#include <linux/clk-provider.h> 1862306a36Sopenharmony_ci#include <dt-bindings/clock/ste-ab8500.h> 1962306a36Sopenharmony_ci#include "clk.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define AB8500_NUM_CLKS 6 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic struct clk *ab8500_clks[AB8500_NUM_CLKS]; 2462306a36Sopenharmony_cistatic struct clk_onecell_data ab8500_clk_data; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Clock definitions for ab8500 */ 2762306a36Sopenharmony_cistatic int ab8500_reg_clks(struct device *dev) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci int ret; 3062306a36Sopenharmony_ci struct clk *clk; 3162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 3262306a36Sopenharmony_ci const char *intclk_parents[] = {"ab8500_sysclk", "ulpclk"}; 3362306a36Sopenharmony_ci u16 intclk_reg_sel[] = {0 , AB8500_SYSULPCLKCTRL1}; 3462306a36Sopenharmony_ci u8 intclk_reg_mask[] = {0 , AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK}; 3562306a36Sopenharmony_ci u8 intclk_reg_bits[] = { 3662306a36Sopenharmony_ci 0 , 3762306a36Sopenharmony_ci (1 << AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT) 3862306a36Sopenharmony_ci }; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* Enable SWAT */ 4162306a36Sopenharmony_ci ret = ab8500_sysctrl_set(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE); 4262306a36Sopenharmony_ci if (ret) 4362306a36Sopenharmony_ci return ret; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* ab8500_sysclk2 */ 4662306a36Sopenharmony_ci clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk2", "ab8500_sysclk", 4762306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, 4862306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, 0, 0); 4962306a36Sopenharmony_ci ab8500_clks[AB8500_SYSCLK_BUF2] = clk; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* ab8500_sysclk3 */ 5262306a36Sopenharmony_ci clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk3", "ab8500_sysclk", 5362306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, 5462306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, 0, 0); 5562306a36Sopenharmony_ci ab8500_clks[AB8500_SYSCLK_BUF3] = clk; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* ab8500_sysclk4 */ 5862306a36Sopenharmony_ci clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk4", "ab8500_sysclk", 5962306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, 6062306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, 0, 0); 6162306a36Sopenharmony_ci ab8500_clks[AB8500_SYSCLK_BUF4] = clk; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* ab_ulpclk */ 6462306a36Sopenharmony_ci clk = clk_reg_sysctrl_gate_fixed_rate(dev, "ulpclk", NULL, 6562306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ, 6662306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1_ULPCLKREQ, 6762306a36Sopenharmony_ci 38400000, 9000, 0); 6862306a36Sopenharmony_ci ab8500_clks[AB8500_SYSCLK_ULP] = clk; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* ab8500_intclk */ 7162306a36Sopenharmony_ci clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2, 7262306a36Sopenharmony_ci intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0); 7362306a36Sopenharmony_ci ab8500_clks[AB8500_SYSCLK_INT] = clk; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* ab8500_audioclk */ 7662306a36Sopenharmony_ci clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk", 7762306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 7862306a36Sopenharmony_ci AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0); 7962306a36Sopenharmony_ci ab8500_clks[AB8500_SYSCLK_AUDIO] = clk; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ab8500_clk_data.clks = ab8500_clks; 8262306a36Sopenharmony_ci ab8500_clk_data.clk_num = ARRAY_SIZE(ab8500_clks); 8362306a36Sopenharmony_ci of_clk_add_provider(np, of_clk_src_onecell_get, &ab8500_clk_data); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci dev_info(dev, "registered clocks for ab850x\n"); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int abx500_clk_probe(struct platform_device *pdev) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent); 9362306a36Sopenharmony_ci int ret; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (is_ab8500(parent) || is_ab8505(parent)) { 9662306a36Sopenharmony_ci ret = ab8500_reg_clks(&pdev->dev); 9762306a36Sopenharmony_ci } else { 9862306a36Sopenharmony_ci dev_err(&pdev->dev, "non supported plf id\n"); 9962306a36Sopenharmony_ci return -ENODEV; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return ret; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic const struct of_device_id abx500_clk_match[] = { 10662306a36Sopenharmony_ci { .compatible = "stericsson,ab8500-clk", }, 10762306a36Sopenharmony_ci {} 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct platform_driver abx500_clk_driver = { 11162306a36Sopenharmony_ci .driver = { 11262306a36Sopenharmony_ci .name = "abx500-clk", 11362306a36Sopenharmony_ci .of_match_table = abx500_clk_match, 11462306a36Sopenharmony_ci }, 11562306a36Sopenharmony_ci .probe = abx500_clk_probe, 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int __init abx500_clk_init(void) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci return platform_driver_register(&abx500_clk_driver); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ciarch_initcall(abx500_clk_init); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciMODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org"); 12562306a36Sopenharmony_ciMODULE_DESCRIPTION("ABX500 clk driver"); 12662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 127