1 // SPDX-License-Identifier: GPL-2.0
3 * GPIO based MDIO bitbang driver.
4 * Supports OpenFirmware.
6 * Copyright (c) 2008 CSE Semaphore Belgium.
7 * by Laurent Pinchart <laurentp@cse-semaphore.com>
9 * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
11 * Based on earlier work by
13 * Copyright (c) 2003 Intracom S.A.
14 * by Pantelis Antoniou <panto@intracom.gr>
16 * 2005 (c) MontaVista Software, Inc.
17 * Vitaly Bordug <vbordug@ru.mvista.com>
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>
30 struct mdio_gpio_info
{
31 struct mdiobb_ctrl ctrl
;
32 struct gpio_desc
*mdc
, *mdio
, *mdo
;
35 static int mdio_gpio_get_data(struct device
*dev
,
36 struct mdio_gpio_info
*bitbang
)
38 bitbang
->mdc
= devm_gpiod_get_index(dev
, NULL
, MDIO_GPIO_MDC
,
40 if (IS_ERR(bitbang
->mdc
))
41 return PTR_ERR(bitbang
->mdc
);
43 bitbang
->mdio
= devm_gpiod_get_index(dev
, NULL
, MDIO_GPIO_MDIO
,
45 if (IS_ERR(bitbang
->mdio
))
46 return PTR_ERR(bitbang
->mdio
);
48 bitbang
->mdo
= devm_gpiod_get_index_optional(dev
, NULL
, MDIO_GPIO_MDO
,
50 return PTR_ERR_OR_ZERO(bitbang
->mdo
);
53 static void mdio_dir(struct mdiobb_ctrl
*ctrl
, int dir
)
55 struct mdio_gpio_info
*bitbang
=
56 container_of(ctrl
, struct mdio_gpio_info
, ctrl
);
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.
64 gpiod_set_value_cansleep(bitbang
->mdo
, 1);
69 gpiod_direction_output(bitbang
->mdio
, 1);
71 gpiod_direction_input(bitbang
->mdio
);
74 static int mdio_get(struct mdiobb_ctrl
*ctrl
)
76 struct mdio_gpio_info
*bitbang
=
77 container_of(ctrl
, struct mdio_gpio_info
, ctrl
);
79 return gpiod_get_value_cansleep(bitbang
->mdio
);
82 static void mdio_set(struct mdiobb_ctrl
*ctrl
, int what
)
84 struct mdio_gpio_info
*bitbang
=
85 container_of(ctrl
, struct mdio_gpio_info
, ctrl
);
88 gpiod_set_value_cansleep(bitbang
->mdo
, what
);
90 gpiod_set_value_cansleep(bitbang
->mdio
, what
);
93 static void mdc_set(struct mdiobb_ctrl
*ctrl
, int what
)
95 struct mdio_gpio_info
*bitbang
=
96 container_of(ctrl
, struct mdio_gpio_info
, ctrl
);
98 gpiod_set_value_cansleep(bitbang
->mdc
, what
);
101 static const struct mdiobb_ops mdio_gpio_ops
= {
102 .owner
= THIS_MODULE
,
104 .set_mdio_dir
= mdio_dir
,
105 .set_mdio_data
= mdio_set
,
106 .get_mdio_data
= mdio_get
,
109 static struct mii_bus
*mdio_gpio_bus_init(struct device
*dev
,
110 struct mdio_gpio_info
*bitbang
,
113 struct mdio_gpio_platform_data
*pdata
= dev_get_platdata(dev
);
114 struct mii_bus
*new_bus
;
116 bitbang
->ctrl
.ops
= &mdio_gpio_ops
;
118 new_bus
= alloc_mdio_bitbang(&bitbang
->ctrl
);
122 new_bus
->name
= "GPIO Bitbanged MDIO";
123 new_bus
->parent
= dev
;
126 snprintf(new_bus
->id
, MII_BUS_ID_SIZE
, "gpio-%x", bus_id
);
128 strncpy(new_bus
->id
, "gpio", MII_BUS_ID_SIZE
);
131 new_bus
->phy_mask
= pdata
->phy_mask
;
132 new_bus
->phy_ignore_ta_mask
= pdata
->phy_ignore_ta_mask
;
135 dev_set_drvdata(dev
, new_bus
);
140 static void mdio_gpio_bus_deinit(struct device
*dev
)
142 struct mii_bus
*bus
= dev_get_drvdata(dev
);
144 free_mdio_bitbang(bus
);
147 static void mdio_gpio_bus_destroy(struct device
*dev
)
149 struct mii_bus
*bus
= dev_get_drvdata(dev
);
151 mdiobus_unregister(bus
);
152 mdio_gpio_bus_deinit(dev
);
155 static int mdio_gpio_probe(struct platform_device
*pdev
)
157 struct mdio_gpio_info
*bitbang
;
158 struct mii_bus
*new_bus
;
161 bitbang
= devm_kzalloc(&pdev
->dev
, sizeof(*bitbang
), GFP_KERNEL
);
165 ret
= mdio_gpio_get_data(&pdev
->dev
, bitbang
);
169 if (pdev
->dev
.of_node
) {
170 bus_id
= of_alias_get_id(pdev
->dev
.of_node
, "mdio-gpio");
172 dev_warn(&pdev
->dev
, "failed to get alias id\n");
179 new_bus
= mdio_gpio_bus_init(&pdev
->dev
, bitbang
, bus_id
);
183 ret
= of_mdiobus_register(new_bus
, pdev
->dev
.of_node
);
185 mdio_gpio_bus_deinit(&pdev
->dev
);
190 static int mdio_gpio_remove(struct platform_device
*pdev
)
192 mdio_gpio_bus_destroy(&pdev
->dev
);
197 static const struct of_device_id mdio_gpio_of_match
[] = {
198 { .compatible
= "virtual,mdio-gpio", },
201 MODULE_DEVICE_TABLE(of
, mdio_gpio_of_match
);
203 static struct platform_driver mdio_gpio_driver
= {
204 .probe
= mdio_gpio_probe
,
205 .remove
= mdio_gpio_remove
,
208 .of_match_table
= mdio_gpio_of_match
,
212 module_platform_driver(mdio_gpio_driver
);
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");