1d9b77361SAkshu Agrawal // SPDX-License-Identifier: MIT
2d9b77361SAkshu Agrawal /*
365ab884aSAjit Kumar Pandey * clock framework for AMD FCH controller block
4d9b77361SAkshu Agrawal *
5d9b77361SAkshu Agrawal * Copyright 2018 Advanced Micro Devices, Inc.
6d9b77361SAkshu Agrawal */
7d9b77361SAkshu Agrawal
8d9b77361SAkshu Agrawal #include <linux/clk.h>
9d9b77361SAkshu Agrawal #include <linux/clkdev.h>
10d9b77361SAkshu Agrawal #include <linux/clk-provider.h>
1165ab884aSAjit Kumar Pandey #include <linux/pci.h>
12d9b77361SAkshu Agrawal #include <linux/platform_data/clk-fch.h>
13d9b77361SAkshu Agrawal #include <linux/platform_device.h>
14d9b77361SAkshu Agrawal
15d9b77361SAkshu Agrawal /* Clock Driving Strength 2 register */
16d9b77361SAkshu Agrawal #define CLKDRVSTR2 0x28
17d9b77361SAkshu Agrawal /* Clock Control 1 register */
18d9b77361SAkshu Agrawal #define MISCCLKCNTL1 0x40
19d9b77361SAkshu Agrawal /* Auxiliary clock1 enable bit */
20d9b77361SAkshu Agrawal #define OSCCLKENB 2
21d9b77361SAkshu Agrawal /* 25Mhz auxiliary output clock freq bit */
22d9b77361SAkshu Agrawal #define OSCOUT1CLK25MHZ 16
23d9b77361SAkshu Agrawal
24d9b77361SAkshu Agrawal #define ST_CLK_48M 0
25d9b77361SAkshu Agrawal #define ST_CLK_25M 1
26d9b77361SAkshu Agrawal #define ST_CLK_MUX 2
27d9b77361SAkshu Agrawal #define ST_CLK_GATE 3
28d9b77361SAkshu Agrawal #define ST_MAX_CLKS 4
29d9b77361SAkshu Agrawal
3065ab884aSAjit Kumar Pandey #define CLK_48M_FIXED 0
3165ab884aSAjit Kumar Pandey #define CLK_GATE_FIXED 1
3265ab884aSAjit Kumar Pandey #define CLK_MAX_FIXED 2
3365ab884aSAjit Kumar Pandey
3465ab884aSAjit Kumar Pandey /* List of supported CPU ids for clk mux with 25Mhz clk support */
3565ab884aSAjit Kumar Pandey #define AMD_CPU_ID_ST 0x1576
3619fe87fdSAkshu Agrawal
37d9b77361SAkshu Agrawal static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" };
38d9b77361SAkshu Agrawal static struct clk_hw *hws[ST_MAX_CLKS];
39d9b77361SAkshu Agrawal
4065ab884aSAjit Kumar Pandey static const struct pci_device_id fch_pci_ids[] = {
4165ab884aSAjit Kumar Pandey { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_ST) },
4265ab884aSAjit Kumar Pandey { }
4365ab884aSAjit Kumar Pandey };
4465ab884aSAjit Kumar Pandey
fch_clk_probe(struct platform_device * pdev)45d9b77361SAkshu Agrawal static int fch_clk_probe(struct platform_device *pdev)
46d9b77361SAkshu Agrawal {
47d9b77361SAkshu Agrawal struct fch_clk_data *fch_data;
4865ab884aSAjit Kumar Pandey struct pci_dev *rdev;
49d9b77361SAkshu Agrawal
50d9b77361SAkshu Agrawal fch_data = dev_get_platdata(&pdev->dev);
51d9b77361SAkshu Agrawal if (!fch_data || !fch_data->base)
52d9b77361SAkshu Agrawal return -EINVAL;
53d9b77361SAkshu Agrawal
5465ab884aSAjit Kumar Pandey rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
5565ab884aSAjit Kumar Pandey if (!rdev) {
5665ab884aSAjit Kumar Pandey dev_err(&pdev->dev, "FCH device not found\n");
5765ab884aSAjit Kumar Pandey return -ENODEV;
5865ab884aSAjit Kumar Pandey }
5965ab884aSAjit Kumar Pandey
6065ab884aSAjit Kumar Pandey if (pci_match_id(fch_pci_ids, rdev)) {
6119fe87fdSAkshu Agrawal hws[ST_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz",
6219fe87fdSAkshu Agrawal NULL, 0, 48000000);
6319fe87fdSAkshu Agrawal hws[ST_CLK_25M] = clk_hw_register_fixed_rate(NULL, "clk25MHz",
6419fe87fdSAkshu Agrawal NULL, 0, 25000000);
65d9b77361SAkshu Agrawal
66d9b77361SAkshu Agrawal hws[ST_CLK_MUX] = clk_hw_register_mux(NULL, "oscout1_mux",
67d9b77361SAkshu Agrawal clk_oscout1_parents, ARRAY_SIZE(clk_oscout1_parents),
6819fe87fdSAkshu Agrawal 0, fch_data->base + CLKDRVSTR2, OSCOUT1CLK25MHZ, 3, 0,
6919fe87fdSAkshu Agrawal NULL);
70d9b77361SAkshu Agrawal
71d9b77361SAkshu Agrawal clk_set_parent(hws[ST_CLK_MUX]->clk, hws[ST_CLK_48M]->clk);
72d9b77361SAkshu Agrawal
7319fe87fdSAkshu Agrawal hws[ST_CLK_GATE] = clk_hw_register_gate(NULL, "oscout1",
7419fe87fdSAkshu Agrawal "oscout1_mux", 0, fch_data->base + MISCCLKCNTL1,
7519fe87fdSAkshu Agrawal OSCCLKENB, CLK_GATE_SET_TO_DISABLE, NULL);
76d9b77361SAkshu Agrawal
7719fe87fdSAkshu Agrawal devm_clk_hw_register_clkdev(&pdev->dev, hws[ST_CLK_GATE],
78c33917b4SAjit Kumar Pandey fch_data->name, NULL);
7919fe87fdSAkshu Agrawal } else {
8065ab884aSAjit Kumar Pandey hws[CLK_48M_FIXED] = clk_hw_register_fixed_rate(NULL, "clk48MHz",
8119fe87fdSAkshu Agrawal NULL, 0, 48000000);
8219fe87fdSAkshu Agrawal
8365ab884aSAjit Kumar Pandey hws[CLK_GATE_FIXED] = clk_hw_register_gate(NULL, "oscout1",
8419fe87fdSAkshu Agrawal "clk48MHz", 0, fch_data->base + MISCCLKCNTL1,
851fdaaa13SAjit Kumar Pandey OSCCLKENB, 0, NULL);
8619fe87fdSAkshu Agrawal
8765ab884aSAjit Kumar Pandey devm_clk_hw_register_clkdev(&pdev->dev, hws[CLK_GATE_FIXED],
88c33917b4SAjit Kumar Pandey fch_data->name, NULL);
8919fe87fdSAkshu Agrawal }
90d9b77361SAkshu Agrawal
9165ab884aSAjit Kumar Pandey pci_dev_put(rdev);
92d9b77361SAkshu Agrawal return 0;
93d9b77361SAkshu Agrawal }
94d9b77361SAkshu Agrawal
fch_clk_remove(struct platform_device * pdev)954690d246SUwe Kleine-König static void fch_clk_remove(struct platform_device *pdev)
96d9b77361SAkshu Agrawal {
9719fe87fdSAkshu Agrawal int i, clks;
9865ab884aSAjit Kumar Pandey struct pci_dev *rdev;
99d9b77361SAkshu Agrawal
10065ab884aSAjit Kumar Pandey rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
10165ab884aSAjit Kumar Pandey if (!rdev)
1024690d246SUwe Kleine-König return;
10319fe87fdSAkshu Agrawal
10465ab884aSAjit Kumar Pandey clks = pci_match_id(fch_pci_ids, rdev) ? CLK_MAX_FIXED : ST_MAX_CLKS;
10519fe87fdSAkshu Agrawal
10619fe87fdSAkshu Agrawal for (i = 0; i < clks; i++)
107d9b77361SAkshu Agrawal clk_hw_unregister(hws[i]);
10819fe87fdSAkshu Agrawal
10965ab884aSAjit Kumar Pandey pci_dev_put(rdev);
110d9b77361SAkshu Agrawal }
111d9b77361SAkshu Agrawal
112d9b77361SAkshu Agrawal static struct platform_driver fch_clk_driver = {
113d9b77361SAkshu Agrawal .driver = {
114d9b77361SAkshu Agrawal .name = "clk-fch",
115d9b77361SAkshu Agrawal .suppress_bind_attrs = true,
116d9b77361SAkshu Agrawal },
117d9b77361SAkshu Agrawal .probe = fch_clk_probe,
118*f00b45dbSUwe Kleine-König .remove = fch_clk_remove,
119d9b77361SAkshu Agrawal };
120d9b77361SAkshu Agrawal builtin_platform_driver(fch_clk_driver);
121