From patchwork Thu Nov 19 18:38:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 7660411 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id ED8BF9F65E for ; Thu, 19 Nov 2015 18:42:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id F19D72045B for ; Thu, 19 Nov 2015 18:42:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F30A920483 for ; Thu, 19 Nov 2015 18:42:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934557AbbKSSmG (ORCPT ); Thu, 19 Nov 2015 13:42:06 -0500 Received: from baptiste.telenet-ops.be ([195.130.132.51]:45473 "EHLO baptiste.telenet-ops.be" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934565AbbKSSjF (ORCPT ); Thu, 19 Nov 2015 13:39:05 -0500 Received: from ayla.of.borg ([84.195.106.123]) by baptiste.telenet-ops.be with bizsmtp id jWf41r00Z2fm56U01Wf4oM; Thu, 19 Nov 2015 19:39:04 +0100 Received: from ramsan.of.borg ([192.168.97.29] helo=ramsan) by ayla.of.borg with esmtp (Exim 4.82) (envelope-from ) id 1ZzU6q-0004Yi-6W; Thu, 19 Nov 2015 19:39:04 +0100 Received: from geert by ramsan with local (Exim 4.82) (envelope-from ) id 1ZzU71-0000G4-5w; Thu, 19 Nov 2015 19:39:15 +0100 From: Geert Uytterhoeven To: Greg Kroah-Hartman , Simon Horman , Magnus Damm , Yoshinori Sato , Laurent Pinchart Cc: linux-serial@vger.kernel.org, linux-sh@vger.kernel.org, linux-kernel@vger.kernel.org, Geert Uytterhoeven Subject: [PATCH 19/25] serial: sh-sci: Add support for optional external (H)SCK input Date: Thu, 19 Nov 2015 19:38:58 +0100 Message-Id: <1447958344-836-20-git-send-email-geert+renesas@glider.be> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1447958344-836-1-git-send-email-geert+renesas@glider.be> References: <1447958344-836-1-git-send-email-geert+renesas@glider.be> Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for using the SCIx clock pin "(H)SCK" as an external clock input on (H)SCI(F). Note that this feature is not yet supported on the select SCIFA variants that also have it (e.g. sh7723, sh7724, and r8a7740). On (H)SCIF variants with an External Baud Rate Generator (BRG), the BRG Clock Select Register must be configured for the external clock. Signed-off-by: Geert Uytterhoeven --- drivers/tty/serial/sh-sci.c | 63 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 12800e52f41953dc..f88aac684ed1e3b6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -79,6 +79,7 @@ enum { enum SCI_CLKS { SCI_FCK, /* Functional Clock */ + SCI_SCK, /* Optional External Clock */ SCI_NUM_CLKS }; @@ -1924,6 +1925,36 @@ static void sci_shutdown(struct uart_port *port) sci_free_irq(s); } +static int sci_sck_calc(struct sci_port *s, unsigned int bps, + unsigned int *srr) +{ + unsigned long freq = s->clk_rates[SCI_SCK]; + unsigned int min_sr, max_sr, sr; + int err, min_err = INT_MAX; + + if (s->sampling_rate) { + /* SCI(F) has a fixed sampling rate */ + min_sr = max_sr = s->sampling_rate / 2; + } else { + /* HSCIF has a variable 1/(8..32) sampling rate */ + min_sr = 8; + max_sr = 32; + } + + for (sr = max_sr; sr >= min_sr; sr--) { + err = DIV_ROUND_CLOSEST(freq, sr) - bps; + if (abs(err) >= abs(min_err)) + continue; + + min_err = err; + *srr = sr - 1; + } + + dev_dbg(s->port.dev, "SCK: %u%+d bps using SR %u\n", bps, min_err, + *srr + 1); + return min_err; +} + /* calculate sample rate, BRR, and clock select */ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr, unsigned int *srr, @@ -2005,7 +2036,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned int baud, smr_val = 0, scr_val = 0, i; - unsigned int brr = 255, cks = 0, srr = 15; + unsigned int brr = 255, cks = 0, srr = 15, sccks = 0; unsigned int brr1 = 255, cks1 = 0, srr1 = 15; struct sci_port *s = to_sci_port(port); const struct plat_sci_reg *reg; @@ -2043,10 +2074,26 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, if (!baud) goto done; + /* Optional External Clock */ + if (s->clk_rates[SCI_SCK] && port->type != PORT_SCIFA && + port->type != PORT_SCIFB) { + err = sci_sck_calc(s, baud, &srr1); + if (abs(err) < abs(min_err)) { + best_clk = SCI_SCK; + scr_val = SCSCR_CKE1; + sccks = SCCKS_CKS; + min_err = err; + srr = srr1; + if (!err) + goto done; + } + } + /* Functional Clock and standard Bit Rate Register */ err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1); if (abs(err) < abs(min_err)) { best_clk = SCI_FCK; + scr_val = 0; min_err = err; brr = brr1; srr = srr1; @@ -2060,14 +2107,20 @@ done: sci_port_enable(s); + /* Program the optional External Baud Rate Generator (BRG) first */ + if (best_clk >= 0 && sci_getreg(port, SCCKS)->size) + serial_port_out(port, SCCKS, sccks); + sci_reset(port); uart_update_timeout(port, termios->c_cflag, baud); if (best_clk >= 0) { smr_val |= cks; - dev_dbg(port->dev, "SMR 0x%x BRR %u SRR %u\n", smr_val, brr, - srr); + dev_dbg(port->dev, + "SCR 0x%x SMR 0x%x BRR %u CKS 0x%x SRR %u\n", + scr_val, smr_val, brr, sccks, srr); + serial_port_out(port, SCSCR, scr_val); serial_port_out(port, SCSMR, smr_val); serial_port_out(port, SCBRR, brr); if (sci_getreg(port, HSSRR)->size) @@ -2303,10 +2356,14 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) { const char *clk_names[] = { [SCI_FCK] = "fck", + [SCI_SCK] = "sck", }; struct clk *clk; unsigned int i; + if (sci_port->cfg->type == PORT_HSCIF) + clk_names[SCI_SCK] = "hsck"; + for (i = 0; i < SCI_NUM_CLKS; i++) { clk = devm_clk_get(dev, clk_names[i]); if (PTR_ERR(clk) == -EPROBE_DEFER)