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