static DECLARE_MUTEX(clocks_sem);
 static DEFINE_SPINLOCK(clockfw_lock);
 static void propagate_rate(struct clk *  clk);
+/* UART clock function */
+static int set_uart_rate(struct clk * clk, unsigned long rate);
 /* External clock (MCLK & BCLK) functions */
 static int set_ext_clk_rate(struct clk *  clk, unsigned long rate);
 static long round_ext_clk_rate(struct clk *  clk, unsigned long rate);
 static long round_to_table_rate(struct clk *  clk, unsigned long rate);
 void clk_setdpll(__u16, __u16);
 
-struct mpu_rate rate_table[] = {
+static struct mpu_rate rate_table[] = {
        /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
         * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
         */
        { 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
 #endif
 #if defined(CONFIG_OMAP_ARM_150MHZ)
-       { 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
+       { 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */
 #endif
 #if defined(CONFIG_OMAP_ARM_120MHZ)
        { 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
 };
 
 
-static void ckctl_recalc(struct clk *  clk)
-{
-       int dsor;
-
-       /* Calculate divisor encoded as 2-bit exponent */
-       dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
-       if (unlikely(clk->rate == clk->parent->rate / dsor))
-               return; /* No change, quick exit */
-       clk->rate = clk->parent->rate / dsor;
-
-       if (unlikely(clk->flags & RATE_PROPAGATES))
-               propagate_rate(clk);
-}
+static void ckctl_recalc(struct clk *  clk);
+int __clk_enable(struct clk *clk);
+void __clk_disable(struct clk *clk);
+void __clk_unuse(struct clk *clk);
+int __clk_use(struct clk *clk);
 
 
 static void followparent_recalc(struct clk *  clk)
        clk->rate = clk->parent->rate / 14;
 }
 
+static void uart_recalc(struct clk * clk)
+{
+       unsigned int val = omap_readl(clk->enable_reg);
+       if (val & clk->enable_bit)
+               clk->rate = 48000000;
+       else
+               clk->rate = 12000000;
+}
 
 static struct clk ck_ref = {
        .name           = "ck_ref",
 static struct clk arminth_ck16xx = {
        .name           = "arminth_ck",
        .parent         = &arm_ck,
-       .flags          = CLOCK_IN_OMAP16XX,
+       .flags          = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
        /* Note: On 16xx the frequency can be divided by 2 by programming
         * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
        .recalc         = &ckctl_recalc,
 };
 
+static struct clk dspper_ck = {
+       .name           = "dspper_ck",
+       .parent         = &ck_dpll1,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         RATE_CKCTL | DSP_DOMAIN_CLOCK,
+       .enable_reg     = DSP_IDLECT2,
+       .enable_bit     = EN_PERCK,
+       .rate_offset    = CKCTL_PERDIV_OFFSET,
+       .recalc         = &followparent_recalc,
+       //.recalc               = &ckctl_recalc,
+};
+
+static struct clk dspxor_ck = {
+       .name           = "dspxor_ck",
+       .parent         = &ck_ref,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         DSP_DOMAIN_CLOCK,
+       .enable_reg     = DSP_IDLECT2,
+       .enable_bit     = EN_XORPCK,
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk dsptim_ck = {
+       .name           = "dsptim_ck",
+       .parent         = &ck_ref,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         DSP_DOMAIN_CLOCK,
+       .enable_reg     = DSP_IDLECT2,
+       .enable_bit     = EN_DSPTIMCK,
+       .recalc         = &followparent_recalc,
+};
+
 static struct clk tc_ck = {
        .name           = "tc_ck",
        .parent         = &ck_dpll1,
 static struct clk arminth_ck1510 = {
        .name           = "arminth_ck",
        .parent         = &tc_ck,
-       .flags          = CLOCK_IN_OMAP1510,
+       .flags          = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
        /* Note: On 1510 the frequency follows TC_CK
         *
 static struct clk tipb_ck = {
        .name           = "tibp_ck",
        .parent         = &tc_ck,
-       .flags          = CLOCK_IN_OMAP1510,
+       .flags          = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk dma_ck = {
        .name           = "dma_ck",
        .parent         = &tc_ck,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+                         ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk dma_lcdfree_ck = {
        .name           = "dma_lcdfree_ck",
        .parent         = &tc_ck,
-       .flags          = CLOCK_IN_OMAP16XX,
+       .flags          = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk rhea1_ck = {
        .name           = "rhea1_ck",
        .parent         = &tc_ck,
-       .flags          = CLOCK_IN_OMAP16XX,
+       .flags          = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk rhea2_ck = {
        .name           = "rhea2_ck",
        .parent         = &tc_ck,
-       .flags          = CLOCK_IN_OMAP16XX,
+       .flags          = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
 };
 
        .recalc         = &ckctl_recalc,
 };
 
-static struct clk uart1_ck = {
+static struct clk uart1_1510 = {
+       .name           = "uart1_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 12000000,
+       .flags          = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = 29,   /* Chooses between 12MHz and 48MHz */
+       .set_rate       = &set_uart_rate,
+       .recalc         = &uart_recalc,
+};
+
+static struct clk uart1_16xx = {
        .name           = "uart1_ck",
        /* Direct from ULPD, no parent */
        .rate           = 48000000,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-                         RATE_FIXED | ENABLE_REG_32BIT,
+       .flags          = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
        .enable_reg     = MOD_CONF_CTRL_0,
        .enable_bit     = 29,
-       /* (Only on 1510)
-        * The "enable bit" actually chooses between 48MHz and 12MHz.
-        */
 };
 
 static struct clk uart2_ck = {
        .name           = "uart2_ck",
        /* Direct from ULPD, no parent */
-       .rate           = 48000000,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-                         RATE_FIXED | ENABLE_REG_32BIT,
+       .rate           = 12000000,
+       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT |
+                         ALWAYS_ENABLED,
        .enable_reg     = MOD_CONF_CTRL_0,
-       .enable_bit     = 30,
-       /* (for both 1510 and 16xx)
-        * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
-        */
+       .enable_bit     = 30,   /* Chooses between 12MHz and 48MHz */
+       .set_rate       = &set_uart_rate,
+       .recalc         = &uart_recalc,
+};
+
+static struct clk uart3_1510 = {
+       .name           = "uart3_ck",
+       /* Direct from ULPD, no parent */
+       .rate           = 12000000,
+       .flags          = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+       .enable_reg     = MOD_CONF_CTRL_0,
+       .enable_bit     = 31,   /* Chooses between 12MHz and 48MHz */
+       .set_rate       = &set_uart_rate,
+       .recalc         = &uart_recalc,
 };
 
-static struct clk uart3_ck = {
+static struct clk uart3_16xx = {
        .name           = "uart3_ck",
        /* Direct from ULPD, no parent */
        .rate           = 48000000,
-       .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-                         RATE_FIXED | ENABLE_REG_32BIT,
+       .flags          = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
        .enable_reg     = MOD_CONF_CTRL_0,
        .enable_bit     = 31,
-       /* (Only on 1510)
-        * The "enable bit" actually chooses between 48MHz and 12MHz.
-        */
 };
 
 static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */
        /* CK_GEN2 clocks */
        &dsp_ck,
        &dspmmu_ck,
+       &dspper_ck,
+       &dspxor_ck,
+       &dsptim_ck,
        /* CK_GEN3 clocks */
        &tc_ck,
        &tipb_ck,
        &rhea2_ck,
        &lcd_ck,
        /* ULPD clocks */
-       &uart1_ck,
+       &uart1_1510,
+       &uart1_16xx,
        &uart2_ck,
-       &uart3_ck,
+       &uart3_1510,
+       &uart3_16xx,
        &usb_clko,
        &usb_hhc_ck1510, &usb_hhc_ck16xx,
        &mclk_1510,  &mclk_16xx,
                return 0;
        }
 
+       if (clk->flags & DSP_DOMAIN_CLOCK) {
+               __clk_use(&api_ck);
+       }
+
        if (clk->flags & ENABLE_REG_32BIT) {
                regval32 = omap_readl(clk->enable_reg);
                regval32 |= (1 << clk->enable_bit);
                omap_writew(regval16, clk->enable_reg);
        }
 
+       if (clk->flags & DSP_DOMAIN_CLOCK) {
+               __clk_unuse(&api_ck);
+       }
+
        return 0;
 }
 
        if (clk->enable_reg == 0)
                return;
 
+       if (clk->flags & DSP_DOMAIN_CLOCK) {
+               __clk_use(&api_ck);
+       }
+
        if (clk->flags & ENABLE_REG_32BIT) {
                regval32 = omap_readl(clk->enable_reg);
                regval32 &= ~(1 << clk->enable_bit);
                regval16 &= ~(1 << clk->enable_bit);
                omap_writew(regval16, clk->enable_reg);
        }
+
+       if (clk->flags & DSP_DOMAIN_CLOCK) {
+               __clk_unuse(&api_ck);
+       }
 }
 
 
        return dsor_exp;
 }
 
+
+static void ckctl_recalc(struct clk *  clk)
+{
+       int dsor;
+
+       /* Calculate divisor encoded as 2-bit exponent */
+       if (clk->flags & DSP_DOMAIN_CLOCK) {
+               /* The clock control bits are in DSP domain,
+                * so api_ck is needed for access
+                */
+               __clk_use(&api_ck);
+               dsor = 1 << (3 & (omap_readw(DSP_CKCTL) >> clk->rate_offset));
+               __clk_unuse(&api_ck);
+       } else {
+               dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+       }
+       if (unlikely(clk->rate == clk->parent->rate / dsor))
+               return; /* No change, quick exit */
+       clk->rate = clk->parent->rate / dsor;
+
+       if (unlikely(clk->flags & RATE_PROPAGATES))
+               propagate_rate(clk);
+}
+
+
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
        int dsor_exp;
        if (!ptr->rate)
                return -EINVAL;
 
+       /*
+        * If ARM_TIM_CK is coming from CK_GEN1, reset it and set
+        * safe values for dividers in ARM_CKCTL.
+        * Otherwise system may hang when reprogramming DPLL_CTL.
+        */
        if (unlikely(ck_dpll1.rate == 0)) {
+               omap_writew(0x03ff, ARM_CKCTL);
                omap_writew(ptr->dpllctl_val, DPLL_CTL);
                ck_dpll1.rate = ptr->pll_rate;
        }
        return dsor;
 }
 
+/* Only needed on 1510 */
+static int set_uart_rate(struct clk * clk, unsigned long rate)
+{
+       unsigned int val;
+
+       val = omap_readl(clk->enable_reg);
+       if (rate == 12000000)
+               val &= ~(1 << clk->enable_bit);
+       else if (rate == 48000000)
+               val |= (1 << clk->enable_bit);
+       else
+               return -EINVAL;
+       omap_writel(val, clk->enable_reg);
+       clk->rate = rate;
+
+       return 0;
+}
 
 static int set_ext_clk_rate(struct clk *  clk, unsigned long rate)
 {
                ck_ref.rate = 19200000;
 #endif
 
+       printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+              omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+              omap_readw(ARM_CKCTL));
+
        /* We want to be in syncronous scalable mode */
        omap_writew(0x1000, ARM_SYSST);
 
+#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
+       /* Use values set by bootloader. Determine PLL rate and recalculate
+        * dependent clocks as if kernel had changed PLL or divisors.
+        */
+       {
+               unsigned pll_ctl_val = omap_readw(DPLL_CTL);
+
+               ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
+               if (pll_ctl_val & 0x10) {
+                       /* PLL enabled, apply multiplier and divisor */
+                       if (pll_ctl_val & 0xf80)
+                               ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
+                       ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
+               } else {
+                       /* PLL disabled, apply bypass divisor */
+                       switch (pll_ctl_val & 0xc) {
+                       case 0:
+                               break;
+                       case 0x4:
+                               ck_dpll1.rate /= 2;
+                               break;
+                       default:
+                               ck_dpll1.rate /= 4;
+                               break;
+                       }
+               }
+       }
+       propagate_rate(&ck_dpll1);
+#else
        /* Find the highest supported frequency and enable it */
        if (select_table_rate(&virtual_ck_mpu, ~0)) {
                printk(KERN_ERR "System frequencies not set. Check your config.\n");
                omap_writew(0x1005, ARM_CKCTL);
                ck_dpll1.rate = 60000000;
                propagate_rate(&ck_dpll1);
-               printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n",
-                      ck_ref.rate, ck_dpll1.rate, arm_ck.rate);
        }
