brintos

brintos / linux-shallow public Read only

0
0
Text · 3.0 KiB · cf5cd3a Raw
121 lines · c
1// SPDX-License-Identifier: MIT2/*3 * clock framework for AMD FCH controller block4 *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/pci.h>12#include <linux/platform_data/clk-fch.h>13#include <linux/platform_device.h>14 15/* Clock Driving Strength 2 register */16#define CLKDRVSTR2	0x2817/* Clock Control 1 register */18#define MISCCLKCNTL1	0x4019/* Auxiliary clock1 enable bit */20#define OSCCLKENB	221/* 25Mhz auxiliary output clock freq bit */22#define OSCOUT1CLK25MHZ	1623 24#define ST_CLK_48M	025#define ST_CLK_25M	126#define ST_CLK_MUX	227#define ST_CLK_GATE	328#define ST_MAX_CLKS	429 30#define CLK_48M_FIXED	031#define CLK_GATE_FIXED	132#define CLK_MAX_FIXED	233 34/* List of supported CPU ids for clk mux with 25Mhz clk support */35#define AMD_CPU_ID_ST                  0x157636 37static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" };38static struct clk_hw *hws[ST_MAX_CLKS];39 40static const struct pci_device_id fch_pci_ids[] = {41	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_ST) },42	{ }43};44 45static int fch_clk_probe(struct platform_device *pdev)46{47	struct fch_clk_data *fch_data;48	struct pci_dev *rdev;49 50	fch_data = dev_get_platdata(&pdev->dev);51	if (!fch_data || !fch_data->base)52		return -EINVAL;53 54	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)) {61		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);65 66		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);70 71		clk_set_parent(hws[ST_CLK_MUX]->clk, hws[ST_CLK_48M]->clk);72 73		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);76 77		devm_clk_hw_register_clkdev(&pdev->dev, hws[ST_CLK_GATE],78					    fch_data->name, NULL);79	} else {80		hws[CLK_48M_FIXED] = clk_hw_register_fixed_rate(NULL, "clk48MHz",81			NULL, 0, 48000000);82 83		hws[CLK_GATE_FIXED] = clk_hw_register_gate(NULL, "oscout1",84			"clk48MHz", 0, fch_data->base + MISCCLKCNTL1,85			OSCCLKENB, 0, NULL);86 87		devm_clk_hw_register_clkdev(&pdev->dev, hws[CLK_GATE_FIXED],88					    fch_data->name, NULL);89	}90 91	pci_dev_put(rdev);92	return 0;93}94 95static void fch_clk_remove(struct platform_device *pdev)96{97	int i, clks;98	struct pci_dev *rdev;99 100	rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));101	if (!rdev)102		return;103 104	clks = pci_match_id(fch_pci_ids, rdev) ? CLK_MAX_FIXED : ST_MAX_CLKS;105 106	for (i = 0; i < clks; i++)107		clk_hw_unregister(hws[i]);108 109	pci_dev_put(rdev);110}111 112static struct platform_driver fch_clk_driver = {113	.driver = {114		.name = "clk-fch",115		.suppress_bind_attrs = true,116	},117	.probe = fch_clk_probe,118	.remove = fch_clk_remove,119};120builtin_platform_driver(fch_clk_driver);121