blob: fdc060e75839f8cffb7abf43c0aae8de56a49b99 [file] [log] [blame]
Akshu Agrawal421bf6a2018-05-09 17:59:00 +08001// SPDX-License-Identifier: MIT
2/*
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +05303 * clock framework for AMD FCH controller block
Akshu Agrawal421bf6a2018-05-09 17:59:00 +08004 *
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>
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053011#include <linux/pci.h>
Akshu Agrawald58669b2020-07-31 19:06:01 +053012#include <linux/platform_data/clk-fch.h>
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080013#include <linux/platform_device.h>
14
15/* Clock Driving Strength 2 register */
16#define CLKDRVSTR2 0x28
17/* Clock Control 1 register */
18#define MISCCLKCNTL1 0x40
19/* Auxiliary clock1 enable bit */
20#define OSCCLKENB 2
21/* 25Mhz auxiliary output clock freq bit */
22#define OSCOUT1CLK25MHZ 16
23
24#define ST_CLK_48M 0
25#define ST_CLK_25M 1
26#define ST_CLK_MUX 2
27#define ST_CLK_GATE 3
28#define ST_MAX_CLKS 4
29
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053030#define CLK_48M_FIXED 0
31#define CLK_GATE_FIXED 1
32#define CLK_MAX_FIXED 2
33
34/* List of supported CPU ids for clk mux with 25Mhz clk support */
35#define AMD_CPU_ID_ST 0x1576
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053036
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080037static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" };
38static struct clk_hw *hws[ST_MAX_CLKS];
39
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053040static const struct pci_device_id fch_pci_ids[] = {
41 { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_ST) },
42 { }
43};
44
Akshu Agrawald9b77362020-07-31 19:06:02 +053045static int fch_clk_probe(struct platform_device *pdev)
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080046{
Akshu Agrawald9b77362020-07-31 19:06:02 +053047 struct fch_clk_data *fch_data;
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053048 struct pci_dev *rdev;
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080049
Akshu Agrawald9b77362020-07-31 19:06:02 +053050 fch_data = dev_get_platdata(&pdev->dev);
51 if (!fch_data || !fch_data->base)
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080052 return -EINVAL;
53
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053054 rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
55 if (!rdev) {
56 dev_err(&pdev->dev, "FCH device not found\n");
57 return -ENODEV;
58 }
59
60 if (pci_match_id(fch_pci_ids, rdev)) {
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053061 hws[ST_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz",
62 NULL, 0, 48000000);
63 hws[ST_CLK_25M] = clk_hw_register_fixed_rate(NULL, "clk25MHz",
64 NULL, 0, 25000000);
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080065
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053066 hws[ST_CLK_MUX] = clk_hw_register_mux(NULL, "oscout1_mux",
67 clk_oscout1_parents, ARRAY_SIZE(clk_oscout1_parents),
68 0, fch_data->base + CLKDRVSTR2, OSCOUT1CLK25MHZ, 3, 0,
69 NULL);
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080070
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053071 clk_set_parent(hws[ST_CLK_MUX]->clk, hws[ST_CLK_48M]->clk);
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080072
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053073 hws[ST_CLK_GATE] = clk_hw_register_gate(NULL, "oscout1",
74 "oscout1_mux", 0, fch_data->base + MISCCLKCNTL1,
75 OSCCLKENB, CLK_GATE_SET_TO_DISABLE, NULL);
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080076
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053077 devm_clk_hw_register_clkdev(&pdev->dev, hws[ST_CLK_GATE],
Ajit Kumar Pandeyc33917b2021-12-12 23:35:26 +053078 fch_data->name, NULL);
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053079 } else {
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053080 hws[CLK_48M_FIXED] = clk_hw_register_fixed_rate(NULL, "clk48MHz",
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053081 NULL, 0, 48000000);
82
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053083 hws[CLK_GATE_FIXED] = clk_hw_register_gate(NULL, "oscout1",
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053084 "clk48MHz", 0, fch_data->base + MISCCLKCNTL1,
Ajit Kumar Pandey1fdaaa12021-12-12 23:35:27 +053085 OSCCLKENB, 0, NULL);
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053086
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053087 devm_clk_hw_register_clkdev(&pdev->dev, hws[CLK_GATE_FIXED],
Ajit Kumar Pandeyc33917b2021-12-12 23:35:26 +053088 fch_data->name, NULL);
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053089 }
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080090
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053091 pci_dev_put(rdev);
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080092 return 0;
93}
94
Akshu Agrawald9b77362020-07-31 19:06:02 +053095static int fch_clk_remove(struct platform_device *pdev)
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080096{
Akshu Agrawal19fe87f2020-07-31 19:06:04 +053097 int i, clks;
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +053098 struct pci_dev *rdev;
Akshu Agrawal421bf6a2018-05-09 17:59:00 +080099
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +0530100 rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
101 if (!rdev)
102 return -ENODEV;
Akshu Agrawal19fe87f2020-07-31 19:06:04 +0530103
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +0530104 clks = pci_match_id(fch_pci_ids, rdev) ? CLK_MAX_FIXED : ST_MAX_CLKS;
Akshu Agrawal19fe87f2020-07-31 19:06:04 +0530105
106 for (i = 0; i < clks; i++)
Akshu Agrawal421bf6a2018-05-09 17:59:00 +0800107 clk_hw_unregister(hws[i]);
Akshu Agrawal19fe87f2020-07-31 19:06:04 +0530108
Ajit Kumar Pandey65ab8842021-12-12 23:35:23 +0530109 pci_dev_put(rdev);
Akshu Agrawal421bf6a2018-05-09 17:59:00 +0800110 return 0;
111}
112
Akshu Agrawald9b77362020-07-31 19:06:02 +0530113static struct platform_driver fch_clk_driver = {
Akshu Agrawal421bf6a2018-05-09 17:59:00 +0800114 .driver = {
Akshu Agrawald9b77362020-07-31 19:06:02 +0530115 .name = "clk-fch",
Akshu Agrawal421bf6a2018-05-09 17:59:00 +0800116 .suppress_bind_attrs = true,
117 },
Akshu Agrawald9b77362020-07-31 19:06:02 +0530118 .probe = fch_clk_probe,
119 .remove = fch_clk_remove,
Akshu Agrawal421bf6a2018-05-09 17:59:00 +0800120};
Akshu Agrawald9b77362020-07-31 19:06:02 +0530121builtin_platform_driver(fch_clk_driver);