-
+#endif
        /* Cache rates for clocks connected to ck_ref (not dpll1) */
        propagate_rate(&ck_ref);
+       printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
+              ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+              ck_dpll1.rate, arm_ck.rate);
 
 #ifdef CONFIG_MACH_OMAP_PERSEUS2
        /* Select slicer output as OMAP input clock */
 
        return 0;
 }
+
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+
+static int __init omap_clk_reset(void)
+{
+       /* Turn off all unused clocks */
+       struct clk *p;
+       __u32 regval32;
+
+       omap_writew(0, SOFT_REQ_REG);
+       omap_writew(0, SOFT_REQ_REG2);
+
+       list_for_each_entry(p, &clocks, node) {
+               if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
+                       p->enable_reg == 0)
+                       continue;
+
+               /* Assume no DSP clocks have been activated by bootloader */
+               if (p->flags & DSP_DOMAIN_CLOCK)
+                       continue;
+
+               /* Is the clock already disabled? */
+               if (p->flags & ENABLE_REG_32BIT)
+                       regval32 = omap_readl(p->enable_reg);
+               else
+                       regval32 = omap_readw(p->enable_reg);
+
+               if ((regval32 & (1 << p->enable_bit)) == 0)
+                       continue;
+
+               /* FIXME: This clock seems to be necessary but no-one
+                * has asked for its activation. */
+               if (p == &tc2_ck         // FIX: pm.c (SRAM), CCP, Camera
+                   || p == &ck_dpll1out // FIX: SoSSI, SSR
+                   || p == &arm_gpio_ck // FIX: GPIO code for 1510
+                   ) {
+                       printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+                              p->name);
+                       continue;
+               }
+
+               printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
+               __clk_disable(p);
+               printk(" done\n");
+       }
+
+       return 0;
+}
+
+late_initcall(omap_clk_reset);
+
+#endif