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);