linux/drivers/clk/x86/clk-st.c
<<
>>
Prefs
   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
  29static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" };
  30static struct clk_hw *hws[ST_MAX_CLKS];
  31
  32static 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
  49        clk_set_parent(hws[ST_CLK_MUX]->clk, hws[ST_CLK_48M]->clk);
  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
  60static 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
  69static 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};
  77builtin_platform_driver(st_clk_driver);
  78