Commit c3206e6f authored by David S. Miller's avatar David S. Miller

Merge branch 'mdio-gpio'

Guenter Roeck says:

====================
net: mdio-gpio enhancements

The following series of patches adds support for active-low gpio pins
as well as for systems with separate MDI and MDO pins to the mdio-gpio
driver.

A board using those features is based on a COM Express CPU board.
The COM Express standard supports GPIO pins on its connector,
with one caveat: The pins on the connector have fixed direction
and are hard configured either as input or output pins.
The COM Express Design Guide [1] provides additional details.

The hardware uses three of the GPO/GPI pins from the COM Express board
to drive an MDIO bus. Connectivity between GPI/GPO pins and the MDIO bus
is as follows.

GPI2 --------------------+------------ MDIO
                         |
            +--------+   |
GPO2 ---+---G        |   |
        |   |        |   |
       4.7k | 2N7002 D---+
	|   |        |
	+---S        |
	|   +--------+
       GND

GPO1 --------------------------------- MDC

To support this hardware, two extensions to the driver were necessary.

- Due to the FET in the MDO path (GPO2), the MDO signal is inverted.
  The driver therefore has to support active-low GPIO pins.

- The MDIO signal must be separated into MDI and MDO.

Those changes are implemented in patch 2/3 and 3/3.
Patch 1/3 simplifies the error path and thus the subsequent
patches.

