162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2019 Baylibre, SAS.
362306a36Sopenharmony_ci * Author: Jerome Brunet <jbrunet@baylibre.com>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/bitfield.h>
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/clk.h>
962306a36Sopenharmony_ci#include <linux/clk-provider.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/iopoll.h>
1362306a36Sopenharmony_ci#include <linux/mdio-mux.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/phy.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define ETH_PLL_STS		0x40
1962306a36Sopenharmony_ci#define ETH_PLL_CTL0		0x44
2062306a36Sopenharmony_ci#define  PLL_CTL0_LOCK_DIG	BIT(30)
2162306a36Sopenharmony_ci#define  PLL_CTL0_RST		BIT(29)
2262306a36Sopenharmony_ci#define  PLL_CTL0_EN		BIT(28)
2362306a36Sopenharmony_ci#define  PLL_CTL0_SEL		BIT(23)
2462306a36Sopenharmony_ci#define  PLL_CTL0_N		GENMASK(14, 10)
2562306a36Sopenharmony_ci#define  PLL_CTL0_M		GENMASK(8, 0)
2662306a36Sopenharmony_ci#define  PLL_LOCK_TIMEOUT	1000000
2762306a36Sopenharmony_ci#define  PLL_MUX_NUM_PARENT	2
2862306a36Sopenharmony_ci#define ETH_PLL_CTL1		0x48
2962306a36Sopenharmony_ci#define ETH_PLL_CTL2		0x4c
3062306a36Sopenharmony_ci#define ETH_PLL_CTL3		0x50
3162306a36Sopenharmony_ci#define ETH_PLL_CTL4		0x54
3262306a36Sopenharmony_ci#define ETH_PLL_CTL5		0x58
3362306a36Sopenharmony_ci#define ETH_PLL_CTL6		0x5c
3462306a36Sopenharmony_ci#define ETH_PLL_CTL7		0x60
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define ETH_PHY_CNTL0		0x80
3762306a36Sopenharmony_ci#define   EPHY_G12A_ID		0x33010180
3862306a36Sopenharmony_ci#define ETH_PHY_CNTL1		0x84
3962306a36Sopenharmony_ci#define  PHY_CNTL1_ST_MODE	GENMASK(2, 0)
4062306a36Sopenharmony_ci#define  PHY_CNTL1_ST_PHYADD	GENMASK(7, 3)
4162306a36Sopenharmony_ci#define   EPHY_DFLT_ADD		8
4262306a36Sopenharmony_ci#define  PHY_CNTL1_MII_MODE	GENMASK(15, 14)
4362306a36Sopenharmony_ci#define   EPHY_MODE_RMII	0x1
4462306a36Sopenharmony_ci#define  PHY_CNTL1_CLK_EN	BIT(16)
4562306a36Sopenharmony_ci#define  PHY_CNTL1_CLKFREQ	BIT(17)
4662306a36Sopenharmony_ci#define  PHY_CNTL1_PHY_ENB	BIT(18)
4762306a36Sopenharmony_ci#define ETH_PHY_CNTL2		0x88
4862306a36Sopenharmony_ci#define  PHY_CNTL2_USE_INTERNAL	BIT(5)
4962306a36Sopenharmony_ci#define  PHY_CNTL2_SMI_SRC_MAC	BIT(6)
5062306a36Sopenharmony_ci#define  PHY_CNTL2_RX_CLK_EPHY	BIT(9)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define MESON_G12A_MDIO_EXTERNAL_ID 0
5362306a36Sopenharmony_ci#define MESON_G12A_MDIO_INTERNAL_ID 1
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistruct g12a_mdio_mux {
5662306a36Sopenharmony_ci	void __iomem *regs;
5762306a36Sopenharmony_ci	void *mux_handle;
5862306a36Sopenharmony_ci	struct clk *pll;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct g12a_ephy_pll {
6262306a36Sopenharmony_ci	void __iomem *base;
6362306a36Sopenharmony_ci	struct clk_hw hw;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define g12a_ephy_pll_to_dev(_hw)			\
6762306a36Sopenharmony_ci	container_of(_hw, struct g12a_ephy_pll, hw)
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw,
7062306a36Sopenharmony_ci					       unsigned long parent_rate)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
7362306a36Sopenharmony_ci	u32 val, m, n;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	val = readl(pll->base + ETH_PLL_CTL0);
7662306a36Sopenharmony_ci	m = FIELD_GET(PLL_CTL0_M, val);
7762306a36Sopenharmony_ci	n = FIELD_GET(PLL_CTL0_N, val);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	return parent_rate * m / n;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int g12a_ephy_pll_enable(struct clk_hw *hw)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
8562306a36Sopenharmony_ci	u32 val = readl(pll->base + ETH_PLL_CTL0);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/* Apply both enable an reset */
8862306a36Sopenharmony_ci	val |= PLL_CTL0_RST | PLL_CTL0_EN;
8962306a36Sopenharmony_ci	writel(val, pll->base + ETH_PLL_CTL0);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* Clear the reset to let PLL lock */
9262306a36Sopenharmony_ci	val &= ~PLL_CTL0_RST;
9362306a36Sopenharmony_ci	writel(val, pll->base + ETH_PLL_CTL0);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Poll on the digital lock instead of the usual analog lock
9662306a36Sopenharmony_ci	 * This is done because bit 31 is unreliable on some SoC. Bit
9762306a36Sopenharmony_ci	 * 31 may indicate that the PLL is not lock even though the clock
9862306a36Sopenharmony_ci	 * is actually running
9962306a36Sopenharmony_ci	 */
10062306a36Sopenharmony_ci	return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val,
10162306a36Sopenharmony_ci				  val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic void g12a_ephy_pll_disable(struct clk_hw *hw)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
10762306a36Sopenharmony_ci	u32 val;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	val = readl(pll->base + ETH_PLL_CTL0);
11062306a36Sopenharmony_ci	val &= ~PLL_CTL0_EN;
11162306a36Sopenharmony_ci	val |= PLL_CTL0_RST;
11262306a36Sopenharmony_ci	writel(val, pll->base + ETH_PLL_CTL0);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int g12a_ephy_pll_is_enabled(struct clk_hw *hw)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
11862306a36Sopenharmony_ci	unsigned int val;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	val = readl(pll->base + ETH_PLL_CTL0);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int g12a_ephy_pll_init(struct clk_hw *hw)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Apply PLL HW settings */
13062306a36Sopenharmony_ci	writel(0x29c0040a, pll->base + ETH_PLL_CTL0);
13162306a36Sopenharmony_ci	writel(0x927e0000, pll->base + ETH_PLL_CTL1);
13262306a36Sopenharmony_ci	writel(0xac5f49e5, pll->base + ETH_PLL_CTL2);
13362306a36Sopenharmony_ci	writel(0x00000000, pll->base + ETH_PLL_CTL3);
13462306a36Sopenharmony_ci	writel(0x00000000, pll->base + ETH_PLL_CTL4);
13562306a36Sopenharmony_ci	writel(0x20200000, pll->base + ETH_PLL_CTL5);
13662306a36Sopenharmony_ci	writel(0x0000c002, pll->base + ETH_PLL_CTL6);
13762306a36Sopenharmony_ci	writel(0x00000023, pll->base + ETH_PLL_CTL7);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return 0;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic const struct clk_ops g12a_ephy_pll_ops = {
14362306a36Sopenharmony_ci	.recalc_rate	= g12a_ephy_pll_recalc_rate,
14462306a36Sopenharmony_ci	.is_enabled	= g12a_ephy_pll_is_enabled,
14562306a36Sopenharmony_ci	.enable		= g12a_ephy_pll_enable,
14662306a36Sopenharmony_ci	.disable	= g12a_ephy_pll_disable,
14762306a36Sopenharmony_ci	.init		= g12a_ephy_pll_init,
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	u32 value;
15362306a36Sopenharmony_ci	int ret;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* Enable the phy clock */
15662306a36Sopenharmony_ci	if (!__clk_is_enabled(priv->pll)) {
15762306a36Sopenharmony_ci		ret = clk_prepare_enable(priv->pll);
15862306a36Sopenharmony_ci		if (ret)
15962306a36Sopenharmony_ci			return ret;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* Initialize ephy control */
16362306a36Sopenharmony_ci	writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* Make sure we get a 0 -> 1 transition on the enable bit */
16662306a36Sopenharmony_ci	value = FIELD_PREP(PHY_CNTL1_ST_MODE, 3) |
16762306a36Sopenharmony_ci		FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) |
16862306a36Sopenharmony_ci		FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) |
16962306a36Sopenharmony_ci		PHY_CNTL1_CLK_EN |
17062306a36Sopenharmony_ci		PHY_CNTL1_CLKFREQ;
17162306a36Sopenharmony_ci	writel(value, priv->regs + ETH_PHY_CNTL1);
17262306a36Sopenharmony_ci	writel(PHY_CNTL2_USE_INTERNAL |
17362306a36Sopenharmony_ci	       PHY_CNTL2_SMI_SRC_MAC |
17462306a36Sopenharmony_ci	       PHY_CNTL2_RX_CLK_EPHY,
17562306a36Sopenharmony_ci	       priv->regs + ETH_PHY_CNTL2);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	value |= PHY_CNTL1_PHY_ENB;
17862306a36Sopenharmony_ci	writel(value, priv->regs + ETH_PHY_CNTL1);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* The phy needs a bit of time to power up */
18162306a36Sopenharmony_ci	mdelay(10);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return 0;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic int g12a_enable_external_mdio(struct g12a_mdio_mux *priv)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	/* Reset the mdio bus mux */
18962306a36Sopenharmony_ci	writel_relaxed(0x0, priv->regs + ETH_PHY_CNTL2);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* Disable the phy clock if enabled */
19262306a36Sopenharmony_ci	if (__clk_is_enabled(priv->pll))
19362306a36Sopenharmony_ci		clk_disable_unprepare(priv->pll);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int g12a_mdio_switch_fn(int current_child, int desired_child,
19962306a36Sopenharmony_ci			       void *data)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct g12a_mdio_mux *priv = dev_get_drvdata(data);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (current_child == desired_child)
20462306a36Sopenharmony_ci		return 0;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	switch (desired_child) {
20762306a36Sopenharmony_ci	case MESON_G12A_MDIO_EXTERNAL_ID:
20862306a36Sopenharmony_ci		return g12a_enable_external_mdio(priv);
20962306a36Sopenharmony_ci	case MESON_G12A_MDIO_INTERNAL_ID:
21062306a36Sopenharmony_ci		return g12a_enable_internal_mdio(priv);
21162306a36Sopenharmony_ci	default:
21262306a36Sopenharmony_ci		return -EINVAL;
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic const struct of_device_id g12a_mdio_mux_match[] = {
21762306a36Sopenharmony_ci	{ .compatible = "amlogic,g12a-mdio-mux", },
21862306a36Sopenharmony_ci	{},
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, g12a_mdio_mux_match);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic int g12a_ephy_glue_clk_register(struct device *dev)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct g12a_mdio_mux *priv = dev_get_drvdata(dev);
22562306a36Sopenharmony_ci	const char *parent_names[PLL_MUX_NUM_PARENT];
22662306a36Sopenharmony_ci	struct clk_init_data init;
22762306a36Sopenharmony_ci	struct g12a_ephy_pll *pll;
22862306a36Sopenharmony_ci	struct clk_mux *mux;
22962306a36Sopenharmony_ci	struct clk *clk;
23062306a36Sopenharmony_ci	char *name;
23162306a36Sopenharmony_ci	int i;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* get the mux parents */
23462306a36Sopenharmony_ci	for (i = 0; i < PLL_MUX_NUM_PARENT; i++) {
23562306a36Sopenharmony_ci		char in_name[8];
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		snprintf(in_name, sizeof(in_name), "clkin%d", i);
23862306a36Sopenharmony_ci		clk = devm_clk_get(dev, in_name);
23962306a36Sopenharmony_ci		if (IS_ERR(clk))
24062306a36Sopenharmony_ci			return dev_err_probe(dev, PTR_ERR(clk),
24162306a36Sopenharmony_ci					     "Missing clock %s\n", in_name);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		parent_names[i] = __clk_get_name(clk);
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* create the input mux */
24762306a36Sopenharmony_ci	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
24862306a36Sopenharmony_ci	if (!mux)
24962306a36Sopenharmony_ci		return -ENOMEM;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%s#mux", dev_name(dev));
25262306a36Sopenharmony_ci	if (!name)
25362306a36Sopenharmony_ci		return -ENOMEM;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	init.name = name;
25662306a36Sopenharmony_ci	init.ops = &clk_mux_ro_ops;
25762306a36Sopenharmony_ci	init.flags = 0;
25862306a36Sopenharmony_ci	init.parent_names = parent_names;
25962306a36Sopenharmony_ci	init.num_parents = PLL_MUX_NUM_PARENT;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	mux->reg = priv->regs + ETH_PLL_CTL0;
26262306a36Sopenharmony_ci	mux->shift = __ffs(PLL_CTL0_SEL);
26362306a36Sopenharmony_ci	mux->mask = PLL_CTL0_SEL >> mux->shift;
26462306a36Sopenharmony_ci	mux->hw.init = &init;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	clk = devm_clk_register(dev, &mux->hw);
26762306a36Sopenharmony_ci	kfree(name);
26862306a36Sopenharmony_ci	if (IS_ERR(clk)) {
26962306a36Sopenharmony_ci		dev_err(dev, "failed to register input mux\n");
27062306a36Sopenharmony_ci		return PTR_ERR(clk);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* create the pll */
27462306a36Sopenharmony_ci	pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
27562306a36Sopenharmony_ci	if (!pll)
27662306a36Sopenharmony_ci		return -ENOMEM;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	name = kasprintf(GFP_KERNEL, "%s#pll", dev_name(dev));
27962306a36Sopenharmony_ci	if (!name)
28062306a36Sopenharmony_ci		return -ENOMEM;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	init.name = name;
28362306a36Sopenharmony_ci	init.ops = &g12a_ephy_pll_ops;
28462306a36Sopenharmony_ci	init.flags = 0;
28562306a36Sopenharmony_ci	parent_names[0] = __clk_get_name(clk);
28662306a36Sopenharmony_ci	init.parent_names = parent_names;
28762306a36Sopenharmony_ci	init.num_parents = 1;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	pll->base = priv->regs;
29062306a36Sopenharmony_ci	pll->hw.init = &init;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	clk = devm_clk_register(dev, &pll->hw);
29362306a36Sopenharmony_ci	kfree(name);
29462306a36Sopenharmony_ci	if (IS_ERR(clk)) {
29562306a36Sopenharmony_ci		dev_err(dev, "failed to register input mux\n");
29662306a36Sopenharmony_ci		return PTR_ERR(clk);
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	priv->pll = clk;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int g12a_mdio_mux_probe(struct platform_device *pdev)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
30762306a36Sopenharmony_ci	struct g12a_mdio_mux *priv;
30862306a36Sopenharmony_ci	struct clk *pclk;
30962306a36Sopenharmony_ci	int ret;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
31262306a36Sopenharmony_ci	if (!priv)
31362306a36Sopenharmony_ci		return -ENOMEM;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	platform_set_drvdata(pdev, priv);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	priv->regs = devm_platform_ioremap_resource(pdev, 0);
31862306a36Sopenharmony_ci	if (IS_ERR(priv->regs))
31962306a36Sopenharmony_ci		return PTR_ERR(priv->regs);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	pclk = devm_clk_get_enabled(dev, "pclk");
32262306a36Sopenharmony_ci	if (IS_ERR(pclk))
32362306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(pclk),
32462306a36Sopenharmony_ci				     "failed to get peripheral clock\n");
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* Register PLL in CCF */
32762306a36Sopenharmony_ci	ret = g12a_ephy_glue_clk_register(dev);
32862306a36Sopenharmony_ci	if (ret)
32962306a36Sopenharmony_ci		return ret;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	ret = mdio_mux_init(dev, dev->of_node, g12a_mdio_switch_fn,
33262306a36Sopenharmony_ci			    &priv->mux_handle, dev, NULL);
33362306a36Sopenharmony_ci	if (ret)
33462306a36Sopenharmony_ci		dev_err_probe(dev, ret, "mdio multiplexer init failed\n");
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	return ret;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic int g12a_mdio_mux_remove(struct platform_device *pdev)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct g12a_mdio_mux *priv = platform_get_drvdata(pdev);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	mdio_mux_uninit(priv->mux_handle);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (__clk_is_enabled(priv->pll))
34662306a36Sopenharmony_ci		clk_disable_unprepare(priv->pll);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return 0;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic struct platform_driver g12a_mdio_mux_driver = {
35262306a36Sopenharmony_ci	.probe		= g12a_mdio_mux_probe,
35362306a36Sopenharmony_ci	.remove		= g12a_mdio_mux_remove,
35462306a36Sopenharmony_ci	.driver		= {
35562306a36Sopenharmony_ci		.name	= "g12a-mdio_mux",
35662306a36Sopenharmony_ci		.of_match_table = g12a_mdio_mux_match,
35762306a36Sopenharmony_ci	},
35862306a36Sopenharmony_ci};
35962306a36Sopenharmony_cimodule_platform_driver(g12a_mdio_mux_driver);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ciMODULE_DESCRIPTION("Amlogic G12a MDIO multiplexer driver");
36262306a36Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
36362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
364