|
@@ -31,6 +31,7 @@
|
|
|
#include <linux/sysdev.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/ioport.h>
|
|
|
+#include <linux/mutex.h>
|
|
|
#include <linux/clk.h>
|
|
|
|
|
|
#include <asm/hardware.h>
|
|
@@ -111,20 +112,38 @@ static struct clk s3c2440_clk_ac97 = {
|
|
|
static int s3c2440_clk_add(struct sys_device *sysdev)
|
|
|
{
|
|
|
unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN);
|
|
|
+ unsigned long clkdivn;
|
|
|
struct clk *clk_h;
|
|
|
struct clk *clk_p;
|
|
|
+ struct clk *clk_upll;
|
|
|
|
|
|
printk("S3C2440: Clock Support, DVS %s\n",
|
|
|
(camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off");
|
|
|
|
|
|
clk_p = clk_get(NULL, "pclk");
|
|
|
clk_h = clk_get(NULL, "hclk");
|
|
|
+ clk_upll = clk_get(NULL, "upll");
|
|
|
|
|
|
- if (IS_ERR(clk_p) || IS_ERR(clk_h)) {
|
|
|
+ if (IS_ERR(clk_p) || IS_ERR(clk_h) || IS_ERR(clk_upll)) {
|
|
|
printk(KERN_ERR "S3C2440: Failed to get parent clocks\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ /* check rate of UPLL, and if it is near 96MHz, then change
|
|
|
+ * to using half the UPLL rate for the system */
|
|
|
+
|
|
|
+ if (clk_get_rate(clk_upll) > (94 * MHZ)) {
|
|
|
+ clk_usb_bus.rate = clk_get_rate(clk_upll) / 2;
|
|
|
+
|
|
|
+ mutex_lock(&clocks_mutex);
|
|
|
+
|
|
|
+ clkdivn = __raw_readl(S3C2410_CLKDIVN);
|
|
|
+ clkdivn |= S3C2440_CLKDIVN_UCLK;
|
|
|
+ __raw_writel(camdivn, S3C2410_CLKDIVN);
|
|
|
+
|
|
|
+ mutex_unlock(&clocks_mutex);
|
|
|
+ }
|
|
|
+
|
|
|
s3c2440_clk_cam.parent = clk_h;
|
|
|
s3c2440_clk_ac97.parent = clk_p;
|
|
|
s3c2440_clk_cam_upll.parent = clk_upll;
|