ARM: tegra: clock: Drop set_rate on audio clocks
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-tegra / tegra2_clocks.c
index c638d672e3eca11dc627f93556e60ce1d49b5e7a..7f5ed03fa958fff4c12cde04681ac7e9d1793d4b 100644 (file)
 #define PLLD_MISC_DIV_RST              (1<<23)
 #define PLLD_MISC_DCCON_SHIFT          12
 
-#define PERIPH_CLK_TO_ENB_REG(c)       ((c->clk_num / 32) * 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c)   ((c->clk_num / 32) * 8)
-#define PERIPH_CLK_TO_ENB_BIT(c)       (1 << (c->clk_num % 32))
+#define PERIPH_CLK_TO_ENB_REG(c)       ((c->u.periph.clk_num / 32) * 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c)   ((c->u.periph.clk_num / 32) * 8)
+#define PERIPH_CLK_TO_ENB_BIT(c)       (1 << (c->u.periph.clk_num % 32))
 
 #define SUPER_CLK_MUX                  0x00
 #define SUPER_STATE_SHIFT              28
 static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
 static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
 
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
+ */
+static int tegra_periph_clk_enable_refcount[3 * 32];
+
 #define clk_writel(value, reg) \
        __raw_writel(value, (u32)reg_clk_base + (reg))
 #define clk_readl(reg) \
@@ -296,6 +302,8 @@ static void tegra2_super_clk_init(struct clk *c)
        }
        BUG_ON(sel->input == NULL);
        c->parent = sel->input;
+
+       INIT_LIST_HEAD(&c->u.shared_bus.list);
 }
 
 static int tegra2_super_clk_enable(struct clk *c)
@@ -381,31 +389,31 @@ static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
         * Take an extra reference to the main pll so it doesn't turn
         * off when we move the cpu off of it
         */
-       clk_enable_locked(c->main);
+       clk_enable_locked(c->u.cpu.main);
 
-       ret = clk_set_parent_locked(c->parent, c->backup);
+       ret = clk_set_parent_locked(c->parent, c->u.cpu.backup);
        if (ret) {
-               pr_err("Failed to switch cpu to clock %s\n", c->backup->name);
+               pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name);
                goto out;
        }
 
-       if (rate == c->backup->rate)
+       if (rate == c->u.cpu.backup->rate)
                goto out;
 
-       ret = clk_set_rate_locked(c->main, rate);
+       ret = clk_set_rate_locked(c->u.cpu.main, rate);
        if (ret) {
                pr_err("Failed to change cpu pll to %lu\n", rate);
                goto out;
        }
 
-       ret = clk_set_parent_locked(c->parent, c->main);
+       ret = clk_set_parent_locked(c->parent, c->u.cpu.main);
        if (ret) {
-               pr_err("Failed to switch cpu to clock %s\n", c->main->name);
+               pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name);
                goto out;
        }
 
 out:
-       clk_disable_locked(c->main);
+       clk_disable_locked(c->u.cpu.main);
        return ret;
 }
 
