struct timer_list break_timer;
int break_flag;
- /* Interface clock */
- struct clk *iclk;
/* Function clock */
struct clk *fclk;
pm_runtime_get_sync(sci_port->port.dev);
- clk_prepare_enable(sci_port->iclk);
- sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
clk_prepare_enable(sci_port->fclk);
+ sci_port->port.uartclk = clk_get_rate(sci_port->fclk);
}
static void sci_port_disable(struct sci_port *sci_port)
sci_port->break_flag = 0;
clk_disable_unprepare(sci_port->fclk);
- clk_disable_unprepare(sci_port->iclk);
pm_runtime_put_sync(sci_port->port.dev);
}
struct uart_port *port = &sci_port->port;
spin_lock_irqsave(&port->lock, flags);
- port->uartclk = clk_get_rate(sci_port->iclk);
+ port->uartclk = clk_get_rate(sci_port->fclk);
spin_unlock_irqrestore(&port->lock, flags);
}
static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
unsigned long freq)
{
- if (s->sampling_rate)
- return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1;
-
- /* Warn, but use a safe default */
- WARN_ON(1);
-
- return ((freq + 16 * bps) / (32 * bps) - 1);
-}
-
-/* calculate frame length from SMR */
-static int sci_baud_calc_frame_len(unsigned int smr_val)
-{
- int len = 10;
-
- if (smr_val & SCSMR_CHR)
- len--;
- if (smr_val & SCSMR_PE)
- len++;
- if (smr_val & SCSMR_STOP)
- len++;
-
- return len;
+ return DIV_ROUND_CLOSEST(freq, s->sampling_rate * bps) - 1;
}
-
/* calculate sample rate, BRR, and clock select for HSCIF */
-static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
- int *brr, unsigned int *srr,
- unsigned int *cks, int frame_len)
+static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr,
+ unsigned int *srr, unsigned int *cks)
{
int sr, c, br, err, recv_margin;
int min_err = 1000; /* 100% */
baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
if (likely(baud && port->uartclk)) {
if (s->cfg->type == PORT_HSCIF) {
- int frame_len = sci_baud_calc_frame_len(smr_val);
sci_baud_calc_hscif(baud, port->uartclk, &t, &srr,
- &cks, frame_len);
+ &cks);
} else {
t = sci_scbrr_calc(s, baud, port->uartclk);
for (cks = 0; t >= 256 && cks <= 3; cks++)
#endif
};
+static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
+{
+ /* Get the SCI functional clock. It's called "fck" on ARM. */
+ sci_port->fclk = devm_clk_get(dev, "fck");
+ if (PTR_ERR(sci_port->fclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (!IS_ERR(sci_port->fclk))
+ return 0;
+
+ /*
+ * But it used to be called "sci_ick", and we need to maintain DT
+ * backward compatibility.
+ */
+ sci_port->fclk = devm_clk_get(dev, "sci_ick");
+ if (PTR_ERR(sci_port->fclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (!IS_ERR(sci_port->fclk))
+ return 0;
+
+ /* SH has historically named the clock "sci_fck". */
+ sci_port->fclk = devm_clk_get(dev, "sci_fck");
+ if (!IS_ERR(sci_port->fclk))
+ return 0;
+
+ /*
+ * Not all SH platforms declare a clock lookup entry for SCI devices,
+ * in which case we need to get the global "peripheral_clk" clock.
+ */
+ sci_port->fclk = devm_clk_get(dev, "peripheral_clk");
+ if (!IS_ERR(sci_port->fclk))
+ return 0;
+
+ dev_err(dev, "failed to get functional clock\n");
+ return PTR_ERR(sci_port->fclk);
+}
+
static int sci_init_single(struct platform_device *dev,
struct sci_port *sci_port, unsigned int index,
struct plat_sci_port *p, bool early)
sci_port->sampling_rate = p->sampling_rate;
if (!early) {
- sci_port->iclk = clk_get(&dev->dev, "sci_ick");
- if (IS_ERR(sci_port->iclk)) {
- sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
- if (IS_ERR(sci_port->iclk)) {
- dev_err(&dev->dev, "can't get iclk\n");
- return PTR_ERR(sci_port->iclk);
- }
- }
-
- /*
- * The function clock is optional, ignore it if we can't
- * find it.
- */
- sci_port->fclk = clk_get(&dev->dev, "sci_fck");
- if (IS_ERR(sci_port->fclk))
- sci_port->fclk = NULL;
+ ret = sci_init_clocks(sci_port, &dev->dev);
+ if (ret < 0)
+ return ret;
port->dev = &dev->dev;
static void sci_cleanup_single(struct sci_port *port)
{
- clk_put(port->iclk);
- clk_put(port->fclk);
-
pm_runtime_disable(port->port.dev);
}
{
struct sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port;
- unsigned short bits, ctrl;
+ unsigned short bits, ctrl, ctrl_temp;
unsigned long flags;
int locked = 1;
else
spin_lock(&port->lock);
- /* first save the SCSCR then disable the interrupts */
+ /* first save SCSCR then disable interrupts, keep clock source */
ctrl = serial_port_in(port, SCSCR);
- serial_port_out(port, SCSCR, sci_port->cfg->scscr);
+ ctrl_temp = (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+ (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
+ serial_port_out(port, SCSCR, ctrl_temp);
uart_console_write(port, s, count, serial_console_putchar);
if (!IS_ENABLED(CONFIG_OF) || !np)
return NULL;
- match = of_match_node(of_sci_match, pdev->dev.of_node);
+ match = of_match_node(of_sci_match, np);
if (!match)
return NULL;
if (!p)
return NULL;
- /* Get the line number for the aliases node. */
+ /* Get the line number from the aliases node. */
id = of_alias_get_id(np, "serial");
if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id (%d)\n", id);