[1] http://www.picmg.org/pdf/picmg_comdg_100.pdf
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents bc383ea5 f1d54c47
...@@ -32,29 +32,39 @@ ...@@ -32,29 +32,39 @@
struct mdio_gpio_info { struct mdio_gpio_info {
struct mdiobb_ctrl ctrl; struct mdiobb_ctrl ctrl;
int mdc, mdio; int mdc, mdio, mdo;
int mdc_active_low, mdio_active_low, mdo_active_low;
}; };
static void *mdio_gpio_of_get_data(struct platform_device *pdev) static void *mdio_gpio_of_get_data(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct mdio_gpio_platform_data *pdata; struct mdio_gpio_platform_data *pdata;
enum of_gpio_flags flags;
int ret; int ret;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return NULL; return NULL;
ret = of_get_gpio(np, 0); ret = of_get_gpio_flags(np, 0, &flags);
if (ret < 0) if (ret < 0)
return NULL; return NULL;
pdata->mdc = ret; pdata->mdc = ret;
pdata->mdc_active_low = flags & OF_GPIO_ACTIVE_LOW;
ret = of_get_gpio(np, 1); ret = of_get_gpio_flags(np, 1, &flags);
if (ret < 0) if (ret < 0)
return NULL; return NULL;
pdata->mdio = ret; pdata->mdio = ret;
pdata->mdio_active_low = flags & OF_GPIO_ACTIVE_LOW;
ret = of_get_gpio_flags(np, 2, &flags);
if (ret > 0) {
pdata->mdo = ret;
pdata->mdo_active_low = flags & OF_GPIO_ACTIVE_LOW;
}
return pdata; return pdata;
} }
...@@ -64,8 +74,19 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) ...@@ -64,8 +74,19 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
struct mdio_gpio_info *bitbang = struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl); container_of(ctrl, struct mdio_gpio_info, ctrl);
if (bitbang->mdo) {
/* Separate output pin. Always set its value to high
* when changing direction. If direction is input,
* assume the pin serves as pull-up. If direction is
* output, the default value is high.
*/
gpio_set_value(bitbang->mdo, 1 ^ bitbang->mdo_active_low);
return;
}
if (dir) if (dir)
gpio_direction_output(bitbang->mdio, 1); gpio_direction_output(bitbang->mdio,
1 ^ bitbang->mdio_active_low);
else else
gpio_direction_input(bitbang->mdio); gpio_direction_input(bitbang->mdio);
} }
...@@ -75,7 +96,7 @@ static int mdio_get(struct mdiobb_ctrl *ctrl) ...@@ -75,7 +96,7 @@ static int mdio_get(struct mdiobb_ctrl *ctrl)
struct mdio_gpio_info *bitbang = struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl); container_of(ctrl, struct mdio_gpio_info, ctrl);
return gpio_get_value(bitbang->mdio); return gpio_get_value(bitbang->mdio) ^ bitbang->mdio_active_low;
} }
static void mdio_set(struct mdiobb_ctrl *ctrl, int what) static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
...@@ -83,7 +104,10 @@ static void mdio_set(struct mdiobb_ctrl *ctrl, int what) ...@@ -83,7 +104,10 @@ static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
struct mdio_gpio_info *bitbang = struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl); container_of(ctrl, struct mdio_gpio_info, ctrl);
gpio_set_value(bitbang->mdio, what); if (bitbang->mdo)
gpio_set_value(bitbang->mdo, what ^ bitbang->mdo_active_low);
else
gpio_set_value(bitbang->mdio, what ^ bitbang->mdio_active_low);
} }
static void mdc_set(struct mdiobb_ctrl *ctrl, int what) static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
...@@ -91,7 +115,7 @@ static void mdc_set(struct mdiobb_ctrl *ctrl, int what) ...@@ -91,7 +115,7 @@ static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
struct mdio_gpio_info *bitbang = struct mdio_gpio_info *bitbang =
container_of(ctrl, struct mdio_gpio_info, ctrl); container_of(ctrl, struct mdio_gpio_info, ctrl);
gpio_set_value(bitbang->mdc, what); gpio_set_value(bitbang->mdc, what ^ bitbang->mdc_active_low);
} }
static struct mdiobb_ops mdio_gpio_ops = { static struct mdiobb_ops mdio_gpio_ops = {
...@@ -110,18 +134,22 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, ...@@ -110,18 +134,22 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
struct mdio_gpio_info *bitbang; struct mdio_gpio_info *bitbang;
int i; int i;
bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); bitbang = devm_kzalloc(dev, sizeof(*bitbang), GFP_KERNEL);
if (!bitbang) if (!bitbang)
goto out; goto out;
bitbang->ctrl.ops = &mdio_gpio_ops; bitbang->ctrl.ops = &mdio_gpio_ops;
bitbang->ctrl.reset = pdata->reset; bitbang->ctrl.reset = pdata->reset;
bitbang->mdc = pdata->mdc; bitbang->mdc = pdata->mdc;
bitbang->mdc_active_low = pdata->mdc_active_low;
bitbang->mdio = pdata->mdio; bitbang->mdio = pdata->mdio;
bitbang->mdio_active_low = pdata->mdio_active_low;
bitbang->mdo = pdata->mdo;
bitbang->mdo_active_low = pdata->mdo_active_low;
new_bus = alloc_mdio_bitbang(&bitbang->ctrl); new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
if (!new_bus) if (!new_bus)
goto out_free_bitbang; goto out;
new_bus->name = "GPIO Bitbanged MDIO", new_bus->name = "GPIO Bitbanged MDIO",
...@@ -138,11 +166,18 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, ...@@ -138,11 +166,18 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
if (gpio_request(bitbang->mdc, "mdc")) if (devm_gpio_request(dev, bitbang->mdc, "mdc"))
goto out_free_bus;
if (devm_gpio_request(dev, bitbang->mdio, "mdio"))
goto out_free_bus; goto out_free_bus;
if (gpio_request(bitbang->mdio, "mdio")) if (bitbang->mdo) {
goto out_free_mdc; if (devm_gpio_request(dev, bitbang->mdo, "mdo"))
goto out_free_bus;
gpio_direction_output(bitbang->mdo, 1);
gpio_direction_input(bitbang->mdio);
}
gpio_direction_output(bitbang->mdc, 0); gpio_direction_output(bitbang->mdc, 0);
...@@ -150,12 +185,8 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, ...@@ -150,12 +185,8 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
return new_bus; return new_bus;
out_free_mdc:
gpio_free(bitbang->mdc);
out_free_bus: out_free_bus:
free_mdio_bitbang(new_bus); free_mdio_bitbang(new_bus);
out_free_bitbang:
kfree(bitbang);
out: out:
return NULL; return NULL;
} }
...@@ -163,13 +194,8 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, ...@@ -163,13 +194,8 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
static void mdio_gpio_bus_deinit(struct device *dev) static void mdio_gpio_bus_deinit(struct device *dev)
{ {
struct mii_bus *bus = dev_get_drvdata(dev); struct mii_bus *bus = dev_get_drvdata(dev);
struct mdio_gpio_info *bitbang = bus->priv;
dev_set_drvdata(dev, NULL);
gpio_free(bitbang->mdio);
gpio_free(bitbang->mdc);
free_mdio_bitbang(bus); free_mdio_bitbang(bus);
kfree(bitbang);
} }
static void mdio_gpio_bus_destroy(struct device *dev) static void mdio_gpio_bus_destroy(struct device *dev)
......
...@@ -17,6 +17,11 @@ struct mdio_gpio_platform_data { ...@@ -17,6 +17,11 @@ struct mdio_gpio_platform_data {
/* GPIO numbers for bus pins */ /* GPIO numbers for bus pins */
unsigned int mdc; unsigned int mdc;
unsigned int mdio; unsigned int mdio;
unsigned int mdo;
bool mdc_active_low;
bool mdio_active_low;
bool mdo_active_low;
unsigned int phy_mask; unsigned int phy_mask;
int irqs[PHY_MAX_ADDR]; int irqs[PHY_MAX_ADDR];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment