Release 4.14 arch/powerpc/platforms/pasemi/gpio_mdio.c
/*
* Copyright (C) 2006-2007 PA Semi, Inc
*
* Author: Olof Johansson, PA Semi
*
* Maintained by: Olof Johansson <olof@lixom.net>
*
* Based on drivers/net/fs_enet/mii-bitbang.c.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/phy.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#define DELAY 1
static void __iomem *gpio_regs;
struct gpio_priv {
int mdc_pin;
int mdio_pin;
};
#define MDC_PIN(bus) (((struct gpio_priv *)bus->priv)->mdc_pin)
#define MDIO_PIN(bus) (((struct gpio_priv *)bus->priv)->mdio_pin)
static inline void mdio_lo(struct mii_bus *bus)
{
out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 26 | 100.00% | 1 | 100.00% |
Total | 26 | 100.00% | 1 | 100.00% |
static inline void mdio_hi(struct mii_bus *bus)
{
out_le32(gpio_regs, 1 << MDIO_PIN(bus));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.00% |
static inline void mdc_lo(struct mii_bus *bus)
{
out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 26 | 100.00% | 1 | 100.00% |
Total | 26 | 100.00% | 1 | 100.00% |
static inline void mdc_hi(struct mii_bus *bus)
{
out_le32(gpio_regs, 1 << MDC_PIN(bus));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 24 | 100.00% | 1 | 100.00% |
Total | 24 | 100.00% | 1 | 100.00% |
static inline void mdio_active(struct mii_bus *bus)
{
out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 37 | 100.00% | 1 | 100.00% |
Total | 37 | 100.00% | 1 | 100.00% |
static inline void mdio_tristate(struct mii_bus *bus)
{
out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 28 | 100.00% | 1 | 100.00% |
Total | 28 | 100.00% | 1 | 100.00% |
static inline int mdio_read(struct mii_bus *bus)
{
return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 33 | 100.00% | 1 | 100.00% |
Total | 33 | 100.00% | 1 | 100.00% |
static void clock_out(struct mii_bus *bus, int bit)
{
if (bit)
mdio_hi(bus);
else
mdio_lo(bus);
udelay(DELAY);
mdc_hi(bus);
udelay(DELAY);
mdc_lo(bus);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 49 | 100.00% | 1 | 100.00% |
Total | 49 | 100.00% | 1 | 100.00% |
/* Utility to send the preamble, address, and register (common to read and write). */
static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
{
int i;
/* CFE uses a really long preamble (40 bits). We'll do the same. */
mdio_active(bus);
for (i = 0; i < 40; i++) {
clock_out(bus, 1);
}
/* send the start bit (01) and the read opcode (10) or write (10) */
clock_out(bus, 0);
clock_out(bus, 1);
clock_out(bus, read);
clock_out(bus, !read);
/* send the PHY address */
for (i = 0; i < 5; i++) {
clock_out(bus, (addr & 0x10) != 0);
addr <<= 1;
}
/* send the register address */
for (i = 0; i < 5; i++) {
clock_out(bus, (reg & 0x10) != 0);
reg <<= 1;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 147 | 100.00% | 1 | 100.00% |
Total | 147 | 100.00% | 1 | 100.00% |
static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
{
u16 rdreg;
int ret, i;
u8 addr = phy_id & 0xff;
u8 reg = location & 0xff;
bitbang_pre(bus, 1, addr, reg);
/* tri-state our MDIO I/O pin so we can read */
mdio_tristate(bus);
udelay(DELAY);
mdc_hi(bus);
udelay(DELAY);
mdc_lo(bus);
/* read 16 bits of register data, MSB first */
rdreg = 0;
for (i = 0; i < 16; i++) {
mdc_lo(bus);
udelay(DELAY);
mdc_hi(bus);
udelay(DELAY);
mdc_lo(bus);
udelay(DELAY);
rdreg <<= 1;
rdreg |= mdio_read(bus);
}
mdc_hi(bus);
udelay(DELAY);
mdc_lo(bus);
udelay(DELAY);
ret = rdreg;
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 164 | 100.00% | 1 | 100.00% |
Total | 164 | 100.00% | 1 | 100.00% |
static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
{
int i;
u8 addr = phy_id & 0xff;
u8 reg = location & 0xff;
u16 value = val & 0xffff;
bitbang_pre(bus, 0, addr, reg);
/* send the turnaround (10) */
mdc_lo(bus);
mdio_hi(bus);
udelay(DELAY);
mdc_hi(bus);
udelay(DELAY);
mdc_lo(bus);
mdio_lo(bus);
udelay(DELAY);
mdc_hi(bus);
udelay(DELAY);
/* write 16 bits of register data, MSB first */
for (i = 0; i < 16; i++) {
mdc_lo(bus);
if (value & 0x8000)
mdio_hi(bus);
else
mdio_lo(bus);
udelay(DELAY);
mdc_hi(bus);
udelay(DELAY);
value <<= 1;
}
/*
* Tri-state the MDIO line.
*/
mdio_tristate(bus);
mdc_lo(bus);
udelay(DELAY);
mdc_hi(bus);
udelay(DELAY);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 192 | 100.00% | 1 | 100.00% |
Total | 192 | 100.00% | 1 | 100.00% |
static int gpio_mdio_reset(struct mii_bus *bus)
{
/*nothing here - dunno how to reset it*/
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 15 | 100.00% | 1 | 100.00% |
Total | 15 | 100.00% | 1 | 100.00% |
static int gpio_mdio_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->dev.of_node;
struct mii_bus *new_bus;
struct gpio_priv *priv;
const unsigned int *prop;
int err;
err = -ENOMEM;
priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
if (!priv)
goto out;
new_bus = mdiobus_alloc();
if (!new_bus)
goto out_free_priv;
new_bus->name = "pasemi gpio mdio bus";
new_bus->read = &gpio_mdio_read;
new_bus->write = &gpio_mdio_write;
new_bus->reset = &gpio_mdio_reset;
prop = of_get_property(np, "reg", NULL);
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", *prop);
new_bus->priv = priv;
prop = of_get_property(np, "mdc-pin", NULL);
priv->mdc_pin = *prop;
prop = of_get_property(np, "mdio-pin", NULL);
priv->mdio_pin = *prop;
new_bus->parent = dev;
dev_set_drvdata(dev, new_bus);
err = of_mdiobus_register(new_bus, np);
if (err != 0) {
printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
new_bus->name, err);
goto out_free_irq;
}
return 0;
out_free_irq:
kfree(new_bus);
out_free_priv:
kfree(priv);
out:
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 230 | 91.63% | 2 | 22.22% |
Andy Fleming | 8 | 3.19% | 1 | 11.11% |
Grant C. Likely | 7 | 2.79% | 3 | 33.33% |
Stephen Rothwell | 3 | 1.20% | 1 | 11.11% |
Lennert Buytenhek | 3 | 1.20% | 2 | 22.22% |
Total | 251 | 100.00% | 9 | 100.00% |
static int gpio_mdio_remove(struct platform_device *dev)
{
struct mii_bus *bus = dev_get_drvdata(&dev->dev);
mdiobus_unregister(bus);
dev_set_drvdata(&dev->dev, NULL);
kfree(bus->priv);
bus->priv = NULL;
mdiobus_free(bus);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 58 | 96.67% | 1 | 33.33% |
Lennert Buytenhek | 1 | 1.67% | 1 | 33.33% |
Grant C. Likely | 1 | 1.67% | 1 | 33.33% |
Total | 60 | 100.00% | 3 | 100.00% |
static const struct of_device_id gpio_mdio_match[] =
{
{
.compatible = "gpio-mdio",
},
{},
};
MODULE_DEVICE_TABLE(of, gpio_mdio_match);
static struct platform_driver gpio_mdio_driver =
{
.probe = gpio_mdio_probe,
.remove = gpio_mdio_remove,
.driver = {
.name = "gpio-mdio-bitbang",
.of_match_table = gpio_mdio_match,
},
};
static int gpio_mdio_init(void)
{
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "1682m-gpio");
if (!np)
np = of_find_compatible_node(NULL, NULL,
"pasemi,pwrficient-gpio");
if (!np)
return -ENODEV;
gpio_regs = of_iomap(np, 0);
of_node_put(np);
if (!gpio_regs)
return -ENODEV;
return platform_driver_register(&gpio_mdio_driver);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 77 | 97.47% | 3 | 60.00% |
Daniel Axtens | 1 | 1.27% | 1 | 20.00% |
Grant C. Likely | 1 | 1.27% | 1 | 20.00% |
Total | 79 | 100.00% | 5 | 100.00% |
module_init(gpio_mdio_init);
static void gpio_mdio_exit(void)
{
platform_driver_unregister(&gpio_mdio_driver);
if (gpio_regs)
iounmap(gpio_regs);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 21 | 91.30% | 2 | 50.00% |
Daniel Axtens | 1 | 4.35% | 1 | 25.00% |
Grant C. Likely | 1 | 4.35% | 1 | 25.00% |
Total | 23 | 100.00% | 4 | 100.00% |
module_exit(gpio_mdio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards");
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Olof Johansson | 1281 | 96.10% | 4 | 21.05% |
Grant C. Likely | 17 | 1.28% | 5 | 26.32% |
Stephen Rothwell | 13 | 0.98% | 2 | 10.53% |
Andy Fleming | 8 | 0.60% | 1 | 5.26% |
Lennert Buytenhek | 4 | 0.30% | 2 | 10.53% |
Tejun Heo | 3 | 0.23% | 1 | 5.26% |
Rob Herring | 3 | 0.23% | 1 | 5.26% |
Daniel Axtens | 2 | 0.15% | 1 | 5.26% |
Jon Loeliger | 1 | 0.08% | 1 | 5.26% |
Uwe Kleine-König | 1 | 0.08% | 1 | 5.26% |
Total | 1333 | 100.00% | 19 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.