]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c
arm64: dts: exynos: Add clocks to Exynos5433 LPASS module
[karo-tx-linux.git] / drivers / net / ethernet / stmicro / stmmac / dwmac-oxnas.c
1 /*
2  * Oxford Semiconductor OXNAS DWMAC glue layer
3  *
4  * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
5  * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org>
6  * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
7  * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <linux/device.h>
18 #include <linux/io.h>
19 #include <linux/module.h>
20 #include <linux/of.h>
21 #include <linux/platform_device.h>
22 #include <linux/regmap.h>
23 #include <linux/mfd/syscon.h>
24 #include <linux/stmmac.h>
25
26 #include "stmmac_platform.h"
27
28 /* System Control regmap offsets */
29 #define OXNAS_DWMAC_CTRL_REGOFFSET      0x78
30 #define OXNAS_DWMAC_DELAY_REGOFFSET     0x100
31
32 /* Control Register */
33 #define DWMAC_CKEN_RX_IN        14
34 #define DWMAC_CKEN_RXN_OUT      13
35 #define DWMAC_CKEN_RX_OUT       12
36 #define DWMAC_CKEN_TX_IN        10
37 #define DWMAC_CKEN_TXN_OUT      9
38 #define DWMAC_CKEN_TX_OUT       8
39 #define DWMAC_RX_SOURCE         7
40 #define DWMAC_TX_SOURCE         6
41 #define DWMAC_LOW_TX_SOURCE     4
42 #define DWMAC_AUTO_TX_SOURCE    3
43 #define DWMAC_RGMII             2
44 #define DWMAC_SIMPLE_MUX        1
45 #define DWMAC_CKEN_GTX          0
46
47 /* Delay register */
48 #define DWMAC_TX_VARDELAY_SHIFT         0
49 #define DWMAC_TXN_VARDELAY_SHIFT        8
50 #define DWMAC_RX_VARDELAY_SHIFT         16
51 #define DWMAC_RXN_VARDELAY_SHIFT        24
52 #define DWMAC_TX_VARDELAY(d)            ((d) << DWMAC_TX_VARDELAY_SHIFT)
53 #define DWMAC_TXN_VARDELAY(d)           ((d) << DWMAC_TXN_VARDELAY_SHIFT)
54 #define DWMAC_RX_VARDELAY(d)            ((d) << DWMAC_RX_VARDELAY_SHIFT)
55 #define DWMAC_RXN_VARDELAY(d)           ((d) << DWMAC_RXN_VARDELAY_SHIFT)
56
57 struct oxnas_dwmac {
58         struct device   *dev;
59         struct clk      *clk;
60         struct regmap   *regmap;
61 };
62
63 static int oxnas_dwmac_init(struct oxnas_dwmac *dwmac)
64 {
65         unsigned int value;
66         int ret;
67
68         /* Reset HW here before changing the glue configuration */
69         ret = device_reset(dwmac->dev);
70         if (ret)
71                 return ret;
72
73         ret = clk_prepare_enable(dwmac->clk);
74         if (ret)
75                 return ret;
76
77         ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value);
78         if (ret < 0) {
79                 clk_disable_unprepare(dwmac->clk);
80                 return ret;
81         }
82
83         /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */
84         value |= BIT(DWMAC_CKEN_GTX)            |
85                  /* Use simple mux for 25/125 Mhz clock switching */
86                  BIT(DWMAC_SIMPLE_MUX)          |
87                  /* set auto switch tx clock source */
88                  BIT(DWMAC_AUTO_TX_SOURCE)      |
89                  /* enable tx & rx vardelay */
90                  BIT(DWMAC_CKEN_TX_OUT)         |
91                  BIT(DWMAC_CKEN_TXN_OUT)        |
92                  BIT(DWMAC_CKEN_TX_IN)          |
93                  BIT(DWMAC_CKEN_RX_OUT)         |
94                  BIT(DWMAC_CKEN_RXN_OUT)        |
95                  BIT(DWMAC_CKEN_RX_IN);
96         regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value);
97
98         /* set tx & rx vardelay */
99         value = DWMAC_TX_VARDELAY(4)    |
100                 DWMAC_TXN_VARDELAY(2)   |
101                 DWMAC_RX_VARDELAY(10)   |
102                 DWMAC_RXN_VARDELAY(8);
103         regmap_write(dwmac->regmap, OXNAS_DWMAC_DELAY_REGOFFSET, value);
104
105         return 0;
106 }
107
108 static int oxnas_dwmac_probe(struct platform_device *pdev)
109 {
110         struct plat_stmmacenet_data *plat_dat;
111         struct stmmac_resources stmmac_res;
112         struct device_node *sysctrl;
113         struct oxnas_dwmac *dwmac;
114         int ret;
115
116         sysctrl = of_parse_phandle(pdev->dev.of_node, "oxsemi,sys-ctrl", 0);
117         if (!sysctrl) {
118                 dev_err(&pdev->dev, "failed to get sys-ctrl node\n");
119                 return -EINVAL;
120         }
121
122         ret = stmmac_get_platform_resources(pdev, &stmmac_res);
123         if (ret)
124                 return ret;
125
126         plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
127         if (IS_ERR(plat_dat))
128                 return PTR_ERR(plat_dat);
129
130         dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
131         if (!dwmac)
132                 return -ENOMEM;
133
134         dwmac->dev = &pdev->dev;
135         plat_dat->bsp_priv = dwmac;
136
137         dwmac->regmap = syscon_node_to_regmap(sysctrl);
138         if (IS_ERR(dwmac->regmap)) {
139                 dev_err(&pdev->dev, "failed to have sysctrl regmap\n");
140                 return PTR_ERR(dwmac->regmap);
141         }
142
143         dwmac->clk = devm_clk_get(&pdev->dev, "gmac");
144         if (IS_ERR(dwmac->clk))
145                 return PTR_ERR(dwmac->clk);
146
147         ret = oxnas_dwmac_init(dwmac);
148         if (ret)
149                 return ret;
150
151         ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
152         if (ret)
153                 clk_disable_unprepare(dwmac->clk);
154
155         return ret;
156 }
157
158 static int oxnas_dwmac_remove(struct platform_device *pdev)
159 {
160         struct oxnas_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
161         int ret = stmmac_dvr_remove(&pdev->dev);
162
163         clk_disable_unprepare(dwmac->clk);
164
165         return ret;
166 }
167
168 #ifdef CONFIG_PM_SLEEP
169 static int oxnas_dwmac_suspend(struct device *dev)
170 {
171         struct oxnas_dwmac *dwmac = get_stmmac_bsp_priv(dev);
172         int ret;
173
174         ret = stmmac_suspend(dev);
175         clk_disable_unprepare(dwmac->clk);
176
177         return ret;
178 }
179
180 static int oxnas_dwmac_resume(struct device *dev)
181 {
182         struct oxnas_dwmac *dwmac = get_stmmac_bsp_priv(dev);
183         int ret;
184
185         ret = oxnas_dwmac_init(dwmac);
186         if (ret)
187                 return ret;
188
189         ret = stmmac_resume(dev);
190
191         return ret;
192 }
193 #endif /* CONFIG_PM_SLEEP */
194
195 static SIMPLE_DEV_PM_OPS(oxnas_dwmac_pm_ops,
196         oxnas_dwmac_suspend, oxnas_dwmac_resume);
197
198 static const struct of_device_id oxnas_dwmac_match[] = {
199         { .compatible = "oxsemi,ox820-dwmac" },
200         { }
201 };
202 MODULE_DEVICE_TABLE(of, oxnas_dwmac_match);
203
204 static struct platform_driver oxnas_dwmac_driver = {
205         .probe  = oxnas_dwmac_probe,
206         .remove = oxnas_dwmac_remove,
207         .driver = {
208                 .name           = "oxnas-dwmac",
209                 .pm             = &oxnas_dwmac_pm_ops,
210                 .of_match_table = oxnas_dwmac_match,
211         },
212 };
213 module_platform_driver(oxnas_dwmac_driver);
214
215 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
216 MODULE_DESCRIPTION("Oxford Semiconductor OXNAS DWMAC glue layer");
217 MODULE_LICENSE("GPL v2");