X-Git-Url: https://git.archive.openwrt.org/?p=openwrt.git;a=blobdiff_plain;f=target%2Flinux%2Far71xx%2Ffiles%2Fdrivers%2Fnet%2Fethernet%2Fatheros%2Fag71xx%2Fag71xx_mdio.c;h=71ae8258b2ef20f7d20ceacec59011ab3babfe23;hp=eaaf12148531f1e141cf6e52b60422d0f7e9de56;hb=48b2781cf59dc1b00cd35ec1b83bfe4beaecf092;hpb=641595b79aacc036a21116a578b8cad093bb02b4 diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c index eaaf121485..71ae8258b2 100644 --- a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c +++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c @@ -105,19 +105,75 @@ void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val) ag71xx_mdio_wait_busy(am); } +static const u32 ar71xx_mdio_div_table[] = { + 4, 4, 6, 8, 10, 14, 20, 28, +}; + +static const u32 ar7240_mdio_div_table[] = { + 2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96, +}; + +static const u32 ar933x_mdio_div_table[] = { + 4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98, +}; + +static int ag71xx_mdio_get_divider(struct ag71xx_mdio *am, u32 *div) +{ + unsigned long ref_clock, mdio_clock; + const u32 *table; + int ndivs; + int i; + + ref_clock = am->pdata->ref_clock; + mdio_clock = am->pdata->mdio_clock; + + if (!ref_clock || !mdio_clock) + return -EINVAL; + + if (am->pdata->is_ar9330 || am->pdata->is_ar934x) { + table = ar933x_mdio_div_table; + ndivs = ARRAY_SIZE(ar933x_mdio_div_table); + } else if (am->pdata->is_ar7240) { + table = ar7240_mdio_div_table; + ndivs = ARRAY_SIZE(ar7240_mdio_div_table); + } else { + table = ar71xx_mdio_div_table; + ndivs = ARRAY_SIZE(ar71xx_mdio_div_table); + } + + for (i = 0; i < ndivs; i++) { + unsigned long t; + + t = ref_clock / table[i]; + if (t <= mdio_clock) { + *div = i; + return 0; + } + } + + dev_err(&am->mii_bus->dev, "no divider found for %lu/%lu\n", + ref_clock, mdio_clock); + return -ENOENT; +} + static int ag71xx_mdio_reset(struct mii_bus *bus) { struct ag71xx_mdio *am = bus->priv; u32 t; + int err; - if (am->pdata->is_ar7240) - t = MII_CFG_CLK_DIV_6; - else if (am->pdata->builtin_switch && !am->pdata->is_ar934x) - t = MII_CFG_CLK_DIV_10; - else if (!am->pdata->builtin_switch && am->pdata->is_ar934x) - t = MII_CFG_CLK_DIV_58; - else - t = MII_CFG_CLK_DIV_28; + err = ag71xx_mdio_get_divider(am, &t); + if (err) { + /* fallback */ + if (am->pdata->is_ar7240) + t = MII_CFG_CLK_DIV_6; + else if (am->pdata->builtin_switch && !am->pdata->is_ar934x) + t = MII_CFG_CLK_DIV_10; + else if (!am->pdata->builtin_switch && am->pdata->is_ar934x) + t = MII_CFG_CLK_DIV_58; + else + t = MII_CFG_CLK_DIV_28; + } ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t | MII_CFG_RESET); udelay(100); @@ -125,6 +181,9 @@ static int ag71xx_mdio_reset(struct mii_bus *bus) ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t); udelay(100); + if (am->pdata->reset) + am->pdata->reset(bus); + return 0; } @@ -149,7 +208,7 @@ static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val) return 0; } -static int __devinit ag71xx_mdio_probe(struct platform_device *pdev) +static int ag71xx_mdio_probe(struct platform_device *pdev) { struct ag71xx_mdio_platform_data *pdata; struct ag71xx_mdio *am; @@ -225,7 +284,7 @@ err_out: return err; } -static int __devexit ag71xx_mdio_remove(struct platform_device *pdev) +static int ag71xx_mdio_remove(struct platform_device *pdev) { struct ag71xx_mdio *am = platform_get_drvdata(pdev); @@ -242,7 +301,7 @@ static int __devexit ag71xx_mdio_remove(struct platform_device *pdev) static struct platform_driver ag71xx_mdio_driver = { .probe = ag71xx_mdio_probe, - .remove = __exit_p(ag71xx_mdio_remove), + .remove = ag71xx_mdio_remove, .driver = { .name = "ag71xx-mdio", }