|
@@ -195,3 +195,148 @@ static struct clk pllc1_div2_clk = {
|
|
* USBCKCR is controlling usb24 clock
|
|
* USBCKCR is controlling usb24 clock
|
|
* bit[7] : parent clock
|
|
* bit[7] : parent clock
|
|
* bit[6] : clock divide rate
|
|
* bit[6] : clock divide rate
|
|
|
|
+ * And this bit[7] is used as a "usb24s" from other devices.
|
|
|
|
+ * (Video clock / Sub clock / SPU clock)
|
|
|
|
+ * You can controll this clock as a below.
|
|
|
|
+ *
|
|
|
|
+ * struct clk *usb24 = clk_get(dev, "usb24");
|
|
|
|
+ * struct clk *usb24s = clk_get(NULL, "usb24s");
|
|
|
|
+ * struct clk *system = clk_get(NULL, "system_clk");
|
|
|
|
+ * int rate = clk_get_rate(system);
|
|
|
|
+ *
|
|
|
|
+ * clk_set_parent(usb24s, system); // for bit[7]
|
|
|
|
+ * clk_set_rate(usb24, rate / 2); // for bit[6]
|
|
|
|
+ */
|
|
|
|
+static struct clk *usb24s_parents[] = {
|
|
|
|
+ [0] = &system_clk,
|
|
|
|
+ [1] = &extal2_clk
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int usb24s_enable(struct clk *clk)
|
|
|
|
+{
|
|
|
|
+ __raw_writel(__raw_readl(USBCKCR) & ~(1 << 8), USBCKCR);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void usb24s_disable(struct clk *clk)
|
|
|
|
+{
|
|
|
|
+ __raw_writel(__raw_readl(USBCKCR) | (1 << 8), USBCKCR);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int usb24s_set_parent(struct clk *clk, struct clk *parent)
|
|
|
|
+{
|
|
|
|
+ int i, ret;
|
|
|
|
+ u32 val;
|
|
|
|
+
|
|
|
|
+ if (!clk->parent_table || !clk->parent_num)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ /* Search the parent */
|
|
|
|
+ for (i = 0; i < clk->parent_num; i++)
|
|
|
|
+ if (clk->parent_table[i] == parent)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ if (i == clk->parent_num)
|
|
|
|
+ return -ENODEV;
|
|
|
|
+
|
|
|
|
+ ret = clk_reparent(clk, parent);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ val = __raw_readl(USBCKCR);
|
|
|
|
+ val &= ~(1 << 7);
|
|
|
|
+ val |= i << 7;
|
|
|
|
+ __raw_writel(val, USBCKCR);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct sh_clk_ops usb24s_clk_ops = {
|
|
|
|
+ .recalc = followparent_recalc,
|
|
|
|
+ .enable = usb24s_enable,
|
|
|
|
+ .disable = usb24s_disable,
|
|
|
|
+ .set_parent = usb24s_set_parent,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct clk usb24s_clk = {
|
|
|
|
+ .ops = &usb24s_clk_ops,
|
|
|
|
+ .parent_table = usb24s_parents,
|
|
|
|
+ .parent_num = ARRAY_SIZE(usb24s_parents),
|
|
|
|
+ .parent = &system_clk,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static unsigned long usb24_recalc(struct clk *clk)
|
|
|
|
+{
|
|
|
|
+ return clk->parent->rate /
|
|
|
|
+ ((__raw_readl(USBCKCR) & (1 << 6)) ? 1 : 2);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int usb24_set_rate(struct clk *clk, unsigned long rate)
|
|
|
|
+{
|
|
|
|
+ u32 val;
|
|
|
|
+
|
|
|
|
+ /* closer to which ? parent->rate or parent->rate/2 */
|
|
|
|
+ val = __raw_readl(USBCKCR);
|
|
|
|
+ val &= ~(1 << 6);
|
|
|
|
+ val |= (rate > (clk->parent->rate / 4) * 3) << 6;
|
|
|
|
+ __raw_writel(val, USBCKCR);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct sh_clk_ops usb24_clk_ops = {
|
|
|
|
+ .recalc = usb24_recalc,
|
|
|
|
+ .set_rate = usb24_set_rate,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct clk usb24_clk = {
|
|
|
|
+ .ops = &usb24_clk_ops,
|
|
|
|
+ .parent = &usb24s_clk,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* External FSIACK/FSIBCK clock */
|
|
|
|
+static struct clk fsiack_clk = {
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct clk fsibck_clk = {
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct clk *main_clks[] = {
|
|
|
|
+ &extalr_clk,
|
|
|
|
+ &extal1_clk,
|
|
|
|
+ &extal2_clk,
|
|
|
|
+ &extal1_div2_clk,
|
|
|
|
+ &extal1_div1024_clk,
|
|
|
|
+ &extal1_div2048_clk,
|
|
|
|
+ &extal2_div2_clk,
|
|
|
|
+ &dv_clk,
|
|
|
|
+ &system_clk,
|
|
|
|
+ &system_div2_clk,
|
|
|
|
+ &r_clk,
|
|
|
|
+ &pllc0_clk,
|
|
|
|
+ &pllc1_clk,
|
|
|
|
+ &pllc1_div2_clk,
|
|
|
|
+ &usb24s_clk,
|
|
|
|
+ &usb24_clk,
|
|
|
|
+ &fsiack_clk,
|
|
|
|
+ &fsibck_clk,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void div4_kick(struct clk *clk)
|
|
|
|
+{
|
|
|
|
+ unsigned long value;
|
|
|
|
+
|
|
|
|
+ /* set KICK bit in FRQCRB to update hardware setting */
|
|
|
|
+ value = __raw_readl(FRQCRB);
|
|
|
|
+ value |= (1 << 31);
|
|
|
|
+ __raw_writel(value, FRQCRB);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
|
|
|
|
+ 24, 32, 36, 48, 0, 72, 96, 0 };
|
|
|
|
+
|
|
|
|
+static struct clk_div_mult_table div4_div_mult_table = {
|
|
|
|
+ .divisors = divisors,
|
|
|
|
+ .nr_divisors = ARRAY_SIZE(divisors),
|
|
|
|
+};
|