brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 2653a9f Raw
187 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * dwmac-sunxi.c - Allwinner sunxi DWMAC specific glue layer4 *5 * Copyright (C) 2013 Chen-Yu Tsai6 *7 * Chen-Yu Tsai  <wens@csie.org>8 */9 10#include <linux/stmmac.h>11#include <linux/clk.h>12#include <linux/module.h>13#include <linux/phy.h>14#include <linux/platform_device.h>15#include <linux/of_net.h>16#include <linux/regulator/consumer.h>17 18#include "stmmac_platform.h"19 20struct sunxi_priv_data {21	phy_interface_t interface;22	int clk_enabled;23	struct clk *tx_clk;24	struct regulator *regulator;25};26 27#define SUN7I_GMAC_GMII_RGMII_RATE	12500000028#define SUN7I_GMAC_MII_RATE		2500000029 30static int sun7i_gmac_init(struct platform_device *pdev, void *priv)31{32	struct sunxi_priv_data *gmac = priv;33	int ret = 0;34 35	if (gmac->regulator) {36		ret = regulator_enable(gmac->regulator);37		if (ret)38			return ret;39	}40 41	/* Set GMAC interface port mode42	 *43	 * The GMAC TX clock lines are configured by setting the clock44	 * rate, which then uses the auto-reparenting feature of the45	 * clock driver, and enabling/disabling the clock.46	 */47	if (phy_interface_mode_is_rgmii(gmac->interface)) {48		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE);49		clk_prepare_enable(gmac->tx_clk);50		gmac->clk_enabled = 1;51	} else {52		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE);53		ret = clk_prepare(gmac->tx_clk);54		if (ret && gmac->regulator)55			regulator_disable(gmac->regulator);56	}57 58	return ret;59}60 61static void sun7i_gmac_exit(struct platform_device *pdev, void *priv)62{63	struct sunxi_priv_data *gmac = priv;64 65	if (gmac->clk_enabled) {66		clk_disable(gmac->tx_clk);67		gmac->clk_enabled = 0;68	}69	clk_unprepare(gmac->tx_clk);70 71	if (gmac->regulator)72		regulator_disable(gmac->regulator);73}74 75static void sun7i_fix_speed(void *priv, unsigned int speed, unsigned int mode)76{77	struct sunxi_priv_data *gmac = priv;78 79	/* only GMII mode requires us to reconfigure the clock lines */80	if (gmac->interface != PHY_INTERFACE_MODE_GMII)81		return;82 83	if (gmac->clk_enabled) {84		clk_disable(gmac->tx_clk);85		gmac->clk_enabled = 0;86	}87	clk_unprepare(gmac->tx_clk);88 89	if (speed == 1000) {90		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE);91		clk_prepare_enable(gmac->tx_clk);92		gmac->clk_enabled = 1;93	} else {94		clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE);95		clk_prepare(gmac->tx_clk);96	}97}98 99static int sun7i_gmac_probe(struct platform_device *pdev)100{101	struct plat_stmmacenet_data *plat_dat;102	struct stmmac_resources stmmac_res;103	struct sunxi_priv_data *gmac;104	struct device *dev = &pdev->dev;105	int ret;106 107	ret = stmmac_get_platform_resources(pdev, &stmmac_res);108	if (ret)109		return ret;110 111	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);112	if (IS_ERR(plat_dat))113		return PTR_ERR(plat_dat);114 115	gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);116	if (!gmac)117		return -ENOMEM;118 119	ret = of_get_phy_mode(dev->of_node, &gmac->interface);120	if (ret && ret != -ENODEV) {121		dev_err(dev, "Can't get phy-mode\n");122		return ret;123	}124 125	gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");126	if (IS_ERR(gmac->tx_clk)) {127		dev_err(dev, "could not get tx clock\n");128		return PTR_ERR(gmac->tx_clk);129	}130 131	/* Optional regulator for PHY */132	gmac->regulator = devm_regulator_get_optional(dev, "phy");133	if (IS_ERR(gmac->regulator)) {134		if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)135			return -EPROBE_DEFER;136		dev_info(dev, "no regulator found\n");137		gmac->regulator = NULL;138	}139 140	/* platform data specifying hardware features and callbacks.141	 * hardware features were copied from Allwinner drivers. */142	plat_dat->tx_coe = 1;143	plat_dat->has_gmac = true;144	plat_dat->bsp_priv = gmac;145	plat_dat->init = sun7i_gmac_init;146	plat_dat->exit = sun7i_gmac_exit;147	plat_dat->fix_mac_speed = sun7i_fix_speed;148	plat_dat->tx_fifo_size = 4096;149	plat_dat->rx_fifo_size = 16384;150 151	ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv);152	if (ret)153		return ret;154 155	ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);156	if (ret)157		goto err_gmac_exit;158 159	return 0;160 161err_gmac_exit:162	sun7i_gmac_exit(pdev, plat_dat->bsp_priv);163 164	return ret;165}166 167static const struct of_device_id sun7i_dwmac_match[] = {168	{ .compatible = "allwinner,sun7i-a20-gmac" },169	{ }170};171MODULE_DEVICE_TABLE(of, sun7i_dwmac_match);172 173static struct platform_driver sun7i_dwmac_driver = {174	.probe  = sun7i_gmac_probe,175	.remove_new = stmmac_pltfr_remove,176	.driver = {177		.name           = "sun7i-dwmac",178		.pm		= &stmmac_pltfr_pm_ops,179		.of_match_table = sun7i_dwmac_match,180	},181};182module_platform_driver(sun7i_dwmac_driver);183 184MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");185MODULE_DESCRIPTION("Allwinner sunxi DWMAC specific glue layer");186MODULE_LICENSE("GPL");187