Преглед изворни кода

waterHeterogeneousDataSynchronization commandProcessing.c 李欣儒 commit at 2020-09-16

李欣儒 пре 4 година
родитељ
комит
bcd9d086cf

+ 133 - 0
waterHeterogeneousDataSynchronization/externalConnectionMonitoring/commandProcessing.c

@@ -121,3 +121,136 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
 
 	rate = clk->parent->get_rate(clk->parent);
 	rate = (rate + div / 2) / div;
+	rate *= mul;
+
+	return rate;
+}
+
+static long pll_set_rate(struct clk *clk, unsigned long rate,
+			 u32 *pll_ctrl)
+{
+	unsigned long mul;
+	unsigned long mul_best_fit = 0;
+	unsigned long div;
+	unsigned long div_min;
+	unsigned long div_max;
+	unsigned long div_best_fit = 0;
+	unsigned long base;
+	unsigned long pll_in;
+	unsigned long actual = 0;
+	unsigned long rate_error;
+	unsigned long rate_error_prev = ~0UL;
+	u32 ctrl;
+
+	/* Rate must be between 80 MHz and 200 Mhz. */
+	if (rate < 80000000UL || rate > 200000000UL)
+		return -EINVAL;
+
+	ctrl = PM_BF(PLLOPT, 4);
+	base = clk->parent->get_rate(clk->parent);
+
+	/* PLL input frequency must be between 6 MHz and 32 MHz. */
+	div_min = DIV_ROUND_UP(base, 32000000UL);
+	div_max = base / 6000000UL;
+
+	if (div_max < div_min)
+		return -EINVAL;
+
+	for (div = div_min; div <= div_max; div++) {
+		pll_in = (base + div / 2) / div;
+		mul = (rate + pll_in / 2) / pll_in;
+
+		if (mul == 0)
+			continue;
+
+		actual = pll_in * mul;
+		rate_error = abs(actual - rate);
+
+		if (rate_error < rate_error_prev) {
+			mul_best_fit = mul;
+			div_best_fit = div;
+			rate_error_prev = rate_error;
+		}
+
+		if (rate_error == 0)
+			break;
+	}
+
+	if (div_best_fit == 0)
+		return -EINVAL;
+
+	ctrl |= PM_BF(PLLMUL, mul_best_fit - 1);
+	ctrl |= PM_BF(PLLDIV, div_best_fit - 1);
+	ctrl |= PM_BF(PLLCOUNT, 16);
+
+	if (clk->parent == &osc1)
+		ctrl |= PM_BIT(PLLOSC);
+
+	*pll_ctrl = ctrl;
+
+	return actual;
+}
+
+static unsigned long pll0_get_rate(struct clk *clk)
+{
+	u32 control;
+
+	control = pm_readl(PLL0);
+
+	return pll_get_rate(clk, control);
+}
+
+static void pll1_mode(struct clk *clk, int enabled)
+{
+	unsigned long timeout;
+	u32 status;
+	u32 ctrl;
+
+	ctrl = pm_readl(PLL1);
+
+	if (enabled) {
+		if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) {
+			pr_debug("clk %s: failed to enable, rate not set\n",
+					clk->name);
+			return;
+		}
+
+		ctrl |= PM_BIT(PLLEN);
+		pm_writel(PLL1, ctrl);
+
+		/* Wait for PLL lock. */
+		for (timeout = 10000; timeout; timeout--) {
+			status = pm_readl(ISR);
+			if (status & PM_BIT(LOCK1))
+				break;
+			udelay(10);
+		}
+
+		if (!(status & PM_BIT(LOCK1)))
+			printk(KERN_ERR "clk %s: timeout waiting for lock\n",
+					clk->name);
+	} else {
+		ctrl &= ~PM_BIT(PLLEN);
+		pm_writel(PLL1, ctrl);
+	}
+}
+
+static unsigned long pll1_get_rate(struct clk *clk)
+{
+	u32 control;
+
+	control = pm_readl(PLL1);
+
+	return pll_get_rate(clk, control);
+}
+
+static long pll1_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+	u32 ctrl = 0;
+	unsigned long actual_rate;
+
+	actual_rate = pll_set_rate(clk, rate, &ctrl);
+
+	if (apply) {
+		if (actual_rate != rate)
+			return -EINVAL;