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.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        err = arc_emac_remove(ndev);
 206
 207        clk_disable_unprepare(priv->refclk);
 208
 209        if (priv->regulator)
 210                regulator_disable(priv->regulator);
 211
 212        free_netdev(ndev);
 213        return err;
 214}
 215
 216static struct platform_driver emac_rockchip_driver = {
 217        .probe = emac_rockchip_probe,
 218        .remove = emac_rockchip_remove,
 219        .driver = {
 220                .name = DRV_NAME,
 221                .of_match_table  = emac_rockchip_dt_ids,
 222        },
 223};
 224
 225module_platform_driver(emac_rockchip_driver);
 226
 227MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
 228MODULE_DESCRIPTION("Rockchip EMAC platform driver");
 229MODULE_LICENSE("GPL");
 230