SM501: Clock updates and checks
[powerpc.git] / drivers / mfd / sm501.c
index 3a0ecfc..e14d70e 100644 (file)
@@ -855,6 +855,24 @@ static void sm501_init_regs(struct sm501_devdata *sm,
                dev_info(sm->dev, "setting MCLK to %ld\n", init->mclk);
                sm501_set_clock(sm->dev, SM501_CLOCK_MCLK, init->mclk);
        }
+
+}
+
+/* Check the PLL sources for the M1CLK and M1XCLK
+ *
+ * If the M1CLK and M1XCLKs are not sourced from the same PLL, then
+ * there is a risk (see errata AB-5) that the SM501 will cease proper
+ * function. If this happens, then it is likely the SM501 will
+ * hang the system.
+*/
+
+static int sm501_check_clocks(struct sm501_devdata *sm)
+{
+       unsigned long pwrmode = readl(sm->regs + SM501_CURRENT_CLOCK);
+       unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC);
+       unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC);
+
+       return ((msrc == 0 && m1src != 0) || (msrc != 0 && m1src == 0));
 }
 
 static unsigned int sm501_mem_local[] = {
@@ -911,6 +929,13 @@ static int sm501_init_dev(struct sm501_devdata *sm)
                }
        }
 
+       ret = sm501_check_clocks(sm);
+       if (ret) {
+               dev_err(sm->dev, "M1X and M clocks sourced from different "
+                                       "PLLs\n");
+               return -EINVAL;
+       }
+
        /* always create a framebuffer */
        sm501_register_display(sm, &mem_avail);
 
@@ -1048,8 +1073,12 @@ static struct sm501_initdata sm501_pci_initdata = {
        },
 
        .devices        = SM501_USE_ALL,
-       .mclk           = 100 * MHZ,
-       .m1xclk         = 160 * MHZ,
+
+       /* Errata AB-3 says that 72MHz is the fastest available
+        * for 33MHZ PCI with proper bus-mastering operation */
+
+       .mclk           = 72 * MHZ,
+       .m1xclk         = 144 * MHZ,
 };
 
 static struct sm501_platdata_fbsub sm501_pdata_fbsub = {