root/drivers/net/phy/mdio-gpio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mdio_gpio_get_data
  2. mdio_dir
  3. mdio_get
  4. mdio_set
  5. mdc_set
  6. mdio_gpio_bus_init
  7. mdio_gpio_bus_deinit
  8. mdio_gpio_bus_destroy
  9. mdio_gpio_probe
  10. mdio_gpio_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * GPIO based MDIO bitbang driver.
   4  * Supports OpenFirmware.
   5  *
   6  * Copyright (c) 2008 CSE Semaphore Belgium.
   7  *  by Laurent Pinchart <laurentp@cse-semaphore.com>
   8  *
   9  * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
  10  *
  11  * Based on earlier work by
  12  *
  13  * Copyright (c) 2003 Intracom S.A.
  14  *  by Pantelis Antoniou <panto@intracom.gr>
  15  *
  16  * 2005 (c) MontaVista Software, Inc.
  17  * Vitaly Bordug <vbordug@ru.mvista.com>
  18  */
  19 
  20 #include <linux/module.h>
  21 #include <linux/slab.h>
  22 #include <linux/interrupt.h>
  23 #include <linux/platform_device.h>
  24 #include <linux/platform_data/mdio-gpio.h>
  25 #include <linux/mdio-bitbang.h>
  26 #include <linux/mdio-gpio.h>
  27 #include <linux/gpio/consumer.h>
  28 #include <linux/of_mdio.h>
  29 
  30 struct mdio_gpio_info {
  31         struct mdiobb_ctrl ctrl;
  32         struct gpio_desc *mdc, *mdio, *mdo;
  33 };
  34 
  35 static int mdio_gpio_get_data(struct device *dev,
  36                               struct mdio_gpio_info *bitbang)
  37 {
  38         bitbang->mdc = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDC,
  39                                             GPIOD_OUT_LOW);
  40         if (IS_ERR(bitbang->mdc))
  41                 return PTR_ERR(bitbang->mdc);
  42 
  43         bitbang->mdio = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDIO,
  44                                              GPIOD_IN);
  45         if (IS_ERR(bitbang->mdio))
  46                 return PTR_ERR(bitbang->mdio);
  47 
  48         bitbang->mdo = devm_gpiod_get_index_optional(dev, NULL, MDIO_GPIO_MDO,
  49                                                      GPIOD_OUT_LOW);
  50         return PTR_ERR_OR_ZERO(bitbang->mdo);
  51 }
  52 
  53 static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
  54 {
  55         struct mdio_gpio_info *bitbang =
  56                 container_of(ctrl, struct mdio_gpio_info, ctrl);
  57 
  58         if (bitbang->mdo) {
  59                 /* Separate output pin. Always set its value to high
  60                  * when changing direction. If direction is input,
  61                  * assume the pin serves as pull-up. If direction is
  62                  * output, the default value is high.
  63                  */
  64                 gpiod_set_value_cansleep(bitbang->mdo, 1);
  65                 return;
  66         }
  67 
  68         if (dir)
  69                 gpiod_direction_output(bitbang->mdio, 1);
  70         else
  71                 gpiod_direction_input(bitbang->mdio);
  72 }
  73 
  74 static int mdio_get(struct mdiobb_ctrl *ctrl)
  75 {
  76         struct mdio_gpio_info *bitbang =
  77                 container_of(ctrl, struct mdio_gpio_info, ctrl);
  78 
  79         return gpiod_get_value_cansleep(bitbang->mdio);
  80 }
  81 
  82 static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
  83 {
  84         struct mdio_gpio_info *bitbang =
  85                 container_of(ctrl, struct mdio_gpio_info, ctrl);
  86 
  87         if (bitbang->mdo)
  88                 gpiod_set_value_cansleep(bitbang->mdo, what);
  89         else
  90                 gpiod_set_value_cansleep(bitbang->mdio, what);
  91 }
  92 
  93 static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
  94 {
  95         struct mdio_gpio_info *bitbang =
  96                 container_of(ctrl, struct mdio_gpio_info, ctrl);
  97 
  98         gpiod_set_value_cansleep(bitbang->mdc, what);
  99 }
 100 
 101 static const struct mdiobb_ops mdio_gpio_ops = {
 102         .owner = THIS_MODULE,
 103         .set_mdc = mdc_set,
 104         .set_mdio_dir = mdio_dir,
 105         .set_mdio_data = mdio_set,
 106         .get_mdio_data = mdio_get,
 107 };
 108 
 109 static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
 110                                           struct mdio_gpio_info *bitbang,
 111                                           int bus_id)
 112 {
 113         struct mdio_gpio_platform_data *pdata = dev_get_platdata(dev);
 114         struct mii_bus *new_bus;
 115 
 116         bitbang->ctrl.ops = &mdio_gpio_ops;
 117 
 118         new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
 119         if (!new_bus)
 120                 return NULL;
 121 
 122         new_bus->name = "GPIO Bitbanged MDIO";
 123         new_bus->parent = dev;
 124 
 125         if (bus_id != -1)
 126                 snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
 127         else
 128                 strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE);
 129 
 130         if (pdata) {
 131                 new_bus->phy_mask = pdata->phy_mask;
 132                 new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
 133         }
 134 
 135         dev_set_drvdata(dev, new_bus);
 136 
 137         return new_bus;
 138 }
 139 
 140 static void mdio_gpio_bus_deinit(struct device *dev)
 141 {
 142         struct mii_bus *bus = dev_get_drvdata(dev);
 143 
 144         free_mdio_bitbang(bus);
 145 }
 146 
 147 static void mdio_gpio_bus_destroy(struct device *dev)
 148 {
 149         struct mii_bus *bus = dev_get_drvdata(dev);
 150 
 151         mdiobus_unregister(bus);
 152         mdio_gpio_bus_deinit(dev);
 153 }
 154 
 155 static int mdio_gpio_probe(struct platform_device *pdev)
 156 {
 157         struct mdio_gpio_info *bitbang;
 158         struct mii_bus *new_bus;
 159         int ret, bus_id;
 160 
 161         bitbang = devm_kzalloc(&pdev->dev, sizeof(*bitbang), GFP_KERNEL);
 162         if (!bitbang)
 163                 return -ENOMEM;
 164 
 165         ret = mdio_gpio_get_data(&pdev->dev, bitbang);
 166         if (ret)
 167                 return ret;
 168 
 169         if (pdev->dev.of_node) {
 170                 bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio");
 171                 if (bus_id < 0) {
 172                         dev_warn(&pdev->dev, "failed to get alias id\n");
 173                         bus_id = 0;
 174                 }
 175         } else {
 176                 bus_id = pdev->id;
 177         }
 178 
 179         new_bus = mdio_gpio_bus_init(&pdev->dev, bitbang, bus_id);
 180         if (!new_bus)
 181                 return -ENODEV;
 182 
 183         ret = of_mdiobus_register(new_bus, pdev->dev.of_node);
 184         if (ret)
 185                 mdio_gpio_bus_deinit(&pdev->dev);
 186 
 187         return ret;
 188 }
 189 
 190 static int mdio_gpio_remove(struct platform_device *pdev)
 191 {
 192         mdio_gpio_bus_destroy(&pdev->dev);
 193 
 194         return 0;
 195 }
 196 
 197 static const struct of_device_id mdio_gpio_of_match[] = {
 198         { .compatible = "virtual,mdio-gpio", },
 199         { /* sentinel */ }
 200 };
 201 MODULE_DEVICE_TABLE(of, mdio_gpio_of_match);
 202 
 203 static struct platform_driver mdio_gpio_driver = {
 204         .probe = mdio_gpio_probe,
 205         .remove = mdio_gpio_remove,
 206         .driver         = {
 207                 .name   = "mdio-gpio",
 208                 .of_match_table = mdio_gpio_of_match,
 209         },
 210 };
 211 
 212 module_platform_driver(mdio_gpio_driver);
 213 
 214 MODULE_ALIAS("platform:mdio-gpio");
 215 MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
 216 MODULE_LICENSE("GPL v2");
 217 MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");

/* [<][>][^][v][top][bottom][index][help] */