xref: /linux/drivers/clk/x86/clk-fch.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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