Commit | Line | Data |
---|---|---|
421bf6a1 AA |
1 | // SPDX-License-Identifier: MIT |
2 | /* | |
3 | * clock framework for AMD Stoney based clocks | |
4 | * | |
5 | * Copyright 2018 Advanced Micro Devices, Inc. | |
6 | */ | |
7 | ||
8 | #include <linux/clk.h> | |
9 | #include <linux/clkdev.h> | |
10 | #include <linux/clk-provider.h> | |
11 | #include <linux/platform_data/clk-st.h> | |
12 | #include <linux/platform_device.h> | |
13 | ||
14 | /* Clock Driving Strength 2 register */ | |
15 | #define CLKDRVSTR2 0x28 | |
16 | /* Clock Control 1 register */ | |
17 | #define MISCCLKCNTL1 0x40 | |
18 | /* Auxiliary clock1 enable bit */ | |
19 | #define OSCCLKENB 2 | |
20 | /* 25Mhz auxiliary output clock freq bit */ | |
21 | #define OSCOUT1CLK25MHZ 16 | |
22 | ||
23 | #define ST_CLK_48M 0 | |
24 | #define ST_CLK_25M 1 | |
25 | #define ST_CLK_MUX 2 | |
26 | #define ST_CLK_GATE 3 | |
27 | #define ST_MAX_CLKS 4 | |
28 | ||
29 | static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" }; | |
30 | static struct clk_hw *hws[ST_MAX_CLKS]; | |
31 | ||
32 | static int st_clk_probe(struct platform_device *pdev) | |
33 | { | |
34 | struct st_clk_data *st_data; | |
35 | ||
36 | st_data = dev_get_platdata(&pdev->dev); | |
37 | if (!st_data || !st_data->base) | |
38 | return -EINVAL; | |
39 | ||
40 | hws[ST_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz", NULL, 0, | |
41 | 48000000); | |
42 | hws[ST_CLK_25M] = clk_hw_register_fixed_rate(NULL, "clk25MHz", NULL, 0, | |
43 | 25000000); | |
44 | ||
45 | hws[ST_CLK_MUX] = clk_hw_register_mux(NULL, "oscout1_mux", | |
46 | clk_oscout1_parents, ARRAY_SIZE(clk_oscout1_parents), | |
47 | 0, st_data->base + CLKDRVSTR2, OSCOUT1CLK25MHZ, 3, 0, NULL); | |
48 | ||
bded6c03 | 49 | clk_set_parent(hws[ST_CLK_MUX]->clk, hws[ST_CLK_48M]->clk); |
421bf6a1 AA |
50 | |
51 | hws[ST_CLK_GATE] = clk_hw_register_gate(NULL, "oscout1", "oscout1_mux", | |
52 | 0, st_data->base + MISCCLKCNTL1, OSCCLKENB, | |
53 | CLK_GATE_SET_TO_DISABLE, NULL); | |
54 | ||
55 | clk_hw_register_clkdev(hws[ST_CLK_GATE], "oscout1", NULL); | |
56 | ||
57 | return 0; | |
58 | } | |
59 | ||
60 | static int st_clk_remove(struct platform_device *pdev) | |
61 | { | |
62 | int i; | |
63 | ||
64 | for (i = 0; i < ST_MAX_CLKS; i++) | |
65 | clk_hw_unregister(hws[i]); | |
66 | return 0; | |
67 | } | |
68 | ||
69 | static struct platform_driver st_clk_driver = { | |
70 | .driver = { | |
71 | .name = "clk-st", | |
72 | .suppress_bind_attrs = true, | |
73 | }, | |
74 | .probe = st_clk_probe, | |
75 | .remove = st_clk_remove, | |
76 | }; | |
77 | builtin_platform_driver(st_clk_driver); |