From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
To: Kumar Gala <galak@codeaurora.org>
Cc: gregkh@linuxfoundation.org, grant.likely@linaro.org,
rob.herring@calxeda.com, rob@landley.net, jslaby@suse.cz,
devicetree-discuss@lists.ozlabs.org,
linux-serial@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
mrana@codeaurora.org, sambley@codeaurora.org
Subject: Re: [PATCH] tty: serial: Add initial MSM UART High Speed Lite driver
Date: Wed, 17 Jul 2013 10:38:43 +0300 [thread overview]
Message-ID: <1374046723.2657.27.camel@iivanov-dev> (raw)
In-Reply-To: <76DBE056-CDFB-47A5-9AB5-239400A2D4F9@codeaurora.org>
Hi Kumar,
On Tue, 2013-07-16 at 15:17 -0500, Kumar Gala wrote:
> On Jul 1, 2013, at 4:11 AM, Ivan T. Ivanov wrote:
>
> > From: "Ivan T. Ivanov" <iivanov@mm-sol.com>
> >
> > This is a tty driver with console support for Qualcomm's UART
> > controllers found in the MSM8974 chipsets. Driver is completely
> > based on implementation found in codeaurora.org msm_serial_hs_lite
> > with Android dependences removed. Other changes include, moved to
> > device managed resources and few cleanups.
> >
> > Driver functionality was tested in LEGACY_HSUART mode.
> >
> > Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com>
> > ---
> > .../bindings/tty/serial/msm_serial_hsl.txt | 52 +
> > drivers/tty/serial/Kconfig | 18 +
> > drivers/tty/serial/Makefile | 1 +
> > drivers/tty/serial/msm_serial_hsl.c | 1399 ++++++++++++++++++++
> > drivers/tty/serial/msm_serial_hsl.h | 294 ++++
> > 5 files changed, 1764 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/tty/serial/msm_serial_hsl.txt
> > create mode 100644 drivers/tty/serial/msm_serial_hsl.c
> > create mode 100644 drivers/tty/serial/msm_serial_hsl.h
> >
> > diff --git a/Documentation/devicetree/bindings/tty/serial/msm_serial_hsl.txt b/Documentation/devicetree/bindings/tty/serial/msm_serial_hsl.txt
> > new file mode 100644
> > index 0000000..972552f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/tty/serial/msm_serial_hsl.txt
> > @@ -0,0 +1,52 @@
> > +* Qualcomm MSM HSUART Lite
> > +
> > +Required properties:
> > +- compatible :
> > + "qcom,msm-lsuart-v14" to be used for UARTDM Core v1.4
>
> If its really v1.4 than the string should be "qcom,msm-lsuart-v1.4"
I am not sure which is the right number here. codeaurora code uses v14
string for compatible name and 1.4 here and there in the comments.
I am inclined to believe that 1.4 is true.
>
> > +
> > +- reg :
> > + offset and length of the register set for both the device,
> > + UART core and GBSI core
> > +
> > +- reg-names :
> > + "uart_mem" to be used as name of the UART core
> > + "gbsi_mem" to be used as name of the GBSI core
> > +
> > +The registers for the "qcom,msm-lsuart-v14" device have specify
> > +UART core block. GSBI reg is optional if specified driver will use
> > +GSBI specific functionality.
> > +
> > +- interrupts : interrupts for UART core
> > +
> > +- clocks : Must contain an entry for each entry in clock-names.
> > +
> > +- clock-names : Must include the following entries:
> > + "core_clk" - mandatory
> > + "iface_clk" - optional
> > +
> > +For details see:
> > +Documentation/devicetree/bindings/clock/clock-bindings.txt
> > +
> > +Example:
> > +
> > + serial@f991e000 {
> > + compatible = "qcom,msm-lsuart-v14";
> > + reg = <0xf991e000 0x1000>;
> > + reg-names = "uart_mem";
> > + interrupts = <0 108 0>;
> > + clocks = <&blsp1_uart2_apps_cxc>, <&blsp1_ahb_cxc>;
> > + clock-names = "core_clk", "iface_clk";
> > + };
> > +
> > +Aliases :
> > +An alias may be optionally used to bind the UART device to a TTY device
> > +(ttyHSL<alias_num>) with a given alias number. Aliases are of the form
> > +uart<n> where <n> is an integer representing the alias number to use.
> > +On systems with multiple UART devices present, an alias may optionally be
> > +defined for such devices. The alias value should be from 0 to 255.
> > +
> > +Example:
> > +
> > + aliases {
> > + uart4 = &uart7; // This device will be enumerated as ttyHSL4
> > + };
> > diff --git a/drivers/tty/serial/msm_serial_hsl.c b/drivers/tty/serial/msm_serial_hsl.c
> > new file mode 100644
> > index 0000000..56c15a8
> > --- /dev/null
> > +++ b/drivers/tty/serial/msm_serial_hsl.c
> > @@ -0,0 +1,1399 @@
> > +/*
> > + * drivers/tty/serial/msm_serial_hsl.c - driver for serial device and console
> > + *
> > + * Copyright (C) 2007 Google, Inc.
> > + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
> > + *
> > + * This software is licensed under the terms of the GNU General Public
> > + * License version 2, as published by the Free Software Foundation, and
> > + * may be copied, distributed, and modified under those terms.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +/* Acknowledgements:
> > + * This file is based on msm_serial.c, originally
> > + * Written by Robert Love <rlove@google.com> */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/console.h>
> > +#include <linux/debugfs.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/irq.h>
> > +#include <linux/module.h>
> > +#include <linux/nmi.h>
> > +#include <linux/of.h>
> > +#include <linux/of_device.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/serial_core.h>
> > +#include <linux/tty.h>
> > +#include <linux/tty_flip.h>
> > +
> > +#include "msm_serial_hsl.h"
> > +
> > +/*
> > + * There are 3 different kind of UART Core available on MSM.
> > + * High Speed UART (i.e. Legacy HSUART), GSBI based HSUART
> > + * and BSLP based HSUART.
> > + */
> > +enum uart_core_type {
> > + LEGACY_HSUART,
> > + GSBI_HSUART,
> > + BLSP_HSUART,
> > +};
> > +
> > +/*
> > + * @uart: uart port instance
> > + * @name: name of the port
> > + * @clk: reference to core clock
> > + * @pclk: reference to interface clock
> > + * @imr: shadow interrupt mask register
> > + * @mapped_gsbi: GSBI contol memory
> > + * @old_snap_state: How many data still left in the FIFO
> > + * @tx_timeout - transmit timout ~600x the character transmit time
> > + * @uart_type - see enum uart_core_type
> > + * @regmap - Register map based on controller version
> > + * It is mainly required where same UART is used across different processor.
> > + * Make sure that Clock driver for platform support setting clock rate to zero.
> > + */
> > +struct msm_hsl_port {
> > + struct uart_port uart;
> > + char name[16];
> > + struct clk *clk;
> > + struct clk *pclk;
> > + struct dentry *loopback_dir;
> > + unsigned int imr;
> > + unsigned int *mapped_gsbi;
> > + unsigned int old_snap_state;
> > + int tx_timeout;
> > + enum uart_core_type uart_type;
> > + const unsigned int *regmap;
> > +};
> > +
> > +#define UARTDM_VERSION_11_13 0
> > +#define UARTDM_VERSION_14 1
> > +#define UART_NR 3
> > +
> > +#define to_hsl_port(p) (container_of(p, struct msm_hsl_port, uart))
> > +#define is_console(port) ((port)->cons && \
> > + (port)->cons->index == (port)->line)
> > +
> > +static const unsigned int regmap[][UARTDM_LAST] = {
> > + [UARTDM_VERSION_11_13] = {
> > + [UARTDM_MR1] = UARTDM_MR1_ADDR,
> > + [UARTDM_MR2] = UARTDM_MR2_ADDR,
> > + [UARTDM_IMR] = UARTDM_IMR_ADDR,
> > + [UARTDM_SR] = UARTDM_SR_ADDR,
> > + [UARTDM_CR] = UARTDM_CR_ADDR,
> > + [UARTDM_CSR] = UARTDM_CSR_ADDR,
> > + [UARTDM_IPR] = UARTDM_IPR_ADDR,
> > + [UARTDM_ISR] = UARTDM_ISR_ADDR,
> > + [UARTDM_RX_TOTAL_SNAP] = UARTDM_RX_TOTAL_SNAP_ADDR,
> > + [UARTDM_TFWR] = UARTDM_TFWR_ADDR,
> > + [UARTDM_RFWR] = UARTDM_RFWR_ADDR,
> > + [UARTDM_RF] = UARTDM_RF_ADDR,
> > + [UARTDM_TF] = UARTDM_TF_ADDR,
> > + [UARTDM_MISR] = UARTDM_MISR_ADDR,
> > + [UARTDM_DMRX] = UARTDM_DMRX_ADDR,
> > + [UARTDM_NCF_TX] = UARTDM_NCF_TX_ADDR,
> > + [UARTDM_DMEN] = UARTDM_DMEN_ADDR,
> > + [UARTDM_TXFS] = UARTDM_TXFS_ADDR,
> > + [UARTDM_RXFS] = UARTDM_RXFS_ADDR,
> > + },
>
> Isn't this unsupported code for version 11_13?
It is supposed to be supported. I will rework code in the probe
method to select the right register map based on compatible field.
>
> > + [UARTDM_VERSION_14] = {
> > + [UARTDM_MR1] = UARTDM_MR1_ADDR,
> > + [UARTDM_MR2] = UARTDM_MR2_ADDR,
> > + [UARTDM_IMR] = UARTDM_IMR_ADDR_V14,
> > + [UARTDM_SR] = UARTDM_SR_ADDR_V14,
> > + [UARTDM_CR] = UARTDM_CR_ADDR_V14,
> > + [UARTDM_CSR] = UARTDM_CSR_ADDR_V14,
> > + [UARTDM_IPR] = UARTDM_IPR_ADDR,
> > + [UARTDM_ISR] = UARTDM_ISR_ADDR_V14,
> > + [UARTDM_RX_TOTAL_SNAP] = UARTDM_RX_TOTAL_SNAP_ADDR_V14,
> > + [UARTDM_TFWR] = UARTDM_TFWR_ADDR,
> > + [UARTDM_RFWR] = UARTDM_RFWR_ADDR,
> > + [UARTDM_RF] = UARTDM_RF_ADDR_V14,
> > + [UARTDM_TF] = UARTDM_TF_ADDR_V14,
> > + [UARTDM_MISR] = UARTDM_MISR_ADDR_V14,
> > + [UARTDM_DMRX] = UARTDM_DMRX_ADDR,
> > + [UARTDM_NCF_TX] = UARTDM_NCF_TX_ADDR,
> > + [UARTDM_DMEN] = UARTDM_DMEN_ADDR,
> > + [UARTDM_TXFS] = UARTDM_TXFS_ADDR,
> > + [UARTDM_RXFS] = UARTDM_RXFS_ADDR,
> > + },
> > +};
> > +
> > +/*
> > + * get_console_state - check the per-port serial console state.
> > + * @port: uart_port structure describing the port
> > + *
> > + * Return the state of serial console availability on port.
> > + * return 1: If serial console is enabled on particular UART port.
> > + * return 0: If serial console is disabled on particular UART port.
> > + */
> > +static int get_console_state(struct uart_port *port)
> > +{
> > +#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
> > + if (is_console(port) && (port->cons->flags & CON_ENABLED))
> > + return 1;
> > + else
> > + return 0;
> > +#else
> > + return -ENODEV;
> > +#endif
> > +}
> > +
> > +static inline void msm_hsl_write(struct uart_port *port,
> > + unsigned int val, unsigned int off)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > +
> > + iowrite32(val, port->membase + hslp->regmap[off]);
> > +}
> > +
> > +static inline unsigned int msm_hsl_read(struct uart_port *port,
> > + unsigned int off)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > +
> > + return ioread32(port->membase + hslp->regmap[off]);
> > +}
> > +
> > +static unsigned int msm_serial_hsl_has_gsbi(struct uart_port *port)
> > +{
> > + return (to_hsl_port(port)->uart_type == GSBI_HSUART);
> > +}
> > +
> > +/*
> > + * set_gsbi_uart_func_mode: Check the currently used GSBI UART mode
> > + * and set the new required GSBI UART Mode if it is different.
> > + * @port: uart port
> > + */
> > +static void set_gsbi_uart_func_mode(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + unsigned int set_mode = GSBI_PROTOCOL_I2C_UART;
> > + unsigned int cur_mode;
> > +
> > + if (hslp->pclk)
> > + clk_prepare_enable(hslp->pclk);
> > +
> > + /* Read current used GSBI UART Mode and set only if it is different. */
> > + cur_mode = ioread32(hslp->mapped_gsbi + GSBI_CONTROL_ADDR);
> > + if ((cur_mode & GSBI_PROTOCOL_CODE_MASK) != set_mode)
> > + /*
> > + * Programmed GSBI based UART protocol mode i.e. I2C/UART
> > + * Shared Mode or UART Mode.
> > + */
> > + iowrite32(set_mode, hslp->mapped_gsbi + GSBI_CONTROL_ADDR);
> > +
> > + if (hslp->pclk)
> > + clk_disable_unprepare(hslp->pclk);
> > +}
> > +
> > +static int msm_hsl_clock_enable(struct uart_port *port, int enable)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + int ret = 0;
> > +
> > + if (enable) {
> > + ret = clk_prepare_enable(hslp->clk);
> > + if (ret)
> > + return ret;
> > + if (hslp->pclk) {
> > + ret = clk_prepare_enable(hslp->pclk);
> > + if (ret)
> > + clk_disable_unprepare(hslp->clk);
> > + }
> > + } else {
> > + clk_disable_unprepare(hslp->clk);
> > + if (hslp->pclk)
> > + clk_disable_unprepare(hslp->pclk);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static int msm_hsl_loopback_set(void *data, u64 val)
> > +{
> > + struct msm_hsl_port *hslp = data;
> > + struct uart_port *port = &(hslp->uart);
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + ret = clk_set_rate(hslp->clk, port->uartclk);
> > + if (!ret)
> > + msm_hsl_clock_enable(port, 1);
> > + else
> > + return -EINVAL;
> > +
> > + if (val) {
> > + spin_lock_irqsave(&port->lock, flags);
> > + ret = msm_hsl_read(port, UARTDM_MR2);
> > + ret |= UARTDM_MR2_LOOP_MODE_BMSK;
> > + msm_hsl_write(port, ret, UARTDM_MR2);
> > + spin_unlock_irqrestore(&port->lock, flags);
> > + } else {
> > + spin_lock_irqsave(&port->lock, flags);
> > + ret = msm_hsl_read(port, UARTDM_MR2);
> > + ret &= ~UARTDM_MR2_LOOP_MODE_BMSK;
> > + msm_hsl_write(port, ret, UARTDM_MR2);
> > + spin_unlock_irqrestore(&port->lock, flags);
> > + }
> > +
> > + msm_hsl_clock_enable(port, 0);
> > + return 0;
> > +}
> > +
> > +static int msm_hsl_loopback_get(void *data, u64 *val)
> > +{
> > + struct msm_hsl_port *hslp = data;
> > + struct uart_port *port = &hslp->uart;
> > + unsigned long flags;
> > + int ret = 0;
> > +
> > + ret = clk_set_rate(hslp->clk, port->uartclk);
> > + if (!ret)
> > + msm_hsl_clock_enable(port, 1);
> > + else
> > + return -EINVAL;
> > +
> > + spin_lock_irqsave(&port->lock, flags);
> > + ret = msm_hsl_read(port, UARTDM_MR2);
> > + spin_unlock_irqrestore(&port->lock, flags);
> > + msm_hsl_clock_enable(port, 0);
> > +
> > + *val = (ret & UARTDM_MR2_LOOP_MODE_BMSK) ? 1 : 0;
> > + return 0;
> > +}
> > +
> > +static void msm_hsl_stop_tx(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > +
> > + hslp->imr &= ~UARTDM_ISR_TXLEV_BMSK;
> > + msm_hsl_write(port, hslp->imr, UARTDM_IMR);
> > +}
> > +
> > +static void msm_hsl_start_tx(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > +
> > + hslp->imr |= UARTDM_ISR_TXLEV_BMSK;
> > + msm_hsl_write(port, hslp->imr, UARTDM_IMR);
> > +}
> > +
> > +static void msm_hsl_stop_rx(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > +
> > + hslp->imr &= ~(UARTDM_ISR_RXLEV_BMSK | UARTDM_ISR_RXSTALE_BMSK);
> > + msm_hsl_write(port, hslp->imr, UARTDM_IMR);
> > +}
> > +
> > +static void msm_hsl_enable_ms(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > +
> > + hslp->imr |= UARTDM_ISR_DELTA_CTS_BMSK;
> > + msm_hsl_write(port, hslp->imr, UARTDM_IMR);
> > +}
> > +
> > +static void msm_hsl_handle_rx(struct uart_port *port, unsigned int misr)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + struct tty_port *tty = &port->state->port;
> > + unsigned int sr;
> > + int count = 0;
> > +
> > + /*
> > + * Handle overrun. My understanding of the hardware is that overrun
> > + * is not tied to the RX buffer, so we handle the case out of band.
> > + */
> > + sr = msm_hsl_read(port, UARTDM_SR);
> > + if (sr & UARTDM_SR_OVERRUN_BMSK) {
> > + port->icount.overrun++;
> > + tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> > + msm_hsl_write(port, RESET_ERROR_STATUS, UARTDM_CR);
> > + }
> > +
> > + if (misr & UARTDM_ISR_RXSTALE_BMSK) {
> > + count = msm_hsl_read(port, UARTDM_RX_TOTAL_SNAP) -
> > + hslp->old_snap_state;
> > + hslp->old_snap_state = 0;
> > + } else {
> > + count = 4 * (msm_hsl_read(port, UARTDM_RFWR));
> > + hslp->old_snap_state += count;
> > + }
> > +
> > + /* and now the main RX loop */
> > + while (count > 0) {
> > + unsigned int c;
> > + char flag = TTY_NORMAL;
> > +
> > + sr = msm_hsl_read(port, UARTDM_SR);
> > + if ((sr & UARTDM_SR_RXRDY_BMSK) == 0) {
> > + hslp->old_snap_state -= count;
> > + break;
> > + }
> > + c = msm_hsl_read(port, UARTDM_RF);
> > + if (sr & UARTDM_SR_RX_BREAK_BMSK) {
> > + port->icount.brk++;
> > + if (uart_handle_break(port))
> > + continue;
> > + } else if (sr & UARTDM_SR_PAR_FRAME_BMSK) {
> > + port->icount.frame++;
> > + } else {
> > + port->icount.rx++;
> > + }
> > +
> > + /* Mask conditions we're ignorning. */
> > + sr &= port->read_status_mask;
> > + if (sr & UARTDM_SR_RX_BREAK_BMSK)
> > + flag = TTY_BREAK;
> > + else if (sr & UARTDM_SR_PAR_FRAME_BMSK)
> > + flag = TTY_FRAME;
> > +
> > + /* TODO: handle sysrq */
> > + /* if (!uart_handle_sysrq_char(port, c)) */
> > + tty_insert_flip_string(tty, (char *)&c,
> > + (count > 4) ? 4 : count);
> > + count -= 4;
> > + }
> > +
> > + tty_flip_buffer_push(tty);
> > +}
> > +
> > +static void msm_hsl_dump_regs(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + unsigned int sr, isr, mr1, mr2, ncf, txfs, rxfs, con_state;
> > +
> > + sr = msm_hsl_read(port, UARTDM_SR);
> > + isr = msm_hsl_read(port, UARTDM_ISR);
> > + mr1 = msm_hsl_read(port, UARTDM_MR1);
> > + mr2 = msm_hsl_read(port, UARTDM_MR2);
> > + ncf = msm_hsl_read(port, UARTDM_NCF_TX);
> > + txfs = msm_hsl_read(port, UARTDM_TXFS);
> > + rxfs = msm_hsl_read(port, UARTDM_RXFS);
> > + con_state = get_console_state(port);
> > +
> > + pr_info("Timeout: %d uS\n", hslp->tx_timeout);
> > + pr_info("SR: %08x\n", sr);
> > + pr_info("ISR: %08x\n", isr);
> > + pr_info("MR1: %08x\n", mr1);
> > + pr_info("MR2: %08x\n", mr2);
> > + pr_info("NCF: %08x\n", ncf);
> > + pr_info("TXFS: %08x\n", txfs);
> > + pr_info("RXFS: %08x\n", rxfs);
> > + pr_info("Console state: %d\n", con_state);
> > +}
> > +
> > +/*
> > + * Wait for transmitter & holding register to empty
> > + * Derived from msm_hsl_wait_for_xmitr in 8250 serial driver by Russell King
> > + */
> > +static void msm_hsl_wait_for_xmitr(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + int count = 0;
> > + int sr;
> > + int isr;
> > +
> > + sr = msm_hsl_read(port, UARTDM_SR);
> > + if (sr & UARTDM_SR_TXEMT_BMSK)
> > + return;
> > +
> > + do {
> > + isr = msm_hsl_read(port, UARTDM_ISR);
> > + sr = msm_hsl_read(port, UARTDM_SR);
> > +
> > + if ((isr & UARTDM_ISR_TX_READY_BMSK) ||
> > + (sr & UARTDM_SR_TXEMT_BMSK))
> > + break;
> > +
> > + udelay(1);
> > + touch_nmi_watchdog();
> > + cpu_relax();
> > +
> > + if (++count == hslp->tx_timeout) {
> > + msm_hsl_dump_regs(port);
> > + panic("MSM HSL msm_hsl_wait_for_xmitr is stuck!");
> > + }
> > +
> > + } while (true);
> > +
> > + msm_hsl_write(port, CLEAR_TX_READY, UARTDM_CR);
> > +
> > +}
> > +
> > +static void msm_hsl_handle_tx(struct uart_port *port)
> > +{
> > + struct circ_buf *xmit = &port->state->xmit;
> > + unsigned int tf_pointer = 0;
> > + int sent_tx;
> > + int tx_count;
> > + int x;
> > + int sr;
> > +
> > + tx_count = uart_circ_chars_pending(xmit);
> > +
> > + if (tx_count > (UART_XMIT_SIZE - xmit->tail))
> > + tx_count = UART_XMIT_SIZE - xmit->tail;
> > + if (tx_count >= port->fifosize)
> > + tx_count = port->fifosize;
> > +
> > + /* Handle x_char */
> > + if (port->x_char) {
> > + msm_hsl_wait_for_xmitr(port);
> > + msm_hsl_write(port, tx_count + 1, UARTDM_NCF_TX);
> > + msm_hsl_read(port, UARTDM_NCF_TX);
> > + msm_hsl_write(port, port->x_char, UARTDM_TF);
> > + port->icount.tx++;
> > + port->x_char = 0;
> > + } else if (tx_count) {
> > + msm_hsl_wait_for_xmitr(port);
> > + msm_hsl_write(port, tx_count, UARTDM_NCF_TX);
> > + msm_hsl_read(port, UARTDM_NCF_TX);
> > + }
> > + if (!tx_count) {
> > + msm_hsl_stop_tx(port);
> > + return;
> > + }
> > +
> > + while (tf_pointer < tx_count) {
> > + sr = msm_hsl_read(port, UARTDM_SR);
> > + if (!(sr & UARTDM_SR_TXRDY_BMSK))
> > + continue;
> > + switch (tx_count - tf_pointer) {
> > + case 1:
> > + x = xmit->buf[xmit->tail];
> > + port->icount.tx++;
> > + break;
> > + case 2:
> > + x = xmit->buf[xmit->tail]
> > + | xmit->buf[xmit->tail + 1] << 8;
> > + port->icount.tx += 2;
> > + break;
> > + case 3:
> > + x = xmit->buf[xmit->tail]
> > + | xmit->buf[xmit->tail + 1] << 8
> > + | xmit->buf[xmit->tail + 2] << 16;
> > + port->icount.tx += 3;
> > + break;
> > + default:
> > + x = *((int *)&(xmit->buf[xmit->tail]));
> > + port->icount.tx += 4;
> > + break;
> > + }
> > + msm_hsl_write(port, x, UARTDM_TF);
> > + xmit->tail = ((tx_count - tf_pointer < 4) ?
> > + (tx_count - tf_pointer + xmit->tail) :
> > + (xmit->tail + 4)) & (UART_XMIT_SIZE - 1);
> > + tf_pointer += 4;
> > + sent_tx = 1;
> > + }
> > +
> > + if (uart_circ_empty(xmit))
> > + msm_hsl_stop_tx(port);
> > +
> > + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> > + uart_write_wakeup(port);
> > +
> > +}
> > +
> > +static void msm_hsl_handle_delta_cts(struct uart_port *port)
> > +{
> > + msm_hsl_write(port, RESET_CTS, UARTDM_CR);
> > + port->icount.cts++;
> > + wake_up_interruptible(&port->state->port.delta_msr_wait);
> > +}
> > +
> > +static irqreturn_t msm_hsl_irq(int irq, void *dev_id)
> > +{
> > + struct uart_port *port = dev_id;
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + unsigned int misr;
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&port->lock, flags);
> > + misr = msm_hsl_read(port, UARTDM_MISR);
> > + /* disable interrupt */
> > + msm_hsl_write(port, 0, UARTDM_IMR);
> > +
> > + if (misr & (UARTDM_ISR_RXSTALE_BMSK | UARTDM_ISR_RXLEV_BMSK)) {
> > + msm_hsl_handle_rx(port, misr);
> > + if (misr & (UARTDM_ISR_RXSTALE_BMSK))
> > + msm_hsl_write(port, RESET_STALE_INT,
> > + UARTDM_CR);
> > + msm_hsl_write(port, 6500, UARTDM_DMRX);
> > + msm_hsl_write(port, STALE_EVENT_ENABLE, UARTDM_CR);
> > + }
> > + if (misr & UARTDM_ISR_TXLEV_BMSK)
> > + msm_hsl_handle_tx(port);
> > +
> > + if (misr & UARTDM_ISR_DELTA_CTS_BMSK)
> > + msm_hsl_handle_delta_cts(port);
> > +
> > + /* restore interrupt */
> > + msm_hsl_write(port, hslp->imr, UARTDM_IMR);
> > + spin_unlock_irqrestore(&port->lock, flags);
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static unsigned int msm_hsl_tx_empty(struct uart_port *port)
> > +{
> > + unsigned int ret;
> > +
> > + ret = msm_hsl_read(port, UARTDM_SR);
> > + ret &= UARTDM_SR_TXEMT_BMSK;
> > +
> > + if (ret)
> > + ret = TIOCSER_TEMT;
> > +
> > + return ret;
> > +}
> > +
> > +static void msm_hsl_reset(struct uart_port *port)
> > +{
> > + /* reset everything */
> > + msm_hsl_write(port, RESET_RX, UARTDM_CR);
> > + msm_hsl_write(port, RESET_TX, UARTDM_CR);
> > + msm_hsl_write(port, RESET_ERROR_STATUS, UARTDM_CR);
> > + msm_hsl_write(port, RESET_BREAK_INT, UARTDM_CR);
> > + msm_hsl_write(port, RESET_CTS, UARTDM_CR);
> > + msm_hsl_write(port, RFR_LOW, UARTDM_CR);
> > +}
> > +
> > +static unsigned int msm_hsl_get_mctrl(struct uart_port *port)
> > +{
> > + return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR | TIOCM_RTS;
> > +}
> > +
> > +static void msm_hsl_set_mctrl(struct uart_port *port, unsigned int mctrl)
> > +{
> > + unsigned int mr;
> > + unsigned int loop_mode;
> > +
> > + mr = msm_hsl_read(port, UARTDM_MR1);
> > +
> > + if (!(mctrl & TIOCM_RTS)) {
> > + mr &= ~UARTDM_MR1_RX_RDY_CTL_BMSK;
> > + msm_hsl_write(port, mr, UARTDM_MR1);
> > + msm_hsl_write(port, RFR_HIGH, UARTDM_CR);
> > + } else {
> > + mr |= UARTDM_MR1_RX_RDY_CTL_BMSK;
> > + msm_hsl_write(port, mr, UARTDM_MR1);
> > + }
> > +
> > + loop_mode = TIOCM_LOOP & mctrl;
> > + if (loop_mode) {
> > + mr = msm_hsl_read(port, UARTDM_MR2);
> > + mr |= UARTDM_MR2_LOOP_MODE_BMSK;
> > + msm_hsl_write(port, mr, UARTDM_MR2);
> > +
> > + /* Reset TX */
> > + msm_hsl_reset(port);
> > +
> > + /* Turn on Uart Receiver & Transmitter */
> > + msm_hsl_write(port, UARTDM_CR_RX_EN_BMSK | UARTDM_CR_TX_EN_BMSK,
> > + UARTDM_CR);
> > + }
> > +}
> > +
> > +static void msm_hsl_break_ctl(struct uart_port *port, int break_ctl)
> > +{
> > +
> > + if (break_ctl)
> > + msm_hsl_write(port, START_BREAK, UARTDM_CR);
> > + else
> > + msm_hsl_write(port, STOP_BREAK, UARTDM_CR);
> > +}
> > +
> > +/*
> > + * msm_hsl_set_baud_rate: set requested baud rate
> > + * @port: uart port
> > + * @baud: baud rate to set (in bps)
> > + */
> > +static void msm_hsl_set_baud_rate(struct uart_port *port, unsigned int baud)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + unsigned int baud_code, rxstale, watermark;
> > + unsigned int data;
> > +
> > + switch (baud) {
> > + case 300:
> > + baud_code = 0x00;
> > + rxstale = 1;
> > + break;
> > + case 600:
> > + baud_code = 0x11;
> > + rxstale = 1;
> > + break;
> > + case 1200:
> > + baud_code = 0x22;
> > + rxstale = 1;
> > + break;
> > + case 2400:
> > + baud_code = 0x33;
> > + rxstale = 1;
> > + break;
> > + case 4800:
> > + baud_code = 0x44;
> > + rxstale = 1;
> > + break;
> > + case 9600:
> > + baud_code = 0x55;
> > + rxstale = 2;
> > + break;
> > + case 14400:
> > + baud_code = 0x66;
> > + rxstale = 3;
> > + break;
> > + case 19200:
> > + baud_code = 0x77;
> > + rxstale = 4;
> > + break;
> > + case 28800:
> > + baud_code = 0x88;
> > + rxstale = 6;
> > + break;
> > + case 38400:
> > + baud_code = 0x99;
> > + rxstale = 8;
> > + break;
> > + case 57600:
> > + baud_code = 0xaa;
> > + rxstale = 16;
> > + break;
> > + case 115200:
> > + baud_code = 0xcc;
> > + rxstale = 31;
> > + break;
> > + case 230400:
> > + baud_code = 0xee;
> > + rxstale = 31;
> > + break;
> > + case 460800:
> > + baud_code = 0xff;
> > + rxstale = 31;
> > + break;
> > + default: /*115200 baud rate */
> > + baud_code = 0xcc;
> > + rxstale = 31;
> > + break;
> > + }
> > +
> > + msm_hsl_write(port, baud_code, UARTDM_CSR);
> > +
> > + /*
> > + * uart baud rate depends on CSR and MND Values
> > + * we are updating CSR before and then calling
> > + * clk_set_rate which updates MND Values. Hence
> > + * dsb requires here.
> > + */
> > + mb();
> > +
> > + /*
> > + * Check requested baud rate and for higher baud rate than 460800,
> > + * calculate required uart clock frequency and set the same.
> > + */
> > + if (baud > 460800)
> > + port->uartclk = baud * 16;
> > + else
> > + port->uartclk = 7372800;
> > +
> > + if (clk_set_rate(hslp->clk, port->uartclk)) {
> > + WARN_ON(1);
> > + return;
> > + }
> > +
> > + /* Set timeout to be ~600x the character transmit time */
> > + hslp->tx_timeout = (1000000000 / baud) * 6;
> > +
> > + /* RX stale watermark */
> > + watermark = UARTDM_IPR_STALE_LSB_BMSK & rxstale;
> > + watermark |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2);
> > + msm_hsl_write(port, watermark, UARTDM_IPR);
> > +
> > + /* Set RX watermark
> > + * Configure Rx Watermark as 3/4 size of Rx FIFO.
> > + * RFWR register takes value in Words for UARTDM Core
> > + * whereas it is consider to be in Bytes for UART Core.
> > + * Hence configuring Rx Watermark as 48 Words.
> > + */
> > + watermark = (port->fifosize * 3) / 4;
> > + msm_hsl_write(port, watermark, UARTDM_RFWR);
> > +
> > + /* set TX watermark */
> > + msm_hsl_write(port, 0, UARTDM_TFWR);
> > +
> > + msm_hsl_write(port, CR_PROTECTION_EN, UARTDM_CR);
> > + msm_hsl_reset(port);
> > +
> > + data = UARTDM_CR_TX_EN_BMSK;
> > + data |= UARTDM_CR_RX_EN_BMSK;
> > + /* enable TX & RX */
> > + msm_hsl_write(port, data, UARTDM_CR);
> > +
> > + msm_hsl_write(port, RESET_STALE_INT, UARTDM_CR);
> > + /* turn on RX and CTS interrupts */
> > + hslp->imr = UARTDM_ISR_RXSTALE_BMSK | UARTDM_ISR_DELTA_CTS_BMSK |
> > + UARTDM_ISR_RXLEV_BMSK;
> > + msm_hsl_write(port, hslp->imr, UARTDM_IMR);
> > + msm_hsl_write(port, 6500, UARTDM_DMRX);
> > + msm_hsl_write(port, STALE_EVENT_ENABLE, UARTDM_CR);
> > +}
> > +
> > +static int msm_hsl_startup(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + unsigned int data, rfr_level;
> > + int ret;
> > + unsigned long flags;
> > +
> > + snprintf(hslp->name, sizeof(hslp->name),
> > + "msm_serial_hsl%d", port->line);
> > +
> > + if (!(is_console(port)) || (!port->cons) ||
> > + (port->cons && (!(port->cons->flags & CON_ENABLED)))) {
> > +
> > + if (msm_serial_hsl_has_gsbi(port))
> > + set_gsbi_uart_func_mode(port);
> > + }
> > +
> > + /*
> > + * Set RFR Level as 3/4 of UARTDM FIFO Size
> > + * i.e. 48 Words = 192 bytes as Rx FIFO is 64 words ( 256 bytes).
> > + */
> > + if (port->fifosize > 48)
> > + rfr_level = port->fifosize - 16;
> > + else
> > + rfr_level = port->fifosize;
> > +
> > + spin_lock_irqsave(&port->lock, flags);
> > +
> > + /* set automatic RFR level */
> > + data = msm_hsl_read(port, UARTDM_MR1);
> > + data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK;
> > + data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK;
> > + data |= UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2);
> > + data |= UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level;
> > + msm_hsl_write(port, data, UARTDM_MR1);
> > + spin_unlock_irqrestore(&port->lock, flags);
> > +
> > + ret = request_irq(port->irq, msm_hsl_irq, IRQF_TRIGGER_HIGH,
> > + hslp->name, port);
> > + if (ret)
> > + dev_err(port->dev, "Failed to request irq\n");
> > +
> > + return ret;
> > +}
> > +
> > +static void msm_hsl_shutdown(struct uart_port *port)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > +
> > + hslp->imr = 0;
> > + /* disable interrupts */
> > + msm_hsl_write(port, 0, UARTDM_IMR);
> > +
> > + free_irq(port->irq, port);
> > +}
> > +
> > +static void msm_hsl_set_termios(struct uart_port *port,
> > + struct ktermios *termios, struct ktermios *old)
> > +{
> > + unsigned int baud, mr;
> > + unsigned long flags;
> > +
> > + if (!termios->c_cflag)
> > + return;
> > +
> > + /*
> > + * Calculate and set baud rate
> > + * 300 is the minimum and 4 Mbps is the maximum baud rate
> > + * supported by driver.
> > + */
> > + baud = uart_get_baud_rate(port, termios, old, 200, 4000000);
> > +
> > + /*
> > + * Due to non-availability of 3.2 Mbps baud rate as standard baud rate
> > + * with TTY/serial core. Map 200 BAUD to 3.2 Mbps
> > + */
> > + if (baud == 200)
> > + baud = 3200000;
> > +
> > + spin_lock_irqsave(&port->lock, flags);
> > +
> > + msm_hsl_set_baud_rate(port, baud);
> > +
> > + /* calculate parity */
> > + mr = msm_hsl_read(port, UARTDM_MR2);
> > + mr &= ~UARTDM_MR2_PARITY_MODE_BMSK;
> > + if (termios->c_cflag & PARENB) {
> > + if (termios->c_cflag & PARODD)
> > + mr |= ODD_PARITY;
> > + else if (termios->c_cflag & CMSPAR)
> > + mr |= SPACE_PARITY;
> > + else
> > + mr |= EVEN_PARITY;
> > + }
> > +
> > + /* calculate bits per char */
> > + mr &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK;
> > + switch (termios->c_cflag & CSIZE) {
> > + case CS5:
> > + mr |= FIVE_BPC;
> > + break;
> > + case CS6:
> > + mr |= SIX_BPC;
> > + break;
> > + case CS7:
> > + mr |= SEVEN_BPC;
> > + break;
> > + case CS8:
> > + default:
> > + mr |= EIGHT_BPC;
> > + break;
> > + }
> > +
> > + /* calculate stop bits */
> > + mr &= ~(STOP_BIT_ONE | STOP_BIT_TWO);
> > + if (termios->c_cflag & CSTOPB)
> > + mr |= STOP_BIT_TWO;
> > + else
> > + mr |= STOP_BIT_ONE;
> > +
> > + /* set parity, bits per char, and stop bit */
> > + msm_hsl_write(port, mr, UARTDM_MR2);
> > +
> > + /* calculate and set hardware flow control */
> > + mr = msm_hsl_read(port, UARTDM_MR1);
> > + mr &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK);
> > + if (termios->c_cflag & CRTSCTS) {
> > + mr |= UARTDM_MR1_CTS_CTL_BMSK;
> > + mr |= UARTDM_MR1_RX_RDY_CTL_BMSK;
> > + }
> > + msm_hsl_write(port, mr, UARTDM_MR1);
> > +
> > + /* Configure status bits to ignore based on termio flags. */
> > + port->read_status_mask = 0;
> > + if (termios->c_iflag & INPCK)
> > + port->read_status_mask |= UARTDM_SR_PAR_FRAME_BMSK;
> > + if (termios->c_iflag & (BRKINT | PARMRK))
> > + port->read_status_mask |= UARTDM_SR_RX_BREAK_BMSK;
> > +
> > + uart_update_timeout(port, termios->c_cflag, baud);
> > +
> > + spin_unlock_irqrestore(&port->lock, flags);
> > +}
> > +
> > +static const char *msm_hsl_type(struct uart_port *port)
> > +{
> > + return "MSM";
> > +}
> > +
> > +static void msm_hsl_release_port(struct uart_port *port)
> > +{
> > +}
> > +
> > +static int msm_hsl_request_port(struct uart_port *port)
> > +{
> > + return 0;
> > +}
> > +
> > +static void msm_hsl_config_port(struct uart_port *port, int flags)
> > +{
> > + if (flags & UART_CONFIG_TYPE)
> > + port->type = PORT_MSM;
> > +
> > + /* Configure required GSBI based UART protocol. */
> > + if (msm_serial_hsl_has_gsbi(port))
> > + set_gsbi_uart_func_mode(port);
> > +}
> > +
> > +static int msm_hsl_verify_port(struct uart_port *port,
> > + struct serial_struct *ser)
> > +{
> > + if (ser->type != PORT_UNKNOWN && ser->type != PORT_MSM)
> > + return -EINVAL;
> > + if (port->irq != ser->irq)
> > + return -EINVAL;
> > + return 0;
> > +}
> > +
> > +static void msm_hsl_power(struct uart_port *port, unsigned int state,
> > + unsigned int oldstate)
> > +{
> > + struct msm_hsl_port *hslp = to_hsl_port(port);
> > + int ret;
> > +
> > + switch (state) {
> > + case UART_PM_STATE_ON:
> > + ret = clk_set_rate(hslp->clk, port->uartclk);
> > + if (ret)
> > + dev_err(port->dev, "Can't change rate to %u\n",
> > + port->uartclk);
> > + msm_hsl_clock_enable(port, 1);
> > + break;
> > + case UART_PM_STATE_OFF:
> > + msm_hsl_clock_enable(port, 0);
> > + break;
> > + default:
> > + dev_err(port->dev, "Unknown PM state %d\n", state);
> > + }
> > +}
> > +
> > +static struct uart_ops msm_hsl_uart_pops = {
> > + .tx_empty = msm_hsl_tx_empty,
> > + .set_mctrl = msm_hsl_set_mctrl,
> > + .get_mctrl = msm_hsl_get_mctrl,
> > + .stop_tx = msm_hsl_stop_tx,
> > + .start_tx = msm_hsl_start_tx,
> > + .stop_rx = msm_hsl_stop_rx,
> > + .enable_ms = msm_hsl_enable_ms,
> > + .break_ctl = msm_hsl_break_ctl,
> > + .startup = msm_hsl_startup,
> > + .shutdown = msm_hsl_shutdown,
> > + .set_termios = msm_hsl_set_termios,
> > + .type = msm_hsl_type,
> > + .release_port = msm_hsl_release_port,
> > + .request_port = msm_hsl_request_port,
> > + .config_port = msm_hsl_config_port,
> > + .verify_port = msm_hsl_verify_port,
> > + .pm = msm_hsl_power,
> > +};
> > +
> > +#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
> > +
> > +static struct msm_hsl_port *msm_hsl_uart_ports[UART_NR];
> > +
> > +static void msm_hsl_console_putchar(struct uart_port *port, int ch)
> > +{
> > + msm_hsl_wait_for_xmitr(port);
> > + msm_hsl_write(port, 1, UARTDM_NCF_TX);
> > + /*
> > + * Dummy read to add 1 AHB clock delay to fix UART hardware bug.
> > + * Bug: Delay required on TX-transfer-init. after writing to
> > + * NO_CHARS_FOR_TX register.
> > + */
> > + msm_hsl_read(port, UARTDM_SR);
> > + msm_hsl_write(port, ch, UARTDM_TF);
> > +}
> > +
> > +static void msm_hsl_console_write(struct console *co, const char *s,
> > + unsigned int count)
> > +{
> > + struct uart_port *port;
> > + struct msm_hsl_port *hslp;
> > + int locked;
> > +
> > + BUG_ON(co->index < 0 || co->index >= UART_NR);
> > +
> > + hslp = msm_hsl_uart_ports[co->index];
> > + port = &hslp->uart;
> > +
> > + /* not pretty, but we can end up here via various convoluted paths */
> > + if (port->sysrq || oops_in_progress)
> > + locked = spin_trylock(&port->lock);
> > + else {
> > + locked = 1;
> > + spin_lock(&port->lock);
> > + }
> > + msm_hsl_write(port, 0, UARTDM_IMR);
> > + uart_console_write(port, s, count, msm_hsl_console_putchar);
> > + msm_hsl_write(port, hslp->imr, UARTDM_IMR);
> > + if (locked == 1)
> > + spin_unlock(&port->lock);
> > +}
> > +
> > +static int msm_hsl_console_setup(struct console *co, char *options)
> > +{
> > + struct uart_port *port;
> > + int baud = 0, flow, bits, parity, mr2;
> > + int ret;
> > +
> > + if (co->index >= UART_NR || co->index < 0)
> > + return -ENXIO;
> > +
> > + port = &msm_hsl_uart_ports[co->index]->uart;
> > +
> > + if (!port->membase)
> > + return -ENXIO;
> > +
> > + port->cons = co;
> > +
> > + pm_runtime_get_noresume(port->dev);
> > +
> > +#ifndef CONFIG_PM_RUNTIME
> > + msm_hsl_clock_enable(port, 1);
> > +#endif
> > + pm_runtime_resume(port->dev);
> > +
> > + if (options)
> > + uart_parse_options(options, &baud, &parity, &bits, &flow);
> > +
> > + bits = 8;
> > + parity = 'n';
> > + flow = 'n';
> > + msm_hsl_write(port, UARTDM_MR2_BITS_PER_CHAR_8 |
> > + STOP_BIT_ONE, UARTDM_MR2); /* 8N1 */
> > +
> > + if (baud < 300 || baud > 115200)
> > + baud = 115200;
> > +
> > + msm_hsl_set_baud_rate(port, baud);
> > +
> > + ret = uart_set_options(port, co, baud, parity, bits, flow);
> > +
> > + mr2 = msm_hsl_read(port, UARTDM_MR2);
> > + mr2 |= UARTDM_MR2_RX_ERROR_CHAR_OFF;
> > + mr2 |= UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF;
> > + msm_hsl_write(port, mr2, UARTDM_MR2);
> > +
> > + msm_hsl_reset(port);
> > + /* Enable transmitter */
> > + msm_hsl_write(port, CR_PROTECTION_EN, UARTDM_CR);
> > + msm_hsl_write(port, UARTDM_CR_TX_EN_BMSK, UARTDM_CR);
> > +
> > + msm_hsl_write(port, 1, UARTDM_NCF_TX);
> > + msm_hsl_read(port, UARTDM_NCF_TX);
> > +
> > + dev_dbg(port->dev, "Console setup on port #%d\n", port->line);
> > +
> > + return ret;
> > +}
> > +
> > +static struct uart_driver msm_hsl_uart_driver;
> > +
> > +static struct console msm_hsl_console = {
> > + .name = "ttyHSL",
> > + .write = msm_hsl_console_write,
> > + .device = uart_console_device,
> > + .setup = msm_hsl_console_setup,
> > + .flags = CON_PRINTBUFFER,
> > + .index = -1,
> > + .data = &msm_hsl_uart_driver,
> > +};
> > +
> > +#define MSM_HSL_CONSOLE (&msm_hsl_console)
> > +
> > +#else
> > +#define MSM_HSL_CONSOLE NULL
> > +#endif
> > +
> > +static struct uart_driver msm_hsl_uart_driver = {
> > + .owner = THIS_MODULE,
> > + .driver_name = "msm_serial_hsl",
> > + .dev_name = "ttyHSL",
> > + .nr = UART_NR,
> > + .cons = MSM_HSL_CONSOLE,
> > +};
> > +
> > +static struct dentry *debug_base;
> > +
> > +DEFINE_SIMPLE_ATTRIBUTE(loopback_enable_fops, msm_hsl_loopback_get,
> > + msm_hsl_loopback_set, "%llu\n");
> > +/*
> > + * msm_serial_hsl debugfs node: <debugfs_root>/msm_serial_hsl/loopback.<id>
> > + * writing 1 turns on internal loopback mode in HW. Useful for automation
> > + * test scripts.
> > + * writing 0 disables the internal loopback mode. Default is disabled.
> > + */
> > +static void msm_hsl_debugfs_init(struct msm_hsl_port *hslp, int id)
> > +{
> > + char node_name[15];
> > +
> > + snprintf(node_name, sizeof(node_name), "loopback.%d", id);
> > + hslp->loopback_dir = debugfs_create_file(node_name,
> > + S_IRUGO | S_IWUSR,
> > + debug_base, hslp,
> > + &loopback_enable_fops);
> > +}
> > +
> > +static atomic_t msm_serial_hsl_next_id = ATOMIC_INIT(0);
> > +
> > +static struct of_device_id msm_hsl_match_table[] = {
> > + {.compatible = "qcom,msm-lsuart-v14"},
> > + { /* Sentinel */ }
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, msm_hsl_match_table);
> > +
> > +static int msm_serial_hsl_probe(struct platform_device *pdev)
> > +{
> > + struct device_node *node = pdev->dev.of_node;
> > + struct msm_hsl_port *hslp;
> > + struct resource *mem;
> > + struct uart_port *port;
> > + const struct of_device_id *match;
> > + u32 line;
> > + int ret;
> > +
> > + if (pdev->id == -1)
> > + pdev->id = atomic_inc_return(&msm_serial_hsl_next_id) - 1;
> > +
> > + line = pdev->id;
> > +
> > + /* Use line number from device tree alias if present */
> > + if (!node)
> > + return -EINVAL;
> > +
> > + ret = of_alias_get_id(node, "serial");
> > + if (ret >= 0)
> > + line = ret;
> > +
> > + if (line < 0 || line >= UART_NR)
> > + return -ENXIO;
> > +
> > + pr_info("detected port #%d (ttyHSL%d)\n", pdev->id, line);
> > +
> > + hslp = devm_kzalloc(&pdev->dev, sizeof(*hslp), GFP_KERNEL);
> > + if (!hslp)
> > + return -ENOMEM;
> > +
> > + port = &hslp->uart;
> > + port->dev = &pdev->dev;
> > + port->uartclk = 7372800;
> > + port->iotype = UPIO_MEM;
> > + port->ops = &msm_hsl_uart_pops;
> > + port->flags = UPF_BOOT_AUTOCONF;
> > + port->fifosize = 64;
> > + port->line = line;
> > +
> > + hslp->clk = devm_clk_get(&pdev->dev, "core_clk");
> > + if (IS_ERR(hslp->clk)) {
> > + ret = PTR_ERR(hslp->clk);
> > + if (ret != -EPROBE_DEFER)
> > + dev_err(&pdev->dev, "Error getting core clk\n");
> > + return ret;
> > + }
> > +
> > + /*
> > + * Interface clock is not required by all UART configurations.
> > + * GSBI UART and BLSP UART needs interface clock but Legacy UART
> > + * do not require interface clock. Hence, do not fail probe with
> > + * iface of_clk_get_by_name failure.
> > + */
> > + hslp->pclk = devm_clk_get(&pdev->dev, "iface_clk");
> > + if (IS_ERR(hslp->pclk)) {
> > + ret = PTR_ERR(hslp->pclk);
> > + if (ret == -EPROBE_DEFER)
> > + return ret;
> > + else
> > + hslp->pclk = NULL;
> > + }
> > +
> > + hslp->uart_type = LEGACY_HSUART;
> > +
> > + match = of_match_device(msm_hsl_match_table, &pdev->dev);
> > + if (!match) {
> > + hslp->regmap = regmap[UARTDM_VERSION_11_13];
>
> how would we ever get here?
There is no way, of course. I will fix this by adding new
compatible = qcom,msm-lsuart-v1.3 field in the match table.
Thank you for your comments.
Regards,
Ivan
>
> > + } else {
> > + hslp->regmap = regmap[UARTDM_VERSION_14];
> > + /*
> > + * BLSP based UART configuration is available with
> > + * UARTDM v14 Revision. Hence set uart_type as UART_BLSP.
> > + */
> > + hslp->uart_type = BLSP_HSUART;
> > + }
> > +
> > + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gbsi_mem");
> > + if (mem) {
> > + hslp->mapped_gsbi = devm_request_and_ioremap(&pdev->dev, mem);
> > + if (!hslp->mapped_gsbi)
> > + dev_warn(&pdev->dev, "GSBI region already claimed\n");
> > + else
> > + hslp->uart_type = GSBI_HSUART;
> > + }
> > +
> > + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uart_mem");
> > + if (!mem) {
> > + dev_err(&pdev->dev, "Getting UART mem failed\n");
> > + return -ENXIO;
> > + }
> > +
> > + port->mapbase = mem->start;
> > +
> > + port->irq = platform_get_irq(pdev, 0);
> > + if ((int)port->irq < 0) {
> > + dev_err(&pdev->dev, "Getting irq failed\n");
> > + return -ENXIO;
> > + }
> > +
> > + port->membase = devm_request_and_ioremap(&pdev->dev, mem);
> > + if (!port->membase) {
> > + dev_err(&pdev->dev, "UART region already claimed\n");
> > + return -EADDRNOTAVAIL;
> > + }
> > +
> > + device_set_wakeup_capable(&pdev->dev, 1);
> > + platform_set_drvdata(pdev, port);
> > + pm_runtime_enable(port->dev);
> > +#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
> > + msm_hsl_uart_ports[line] = hslp;
> > +#endif
> > + msm_hsl_debugfs_init(hslp, hslp->uart.line);
> > +
> > + /* Temporarily increase the refcount on the GSBI clock to avoid a race
> > + * condition with the earlyprintk handover mechanism.
> > + */
> > + if (hslp->pclk)
> > + clk_prepare_enable(hslp->pclk);
> > + ret = uart_add_one_port(&msm_hsl_uart_driver, port);
> > + if (hslp->pclk)
> > + clk_disable_unprepare(hslp->pclk);
> > +
> > + if (!ret)
> > + platform_set_drvdata(pdev, hslp);
> > +
> > + return ret;
> > +}
> > +
> > +static int msm_serial_hsl_remove(struct platform_device *pdev)
> > +{
> > + struct msm_hsl_port *hslp = platform_get_drvdata(pdev);
> > + struct uart_port *port;
> > +
> > + port = &hslp->uart;
> > +
> > + pm_runtime_put_sync(&pdev->dev);
> > + pm_runtime_disable(&pdev->dev);
> > +
> > + device_set_wakeup_capable(&pdev->dev, 0);
> > + platform_set_drvdata(pdev, NULL);
> > +
> > + uart_remove_one_port(&msm_hsl_uart_driver, port);
> > +
> > + debugfs_remove(hslp->loopback_dir);
> > + return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +static int msm_serial_hsl_suspend(struct device *dev)
> > +{
> > + struct msm_hsl_port *hslp = dev_get_drvdata(dev);
> > + struct uart_port *port;
> > +
> > + port = &hslp->uart;
> > +
> > + if (port)
> > + return 0;
> > +
> > + if (is_console(port))
> > + msm_hsl_clock_enable(port, 0);
> > +
> > + uart_suspend_port(&msm_hsl_uart_driver, port);
> > + if (device_may_wakeup(dev))
> > + enable_irq_wake(port->irq);
> > +
> > + return 0;
> > +}
> > +
> > +static int msm_serial_hsl_resume(struct device *dev)
> > +{
> > + struct msm_hsl_port *hslp = dev_get_drvdata(dev);
> > + struct uart_port *port;
> > +
> > + port = &hslp->uart;
> > +
> > + if (!port)
> > + return 0;
> > +
> > + uart_resume_port(&msm_hsl_uart_driver, port);
> > + if (device_may_wakeup(dev))
> > + disable_irq_wake(port->irq);
> > +
> > + if (is_console(port))
> > + msm_hsl_clock_enable(port, 1);
> > +
> > + return 0;
> > +}
> > +#else
> > +#define msm_serial_hsl_suspend NULL
> > +#define msm_serial_hsl_resume NULL
> > +#endif
> > +
> > +static int msm_hsl_runtime_suspend(struct device *dev)
> > +{
> > + struct msm_hsl_port *hslp = dev_get_drvdata(dev);
> > + struct uart_port *port;
> > +
> > + port = &hslp->uart;
> > +
> > + dev_dbg(dev, "pm_runtime: suspending\n");
> > + msm_hsl_clock_enable(port, 0);
> > + return 0;
> > +}
> > +
> > +static int msm_hsl_runtime_resume(struct device *dev)
> > +{
> > + struct msm_hsl_port *hslp = dev_get_drvdata(dev);
> > + struct uart_port *port;
> > +
> > + port = &hslp->uart;
> > +
> > + dev_dbg(dev, "pm_runtime: resuming\n");
> > + msm_hsl_clock_enable(port, 1);
> > + return 0;
> > +}
> > +
> > +static const struct dev_pm_ops msm_hsl_dev_pm_ops = {
> > + .suspend = msm_serial_hsl_suspend,
> > + .resume = msm_serial_hsl_resume,
> > + .runtime_suspend = msm_hsl_runtime_suspend,
> > + .runtime_resume = msm_hsl_runtime_resume,
> > +};
> > +
> > +static struct platform_driver msm_hsl_platform_driver = {
> > + .probe = msm_serial_hsl_probe,
> > + .remove = msm_serial_hsl_remove,
> > + .driver = {
> > + .name = "msm_serial_hsl",
> > + .owner = THIS_MODULE,
> > + .pm = &msm_hsl_dev_pm_ops,
> > + .of_match_table = msm_hsl_match_table,
> > + },
> > +};
> > +
> > +static int __init msm_serial_hsl_init(void)
> > +{
> > + int ret;
> > +
> > + ret = uart_register_driver(&msm_hsl_uart_driver);
> > + if (ret)
> > + return ret;
> > +
> > + debug_base = debugfs_create_dir("msm_serial_hsl", NULL);
> > + if (IS_ERR_OR_NULL(debug_base))
> > + pr_err("Cannot create debugfs dir\n");
> > +
> > + ret = platform_driver_register(&msm_hsl_platform_driver);
> > + if (ret)
> > + uart_unregister_driver(&msm_hsl_uart_driver);
> > +
> > + pr_debug("Driver initialized\n");
> > + return ret;
> > +}
> > +
> > +static void __exit msm_serial_hsl_exit(void)
> > +{
> > + debugfs_remove_recursive(debug_base);
> > +#ifdef CONFIG_SERIAL_MSM_HSL_CONSOLE
> > + unregister_console(&msm_hsl_console);
> > +#endif
> > + platform_driver_unregister(&msm_hsl_platform_driver);
> > + uart_unregister_driver(&msm_hsl_uart_driver);
> > +}
> > +
> > +module_init(msm_serial_hsl_init);
> > +module_exit(msm_serial_hsl_exit);
> > +
> > +MODULE_DESCRIPTION("Driver for MSM HSUART UART serial device");
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/drivers/tty/serial/msm_serial_hsl.h b/drivers/tty/serial/msm_serial_hsl.h
> > new file mode 100644
> > index 0000000..beb97d4
> > --- /dev/null
> > +++ b/drivers/tty/serial/msm_serial_hsl.h
> > @@ -0,0 +1,294 @@
> > +/* drivers/tty/serial/msm_serial_hsl.h
> > + *
> > + * Copyright (c) 2007-2009, 2012-2013,The Linux Foundation. All rights reserved.
> > + *
> > + * All source code in this file is licensed under the following license
> > + * except where indicated.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2 as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> > + * See the GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, you can find it at http://www.fsf.org
> > + */
> > +
> > +#ifndef MSM_SERIAL_HSL_H
> > +#define MSM_SERIAL_HSL_H
> > +
> > +#define GSBI_CONTROL_ADDR 0x0
> > +#define GSBI_PROTOCOL_CODE_MASK 0x30
> > +#define GSBI_PROTOCOL_I2C_UART 0x60
> > +#define GSBI_PROTOCOL_UART 0x40
> > +#define GSBI_PROTOCOL_IDLE 0x0
> > +
> > +#define TCSR_ADM_1_A_CRCI_MUX_SEL 0x78
> > +#define TCSR_ADM_1_B_CRCI_MUX_SEL 0x7c
> > +#define ADM1_CRCI_GSBI6_RX_SEL 0x800
> > +#define ADM1_CRCI_GSBI6_TX_SEL 0x400
> > +
> > +enum msm_hsl_regs {
> > + UARTDM_MR1,
> > + UARTDM_MR2,
> > + UARTDM_IMR,
> > + UARTDM_SR,
> > + UARTDM_CR,
> > + UARTDM_CSR,
> > + UARTDM_IPR,
> > + UARTDM_ISR,
> > + UARTDM_RX_TOTAL_SNAP,
> > + UARTDM_RFWR,
> > + UARTDM_TFWR,
> > + UARTDM_RF,
> > + UARTDM_TF,
> > + UARTDM_MISR,
> > + UARTDM_DMRX,
> > + UARTDM_NCF_TX,
> > + UARTDM_DMEN,
> > + UARTDM_BCR,
> > + UARTDM_TXFS,
> > + UARTDM_RXFS,
> > + UARTDM_LAST,
> > +};
> > +
> > +#define UARTDM_MR1_ADDR 0x0
> > +#define UARTDM_MR2_ADDR 0x4
> > +
> > +/* Backward Compatability Register for UARTDM Core v1.4 */
> > +#define UARTDM_BCR_ADDR 0xc8
> > +
> > +/*
> > + * UARTDM Core v1.4 STALE_IRQ_EMPTY bit defination
> > + * Stale interrupt will fire if bit is set when RX-FIFO is empty
> > + */
> > +#define UARTDM_BCR_STALE_IRQ_EMPTY 0x2
> > +
> > +/* TRANSFER_CONTROL Register for UARTDM Core v1.4 */
> > +#define UARTDM_RX_TRANS_CTRL_ADDR 0xcc
> > +
> > +/* TRANSFER_CONTROL Register bits */
> > +#define RX_STALE_AUTO_RE_EN 0x1
> > +#define RX_TRANS_AUTO_RE_ACTIVATE 0x2
> > +#define RX_DMRX_CYCLIC_EN 0x4
> > +
> > +/* write only register */
> > +#define UARTDM_IPR_ADDR 0x18
> > +#define UARTDM_TFWR_ADDR 0x1c
> > +#define UARTDM_RFWR_ADDR 0x20
> > +#define UARTDM_HCR_ADDR 0x24
> > +#define UARTDM_DMRX_ADDR 0x34
> > +#define UARTDM_DMEN_ADDR 0x3c
> > +
> > +/* UART_DM_NO_CHARS_FOR_TX */
> > +#define UARTDM_NCF_TX_ADDR 0x40
> > +
> > +#define UARTDM_BADR_ADDR 0x44
> > +
> > +#define UARTDM_SIM_CFG_ADDR 0x80
> > +
> > +/* Read Only register */
> > +#define UARTDM_TXFS_ADDR 0x4c
> > +#define UARTDM_RXFS_ADDR 0x50
> > +
> > +/* Register field Mask Mapping */
> > +#define UARTDM_SR_RX_BREAK_BMSK BIT(6)
> > +#define UARTDM_SR_PAR_FRAME_BMSK BIT(5)
> > +#define UARTDM_SR_OVERRUN_BMSK BIT(4)
> > +#define UARTDM_SR_TXEMT_BMSK BIT(3)
> > +#define UARTDM_SR_TXRDY_BMSK BIT(2)
> > +#define UARTDM_SR_RXRDY_BMSK BIT(0)
> > +
> > +#define UARTDM_CR_TX_DISABLE_BMSK BIT(3)
> > +#define UARTDM_CR_RX_DISABLE_BMSK BIT(1)
> > +#define UARTDM_CR_TX_EN_BMSK BIT(2)
> > +#define UARTDM_CR_RX_EN_BMSK BIT(0)
> > +
> > +/* UARTDM_CR channel_comman bit value (register field is bits 8:4) */
> > +#define RESET_RX 0x10
> > +#define RESET_TX 0x20
> > +#define RESET_ERROR_STATUS 0x30
> > +#define RESET_BREAK_INT 0x40
> > +#define START_BREAK 0x50
> > +#define STOP_BREAK 0x60
> > +#define RESET_CTS 0x70
> > +#define RESET_STALE_INT 0x80
> > +#define RFR_LOW 0xD0
> > +#define RFR_HIGH 0xE0
> > +#define CR_PROTECTION_EN 0x100
> > +#define STALE_EVENT_ENABLE 0x500
> > +#define STALE_EVENT_DISABLE 0x600
> > +#define FORCE_STALE_EVENT 0x400
> > +#define CLEAR_TX_READY 0x300
> > +#define RESET_TX_ERROR 0x800
> > +#define RESET_TX_DONE 0x810
> > +
> > +/*
> > + * UARTDM_CR BAM IFC comman bit value
> > + * for UARTDM Core v1.4
> > + */
> > +#define START_RX_BAM_IFC 0x850
> > +#define START_TX_BAM_IFC 0x860
> > +
> > +#define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00
> > +#define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f
> > +#define UARTDM_MR1_CTS_CTL_BMSK 0x40
> > +#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80
> > +
> > +/*
> > + * UARTDM Core v1.4 MR2_RFR_CTS_LOOP bitmask
> > + * Enables internal loopback between RFR_N of
> > + * RX channel and CTS_N of TX channel.
> > + */
> > +#define UARTDM_MR2_RFR_CTS_LOOP_MODE_BMSK 0x400
> > +
> > +#define UARTDM_MR2_LOOP_MODE_BMSK 0x80
> > +#define UARTDM_MR2_ERROR_MODE_BMSK 0x40
> > +#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30
> > +#define UARTDM_MR2_RX_ZERO_CHAR_OFF 0x100
> > +#define UARTDM_MR2_RX_ERROR_CHAR_OFF 0x200
> > +#define UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF 0x100
> > +
> > +#define UARTDM_MR2_BITS_PER_CHAR_8 (0x3 << 4)
> > +
> > +/* bits per character configuration */
> > +#define FIVE_BPC (0 << 4)
> > +#define SIX_BPC (1 << 4)
> > +#define SEVEN_BPC (2 << 4)
> > +#define EIGHT_BPC (3 << 4)
> > +
> > +#define UARTDM_MR2_STOP_BIT_LEN_BMSK 0xc
> > +#define STOP_BIT_ONE (1 << 2)
> > +#define STOP_BIT_TWO (3 << 2)
> > +
> > +#define UARTDM_MR2_PARITY_MODE_BMSK 0x3
> > +
> > +/* Parity configuration */
> > +#define NO_PARITY 0x0
> > +#define EVEN_PARITY 0x2
> > +#define ODD_PARITY 0x1
> > +#define SPACE_PARITY 0x3
> > +
> > +#define UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK 0xffffff80
> > +#define UARTDM_IPR_STALE_LSB_BMSK 0x1f
> > +
> > +/* These can be used for both ISR and IMR register */
> > +#define UARTDM_ISR_TX_READY_BMSK BIT(7)
> > +#define UARTDM_ISR_CURRENT_CTS_BMSK BIT(6)
> > +#define UARTDM_ISR_DELTA_CTS_BMSK BIT(5)
> > +#define UARTDM_ISR_RXLEV_BMSK BIT(4)
> > +#define UARTDM_ISR_RXSTALE_BMSK BIT(3)
> > +#define UARTDM_ISR_RXBREAK_BMSK BIT(2)
> > +#define UARTDM_ISR_RXHUNT_BMSK BIT(1)
> > +#define UARTDM_ISR_TXLEV_BMSK BIT(0)
> > +
> > +/* Field definitions for UART_DM_DMEN*/
> > +#define UARTDM_TX_DM_EN_BMSK 0x1
> > +#define UARTDM_RX_DM_EN_BMSK 0x2
> > +
> > +/*
> > + * UARTDM Core v1.4 bitmask
> > + * Bitmasks for enabling Rx and Tx BAM Interface
> > + */
> > +#define UARTDM_TX_BAM_ENABLE_BMSK 0x4
> > +#define UARTDM_RX_BAM_ENABLE_BMSK 0x8
> > +
> > +/*
> > + * Some of the BLSP Based UART Core(v14) existing register offsets
> > + * are different compare to GSBI based UART Core(v13)
> > + * Hence add the changed register offsets for UART Core v14
> > + */
> > +
> > +/* write only register */
> > +#define UARTDM_CSR_ADDR_V14 0xa0
> > +
> > +/* write only register */
> > +#define UARTDM_TF_ADDR_V14 0x100
> > +#define UARTDM_TF2_ADDR_V14 0x104
> > +#define UARTDM_TF3_ADDR_V14 0x108
> > +#define UARTDM_TF4_ADDR_V14 0x10c
> > +#define UARTDM_TF5_ADDR_V14 0x110
> > +#define UARTDM_TF6_ADDR_V14 0x114
> > +#define UARTDM_TF7_ADDR_V14 0x118
> > +#define UARTDM_TF8_ADDR_V14 0x11c
> > +#define UARTDM_TF9_ADDR_V14 0x120
> > +#define UARTDM_TF10_ADDR_V14 0x124
> > +#define UARTDM_TF11_ADDR_V14 0x128
> > +#define UARTDM_TF12_ADDR_V14 0x12c
> > +#define UARTDM_TF13_ADDR_V14 0x130
> > +#define UARTDM_TF14_ADDR_V14 0x134
> > +#define UARTDM_TF15_ADDR_V14 0x138
> > +#define UARTDM_TF16_ADDR_V14 0x13c
> > +
> > +/* write only register */
> > +#define UARTDM_CR_ADDR_V14 0xa8
> > +/* write only register */
> > +#define UARTDM_IMR_ADDR_V14 0xb0
> > +#define UARTDM_IRDA_ADDR_V14 0xb8
> > +
> > +/* Read Only register */
> > +#define UARTDM_SR_ADDR_V14 0xa4
> > +
> > +/* Read Only register */
> > +#define UARTDM_RF_ADDR_V14 0x140
> > +#define UARTDM_RF2_ADDR_V14 0x144
> > +#define UARTDM_RF3_ADDR_V14 0x148
> > +#define UARTDM_RF4_ADDR_V14 0x14c
> > +#define UARTDM_RF5_ADDR_V14 0x150
> > +#define UARTDM_RF6_ADDR_V14 0x154
> > +#define UARTDM_RF7_ADDR_V14 0x158
> > +#define UARTDM_RF8_ADDR_V14 0x15c
> > +#define UARTDM_RF9_ADDR_V14 0x160
> > +#define UARTDM_RF10_ADDR_V14 0x164
> > +#define UARTDM_RF11_ADDR_V14 0x168
> > +#define UARTDM_RF12_ADDR_V14 0x16c
> > +#define UARTDM_RF13_ADDR_V14 0x170
> > +#define UARTDM_RF14_ADDR_V14 0x174
> > +#define UARTDM_RF15_ADDR_V14 0x178
> > +#define UARTDM_RF16_ADDR_V14 0x17c
> > +
> > +/* Read Only register */
> > +#define UARTDM_MISR_ADDR_V14 0xac
> > +
> > +/* Read Only register */
> > +#define UARTDM_ISR_ADDR_V14 0xb4
> > +#define UARTDM_RX_TOTAL_SNAP_ADDR_V14 0xbc
> > +
> > +/* Register offsets for UART Core v13 */
> > +
> > +/* write only register */
> > +#define UARTDM_CSR_ADDR 0x8
> > +
> > +/* write only register */
> > +#define UARTDM_TF_ADDR 0x70
> > +#define UARTDM_TF2_ADDR 0x74
> > +#define UARTDM_TF3_ADDR 0x78
> > +#define UARTDM_TF4_ADDR 0x7c
> > +
> > +/* write only register */
> > +#define UARTDM_CR_ADDR 0x10
> > +/* write only register */
> > +#define UARTDM_IMR_ADDR 0x14
> > +#define UARTDM_IRDA_ADDR 0x38
> > +
> > +/* Read Only register */
> > +#define UARTDM_SR_ADDR 0x8
> > +
> > +/* Read Only register */
> > +#define UARTDM_RF_ADDR 0x70
> > +#define UARTDM_RF2_ADDR 0x74
> > +#define UARTDM_RF3_ADDR 0x78
> > +#define UARTDM_RF4_ADDR 0x7c
> > +
> > +/* Read Only register */
> > +#define UARTDM_MISR_ADDR 0x10
> > +
> > +/* Read Only register */
> > +#define UARTDM_ISR_ADDR 0x14
> > +#define UARTDM_RX_TOTAL_SNAP_ADDR 0x38
> > +
> > +#endif /* MSM_SERIAL_HSL_H */
> > --
> > 1.7.9.5
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> --
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
>
prev parent reply other threads:[~2013-07-17 7:39 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-01 9:11 [PATCH] tty: serial: Add initial MSM UART High Speed Lite driver Ivan T. Ivanov
2013-07-16 11:46 ` Ivan T. Ivanov
[not found] ` <76DBE056-CDFB-47A5-9AB5-239400A2D4F9@codeaurora.org>
2013-07-17 7:38 ` Ivan T. Ivanov [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1374046723.2657.27.camel@iivanov-dev \
--to=iivanov@mm-sol.com \
--cc=devicetree-discuss@lists.ozlabs.org \
--cc=galak@codeaurora.org \
--cc=grant.likely@linaro.org \
--cc=gregkh@linuxfoundation.org \
--cc=jslaby@suse.cz \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
--cc=mrana@codeaurora.org \
--cc=rob.herring@calxeda.com \
--cc=rob@landley.net \
--cc=sambley@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.