Linux Audio

Check our new training course

Open-source upstreaming

Need help get the support for your hardware in upstream Linux?
Loading...
Note: File does not exist in v6.13.7.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2019 Baylibre, SAS.
  3 * Author: Jerome Brunet <jbrunet@baylibre.com>
  4 */
  5
  6#include <linux/bitfield.h>
  7#include <linux/clk.h>
  8#include <linux/clk-provider.h>
  9#include <linux/device.h>
 10#include <linux/io.h>
 11#include <linux/iopoll.h>
 12#include <linux/mdio-mux.h>
 13#include <linux/module.h>
 14#include <linux/phy.h>
 15#include <linux/platform_device.h>
 16
 17#define ETH_PLL_STS		0x40
 18#define ETH_PLL_CTL0		0x44
 19#define  PLL_CTL0_LOCK_DIG	BIT(30)
 20#define  PLL_CTL0_RST		BIT(29)
 21#define  PLL_CTL0_EN		BIT(28)
 22#define  PLL_CTL0_SEL		BIT(23)
 23#define  PLL_CTL0_N		GENMASK(14, 10)
 24#define  PLL_CTL0_M		GENMASK(8, 0)
 25#define  PLL_LOCK_TIMEOUT	1000000
 26#define  PLL_MUX_NUM_PARENT	2
 27#define ETH_PLL_CTL1		0x48
 28#define ETH_PLL_CTL2		0x4c
 29#define ETH_PLL_CTL3		0x50
 30#define ETH_PLL_CTL4		0x54
 31#define ETH_PLL_CTL5		0x58
 32#define ETH_PLL_CTL6		0x5c
 33#define ETH_PLL_CTL7		0x60
 34
 35#define ETH_PHY_CNTL0		0x80
 36#define   EPHY_G12A_ID		0x33010180
 37#define ETH_PHY_CNTL1		0x84
 38#define  PHY_CNTL1_ST_MODE	GENMASK(2, 0)
 39#define  PHY_CNTL1_ST_PHYADD	GENMASK(7, 3)
 40#define   EPHY_DFLT_ADD		8
 41#define  PHY_CNTL1_MII_MODE	GENMASK(15, 14)
 42#define   EPHY_MODE_RMII	0x1
 43#define  PHY_CNTL1_CLK_EN	BIT(16)
 44#define  PHY_CNTL1_CLKFREQ	BIT(17)
 45#define  PHY_CNTL1_PHY_ENB	BIT(18)
 46#define ETH_PHY_CNTL2		0x88
 47#define  PHY_CNTL2_USE_INTERNAL	BIT(5)
 48#define  PHY_CNTL2_SMI_SRC_MAC	BIT(6)
 49#define  PHY_CNTL2_RX_CLK_EPHY	BIT(9)
 50
 51#define MESON_G12A_MDIO_EXTERNAL_ID 0
 52#define MESON_G12A_MDIO_INTERNAL_ID 1
 53
 54struct g12a_mdio_mux {
 55	bool pll_is_enabled;
 56	void __iomem *regs;
 57	void *mux_handle;
 58	struct clk *pclk;
 59	struct clk *pll;
 60};
 61
 62struct g12a_ephy_pll {
 63	void __iomem *base;
 64	struct clk_hw hw;
 65};
 66
 67#define g12a_ephy_pll_to_dev(_hw)			\
 68	container_of(_hw, struct g12a_ephy_pll, hw)
 69
 70static unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw,
 71					       unsigned long parent_rate)
 72{
 73	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
 74	u32 val, m, n;
 75
 76	val = readl(pll->base + ETH_PLL_CTL0);
 77	m = FIELD_GET(PLL_CTL0_M, val);
 78	n = FIELD_GET(PLL_CTL0_N, val);
 79
 80	return parent_rate * m / n;
 81}
 82
 83static int g12a_ephy_pll_enable(struct clk_hw *hw)
 84{
 85	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
 86	u32 val = readl(pll->base + ETH_PLL_CTL0);
 87
 88	/* Apply both enable an reset */
 89	val |= PLL_CTL0_RST | PLL_CTL0_EN;
 90	writel(val, pll->base + ETH_PLL_CTL0);
 91
 92	/* Clear the reset to let PLL lock */
 93	val &= ~PLL_CTL0_RST;
 94	writel(val, pll->base + ETH_PLL_CTL0);
 95
 96	/* Poll on the digital lock instead of the usual analog lock
 97	 * This is done because bit 31 is unreliable on some SoC. Bit
 98	 * 31 may indicate that the PLL is not lock eventhough the clock
 99	 * is actually running
100	 */
101	return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val,
102				  val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT);
103}
104
105static void g12a_ephy_pll_disable(struct clk_hw *hw)
106{
107	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
108	u32 val;
109
110	val = readl(pll->base + ETH_PLL_CTL0);
111	val &= ~PLL_CTL0_EN;
112	val |= PLL_CTL0_RST;
113	writel(val, pll->base + ETH_PLL_CTL0);
114}
115
116static int g12a_ephy_pll_is_enabled(struct clk_hw *hw)
117{
118	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
119	unsigned int val;
120
121	val = readl(pll->base + ETH_PLL_CTL0);
122
123	return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0;
124}
125
126static void g12a_ephy_pll_init(struct clk_hw *hw)
127{
128	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
129
130	/* Apply PLL HW settings */
131	writel(0x29c0040a, pll->base + ETH_PLL_CTL0);
132	writel(0x927e0000, pll->base + ETH_PLL_CTL1);
133	writel(0xac5f49e5, pll->base + ETH_PLL_CTL2);
134	writel(0x00000000, pll->base + ETH_PLL_CTL3);
135	writel(0x00000000, pll->base + ETH_PLL_CTL4);
136	writel(0x20200000, pll->base + ETH_PLL_CTL5);
137	writel(0x0000c002, pll->base + ETH_PLL_CTL6);
138	writel(0x00000023, pll->base + ETH_PLL_CTL7);
139}
140
141static const struct clk_ops g12a_ephy_pll_ops = {
142	.recalc_rate	= g12a_ephy_pll_recalc_rate,
143	.is_enabled	= g12a_ephy_pll_is_enabled,
144	.enable		= g12a_ephy_pll_enable,
145	.disable	= g12a_ephy_pll_disable,
146	.init		= g12a_ephy_pll_init,
147};
148
149static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv)
150{
151	int ret;
152
153	/* Enable the phy clock */
154	if (!priv->pll_is_enabled) {
155		ret = clk_prepare_enable(priv->pll);
156		if (ret)
157			return ret;
158	}
159
160	priv->pll_is_enabled = true;
161
162	/* Initialize ephy control */
163	writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0);
164	writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
165	       FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
166	       FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
167	       PHY_CNTL1_CLK_EN |
168	       PHY_CNTL1_CLKFREQ |
169	       PHY_CNTL1_PHY_ENB,
170	       priv->regs + ETH_PHY_CNTL1);
171	writel(PHY_CNTL2_USE_INTERNAL |
172	       PHY_CNTL2_SMI_SRC_MAC |
173	       PHY_CNTL2_RX_CLK_EPHY,
174	       priv->regs + ETH_PHY_CNTL2);
175
176	return 0;
177}
178
179static int g12a_enable_external_mdio(struct g12a_mdio_mux *priv)
180{
181	/* Reset the mdio bus mux */
182	writel_relaxed(0x0, priv->regs + ETH_PHY_CNTL2);
183
184	/* Disable the phy clock if enabled */
185	if (priv->pll_is_enabled) {
186		clk_disable_unprepare(priv->pll);
187		priv->pll_is_enabled = false;
188	}
189
190	return 0;
191}
192
193static int g12a_mdio_switch_fn(int current_child, int desired_child,
194			       void *data)
195{
196	struct g12a_mdio_mux *priv = dev_get_drvdata(data);
197
198	if (current_child == desired_child)
199		return 0;
200
201	switch (desired_child) {
202	case MESON_G12A_MDIO_EXTERNAL_ID:
203		return g12a_enable_external_mdio(priv);
204	case MESON_G12A_MDIO_INTERNAL_ID:
205		return g12a_enable_internal_mdio(priv);
206	default:
207		return -EINVAL;
208	}
209}
210
211static const struct of_device_id g12a_mdio_mux_match[] = {
212	{ .compatible = "amlogic,g12a-mdio-mux", },
213	{},
214};
215MODULE_DEVICE_TABLE(of, g12a_mdio_mux_match);
216
217static int g12a_ephy_glue_clk_register(struct device *dev)
218{
219	struct g12a_mdio_mux *priv = dev_get_drvdata(dev);
220	const char *parent_names[PLL_MUX_NUM_PARENT];
221	struct clk_init_data init;
222	struct g12a_ephy_pll *pll;
223	struct clk_mux *mux;
224	struct clk *clk;
225	char *name;
226	int i;
227
228	/* get the mux parents */
229	for (i = 0; i < PLL_MUX_NUM_PARENT; i++) {
230		char in_name[8];
231
232		snprintf(in_name, sizeof(in_name), "clkin%d", i);
233		clk = devm_clk_get(dev, in_name);
234		if (IS_ERR(clk)) {
235			if (PTR_ERR(clk) != -EPROBE_DEFER)
236				dev_err(dev, "Missing clock %s\n", in_name);
237			return PTR_ERR(clk);
238		}
239
240		parent_names[i] = __clk_get_name(clk);
241	}
242
243	/* create the input mux */
244	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
245	if (!mux)
246		return -ENOMEM;
247
248	name = kasprintf(GFP_KERNEL, "%s#mux", dev_name(dev));
249	if (!name)
250		return -ENOMEM;
251
252	init.name = name;
253	init.ops = &clk_mux_ro_ops;
254	init.flags = 0;
255	init.parent_names = parent_names;
256	init.num_parents = PLL_MUX_NUM_PARENT;
257
258	mux->reg = priv->regs + ETH_PLL_CTL0;
259	mux->shift = __ffs(PLL_CTL0_SEL);
260	mux->mask = PLL_CTL0_SEL >> mux->shift;
261	mux->hw.init = &init;
262
263	clk = devm_clk_register(dev, &mux->hw);
264	kfree(name);
265	if (IS_ERR(clk)) {
266		dev_err(dev, "failed to register input mux\n");
267		return PTR_ERR(clk);
268	}
269
270	/* create the pll */
271	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
272	if (!pll)
273		return -ENOMEM;
274
275	name = kasprintf(GFP_KERNEL, "%s#pll", dev_name(dev));
276	if (!name)
277		return -ENOMEM;
278
279	init.name = name;
280	init.ops = &g12a_ephy_pll_ops;
281	init.flags = 0;
282	parent_names[0] = __clk_get_name(clk);
283	init.parent_names = parent_names;
284	init.num_parents = 1;
285
286	pll->base = priv->regs;
287	pll->hw.init = &init;
288
289	clk = devm_clk_register(dev, &pll->hw);
290	kfree(name);
291	if (IS_ERR(clk)) {
292		dev_err(dev, "failed to register input mux\n");
293		return PTR_ERR(clk);
294	}
295
296	priv->pll = clk;
297
298	return 0;
299}
300
301static int g12a_mdio_mux_probe(struct platform_device *pdev)
302{
303	struct device *dev = &pdev->dev;
304	struct g12a_mdio_mux *priv;
305	int ret;
306
307	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
308	if (!priv)
309		return -ENOMEM;
310
311	platform_set_drvdata(pdev, priv);
312
313	priv->regs = devm_platform_ioremap_resource(pdev, 0);
314	if (IS_ERR(priv->regs))
315		return PTR_ERR(priv->regs);
316
317	priv->pclk = devm_clk_get(dev, "pclk");
318	if (IS_ERR(priv->pclk)) {
319		ret = PTR_ERR(priv->pclk);
320		if (ret != -EPROBE_DEFER)
321			dev_err(dev, "failed to get peripheral clock\n");
322		return ret;
323	}
324
325	/* Make sure the device registers are clocked */
326	ret = clk_prepare_enable(priv->pclk);
327	if (ret) {
328		dev_err(dev, "failed to enable peripheral clock");
329		return ret;
330	}
331
332	/* Register PLL in CCF */
333	ret = g12a_ephy_glue_clk_register(dev);
334	if (ret)
335		goto err;
336
337	ret = mdio_mux_init(dev, dev->of_node, g12a_mdio_switch_fn,
338			    &priv->mux_handle, dev, NULL);
339	if (ret) {
340		if (ret != -EPROBE_DEFER)
341			dev_err(dev, "mdio multiplexer init failed: %d", ret);
342		goto err;
343	}
344
345	return 0;
346
347err:
348	clk_disable_unprepare(priv->pclk);
349	return ret;
350}
351
352static int g12a_mdio_mux_remove(struct platform_device *pdev)
353{
354	struct g12a_mdio_mux *priv = platform_get_drvdata(pdev);
355
356	mdio_mux_uninit(priv->mux_handle);
357
358	if (priv->pll_is_enabled)
359		clk_disable_unprepare(priv->pll);
360
361	clk_disable_unprepare(priv->pclk);
362
363	return 0;
364}
365
366static struct platform_driver g12a_mdio_mux_driver = {
367	.probe		= g12a_mdio_mux_probe,
368	.remove		= g12a_mdio_mux_remove,
369	.driver		= {
370		.name	= "g12a-mdio_mux",
371		.of_match_table = g12a_mdio_mux_match,
372	},
373};
374module_platform_driver(g12a_mdio_mux_driver);
375
376MODULE_DESCRIPTION("Amlogic G12a MDIO multiplexer driver");
377MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
378MODULE_LICENSE("GPL v2");