File Index
Files and directories
Sign in
FILE

clk-starfive-jh7110-aon.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/starfive/clk-starfive-jh7110-aon.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * StarFive JH7110 Always-On Clock Driver
  4 *
  5 * Copyright (C) 2022 Emil Renner Berthing <kernel@esmil.dk>
  6 * Copyright (C) 2022 StarFive Technology Co., Ltd.
  7 */
  8
  9#include <linux/clk-provider.h>
 10#include <linux/io.h>
 11#include <linux/platform_device.h>
 12
 13#include <dt-bindings/clock/starfive,jh7110-crg.h>
 14
 15#include "clk-starfive-jh7110.h"
 16
 17/* external clocks */
 18#define JH7110_AONCLK_OSC		(JH7110_AONCLK_END + 0)
 19#define JH7110_AONCLK_GMAC0_RMII_REFIN	(JH7110_AONCLK_END + 1)
 20#define JH7110_AONCLK_GMAC0_RGMII_RXIN	(JH7110_AONCLK_END + 2)
 21#define JH7110_AONCLK_STG_AXIAHB	(JH7110_AONCLK_END + 3)
 22#define JH7110_AONCLK_APB_BUS		(JH7110_AONCLK_END + 4)
 23#define JH7110_AONCLK_GMAC0_GTXCLK	(JH7110_AONCLK_END + 5)
 24#define JH7110_AONCLK_RTC_OSC		(JH7110_AONCLK_END + 6)
 25
 26static const struct jh71x0_clk_data jh7110_aonclk_data[] = {
 27	/* source */
 28	JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC),
 29	JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 0, 2,
 30		    JH7110_AONCLK_OSC_DIV4,
 31		    JH7110_AONCLK_OSC),
 32	/* gmac0 */
 33	JH71X0_GATE(JH7110_AONCLK_GMAC0_AHB, "gmac0_ahb", 0, JH7110_AONCLK_STG_AXIAHB),
 34	JH71X0_GATE(JH7110_AONCLK_GMAC0_AXI, "gmac0_axi", 0, JH7110_AONCLK_STG_AXIAHB),
 35	JH71X0__DIV(JH7110_AONCLK_GMAC0_RMII_RTX, "gmac0_rmii_rtx", 30,
 36		    JH7110_AONCLK_GMAC0_RMII_REFIN),
 37	JH71X0_GMUX(JH7110_AONCLK_GMAC0_TX, "gmac0_tx",
 38		    CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2,
 39		    JH7110_AONCLK_GMAC0_GTXCLK,
 40		    JH7110_AONCLK_GMAC0_RMII_RTX),
 41	JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX),
 42	JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 0, 2,
 43		    JH7110_AONCLK_GMAC0_RGMII_RXIN,
 44		    JH7110_AONCLK_GMAC0_RMII_RTX),
 45	JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX),
 46	/* otpc */
 47	JH71X0_GATE(JH7110_AONCLK_OTPC_APB, "otpc_apb", 0, JH7110_AONCLK_APB_BUS),
 48	/* rtc */
 49	JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS),
 50	JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC),
 51	JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 0, 2,
 52		    JH7110_AONCLK_RTC_OSC,
 53		    JH7110_AONCLK_RTC_INTERNAL),
 54	JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC),
 55};
 56
 57static int jh7110_aoncrg_probe(struct platform_device *pdev)
 58{
 59	struct jh71x0_clk_priv *priv;
 60	unsigned int idx;
 61	int ret;
 62
 63	priv = devm_kzalloc(&pdev->dev,
 64			    struct_size(priv, reg, JH7110_AONCLK_END),
 65			    GFP_KERNEL);
 66	if (!priv)
 67		return -ENOMEM;
 68
 69	spin_lock_init(&priv->rmw_lock);
 70	priv->num_reg = JH7110_AONCLK_END;
 71	priv->dev = &pdev->dev;
 72	priv->base = devm_platform_ioremap_resource(pdev, 0);
 73	if (IS_ERR(priv->base))
 74		return PTR_ERR(priv->base);
 75
 76	for (idx = 0; idx < JH7110_AONCLK_END; idx++) {
 77		u32 max = jh7110_aonclk_data[idx].max;
 78		struct clk_parent_data parents[4] = {};
 79		struct clk_init_data init = {
 80			.name = jh7110_aonclk_data[idx].name,
 81			.ops = starfive_jh71x0_clk_ops(max),
 82			.parent_data = parents,
 83			.num_parents =
 84				((max & JH71X0_CLK_MUX_MASK) >> JH71X0_CLK_MUX_SHIFT) + 1,
 85			.flags = jh7110_aonclk_data[idx].flags,
 86		};
 87		struct jh71x0_clk *clk = &priv->reg[idx];
 88		unsigned int i;
 89
 90		for (i = 0; i < init.num_parents; i++) {
 91			unsigned int pidx = jh7110_aonclk_data[idx].parents[i];
 92
 93			if (pidx < JH7110_AONCLK_END)
 94				parents[i].hw = &priv->reg[pidx].hw;
 95			else if (pidx == JH7110_AONCLK_OSC)
 96				parents[i].fw_name = "osc";
 97			else if (pidx == JH7110_AONCLK_GMAC0_RMII_REFIN)
 98				parents[i].fw_name = "gmac0_rmii_refin";
 99			else if (pidx == JH7110_AONCLK_GMAC0_RGMII_RXIN)
100				parents[i].fw_name = "gmac0_rgmii_rxin";
101			else if (pidx == JH7110_AONCLK_STG_AXIAHB)
102				parents[i].fw_name = "stg_axiahb";
103			else if (pidx == JH7110_AONCLK_APB_BUS)
104				parents[i].fw_name = "apb_bus";
105			else if (pidx == JH7110_AONCLK_GMAC0_GTXCLK)
106				parents[i].fw_name = "gmac0_gtxclk";
107			else if (pidx == JH7110_AONCLK_RTC_OSC)
108				parents[i].fw_name = "rtc_osc";
109		}
110
111		clk->hw.init = &init;
112		clk->idx = idx;
113		clk->max_div = max & JH71X0_CLK_DIV_MASK;
114
115		ret = devm_clk_hw_register(&pdev->dev, &clk->hw);
116		if (ret)
117			return ret;
118	}
119
120	ret = devm_of_clk_add_hw_provider(&pdev->dev, jh71x0_clk_get, priv);
121	if (ret)
122		return ret;
123
124	return jh7110_reset_controller_register(priv, "rst-aon", 1);
125}
126
127static const struct of_device_id jh7110_aoncrg_match[] = {
128	{ .compatible = "starfive,jh7110-aoncrg" },
129	{ /* sentinel */ }
130};
131MODULE_DEVICE_TABLE(of, jh7110_aoncrg_match);
132
133static struct platform_driver jh7110_aoncrg_driver = {
134	.probe = jh7110_aoncrg_probe,
135	.driver = {
136		.name = "clk-starfive-jh7110-aon",
137		.of_match_table = jh7110_aoncrg_match,
138	},
139};
140module_platform_driver(jh7110_aoncrg_driver);
141
142MODULE_AUTHOR("Emil Renner Berthing");
143MODULE_DESCRIPTION("StarFive JH7110 always-on clock driver");
144MODULE_LICENSE("GPL");
~/ Read-only file preview.