| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * abx500 clock implementation for ux500 platform. | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2012 ST-Ericsson SA | 
|  | 5 | * Author: Ulf Hansson <ulf.hansson@linaro.org> | 
|  | 6 | * | 
|  | 7 | * License terms: GNU General Public License (GPL) version 2 | 
|  | 8 | */ | 
|  | 9 |  | 
|  | 10 | #include <linux/err.h> | 
|  | 11 | #include <linux/module.h> | 
|  | 12 | #include <linux/device.h> | 
|  | 13 | #include <linux/of.h> | 
|  | 14 | #include <linux/platform_device.h> | 
|  | 15 | #include <linux/mfd/abx500/ab8500.h> | 
|  | 16 | #include <linux/mfd/abx500/ab8500-sysctrl.h> | 
|  | 17 | #include <linux/clkdev.h> | 
|  | 18 | #include <linux/clk-provider.h> | 
|  | 19 | #include <dt-bindings/clock/ste-ab8500.h> | 
|  | 20 | #include "clk.h" | 
|  | 21 |  | 
|  | 22 | #define AB8500_NUM_CLKS 6 | 
|  | 23 |  | 
|  | 24 | static struct clk *ab8500_clks[AB8500_NUM_CLKS]; | 
|  | 25 | static struct clk_onecell_data ab8500_clk_data; | 
|  | 26 |  | 
|  | 27 | /* Clock definitions for ab8500 */ | 
|  | 28 | static int ab8500_reg_clks(struct device *dev) | 
|  | 29 | { | 
|  | 30 | int ret; | 
|  | 31 | struct clk *clk; | 
|  | 32 | struct device_node *np = dev->of_node; | 
|  | 33 | const char *intclk_parents[] = {"ab8500_sysclk", "ulpclk"}; | 
|  | 34 | u16 intclk_reg_sel[] = {0 , AB8500_SYSULPCLKCTRL1}; | 
|  | 35 | u8 intclk_reg_mask[] = {0 , AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK}; | 
|  | 36 | u8 intclk_reg_bits[] = { | 
|  | 37 | 0 , | 
|  | 38 | (1 << AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT) | 
|  | 39 | }; | 
|  | 40 |  | 
|  | 41 | /* Enable SWAT */ | 
|  | 42 | ret = ab8500_sysctrl_set(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE); | 
|  | 43 | if (ret) | 
|  | 44 | return ret; | 
|  | 45 |  | 
|  | 46 | /* ab8500_sysclk2 */ | 
|  | 47 | clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk2", "ab8500_sysclk", | 
|  | 48 | AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, | 
|  | 49 | AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, 0, 0); | 
|  | 50 | ab8500_clks[AB8500_SYSCLK_BUF2] = clk; | 
|  | 51 |  | 
|  | 52 | /* ab8500_sysclk3 */ | 
|  | 53 | clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk3", "ab8500_sysclk", | 
|  | 54 | AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, | 
|  | 55 | AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, 0, 0); | 
|  | 56 | ab8500_clks[AB8500_SYSCLK_BUF3] = clk; | 
|  | 57 |  | 
|  | 58 | /* ab8500_sysclk4 */ | 
|  | 59 | clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk4", "ab8500_sysclk", | 
|  | 60 | AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, | 
|  | 61 | AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, 0, 0); | 
|  | 62 | ab8500_clks[AB8500_SYSCLK_BUF4] = clk; | 
|  | 63 |  | 
|  | 64 | /* ab_ulpclk */ | 
|  | 65 | clk = clk_reg_sysctrl_gate_fixed_rate(dev, "ulpclk", NULL, | 
|  | 66 | AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ, | 
|  | 67 | AB8500_SYSULPCLKCTRL1_ULPCLKREQ, | 
|  | 68 | 38400000, 9000, 0); | 
|  | 69 | ab8500_clks[AB8500_SYSCLK_ULP] = clk; | 
|  | 70 |  | 
|  | 71 | /* ab8500_intclk */ | 
|  | 72 | clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2, | 
|  | 73 | intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0); | 
|  | 74 | ab8500_clks[AB8500_SYSCLK_INT] = clk; | 
|  | 75 |  | 
|  | 76 | /* ab8500_audioclk */ | 
|  | 77 | clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk", | 
|  | 78 | AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, | 
|  | 79 | AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0); | 
|  | 80 | ab8500_clks[AB8500_SYSCLK_AUDIO] = clk; | 
|  | 81 |  | 
|  | 82 | ab8500_clk_data.clks = ab8500_clks; | 
|  | 83 | ab8500_clk_data.clk_num = ARRAY_SIZE(ab8500_clks); | 
|  | 84 | of_clk_add_provider(np, of_clk_src_onecell_get, &ab8500_clk_data); | 
|  | 85 |  | 
|  | 86 | dev_info(dev, "registered clocks for ab850x\n"); | 
|  | 87 |  | 
|  | 88 | return 0; | 
|  | 89 | } | 
|  | 90 |  | 
|  | 91 | static int abx500_clk_probe(struct platform_device *pdev) | 
|  | 92 | { | 
|  | 93 | struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent); | 
|  | 94 | int ret; | 
|  | 95 |  | 
|  | 96 | if (is_ab8500(parent) || is_ab8505(parent)) { | 
|  | 97 | ret = ab8500_reg_clks(&pdev->dev); | 
|  | 98 | } else { | 
|  | 99 | dev_err(&pdev->dev, "non supported plf id\n"); | 
|  | 100 | return -ENODEV; | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | return ret; | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | static const struct of_device_id abx500_clk_match[] = { | 
|  | 107 | { .compatible = "stericsson,ab8500-clk", }, | 
|  | 108 | {} | 
|  | 109 | }; | 
|  | 110 |  | 
|  | 111 | static struct platform_driver abx500_clk_driver = { | 
|  | 112 | .driver = { | 
|  | 113 | .name = "abx500-clk", | 
|  | 114 | .of_match_table = abx500_clk_match, | 
|  | 115 | }, | 
|  | 116 | .probe	= abx500_clk_probe, | 
|  | 117 | }; | 
|  | 118 |  | 
|  | 119 | static int __init abx500_clk_init(void) | 
|  | 120 | { | 
|  | 121 | return platform_driver_register(&abx500_clk_driver); | 
|  | 122 | } | 
|  | 123 | arch_initcall(abx500_clk_init); | 
|  | 124 |  | 
|  | 125 | MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org"); | 
|  | 126 | MODULE_DESCRIPTION("ABX500 clk driver"); | 
|  | 127 | MODULE_LICENSE("GPL v2"); |