From b97d27914354619ec6883ffe08dbd9c8e4b826b7 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 18 Apr 2007 16:39:54 +1000 Subject: [POWERPC] pasemi: GPIO MDIO of_platform driver MDIO driver for PHY's connected via GPIO as on the PA Semi Electra eval board. Signed-off-by: Olof Johansson Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/pasemi/gpio_mdio.c | 339 ++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 arch/powerpc/platforms/pasemi/gpio_mdio.c (limited to 'arch/powerpc/platforms/pasemi/gpio_mdio.c') diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c new file mode 100644 index 000000000000..b1d3b6b420ae --- /dev/null +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * Author: Olof Johansson, PA Semi + * + * Maintained by: Olof Johansson + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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)); +} + +static inline void mdio_hi(struct mii_bus *bus) +{ + out_le32(gpio_regs, 1 << MDIO_PIN(bus)); +} + +static inline void mdc_lo(struct mii_bus *bus) +{ + out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus)); +} + +static inline void mdc_hi(struct mii_bus *bus) +{ + out_le32(gpio_regs, 1 << MDC_PIN(bus)); +} + +static inline void mdio_active(struct mii_bus *bus) +{ + out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus))); +} + +static inline void mdio_tristate(struct mii_bus *bus) +{ + out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus))); +} + +static inline int mdio_read(struct mii_bus *bus) +{ + return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus))); +} + +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); +} + +/* 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; + } +} + +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; +} + +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; +} + +static int gpio_mdio_reset(struct mii_bus *bus) +{ + /*nothing here - dunno how to reset it*/ + return 0; +} + + +static int __devinit gpio_mdio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device *dev = &ofdev->dev; + struct device_node *np = ofdev->node; + struct device_node *gpio_np; + struct mii_bus *new_bus; + struct resource res; + struct gpio_priv *priv; + const unsigned int *prop; + int err = 0; + int i; + + gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio"); + + if (!gpio_np) + return -ENODEV; + + err = of_address_to_resource(gpio_np, 0, &res); + of_node_put(gpio_np); + + if (err) + return -EINVAL; + + if (!gpio_regs) + gpio_regs = ioremap(res.start, 0x100); + + if (!gpio_regs) + return -EPERM; + + priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); + + if (new_bus == NULL) + return -ENOMEM; + + 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 = get_property(np, "reg", NULL); + new_bus->id = *prop; + new_bus->priv = priv; + + new_bus->phy_mask = 0; + + new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + for(i = 0; i < PHY_MAX_ADDR; ++i) + new_bus->irq[i] = irq_create_mapping(NULL, 10); + + + prop = get_property(np, "mdc-pin", NULL); + priv->mdc_pin = *prop; + + prop = get_property(np, "mdio-pin", NULL); + priv->mdio_pin = *prop; + + new_bus->dev = dev; + dev_set_drvdata(dev, new_bus); + + err = mdiobus_register(new_bus); + + if (0 != err) { + printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n", + new_bus->name, err); + goto bus_register_fail; + } + + return 0; + +bus_register_fail: + kfree(new_bus); + + return err; +} + + +static int gpio_mdio_remove(struct of_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; + kfree(bus); + + return 0; +} + +static struct of_device_id gpio_mdio_match[] = +{ + { + .compatible = "gpio-mdio", + }, + {}, +}; + +static struct of_platform_driver gpio_mdio_driver = +{ + .name = "gpio-mdio-bitbang", + .match_table = gpio_mdio_match, + .probe = gpio_mdio_probe, + .remove = gpio_mdio_remove, +}; + +int gpio_mdio_init(void) +{ + return of_register_platform_driver(&gpio_mdio_driver); +} + +void gpio_mdio_exit(void) +{ + of_unregister_platform_driver(&gpio_mdio_driver); +} +device_initcall(gpio_mdio_init); + -- cgit v1.2.3-59-g8ed1b From 12d371a69e6df96cd949af6bcb569e978e8f9d41 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Sun, 29 Apr 2007 16:29:08 +1000 Subject: [POWERPC] get_property cleanups Just another pass through arch/powerpc for old usages. Signed-off-by: Stephen Rothwell Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/ras.c | 4 ++-- arch/powerpc/platforms/pasemi/cpufreq.c | 11 ++++++----- arch/powerpc/platforms/pasemi/gpio_mdio.c | 6 +++--- arch/powerpc/sysdev/uic.c | 8 ++++---- 4 files changed, 15 insertions(+), 14 deletions(-) (limited to 'arch/powerpc/platforms/pasemi/gpio_mdio.c') diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index b5ebc916388b..3961a085b432 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -149,7 +149,7 @@ static int __init cbe_ptcal_enable(void) if (!np) return -ENODEV; - size = get_property(np, "ibm,cbe-ptcal-size", NULL); + size = of_get_property(np, "ibm,cbe-ptcal-size", NULL); if (!size) return -ENODEV; @@ -168,7 +168,7 @@ static int __init cbe_ptcal_enable(void) /* support for older device tree - use cpu nodes */ for_each_node_by_type(np, "cpu") { - const u32 *nid = get_property(np, "node-id", NULL); + const u32 *nid = of_get_property(np, "node-id", NULL); if (!nid) { printk(KERN_ERR "%s: node %s is missing node-id?\n", __FUNCTION__, np->full_name); diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index 4dd5c512f869..2a57d6023685 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c @@ -134,7 +134,8 @@ void restore_astate(int cpu) static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) { - u32 *max_freq; + const u32 *max_freqp; + u32 max_freq; int i, cur_astate; struct resource res; struct device_node *cpu, *dn; @@ -175,16 +176,16 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) pr_debug("init cpufreq on CPU %d\n", policy->cpu); - max_freq = (u32*) get_property(cpu, "clock-frequency", NULL); - if (!max_freq) { + max_freqp = of_get_property(cpu, "clock-frequency", NULL); + if (!max_freqp) { err = -EINVAL; goto out_unmap_sdcpwr; } /* we need the freq in kHz */ - *max_freq /= 1000; + max_freq = *max_freqp / 1000; - pr_debug("max clock-frequency is at %u kHz\n", *max_freq); + pr_debug("max clock-frequency is at %u kHz\n", max_freq); pr_debug("initializing frequency table\n"); /* initialize frequency table */ diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index b1d3b6b420ae..c91a33593bb8 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c @@ -258,7 +258,7 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, new_bus->write = &gpio_mdio_write, new_bus->reset = &gpio_mdio_reset, - prop = get_property(np, "reg", NULL); + prop = of_get_property(np, "reg", NULL); new_bus->id = *prop; new_bus->priv = priv; @@ -269,10 +269,10 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, new_bus->irq[i] = irq_create_mapping(NULL, 10); - prop = get_property(np, "mdc-pin", NULL); + prop = of_get_property(np, "mdc-pin", NULL); priv->mdc_pin = *prop; - prop = get_property(np, "mdio-pin", NULL); + prop = of_get_property(np, "mdio-pin", NULL); priv->mdio_pin = *prop; new_bus->dev = dev; diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index cdbe68437afe..968fb40af9dc 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -230,7 +230,7 @@ static struct uic * __init uic_init_one(struct device_node *node) memset(uic, 0, sizeof(*uic)); spin_lock_init(&uic->lock); uic->of_node = of_node_get(node); - indexp = get_property(node, "cell-index", &len); + indexp = of_get_property(node, "cell-index", &len); if (!indexp || (len != sizeof(u32))) { printk(KERN_ERR "uic: Device node %s has missing or invalid " "cell-index property\n", node->full_name); @@ -238,7 +238,7 @@ static struct uic * __init uic_init_one(struct device_node *node) } uic->index = *indexp; - dcrreg = get_property(node, "dcr-reg", &len); + dcrreg = of_get_property(node, "dcr-reg", &len); if (!dcrreg || (len != 2*sizeof(u32))) { printk(KERN_ERR "uic: Device node %s has missing or invalid " "dcr-reg property\n", node->full_name); @@ -278,7 +278,7 @@ void __init uic_init_tree(void) np = of_find_compatible_node(NULL, NULL, "ibm,uic"); while (np) { - interrupts = get_property(np, "interrupts", NULL); + interrupts = of_get_property(np, "interrupts", NULL); if (! interrupts) break; @@ -297,7 +297,7 @@ void __init uic_init_tree(void) /* The scan again for cascaded UICs */ np = of_find_compatible_node(NULL, NULL, "ibm,uic"); while (np) { - interrupts = get_property(np, "interrupts", NULL); + interrupts = of_get_property(np, "interrupts", NULL); if (interrupts) { /* Secondary UIC */ int cascade_virq; -- cgit v1.2.3-59-g8ed1b