@@ -418,16 +426,6 @@ static struct clk_ops tegra_cpu_ops = {
 
 /* virtual cop clock functions. Used to acquire the fake 'cop' clock to
  * reset the COP block (i.e. AVP) */
-static void tegra2_cop_clk_init(struct clk *c)
-{
-       c->state = c->parent->state;
-}
-
-static int tegra2_cop_clk_enable(struct clk *c)
-{
-       return 0;
-}
-
 static void tegra2_cop_clk_reset(struct clk *c, bool assert)
 {
        unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
@@ -437,8 +435,6 @@ static void tegra2_cop_clk_reset(struct clk *c, bool assert)
 }
 
 static struct clk_ops tegra_cop_ops = {
-       .init     = tegra2_cop_clk_init,
-       .enable   = tegra2_cop_clk_enable,
        .reset    = tegra2_cop_clk_reset,
 };
 
@@ -575,7 +571,7 @@ static struct clk_ops tegra_blink_clk_ops = {
 /* PLL Functions */
 static int tegra2_pll_clk_wait_for_lock(struct clk *c)
 {
-       udelay(c->pll_lock_delay);
+       udelay(c->u.pll.lock_delay);
 
        return 0;
 }
@@ -632,12 +628,12 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
 {
        u32 val;
        unsigned long input_rate;
-       const struct clk_pll_table *sel;
+       const struct clk_pll_freq_table *sel;
 
        pr_debug("%s: %s %lu\n", __func__, c->name, rate);
 
        input_rate = c->parent->rate;
-       for (sel = c->pll_table; sel->input_rate != 0; sel++) {
+       for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
                if (sel->input_rate == input_rate && sel->output_rate == rate) {
                        c->mul = sel->n;
                        c->div = sel->m * sel->p;
@@ -873,6 +869,10 @@ static int tegra2_periph_clk_enable(struct clk *c)
        u32 val;
        pr_debug("%s on clock %s\n", __func__, c->name);
 
+       tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+       if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+               return 0;
+
        clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
                CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
        if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
@@ -892,8 +892,12 @@ static void tegra2_periph_clk_disable(struct clk *c)
 {
        pr_debug("%s on clock %s\n", __func__, c->name);
 
-       clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
-               CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+       if (c->refcnt)
+               tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+       if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0)
+               clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+                       CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
 }
 
 static void tegra2_periph_clk_reset(struct clk *c, bool assert)
@@ -1079,30 +1083,10 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
        return -EINVAL;
 }
 
-static int tegra2_audio_sync_clk_set_rate(struct clk *c, unsigned long rate)
-{
-       unsigned long parent_rate;
-       if (!c->parent) {
-               pr_err("%s: clock has no parent\n", __func__);
-               return -EINVAL;
-       }
-       parent_rate = c->parent->rate;
-       if (rate != parent_rate) {
-               pr_err("%s: %s/%ld differs from parent %s/%ld\n",
-                       __func__,
-                       c->name, rate,
-                       c->parent->name, parent_rate);
-               return -EINVAL;
-       }
-       c->rate = parent_rate;
-       return 0;
-}
-
 static struct clk_ops tegra_audio_sync_clk_ops = {
        .init       = tegra2_audio_sync_clk_init,
        .enable     = tegra2_audio_sync_clk_enable,
        .disable    = tegra2_audio_sync_clk_disable,
-       .set_rate   = tegra2_audio_sync_clk_set_rate,
        .set_parent = tegra2_audio_sync_clk_set_parent,
 };
 
@@ -1137,6 +1121,66 @@ static struct clk_ops tegra_cdev_clk_ops = {
        .disable                = &tegra2_cdev_clk_disable,
 };
 
+/* shared bus ops */
+/*
+ * Some clocks may have multiple downstream users that need to request a
+ * higher clock rate.  Shared bus clocks provide a unique shared_bus_user
+ * clock to each user.  The frequency of the bus is set to the highest
+ * enabled shared_bus_user clock, with a minimum value set by the
+ * shared bus.
+ */
+static void tegra_clk_shared_bus_update(struct clk *bus)
+{
+       struct clk *c;
+       unsigned long rate = bus->u.shared_bus.min_rate;
+
+       list_for_each_entry(c, &bus->u.shared_bus.list, u.shared_bus_user.node)
+               if (c->u.shared_bus_user.enabled)
+                       rate = max(c->u.shared_bus_user.rate, rate);
+
+       if (rate != bus->rate)
+               clk_set_rate_locked(bus, rate);
+};
+
+static void tegra_clk_shared_bus_init(struct clk *c)
+{
+       c->max_rate = c->parent->max_rate;
+       c->u.shared_bus_user.rate = c->parent->max_rate;
+       c->state = OFF;
+       c->set = true;
+
+       list_add_tail(&c->u.shared_bus_user.node,
+               &c->parent->u.shared_bus.list);
+}
+
+static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
+{
+       c->u.shared_bus_user.rate = rate;
+       tegra_clk_shared_bus_update(c->parent);
+       return 0;
+}
+
+static int tegra_clk_shared_bus_enable(struct clk *c)
+{
+       c->u.shared_bus_user.enabled = true;
+       tegra_clk_shared_bus_update(c->parent);
+       return 0;
+}
+
+static void tegra_clk_shared_bus_disable(struct clk *c)
+{
+       c->u.shared_bus_user.enabled = false;
+       tegra_clk_shared_bus_update(c->parent);
+}
+
+static struct clk_ops tegra_clk_shared_bus_ops = {
+       .init = tegra_clk_shared_bus_init,
+       .enable = tegra_clk_shared_bus_enable,
+       .disable = tegra_clk_shared_bus_disable,
+       .set_rate = tegra_clk_shared_bus_set_rate,
+};
+
+
 /* Clock definitions */
 static struct clk tegra_clk_32k = {
        .name = "clk_32k",
@@ -1145,7 +1189,7 @@ static struct clk tegra_clk_32k = {
        .max_rate = 32768,
 };
 
-static struct clk_pll_table tegra_pll_s_table[] = {
+static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
        {32768, 12000000, 366, 1, 1, 0},
        {32768, 13000000, 397, 1, 1, 0},
        {32768, 19200000, 586, 1, 1, 0},
@@ -1157,17 +1201,19 @@ static struct clk tegra_pll_s = {
        .name      = "pll_s",
        .flags     = PLL_ALT_MISC_REG,
        .ops       = &tegra_pll_ops,
-       .reg       = 0xf0,
-       .input_min = 32768,
-       .input_max = 32768,
        .parent    = &tegra_clk_32k,
-       .cf_min    = 0, /* FIXME */
-       .cf_max    = 0, /* FIXME */
-       .vco_min   = 12000000,
-       .vco_max   = 26000000,
-       .pll_table = tegra_pll_s_table,
        .max_rate  = 26000000,
-       .pll_lock_delay = 300,
+       .reg       = 0xf0,
+       .u.pll = {
+               .input_min = 32768,
+               .input_max = 32768,
+               .cf_min    = 0, /* FIXME */
+               .cf_max    = 0, /* FIXME */
+               .vco_min   = 12000000,
+               .vco_max   = 26000000,
+               .freq_table = tegra_pll_s_freq_table,
+               .lock_delay = 300,
+       },
 };
 
 static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -1175,18 +1221,18 @@ static struct clk_mux_sel tegra_clk_m_sel[] = {
        { .input = &tegra_pll_s,  .value = 1},
        { 0, 0},
 };
+
 static struct clk tegra_clk_m = {
        .name      = "clk_m",
        .flags     = ENABLE_ON_INIT,
        .ops       = &tegra_clk_m_ops,
        .inputs    = tegra_clk_m_sel,
        .reg       = 0x1fc,
-       .reg_mask  = (1<<28),
        .reg_shift = 28,
        .max_rate  = 26000000,
 };
 
-static struct clk_pll_table tegra_pll_c_table[] = {
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
        { 0, 0, 0, 0, 0, 0 },
 };
 
@@ -1195,16 +1241,18 @@ static struct clk tegra_pll_c = {
        .flags     = PLL_HAS_CPCON,
        .ops       = &tegra_pll_ops,
        .reg       = 0x80,
-       .input_min = 2000000,
-       .input_max = 31000000,
        .parent    = &tegra_clk_m,
-       .cf_min    = 1000000,
-       .cf_max    = 6000000,
-       .vco_min   = 20000000,
-       .vco_max   = 1400000000,
-       .pll_table = tegra_pll_c_table,
        .max_rate  = 600000000,
-       .pll_lock_delay = 300,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1400000000,
+               .freq_table = tegra_pll_c_freq_table,
+               .lock_delay = 300,
+       },
 };
 
 static struct clk tegra_pll_c_out1 = {
@@ -1217,7 +1265,7 @@ static struct clk tegra_pll_c_out1 = {
        .max_rate  = 600000000,
 };
 
-static struct clk_pll_table tegra_pll_m_table[] = {
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
        { 12000000, 666000000, 666, 12, 1, 8},
        { 13000000, 666000000, 666, 13, 1, 8},
        { 19200000, 666000000, 555, 16, 1, 8},
@@ -1234,16 +1282,18 @@ static struct clk tegra_pll_m = {
        .flags     = PLL_HAS_CPCON,
        .ops       = &tegra_pll_ops,
        .reg       = 0x90,
-       .input_min = 2000000,
-       .input_max = 31000000,
        .parent    = &tegra_clk_m,
-       .cf_min    = 1000000,
-       .cf_max    = 6000000,
-       .vco_min   = 20000000,
-       .vco_max   = 1200000000,
-       .pll_table = tegra_pll_m_table,
        .max_rate  = 800000000,
-       .pll_lock_delay = 300,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1200000000,
+               .freq_table = tegra_pll_m_freq_table,
+               .lock_delay = 300,
+       },
 };
 
 static struct clk tegra_pll_m_out1 = {
@@ -1256,7 +1306,7 @@ static struct clk tegra_pll_m_out1 = {
        .max_rate  = 600000000,
 };
 
-static struct clk_pll_table tegra_pll_p_table[] = {
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
        { 12000000, 216000000, 432, 12, 2, 8},
        { 13000000, 216000000, 432, 13, 2, 8},
        { 19200000, 216000000, 90,   4, 2, 1},
@@ -1273,16 +1323,18 @@ static struct clk tegra_pll_p = {
        .flags     = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
        .ops       = &tegra_pll_ops,
        .reg       = 0xa0,
-       .input_min = 2000000,
-       .input_max = 31000000,
        .parent    = &tegra_clk_m,
-       .cf_min    = 1000000,
-       .cf_max    = 6000000,
-       .vco_min   = 20000000,
-       .vco_max   = 1400000000,
-       .pll_table = tegra_pll_p_table,
        .max_rate  = 432000000,
-       .pll_lock_delay = 300,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1400000000,
+               .freq_table = tegra_pll_p_freq_table,
+               .lock_delay = 300,
+       },
 };
 
 static struct clk tegra_pll_p_out1 = {
@@ -1325,7 +1377,7 @@ static struct clk tegra_pll_p_out4 = {
        .max_rate  = 432000000,
 };
 
-static struct clk_pll_table tegra_pll_a_table[] = {
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
        { 28800000, 56448000, 49, 25, 1, 1},
        { 28800000, 73728000, 64, 25, 1, 1},
        { 28800000, 11289600, 49, 25, 1, 1},
@@ -1339,16 +1391,18 @@ static struct clk tegra_pll_a = {
        .flags     = PLL_HAS_CPCON,
        .ops       = &tegra_pll_ops,
        .reg       = 0xb0,
-       .input_min = 2000000,
-       .input_max = 31000000,
        .parent    = &tegra_pll_p_out1,
-       .cf_min    = 1000000,
-       .cf_max    = 6000000,
-       .vco_min   = 20000000,
-       .vco_max   = 1400000000,
-       .pll_table = tegra_pll_a_table,
        .max_rate  = 56448000,
-       .pll_lock_delay = 300,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1400000000,
+               .freq_table = tegra_pll_a_freq_table,
+               .lock_delay = 300,
+       },
 };
 
 static struct clk tegra_pll_a_out0 = {
@@ -1361,7 +1415,7 @@ static struct clk tegra_pll_a_out0 = {
        .max_rate  = 56448000,
 };
 
-static struct clk_pll_table tegra_pll_d_table[] = {
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
        { 12000000, 216000000, 216, 12, 1, 4},
        { 13000000, 216000000, 216, 13, 1, 4},
        { 19200000, 216000000, 135, 12, 1, 3},
@@ -1385,16 +1439,18 @@ static struct clk tegra_pll_d = {
        .flags     = PLL_HAS_CPCON | PLLD,
        .ops       = &tegra_pll_ops,
        .reg       = 0xd0,
-       .input_min = 2000000,
-       .input_max = 40000000,
        .parent    = &tegra_clk_m,
-       .cf_min    = 1000000,
-       .cf_max    = 6000000,
-       .vco_min   = 40000000,
-       .vco_max   = 1000000000,
-       .pll_table = tegra_pll_d_table,
        .max_rate  = 1000000000,
-       .pll_lock_delay = 1000,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 40000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 40000000,
+               .vco_max   = 1000000000,
+               .freq_table = tegra_pll_d_freq_table,
+               .lock_delay = 1000,
+       },
 };
 
 static struct clk tegra_pll_d_out0 = {
@@ -1405,7 +1461,7 @@ static struct clk tegra_pll_d_out0 = {
        .max_rate  = 500000000,
 };
 
-static struct clk_pll_table tegra_pll_u_table[] = {
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
        { 12000000, 480000000, 960, 12, 2, 0},
        { 13000000, 480000000, 960, 13, 2, 0},
        { 19200000, 480000000, 200, 4,  2, 0},
@@ -1418,19 +1474,21 @@ static struct clk tegra_pll_u = {
        .flags     = PLLU,
        .ops       = &tegra_pll_ops,
        .reg       = 0xc0,
-       .input_min = 2000000,
-       .input_max = 40000000,
        .parent    = &tegra_clk_m,
-       .cf_min    = 1000000,
-       .cf_max    = 6000000,
-       .vco_min   = 480000000,
-       .vco_max   = 960000000,
-       .pll_table = tegra_pll_u_table,
        .max_rate  = 480000000,
-       .pll_lock_delay = 1000,
-};
-
-static struct clk_pll_table tegra_pll_x_table[] = {
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 40000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 480000000,
+               .vco_max   = 960000000,
+               .freq_table = tegra_pll_u_freq_table,
+               .lock_delay = 1000,
+       },
+};
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
        /* 1 GHz */
        { 12000000, 1000000000, 1000, 12, 1, 12},
        { 13000000, 1000000000, 1000, 13, 1, 12},
@@ -1481,45 +1539,53 @@ static struct clk tegra_pll_x = {
        .flags     = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
        .ops       = &tegra_pllx_ops,
        .reg       = 0xe0,
-       .input_min = 2000000,
-       .input_max = 31000000,
        .parent    = &tegra_clk_m,
-       .cf_min    = 1000000,
-       .cf_max    = 6000000,
-       .vco_min   = 20000000,
-       .vco_max   = 1200000000,
-       .pll_table = tegra_pll_x_table,
        .max_rate  = 1000000000,
-       .pll_lock_delay = 300,
+       .u.pll = {
+               .input_min = 2000000,
+               .input_max = 31000000,
+               .cf_min    = 1000000,
+               .cf_max    = 6000000,
+               .vco_min   = 20000000,
+               .vco_max   = 1200000000,
+               .freq_table = tegra_pll_x_freq_table,
+               .lock_delay = 300,
+       },
 };
 
 static struct clk tegra_clk_d = {
        .name      = "clk_d",
        .flags     = PERIPH_NO_RESET,
        .ops       = &tegra_clk_double_ops,
-       .clk_num   = 90,
        .reg       = 0x34,
        .reg_shift = 12,
        .parent    = &tegra_clk_m,
        .max_rate  = 52000000,
+       .u.periph  = {
+               .clk_num = 90,
+       },
 };
 
 /* dap_mclk1, belongs to the cdev1 pingroup. */
 static struct clk tegra_dev1_clk = {
        .name      = "clk_dev1",
        .ops       = &tegra_cdev_clk_ops,
-       .clk_num   = 94,
        .rate      = 26000000,
        .max_rate  = 26000000,
+       .u.periph  = {
+               .clk_num = 94,
+       },
 };
 
 /* dap_mclk2, belongs to the cdev2 pingroup. */
 static struct clk tegra_dev2_clk = {
        .name      = "clk_dev2",
        .ops       = &tegra_cdev_clk_ops,
-       .clk_num   = 93,
        .rate      = 26000000,
        .max_rate  = 26000000,
+       .u.periph  = {
+               .clk_num   = 93,
+       },
 };
 
 /* initialized before peripheral clocks */
@@ -1554,10 +1620,12 @@ static struct clk tegra_clk_audio_2x = {
        .flags     = PERIPH_NO_RESET,
        .max_rate  = 48000000,
        .ops       = &tegra_clk_double_ops,
-       .clk_num   = 89,
        .reg       = 0x34,
        .reg_shift = 8,
        .parent    = &tegra_clk_audio,
+       .u.periph = {
+               .clk_num = 89,
+       },
 };
 
 struct clk_lookup tegra_audio_clk_lookups[] = {
@@ -1630,15 +1698,20 @@ static struct clk tegra_clk_sclk = {
        .reg    = 0x28,
        .ops    = &tegra_super_ops,
        .max_rate = 240000000,
+       .u.shared_bus = {
+               .min_rate = 120000000,
+       },
 };
 
 static struct clk tegra_clk_virtual_cpu = {
        .name      = "cpu",
        .parent    = &tegra_clk_cclk,
-       .main      = &tegra_pll_x,
-       .backup    = &tegra_pll_p,
        .ops       = &tegra_cpu_ops,
        .max_rate  = 1000000000,
+       .u.cpu = {
+               .main      = &tegra_pll_x,
+               .backup    = &tegra_pll_p,
+       },
 };
 
 static struct clk tegra_clk_cop = {
@@ -1760,11 +1833,24 @@ static struct clk_mux_sel mux_clk_32k[] = {
                        .con_id    = _con,              \
                },                                      \
                .ops       = &tegra_periph_clk_ops,     \
-               .clk_num   = _clk_num,                  \
                .reg       = _reg,                      \
                .inputs    = _inputs,                   \
                .flags     = _flags,                    \
                .max_rate  = _max,                      \
+               .u.periph = {                           \
+                       .clk_num   = _clk_num,          \
+               },                                      \
+       }
+
+#define SHARED_CLK(_name, _dev, _con, _parent)         \
+       {                                               \
+               .name      = _name,                     \
+               .lookup    = {                          \
+                       .dev_id    = _dev,              \
+                       .con_id    = _con,              \
+               },                                      \
+               .ops       = &tegra_clk_shared_bus_ops, \
+               .parent = _parent,                      \
        }
 
 struct clk tegra_list_clks[] = {
@@ -1772,7 +1858,6 @@ struct clk tegra_list_clks[] = {
        PERIPH_CLK("timer",     "timer",                NULL,   5,      0,      26000000,  mux_clk_m,                   0),
        PERIPH_CLK("i2s1",      "i2s.0",                NULL,   11,     0x100,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
        PERIPH_CLK("i2s2",      "i2s.1",                NULL,   18,     0x104,  26000000,  mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
-       /* FIXME: spdif has 2 clocks but 1 enable */
        PERIPH_CLK("spdif_out", "spdif_out",            NULL,   10,     0x108,  100000000, mux_pllaout0_audio2x_pllp_clkm,      MUX | DIV_U71),
        PERIPH_CLK("spdif_in",  "spdif_in",             NULL,   10,     0x10c,  100000000, mux_pllp_pllc_pllm,          MUX | DIV_U71),
        PERIPH_CLK("pwm",       "pwm",                  NULL,   17,     0x110,  432000000, mux_pllp_pllc_audio_clkm_clk32,      MUX | DIV_U71),
@@ -1785,7 +1870,6 @@ struct clk tegra_list_clks[] = {
        PERIPH_CLK("sbc4",      "spi_tegra.3",          NULL,   68,     0x1b4,  160000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
        PERIPH_CLK("ide",       "ide",                  NULL,   25,     0x144,  100000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* requires min voltage */
        PERIPH_CLK("ndflash",   "tegra_nand",           NULL,   13,     0x160,  164000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
-       /* FIXME: vfir shares an enable with uartb */
        PERIPH_CLK("vfir",      "vfir",                 NULL,   7,      0x168,  72000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71),
        PERIPH_CLK("sdmmc1",    "sdhci-tegra.0",        NULL,   14,     0x150,  52000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
        PERIPH_CLK("sdmmc2",    "sdhci-tegra.1",        NULL,   9,      0x154,  52000000,  mux_pllp_pllc_pllm_clkm,     MUX | DIV_U71), /* scales with voltage */
@@ -1815,13 +1899,11 @@ struct clk tegra_list_clks[] = {
        PERIPH_CLK("uarte",     "uart.4",               NULL,   66,     0x1c4,  600000000, mux_pllp_pllc_pllm_clkm,     MUX),
        PERIPH_CLK("3d",        "3d",                   NULL,   24,     0x158,  300000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
        PERIPH_CLK("2d",        "2d",                   NULL,   21,     0x15c,  300000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
-       /* FIXME: vi and vi_sensor share an enable */
        PERIPH_CLK("vi",        "tegra_camera",         "vi",   20,     0x148,  150000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
        PERIPH_CLK("vi_sensor", "tegra_camera",         "vi_sensor",    20,     0x1a8,  150000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
        PERIPH_CLK("epp",       "epp",                  NULL,   19,     0x16c,  300000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
        PERIPH_CLK("mpe",       "mpe",                  NULL,   60,     0x170,  250000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
        PERIPH_CLK("host1x",    "host1x",               NULL,   28,     0x180,  166000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71), /* scales with voltage and process_id */
-       /* FIXME: cve and tvo share an enable   */
        PERIPH_CLK("cve",       "cve",                  NULL,   49,     0x140,  250000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
        PERIPH_CLK("tvo",       "tvo",                  NULL,   49,     0x188,  250000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
        PERIPH_CLK("hdmi",      "hdmi",                 NULL,   51,     0x18c,  600000000, mux_pllp_plld_pllc_clkm,     MUX | DIV_U71), /* requires min voltage */
@@ -1836,6 +1918,8 @@ struct clk tegra_list_clks[] = {
        PERIPH_CLK("csi",       "tegra_camera",         "csi",  52,     0,      72000000,  mux_pllp_out3,               0),
        PERIPH_CLK("isp",       "tegra_camera",         "isp",  23,     0,      150000000, mux_clk_m,                   0), /* same frequency as VI */
        PERIPH_CLK("csus",      "tegra_camera",         "csus", 92,     0,      150000000, mux_clk_m,                   PERIPH_NO_RESET),
+
+       SHARED_CLK("avp.sclk",  "tegra-avp",            "sclk", &tegra_clk_sclk),
 };
 
 #define CLK_DUPLICATE(_name, _dev, _con)               \
@@ -1949,7 +2033,7 @@ void __init tegra2_init_clocks(void)
 
 #ifdef CONFIG_PM
 static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
-                          PERIPH_CLK_SOURCE_NUM + 19];
+                          PERIPH_CLK_SOURCE_NUM + 15];
 
 void tegra_clk_suspend(void)
 {
@@ -1957,16 +2041,12 @@ void tegra_clk_suspend(void)
        u32 *ctx = clk_rst_suspend;
 
        *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
-       *ctx++ = clk_readl(tegra_pll_p.reg + PLL_BASE);
-       *ctx++ = clk_readl(tegra_pll_p.reg + PLL_MISC(&tegra_pll_p));
        *ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
        *ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
        *ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
        *ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
 
        *ctx++ = clk_readl(tegra_pll_m_out1.reg);
-       *ctx++ = clk_readl(tegra_pll_p_out1.reg);
-       *ctx++ = clk_readl(tegra_pll_p_out3.reg);
        *ctx++ = clk_readl(tegra_pll_a_out0.reg);
        *ctx++ = clk_readl(tegra_pll_c_out1.reg);
 
@@ -2006,8 +2086,6 @@ void tegra_clk_resume(void)
        val |= *ctx++;
        clk_writel(val, OSC_CTRL);
 
-       clk_writel(*ctx++, tegra_pll_p.reg + PLL_BASE);
-       clk_writel(*ctx++, tegra_pll_p.reg + PLL_MISC(&tegra_pll_p));
        clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
        clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
        clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
@@ -2015,8 +2093,6 @@ void tegra_clk_resume(void)
        udelay(300);
 
        clk_writel(*ctx++, tegra_pll_m_out1.reg);
-       clk_writel(*ctx++, tegra_pll_p_out1.reg);
-       clk_writel(*ctx++, tegra_pll_p_out3.reg);
        clk_writel(*ctx++, tegra_pll_a_out0.reg);
        clk_writel(*ctx++, tegra_pll_c_out1.reg);