linux/drivers/net/ethernet/arc/emac_rockchip.c
<<
>>
Prefs
   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.1"
  29
  30struct emac_rockchip_soc_data {
  31        unsigned int grf_offset;
  32        unsigned int grf_mode_offset;
  33        unsigned int grf_speed_offset;
  34        bool need_div_macclk;
  35};
  36
  37struct rockchip_priv_data {
  38        struct arc_emac_priv emac;
  39        struct regmap *grf;
  40        const struct emac_rockchip_soc_data *soc_data;
  41        struct regulator *regulator;
  42        struct clk *refclk;
  43        struct clk *macclk;
  44};
  45
  46static void emac_rockchip_set_mac_speed(void *priv, unsigned int speed)
  47{
  48        struct rockchip_priv_data *emac = priv;
  49        u32 speed_offset = emac->soc_data->grf_speed_offset;
  50        u32 data;
  51        int err = 0;
  52
  53        switch (speed) {
  54        case 10:
  55                data = (1 << (speed_offset + 16)) | (0 << speed_offset);
  56                break;
  57        case 100:
  58                data = (1 << (speed_offset + 16)) | (1 << speed_offset);
  59                break;
  60        default:
  61                pr_err("speed %u not supported\n", speed);
  62                return;
  63        }
  64
  65        err = regmap_write(emac->grf, emac->soc_data->grf_offset, data);
  66        if (err)
  67                pr_err("unable to apply speed %u to grf (%d)\n", speed, err);
  68}
  69
  70static const struct emac_rockchip_soc_data emac_rk3036_emac_data = {
  71        .grf_offset = 0x140,   .grf_mode_offset = 8,
  72        .grf_speed_offset = 9, .need_div_macclk = 1,
  73};
  74
  75static const struct emac_rockchip_soc_data emac_rk3066_emac_data = {
  76        .grf_offset = 0x154,   .grf_mode_offset = 0,
  77        .grf_speed_offset = 1, .need_div_macclk = 0,
  78};
  79
  80static const struct emac_rockchip_soc_data emac_rk3188_emac_data = {
  81        .grf_offset = 0x0a4,   .grf_mode_offset = 0,
  82        .grf_speed_offset = 1, .need_div_macclk = 0,
  83};
  84
  85static const struct of_device_id emac_rockchip_dt_ids[] = {
  86        {
  87                .compatible = "rockchip,rk3036-emac",
  88                .data = &emac_rk3036_emac_data,
  89        },
  90        {
  91                .compatible = "rockchip,rk3066-emac",
  92                .data = &emac_rk3066_emac_data,
  93        },
  94        {
  95                .compatible = "rockchip,rk3188-emac",
  96                .data = &emac_rk3188_emac_data,
  97        },
  98        { /* Sentinel */ }
  99};
 100
 101MODULE_DEVICE_TABLE(of, emac_rockchip_dt_ids);
 102
 103static int emac_rockchip_probe(struct platform_device *pdev)
 104{
 105        struct device *dev = &pdev->dev;
 106        struct net_device *ndev;
 107        struct rockchip_priv_data *priv;
 108        const struct of_device_id *match;
 109        u32 data;
 110        int err, interface;
 111
 112        if (!pdev->dev.of_node)
 113                return -ENODEV;
 114
 115        ndev = alloc_etherdev(sizeof(struct rockchip_priv_data));
 116        if (!ndev)
 117                return -ENOMEM;
 118        platform_set_drvdata(pdev, ndev);
 119        SET_NETDEV_DEV(ndev, dev);
 120
 121        priv = netdev_priv(ndev);
 122        priv->emac.drv_name = DRV_NAME;
 123        priv->emac.drv_version = DRV_VERSION;
 124        priv->emac.set_mac_speed = emac_rockchip_set_mac_speed;
 125
 126        interface = of_get_phy_mode(dev->of_node);
 127
 128        /* RK3036/RK3066/RK3188 SoCs only support RMII */
 129        if (interface != PHY_INTERFACE_MODE_RMII) {
 130                dev_err(dev, "unsupported phy interface mode %d\n", interface);
 131                err = -ENOTSUPP;
 132                goto out_netdev;
 133        }
 134
 135        priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
 136                                                    "rockchip,grf");
 137        if (IS_ERR(priv->grf)) {
 138                dev_err(dev, "failed to retrieve global register file (%ld)\n",
 139                        PTR_ERR(priv->grf));
 140                err = PTR_ERR(priv->grf);
 141                goto out_netdev;
 142        }
 143
 144        match = of_match_node(emac_rockchip_dt_ids, dev->of_node);
 145        priv->soc_data = match->data;
 146
 147        priv->emac.clk = devm_clk_get(dev, "hclk");
 148        if (IS_ERR(priv->emac.clk)) {
 149                dev_err(dev, "failed to retrieve host clock (%ld)\n",
 150                        PTR_ERR(priv->emac.clk));
 151                err = PTR_ERR(priv->emac.clk);
 152                goto out_netdev;
 153        }
 154
 155        priv->refclk = devm_clk_get(dev, "macref");
 156        if (IS_ERR(priv->refclk)) {
 157                dev_err(dev, "failed to retrieve reference clock (%ld)\n",
 158                        PTR_ERR(priv->refclk));
 159                err = PTR_ERR(priv->refclk);
 160                goto out_netdev;
 161        }
 162
 163        err = clk_prepare_enable(priv->refclk);
 164        if (err) {
 165                dev_err(dev, "failed to enable reference clock (%d)\n", err);
 166                goto out_netdev;
 167        }
 168
 169        /* Optional regulator for PHY */
 170        priv->regulator = devm_regulator_get_optional(dev, "phy");
 171        if (IS_ERR(priv->regulator)) {
 172                if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) {
 173                        err = -EPROBE_DEFER;
 174                        goto out_clk_disable;
 175                }
 176                dev_err(dev, "no regulator found\n");
 177                priv->regulator = NULL;
 178        }
 179
 180        if (priv->regulator) {
 181                err = regulator_enable(priv->regulator);
 182                if (err) {
 183                        dev_err(dev, "failed to enable phy-supply (%d)\n", err);
 184                        goto out_clk_disable;
 185                }
 186        }
 187
 188        /* Set speed 100M */
 189        data = (1 << (priv->soc_data->grf_speed_offset + 16)) |
 190               (1 << priv->soc_data->grf_speed_offset);
 191        /* Set RMII mode */
 192        data |= (1 << (priv->soc_data->grf_mode_offset + 16)) |
 193                (0 << priv->soc_data->grf_mode_offset);
 194
 195        err = regmap_write(priv->grf, priv->soc_data->grf_offset, data);
 196        if (err) {
 197                dev_err(dev, "unable to apply initial settings to grf (%d)\n",
 198                        err);
 199                goto out_regulator_disable;
 200        }
 201
 202        /* RMII interface needs always a rate of 50MHz */
 203        err = clk_set_rate(priv->refclk, 50000000);
 204        if (err) {
 205                dev_err(dev,
 206                        "failed to change reference clock rate (%d)\n", err);
 207                goto out_regulator_disable;
 208        }
 209
 210        if (priv->soc_data->need_div_macclk) {
 211                priv->macclk = devm_clk_get(dev, "macclk");
 212                if (IS_ERR(priv->macclk)) {
 213                        dev_err(dev, "failed to retrieve mac clock (%ld)\n",
 214                                PTR_ERR(priv->macclk));
 215                        err = PTR_ERR(priv->macclk);
 216                        goto out_regulator_disable;
 217                }
 218
 219                err = clk_prepare_enable(priv->macclk);
 220                if (err) {
 221                        dev_err(dev, "failed to enable mac clock (%d)\n", err);
 222                        goto out_regulator_disable;
 223                }
 224
 225                /* RMII TX/RX needs always a rate of 25MHz */
 226                err = clk_set_rate(priv->macclk, 25000000);
 227                if (err) {
 228                        dev_err(dev,
 229                                "failed to change mac clock rate (%d)\n", err);
 230                        goto out_clk_disable_macclk;
 231                }
 232        }
 233
 234        err = arc_emac_probe(ndev, interface);
 235        if (err) {
 236                dev_err(dev, "failed to probe arc emac (%d)\n", err);
 237                goto out_clk_disable_macclk;
 238        }
 239
 240        return 0;
 241
 242out_clk_disable_macclk:
 243        if (priv->soc_data->need_div_macclk)
 244                clk_disable_unprepare(priv->macclk);
 245out_regulator_disable:
 246        if (priv->regulator)
 247                regulator_disable(priv->regulator);
 248out_clk_disable:
 249        clk_disable_unprepare(priv->refclk);
 250out_netdev:
 251        free_netdev(ndev);
 252        return err;
 253}
 254
 255static int emac_rockchip_remove(struct platform_device *pdev)
 256{
 257        struct net_device *ndev = platform_get_drvdata(pdev);
 258        struct rockchip_priv_data *priv = netdev_priv(ndev);
 259        int err;
 260
 261        err = arc_emac_remove(ndev);
 262
 263        clk_disable_unprepare(priv->refclk);
 264
 265        if (priv->regulator)
 266                regulator_disable(priv->regulator);
 267
 268        free_netdev(ndev);
 269        return err;
 270}
 271
 272static struct platform_driver emac_rockchip_driver = {
 273        .probe = emac_rockchip_probe,
 274        .remove = emac_rockchip_remove,
 275        .driver = {
 276                .name = DRV_NAME,
 277                .of_match_table  = emac_rockchip_dt_ids,
 278        },
 279};
 280
 281module_platform_driver(emac_rockchip_driver);
 282
 283MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
 284MODULE_DESCRIPTION("Rockchip EMAC platform driver");
 285MODULE_LICENSE("GPL");
 286