2 * dwmac-stm32.c - DWMAC Specific Glue layer for STM32 MCU
4 * Copyright (C) Alexandre Torgue 2015
5 * Author: Alexandre Torgue <alexandre.torgue@gmail.com>
6 * License terms: GNU General Public License (GPL), version 2
10 #include <linux/clk.h>
11 #include <linux/kernel.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
15 #include <linux/of_device.h>
16 #include <linux/of_net.h>
17 #include <linux/phy.h>
18 #include <linux/platform_device.h>
19 #include <linux/regmap.h>
20 #include <linux/slab.h>
21 #include <linux/stmmac.h>
23 #include "stmmac_platform.h"
25 #define MII_PHY_SEL_MASK BIT(23)
30 u32 mode_reg
; /* MAC glue-logic mode register */
31 struct regmap
*regmap
;
35 static int stm32_dwmac_init(struct plat_stmmacenet_data
*plat_dat
)
37 struct stm32_dwmac
*dwmac
= plat_dat
->bsp_priv
;
38 u32 reg
= dwmac
->mode_reg
;
42 val
= (plat_dat
->interface
== PHY_INTERFACE_MODE_MII
) ? 0 : 1;
43 ret
= regmap_update_bits(dwmac
->regmap
, reg
, MII_PHY_SEL_MASK
, val
);
47 ret
= clk_prepare_enable(dwmac
->clk_tx
);
51 ret
= clk_prepare_enable(dwmac
->clk_rx
);
53 clk_disable_unprepare(dwmac
->clk_tx
);
58 static void stm32_dwmac_clk_disable(struct stm32_dwmac
*dwmac
)
60 clk_disable_unprepare(dwmac
->clk_tx
);
61 clk_disable_unprepare(dwmac
->clk_rx
);
64 static int stm32_dwmac_parse_data(struct stm32_dwmac
*dwmac
,
67 struct device_node
*np
= dev
->of_node
;
70 /* Get TX/RX clocks */
71 dwmac
->clk_tx
= devm_clk_get(dev
, "mac-clk-tx");
72 if (IS_ERR(dwmac
->clk_tx
)) {
73 dev_err(dev
, "No tx clock provided...\n");
74 return PTR_ERR(dwmac
->clk_tx
);
76 dwmac
->clk_rx
= devm_clk_get(dev
, "mac-clk-rx");
77 if (IS_ERR(dwmac
->clk_rx
)) {
78 dev_err(dev
, "No rx clock provided...\n");
79 return PTR_ERR(dwmac
->clk_rx
);
82 /* Get mode register */
83 dwmac
->regmap
= syscon_regmap_lookup_by_phandle(np
, "st,syscon");
84 if (IS_ERR(dwmac
->regmap
))
85 return PTR_ERR(dwmac
->regmap
);
87 err
= of_property_read_u32_index(np
, "st,syscon", 1, &dwmac
->mode_reg
);
89 dev_err(dev
, "Can't get sysconfig mode offset (%d)\n", err
);
94 static int stm32_dwmac_probe(struct platform_device
*pdev
)
96 struct plat_stmmacenet_data
*plat_dat
;
97 struct stmmac_resources stmmac_res
;
98 struct stm32_dwmac
*dwmac
;
101 ret
= stmmac_get_platform_resources(pdev
, &stmmac_res
);
105 plat_dat
= stmmac_probe_config_dt(pdev
, &stmmac_res
.mac
);
106 if (IS_ERR(plat_dat
))
107 return PTR_ERR(plat_dat
);
109 dwmac
= devm_kzalloc(&pdev
->dev
, sizeof(*dwmac
), GFP_KERNEL
);
112 goto err_remove_config_dt
;
115 ret
= stm32_dwmac_parse_data(dwmac
, &pdev
->dev
);
117 dev_err(&pdev
->dev
, "Unable to parse OF data\n");
118 goto err_remove_config_dt
;
121 plat_dat
->bsp_priv
= dwmac
;
123 ret
= stm32_dwmac_init(plat_dat
);
125 goto err_remove_config_dt
;
127 ret
= stmmac_dvr_probe(&pdev
->dev
, plat_dat
, &stmmac_res
);
129 goto err_clk_disable
;
134 stm32_dwmac_clk_disable(dwmac
);
135 err_remove_config_dt
:
136 stmmac_remove_config_dt(pdev
, plat_dat
);
141 static int stm32_dwmac_remove(struct platform_device
*pdev
)
143 struct net_device
*ndev
= platform_get_drvdata(pdev
);
144 struct stmmac_priv
*priv
= netdev_priv(ndev
);
145 int ret
= stmmac_dvr_remove(&pdev
->dev
);
147 stm32_dwmac_clk_disable(priv
->plat
->bsp_priv
);
152 #ifdef CONFIG_PM_SLEEP
153 static int stm32_dwmac_suspend(struct device
*dev
)
155 struct net_device
*ndev
= dev_get_drvdata(dev
);
156 struct stmmac_priv
*priv
= netdev_priv(ndev
);
159 ret
= stmmac_suspend(dev
);
160 stm32_dwmac_clk_disable(priv
->plat
->bsp_priv
);
165 static int stm32_dwmac_resume(struct device
*dev
)
167 struct net_device
*ndev
= dev_get_drvdata(dev
);
168 struct stmmac_priv
*priv
= netdev_priv(ndev
);
171 ret
= stm32_dwmac_init(priv
->plat
);
175 ret
= stmmac_resume(dev
);
179 #endif /* CONFIG_PM_SLEEP */
181 static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops
,
182 stm32_dwmac_suspend
, stm32_dwmac_resume
);
184 static const struct of_device_id stm32_dwmac_match
[] = {
185 { .compatible
= "st,stm32-dwmac"},
188 MODULE_DEVICE_TABLE(of
, stm32_dwmac_match
);
190 static struct platform_driver stm32_dwmac_driver
= {
191 .probe
= stm32_dwmac_probe
,
192 .remove
= stm32_dwmac_remove
,
194 .name
= "stm32-dwmac",
195 .pm
= &stm32_dwmac_pm_ops
,
196 .of_match_table
= stm32_dwmac_match
,
199 module_platform_driver(stm32_dwmac_driver
);
201 MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@gmail.com>");
202 MODULE_DESCRIPTION("STMicroelectronics MCU DWMAC Specific Glue layer");
203 MODULE_LICENSE("GPL v2");