aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Perier <romain.perier@gmail.com>2014-09-08 13:14:47 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-09 20:29:59 -0400
commit6eacf31139bf9638c62eb7853ee37f70da1ad28c (patch)
tree607c1c2f61ada0e61a2089e5a8b583b23a143343
parent60005c60b1ea807013bcbbfe9309fc924a3881f0 (diff)
ethernet: arc: Add support for Rockchip SoC layer device tree bindings
This patch defines a platform glue layer for Rockchip SoCs which support arc-emac driver. It ensures that regulator for the rmii is on before trying to connect to the ethernet controller. It applies right speed and mode changes to the grf when ethernet settings change. Signed-off-by: Romain Perier <romain.perier@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/arc/Kconfig10
-rw-r--r--drivers/net/ethernet/arc/Makefile1
-rw-r--r--drivers/net/ethernet/arc/emac.h4
-rw-r--r--drivers/net/ethernet/arc/emac_main.c2
-rw-r--r--drivers/net/ethernet/arc/emac_rockchip.c228
5 files changed, 244 insertions, 1 deletions
diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig
index 89e04fde5f4e..8e262e2b39b6 100644
--- a/drivers/net/ethernet/arc/Kconfig
+++ b/drivers/net/ethernet/arc/Kconfig
@@ -32,4 +32,14 @@ config ARC_EMAC
32 non-standard on-chip ethernet device ARC EMAC 10/100 is used. 32 non-standard on-chip ethernet device ARC EMAC 10/100 is used.
33 Say Y here if you have such a board. If unsure, say N. 33 Say Y here if you have such a board. If unsure, say N.
34 34
35config EMAC_ROCKCHIP
36 tristate "Rockchip EMAC support"
37 select ARC_EMAC_CORE
38 depends on OF_IRQ && OF_NET && REGULATOR
39 ---help---
40 Support for Rockchip RK3066/RK3188 EMAC ethernet controllers.
41 This selects Rockchip SoC glue layer support for the
42 emac device driver. This driver is used for RK3066/RK3188
43 EMAC ethernet controller.
44
35endif # NET_VENDOR_ARC 45endif # NET_VENDOR_ARC
diff --git a/drivers/net/ethernet/arc/Makefile b/drivers/net/ethernet/arc/Makefile
index 241bb809f351..79108af553fb 100644
--- a/drivers/net/ethernet/arc/Makefile
+++ b/drivers/net/ethernet/arc/Makefile
@@ -5,3 +5,4 @@
5arc_emac-objs := emac_main.o emac_mdio.o 5arc_emac-objs := emac_main.o emac_mdio.o
6obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o 6obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o
7obj-$(CONFIG_ARC_EMAC) += emac_arc.o 7obj-$(CONFIG_ARC_EMAC) += emac_arc.o
8obj-$(CONFIG_EMAC_ROCKCHIP) += emac_rockchip.o
diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h
index eb2ba67ac711..dae1ac300a49 100644
--- a/drivers/net/ethernet/arc/emac.h
+++ b/drivers/net/ethernet/arc/emac.h
@@ -123,9 +123,11 @@ struct buffer_state {
123 * @speed: PHY's last set speed. 123 * @speed: PHY's last set speed.
124 */ 124 */
125struct arc_emac_priv { 125struct arc_emac_priv {
126 /* Devices */
127 const char *drv_name; 126 const char *drv_name;
128 const char *drv_version; 127 const char *drv_version;
128 void (*set_mac_speed)(void *priv, unsigned int speed);
129
130 /* Devices */
129 struct device *dev; 131 struct device *dev;
130 struct phy_device *phy_dev; 132 struct phy_device *phy_dev;
131 struct mii_bus *bus; 133 struct mii_bus *bus;
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a7773923a7a0..dbea8472bfb4 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -48,6 +48,8 @@ static void arc_emac_adjust_link(struct net_device *ndev)
48 if (priv->speed != phy_dev->speed) { 48 if (priv->speed != phy_dev->speed) {
49 priv->speed = phy_dev->speed; 49 priv->speed = phy_dev->speed;
50 state_changed = 1; 50 state_changed = 1;
51 if (priv->set_mac_speed)
52 priv->set_mac_speed(priv, priv->speed);
51 } 53 }
52 54
53 if (priv->duplex != phy_dev->duplex) { 55 if (priv->duplex != phy_dev->duplex) {
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c
new file mode 100644
index 000000000000..51d0585e2575
--- /dev/null
+++ b/drivers/net/ethernet/arc/emac_rockchip.c
@@ -0,0 +1,228 @@
1/**
2 * emac-rockchip.c - Rockchip EMAC specific glue layer
3 *
4 * Copyright (C) 2014 Romain Perier <romain.perier@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/etherdevice.h>
18#include <linux/mfd/syscon.h>
19#include <linux/module.h>
20#include <linux/of_net.h>
21#include <linux/platform_device.h>
22#include <linux/regmap.h>
23#include <linux/regulator/consumer.h>
24
25#include "emac.h"
26
27#define DRV_NAME "rockchip_emac"
28#define DRV_VERSION "1.0"
29
30#define GRF_MODE_MII (1UL << 0)
31#define GRF_MODE_RMII (0UL << 0)
32#define GRF_SPEED_10M (0UL << 1)
33#define GRF_SPEED_100M (1UL << 1)
34#define GRF_SPEED_ENABLE_BIT (1UL << 17)
35#define GRF_MODE_ENABLE_BIT (1UL << 16)
36
37struct emac_rockchip_soc_data {
38 int grf_offset;
39};
40
41struct rockchip_priv_data {
42 struct arc_emac_priv emac;
43 struct regmap *grf;
44 const struct emac_rockchip_soc_data *soc_data;
45 struct regulator *regulator;
46 struct clk *refclk;
47};
48
49static void emac_rockchip_set_mac_speed(void *priv, unsigned int speed)
50{
51 struct rockchip_priv_data *emac = priv;
52 u32 data;
53 int err = 0;
54
55 /* write-enable bits */
56 data = GRF_SPEED_ENABLE_BIT;
57
58 switch(speed) {
59 case 10:
60 data |= GRF_SPEED_10M;
61 break;
62 case 100:
63 data |= GRF_SPEED_100M;
64 break;
65 default:
66 pr_err("speed %u not supported\n", speed);
67 return;
68 }
69
70 err = regmap_write(emac->grf, emac->soc_data->grf_offset, data);
71 if (err)
72 pr_err("unable to apply speed %u to grf (%d)\n", speed, err);
73}
74
75static const struct emac_rockchip_soc_data emac_rockchip_dt_data[] = {
76 { .grf_offset = 0x154 }, /* rk3066 */
77 { .grf_offset = 0x0a4 }, /* rk3188 */
78};
79
80static const struct of_device_id emac_rockchip_dt_ids[] = {
81 { .compatible = "rockchip,rk3066-emac", .data = &emac_rockchip_dt_data[0] },
82 { .compatible = "rockchip,rk3188-emac", .data = &emac_rockchip_dt_data[1] },
83 { /* Sentinel */ }
84};
85
86MODULE_DEVICE_TABLE(of, emac_rockchip_dt_ids);
87
88static int emac_rockchip_probe(struct platform_device *pdev)
89{
90 struct device *dev = &pdev->dev;
91 struct net_device *ndev;
92 struct rockchip_priv_data *priv;
93 const struct of_device_id *match;
94 u32 data;
95 int err, interface;
96
97 if (!pdev->dev.of_node)
98 return -ENODEV;
99
100 ndev = alloc_etherdev(sizeof(struct rockchip_priv_data));
101 if (!ndev)
102 return -ENOMEM;
103 platform_set_drvdata(pdev, ndev);
104 SET_NETDEV_DEV(ndev, dev);
105
106 priv = netdev_priv(ndev);
107 priv->emac.drv_name = DRV_NAME;
108 priv->emac.drv_version = DRV_VERSION;
109 priv->emac.set_mac_speed = emac_rockchip_set_mac_speed;
110
111 interface = of_get_phy_mode(dev->of_node);
112
113 /* RK3066 and RK3188 SoCs only support RMII */
114 if (interface != PHY_INTERFACE_MODE_RMII) {
115 dev_err(dev, "unsupported phy interface mode %d\n", interface);
116 err = -ENOTSUPP;
117 goto out_netdev;
118 }
119
120 priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
121 if (IS_ERR(priv->grf)) {
122 dev_err(dev, "failed to retrieve global register file (%ld)\n", PTR_ERR(priv->grf));
123 err = PTR_ERR(priv->grf);
124 goto out_netdev;
125 }
126
127 match = of_match_node(emac_rockchip_dt_ids, dev->of_node);
128 priv->soc_data = match->data;
129
130 priv->emac.clk = devm_clk_get(dev, "hclk");
131 if (IS_ERR(priv->emac.clk)) {
132 dev_err(dev, "failed to retrieve host clock (%ld)\n", PTR_ERR(priv->emac.clk));
133 err = PTR_ERR(priv->emac.clk);
134 goto out_netdev;
135 }
136
137 priv->refclk = devm_clk_get(dev, "macref");
138 if (IS_ERR(priv->refclk)) {
139 dev_err(dev, "failed to retrieve reference clock (%ld)\n", PTR_ERR(priv->refclk));
140 err = PTR_ERR(priv->refclk);
141 goto out_netdev;
142 }
143
144 err = clk_prepare_enable(priv->refclk);
145 if (err) {
146 dev_err(dev, "failed to enable reference clock (%d)\n", err);
147 goto out_netdev;
148 }
149
150 /* Optional regulator for PHY */
151 priv->regulator = devm_regulator_get_optional(dev, "phy");
152 if (IS_ERR(priv->regulator)) {
153 if (PTR_ERR(priv->regulator) == -EPROBE_DEFER)
154 return -EPROBE_DEFER;
155 dev_err(dev, "no regulator found\n");
156 priv->regulator = NULL;
157 }
158
159 if (priv->regulator) {
160 err = regulator_enable(priv->regulator);
161 if (err) {
162 dev_err(dev, "failed to enable phy-supply (%d)\n", err);
163 goto out_clk_disable;
164 }
165 }
166
167 err = arc_emac_probe(ndev, interface);
168 if (err)
169 goto out_regulator_disable;
170
171 /* write-enable bits */
172 data = GRF_MODE_ENABLE_BIT | GRF_SPEED_ENABLE_BIT;
173
174 data |= GRF_SPEED_100M;
175 data |= GRF_MODE_RMII;
176
177 err = regmap_write(priv->grf, priv->soc_data->grf_offset, data);
178 if (err) {
179 dev_err(dev, "unable to apply initial settings to grf (%d)\n", err);
180 goto out_regulator_disable;
181 }
182
183 /* RMII interface needs always a rate of 50MHz */
184 err = clk_set_rate(priv->refclk, 50000000);
185 if (err)
186 dev_err(dev, "failed to change reference clock rate (%d)\n", err);
187 return 0;
188
189out_regulator_disable:
190 if (priv->regulator)
191 regulator_disable(priv->regulator);
192out_clk_disable:
193 clk_disable_unprepare(priv->refclk);
194out_netdev:
195 free_netdev(ndev);
196 return err;
197}
198
199static int emac_rockchip_remove(struct platform_device *pdev)
200{
201 struct net_device *ndev = platform_get_drvdata(pdev);
202 struct rockchip_priv_data *priv = netdev_priv(ndev);
203 int err;
204
205 clk_disable_unprepare(priv->refclk);
206
207 if (priv->regulator)
208 regulator_disable(priv->regulator);
209
210 err = arc_emac_remove(ndev);
211 free_netdev(ndev);
212 return err;
213}
214
215static struct platform_driver emac_rockchip_driver = {
216 .probe = emac_rockchip_probe,
217 .remove = emac_rockchip_remove,
218 .driver = {
219 .name = DRV_NAME,
220 .of_match_table = emac_rockchip_dt_ids,
221 },
222};
223
224module_platform_driver(emac_rockchip_driver);
225
226MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
227MODULE_DESCRIPTION("Rockchip EMAC platform driver");
228MODULE_LICENSE("GPL");