1*af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
245228ef3SUlf Hansson /*
345228ef3SUlf Hansson * abx500 clock implementation for ux500 platform.
445228ef3SUlf Hansson *
545228ef3SUlf Hansson * Copyright (C) 2012 ST-Ericsson SA
645228ef3SUlf Hansson * Author: Ulf Hansson <ulf.hansson@linaro.org>
745228ef3SUlf Hansson */
845228ef3SUlf Hansson
945228ef3SUlf Hansson #include <linux/err.h>
1045228ef3SUlf Hansson #include <linux/module.h>
1145228ef3SUlf Hansson #include <linux/device.h>
1255921ce2SLinus Walleij #include <linux/of.h>
1345228ef3SUlf Hansson #include <linux/platform_device.h>
1445228ef3SUlf Hansson #include <linux/mfd/abx500/ab8500.h>
15312f0f0bSUlf Hansson #include <linux/mfd/abx500/ab8500-sysctrl.h>
16312f0f0bSUlf Hansson #include <linux/clkdev.h>
17312f0f0bSUlf Hansson #include <linux/clk-provider.h>
1855921ce2SLinus Walleij #include <dt-bindings/clock/ste-ab8500.h>
19312f0f0bSUlf Hansson #include "clk.h"
2045228ef3SUlf Hansson
2155921ce2SLinus Walleij #define AB8500_NUM_CLKS 6
2255921ce2SLinus Walleij
2355921ce2SLinus Walleij static struct clk *ab8500_clks[AB8500_NUM_CLKS];
2455921ce2SLinus Walleij static struct clk_onecell_data ab8500_clk_data;
2555921ce2SLinus Walleij
2645228ef3SUlf Hansson /* Clock definitions for ab8500 */
ab8500_reg_clks(struct device * dev)2745228ef3SUlf Hansson static int ab8500_reg_clks(struct device *dev)
2845228ef3SUlf Hansson {
29312f0f0bSUlf Hansson int ret;
30312f0f0bSUlf Hansson struct clk *clk;
3155921ce2SLinus Walleij struct device_node *np = dev->of_node;
32312f0f0bSUlf Hansson const char *intclk_parents[] = {"ab8500_sysclk", "ulpclk"};
33312f0f0bSUlf Hansson u16 intclk_reg_sel[] = {0 , AB8500_SYSULPCLKCTRL1};
34312f0f0bSUlf Hansson u8 intclk_reg_mask[] = {0 , AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK};
35312f0f0bSUlf Hansson u8 intclk_reg_bits[] = {
36312f0f0bSUlf Hansson 0 ,
37312f0f0bSUlf Hansson (1 << AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT)
38312f0f0bSUlf Hansson };
39312f0f0bSUlf Hansson
40312f0f0bSUlf Hansson /* Enable SWAT */
41312f0f0bSUlf Hansson ret = ab8500_sysctrl_set(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE);
42312f0f0bSUlf Hansson if (ret)
43312f0f0bSUlf Hansson return ret;
44312f0f0bSUlf Hansson
45312f0f0bSUlf Hansson /* ab8500_sysclk2 */
46312f0f0bSUlf Hansson clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk2", "ab8500_sysclk",
47312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ,
48312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, 0, 0);
4955921ce2SLinus Walleij ab8500_clks[AB8500_SYSCLK_BUF2] = clk;
50312f0f0bSUlf Hansson
51312f0f0bSUlf Hansson /* ab8500_sysclk3 */
52312f0f0bSUlf Hansson clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk3", "ab8500_sysclk",
53312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ,
54312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, 0, 0);
5555921ce2SLinus Walleij ab8500_clks[AB8500_SYSCLK_BUF3] = clk;
56312f0f0bSUlf Hansson
57312f0f0bSUlf Hansson /* ab8500_sysclk4 */
58312f0f0bSUlf Hansson clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk4", "ab8500_sysclk",
59312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ,
60312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, 0, 0);
6155921ce2SLinus Walleij ab8500_clks[AB8500_SYSCLK_BUF4] = clk;
62312f0f0bSUlf Hansson
63312f0f0bSUlf Hansson /* ab_ulpclk */
64312f0f0bSUlf Hansson clk = clk_reg_sysctrl_gate_fixed_rate(dev, "ulpclk", NULL,
65312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
66312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
6766f4ae77SStephen Boyd 38400000, 9000, 0);
6855921ce2SLinus Walleij ab8500_clks[AB8500_SYSCLK_ULP] = clk;
69312f0f0bSUlf Hansson
70312f0f0bSUlf Hansson /* ab8500_intclk */
71312f0f0bSUlf Hansson clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2,
72312f0f0bSUlf Hansson intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0);
7355921ce2SLinus Walleij ab8500_clks[AB8500_SYSCLK_INT] = clk;
74312f0f0bSUlf Hansson
75312f0f0bSUlf Hansson /* ab8500_audioclk */
76312f0f0bSUlf Hansson clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk",
77312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA,
78312f0f0bSUlf Hansson AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0);
7955921ce2SLinus Walleij ab8500_clks[AB8500_SYSCLK_AUDIO] = clk;
8055921ce2SLinus Walleij
8155921ce2SLinus Walleij ab8500_clk_data.clks = ab8500_clks;
8255921ce2SLinus Walleij ab8500_clk_data.clk_num = ARRAY_SIZE(ab8500_clks);
8355921ce2SLinus Walleij of_clk_add_provider(np, of_clk_src_onecell_get, &ab8500_clk_data);
8455921ce2SLinus Walleij
8555921ce2SLinus Walleij dev_info(dev, "registered clocks for ab850x\n");
86312f0f0bSUlf Hansson
8745228ef3SUlf Hansson return 0;
8845228ef3SUlf Hansson }
8945228ef3SUlf Hansson
abx500_clk_probe(struct platform_device * pdev)900fe763c5SGreg Kroah-Hartman static int abx500_clk_probe(struct platform_device *pdev)
9145228ef3SUlf Hansson {
9245228ef3SUlf Hansson struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent);
9345228ef3SUlf Hansson int ret;
9445228ef3SUlf Hansson
9545228ef3SUlf Hansson if (is_ab8500(parent) || is_ab8505(parent)) {
9645228ef3SUlf Hansson ret = ab8500_reg_clks(&pdev->dev);
9745228ef3SUlf Hansson } else {
9845228ef3SUlf Hansson dev_err(&pdev->dev, "non supported plf id\n");
9945228ef3SUlf Hansson return -ENODEV;
10045228ef3SUlf Hansson }
10145228ef3SUlf Hansson
10245228ef3SUlf Hansson return ret;
10345228ef3SUlf Hansson }
10445228ef3SUlf Hansson
10555921ce2SLinus Walleij static const struct of_device_id abx500_clk_match[] = {
10655921ce2SLinus Walleij { .compatible = "stericsson,ab8500-clk", },
10755921ce2SLinus Walleij {}
10855921ce2SLinus Walleij };
10955921ce2SLinus Walleij
11045228ef3SUlf Hansson static struct platform_driver abx500_clk_driver = {
11145228ef3SUlf Hansson .driver = {
11245228ef3SUlf Hansson .name = "abx500-clk",
11355921ce2SLinus Walleij .of_match_table = abx500_clk_match,
11445228ef3SUlf Hansson },
11545228ef3SUlf Hansson .probe = abx500_clk_probe,
11645228ef3SUlf Hansson };
11745228ef3SUlf Hansson
abx500_clk_init(void)11845228ef3SUlf Hansson static int __init abx500_clk_init(void)
11945228ef3SUlf Hansson {
12045228ef3SUlf Hansson return platform_driver_register(&abx500_clk_driver);
12145228ef3SUlf Hansson }
12245228ef3SUlf Hansson arch_initcall(abx500_clk_init);
12345228ef3SUlf Hansson
12445228ef3SUlf Hansson MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org");
12545228ef3SUlf Hansson MODULE_DESCRIPTION("ABX500 clk driver");
12645228ef3SUlf Hansson MODULE_LICENSE("GPL v2");
127