static void qcom_geni_serial_stop_rx(struct uart_port *uport);
static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop);
-static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200,
- 32000000, 48000000, 51200000, 64000000,
- 80000000, 96000000, 100000000,
- 102400000, 112000000, 120000000,
- 128000000};
-
#define to_dev_port(ptr, member) \
container_of(ptr, struct qcom_geni_serial_port, member)
return 0;
}
-static unsigned long get_clk_cfg(unsigned long clk_freq)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(root_freq); i++) {
- if (!(root_freq[i] % clk_freq))
- return root_freq[i];
- }
- return 0;
-}
-
-static unsigned long get_clk_div_rate(unsigned int baud,
+static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud,
unsigned int sampling_rate, unsigned int *clk_div)
{
unsigned long ser_clk;
unsigned long desired_clk;
+ unsigned long freq, prev;
+ unsigned long div, maxdiv;
+ int64_t mult;
desired_clk = baud * sampling_rate;
- ser_clk = get_clk_cfg(desired_clk);
+ if (!desired_clk) {
+ pr_err("%s: Invalid frequency\n", __func__);
+ return 0;
+ }
+
+ maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT;
+ prev = 0;
+
+ for (div = 1; div <= maxdiv; div++) {
+ mult = div * desired_clk;
+ if (mult > ULONG_MAX)
+ break;
+
+ freq = clk_round_rate(clk, (unsigned long)mult);
+ if (!(freq % desired_clk)) {
+ ser_clk = freq;
+ break;
+ }
+
+ if (!prev)
+ ser_clk = freq;
+ else if (prev == freq)
+ break;
+
+ prev = freq;
+ }
+
if (!ser_clk) {
pr_err("%s: Can't find matching DFS entry for baud %d\n",
__func__, baud);
}
*clk_div = ser_clk / desired_clk;
+ if (!(*clk_div))
+ *clk_div = 1;
+
return ser_clk;
}
if (ver >= QUP_SE_VERSION_2_5)
sampling_rate /= 2;
- clk_rate = get_clk_div_rate(baud, sampling_rate, &clk_div);
+ clk_rate = get_clk_div_rate(port->se.clk, baud,
+ sampling_rate, &clk_div);
if (!clk_rate)
goto out_restart_rx;