mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
Omap driver changes for v4.2 to switch drivers over to Linux generic
wake IRQ events for omap_hsmmc, 8250_omap and omap-serial drivers. The generic wake IRQs also fix issues that these drivers potentially have with IRQ re-entrancy at least for serial-omap. Note that because of dependencies and merge conflicts these are based on Rafael's pm-wakeirq and Greg's tty-next branches. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJVd97YAAoJEBvUPslcq6VzpikQAOAwwRMTdy9trxpNbGA+yI3W rmboPX/jp86PV5EywsD1VMMWWfd5toJawyC2GKJ7lpme9wdB6zpJZFkGxsxFkMXS peoeY5HyWHVT2gdeO8auT0GsxdN0U0SUlMz051aVdLz6DjajSVnKwFJpJvUNLgUx d3MCNoxQAxIad5G9LHhtMlZNvZXg8ibp6TGyEkQvUDz/V37J+22hxlbaAZ0/SiOo ymBZ8osCCHZvOLeyPogHxSkXcLP5cwGDOXzClZ76OCUKYIbcP8Y59ibb78S2cuOB UaOh4To1aKENYtE9B2QVcA6bbOPulwT2qAJvrt9poGFFOfi+jd2NZLQC13ia8EWG NrFFIcAm+dgrnhZedJVUGKGxrqpFKxUyoaRKO+FNvCJ8tu0xK7vBJLB+XLb5fdXY WeeVUv+GgQWPkzahJrXkEh/9syccVtM42+fXJW+cHH7jV2jDtSLCpWWW8lQ1u/dE VSHQCH+2f/vDeKd3u8Pe3FLhOA9jBfZTVM4simbZ4qecFBdPZKoLReiX4sY2S+39 2vBBdKHNwWQFtOb07nq/iLp0KKCLxVHVJKWSYQ2fNcyc5RNAAu+/iZx6WfFwdhW2 e5AAfXOvEHU1522vwY/V621N8low69MuST8zkPZ0aPXwyzQQ1A5WzqCQjqu5Sg8u 72Iie7TLuUqLSGnJXo2x =ocy8 -----END PGP SIGNATURE----- Merge tag 'omap-for-v4.2/wakeirq-drivers-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/late Merge "omap generic wakeirq for v4.2 merge window" from Tony Lindgren: Omap driver changes for v4.2 to switch drivers over to Linux generic wake IRQ events for omap_hsmmc, 8250_omap and omap-serial drivers. The generic wake IRQs also fix issues that these drivers potentially have with IRQ re-entrancy at least for serial-omap. Note that because of dependencies and merge conflicts these are based on Rafael's pm-wakeirq and Greg's tty-next branches. * tag 'omap-for-v4.2/wakeirq-drivers-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (148 commits) serial: 8250_omap: Move wake-up interrupt to generic wakeirq serial: omap: Switch wake-up interrupt to generic wakeirq tty: move linux/gsmmux.h to uapi doc: dt: add documentation for nxp,lpc1850-uart serial: 8250: add LPC18xx/43xx UART driver serial: 8250_uniphier: add UniPhier serial driver serial: 8250_dw: support ACPI platforms with integrated DMA engine serial: of_serial: check the return value of clk_prepare_enable() serial: of_serial: use devm_clk_get() instead of clk_get() serial: earlycon: Add support for big-endian MMIO accesses serial: sirf: use hrtimer for data rx serial: sirf: correct the fifo empty_bit serial: sirf: fix system hung on console log output serial: 8250: remove return statements from void function sc16is7xx: use kworker for RS-485 configuration sc16is7xx: use kworker to update ier bits sc16is7xx: use kworker for md_proc sc16is7xx: move RTS delay to workqueue sc16is7xx: use kthread_worker for tx_work and irq sc16is7xx: use LSR_TEMT_BIT in .tx_empty() ...
This commit is contained in:
commit
593aae2142
10
Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
Normal file
10
Documentation/devicetree/bindings/serial/arm_sbsa_uart.txt
Normal file
@ -0,0 +1,10 @@
|
||||
* ARM SBSA defined generic UART
|
||||
This UART uses a subset of the PL011 registers and consequently lives
|
||||
in the PL011 driver. It's baudrate and other communication parameters
|
||||
cannot be adjusted at runtime, so it lacks a clock specifier here.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "arm,sbsa-uart"
|
||||
- reg: exactly one register range
|
||||
- interrupts: exactly one interrupt specifier
|
||||
- current-speed: the (fixed) baud rate set by the firmware
|
@ -14,7 +14,14 @@ Required properties:
|
||||
|
||||
- interrupts: A single interrupt specifier.
|
||||
|
||||
- clocks: Clock driving the hardware.
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names:
|
||||
- "baud": The clock the baudrate is derived from
|
||||
- "bus": The bus clock for register accesses (optional)
|
||||
|
||||
For compatibility with older device trees an unnamed clock is used for the
|
||||
baud clock if the baudclk does not exist. Do not use this for new designs.
|
||||
|
||||
Example:
|
||||
|
||||
@ -22,5 +29,6 @@ Example:
|
||||
compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
|
||||
reg = <0x11006000 0x400>;
|
||||
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&uart_clk>;
|
||||
clocks = <&uart_clk>, <&bus_clk>;
|
||||
clock-names = "baud", "bus";
|
||||
};
|
||||
|
@ -0,0 +1,28 @@
|
||||
* NXP LPC1850 UART
|
||||
|
||||
Required properties:
|
||||
- compatible : "nxp,lpc1850-uart", "ns16550a".
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : should contain uart interrupt.
|
||||
- clocks : phandle to the input clocks.
|
||||
- clock-names : required elements: "uartclk", "reg".
|
||||
|
||||
Optional properties:
|
||||
- dmas : Two or more DMA channel specifiers following the
|
||||
convention outlined in bindings/dma/dma.txt
|
||||
- dma-names : Names for the dma channels, if present. There must
|
||||
be at least one channel named "tx" for transmit
|
||||
and named "rx" for receive.
|
||||
|
||||
Since it's also possible to also use the of_serial.c driver all
|
||||
parameters from 8250.txt also apply but are optional.
|
||||
|
||||
Example:
|
||||
uart0: serial@40081000 {
|
||||
compatible = "nxp,lpc1850-uart", "ns16550a";
|
||||
reg = <0x40081000 0x1000>;
|
||||
reg-shift = <2>;
|
||||
interrupts = <24>;
|
||||
clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>;
|
||||
clock-names = "uartclk", "reg";
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
* NXP SC16IS7xx advanced Universal Asynchronous Receiver-Transmitter (UART)
|
||||
* i2c as bus
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
@ -31,3 +32,39 @@ Example:
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
* spi as bus
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
- "nxp,sc16is740" for NXP SC16IS740,
|
||||
- "nxp,sc16is741" for NXP SC16IS741,
|
||||
- "nxp,sc16is750" for NXP SC16IS750,
|
||||
- "nxp,sc16is752" for NXP SC16IS752,
|
||||
- "nxp,sc16is760" for NXP SC16IS760,
|
||||
- "nxp,sc16is762" for NXP SC16IS762.
|
||||
- reg: SPI chip select number.
|
||||
- interrupt-parent: The phandle for the interrupt controller that
|
||||
services interrupts for this IC.
|
||||
- interrupts: Specifies the interrupt source of the parent interrupt
|
||||
controller. The format of the interrupt specifier depends on the
|
||||
parent interrupt controller.
|
||||
- clocks: phandle to the IC source clock.
|
||||
|
||||
Optional properties:
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be two. The first cell is the GPIO number and
|
||||
the second cell is used to specify the GPIO polarity:
|
||||
0 = active high,
|
||||
1 = active low.
|
||||
|
||||
Example:
|
||||
sc16is750: sc16is750@0 {
|
||||
compatible = "nxp,sc16is750";
|
||||
reg = <0>;
|
||||
clocks = <&clk20m>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
@ -44,6 +44,11 @@ Required properties:
|
||||
Note: Each enabled SCIx UART should have an alias correctly numbered in the
|
||||
"aliases" node.
|
||||
|
||||
Optional properties:
|
||||
- dmas: Must contain a list of two references to DMA specifiers, one for
|
||||
transmission, and one for reception.
|
||||
- dma-names: Must contain a list of two DMA names, "tx" and "rx".
|
||||
|
||||
Example:
|
||||
aliases {
|
||||
serial0 = &scifa0;
|
||||
@ -56,4 +61,6 @@ Example:
|
||||
interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>;
|
||||
clock-names = "sci_ick";
|
||||
dmas = <&dmac0 0x21>, <&dmac0 0x22>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
|
||||
"sirf,atlas7-uart" or "sirf,atlas7-bt-uart" which means
|
||||
uart located in BT module and used for BT.
|
||||
"sirf,atlas7-uart" or "sirf,atlas7-usp-uart".
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- fifosize : Should define hardware rx/tx fifo size
|
||||
@ -33,15 +32,3 @@ usp@b0090000 {
|
||||
rts-gpios = <&gpio 15 0>;
|
||||
cts-gpios = <&gpio 46 0>;
|
||||
};
|
||||
|
||||
for uart use in BT module,
|
||||
uart6: uart@11000000 {
|
||||
cell-index = <6>;
|
||||
compatible = "sirf,atlas7-bt-uart", "sirf,atlas7-uart";
|
||||
reg = <0x11000000 0x1000>;
|
||||
interrupts = <0 100 0>;
|
||||
clocks = <&clks 138>, <&clks 140>, <&clks 141>;
|
||||
clock-names = "uart", "general", "noc";
|
||||
fifosize = <128>;
|
||||
status = "disabled";
|
||||
}
|
||||
|
@ -959,14 +959,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
uart[8250],io,<addr>[,options]
|
||||
uart[8250],mmio,<addr>[,options]
|
||||
uart[8250],mmio32,<addr>[,options]
|
||||
uart[8250],mmio32be,<addr>[,options]
|
||||
uart[8250],0x<addr>[,options]
|
||||
Start an early, polled-mode console on the 8250/16550
|
||||
UART at the specified I/O port or MMIO address.
|
||||
MMIO inter-register address stride is either 8-bit
|
||||
(mmio) or 32-bit (mmio32).
|
||||
If none of [io|mmio|mmio32], <addr> is assumed to be
|
||||
equivalent to 'mmio'. 'options' are specified in the
|
||||
same format described for "console=ttyS<n>"; if
|
||||
(mmio) or 32-bit (mmio32 or mmio32be).
|
||||
If none of [io|mmio|mmio32|mmio32be], <addr> is assumed
|
||||
to be equivalent to 'mmio'. 'options' are specified
|
||||
in the same format described for "console=ttyS<n>"; if
|
||||
unspecified, the h/w is not initialized.
|
||||
|
||||
pl011,<addr>
|
||||
|
@ -556,6 +556,12 @@ helper functions described in Section 4. In that case, pm_runtime_resume()
|
||||
should be used. Of course, for this purpose the device's runtime PM has to be
|
||||
enabled earlier by calling pm_runtime_enable().
|
||||
|
||||
Note, if the device may execute pm_runtime calls during the probe (such as
|
||||
if it is registers with a subsystem that may call back in) then the
|
||||
pm_runtime_get_sync() call paired with a pm_runtime_put() call will be
|
||||
appropriate to ensure that the device is not put back to sleep during the
|
||||
probe. This can happen with systems such as the network device layer.
|
||||
|
||||
It may be desirable to suspend the device once ->probe() has finished.
|
||||
Therefore the driver core uses the asyncronous pm_request_idle() to submit a
|
||||
request to execute the subsystem-level idle callback for the device at that
|
||||
|
@ -13,7 +13,7 @@
|
||||
#define BASE_BAUD ( 1843200 / 16 )
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#else
|
||||
|
@ -1350,6 +1350,9 @@ void edma_stop(unsigned channel)
|
||||
edma_shadow0_write_array(ctlr, SH_SECR, j, mask);
|
||||
edma_write_array(ctlr, EDMA_EMCR, j, mask);
|
||||
|
||||
/* clear possibly pending completion interrupt */
|
||||
edma_shadow0_write_array(ctlr, SH_ICR, j, mask);
|
||||
|
||||
pr_debug("EDMA: EER%d %08x\n", j,
|
||||
edma_shadow0_read_array(ctlr, SH_EER, j));
|
||||
|
||||
|
@ -22,9 +22,9 @@
|
||||
defined(CONFIG_BFIN_UART2_CTSRTS) || \
|
||||
defined(CONFIG_BFIN_UART3_CTSRTS)
|
||||
# if defined(BFIN_UART_BF54X_STYLE) || defined(BFIN_UART_BF60X_STYLE)
|
||||
# define CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
# define SERIAL_BFIN_HARD_CTSRTS
|
||||
# else
|
||||
# define CONFIG_SERIAL_BFIN_CTSRTS
|
||||
# define SERIAL_BFIN_CTSRTS
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -50,8 +50,8 @@ struct bfin_serial_port {
|
||||
#elif ANOMALY_05000363
|
||||
unsigned int anomaly_threshold;
|
||||
#endif
|
||||
#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
|
||||
defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
|
||||
#if defined(SERIAL_BFIN_CTSRTS) || \
|
||||
defined(SERIAL_BFIN_HARD_CTSRTS)
|
||||
int cts_pin;
|
||||
int rts_pin;
|
||||
#endif
|
||||
|
@ -17,7 +17,7 @@
|
||||
#define BASE_BAUD ( 1843200 / 16 )
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#else
|
||||
|
@ -13,7 +13,7 @@
|
||||
#define _ASM_SERIAL_H
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
|
||||
#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
|
||||
#else
|
||||
@ -21,7 +21,7 @@
|
||||
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_MANY_PORTS
|
||||
#ifdef CONFIG_SERIAL_8250_MANY_PORTS
|
||||
#define FOURPORT_FLAGS ASYNC_FOURPORT
|
||||
#define ACCENT_FLAGS 0
|
||||
#define BOCA_FLAGS 0
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define BASE_BAUD (1843200/16)
|
||||
|
||||
/* Standard COM flags (except for COM4, because of the 8514 problem) */
|
||||
#ifdef CONFIG_SERIAL_DETECT_IRQ
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
# define STD_COMX_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
|
||||
# define STD_COM4_FLAGS (UPF_BOOT_AUTOCONF | 0 | UPF_AUTO_IRQ)
|
||||
#else
|
||||
|
@ -1,4 +1,4 @@
|
||||
obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
|
||||
obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o
|
||||
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
|
||||
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
|
||||
obj-$(CONFIG_PM_OPP) += opp.o
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm-trace.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/async.h>
|
||||
@ -587,6 +588,7 @@ void dpm_resume_noirq(pm_message_t state)
|
||||
async_synchronize_full();
|
||||
dpm_show_time(starttime, state, "noirq");
|
||||
resume_device_irqs();
|
||||
device_wakeup_disarm_wake_irqs();
|
||||
cpuidle_resume();
|
||||
trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
|
||||
}
|
||||
@ -1104,6 +1106,7 @@ int dpm_suspend_noirq(pm_message_t state)
|
||||
|
||||
trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);
|
||||
cpuidle_pause();
|
||||
device_wakeup_arm_wake_irqs();
|
||||
suspend_device_irqs();
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
pm_transition = state;
|
||||
|
@ -20,6 +20,46 @@ static inline void pm_runtime_early_init(struct device *dev)
|
||||
extern void pm_runtime_init(struct device *dev);
|
||||
extern void pm_runtime_remove(struct device *dev);
|
||||
|
||||
struct wake_irq {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
bool dedicated_irq:1;
|
||||
};
|
||||
|
||||
extern void dev_pm_arm_wake_irq(struct wake_irq *wirq);
|
||||
extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
extern int device_wakeup_attach_irq(struct device *dev,
|
||||
struct wake_irq *wakeirq);
|
||||
extern void device_wakeup_detach_irq(struct device *dev);
|
||||
extern void device_wakeup_arm_wake_irqs(void);
|
||||
extern void device_wakeup_disarm_wake_irqs(void);
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
device_wakeup_attach_irq(struct device *dev,
|
||||
struct wake_irq *wakeirq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void device_wakeup_detach_irq(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void device_wakeup_arm_wake_irqs(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void device_wakeup_disarm_wake_irqs(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/*
|
||||
* sysfs.c
|
||||
*/
|
||||
@ -52,6 +92,14 @@ static inline void wakeup_sysfs_remove(struct device *dev) {}
|
||||
static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
|
||||
static inline void pm_qos_sysfs_remove(struct device *dev) {}
|
||||
|
||||
static inline void dev_pm_arm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <trace/events/rpm.h>
|
||||
#include "power.h"
|
||||
|
||||
@ -514,6 +515,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
|
||||
|
||||
callback = RPM_GET_CALLBACK(dev, runtime_suspend);
|
||||
|
||||
dev_pm_enable_wake_irq(dev);
|
||||
retval = rpm_callback(callback, dev);
|
||||
if (retval)
|
||||
goto fail;
|
||||
@ -552,6 +554,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
|
||||
return retval;
|
||||
|
||||
fail:
|
||||
dev_pm_disable_wake_irq(dev);
|
||||
__update_runtime_status(dev, RPM_ACTIVE);
|
||||
dev->power.deferred_resume = false;
|
||||
wake_up_all(&dev->power.wait_queue);
|
||||
@ -734,13 +737,16 @@ static int rpm_resume(struct device *dev, int rpmflags)
|
||||
|
||||
callback = RPM_GET_CALLBACK(dev, runtime_resume);
|
||||
|
||||
dev_pm_disable_wake_irq(dev);
|
||||
retval = rpm_callback(callback, dev);
|
||||
if (retval) {
|
||||
__update_runtime_status(dev, RPM_SUSPENDED);
|
||||
pm_runtime_cancel_pending(dev);
|
||||
dev_pm_enable_wake_irq(dev);
|
||||
} else {
|
||||
no_callback:
|
||||
__update_runtime_status(dev, RPM_ACTIVE);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
if (parent)
|
||||
atomic_inc(&parent->power.child_count);
|
||||
}
|
||||
|
273
drivers/base/power/wakeirq.c
Normal file
273
drivers/base/power/wakeirq.c
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* wakeirq.c - Device wakeirq helper functions
|
||||
*
|
||||
* 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 "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
|
||||
#include "power.h"
|
||||
|
||||
/**
|
||||
* dev_pm_attach_wake_irq - Attach device interrupt as a wake IRQ
|
||||
* @dev: Device entry
|
||||
* @irq: Device wake-up capable interrupt
|
||||
* @wirq: Wake irq specific data
|
||||
*
|
||||
* Internal function to attach either a device IO interrupt or a
|
||||
* dedicated wake-up interrupt as a wake IRQ.
|
||||
*/
|
||||
static int dev_pm_attach_wake_irq(struct device *dev, int irq,
|
||||
struct wake_irq *wirq)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (!dev || !wirq)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&dev->power.lock, flags);
|
||||
if (dev_WARN_ONCE(dev, dev->power.wakeirq,
|
||||
"wake irq already initialized\n")) {
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
dev->power.wakeirq = wirq;
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
|
||||
err = device_wakeup_attach_irq(dev, wirq);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_set_wake_irq - Attach device IO interrupt as wake IRQ
|
||||
* @dev: Device entry
|
||||
* @irq: Device IO interrupt
|
||||
*
|
||||
* Attach a device IO interrupt as a wake IRQ. The wake IRQ gets
|
||||
* automatically configured for wake-up from suspend based
|
||||
* on the device specific sysfs wakeup entry. Typically called
|
||||
* during driver probe after calling device_init_wakeup().
|
||||
*/
|
||||
int dev_pm_set_wake_irq(struct device *dev, int irq)
|
||||
{
|
||||
struct wake_irq *wirq;
|
||||
int err;
|
||||
|
||||
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
|
||||
if (!wirq)
|
||||
return -ENOMEM;
|
||||
|
||||
wirq->dev = dev;
|
||||
wirq->irq = irq;
|
||||
|
||||
err = dev_pm_attach_wake_irq(dev, irq, wirq);
|
||||
if (err)
|
||||
kfree(wirq);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_clear_wake_irq - Detach a device IO interrupt wake IRQ
|
||||
* @dev: Device entry
|
||||
*
|
||||
* Detach a device wake IRQ and free resources.
|
||||
*
|
||||
* Note that it's OK for drivers to call this without calling
|
||||
* dev_pm_set_wake_irq() as all the driver instances may not have
|
||||
* a wake IRQ configured. This avoid adding wake IRQ specific
|
||||
* checks into the drivers.
|
||||
*/
|
||||
void dev_pm_clear_wake_irq(struct device *dev)
|
||||
{
|
||||
struct wake_irq *wirq = dev->power.wakeirq;
|
||||
unsigned long flags;
|
||||
|
||||
if (!wirq)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->power.lock, flags);
|
||||
dev->power.wakeirq = NULL;
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
|
||||
device_wakeup_detach_irq(dev);
|
||||
if (wirq->dedicated_irq)
|
||||
free_irq(wirq->irq, wirq);
|
||||
kfree(wirq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_clear_wake_irq);
|
||||
|
||||
/**
|
||||
* handle_threaded_wake_irq - Handler for dedicated wake-up interrupts
|
||||
* @irq: Device specific dedicated wake-up interrupt
|
||||
* @_wirq: Wake IRQ data
|
||||
*
|
||||
* Some devices have a separate wake-up interrupt in addition to the
|
||||
* device IO interrupt. The wake-up interrupt signals that a device
|
||||
* should be woken up from it's idle state. This handler uses device
|
||||
* specific pm_runtime functions to wake the device, and then it's
|
||||
* up to the device to do whatever it needs to. Note that as the
|
||||
* device may need to restore context and start up regulators, we
|
||||
* use a threaded IRQ.
|
||||
*
|
||||
* Also note that we are not resending the lost device interrupts.
|
||||
* We assume that the wake-up interrupt just needs to wake-up the
|
||||
* device, and then device's pm_runtime_resume() can deal with the
|
||||
* situation.
|
||||
*/
|
||||
static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq)
|
||||
{
|
||||
struct wake_irq *wirq = _wirq;
|
||||
int res;
|
||||
|
||||
/* We don't want RPM_ASYNC or RPM_NOWAIT here */
|
||||
res = pm_runtime_resume(wirq->dev);
|
||||
if (res < 0)
|
||||
dev_warn(wirq->dev,
|
||||
"wake IRQ with no resume: %i\n", res);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_set_dedicated_wake_irq - Request a dedicated wake-up interrupt
|
||||
* @dev: Device entry
|
||||
* @irq: Device wake-up interrupt
|
||||
*
|
||||
* Unless your hardware has separate wake-up interrupts in addition
|
||||
* to the device IO interrupts, you don't need this.
|
||||
*
|
||||
* Sets up a threaded interrupt handler for a device that has
|
||||
* a dedicated wake-up interrupt in addition to the device IO
|
||||
* interrupt.
|
||||
*
|
||||
* The interrupt starts disabled, and needs to be managed for
|
||||
* the device by the bus code or the device driver using
|
||||
* dev_pm_enable_wake_irq() and dev_pm_disable_wake_irq()
|
||||
* functions.
|
||||
*/
|
||||
int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
|
||||
{
|
||||
struct wake_irq *wirq;
|
||||
int err;
|
||||
|
||||
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
|
||||
if (!wirq)
|
||||
return -ENOMEM;
|
||||
|
||||
wirq->dev = dev;
|
||||
wirq->irq = irq;
|
||||
wirq->dedicated_irq = true;
|
||||
irq_set_status_flags(irq, IRQ_NOAUTOEN);
|
||||
|
||||
/*
|
||||
* Consumer device may need to power up and restore state
|
||||
* so we use a threaded irq.
|
||||
*/
|
||||
err = request_threaded_irq(irq, NULL, handle_threaded_wake_irq,
|
||||
IRQF_ONESHOT, dev_name(dev), wirq);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
err = dev_pm_attach_wake_irq(dev, irq, wirq);
|
||||
if (err)
|
||||
goto err_free_irq;
|
||||
|
||||
return err;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(irq, wirq);
|
||||
err_free:
|
||||
kfree(wirq);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_set_dedicated_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_enable_wake_irq - Enable device wake-up interrupt
|
||||
* @dev: Device
|
||||
*
|
||||
* Called from the bus code or the device driver for
|
||||
* runtime_suspend() to enable the wake-up interrupt while
|
||||
* the device is running.
|
||||
*
|
||||
* Note that for runtime_suspend()) the wake-up interrupts
|
||||
* should be unconditionally enabled unlike for suspend()
|
||||
* that is conditional.
|
||||
*/
|
||||
void dev_pm_enable_wake_irq(struct device *dev)
|
||||
{
|
||||
struct wake_irq *wirq = dev->power.wakeirq;
|
||||
|
||||
if (wirq && wirq->dedicated_irq)
|
||||
enable_irq(wirq->irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_enable_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_disable_wake_irq - Disable device wake-up interrupt
|
||||
* @dev: Device
|
||||
*
|
||||
* Called from the bus code or the device driver for
|
||||
* runtime_resume() to disable the wake-up interrupt while
|
||||
* the device is running.
|
||||
*/
|
||||
void dev_pm_disable_wake_irq(struct device *dev)
|
||||
{
|
||||
struct wake_irq *wirq = dev->power.wakeirq;
|
||||
|
||||
if (wirq && wirq->dedicated_irq)
|
||||
disable_irq_nosync(wirq->irq);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_disable_wake_irq);
|
||||
|
||||
/**
|
||||
* dev_pm_arm_wake_irq - Arm device wake-up
|
||||
* @wirq: Device wake-up interrupt
|
||||
*
|
||||
* Sets up the wake-up event conditionally based on the
|
||||
* device_may_wake().
|
||||
*/
|
||||
void dev_pm_arm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
if (!wirq)
|
||||
return;
|
||||
|
||||
if (device_may_wakeup(wirq->dev))
|
||||
enable_irq_wake(wirq->irq);
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_disarm_wake_irq - Disarm device wake-up
|
||||
* @wirq: Device wake-up interrupt
|
||||
*
|
||||
* Clears up the wake-up event conditionally based on the
|
||||
* device_may_wake().
|
||||
*/
|
||||
void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
|
||||
{
|
||||
if (!wirq)
|
||||
return;
|
||||
|
||||
if (device_may_wakeup(wirq->dev))
|
||||
disable_irq_wake(wirq->irq);
|
||||
}
|
@ -14,6 +14,7 @@
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include "power.h"
|
||||
@ -238,6 +239,97 @@ int device_wakeup_enable(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_wakeup_enable);
|
||||
|
||||
/**
|
||||
* device_wakeup_attach_irq - Attach a wakeirq to a wakeup source
|
||||
* @dev: Device to handle
|
||||
* @wakeirq: Device specific wakeirq entry
|
||||
*
|
||||
* Attach a device wakeirq to the wakeup source so the device
|
||||
* wake IRQ can be configured automatically for suspend and
|
||||
* resume.
|
||||
*/
|
||||
int device_wakeup_attach_irq(struct device *dev,
|
||||
struct wake_irq *wakeirq)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
ws = dev->power.wakeup;
|
||||
if (!ws) {
|
||||
dev_err(dev, "forgot to call call device_init_wakeup?\n");
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (ws->wakeirq) {
|
||||
ret = -EEXIST;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ws->wakeirq = wakeirq;
|
||||
|
||||
unlock:
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_detach_irq - Detach a wakeirq from a wakeup source
|
||||
* @dev: Device to handle
|
||||
*
|
||||
* Removes a device wakeirq from the wakeup source.
|
||||
*/
|
||||
void device_wakeup_detach_irq(struct device *dev)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
ws = dev->power.wakeup;
|
||||
if (!ws)
|
||||
goto unlock;
|
||||
|
||||
ws->wakeirq = NULL;
|
||||
|
||||
unlock:
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_arm_wake_irqs(void)
|
||||
*
|
||||
* Itereates over the list of device wakeirqs to arm them.
|
||||
*/
|
||||
void device_wakeup_arm_wake_irqs(void)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
if (ws->wakeirq)
|
||||
dev_pm_arm_wake_irq(ws->wakeirq);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_disarm_wake_irqs(void)
|
||||
*
|
||||
* Itereates over the list of device wakeirqs to disarm them.
|
||||
*/
|
||||
void device_wakeup_disarm_wake_irqs(void)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
if (ws->wakeirq)
|
||||
dev_pm_disarm_wake_irq(ws->wakeirq);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_detach - Detach a device's wakeup source object from it.
|
||||
* @dev: Device to detach the wakeup source object from.
|
||||
|
@ -300,8 +300,7 @@ static int edma_dma_pause(struct dma_chan *chan)
|
||||
{
|
||||
struct edma_chan *echan = to_edma_chan(chan);
|
||||
|
||||
/* Pause/Resume only allowed with cyclic mode */
|
||||
if (!echan->edesc || !echan->edesc->cyclic)
|
||||
if (!echan->edesc)
|
||||
return -EINVAL;
|
||||
|
||||
edma_pause(echan->ch_num);
|
||||
@ -312,10 +311,6 @@ static int edma_dma_resume(struct dma_chan *chan)
|
||||
{
|
||||
struct edma_chan *echan = to_edma_chan(chan);
|
||||
|
||||
/* Pause/Resume only allowed with cyclic mode */
|
||||
if (!echan->edesc->cyclic)
|
||||
return -EINVAL;
|
||||
|
||||
edma_resume(echan->ch_num);
|
||||
return 0;
|
||||
}
|
||||
|
@ -167,7 +167,6 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
|
||||
{
|
||||
struct serport *serport = (struct serport*) tty->disc_data;
|
||||
struct serio *serio;
|
||||
char name[64];
|
||||
|
||||
if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
|
||||
return -EBUSY;
|
||||
@ -177,7 +176,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
|
||||
return -ENOMEM;
|
||||
|
||||
strlcpy(serio->name, "Serial port", sizeof(serio->name));
|
||||
snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name));
|
||||
snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty));
|
||||
serio->id = serport->id;
|
||||
serio->id.type = SERIO_RS232;
|
||||
serio->write = serport_serio_write;
|
||||
@ -187,7 +186,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u
|
||||
serio->dev.parent = tty->dev;
|
||||
|
||||
serio_register_port(serport->serio);
|
||||
printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name));
|
||||
printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty));
|
||||
|
||||
wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags));
|
||||
serio_unregister_port(serport->serio);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/platform_data/hsmmc-omap.h>
|
||||
|
||||
/* OMAP HSMMC Host Controller Registers */
|
||||
@ -218,7 +219,6 @@ struct omap_hsmmc_host {
|
||||
unsigned int flags;
|
||||
#define AUTO_CMD23 (1 << 0) /* Auto CMD23 support */
|
||||
#define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
|
||||
#define HSMMC_WAKE_IRQ_ENABLED (1 << 2)
|
||||
struct omap_hsmmc_next next_data;
|
||||
struct omap_hsmmc_platform_data *pdata;
|
||||
|
||||
@ -1117,22 +1117,6 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t omap_hsmmc_wake_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct omap_hsmmc_host *host = dev_id;
|
||||
|
||||
/* cirq is level triggered, disable to avoid infinite loop */
|
||||
spin_lock(&host->irq_lock);
|
||||
if (host->flags & HSMMC_WAKE_IRQ_ENABLED) {
|
||||
disable_irq_nosync(host->wake_irq);
|
||||
host->flags &= ~HSMMC_WAKE_IRQ_ENABLED;
|
||||
}
|
||||
spin_unlock(&host->irq_lock);
|
||||
pm_request_resume(host->dev); /* no use counter */
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void set_sd_bus_power(struct omap_hsmmc_host *host)
|
||||
{
|
||||
unsigned long i;
|
||||
@ -1665,7 +1649,6 @@ static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||
|
||||
static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -1677,11 +1660,7 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host)
|
||||
if (!host->dev->of_node || !host->wake_irq)
|
||||
return -ENODEV;
|
||||
|
||||
/* Prevent auto-enabling of IRQ */
|
||||
irq_set_status_flags(host->wake_irq, IRQ_NOAUTOEN);
|
||||
ret = devm_request_irq(host->dev, host->wake_irq, omap_hsmmc_wake_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
mmc_hostname(mmc), host);
|
||||
ret = dev_pm_set_dedicated_wake_irq(host->dev, host->wake_irq);
|
||||
if (ret) {
|
||||
dev_err(mmc_dev(host->mmc), "Unable to request wake IRQ\n");
|
||||
goto err;
|
||||
@ -1718,7 +1697,7 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host)
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
devm_free_irq(host->dev, host->wake_irq, host);
|
||||
dev_pm_clear_wake_irq(host->dev);
|
||||
err:
|
||||
dev_warn(host->dev, "no SDIO IRQ support, falling back to polling\n");
|
||||
host->wake_irq = 0;
|
||||
@ -2007,6 +1986,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
|
||||
omap_hsmmc_ops.multi_io_quirk = omap_hsmmc_multi_io_quirk;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
pm_runtime_enable(host->dev);
|
||||
pm_runtime_get_sync(host->dev);
|
||||
pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
|
||||
@ -2147,6 +2127,7 @@ err_slot_name:
|
||||
if (host->use_reg)
|
||||
omap_hsmmc_reg_put(host);
|
||||
err_irq:
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
if (host->tx_chan)
|
||||
dma_release_channel(host->tx_chan);
|
||||
if (host->rx_chan)
|
||||
@ -2178,6 +2159,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_put_sync(host->dev);
|
||||
pm_runtime_disable(host->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
if (host->dbclk)
|
||||
clk_disable_unprepare(host->dbclk);
|
||||
|
||||
@ -2204,11 +2186,6 @@ static int omap_hsmmc_suspend(struct device *dev)
|
||||
OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
|
||||
}
|
||||
|
||||
/* do not wake up due to sdio irq */
|
||||
if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
|
||||
!(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
|
||||
disable_irq(host->wake_irq);
|
||||
|
||||
if (host->dbclk)
|
||||
clk_disable_unprepare(host->dbclk);
|
||||
|
||||
@ -2233,11 +2210,6 @@ static int omap_hsmmc_resume(struct device *dev)
|
||||
omap_hsmmc_conf_bus_power(host);
|
||||
|
||||
omap_hsmmc_protect_card(host);
|
||||
|
||||
if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
|
||||
!(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
|
||||
enable_irq(host->wake_irq);
|
||||
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
return 0;
|
||||
@ -2277,10 +2249,6 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
|
||||
}
|
||||
|
||||
pinctrl_pm_select_idle_state(dev);
|
||||
|
||||
WARN_ON(host->flags & HSMMC_WAKE_IRQ_ENABLED);
|
||||
enable_irq(host->wake_irq);
|
||||
host->flags |= HSMMC_WAKE_IRQ_ENABLED;
|
||||
} else {
|
||||
pinctrl_pm_select_idle_state(dev);
|
||||
}
|
||||
@ -2302,11 +2270,6 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
|
||||
spin_lock_irqsave(&host->irq_lock, flags);
|
||||
if ((host->mmc->caps & MMC_CAP_SDIO_IRQ) &&
|
||||
(host->flags & HSMMC_SDIO_IRQ_ENABLED)) {
|
||||
/* sdio irq flag can't change while in runtime suspend */
|
||||
if (host->flags & HSMMC_WAKE_IRQ_ENABLED) {
|
||||
disable_irq_nosync(host->wake_irq);
|
||||
host->flags &= ~HSMMC_WAKE_IRQ_ENABLED;
|
||||
}
|
||||
|
||||
pinctrl_pm_select_default_state(host->dev);
|
||||
|
||||
|
@ -966,9 +966,7 @@ static void rs_throttle(struct tty_struct * tty)
|
||||
struct serial_state *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
char buf[64];
|
||||
|
||||
printk("throttle %s: %d....\n", tty_name(tty, buf),
|
||||
printk("throttle %s: %d....\n", tty_name(tty),
|
||||
tty->ldisc.chars_in_buffer(tty));
|
||||
#endif
|
||||
|
||||
@ -991,9 +989,7 @@ static void rs_unthrottle(struct tty_struct * tty)
|
||||
struct serial_state *info = tty->driver_data;
|
||||
unsigned long flags;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
char buf[64];
|
||||
|
||||
printk("unthrottle %s: %d....\n", tty_name(tty, buf),
|
||||
printk("unthrottle %s: %d....\n", tty_name(tty),
|
||||
tty->ldisc.chars_in_buffer(tty));
|
||||
#endif
|
||||
|
||||
@ -1786,7 +1782,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)
|
||||
struct serial_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
|
||||
if ((error = tty_unregister_driver(serial_driver)))
|
||||
error = tty_unregister_driver(serial_driver);
|
||||
if (error)
|
||||
printk("SERIAL: failed to unregister serial driver (%d)\n",
|
||||
error);
|
||||
put_tty_driver(serial_driver);
|
||||
|
@ -2861,9 +2861,7 @@ static void cy_throttle(struct tty_struct *tty)
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CY_DEBUG_THROTTLE
|
||||
char buf[64];
|
||||
|
||||
printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
|
||||
printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty),
|
||||
tty->ldisc.chars_in_buffer(tty), info->line);
|
||||
#endif
|
||||
|
||||
@ -2902,10 +2900,8 @@ static void cy_unthrottle(struct tty_struct *tty)
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CY_DEBUG_THROTTLE
|
||||
char buf[64];
|
||||
|
||||
printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
|
||||
tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
|
||||
tty_name(tty), tty_chars_in_buffer(tty), info->line);
|
||||
#endif
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
|
||||
|
@ -42,13 +42,6 @@ config HVC_RTAS
|
||||
help
|
||||
IBM Console device driver which makes use of RTAS
|
||||
|
||||
config HVC_BEAT
|
||||
bool "Toshiba's Beat Hypervisor Console support"
|
||||
depends on PPC_CELLEB
|
||||
select HVC_DRIVER
|
||||
help
|
||||
Toshiba's Cell Reference Set Beat Console device driver
|
||||
|
||||
config HVC_IUCV
|
||||
bool "z/VM IUCV Hypervisor console support (VM only)"
|
||||
depends on S390
|
||||
|
@ -4,7 +4,6 @@ obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o
|
||||
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
|
||||
obj-$(CONFIG_HVC_TILE) += hvc_tile.o
|
||||
obj-$(CONFIG_HVC_DCC) += hvc_dcc.o
|
||||
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
|
||||
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
|
||||
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
|
||||
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Beat hypervisor console driver
|
||||
*
|
||||
* (C) Copyright 2006 TOSHIBA CORPORATION
|
||||
*
|
||||
* This code is based on drivers/char/hvc_rtas.c:
|
||||
* (C) Copyright IBM Corporation 2001-2005
|
||||
* (C) Copyright Red Hat, Inc. 2005
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/console.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/hvconsole.h>
|
||||
#include <asm/firmware.h>
|
||||
|
||||
#include "hvc_console.h"
|
||||
|
||||
extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *);
|
||||
extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t);
|
||||
|
||||
struct hvc_struct *hvc_beat_dev = NULL;
|
||||
|
||||
/* bug: only one queue is available regardless of vtermno */
|
||||
static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
|
||||
{
|
||||
static unsigned char q[sizeof(unsigned long) * 2]
|
||||
__attribute__((aligned(sizeof(unsigned long))));
|
||||
static int qlen = 0;
|
||||
u64 got;
|
||||
|
||||
again:
|
||||
if (qlen) {
|
||||
if (qlen > cnt) {
|
||||
memcpy(buf, q, cnt);
|
||||
qlen -= cnt;
|
||||
memmove(q + cnt, q, qlen);
|
||||
return cnt;
|
||||
} else { /* qlen <= cnt */
|
||||
int r;
|
||||
|
||||
memcpy(buf, q, qlen);
|
||||
r = qlen;
|
||||
qlen = 0;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (beat_get_term_char(vtermno, &got,
|
||||
((u64 *)q), ((u64 *)q) + 1) == 0) {
|
||||
qlen = got;
|
||||
goto again;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
|
||||
{
|
||||
unsigned long kb[2];
|
||||
int rest, nlen;
|
||||
|
||||
for (rest = cnt; rest > 0; rest -= nlen) {
|
||||
nlen = (rest > 16) ? 16 : rest;
|
||||
memcpy(kb, buf, nlen);
|
||||
beat_put_term_char(vtermno, nlen, kb[0], kb[1]);
|
||||
buf += nlen;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static const struct hv_ops hvc_beat_get_put_ops = {
|
||||
.get_chars = hvc_beat_get_chars,
|
||||
.put_chars = hvc_beat_put_chars,
|
||||
};
|
||||
|
||||
static int hvc_beat_useit = 1;
|
||||
|
||||
static int hvc_beat_config(char *p)
|
||||
{
|
||||
hvc_beat_useit = simple_strtoul(p, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init hvc_beat_console_init(void)
|
||||
{
|
||||
if (hvc_beat_useit && of_machine_is_compatible("Beat")) {
|
||||
hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* temp */
|
||||
static int __init hvc_beat_init(void)
|
||||
{
|
||||
struct hvc_struct *hp;
|
||||
|
||||
if (!firmware_has_feature(FW_FEATURE_BEAT))
|
||||
return -ENODEV;
|
||||
|
||||
hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16);
|
||||
if (IS_ERR(hp))
|
||||
return PTR_ERR(hp);
|
||||
hvc_beat_dev = hp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit hvc_beat_exit(void)
|
||||
{
|
||||
if (hvc_beat_dev)
|
||||
hvc_remove(hvc_beat_dev);
|
||||
}
|
||||
|
||||
module_init(hvc_beat_init);
|
||||
module_exit(hvc_beat_exit);
|
||||
|
||||
__setup("hvc_beat=", hvc_beat_config);
|
||||
|
||||
console_initcall(hvc_beat_console_init);
|
@ -319,7 +319,8 @@ static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
int rc;
|
||||
|
||||
/* Auto increments kref reference if found. */
|
||||
if (!(hp = hvc_get_by_index(tty->index)))
|
||||
hp = hvc_get_by_index(tty->index);
|
||||
if (!hp)
|
||||
return -ENODEV;
|
||||
|
||||
tty->driver_data = hp;
|
||||
|
@ -1044,8 +1044,8 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
|
||||
* It is possible that the vty-server was removed between the time that
|
||||
* the conn was registered and now.
|
||||
*/
|
||||
if (!(rc = request_irq(irq, &hvcs_handle_interrupt,
|
||||
0, "ibmhvcs", hvcsd))) {
|
||||
rc = request_irq(irq, &hvcs_handle_interrupt, 0, "ibmhvcs", hvcsd);
|
||||
if (!rc) {
|
||||
/*
|
||||
* It is possible the vty-server was removed after the irq was
|
||||
* requested but before we have time to enable interrupts.
|
||||
|
@ -161,7 +161,7 @@ struct gsm_dlci {
|
||||
struct net_device *net; /* network interface, if created */
|
||||
};
|
||||
|
||||
/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
|
||||
/* DLCI 0, 62/63 are special or reserved see gsmtty_open */
|
||||
|
||||
#define NUM_DLCI 64
|
||||
|
||||
@ -2274,7 +2274,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
const unsigned char *dp;
|
||||
char *f;
|
||||
int i;
|
||||
char buf[64];
|
||||
char flags = TTY_NORMAL;
|
||||
|
||||
if (debug & 4)
|
||||
@ -2296,7 +2295,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "%s: unknown flag %d\n",
|
||||
tty_name(tty, buf), flags);
|
||||
tty_name(tty), flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1190,13 +1190,12 @@ static void n_tty_receive_break(struct tty_struct *tty)
|
||||
static void n_tty_receive_overrun(struct tty_struct *tty)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
char buf[64];
|
||||
|
||||
ldata->num_overrun++;
|
||||
if (time_after(jiffies, ldata->overrun_time + HZ) ||
|
||||
time_after(ldata->overrun_time, jiffies)) {
|
||||
printk(KERN_WARNING "%s: %d input overrun(s)\n",
|
||||
tty_name(tty, buf),
|
||||
tty_name(tty),
|
||||
ldata->num_overrun);
|
||||
ldata->overrun_time = jiffies;
|
||||
ldata->num_overrun = 0;
|
||||
@ -1471,8 +1470,6 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
|
||||
static void
|
||||
n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
switch (flag) {
|
||||
case TTY_BREAK:
|
||||
n_tty_receive_break(tty);
|
||||
@ -1486,7 +1483,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s: unknown flag %d\n",
|
||||
tty_name(tty, buf), flag);
|
||||
tty_name(tty), flag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ static int debug;
|
||||
#define R_FCR 0x0000 /* Flow Control Register */
|
||||
#define R_IER 0x0004 /* Interrupt Enable Register */
|
||||
|
||||
#define CONFIG_MAGIC 0xEFEFFEFE
|
||||
#define TOGGLE_VALID 0x0000
|
||||
#define NOZOMI_CONFIG_MAGIC 0xEFEFFEFE
|
||||
#define TOGGLE_VALID 0x0000
|
||||
|
||||
/* Definition of interrupt tokens */
|
||||
#define MDM_DL1 0x0001
|
||||
@ -660,9 +660,9 @@ static int nozomi_read_config_table(struct nozomi *dc)
|
||||
read_mem32((u32 *) &dc->config_table, dc->base_addr + 0,
|
||||
sizeof(struct config_table));
|
||||
|
||||
if (dc->config_table.signature != CONFIG_MAGIC) {
|
||||
if (dc->config_table.signature != NOZOMI_CONFIG_MAGIC) {
|
||||
dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n",
|
||||
dc->config_table.signature, CONFIG_MAGIC);
|
||||
dc->config_table.signature, NOZOMI_CONFIG_MAGIC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ struct rocket_version {
|
||||
#define ROCKET_HUP_NOTIFY 0x00000004
|
||||
#define ROCKET_SPLIT_TERMIOS 0x00000008
|
||||
#define ROCKET_SPD_MASK 0x00000070
|
||||
#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */
|
||||
#define ROCKET_SPD_HI 0x00000010 /* Use 57600 instead of 38400 bps */
|
||||
#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */
|
||||
#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */
|
||||
#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */
|
||||
|
@ -508,7 +508,8 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
|
||||
int i;
|
||||
|
||||
cflag = tty->termios.c_cflag;
|
||||
if (!(port = info->port))
|
||||
port = info->port;
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
ustcnt = uart->ustcnt;
|
||||
|
@ -85,19 +85,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
|
||||
#define CONFIG_SERIAL_DETECT_IRQ 1
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_8250_MANY_PORTS
|
||||
#define CONFIG_SERIAL_MANY_PORTS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* HUB6 is always on. This will be removed once the header
|
||||
* files have been cleaned.
|
||||
*/
|
||||
#define CONFIG_HUB6 1
|
||||
|
||||
#include <asm/serial.h>
|
||||
/*
|
||||
* SERIAL_PORT_DFNS tells us about built-in ports that have no
|
||||
@ -2019,8 +2006,9 @@ EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
|
||||
static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
if (port->set_mctrl)
|
||||
return port->set_mctrl(port, mctrl);
|
||||
return serial8250_do_set_mctrl(port, mctrl);
|
||||
port->set_mctrl(port, mctrl);
|
||||
else
|
||||
serial8250_do_set_mctrl(port, mctrl);
|
||||
}
|
||||
|
||||
static void serial8250_break_ctl(struct uart_port *port, int break_state)
|
||||
@ -3548,6 +3536,9 @@ static struct console univ8250_console = {
|
||||
|
||||
static int __init univ8250_console_init(void)
|
||||
{
|
||||
if (nr_uarts == 0)
|
||||
return -ENODEV;
|
||||
|
||||
serial8250_isa_init_ports();
|
||||
register_console(&univ8250_console);
|
||||
return 0;
|
||||
@ -3578,7 +3569,7 @@ int __init early_serial_setup(struct uart_port *port)
|
||||
{
|
||||
struct uart_port *p;
|
||||
|
||||
if (port->line >= ARRAY_SIZE(serial8250_ports))
|
||||
if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0)
|
||||
return -ENODEV;
|
||||
|
||||
serial8250_isa_init_ports();
|
||||
@ -3850,7 +3841,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
uart->port.mapbase = up->port.mapbase;
|
||||
uart->port.mapsize = up->port.mapsize;
|
||||
uart->port.private_data = up->port.private_data;
|
||||
uart->port.fifosize = up->port.fifosize;
|
||||
uart->tx_loadsz = up->tx_loadsz;
|
||||
uart->capabilities = up->capabilities;
|
||||
uart->port.throttle = up->port.throttle;
|
||||
@ -3945,6 +3935,9 @@ static int __init serial8250_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (nr_uarts == 0)
|
||||
return -ENODEV;
|
||||
|
||||
serial8250_isa_init_ports();
|
||||
|
||||
printk(KERN_INFO "Serial: 8250/16550 driver, "
|
||||
|
@ -377,6 +377,16 @@ static int dw8250_probe_of(struct uart_port *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct device *dev = param;
|
||||
|
||||
if (dev != chan->device->dev->parent)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int dw8250_probe_acpi(struct uart_8250_port *up,
|
||||
struct dw8250_data *data)
|
||||
{
|
||||
@ -389,8 +399,15 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
p->regshift = 2;
|
||||
|
||||
up->dma = &data->dma;
|
||||
/* Platforms with iDMA */
|
||||
if (platform_get_resource_byname(to_platform_device(up->port.dev),
|
||||
IORESOURCE_MEM, "lpss_priv")) {
|
||||
data->dma.rx_param = up->port.dev->parent;
|
||||
data->dma.tx_param = up->port.dev->parent;
|
||||
data->dma.fn = dw8250_idma_filter;
|
||||
}
|
||||
|
||||
up->dma = &data->dma;
|
||||
up->dma->rxconf.src_maxburst = p->fifosize / 4;
|
||||
up->dma->txconf.dst_maxburst = p->fifosize / 4;
|
||||
|
||||
|
@ -131,7 +131,7 @@ static void __init init_port(struct earlycon_device *device)
|
||||
serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
|
||||
}
|
||||
|
||||
static int __init early_serial8250_setup(struct earlycon_device *device,
|
||||
int __init early_serial8250_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
if (!(device->port.membase || device->port.iobase))
|
||||
|
230
drivers/tty/serial/8250/8250_lpc18xx.c
Normal file
230
drivers/tty/serial/8250/8250_lpc18xx.c
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Serial port driver for NXP LPC18xx/43xx UART
|
||||
*
|
||||
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* Based on 8250_mtk.c:
|
||||
* Copyright (c) 2014 MundoReader S.L.
|
||||
* Matthias Brugger <matthias.bgg@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
/* Additional LPC18xx/43xx 8250 registers and bits */
|
||||
#define LPC18XX_UART_RS485CTRL (0x04c / sizeof(u32))
|
||||
#define LPC18XX_UART_RS485CTRL_NMMEN BIT(0)
|
||||
#define LPC18XX_UART_RS485CTRL_DCTRL BIT(4)
|
||||
#define LPC18XX_UART_RS485CTRL_OINV BIT(5)
|
||||
#define LPC18XX_UART_RS485DLY (0x054 / sizeof(u32))
|
||||
#define LPC18XX_UART_RS485DLY_MAX 255
|
||||
|
||||
struct lpc18xx_uart_data {
|
||||
struct uart_8250_dma dma;
|
||||
struct clk *clk_uart;
|
||||
struct clk *clk_reg;
|
||||
int line;
|
||||
};
|
||||
|
||||
static int lpc18xx_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
u32 rs485_ctrl_reg = 0;
|
||||
u32 rs485_dly_reg = 0;
|
||||
unsigned baud_clk;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED)
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
else
|
||||
memset(rs485, 0, sizeof(*rs485));
|
||||
|
||||
rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
|
||||
SER_RS485_RTS_AFTER_SEND;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN |
|
||||
LPC18XX_UART_RS485CTRL_DCTRL;
|
||||
|
||||
if (rs485->flags & SER_RS485_RTS_ON_SEND) {
|
||||
rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV;
|
||||
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
} else {
|
||||
rs485->flags |= SER_RS485_RTS_AFTER_SEND;
|
||||
}
|
||||
}
|
||||
|
||||
if (rs485->delay_rts_after_send) {
|
||||
baud_clk = port->uartclk / up->dl_read(up);
|
||||
rs485_dly_reg = DIV_ROUND_UP(rs485->delay_rts_after_send
|
||||
* baud_clk, MSEC_PER_SEC);
|
||||
|
||||
if (rs485_dly_reg > LPC18XX_UART_RS485DLY_MAX)
|
||||
rs485_dly_reg = LPC18XX_UART_RS485DLY_MAX;
|
||||
|
||||
/* Calculate the resulting delay in ms */
|
||||
rs485->delay_rts_after_send = (rs485_dly_reg * MSEC_PER_SEC)
|
||||
/ baud_clk;
|
||||
}
|
||||
|
||||
/* Delay RTS before send not supported */
|
||||
rs485->delay_rts_before_send = 0;
|
||||
|
||||
serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg);
|
||||
serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
/*
|
||||
* For DMA mode one must ensure that the UART_FCR_DMA_SELECT
|
||||
* bit is set when FIFO is enabled. Even if DMA is not used
|
||||
* setting this bit doesn't seem to affect anything.
|
||||
*/
|
||||
if (offset == UART_FCR && (value & UART_FCR_ENABLE_FIFO))
|
||||
value |= UART_FCR_DMA_SELECT;
|
||||
|
||||
offset = offset << p->regshift;
|
||||
writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static int lpc18xx_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_uart_data *data;
|
||||
struct uart_8250_port uart;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "irq not found");
|
||||
return irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "memory resource not found");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&uart, 0, sizeof(uart));
|
||||
|
||||
uart.port.membase = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!uart.port.membase)
|
||||
return -ENOMEM;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->clk_uart = devm_clk_get(&pdev->dev, "uartclk");
|
||||
if (IS_ERR(data->clk_uart)) {
|
||||
dev_err(&pdev->dev, "uart clock not found\n");
|
||||
return PTR_ERR(data->clk_uart);
|
||||
}
|
||||
|
||||
data->clk_reg = devm_clk_get(&pdev->dev, "reg");
|
||||
if (IS_ERR(data->clk_reg)) {
|
||||
dev_err(&pdev->dev, "reg clock not found\n");
|
||||
return PTR_ERR(data->clk_reg);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(data->clk_reg);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable reg clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(data->clk_uart);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable uart clock\n");
|
||||
goto dis_clk_reg;
|
||||
}
|
||||
|
||||
ret = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (ret >= 0)
|
||||
uart.port.line = ret;
|
||||
|
||||
data->dma.rx_param = data;
|
||||
data->dma.tx_param = data;
|
||||
|
||||
spin_lock_init(&uart.port.lock);
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.irq = irq;
|
||||
uart.port.iotype = UPIO_MEM32;
|
||||
uart.port.mapbase = res->start;
|
||||
uart.port.regshift = 2;
|
||||
uart.port.type = PORT_16550A;
|
||||
uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST;
|
||||
uart.port.uartclk = clk_get_rate(data->clk_uart);
|
||||
uart.port.private_data = data;
|
||||
uart.port.rs485_config = lpc18xx_rs485_config;
|
||||
uart.port.serial_out = lpc18xx_uart_serial_out;
|
||||
|
||||
uart.dma = &data->dma;
|
||||
uart.dma->rxconf.src_maxburst = 1;
|
||||
uart.dma->txconf.dst_maxburst = 1;
|
||||
|
||||
ret = serial8250_register_8250_port(&uart);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "unable to register 8250 port\n");
|
||||
goto dis_uart_clk;
|
||||
}
|
||||
|
||||
data->line = ret;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
return 0;
|
||||
|
||||
dis_uart_clk:
|
||||
clk_disable_unprepare(data->clk_uart);
|
||||
dis_clk_reg:
|
||||
clk_disable_unprepare(data->clk_reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpc18xx_serial_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_uart_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
serial8250_unregister_port(data->line);
|
||||
clk_disable_unprepare(data->clk_uart);
|
||||
clk_disable_unprepare(data->clk_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc18xx_serial_match[] = {
|
||||
{ .compatible = "nxp,lpc1850-uart" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_serial_match);
|
||||
|
||||
static struct platform_driver lpc18xx_serial_driver = {
|
||||
.probe = lpc18xx_serial_probe,
|
||||
.remove = lpc18xx_serial_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-uart",
|
||||
.of_match_table = lpc18xx_serial_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpc18xx_serial_driver);
|
||||
|
||||
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
|
||||
MODULE_DESCRIPTION("Serial port driver NXP LPC18xx/43xx devices");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -34,6 +34,7 @@
|
||||
struct mtk8250_data {
|
||||
int line;
|
||||
struct clk *uart_clk;
|
||||
struct clk *bus_clk;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -115,6 +116,36 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
}
|
||||
|
||||
static int mtk8250_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(data->uart_clk);
|
||||
clk_disable_unprepare(data->bus_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk8250_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(data->uart_clk);
|
||||
if (err) {
|
||||
dev_warn(dev, "Can't enable clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(data->bus_clk);
|
||||
if (err) {
|
||||
dev_warn(dev, "Can't enable bus clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
{
|
||||
@ -130,22 +161,24 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p,
|
||||
struct mtk8250_data *data)
|
||||
{
|
||||
int err;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
data->uart_clk = of_clk_get(np, 0);
|
||||
data->uart_clk = devm_clk_get(&pdev->dev, "baud");
|
||||
if (IS_ERR(data->uart_clk)) {
|
||||
dev_warn(&pdev->dev, "Can't get timer clock\n");
|
||||
return PTR_ERR(data->uart_clk);
|
||||
/*
|
||||
* For compatibility with older device trees try unnamed
|
||||
* clk when no baud clk can be found.
|
||||
*/
|
||||
data->uart_clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(data->uart_clk)) {
|
||||
dev_warn(&pdev->dev, "Can't get uart clock\n");
|
||||
return PTR_ERR(data->uart_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(data->uart_clk);
|
||||
if (err) {
|
||||
dev_warn(&pdev->dev, "Can't prepare clock\n");
|
||||
clk_put(data->uart_clk);
|
||||
return err;
|
||||
}
|
||||
p->uartclk = clk_get_rate(data->uart_clk);
|
||||
data->bus_clk = devm_clk_get(&pdev->dev, "bus");
|
||||
if (IS_ERR(data->bus_clk))
|
||||
return PTR_ERR(data->bus_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -190,20 +223,25 @@ static int mtk8250_probe(struct platform_device *pdev)
|
||||
uart.port.regshift = 2;
|
||||
uart.port.private_data = data;
|
||||
uart.port.set_termios = mtk8250_set_termios;
|
||||
uart.port.uartclk = clk_get_rate(data->uart_clk);
|
||||
|
||||
/* Disable Rate Fix function */
|
||||
writel(0x0, uart.port.membase +
|
||||
(MTK_UART_RATE_FIX << uart.port.regshift));
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
if (!pm_runtime_enabled(&pdev->dev)) {
|
||||
err = mtk8250_runtime_resume(&pdev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
data->line = serial8250_register_8250_port(&uart);
|
||||
if (data->line < 0)
|
||||
return data->line;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -214,13 +252,13 @@ static int mtk8250_remove(struct platform_device *pdev)
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
serial8250_unregister_port(data->line);
|
||||
if (!IS_ERR(data->uart_clk)) {
|
||||
clk_disable_unprepare(data->uart_clk);
|
||||
clk_put(data->uart_clk);
|
||||
}
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
mtk8250_runtime_suspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -244,28 +282,6 @@ static int mtk8250_resume(struct device *dev)
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mtk8250_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (!IS_ERR(data->uart_clk))
|
||||
clk_disable_unprepare(data->uart_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk8250_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (!IS_ERR(data->uart_clk))
|
||||
clk_prepare_enable(data->uart_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops mtk8250_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume)
|
||||
SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume,
|
||||
@ -289,6 +305,21 @@ static struct platform_driver mtk8250_platform_driver = {
|
||||
};
|
||||
module_platform_driver(mtk8250_platform_driver);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init early_mtk8250_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->port.iotype = UPIO_MEM32;
|
||||
|
||||
return early_serial8250_setup(device, NULL);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Matthias Brugger");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Mediatek 8250 serial port driver");
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "8250.h"
|
||||
@ -98,6 +99,7 @@ struct omap8250_priv {
|
||||
struct pm_qos_request pm_qos_request;
|
||||
struct work_struct qos_work;
|
||||
struct uart_8250_dma omap8250_dma;
|
||||
spinlock_t rx_dma_lock;
|
||||
};
|
||||
|
||||
static u32 uart_read(struct uart_8250_port *up, u32 reg)
|
||||
@ -551,17 +553,6 @@ static void omap8250_uart_qos_work(struct work_struct *work)
|
||||
pm_qos_update_request(&priv->pm_qos_request, priv->latency);
|
||||
}
|
||||
|
||||
static irqreturn_t omap_wake_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
int ret;
|
||||
|
||||
ret = port->handle_irq(port);
|
||||
if (ret)
|
||||
return IRQ_HANDLED;
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static int omap_8250_dma_handle_irq(struct uart_port *port);
|
||||
#endif
|
||||
@ -595,11 +586,9 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
int ret;
|
||||
|
||||
if (priv->wakeirq) {
|
||||
ret = request_irq(priv->wakeirq, omap_wake_irq,
|
||||
port->irqflags, "uart wakeup irq", port);
|
||||
ret = dev_pm_set_dedicated_wake_irq(port->dev, priv->wakeirq);
|
||||
if (ret)
|
||||
return ret;
|
||||
disable_irq(priv->wakeirq);
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
@ -648,8 +637,7 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
err:
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
if (priv->wakeirq)
|
||||
free_irq(priv->wakeirq, port);
|
||||
dev_pm_clear_wake_irq(port->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -681,10 +669,8 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
|
||||
free_irq(port->irq, port);
|
||||
if (priv->wakeirq)
|
||||
free_irq(priv->wakeirq, port);
|
||||
dev_pm_clear_wake_irq(port->dev);
|
||||
}
|
||||
|
||||
static void omap_8250_throttle(struct uart_port *port)
|
||||
@ -726,14 +712,21 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
|
||||
|
||||
static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
{
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct tty_port *tty_port = &p->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
int count;
|
||||
unsigned long flags;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
spin_lock_irqsave(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (!dma->rx_running)
|
||||
goto unlock;
|
||||
|
||||
dma->rx_running = 0;
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
@ -742,6 +735,9 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
|
||||
tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||
p->port.icount.rx += count;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (!error)
|
||||
omap_8250_rx_dma(p, 0);
|
||||
|
||||
@ -753,28 +749,45 @@ static void __dma_rx_complete(void *param)
|
||||
__dma_rx_do_complete(param, false);
|
||||
}
|
||||
|
||||
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
{
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (!dma->rx_running) {
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
dmaengine_pause(dma->rxchan);
|
||||
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
|
||||
__dma_rx_do_complete(p, true);
|
||||
}
|
||||
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
{
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
int err = 0;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
unsigned long flags;
|
||||
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RLSI:
|
||||
/* 8250_core handles errors and break interrupts */
|
||||
if (dma->rx_running) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_do_complete(p, true);
|
||||
}
|
||||
omap_8250_rx_dma_flush(p);
|
||||
return -EIO;
|
||||
case UART_IIR_RX_TIMEOUT:
|
||||
/*
|
||||
* If RCVR FIFO trigger level was not reached, complete the
|
||||
* transfer and let 8250_core copy the remaining data.
|
||||
*/
|
||||
if (dma->rx_running) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_do_complete(p, true);
|
||||
}
|
||||
omap_8250_rx_dma_flush(p);
|
||||
return -ETIMEDOUT;
|
||||
case UART_IIR_RDI:
|
||||
/*
|
||||
@ -786,24 +799,25 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
* the DMA won't do anything soon so we have to cancel the DMA
|
||||
* transfer and purge the FIFO manually.
|
||||
*/
|
||||
if (dma->rx_running) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_do_complete(p, true);
|
||||
}
|
||||
omap_8250_rx_dma_flush(p);
|
||||
return -ETIMEDOUT;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (dma->rx_running)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
return -EBUSY;
|
||||
if (!desc) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dma->rx_running = 1;
|
||||
desc->callback = __dma_rx_complete;
|
||||
@ -815,7 +829,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
return 0;
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int omap_8250_tx_dma(struct uart_8250_port *p);
|
||||
@ -1129,6 +1145,8 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
priv->latency);
|
||||
INIT_WORK(&priv->qos_work, omap8250_uart_qos_work);
|
||||
|
||||
spin_lock_init(&priv->rx_dma_lock);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, -1);
|
||||
@ -1193,31 +1211,6 @@ static int omap8250_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static inline void omap8250_enable_wakeirq(struct omap8250_priv *priv,
|
||||
bool enable)
|
||||
{
|
||||
if (!priv->wakeirq)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
enable_irq(priv->wakeirq);
|
||||
else
|
||||
disable_irq_nosync(priv->wakeirq);
|
||||
}
|
||||
|
||||
static void omap8250_enable_wakeup(struct omap8250_priv *priv,
|
||||
bool enable)
|
||||
{
|
||||
if (enable == priv->wakeups_enabled)
|
||||
return;
|
||||
|
||||
omap8250_enable_wakeirq(priv, enable);
|
||||
priv->wakeups_enabled = enable;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int omap8250_prepare(struct device *dev)
|
||||
{
|
||||
@ -1244,11 +1237,6 @@ static int omap8250_suspend(struct device *dev)
|
||||
|
||||
serial8250_suspend_port(priv->line);
|
||||
flush_work(&priv->qos_work);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
omap8250_enable_wakeup(priv, true);
|
||||
else
|
||||
omap8250_enable_wakeup(priv, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1256,9 +1244,6 @@ static int omap8250_resume(struct device *dev)
|
||||
{
|
||||
struct omap8250_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
omap8250_enable_wakeup(priv, false);
|
||||
|
||||
serial8250_resume_port(priv->line);
|
||||
return 0;
|
||||
}
|
||||
@ -1300,7 +1285,6 @@ static int omap8250_runtime_suspend(struct device *dev)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
omap8250_enable_wakeup(priv, true);
|
||||
if (up->dma)
|
||||
omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
|
||||
|
||||
@ -1321,7 +1305,6 @@ static int omap8250_runtime_resume(struct device *dev)
|
||||
return 0;
|
||||
|
||||
up = serial8250_get_port(priv->line);
|
||||
omap8250_enable_wakeup(priv, false);
|
||||
loss_cntx = omap8250_lost_context(up);
|
||||
|
||||
if (loss_cntx)
|
||||
|
257
drivers/tty/serial/8250/8250_uniphier.c
Normal file
257
drivers/tty/serial/8250/8250_uniphier.c
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
|
||||
#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64
|
||||
|
||||
#define UNIPHIER_UART_CHAR_FCR 3 /* Character / FIFO Control Register */
|
||||
#define UNIPHIER_UART_LCR_MCR 4 /* Line/Modem Control Register */
|
||||
#define UNIPHIER_UART_LCR_SHIFT 8
|
||||
#define UNIPHIER_UART_DLR 9 /* Divisor Latch Register */
|
||||
|
||||
struct uniphier8250_priv {
|
||||
int line;
|
||||
struct clk *clk;
|
||||
spinlock_t atomic_write_lock;
|
||||
};
|
||||
|
||||
/*
|
||||
* The register map is slightly different from that of 8250.
|
||||
* IO callbacks must be overridden for correct access to FCR, LCR, and MCR.
|
||||
*/
|
||||
static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
unsigned int valshift = 0;
|
||||
|
||||
switch (offset) {
|
||||
case UART_LCR:
|
||||
valshift = UNIPHIER_UART_LCR_SHIFT;
|
||||
/* fall through */
|
||||
case UART_MCR:
|
||||
offset = UNIPHIER_UART_LCR_MCR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
offset <<= p->regshift;
|
||||
|
||||
/*
|
||||
* The return value must be masked with 0xff because LCR and MCR reside
|
||||
* in the same register that must be accessed by 32-bit write/read.
|
||||
* 8 or 16 bit access to this hardware result in unexpected behavior.
|
||||
*/
|
||||
return (readl(p->membase + offset) >> valshift) & 0xff;
|
||||
}
|
||||
|
||||
static void uniphier_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
unsigned int valshift = 0;
|
||||
bool normal = false;
|
||||
|
||||
switch (offset) {
|
||||
case UART_FCR:
|
||||
offset = UNIPHIER_UART_CHAR_FCR;
|
||||
break;
|
||||
case UART_LCR:
|
||||
valshift = UNIPHIER_UART_LCR_SHIFT;
|
||||
/* Divisor latch access bit does not exist. */
|
||||
value &= ~(UART_LCR_DLAB << valshift);
|
||||
/* fall through */
|
||||
case UART_MCR:
|
||||
offset = UNIPHIER_UART_LCR_MCR;
|
||||
break;
|
||||
default:
|
||||
normal = true;
|
||||
break;
|
||||
}
|
||||
|
||||
offset <<= p->regshift;
|
||||
|
||||
if (normal) {
|
||||
writel(value, p->membase + offset);
|
||||
} else {
|
||||
/*
|
||||
* Special case: two registers share the same address that
|
||||
* must be 32-bit accessed. As this is not longer atomic safe,
|
||||
* take a lock just in case.
|
||||
*/
|
||||
struct uniphier8250_priv *priv = p->private_data;
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
spin_lock_irqsave(&priv->atomic_write_lock, flags);
|
||||
tmp = readl(p->membase + offset);
|
||||
tmp &= ~(0xff << valshift);
|
||||
tmp |= value << valshift;
|
||||
writel(tmp, p->membase + offset);
|
||||
spin_unlock_irqrestore(&priv->atomic_write_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This hardware does not have the divisor latch access bit.
|
||||
* The divisor latch register exists at different address.
|
||||
* Override dl_read/write callbacks.
|
||||
*/
|
||||
static int uniphier_serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return readl(up->port.membase + UNIPHIER_UART_DLR);
|
||||
}
|
||||
|
||||
static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
writel(value, up->port.membase + UNIPHIER_UART_DLR);
|
||||
}
|
||||
|
||||
static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
|
||||
struct uniphier8250_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
u32 prop;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get alias id\n");
|
||||
return ret;
|
||||
}
|
||||
port->line = priv->line = ret;
|
||||
|
||||
/* Get clk rate through clk driver */
|
||||
priv->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->clk)) {
|
||||
dev_err(dev, "failed to get clock\n");
|
||||
return PTR_ERR(priv->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port->uartclk = clk_get_rate(priv->clk);
|
||||
|
||||
/* Check for fifo size */
|
||||
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
|
||||
port->fifosize = prop;
|
||||
else
|
||||
port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uart_8250_port up;
|
||||
struct uniphier8250_priv *priv;
|
||||
struct resource *regs;
|
||||
void __iomem *membase;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!regs) {
|
||||
dev_err(dev, "failed to get memory resource");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
membase = devm_ioremap(dev, regs->start, resource_size(regs));
|
||||
if (!membase)
|
||||
return -ENOMEM;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ number");
|
||||
return irq;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&up, 0, sizeof(up));
|
||||
|
||||
ret = uniphier_of_serial_setup(dev, &up.port, priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&priv->atomic_write_lock);
|
||||
|
||||
up.port.dev = dev;
|
||||
up.port.private_data = priv;
|
||||
up.port.mapbase = regs->start;
|
||||
up.port.mapsize = resource_size(regs);
|
||||
up.port.membase = membase;
|
||||
up.port.irq = irq;
|
||||
|
||||
up.port.type = PORT_16550A;
|
||||
up.port.iotype = UPIO_MEM32;
|
||||
up.port.regshift = 2;
|
||||
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
up.capabilities = UART_CAP_FIFO;
|
||||
|
||||
up.port.serial_in = uniphier_serial_in;
|
||||
up.port.serial_out = uniphier_serial_out;
|
||||
up.dl_read = uniphier_serial_dl_read;
|
||||
up.dl_write = uniphier_serial_dl_write;
|
||||
|
||||
ret = serial8250_register_8250_port(&up);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register 8250 port\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier8250_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
serial8250_unregister_port(priv->line);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id uniphier_uart_match[] = {
|
||||
{ .compatible = "socionext,uniphier-uart" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uniphier_uart_match);
|
||||
|
||||
static struct platform_driver uniphier_uart_platform_driver = {
|
||||
.probe = uniphier_uart_probe,
|
||||
.remove = uniphier_uart_remove,
|
||||
.driver = {
|
||||
.name = "uniphier-uart",
|
||||
.of_match_table = uniphier_uart_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(uniphier_uart_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
|
||||
MODULE_DESCRIPTION("UniPhier UART driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -336,9 +336,24 @@ config SERIAL_8250_FINTEK
|
||||
LPC to 4 UART. This device has some RS485 functionality not available
|
||||
through the PNP driver. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_LPC18XX
|
||||
bool "NXP LPC18xx/43xx serial port support"
|
||||
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
|
||||
default ARCH_LPC18XX
|
||||
help
|
||||
If you have a LPC18xx/43xx based board and want to use the
|
||||
serial port, say Y to this option. If unsure, say Y.
|
||||
|
||||
config SERIAL_8250_MT6577
|
||||
bool "Mediatek serial port support"
|
||||
depends on SERIAL_8250 && ARCH_MEDIATEK
|
||||
help
|
||||
If you have a Mediatek based board and want to use the
|
||||
serial port, say Y to this option. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_UNIPHIER
|
||||
tristate "Support for UniPhier on-chip UART"
|
||||
depends on SERIAL_8250 && ARCH_UNIPHIER
|
||||
help
|
||||
If you have a UniPhier based board and want to use the on-chip
|
||||
serial ports, say Y to this option. If unsure, say N.
|
||||
|
@ -22,4 +22,6 @@ obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
|
||||
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
|
||||
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
|
||||
obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
|
||||
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
|
||||
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
|
||||
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
|
||||
|
@ -241,7 +241,6 @@ config SERIAL_SAMSUNG
|
||||
tristate "Samsung SoC serial support"
|
||||
depends on PLAT_SAMSUNG || ARCH_EXYNOS
|
||||
select SERIAL_CORE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
|
||||
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
|
||||
@ -277,6 +276,7 @@ config SERIAL_SAMSUNG_CONSOLE
|
||||
bool "Support for console on Samsung SoC serial port"
|
||||
depends on SERIAL_SAMSUNG=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Allow selection of the S3C24XX on-board serial ports for use as
|
||||
an virtual console.
|
||||
@ -1179,15 +1179,42 @@ config SERIAL_SCCNXP_CONSOLE
|
||||
help
|
||||
Support for console on SCCNXP serial ports.
|
||||
|
||||
config SERIAL_SC16IS7XX_CORE
|
||||
tristate
|
||||
|
||||
config SERIAL_SC16IS7XX
|
||||
tristate "SC16IS7xx serial support"
|
||||
depends on I2C
|
||||
select SERIAL_CORE
|
||||
select REGMAP_I2C if I2C
|
||||
help
|
||||
This selects support for SC16IS7xx serial ports.
|
||||
Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
|
||||
SC16IS760 and SC16IS762.
|
||||
tristate "SC16IS7xx serial support"
|
||||
select SERIAL_CORE
|
||||
depends on I2C || SPI_MASTER
|
||||
help
|
||||
This selects support for SC16IS7xx serial ports.
|
||||
Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
|
||||
SC16IS760 and SC16IS762. Select supported buses using options below.
|
||||
|
||||
config SERIAL_SC16IS7XX_I2C
|
||||
bool "SC16IS7xx for I2C interface"
|
||||
depends on SERIAL_SC16IS7XX
|
||||
depends on I2C
|
||||
select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
|
||||
select REGMAP_I2C if I2C
|
||||
default y
|
||||
help
|
||||
Enable SC16IS7xx driver on I2C bus,
|
||||
If required say y, and say n to i2c if not required,
|
||||
Enabled by default to support oldconfig.
|
||||
You must select at least one bus for the driver to be built.
|
||||
|
||||
config SERIAL_SC16IS7XX_SPI
|
||||
bool "SC16IS7xx for spi interface"
|
||||
depends on SERIAL_SC16IS7XX
|
||||
depends on SPI_MASTER
|
||||
select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
|
||||
select REGMAP_SPI if SPI_MASTER
|
||||
help
|
||||
Enable SC16IS7xx driver on SPI bus,
|
||||
If required say y, and say n to spi if not required,
|
||||
This is additional support to exsisting driver.
|
||||
You must select at least one bus for the driver to be built.
|
||||
|
||||
config SERIAL_BFIN_SPORT
|
||||
tristate "Blackfin SPORT emulate UART"
|
||||
@ -1349,7 +1376,7 @@ config SERIAL_ALTERA_UART_CONSOLE
|
||||
|
||||
config SERIAL_IFX6X60
|
||||
tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
|
||||
depends on GPIOLIB && SPI
|
||||
depends on GPIOLIB && SPI && HAS_DMA
|
||||
help
|
||||
Support for the IFX6x60 modem devices on Intel MID platforms.
|
||||
|
||||
@ -1378,14 +1405,6 @@ config SERIAL_PCH_UART_CONSOLE
|
||||
(the system console is the device which receives all kernel messages and
|
||||
warnings and which allows logins in single user mode).
|
||||
|
||||
config SERIAL_MSM_SMD
|
||||
bool "Enable tty device interface for some SMD ports"
|
||||
default n
|
||||
depends on MSM_SMD
|
||||
help
|
||||
Enables userspace clients to read and write to some streaming SMD
|
||||
ports via tty device interface for MSM chipset.
|
||||
|
||||
config SERIAL_MXS_AUART
|
||||
depends on ARCH_MXS
|
||||
tristate "MXS AUART support"
|
||||
|
@ -53,7 +53,7 @@ obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
|
||||
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
|
||||
obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o
|
||||
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
|
||||
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
|
||||
obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
|
||||
obj-$(CONFIG_SERIAL_JSM) += jsm/
|
||||
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
|
||||
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
|
||||
@ -79,7 +79,6 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
|
||||
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
|
||||
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
|
||||
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
|
||||
obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o
|
||||
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
|
||||
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
|
||||
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
|
||||
|
@ -387,7 +387,7 @@ console_initcall(altera_jtaguart_console_init);
|
||||
|
||||
#define ALTERA_JTAGUART_CONSOLE NULL
|
||||
|
||||
#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
|
||||
#endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */
|
||||
|
||||
static struct uart_driver altera_jtaguart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -493,7 +493,7 @@ console_initcall(altera_uart_console_init);
|
||||
|
||||
#define ALTERA_UART_CONSOLE NULL
|
||||
|
||||
#endif /* CONFIG_ALTERA_UART_CONSOLE */
|
||||
#endif /* CONFIG_SERIAL_ALTERA_UART_CONSOLE */
|
||||
|
||||
/*
|
||||
* Define the altera_uart UART driver structure.
|
||||
|
@ -58,7 +58,7 @@
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define UART_NR 14
|
||||
|
||||
@ -79,6 +79,8 @@ struct vendor_data {
|
||||
bool oversampling;
|
||||
bool dma_threshold;
|
||||
bool cts_event_workaround;
|
||||
bool always_enabled;
|
||||
bool fixed_options;
|
||||
|
||||
unsigned int (*get_fifosize)(struct amba_device *dev);
|
||||
};
|
||||
@ -95,9 +97,19 @@ static struct vendor_data vendor_arm = {
|
||||
.oversampling = false,
|
||||
.dma_threshold = false,
|
||||
.cts_event_workaround = false,
|
||||
.always_enabled = false,
|
||||
.fixed_options = false,
|
||||
.get_fifosize = get_fifosize_arm,
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_sbsa = {
|
||||
.oversampling = false,
|
||||
.dma_threshold = false,
|
||||
.cts_event_workaround = false,
|
||||
.always_enabled = true,
|
||||
.fixed_options = true,
|
||||
};
|
||||
|
||||
static unsigned int get_fifosize_st(struct amba_device *dev)
|
||||
{
|
||||
return 64;
|
||||
@ -110,6 +122,8 @@ static struct vendor_data vendor_st = {
|
||||
.oversampling = true,
|
||||
.dma_threshold = true,
|
||||
.cts_event_workaround = true,
|
||||
.always_enabled = false,
|
||||
.fixed_options = false,
|
||||
.get_fifosize = get_fifosize_st,
|
||||
};
|
||||
|
||||
@ -157,9 +171,8 @@ struct uart_amba_port {
|
||||
unsigned int lcrh_tx; /* vendor-specific */
|
||||
unsigned int lcrh_rx; /* vendor-specific */
|
||||
unsigned int old_cr; /* state during shutdown */
|
||||
struct delayed_work tx_softirq_work;
|
||||
bool autorts;
|
||||
unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */
|
||||
unsigned int fixed_baud; /* vendor-set fixed baud rate */
|
||||
char type[12];
|
||||
#ifdef CONFIG_DMA_ENGINE
|
||||
/* DMA stuff */
|
||||
@ -1172,15 +1185,14 @@ static void pl011_stop_tx(struct uart_port *port)
|
||||
pl011_dma_tx_stop(uap);
|
||||
}
|
||||
|
||||
static bool pl011_tx_chars(struct uart_amba_port *uap);
|
||||
static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
|
||||
|
||||
/* Start TX with programmed I/O only (no DMA) */
|
||||
static void pl011_start_tx_pio(struct uart_amba_port *uap)
|
||||
{
|
||||
uap->im |= UART011_TXIM;
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
if (!uap->tx_irq_seen)
|
||||
pl011_tx_chars(uap);
|
||||
pl011_tx_chars(uap, false);
|
||||
}
|
||||
|
||||
static void pl011_start_tx(struct uart_port *port)
|
||||
@ -1247,15 +1259,11 @@ __acquires(&uap->port.lock)
|
||||
spin_lock(&uap->port.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Transmit a character
|
||||
*
|
||||
* Returns true if the character was successfully queued to the FIFO.
|
||||
* Returns false otherwise.
|
||||
*/
|
||||
static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
|
||||
static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
|
||||
bool from_irq)
|
||||
{
|
||||
if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
|
||||
if (unlikely(!from_irq) &&
|
||||
readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)
|
||||
return false; /* unable to transmit character */
|
||||
|
||||
writew(c, uap->port.membase + UART01x_DR);
|
||||
@ -1264,70 +1272,41 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool pl011_tx_chars(struct uart_amba_port *uap)
|
||||
static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
|
||||
{
|
||||
struct circ_buf *xmit = &uap->port.state->xmit;
|
||||
int count;
|
||||
|
||||
if (unlikely(uap->tx_irq_seen < 2))
|
||||
/*
|
||||
* Initial FIFO fill level unknown: we must check TXFF
|
||||
* after each write, so just try to fill up the FIFO.
|
||||
*/
|
||||
count = uap->fifosize;
|
||||
else /* tx_irq_seen >= 2 */
|
||||
/*
|
||||
* FIFO initially at least half-empty, so we can simply
|
||||
* write half the FIFO without polling TXFF.
|
||||
|
||||
* Note: the *first* TX IRQ can still race with
|
||||
* pl011_start_tx_pio(), which can result in the FIFO
|
||||
* being fuller than expected in that case.
|
||||
*/
|
||||
count = uap->fifosize >> 1;
|
||||
|
||||
/*
|
||||
* If the FIFO is full we're guaranteed a TX IRQ at some later point,
|
||||
* and can't transmit immediately in any case:
|
||||
*/
|
||||
if (unlikely(uap->tx_irq_seen < 2 &&
|
||||
readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF))
|
||||
return false;
|
||||
int count = uap->fifosize >> 1;
|
||||
|
||||
if (uap->port.x_char) {
|
||||
if (!pl011_tx_char(uap, uap->port.x_char))
|
||||
goto done;
|
||||
if (!pl011_tx_char(uap, uap->port.x_char, from_irq))
|
||||
return;
|
||||
uap->port.x_char = 0;
|
||||
--count;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
|
||||
pl011_stop_tx(&uap->port);
|
||||
goto done;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we are using DMA mode, try to send some characters. */
|
||||
if (pl011_dma_tx_irq(uap))
|
||||
goto done;
|
||||
return;
|
||||
|
||||
while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) {
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
do {
|
||||
if (likely(from_irq) && count-- == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
|
||||
break;
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
} while (!uart_circ_empty(xmit));
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
if (uart_circ_empty(xmit))
|
||||
pl011_stop_tx(&uap->port);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (unlikely(!uap->tx_irq_seen))
|
||||
schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout);
|
||||
|
||||
done:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void pl011_modem_status(struct uart_amba_port *uap)
|
||||
@ -1354,26 +1333,23 @@ static void pl011_modem_status(struct uart_amba_port *uap)
|
||||
wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
static void pl011_tx_softirq(struct work_struct *work)
|
||||
static void check_apply_cts_event_workaround(struct uart_amba_port *uap)
|
||||
{
|
||||
struct delayed_work *dwork = to_delayed_work(work);
|
||||
struct uart_amba_port *uap =
|
||||
container_of(dwork, struct uart_amba_port, tx_softirq_work);
|
||||
unsigned int dummy_read;
|
||||
|
||||
spin_lock(&uap->port.lock);
|
||||
while (pl011_tx_chars(uap)) ;
|
||||
spin_unlock(&uap->port.lock);
|
||||
}
|
||||
|
||||
static void pl011_tx_irq_seen(struct uart_amba_port *uap)
|
||||
{
|
||||
if (likely(uap->tx_irq_seen > 1))
|
||||
if (!uap->vendor->cts_event_workaround)
|
||||
return;
|
||||
|
||||
uap->tx_irq_seen++;
|
||||
if (uap->tx_irq_seen < 2)
|
||||
/* first TX IRQ */
|
||||
cancel_delayed_work(&uap->tx_softirq_work);
|
||||
/* workaround to make sure that all bits are unlocked.. */
|
||||
writew(0x00, uap->port.membase + UART011_ICR);
|
||||
|
||||
/*
|
||||
* WA: introduce 26ns(1 uart clk) delay before W1C;
|
||||
* single apb access will incur 2 pclk(133.12Mhz) delay,
|
||||
* so add 2 dummy reads
|
||||
*/
|
||||
dummy_read = readw(uap->port.membase + UART011_ICR);
|
||||
dummy_read = readw(uap->port.membase + UART011_ICR);
|
||||
}
|
||||
|
||||
static irqreturn_t pl011_int(int irq, void *dev_id)
|
||||
@ -1381,25 +1357,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
||||
struct uart_amba_port *uap = dev_id;
|
||||
unsigned long flags;
|
||||
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
|
||||
u16 imsc;
|
||||
int handled = 0;
|
||||
unsigned int dummy_read;
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
status = readw(uap->port.membase + UART011_MIS);
|
||||
imsc = readw(uap->port.membase + UART011_IMSC);
|
||||
status = readw(uap->port.membase + UART011_RIS) & imsc;
|
||||
if (status) {
|
||||
do {
|
||||
if (uap->vendor->cts_event_workaround) {
|
||||
/* workaround to make sure that all bits are unlocked.. */
|
||||
writew(0x00, uap->port.membase + UART011_ICR);
|
||||
|
||||
/*
|
||||
* WA: introduce 26ns(1 uart clk) delay before W1C;
|
||||
* single apb access will incur 2 pclk(133.12Mhz) delay,
|
||||
* so add 2 dummy reads
|
||||
*/
|
||||
dummy_read = readw(uap->port.membase + UART011_ICR);
|
||||
dummy_read = readw(uap->port.membase + UART011_ICR);
|
||||
}
|
||||
check_apply_cts_event_workaround(uap);
|
||||
|
||||
writew(status & ~(UART011_TXIS|UART011_RTIS|
|
||||
UART011_RXIS),
|
||||
@ -1414,15 +1380,13 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
||||
if (status & (UART011_DSRMIS|UART011_DCDMIS|
|
||||
UART011_CTSMIS|UART011_RIMIS))
|
||||
pl011_modem_status(uap);
|
||||
if (status & UART011_TXIS) {
|
||||
pl011_tx_irq_seen(uap);
|
||||
pl011_tx_chars(uap);
|
||||
}
|
||||
if (status & UART011_TXIS)
|
||||
pl011_tx_chars(uap, true);
|
||||
|
||||
if (pass_counter-- == 0)
|
||||
break;
|
||||
|
||||
status = readw(uap->port.membase + UART011_MIS);
|
||||
status = readw(uap->port.membase + UART011_RIS) & imsc;
|
||||
} while (status != 0);
|
||||
handled = 1;
|
||||
}
|
||||
@ -1617,6 +1581,32 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
|
||||
}
|
||||
}
|
||||
|
||||
static int pl011_allocate_irq(struct uart_amba_port *uap)
|
||||
{
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
|
||||
return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable interrupts, only timeouts when using DMA
|
||||
* if initial RX DMA job failed, start in interrupt mode
|
||||
* as well.
|
||||
*/
|
||||
static void pl011_enable_interrupts(struct uart_amba_port *uap)
|
||||
{
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
|
||||
/* Clear out any spuriously appearing RX interrupts */
|
||||
writew(UART011_RTIS | UART011_RXIS,
|
||||
uap->port.membase + UART011_ICR);
|
||||
uap->im = UART011_RTIM;
|
||||
if (!pl011_dma_rx_running(uap))
|
||||
uap->im |= UART011_RXIM;
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
spin_unlock_irq(&uap->port.lock);
|
||||
}
|
||||
|
||||
static int pl011_startup(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
@ -1628,20 +1618,12 @@ static int pl011_startup(struct uart_port *port)
|
||||
if (retval)
|
||||
goto clk_dis;
|
||||
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
|
||||
/*
|
||||
* Allocate the IRQ
|
||||
*/
|
||||
retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
|
||||
retval = pl011_allocate_irq(uap);
|
||||
if (retval)
|
||||
goto clk_dis;
|
||||
|
||||
writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
|
||||
|
||||
/* Assume that TX IRQ doesn't work until we see one: */
|
||||
uap->tx_irq_seen = 0;
|
||||
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
|
||||
/* restore RTS and DTR */
|
||||
@ -1659,20 +1641,7 @@ static int pl011_startup(struct uart_port *port)
|
||||
/* Startup DMA */
|
||||
pl011_dma_startup(uap);
|
||||
|
||||
/*
|
||||
* Finally, enable interrupts, only timeouts when using DMA
|
||||
* if initial RX DMA job failed, start in interrupt mode
|
||||
* as well.
|
||||
*/
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
/* Clear out any spuriously appearing RX interrupts */
|
||||
writew(UART011_RTIS | UART011_RXIS,
|
||||
uap->port.membase + UART011_ICR);
|
||||
uap->im = UART011_RTIM;
|
||||
if (!pl011_dma_rx_running(uap))
|
||||
uap->im |= UART011_RXIM;
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
spin_unlock_irq(&uap->port.lock);
|
||||
pl011_enable_interrupts(uap);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1681,6 +1650,28 @@ static int pl011_startup(struct uart_port *port)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int sbsa_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
int retval;
|
||||
|
||||
retval = pl011_hwinit(port);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = pl011_allocate_irq(uap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* The SBSA UART does not support any modem status lines. */
|
||||
uap->old_status = 0;
|
||||
|
||||
pl011_enable_interrupts(uap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pl011_shutdown_channel(struct uart_amba_port *uap,
|
||||
unsigned int lcrh)
|
||||
{
|
||||
@ -1691,36 +1682,15 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap,
|
||||
writew(val, uap->port.membase + lcrh);
|
||||
}
|
||||
|
||||
static void pl011_shutdown(struct uart_port *port)
|
||||
/*
|
||||
* disable the port. It should not disable RTS and DTR.
|
||||
* Also RTS and DTR state should be preserved to restore
|
||||
* it during startup().
|
||||
*/
|
||||
static void pl011_disable_uart(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int cr;
|
||||
|
||||
cancel_delayed_work_sync(&uap->tx_softirq_work);
|
||||
|
||||
/*
|
||||
* disable all interrupts
|
||||
*/
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
uap->im = 0;
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
writew(0xffff, uap->port.membase + UART011_ICR);
|
||||
spin_unlock_irq(&uap->port.lock);
|
||||
|
||||
pl011_dma_shutdown(uap);
|
||||
|
||||
/*
|
||||
* Free the interrupt
|
||||
*/
|
||||
free_irq(uap->port.irq, uap);
|
||||
|
||||
/*
|
||||
* disable the port
|
||||
* disable the port. It should not disable RTS and DTR.
|
||||
* Also RTS and DTR state should be preserved to restore
|
||||
* it during startup().
|
||||
*/
|
||||
uap->autorts = false;
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
cr = readw(uap->port.membase + UART011_CR);
|
||||
@ -1736,6 +1706,32 @@ static void pl011_shutdown(struct uart_port *port)
|
||||
pl011_shutdown_channel(uap, uap->lcrh_rx);
|
||||
if (uap->lcrh_rx != uap->lcrh_tx)
|
||||
pl011_shutdown_channel(uap, uap->lcrh_tx);
|
||||
}
|
||||
|
||||
static void pl011_disable_interrupts(struct uart_amba_port *uap)
|
||||
{
|
||||
spin_lock_irq(&uap->port.lock);
|
||||
|
||||
/* mask all interrupts and clear all pending ones */
|
||||
uap->im = 0;
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
writew(0xffff, uap->port.membase + UART011_ICR);
|
||||
|
||||
spin_unlock_irq(&uap->port.lock);
|
||||
}
|
||||
|
||||
static void pl011_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
pl011_disable_interrupts(uap);
|
||||
|
||||
pl011_dma_shutdown(uap);
|
||||
|
||||
free_irq(uap->port.irq, uap);
|
||||
|
||||
pl011_disable_uart(uap);
|
||||
|
||||
/*
|
||||
* Shut down the clock producer
|
||||
@ -1756,6 +1752,51 @@ static void pl011_shutdown(struct uart_port *port)
|
||||
uap->port.ops->flush_buffer(port);
|
||||
}
|
||||
|
||||
static void sbsa_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
pl011_disable_interrupts(uap);
|
||||
|
||||
free_irq(uap->port.irq, uap);
|
||||
|
||||
if (uap->port.ops->flush_buffer)
|
||||
uap->port.ops->flush_buffer(port);
|
||||
}
|
||||
|
||||
static void
|
||||
pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios)
|
||||
{
|
||||
port->read_status_mask = UART011_DR_OE | 255;
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
|
||||
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||
port->read_status_mask |= UART011_DR_BE;
|
||||
|
||||
/*
|
||||
* Characters to ignore
|
||||
*/
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
|
||||
if (termios->c_iflag & IGNBRK) {
|
||||
port->ignore_status_mask |= UART011_DR_BE;
|
||||
/*
|
||||
* If we're ignoring parity and break indicators,
|
||||
* ignore overruns too (for real raw support).
|
||||
*/
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= UART011_DR_OE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore all characters if CREAD is not set.
|
||||
*/
|
||||
if ((termios->c_cflag & CREAD) == 0)
|
||||
port->ignore_status_mask |= UART_DUMMY_DR_RX;
|
||||
}
|
||||
|
||||
static void
|
||||
pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
@ -1820,33 +1861,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
*/
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
port->read_status_mask = UART011_DR_OE | 255;
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= UART011_DR_FE | UART011_DR_PE;
|
||||
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||
port->read_status_mask |= UART011_DR_BE;
|
||||
|
||||
/*
|
||||
* Characters to ignore
|
||||
*/
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE;
|
||||
if (termios->c_iflag & IGNBRK) {
|
||||
port->ignore_status_mask |= UART011_DR_BE;
|
||||
/*
|
||||
* If we're ignoring parity and break indicators,
|
||||
* ignore overruns too (for real raw support).
|
||||
*/
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= UART011_DR_OE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore all characters if CREAD is not set.
|
||||
*/
|
||||
if ((termios->c_cflag & CREAD) == 0)
|
||||
port->ignore_status_mask |= UART_DUMMY_DR_RX;
|
||||
pl011_setup_status_masks(port, termios);
|
||||
|
||||
if (UART_ENABLE_MS(port, termios->c_cflag))
|
||||
pl011_enable_ms(port);
|
||||
@ -1901,6 +1916,27 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud);
|
||||
|
||||
/* The SBSA UART only supports 8n1 without hardware flow control. */
|
||||
termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
|
||||
termios->c_cflag &= ~(CMSPAR | CRTSCTS);
|
||||
termios->c_cflag |= CS8 | CLOCAL;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
uart_update_timeout(port, CS8, uap->fixed_baud);
|
||||
pl011_setup_status_masks(port, termios);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *pl011_type(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
@ -1976,6 +2012,37 @@ static struct uart_ops amba_pl011_pops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
}
|
||||
|
||||
static unsigned int sbsa_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct uart_ops sbsa_uart_pops = {
|
||||
.tx_empty = pl011_tx_empty,
|
||||
.set_mctrl = sbsa_uart_set_mctrl,
|
||||
.get_mctrl = sbsa_uart_get_mctrl,
|
||||
.stop_tx = pl011_stop_tx,
|
||||
.start_tx = pl011_start_tx,
|
||||
.stop_rx = pl011_stop_rx,
|
||||
.startup = sbsa_uart_startup,
|
||||
.shutdown = sbsa_uart_shutdown,
|
||||
.set_termios = sbsa_uart_set_termios,
|
||||
.type = pl011_type,
|
||||
.release_port = pl011_release_port,
|
||||
.request_port = pl011_request_port,
|
||||
.config_port = pl011_config_port,
|
||||
.verify_port = pl011_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_init = pl011_hwinit,
|
||||
.poll_get_char = pl011_get_poll_char,
|
||||
.poll_put_char = pl011_put_poll_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct uart_amba_port *amba_ports[UART_NR];
|
||||
|
||||
#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE
|
||||
@ -1994,7 +2061,7 @@ static void
|
||||
pl011_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_amba_port *uap = amba_ports[co->index];
|
||||
unsigned int status, old_cr, new_cr;
|
||||
unsigned int status, old_cr = 0, new_cr;
|
||||
unsigned long flags;
|
||||
int locked = 1;
|
||||
|
||||
@ -2011,10 +2078,12 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
|
||||
/*
|
||||
* First save the CR then disable the interrupts
|
||||
*/
|
||||
old_cr = readw(uap->port.membase + UART011_CR);
|
||||
new_cr = old_cr & ~UART011_CR_CTSEN;
|
||||
new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
|
||||
writew(new_cr, uap->port.membase + UART011_CR);
|
||||
if (!uap->vendor->always_enabled) {
|
||||
old_cr = readw(uap->port.membase + UART011_CR);
|
||||
new_cr = old_cr & ~UART011_CR_CTSEN;
|
||||
new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
|
||||
writew(new_cr, uap->port.membase + UART011_CR);
|
||||
}
|
||||
|
||||
uart_console_write(&uap->port, s, count, pl011_console_putchar);
|
||||
|
||||
@ -2025,7 +2094,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
|
||||
do {
|
||||
status = readw(uap->port.membase + UART01x_FR);
|
||||
} while (status & UART01x_FR_BUSY);
|
||||
writew(old_cr, uap->port.membase + UART011_CR);
|
||||
if (!uap->vendor->always_enabled)
|
||||
writew(old_cr, uap->port.membase + UART011_CR);
|
||||
|
||||
if (locked)
|
||||
spin_unlock(&uap->port.lock);
|
||||
@ -2106,10 +2176,15 @@ static int __init pl011_console_setup(struct console *co, char *options)
|
||||
|
||||
uap->port.uartclk = clk_get_rate(uap->clk);
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
else
|
||||
pl011_console_get_options(uap, &baud, &parity, &bits);
|
||||
if (uap->vendor->fixed_options) {
|
||||
baud = uap->fixed_baud;
|
||||
} else {
|
||||
if (options)
|
||||
uart_parse_options(options,
|
||||
&baud, &parity, &bits, &flow);
|
||||
else
|
||||
pl011_console_get_options(uap, &baud, &parity, &bits);
|
||||
}
|
||||
|
||||
return uart_set_options(&uap->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
@ -2201,30 +2276,96 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* unregisters the driver also if no more ports are left */
|
||||
static void pl011_unregister_port(struct uart_amba_port *uap)
|
||||
{
|
||||
int i;
|
||||
bool busy = false;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
|
||||
if (amba_ports[i] == uap)
|
||||
amba_ports[i] = NULL;
|
||||
else if (amba_ports[i])
|
||||
busy = true;
|
||||
}
|
||||
pl011_dma_remove(uap);
|
||||
if (!busy)
|
||||
uart_unregister_driver(&amba_reg);
|
||||
}
|
||||
|
||||
static int pl011_find_free_port(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
|
||||
if (amba_ports[i] == NULL)
|
||||
return i;
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
|
||||
struct resource *mmiobase, int index)
|
||||
{
|
||||
void __iomem *base;
|
||||
|
||||
base = devm_ioremap_resource(dev, mmiobase);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
index = pl011_probe_dt_alias(index, dev);
|
||||
|
||||
uap->old_cr = 0;
|
||||
uap->port.dev = dev;
|
||||
uap->port.mapbase = mmiobase->start;
|
||||
uap->port.membase = base;
|
||||
uap->port.iotype = UPIO_MEM;
|
||||
uap->port.fifosize = uap->fifosize;
|
||||
uap->port.flags = UPF_BOOT_AUTOCONF;
|
||||
uap->port.line = index;
|
||||
|
||||
amba_ports[index] = uap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl011_register_port(struct uart_amba_port *uap)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Ensure interrupts from this UART are masked and cleared */
|
||||
writew(0, uap->port.membase + UART011_IMSC);
|
||||
writew(0xffff, uap->port.membase + UART011_ICR);
|
||||
|
||||
if (!amba_reg.state) {
|
||||
ret = uart_register_driver(&amba_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(uap->port.dev,
|
||||
"Failed to register AMBA-PL011 driver\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&amba_reg, &uap->port);
|
||||
if (ret)
|
||||
pl011_unregister_port(uap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
||||
{
|
||||
struct uart_amba_port *uap;
|
||||
struct vendor_data *vendor = id->data;
|
||||
void __iomem *base;
|
||||
int i, ret;
|
||||
int portnr, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
|
||||
if (amba_ports[i] == NULL)
|
||||
break;
|
||||
|
||||
if (i == ARRAY_SIZE(amba_ports))
|
||||
return -EBUSY;
|
||||
portnr = pl011_find_free_port();
|
||||
if (portnr < 0)
|
||||
return portnr;
|
||||
|
||||
uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
|
||||
GFP_KERNEL);
|
||||
if (uap == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
i = pl011_probe_dt_alias(i, &dev->dev);
|
||||
|
||||
base = devm_ioremap(&dev->dev, dev->res.start,
|
||||
resource_size(&dev->res));
|
||||
if (!base)
|
||||
if (!uap)
|
||||
return -ENOMEM;
|
||||
|
||||
uap->clk = devm_clk_get(&dev->dev, NULL);
|
||||
@ -2234,64 +2375,27 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
||||
uap->vendor = vendor;
|
||||
uap->lcrh_rx = vendor->lcrh_rx;
|
||||
uap->lcrh_tx = vendor->lcrh_tx;
|
||||
uap->old_cr = 0;
|
||||
uap->fifosize = vendor->get_fifosize(dev);
|
||||
uap->port.dev = &dev->dev;
|
||||
uap->port.mapbase = dev->res.start;
|
||||
uap->port.membase = base;
|
||||
uap->port.iotype = UPIO_MEM;
|
||||
uap->port.irq = dev->irq[0];
|
||||
uap->port.fifosize = uap->fifosize;
|
||||
uap->port.ops = &amba_pl011_pops;
|
||||
uap->port.flags = UPF_BOOT_AUTOCONF;
|
||||
uap->port.line = i;
|
||||
INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq);
|
||||
|
||||
/* Ensure interrupts from this UART are masked and cleared */
|
||||
writew(0, uap->port.membase + UART011_IMSC);
|
||||
writew(0xffff, uap->port.membase + UART011_ICR);
|
||||
|
||||
snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
|
||||
|
||||
amba_ports[i] = uap;
|
||||
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
amba_set_drvdata(dev, uap);
|
||||
|
||||
if (!amba_reg.state) {
|
||||
ret = uart_register_driver(&amba_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&dev->dev,
|
||||
"Failed to register AMBA-PL011 driver\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&amba_reg, &uap->port);
|
||||
if (ret) {
|
||||
amba_ports[i] = NULL;
|
||||
uart_unregister_driver(&amba_reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return pl011_register_port(uap);
|
||||
}
|
||||
|
||||
static int pl011_remove(struct amba_device *dev)
|
||||
{
|
||||
struct uart_amba_port *uap = amba_get_drvdata(dev);
|
||||
bool busy = false;
|
||||
int i;
|
||||
|
||||
uart_remove_one_port(&amba_reg, &uap->port);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
|
||||
if (amba_ports[i] == uap)
|
||||
amba_ports[i] = NULL;
|
||||
else if (amba_ports[i])
|
||||
busy = true;
|
||||
|
||||
pl011_dma_remove(uap);
|
||||
if (!busy)
|
||||
uart_unregister_driver(&amba_reg);
|
||||
pl011_unregister_port(uap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2319,6 +2423,86 @@ static int pl011_resume(struct device *dev)
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
|
||||
|
||||
static int sbsa_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_amba_port *uap;
|
||||
struct resource *r;
|
||||
int portnr, ret;
|
||||
int baudrate;
|
||||
|
||||
/*
|
||||
* Check the mandatory baud rate parameter in the DT node early
|
||||
* so that we can easily exit with the error.
|
||||
*/
|
||||
if (pdev->dev.of_node) {
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
ret = of_property_read_u32(np, "current-speed", &baudrate);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
baudrate = 115200;
|
||||
}
|
||||
|
||||
portnr = pl011_find_free_port();
|
||||
if (portnr < 0)
|
||||
return portnr;
|
||||
|
||||
uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
|
||||
GFP_KERNEL);
|
||||
if (!uap)
|
||||
return -ENOMEM;
|
||||
|
||||
uap->vendor = &vendor_sbsa;
|
||||
uap->fifosize = 32;
|
||||
uap->port.irq = platform_get_irq(pdev, 0);
|
||||
uap->port.ops = &sbsa_uart_pops;
|
||||
uap->fixed_baud = baudrate;
|
||||
|
||||
snprintf(uap->type, sizeof(uap->type), "SBSA");
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, uap);
|
||||
|
||||
return pl011_register_port(uap);
|
||||
}
|
||||
|
||||
static int sbsa_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_amba_port *uap = platform_get_drvdata(pdev);
|
||||
|
||||
uart_remove_one_port(&amba_reg, &uap->port);
|
||||
pl011_unregister_port(uap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sbsa_uart_of_match[] = {
|
||||
{ .compatible = "arm,sbsa-uart", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
|
||||
|
||||
static const struct acpi_device_id sbsa_uart_acpi_match[] = {
|
||||
{ "ARMH0011", 0 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
|
||||
|
||||
static struct platform_driver arm_sbsa_uart_platform_driver = {
|
||||
.probe = sbsa_uart_probe,
|
||||
.remove = sbsa_uart_remove,
|
||||
.driver = {
|
||||
.name = "sbsa-uart",
|
||||
.of_match_table = of_match_ptr(sbsa_uart_of_match),
|
||||
.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
|
||||
},
|
||||
};
|
||||
|
||||
static struct amba_id pl011_ids[] = {
|
||||
{
|
||||
.id = 0x00041011,
|
||||
@ -2349,11 +2533,14 @@ static int __init pl011_init(void)
|
||||
{
|
||||
printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
|
||||
|
||||
if (platform_driver_register(&arm_sbsa_uart_platform_driver))
|
||||
pr_warn("could not register SBSA UART platform driver\n");
|
||||
return amba_driver_register(&pl011_driver);
|
||||
}
|
||||
|
||||
static void __exit pl011_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&arm_sbsa_uart_platform_driver);
|
||||
amba_driver_unregister(&pl011_driver);
|
||||
}
|
||||
|
||||
|
@ -165,6 +165,7 @@ struct atmel_uart_port {
|
||||
struct tasklet_struct tasklet;
|
||||
unsigned int irq_status;
|
||||
unsigned int irq_status_prev;
|
||||
unsigned int status_change;
|
||||
|
||||
struct circ_buf rx_ring;
|
||||
|
||||
@ -315,8 +316,7 @@ static int atmel_config_rs485(struct uart_port *port,
|
||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
|
||||
if ((rs485conf->delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
|
||||
UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else {
|
||||
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||
@ -354,8 +354,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
||||
|
||||
/* override mode to RS485 if needed, otherwise keep the current mode */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if ((port->rs485.delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
||||
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
||||
mode &= ~ATMEL_US_USMODE;
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
}
|
||||
@ -1177,6 +1176,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
|
||||
if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
|
||||
| ATMEL_US_CTSIC)) {
|
||||
atmel_port->irq_status = status;
|
||||
atmel_port->status_change = atmel_port->irq_status ^
|
||||
atmel_port->irq_status_prev;
|
||||
atmel_port->irq_status_prev = status;
|
||||
tasklet_schedule(&atmel_port->tasklet);
|
||||
}
|
||||
}
|
||||
@ -1523,17 +1525,14 @@ static void atmel_tasklet_func(unsigned long data)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)data;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int status;
|
||||
unsigned int status_change;
|
||||
unsigned int status = atmel_port->irq_status;
|
||||
unsigned int status_change = atmel_port->status_change;
|
||||
|
||||
/* The interrupt handler does not take the lock */
|
||||
spin_lock(&port->lock);
|
||||
|
||||
atmel_port->schedule_tx(port);
|
||||
|
||||
status = atmel_port->irq_status;
|
||||
status_change = status ^ atmel_port->irq_status_prev;
|
||||
|
||||
if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
|
||||
| ATMEL_US_DCD | ATMEL_US_CTS)) {
|
||||
/* TODO: All reads to CSR will clear these interrupts! */
|
||||
@ -1548,7 +1547,7 @@ static void atmel_tasklet_func(unsigned long data)
|
||||
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
|
||||
atmel_port->irq_status_prev = status;
|
||||
atmel_port->status_change = 0;
|
||||
}
|
||||
|
||||
atmel_port->schedule_rx(port);
|
||||
@ -2061,8 +2060,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
|
||||
/* mode */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if ((port->rs485.delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
||||
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else if (termios->c_cflag & CRTSCTS) {
|
||||
/* RS232 with hardware handshake (RTS/CTS) */
|
||||
|
@ -74,8 +74,8 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
|
||||
|
||||
static void bfin_serial_reset_irda(struct uart_port *port);
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
|
||||
defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
|
||||
#if defined(SERIAL_BFIN_CTSRTS) || \
|
||||
defined(SERIAL_BFIN_HARD_CTSRTS)
|
||||
static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
|
||||
@ -110,7 +110,7 @@ static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
|
||||
struct bfin_serial_port *uart = dev_id;
|
||||
struct uart_port *uport = &uart->port;
|
||||
unsigned int status = bfin_serial_get_mctrl(uport);
|
||||
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
#ifdef SERIAL_BFIN_HARD_CTSRTS
|
||||
|
||||
UART_CLEAR_SCTS(uart);
|
||||
if (uport->hw_stopped) {
|
||||
@ -700,7 +700,7 @@ static int bfin_serial_startup(struct uart_port *port)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
|
||||
#ifdef SERIAL_BFIN_CTSRTS
|
||||
if (uart->cts_pin >= 0) {
|
||||
if (request_irq(gpio_to_irq(uart->cts_pin),
|
||||
bfin_serial_mctrl_cts_int,
|
||||
@ -718,7 +718,7 @@ static int bfin_serial_startup(struct uart_port *port)
|
||||
gpio_direction_output(uart->rts_pin, 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
#ifdef SERIAL_BFIN_HARD_CTSRTS
|
||||
if (uart->cts_pin >= 0) {
|
||||
if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int,
|
||||
0, "BFIN_UART_MODEM_STATUS", uart)) {
|
||||
@ -766,13 +766,13 @@ static void bfin_serial_shutdown(struct uart_port *port)
|
||||
free_irq(uart->tx_irq, uart);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
|
||||
#ifdef SERIAL_BFIN_CTSRTS
|
||||
if (uart->cts_pin >= 0)
|
||||
free_irq(gpio_to_irq(uart->cts_pin), uart);
|
||||
if (uart->rts_pin >= 0)
|
||||
gpio_free(uart->rts_pin);
|
||||
#endif
|
||||
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
|
||||
#ifdef SERIAL_BFIN_HARD_CTSRTS
|
||||
if (uart->cts_pin >= 0)
|
||||
free_irq(uart->status_irq, uart);
|
||||
#endif
|
||||
@ -788,7 +788,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
unsigned int ier, lcr = 0;
|
||||
unsigned long timeout;
|
||||
|
||||
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
|
||||
#ifdef SERIAL_BFIN_CTSRTS
|
||||
if (old == NULL && uart->cts_pin != -1)
|
||||
termios->c_cflag |= CRTSCTS;
|
||||
else if (uart->cts_pin == -1)
|
||||
@ -1110,8 +1110,8 @@ bfin_serial_console_setup(struct console *co, char *options)
|
||||
int baud = 57600;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
|
||||
defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
|
||||
# if defined(SERIAL_BFIN_CTSRTS) || \
|
||||
defined(SERIAL_BFIN_HARD_CTSRTS)
|
||||
int flow = 'r';
|
||||
# else
|
||||
int flow = 'n';
|
||||
@ -1322,8 +1322,8 @@ static int bfin_serial_probe(struct platform_device *pdev)
|
||||
init_timer(&(uart->rx_dma_timer));
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \
|
||||
defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS)
|
||||
#if defined(SERIAL_BFIN_CTSRTS) || \
|
||||
defined(SERIAL_BFIN_HARD_CTSRTS)
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (res == NULL)
|
||||
uart->cts_pin = -1;
|
||||
|
@ -56,10 +56,6 @@ static char *serial_version = "$Revision: 1.25 $";
|
||||
#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
|
||||
#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All of the compatibilty code so we can compile serial.c against
|
||||
* older kernels is hidden in serial_compat.h
|
||||
@ -455,30 +451,6 @@ static struct e100_serial rs_table[] = {
|
||||
static struct fast_timer fast_timers[NR_PORTS];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY
|
||||
#define PROCSTAT(x) x
|
||||
struct ser_statistics_type {
|
||||
int overrun_cnt;
|
||||
int early_errors_cnt;
|
||||
int ser_ints_ok_cnt;
|
||||
int errors_cnt;
|
||||
unsigned long int processing_flip;
|
||||
unsigned long processing_flip_still_room;
|
||||
unsigned long int timeout_flush_cnt;
|
||||
int rx_dma_ints;
|
||||
int tx_dma_ints;
|
||||
int rx_tot;
|
||||
int tx_tot;
|
||||
};
|
||||
|
||||
static struct ser_statistics_type ser_stat[NR_PORTS];
|
||||
|
||||
#else
|
||||
|
||||
#define PROCSTAT(x)
|
||||
|
||||
#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */
|
||||
|
||||
/* RS-485 */
|
||||
#if defined(CONFIG_ETRAX_RS485)
|
||||
#ifdef CONFIG_ETRAX_FAST_TIMER
|
||||
@ -487,9 +459,6 @@ static struct fast_timer fast_timers_rs485[NR_PORTS];
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PA)
|
||||
static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
|
||||
#endif
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
|
||||
static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Info and macros needed for each ports extra control/status signals. */
|
||||
@ -739,10 +708,10 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
|
||||
defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \
|
||||
defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \
|
||||
defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED)
|
||||
#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
|
||||
#define ETRAX_SERX_DTR_RI_DSR_CD_MIXED
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED
|
||||
#ifdef ETRAX_SERX_DTR_RI_DSR_CD_MIXED
|
||||
/* The pins can be mixed on PA and PB */
|
||||
#define CONTROL_PINS_PORT_NOT_USED(line) \
|
||||
&dummy_ser[line], &dummy_ser[line], \
|
||||
@ -835,7 +804,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
|
||||
#else /* ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
|
||||
|
||||
/* All pins are on either PA or PB for each serial port */
|
||||
#define CONTROL_PINS_PORT_NOT_USED(line) \
|
||||
@ -917,7 +886,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
|
||||
#endif /* !ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
|
||||
|
||||
#define E100_RTS_MASK 0x20
|
||||
#define E100_CTS_MASK 0x40
|
||||
@ -1367,16 +1336,6 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r)
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PA)
|
||||
*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
|
||||
#endif
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
|
||||
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
|
||||
rs485_port_g_bit, 1);
|
||||
#endif
|
||||
#if defined(CONFIG_ETRAX_RS485_LTC1387)
|
||||
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
|
||||
CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
|
||||
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
|
||||
CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
|
||||
#endif
|
||||
|
||||
info->rs485 = *r;
|
||||
|
||||
@ -1676,7 +1635,8 @@ alloc_recv_buffer(unsigned int size)
|
||||
{
|
||||
struct etrax_recv_buffer *buffer;
|
||||
|
||||
if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC)))
|
||||
buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
buffer->next = NULL;
|
||||
@ -1712,7 +1672,8 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl
|
||||
{
|
||||
struct etrax_recv_buffer *buffer;
|
||||
if (info->uses_dma_in) {
|
||||
if (!(buffer = alloc_recv_buffer(4)))
|
||||
buffer = alloc_recv_buffer(4);
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
buffer->length = 1;
|
||||
@ -1750,7 +1711,8 @@ static unsigned int handle_descr_data(struct e100_serial *info,
|
||||
|
||||
append_recv_buffer(info, buffer);
|
||||
|
||||
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
|
||||
buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
|
||||
if (!buffer)
|
||||
panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
|
||||
|
||||
descr->buf = virt_to_phys(buffer->buffer);
|
||||
@ -1841,7 +1803,6 @@ static void receive_chars_dma(struct e100_serial *info)
|
||||
*/
|
||||
unsigned char data = info->ioport[REG_DATA];
|
||||
|
||||
PROCSTAT(ser_stat[info->line].errors_cnt++);
|
||||
DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n",
|
||||
((rstat & SER_ERROR_MASK) << 8) | data);
|
||||
|
||||
@ -1867,7 +1828,8 @@ static int start_recv_dma(struct e100_serial *info)
|
||||
|
||||
/* Set up the receiving descriptors */
|
||||
for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
|
||||
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
|
||||
buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE);
|
||||
if (!buffer)
|
||||
panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
|
||||
|
||||
descr[i].ctrl = d_int;
|
||||
@ -1943,7 +1905,6 @@ tr_interrupt(int irq, void *dev_id)
|
||||
/* Read jiffies_usec first,
|
||||
* we want this time to be as late as possible
|
||||
*/
|
||||
PROCSTAT(ser_stat[info->line].tx_dma_ints++);
|
||||
info->last_tx_active_usec = GET_JIFFIES_USEC();
|
||||
info->last_tx_active = jiffies;
|
||||
transmit_chars_dma(info);
|
||||
@ -2022,7 +1983,6 @@ static int force_eop_if_needed(struct e100_serial *info)
|
||||
*/
|
||||
if (!info->forced_eop) {
|
||||
info->forced_eop = 1;
|
||||
PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
|
||||
TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
|
||||
FORCE_EOP(info);
|
||||
}
|
||||
@ -2374,7 +2334,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
DEBUG_LOG(info->line, "#iERR s d %04X\n",
|
||||
((rstat & SER_ERROR_MASK) << 8) | data);
|
||||
}
|
||||
PROCSTAT(ser_stat[info->line].early_errors_cnt++);
|
||||
} else { /* It was a valid byte, now let the DMA do the rest */
|
||||
unsigned long curr_time_u = GET_JIFFIES_USEC();
|
||||
unsigned long curr_time = jiffies;
|
||||
@ -2407,7 +2366,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
|
||||
info->break_detected_cnt = 0;
|
||||
|
||||
PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
|
||||
}
|
||||
/* Restarting the DMA never hurts */
|
||||
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
|
||||
@ -2867,19 +2825,6 @@ change_speed(struct e100_serial *info)
|
||||
*R_SERIAL_PRESCALE = divisor;
|
||||
info->baud = SERIAL_PRESCALE_BASE/divisor;
|
||||
}
|
||||
#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
|
||||
else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
|
||||
info->custom_divisor == 1) ||
|
||||
(info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
|
||||
info->custom_divisor == 8)) {
|
||||
/* ext_clk selected */
|
||||
alt_source =
|
||||
IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
|
||||
IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
|
||||
DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
|
||||
info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
/* Bad baudbase, we don't support using timer0
|
||||
@ -3216,9 +3161,7 @@ rs_throttle(struct tty_struct * tty)
|
||||
{
|
||||
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
char buf[64];
|
||||
|
||||
printk("throttle %s: %lu....\n", tty_name(tty, buf),
|
||||
printk("throttle %s: %lu....\n", tty_name(tty),
|
||||
(unsigned long)tty->ldisc.chars_in_buffer(tty));
|
||||
#endif
|
||||
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
|
||||
@ -3238,9 +3181,7 @@ rs_unthrottle(struct tty_struct * tty)
|
||||
{
|
||||
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
|
||||
#ifdef SERIAL_DEBUG_THROTTLE
|
||||
char buf[64];
|
||||
|
||||
printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
|
||||
printk("unthrottle %s: %lu....\n", tty_name(tty),
|
||||
(unsigned long)tty->ldisc.chars_in_buffer(tty));
|
||||
#endif
|
||||
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
|
||||
@ -3724,16 +3665,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
info->rs485.flags &= ~(SER_RS485_ENABLED);
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PA)
|
||||
*R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
|
||||
#endif
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
|
||||
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
|
||||
rs485_port_g_bit, 0);
|
||||
#endif
|
||||
#if defined(CONFIG_ETRAX_RS485_LTC1387)
|
||||
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
|
||||
CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
|
||||
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
|
||||
CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@ -4263,15 +4194,6 @@ static int __init rs_init(void)
|
||||
return -EBUSY;
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
|
||||
if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit,
|
||||
rs485_port_g_bit)) {
|
||||
printk(KERN_ERR "ETRAX100LX serial: Could not allocate "
|
||||
"RS485 pin\n");
|
||||
put_tty_driver(driver);
|
||||
return -EBUSY;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Initialize the tty_driver structure */
|
||||
|
@ -72,6 +72,7 @@ static int __init parse_options(struct earlycon_device *device, char *options)
|
||||
|
||||
switch (port->iotype) {
|
||||
case UPIO_MEM32:
|
||||
case UPIO_MEM32BE:
|
||||
port->regshift = 2; /* fall-through */
|
||||
case UPIO_MEM:
|
||||
port->mapbase = addr;
|
||||
@ -90,9 +91,11 @@ static int __init parse_options(struct earlycon_device *device, char *options)
|
||||
strlcpy(device->options, options, length);
|
||||
}
|
||||
|
||||
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32)
|
||||
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 ||
|
||||
port->iotype == UPIO_MEM32BE)
|
||||
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
|
||||
(port->iotype == UPIO_MEM32) ? "32" : "",
|
||||
(port->iotype == UPIO_MEM) ? "" :
|
||||
(port->iotype == UPIO_MEM32) ? "32" : "32be",
|
||||
(unsigned long long)port->mapbase,
|
||||
device->options);
|
||||
else
|
||||
@ -133,7 +136,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
|
||||
*
|
||||
* Registers the earlycon console matching the earlycon specified
|
||||
* in the param string @buf. Acceptable param strings are of the form
|
||||
* <name>,io|mmio|mmio32,<addr>,<options>
|
||||
* <name>,io|mmio|mmio32|mmio32be,<addr>,<options>
|
||||
* <name>,0x<addr>,<options>
|
||||
* <name>,<options>
|
||||
* <name>
|
||||
|
@ -1504,7 +1504,8 @@ static int icom_probe(struct pci_dev *dev,
|
||||
return retval;
|
||||
}
|
||||
|
||||
if ( (retval = pci_request_regions(dev, "icom"))) {
|
||||
retval = pci_request_regions(dev, "icom");
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "pci_request_regions FAILED\n");
|
||||
pci_disable_device(dev);
|
||||
return retval;
|
||||
@ -1512,7 +1513,8 @@ static int icom_probe(struct pci_dev *dev,
|
||||
|
||||
pci_set_master(dev);
|
||||
|
||||
if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
|
||||
retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "PCI Config read FAILED\n");
|
||||
return retval;
|
||||
}
|
||||
@ -1556,9 +1558,8 @@ static int icom_probe(struct pci_dev *dev,
|
||||
}
|
||||
|
||||
/* save off irq and request irq line */
|
||||
if ( (retval = request_irq(dev->irq, icom_interrupt,
|
||||
IRQF_SHARED, ICOM_DRIVER_NAME,
|
||||
(void *) icom_adapter))) {
|
||||
retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
|
||||
if (retval) {
|
||||
goto probe_exit2;
|
||||
}
|
||||
|
||||
|
@ -1175,7 +1175,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
|
||||
ifx_spi_reset_interrupt,
|
||||
IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
|
||||
(void *)ifx_dev);
|
||||
ifx_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to get irq %x\n",
|
||||
gpio_to_irq(ifx_dev->gpio.reset_out));
|
||||
@ -1185,9 +1185,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
ret = ifx_spi_reset(ifx_dev);
|
||||
|
||||
ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
|
||||
ifx_spi_srdy_interrupt,
|
||||
IRQF_TRIGGER_RISING, DRVNAME,
|
||||
(void *)ifx_dev);
|
||||
ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME,
|
||||
ifx_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to get irq %x",
|
||||
gpio_to_irq(ifx_dev->gpio.srdy));
|
||||
@ -1212,7 +1211,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
return 0;
|
||||
|
||||
error_ret7:
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
|
||||
error_ret6:
|
||||
gpio_free(ifx_dev->gpio.srdy);
|
||||
error_ret5:
|
||||
@ -1243,8 +1242,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi)
|
||||
/* stop activity */
|
||||
tasklet_kill(&ifx_dev->io_work_tasklet);
|
||||
/* free irq */
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev);
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev);
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev);
|
||||
|
||||
gpio_free(ifx_dev->gpio.srdy);
|
||||
gpio_free(ifx_dev->gpio.mrdy);
|
||||
@ -1381,7 +1380,7 @@ static void __exit ifx_spi_exit(void)
|
||||
/* unregister */
|
||||
tty_unregister_driver(tty_drv);
|
||||
put_tty_driver(tty_drv);
|
||||
spi_unregister_driver((void *)&ifx_spi_driver);
|
||||
spi_unregister_driver(&ifx_spi_driver);
|
||||
unregister_reboot_notifier(&ifx_modem_reboot_notifier_block);
|
||||
}
|
||||
|
||||
@ -1420,7 +1419,7 @@ static int __init ifx_spi_init(void)
|
||||
goto err_free_tty;
|
||||
}
|
||||
|
||||
result = spi_register_driver((void *)&ifx_spi_driver);
|
||||
result = spi_register_driver(&ifx_spi_driver);
|
||||
if (result) {
|
||||
pr_err("%s: spi_register_driver failed(%d)",
|
||||
DRVNAME, result);
|
||||
@ -1436,7 +1435,7 @@ static int __init ifx_spi_init(void)
|
||||
|
||||
return 0;
|
||||
err_unreg_spi:
|
||||
spi_unregister_driver((void *)&ifx_spi_driver);
|
||||
spi_unregister_driver(&ifx_spi_driver);
|
||||
err_unreg_tty:
|
||||
tty_unregister_driver(tty_drv);
|
||||
err_free_tty:
|
||||
|
@ -239,7 +239,7 @@ static struct imx_uart_data imx_uart_devdata[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device_id imx_uart_devtype[] = {
|
||||
static const struct platform_device_id imx_uart_devtype[] = {
|
||||
{
|
||||
.name = "imx1-uart",
|
||||
.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
|
||||
@ -853,7 +853,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
|
||||
#define TXTL 2 /* reset default */
|
||||
#define RXTL 1 /* reset default */
|
||||
|
||||
static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
|
||||
static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
@ -861,7 +861,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
|
||||
val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
|
||||
val |= TXTL << UFCR_TXTL_SHF | RXTL;
|
||||
writel(val, sport->port.membase + UFCR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define RX_BUF_SIZE (PAGE_SIZE)
|
||||
@ -1122,6 +1121,12 @@ static int imx_startup(struct uart_port *port)
|
||||
|
||||
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
|
||||
|
||||
/* Can we enable the DMA support? */
|
||||
if (is_imx6q_uart(sport) && !uart_console(port) &&
|
||||
!sport->dma_is_inited)
|
||||
imx_uart_dma_init(sport);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
/* Reset fifo's and state machines */
|
||||
i = 100;
|
||||
|
||||
@ -1132,13 +1137,6 @@ static int imx_startup(struct uart_port *port)
|
||||
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
|
||||
udelay(1);
|
||||
|
||||
/* Can we enable the DMA support? */
|
||||
if (is_imx6q_uart(sport) && !uart_console(port) &&
|
||||
!sport->dma_is_inited)
|
||||
imx_uart_dma_init(sport);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
/*
|
||||
* Finally, clear and enable interrupts
|
||||
*/
|
||||
|
@ -2137,7 +2137,8 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
|
||||
|
||||
/* register port with the serial core */
|
||||
|
||||
if ((ret = ioc3_serial_core_attach(is, idd)))
|
||||
ret = ioc3_serial_core_attach(is, idd);
|
||||
if (ret)
|
||||
goto out4;
|
||||
|
||||
Num_of_ioc3_cards++;
|
||||
|
@ -1011,7 +1011,8 @@ static irqreturn_t ioc4_intr(int irq, void *arg)
|
||||
*/
|
||||
for (xx = 0; xx < num_intrs; xx++) {
|
||||
intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx];
|
||||
if ((this_mir = this_ir & intr_info->sd_bits)) {
|
||||
this_mir = this_ir & intr_info->sd_bits;
|
||||
if (this_mir) {
|
||||
/* Disable owned interrupts, call handler */
|
||||
handled++;
|
||||
write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC,
|
||||
@ -2865,10 +2866,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
|
||||
|
||||
/* register port with the serial core - 1 rs232, 1 rs422 */
|
||||
|
||||
if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232)))
|
||||
ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232);
|
||||
if (ret)
|
||||
goto out4;
|
||||
|
||||
if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422)))
|
||||
ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422);
|
||||
if (ret)
|
||||
goto out5;
|
||||
|
||||
Num_of_ioc4_cards++;
|
||||
|
@ -173,18 +173,18 @@ static int kgdb_nmi_poll_one_knock(void)
|
||||
bool kgdb_nmi_poll_knock(void)
|
||||
{
|
||||
if (kgdb_nmi_knock < 0)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
while (1) {
|
||||
int ret;
|
||||
|
||||
ret = kgdb_nmi_poll_one_knock();
|
||||
if (ret == NO_POLL_CHAR)
|
||||
return 0;
|
||||
return false;
|
||||
else if (ret == 1)
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -597,7 +597,7 @@ console_initcall(mcf_console_init);
|
||||
#define MCF_CONSOLE NULL
|
||||
|
||||
/****************************************************************************/
|
||||
#endif /* CONFIG_MCF_CONSOLE */
|
||||
#endif /* CONFIG_SERIAL_MCF_CONSOLE */
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -370,7 +370,7 @@ static int meson_uart_verify_port(struct uart_port *port,
|
||||
static void meson_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
iounmap(port->membase);
|
||||
devm_iounmap(port->dev, port->membase);
|
||||
port->membase = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -405,7 +405,7 @@ static struct psc_ops mpc5200b_psc_ops = {
|
||||
.get_mr1 = mpc52xx_psc_get_mr1,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_MPC52xx */
|
||||
#endif /* CONFIG_PPC_MPC52xx */
|
||||
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
|
||||
|
@ -913,7 +913,8 @@ static int mpsc_make_ready(struct mpsc_port_info *pi)
|
||||
|
||||
if (!pi->ready) {
|
||||
mpsc_init_hw(pi);
|
||||
if ((rc = mpsc_alloc_ring_mem(pi)))
|
||||
rc = mpsc_alloc_ring_mem(pi);
|
||||
if (rc)
|
||||
return rc;
|
||||
mpsc_init_rings(pi);
|
||||
pi->ready = 1;
|
||||
@ -1895,7 +1896,8 @@ static int mpsc_shared_drv_probe(struct platform_device *dev)
|
||||
int rc = -ENODEV;
|
||||
|
||||
if (dev->id == 0) {
|
||||
if (!(rc = mpsc_shared_map_regs(dev))) {
|
||||
rc = mpsc_shared_map_regs(dev);
|
||||
if (!rc) {
|
||||
pdata = (struct mpsc_shared_pdata *)
|
||||
dev_get_platdata(&dev->dev);
|
||||
|
||||
@ -2081,14 +2083,16 @@ static int mpsc_drv_probe(struct platform_device *dev)
|
||||
if (dev->id < MPSC_NUM_CTLRS) {
|
||||
pi = &mpsc_ports[dev->id];
|
||||
|
||||
if (!(rc = mpsc_drv_map_regs(pi, dev))) {
|
||||
rc = mpsc_drv_map_regs(pi, dev);
|
||||
if (!rc) {
|
||||
mpsc_drv_get_platform_data(pi, dev, dev->id);
|
||||
pi->port.dev = &dev->dev;
|
||||
|
||||
if (!(rc = mpsc_make_ready(pi))) {
|
||||
rc = mpsc_make_ready(pi);
|
||||
if (!rc) {
|
||||
spin_lock_init(&pi->tx_lock);
|
||||
if (!(rc = uart_add_one_port(&mpsc_reg,
|
||||
&pi->port))) {
|
||||
rc = uart_add_one_port(&mpsc_reg, &pi->port);
|
||||
if (!rc) {
|
||||
rc = 0;
|
||||
} else {
|
||||
mpsc_release_port((struct uart_port *)
|
||||
@ -2136,9 +2140,12 @@ static int __init mpsc_drv_init(void)
|
||||
memset(mpsc_ports, 0, sizeof(mpsc_ports));
|
||||
memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
|
||||
|
||||
if (!(rc = uart_register_driver(&mpsc_reg))) {
|
||||
if (!(rc = platform_driver_register(&mpsc_shared_driver))) {
|
||||
if ((rc = platform_driver_register(&mpsc_driver))) {
|
||||
rc = uart_register_driver(&mpsc_reg);
|
||||
if (!rc) {
|
||||
rc = platform_driver_register(&mpsc_shared_driver);
|
||||
if (!rc) {
|
||||
rc = platform_driver_register(&mpsc_driver);
|
||||
if (rc) {
|
||||
platform_driver_unregister(&mpsc_shared_driver);
|
||||
uart_unregister_driver(&mpsc_reg);
|
||||
}
|
||||
|
@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
* Author: Brian Swetland <swetland@google.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#include <mach/msm_smd.h>
|
||||
|
||||
#define MAX_SMD_TTYS 32
|
||||
|
||||
struct smd_tty_info {
|
||||
struct tty_port port;
|
||||
smd_channel_t *ch;
|
||||
};
|
||||
|
||||
struct smd_tty_channel_desc {
|
||||
int id;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static struct smd_tty_info smd_tty[MAX_SMD_TTYS];
|
||||
|
||||
static const struct smd_tty_channel_desc smd_default_tty_channels[] = {
|
||||
{ .id = 0, .name = "SMD_DS" },
|
||||
{ .id = 27, .name = "SMD_GPSNMEA" },
|
||||
};
|
||||
|
||||
static const struct smd_tty_channel_desc *smd_tty_channels =
|
||||
smd_default_tty_channels;
|
||||
static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels);
|
||||
|
||||
static void smd_tty_notify(void *priv, unsigned event)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
int avail;
|
||||
struct smd_tty_info *info = priv;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (event != SMD_EVENT_DATA)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags))
|
||||
break;
|
||||
avail = smd_read_avail(info->ch);
|
||||
if (avail == 0)
|
||||
break;
|
||||
|
||||
avail = tty_prepare_flip_string(&info->port, &ptr, avail);
|
||||
|
||||
if (smd_read(info->ch, ptr, avail) != avail) {
|
||||
/* shouldn't be possible since we're in interrupt
|
||||
** context here and nobody else could 'steal' our
|
||||
** characters.
|
||||
*/
|
||||
pr_err("OOPS - smd_tty_buffer mismatch?!");
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(&info->port);
|
||||
}
|
||||
|
||||
/* XXX only when writable and necessary */
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||
{
|
||||
struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
|
||||
port);
|
||||
int i, res = 0;
|
||||
const char *name = NULL;
|
||||
|
||||
for (i = 0; i < smd_tty_channels_len; i++) {
|
||||
if (smd_tty_channels[i].id == tty->index) {
|
||||
name = smd_tty_channels[i].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!name)
|
||||
return -ENODEV;
|
||||
|
||||
if (info->ch)
|
||||
smd_kick(info->ch);
|
||||
else
|
||||
res = smd_open(name, &info->ch, info, smd_tty_notify);
|
||||
|
||||
if (!res)
|
||||
tty->driver_data = info;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void smd_tty_port_shutdown(struct tty_port *tport)
|
||||
{
|
||||
struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
|
||||
port);
|
||||
|
||||
if (info->ch) {
|
||||
smd_close(info->ch);
|
||||
info->ch = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int smd_tty_open(struct tty_struct *tty, struct file *f)
|
||||
{
|
||||
struct smd_tty_info *info = smd_tty + tty->index;
|
||||
|
||||
return tty_port_open(&info->port, tty, f);
|
||||
}
|
||||
|
||||
static void smd_tty_close(struct tty_struct *tty, struct file *f)
|
||||
{
|
||||
struct smd_tty_info *info = tty->driver_data;
|
||||
|
||||
tty_port_close(&info->port, tty, f);
|
||||
}
|
||||
|
||||
static int smd_tty_write(struct tty_struct *tty,
|
||||
const unsigned char *buf, int len)
|
||||
{
|
||||
struct smd_tty_info *info = tty->driver_data;
|
||||
int avail;
|
||||
|
||||
/* if we're writing to a packet channel we will
|
||||
** never be able to write more data than there
|
||||
** is currently space for
|
||||
*/
|
||||
avail = smd_write_avail(info->ch);
|
||||
if (len > avail)
|
||||
len = avail;
|
||||
|
||||
return smd_write(info->ch, buf, len);
|
||||
}
|
||||
|
||||
static int smd_tty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct smd_tty_info *info = tty->driver_data;
|
||||
return smd_write_avail(info->ch);
|
||||
}
|
||||
|
||||
static int smd_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct smd_tty_info *info = tty->driver_data;
|
||||
return smd_read_avail(info->ch);
|
||||
}
|
||||
|
||||
static void smd_tty_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct smd_tty_info *info = tty->driver_data;
|
||||
smd_kick(info->ch);
|
||||
}
|
||||
|
||||
static const struct tty_port_operations smd_tty_port_ops = {
|
||||
.shutdown = smd_tty_port_shutdown,
|
||||
.activate = smd_tty_port_activate,
|
||||
};
|
||||
|
||||
static const struct tty_operations smd_tty_ops = {
|
||||
.open = smd_tty_open,
|
||||
.close = smd_tty_close,
|
||||
.write = smd_tty_write,
|
||||
.write_room = smd_tty_write_room,
|
||||
.chars_in_buffer = smd_tty_chars_in_buffer,
|
||||
.unthrottle = smd_tty_unthrottle,
|
||||
};
|
||||
|
||||
static struct tty_driver *smd_tty_driver;
|
||||
|
||||
static int __init smd_tty_init(void)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS);
|
||||
if (smd_tty_driver == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
smd_tty_driver->driver_name = "smd_tty_driver";
|
||||
smd_tty_driver->name = "smd";
|
||||
smd_tty_driver->major = 0;
|
||||
smd_tty_driver->minor_start = 0;
|
||||
smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
smd_tty_driver->subtype = SERIAL_TYPE_NORMAL;
|
||||
smd_tty_driver->init_termios = tty_std_termios;
|
||||
smd_tty_driver->init_termios.c_iflag = 0;
|
||||
smd_tty_driver->init_termios.c_oflag = 0;
|
||||
smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
|
||||
smd_tty_driver->init_termios.c_lflag = 0;
|
||||
smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS |
|
||||
TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
tty_set_operations(smd_tty_driver, &smd_tty_ops);
|
||||
|
||||
ret = tty_register_driver(smd_tty_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < smd_tty_channels_len; i++) {
|
||||
struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port;
|
||||
tty_port_init(port);
|
||||
port->ops = &smd_tty_port_ops;
|
||||
tty_port_register_device(port, smd_tty_driver,
|
||||
smd_tty_channels[i].id, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(smd_tty_init);
|
@ -169,7 +169,7 @@ struct mxs_auart_port {
|
||||
bool ms_irq_enabled;
|
||||
};
|
||||
|
||||
static struct platform_device_id mxs_auart_devtype[] = {
|
||||
static const struct platform_device_id mxs_auart_devtype[] = {
|
||||
{ .name = "mxs-auart-imx23", .driver_data = IMX23_AUART },
|
||||
{ .name = "mxs-auart-imx28", .driver_data = IMX28_AUART },
|
||||
{ /* sentinel */ }
|
||||
|
@ -67,14 +67,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||
if (of_property_read_u32(np, "clock-frequency", &clk)) {
|
||||
|
||||
/* Get clk rate through clk driver if present */
|
||||
info->clk = clk_get(&ofdev->dev, NULL);
|
||||
info->clk = devm_clk_get(&ofdev->dev, NULL);
|
||||
if (IS_ERR(info->clk)) {
|
||||
dev_warn(&ofdev->dev,
|
||||
"clk or clock-frequency not defined\n");
|
||||
return PTR_ERR(info->clk);
|
||||
}
|
||||
|
||||
clk_prepare_enable(info->clk);
|
||||
ret = clk_prepare_enable(info->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
clk = clk_get_rate(info->clk);
|
||||
}
|
||||
/* If current-speed was set, then try not to change it. */
|
||||
@ -188,7 +191,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct uart_8250_port port8250;
|
||||
memset(&port8250, 0, sizeof(port8250));
|
||||
port.type = port_type;
|
||||
port8250.port = port;
|
||||
|
||||
if (port.fifosize)
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -160,7 +161,6 @@ struct uart_omap_port {
|
||||
unsigned long port_activity;
|
||||
int context_loss_cnt;
|
||||
u32 errata;
|
||||
u8 wakeups_enabled;
|
||||
u32 features;
|
||||
|
||||
int rts_gpio;
|
||||
@ -209,28 +209,11 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
|
||||
return pdata->get_context_loss_count(up->dev);
|
||||
}
|
||||
|
||||
static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up,
|
||||
bool enable)
|
||||
{
|
||||
if (!up->wakeirq)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
enable_irq(up->wakeirq);
|
||||
else
|
||||
disable_irq_nosync(up->wakeirq);
|
||||
}
|
||||
|
||||
/* REVISIT: Remove this when omap3 boots in device tree only mode */
|
||||
static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
|
||||
{
|
||||
struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
|
||||
|
||||
if (enable == up->wakeups_enabled)
|
||||
return;
|
||||
|
||||
serial_omap_enable_wakeirq(up, enable);
|
||||
up->wakeups_enabled = enable;
|
||||
|
||||
if (!pdata || !pdata->enable_wakeup)
|
||||
return;
|
||||
|
||||
@ -750,13 +733,11 @@ static int serial_omap_startup(struct uart_port *port)
|
||||
|
||||
/* Optional wake-up IRQ */
|
||||
if (up->wakeirq) {
|
||||
retval = request_irq(up->wakeirq, serial_omap_irq,
|
||||
up->port.irqflags, up->name, up);
|
||||
retval = dev_pm_set_dedicated_wake_irq(up->dev, up->wakeirq);
|
||||
if (retval) {
|
||||
free_irq(up->port.irq, up);
|
||||
return retval;
|
||||
}
|
||||
disable_irq(up->wakeirq);
|
||||
}
|
||||
|
||||
dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
|
||||
@ -845,8 +826,7 @@ static void serial_omap_shutdown(struct uart_port *port)
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
pm_runtime_put_autosuspend(up->dev);
|
||||
free_irq(up->port.irq, up);
|
||||
if (up->wakeirq)
|
||||
free_irq(up->wakeirq, up);
|
||||
dev_pm_clear_wake_irq(up->dev);
|
||||
}
|
||||
|
||||
static void serial_omap_uart_qos_work(struct work_struct *work)
|
||||
@ -1139,13 +1119,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state,
|
||||
serial_out(up, UART_EFR, efr);
|
||||
serial_out(up, UART_LCR, 0);
|
||||
|
||||
if (!device_may_wakeup(up->dev)) {
|
||||
if (!state)
|
||||
pm_runtime_forbid(up->dev);
|
||||
else
|
||||
pm_runtime_allow(up->dev);
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
pm_runtime_put_autosuspend(up->dev);
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
|
||||
s3c24xx_serial_start_tx_dma(ourport, count);
|
||||
}
|
||||
|
||||
void s3c24xx_serial_start_tx(struct uart_port *port)
|
||||
static void s3c24xx_serial_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
@ -2337,7 +2337,7 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
|
||||
#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
|
||||
#endif
|
||||
|
||||
static struct platform_device_id s3c24xx_serial_driver_ids[] = {
|
||||
static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
|
||||
{
|
||||
.name = "s3c2410-uart",
|
||||
.driver_data = S3C2410_SERIAL_DRV_DATA,
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/serial.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define SC16IS7XX_NAME "sc16is7xx"
|
||||
@ -300,25 +301,38 @@ struct sc16is7xx_devtype {
|
||||
int nr_uart;
|
||||
};
|
||||
|
||||
#define SC16IS7XX_RECONF_MD (1 << 0)
|
||||
#define SC16IS7XX_RECONF_IER (1 << 1)
|
||||
#define SC16IS7XX_RECONF_RS485 (1 << 2)
|
||||
|
||||
struct sc16is7xx_one_config {
|
||||
unsigned int flags;
|
||||
u8 ier_clear;
|
||||
};
|
||||
|
||||
struct sc16is7xx_one {
|
||||
struct uart_port port;
|
||||
struct work_struct tx_work;
|
||||
struct work_struct md_work;
|
||||
struct kthread_work tx_work;
|
||||
struct kthread_work reg_work;
|
||||
struct sc16is7xx_one_config config;
|
||||
};
|
||||
|
||||
struct sc16is7xx_port {
|
||||
struct uart_driver uart;
|
||||
struct sc16is7xx_devtype *devtype;
|
||||
struct regmap *regmap;
|
||||
struct mutex mutex;
|
||||
struct clk *clk;
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct gpio_chip gpio;
|
||||
#endif
|
||||
unsigned char buf[SC16IS7XX_FIFO_SIZE];
|
||||
struct kthread_worker kworker;
|
||||
struct task_struct *kworker_task;
|
||||
struct kthread_work irq_work;
|
||||
struct sc16is7xx_one p[0];
|
||||
};
|
||||
|
||||
#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e)))
|
||||
#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
|
||||
|
||||
static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
|
||||
@ -615,9 +629,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
||||
!!(msr & SC16IS7XX_MSR_CTS_BIT));
|
||||
break;
|
||||
case SC16IS7XX_IIR_THRI_SRC:
|
||||
mutex_lock(&s->mutex);
|
||||
sc16is7xx_handle_tx(port);
|
||||
mutex_unlock(&s->mutex);
|
||||
break;
|
||||
default:
|
||||
dev_err_ratelimited(port->dev,
|
||||
@ -628,81 +640,115 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static irqreturn_t sc16is7xx_ist(int irq, void *dev_id)
|
||||
static void sc16is7xx_ist(struct kthread_work *ws)
|
||||
{
|
||||
struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
|
||||
struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->uart.nr; ++i)
|
||||
sc16is7xx_port_irq(s, i);
|
||||
}
|
||||
|
||||
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
|
||||
|
||||
queue_kthread_work(&s->kworker, &s->irq_work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void sc16is7xx_wq_proc(struct work_struct *ws)
|
||||
static void sc16is7xx_tx_proc(struct kthread_work *ws)
|
||||
{
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work);
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
|
||||
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
|
||||
|
||||
mutex_lock(&s->mutex);
|
||||
sc16is7xx_handle_tx(&one->port);
|
||||
mutex_unlock(&s->mutex);
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
(port->rs485.delay_rts_before_send > 0))
|
||||
msleep(port->rs485.delay_rts_before_send);
|
||||
|
||||
sc16is7xx_handle_tx(port);
|
||||
}
|
||||
|
||||
static void sc16is7xx_stop_tx(struct uart_port* port)
|
||||
static void sc16is7xx_reconf_rs485(struct uart_port *port)
|
||||
{
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
struct circ_buf *xmit = &one->port.state->xmit;
|
||||
const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT |
|
||||
SC16IS7XX_EFCR_RTS_INVERT_BIT;
|
||||
u32 efcr = 0;
|
||||
struct serial_rs485 *rs485 = &port->rs485;
|
||||
unsigned long irqflags;
|
||||
|
||||
/* handle rs485 */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* do nothing if current tx not yet completed */
|
||||
int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG);
|
||||
if (!(lsr & SC16IS7XX_LSR_TEMT_BIT))
|
||||
return;
|
||||
spin_lock_irqsave(&port->lock, irqflags);
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT;
|
||||
|
||||
if (uart_circ_empty(xmit) &&
|
||||
(port->rs485.delay_rts_after_send > 0))
|
||||
mdelay(port->rs485.delay_rts_after_send);
|
||||
if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
|
||||
efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT;
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, irqflags);
|
||||
|
||||
sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
|
||||
SC16IS7XX_IER_THRI_BIT,
|
||||
0);
|
||||
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr);
|
||||
}
|
||||
|
||||
static void sc16is7xx_stop_rx(struct uart_port* port)
|
||||
static void sc16is7xx_reg_proc(struct kthread_work *ws)
|
||||
{
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work);
|
||||
struct sc16is7xx_one_config config;
|
||||
unsigned long irqflags;
|
||||
|
||||
spin_lock_irqsave(&one->port.lock, irqflags);
|
||||
config = one->config;
|
||||
memset(&one->config, 0, sizeof(one->config));
|
||||
spin_unlock_irqrestore(&one->port.lock, irqflags);
|
||||
|
||||
if (config.flags & SC16IS7XX_RECONF_MD)
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_LOOP_BIT,
|
||||
(one->port.mctrl & TIOCM_LOOP) ?
|
||||
SC16IS7XX_MCR_LOOP_BIT : 0);
|
||||
|
||||
if (config.flags & SC16IS7XX_RECONF_IER)
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG,
|
||||
config.ier_clear, 0);
|
||||
|
||||
if (config.flags & SC16IS7XX_RECONF_RS485)
|
||||
sc16is7xx_reconf_rs485(&one->port);
|
||||
}
|
||||
|
||||
static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
one->port.read_status_mask &= ~SC16IS7XX_LSR_DR_BIT;
|
||||
sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
|
||||
SC16IS7XX_LSR_DR_BIT,
|
||||
0);
|
||||
one->config.flags |= SC16IS7XX_RECONF_IER;
|
||||
one->config.ier_clear |= bit;
|
||||
queue_kthread_work(&s->kworker, &one->reg_work);
|
||||
}
|
||||
|
||||
static void sc16is7xx_stop_tx(struct uart_port *port)
|
||||
{
|
||||
sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT);
|
||||
}
|
||||
|
||||
static void sc16is7xx_stop_rx(struct uart_port *port)
|
||||
{
|
||||
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
|
||||
}
|
||||
|
||||
static void sc16is7xx_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
/* handle rs485 */
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
(port->rs485.delay_rts_before_send > 0)) {
|
||||
mdelay(port->rs485.delay_rts_before_send);
|
||||
}
|
||||
|
||||
if (!work_pending(&one->tx_work))
|
||||
schedule_work(&one->tx_work);
|
||||
queue_kthread_work(&s->kworker, &one->tx_work);
|
||||
}
|
||||
|
||||
static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
|
||||
{
|
||||
unsigned int lvl, lsr;
|
||||
unsigned int lsr;
|
||||
|
||||
lvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
|
||||
lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG);
|
||||
|
||||
return ((lsr & SC16IS7XX_LSR_THRE_BIT) && !lvl) ? TIOCSER_TEMT : 0;
|
||||
return (lsr & SC16IS7XX_LSR_TEMT_BIT) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
|
||||
@ -713,21 +759,13 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
|
||||
return TIOCM_DSR | TIOCM_CAR;
|
||||
}
|
||||
|
||||
static void sc16is7xx_md_proc(struct work_struct *ws)
|
||||
{
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work);
|
||||
|
||||
sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG,
|
||||
SC16IS7XX_MCR_LOOP_BIT,
|
||||
(one->port.mctrl & TIOCM_LOOP) ?
|
||||
SC16IS7XX_MCR_LOOP_BIT : 0);
|
||||
}
|
||||
|
||||
static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
schedule_work(&one->md_work);
|
||||
one->config.flags |= SC16IS7XX_RECONF_MD;
|
||||
queue_kthread_work(&s->kworker, &one->reg_work);
|
||||
}
|
||||
|
||||
static void sc16is7xx_break_ctl(struct uart_port *port, int break_state)
|
||||
@ -831,9 +869,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
||||
static int sc16is7xx_config_rs485(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT |
|
||||
SC16IS7XX_EFCR_RTS_INVERT_BIT;
|
||||
u32 efcr = 0;
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
bool rts_during_rx, rts_during_tx;
|
||||
@ -841,21 +878,23 @@ static int sc16is7xx_config_rs485(struct uart_port *port,
|
||||
rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND;
|
||||
rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND;
|
||||
|
||||
efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT;
|
||||
|
||||
if (!rts_during_rx && rts_during_tx)
|
||||
/* default */;
|
||||
else if (rts_during_rx && !rts_during_tx)
|
||||
efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT;
|
||||
else
|
||||
if (rts_during_rx == rts_during_tx)
|
||||
dev_err(port->dev,
|
||||
"unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n",
|
||||
rts_during_tx, rts_during_rx);
|
||||
|
||||
/*
|
||||
* RTS signal is handled by HW, it's timing can't be influenced.
|
||||
* However, it's sometimes useful to delay TX even without RTS
|
||||
* control therefore we try to handle .delay_rts_before_send.
|
||||
*/
|
||||
if (rs485->delay_rts_after_send)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
one->config.flags |= SC16IS7XX_RECONF_RS485;
|
||||
queue_kthread_work(&s->kworker, &one->reg_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -916,6 +955,8 @@ static int sc16is7xx_startup(struct uart_port *port)
|
||||
|
||||
static void sc16is7xx_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
|
||||
/* Disable all interrupts */
|
||||
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
|
||||
/* Disable TX/RX */
|
||||
@ -926,6 +967,8 @@ static void sc16is7xx_shutdown(struct uart_port *port)
|
||||
SC16IS7XX_EFCR_TXDISABLE_BIT);
|
||||
|
||||
sc16is7xx_power(port, 0);
|
||||
|
||||
flush_kthread_worker(&s->kworker);
|
||||
}
|
||||
|
||||
static const char *sc16is7xx_type(struct uart_port *port)
|
||||
@ -1043,6 +1086,7 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
struct sc16is7xx_devtype *devtype,
|
||||
struct regmap *regmap, int irq, unsigned long flags)
|
||||
{
|
||||
struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
|
||||
unsigned long freq, *pfreq = dev_get_platdata(dev);
|
||||
int i, ret;
|
||||
struct sc16is7xx_port *s;
|
||||
@ -1084,6 +1128,16 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
goto out_clk;
|
||||
}
|
||||
|
||||
init_kthread_worker(&s->kworker);
|
||||
init_kthread_work(&s->irq_work, sc16is7xx_ist);
|
||||
s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker,
|
||||
"sc16is7xx");
|
||||
if (IS_ERR(s->kworker_task)) {
|
||||
ret = PTR_ERR(s->kworker_task);
|
||||
goto out_uart;
|
||||
}
|
||||
sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (devtype->nr_gpio) {
|
||||
/* Setup GPIO cotroller */
|
||||
@ -1099,12 +1153,10 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
s->gpio.can_sleep = 1;
|
||||
ret = gpiochip_add(&s->gpio);
|
||||
if (ret)
|
||||
goto out_uart;
|
||||
goto out_thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
mutex_init(&s->mutex);
|
||||
|
||||
for (i = 0; i < devtype->nr_uart; ++i) {
|
||||
/* Initialize port data */
|
||||
s->p[i].port.line = i;
|
||||
@ -1123,10 +1175,9 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG,
|
||||
SC16IS7XX_EFCR_RXDISABLE_BIT |
|
||||
SC16IS7XX_EFCR_TXDISABLE_BIT);
|
||||
/* Initialize queue for start TX */
|
||||
INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc);
|
||||
/* Initialize queue for changing mode */
|
||||
INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc);
|
||||
/* Initialize kthread work structs */
|
||||
init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
|
||||
init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
|
||||
/* Register port */
|
||||
uart_add_one_port(&s->uart, &s->p[i].port);
|
||||
/* Go to suspend mode */
|
||||
@ -1134,22 +1185,23 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
}
|
||||
|
||||
/* Setup interrupt */
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist,
|
||||
IRQF_ONESHOT | flags, dev_name(dev), s);
|
||||
ret = devm_request_irq(dev, irq, sc16is7xx_irq,
|
||||
IRQF_ONESHOT | flags, dev_name(dev), s);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++)
|
||||
uart_remove_one_port(&s->uart, &s->p[i].port);
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (devtype->nr_gpio)
|
||||
gpiochip_remove(&s->gpio);
|
||||
|
||||
out_uart:
|
||||
out_thread:
|
||||
#endif
|
||||
kthread_stop(s->kworker_task);
|
||||
|
||||
out_uart:
|
||||
uart_unregister_driver(&s->uart);
|
||||
|
||||
out_clk:
|
||||
@ -1170,13 +1222,13 @@ static int sc16is7xx_remove(struct device *dev)
|
||||
#endif
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
cancel_work_sync(&s->p[i].tx_work);
|
||||
cancel_work_sync(&s->p[i].md_work);
|
||||
uart_remove_one_port(&s->uart, &s->p[i].port);
|
||||
sc16is7xx_power(&s->p[i].port, 0);
|
||||
}
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
flush_kthread_worker(&s->kworker);
|
||||
kthread_stop(s->kworker_task);
|
||||
|
||||
uart_unregister_driver(&s->uart);
|
||||
if (!IS_ERR(s->clk))
|
||||
clk_disable_unprepare(s->clk);
|
||||
@ -1204,6 +1256,75 @@ static struct regmap_config regcfg = {
|
||||
.precious_reg = sc16is7xx_regmap_precious,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
|
||||
static int sc16is7xx_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct sc16is7xx_devtype *devtype;
|
||||
unsigned long flags = 0;
|
||||
struct regmap *regmap;
|
||||
int ret;
|
||||
|
||||
/* Setup SPI bus */
|
||||
spi->bits_per_word = 8;
|
||||
/* only supports mode 0 on SC16IS762 */
|
||||
spi->mode = spi->mode ? : SPI_MODE_0;
|
||||
spi->max_speed_hz = spi->max_speed_hz ? : 15000000;
|
||||
ret = spi_setup(spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (spi->dev.of_node) {
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(sc16is7xx_dt_ids, &spi->dev);
|
||||
|
||||
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
||||
} else {
|
||||
const struct spi_device_id *id_entry = spi_get_device_id(spi);
|
||||
|
||||
devtype = (struct sc16is7xx_devtype *)id_entry->driver_data;
|
||||
flags = IRQF_TRIGGER_FALLING;
|
||||
}
|
||||
|
||||
regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
|
||||
(devtype->nr_uart - 1);
|
||||
regmap = devm_regmap_init_spi(spi, ®cfg);
|
||||
|
||||
return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags);
|
||||
}
|
||||
|
||||
static int sc16is7xx_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return sc16is7xx_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id sc16is7xx_spi_id_table[] = {
|
||||
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
|
||||
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
|
||||
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
|
||||
{ "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
|
||||
|
||||
static struct spi_driver sc16is7xx_spi_uart_driver = {
|
||||
.driver = {
|
||||
.name = SC16IS7XX_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(sc16is7xx_dt_ids),
|
||||
},
|
||||
.probe = sc16is7xx_spi_probe,
|
||||
.remove = sc16is7xx_spi_remove,
|
||||
.id_table = sc16is7xx_spi_id_table,
|
||||
};
|
||||
|
||||
MODULE_ALIAS("spi:sc16is7xx");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
|
||||
static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -1235,6 +1356,8 @@ static int sc16is7xx_i2c_remove(struct i2c_client *client)
|
||||
|
||||
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
|
||||
{ "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
|
||||
{ "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
|
||||
{ "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
|
||||
{ "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
|
||||
@ -1253,8 +1376,43 @@ static struct i2c_driver sc16is7xx_i2c_uart_driver = {
|
||||
.remove = sc16is7xx_i2c_remove,
|
||||
.id_table = sc16is7xx_i2c_id_table,
|
||||
};
|
||||
module_i2c_driver(sc16is7xx_i2c_uart_driver);
|
||||
|
||||
MODULE_ALIAS("i2c:sc16is7xx");
|
||||
#endif
|
||||
|
||||
static int __init sc16is7xx_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
|
||||
ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to init sc16is7xx i2c --> %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
|
||||
ret = spi_register_driver(&sc16is7xx_spi_uart_driver);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to init sc16is7xx spi --> %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(sc16is7xx_init);
|
||||
|
||||
static void __exit sc16is7xx_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
|
||||
i2c_del_driver(&sc16is7xx_i2c_uart_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
|
||||
spi_unregister_driver(&sc16is7xx_spi_uart_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(sc16is7xx_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
|
||||
|
@ -131,8 +131,8 @@ struct tegra_uart_port {
|
||||
struct dma_async_tx_descriptor *rx_dma_desc;
|
||||
dma_cookie_t tx_cookie;
|
||||
dma_cookie_t rx_cookie;
|
||||
int tx_bytes_requested;
|
||||
int rx_bytes_requested;
|
||||
unsigned int tx_bytes_requested;
|
||||
unsigned int rx_bytes_requested;
|
||||
};
|
||||
|
||||
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup);
|
||||
@ -234,6 +234,22 @@ static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl)
|
||||
tup->lcr_shadow = lcr;
|
||||
}
|
||||
|
||||
/**
|
||||
* tegra_uart_wait_cycle_time: Wait for N UART clock periods
|
||||
*
|
||||
* @tup: Tegra serial port data structure.
|
||||
* @cycles: Number of clock periods to wait.
|
||||
*
|
||||
* Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART
|
||||
* clock speed is 16X the current baud rate.
|
||||
*/
|
||||
static void tegra_uart_wait_cycle_time(struct tegra_uart_port *tup,
|
||||
unsigned int cycles)
|
||||
{
|
||||
if (tup->current_baud)
|
||||
udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16));
|
||||
}
|
||||
|
||||
/* Wait for a symbol-time. */
|
||||
static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup,
|
||||
unsigned int syms)
|
||||
@ -263,8 +279,12 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits)
|
||||
/* Dummy read to ensure the write is posted */
|
||||
tegra_uart_read(tup, UART_SCR);
|
||||
|
||||
/* Wait for the flush to propagate. */
|
||||
tegra_uart_wait_sym_time(tup, 1);
|
||||
/*
|
||||
* For all tegra devices (up to t210), there is a hardware issue that
|
||||
* requires software to wait for 32 UART clock periods for the flush
|
||||
* to propagate, otherwise data could be lost.
|
||||
*/
|
||||
tegra_uart_wait_cycle_time(tup, 32);
|
||||
}
|
||||
|
||||
static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud)
|
||||
@ -388,9 +408,9 @@ static void tegra_uart_tx_dma_complete(void *args)
|
||||
struct circ_buf *xmit = &tup->uport.state->xmit;
|
||||
struct dma_tx_state state;
|
||||
unsigned long flags;
|
||||
int count;
|
||||
unsigned int count;
|
||||
|
||||
dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state);
|
||||
dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state);
|
||||
count = tup->tx_bytes_requested - state.residue;
|
||||
async_tx_ack(tup->tx_dma_desc);
|
||||
spin_lock_irqsave(&tup->uport.lock, flags);
|
||||
@ -480,7 +500,7 @@ static void tegra_uart_stop_tx(struct uart_port *u)
|
||||
struct tegra_uart_port *tup = to_tegra_uport(u);
|
||||
struct circ_buf *xmit = &tup->uport.state->xmit;
|
||||
struct dma_tx_state state;
|
||||
int count;
|
||||
unsigned int count;
|
||||
|
||||
if (tup->tx_in_progress != TEGRA_UART_TX_DMA)
|
||||
return;
|
||||
@ -530,10 +550,15 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
|
||||
}
|
||||
|
||||
static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
|
||||
struct tty_port *tty, int count)
|
||||
struct tty_port *tty,
|
||||
unsigned int count)
|
||||
{
|
||||
int copied;
|
||||
|
||||
/* If count is zero, then there is no data to be copied */
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
tup->uport.icount.rx += count;
|
||||
if (!tty) {
|
||||
dev_err(tup->uport.dev, "No tty port\n");
|
||||
@ -555,21 +580,30 @@ static void tegra_uart_rx_dma_complete(void *args)
|
||||
{
|
||||
struct tegra_uart_port *tup = args;
|
||||
struct uart_port *u = &tup->uport;
|
||||
int count = tup->rx_bytes_requested;
|
||||
unsigned int count = tup->rx_bytes_requested;
|
||||
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
|
||||
struct tty_port *port = &u->state->port;
|
||||
unsigned long flags;
|
||||
struct dma_tx_state state;
|
||||
enum dma_status status;
|
||||
|
||||
spin_lock_irqsave(&u->lock, flags);
|
||||
|
||||
status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||
|
||||
if (status == DMA_IN_PROGRESS) {
|
||||
dev_dbg(tup->uport.dev, "RX DMA is in progress\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
async_tx_ack(tup->rx_dma_desc);
|
||||
spin_lock_irqsave(&u->lock, flags);
|
||||
|
||||
/* Deactivate flow control to stop sender */
|
||||
if (tup->rts_active)
|
||||
set_rts(tup, false);
|
||||
|
||||
/* If we are here, DMA is stopped */
|
||||
if (count)
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
|
||||
tegra_uart_handle_rx_pio(tup, port);
|
||||
if (tty) {
|
||||
@ -584,6 +618,7 @@ static void tegra_uart_rx_dma_complete(void *args)
|
||||
if (tup->rts_active)
|
||||
set_rts(tup, true);
|
||||
|
||||
done:
|
||||
spin_unlock_irqrestore(&u->lock, flags);
|
||||
}
|
||||
|
||||
@ -594,7 +629,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
|
||||
struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
|
||||
struct tty_port *port = &tup->uport.state->port;
|
||||
struct uart_port *u = &tup->uport;
|
||||
int count;
|
||||
unsigned int count;
|
||||
|
||||
/* Deactivate flow control to stop sender */
|
||||
if (tup->rts_active)
|
||||
@ -606,8 +641,7 @@ static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
|
||||
count = tup->rx_bytes_requested - state.residue;
|
||||
|
||||
/* If we are here, DMA is stopped */
|
||||
if (count)
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
tegra_uart_copy_rx_to_tty(tup, port, count);
|
||||
|
||||
tegra_uart_handle_rx_pio(tup, port);
|
||||
if (tty) {
|
||||
@ -865,6 +899,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
|
||||
tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B;
|
||||
tegra_uart_write(tup, tup->fcr_shadow, UART_FCR);
|
||||
|
||||
/* Dummy read to ensure the write is posted */
|
||||
tegra_uart_read(tup, UART_SCR);
|
||||
|
||||
/*
|
||||
* For all tegra devices (up to t210), there is a hardware issue that
|
||||
* requires software to wait for 3 UART clock periods after enabling
|
||||
* the TX fifo, otherwise data could be lost.
|
||||
*/
|
||||
tegra_uart_wait_cycle_time(tup, 3);
|
||||
|
||||
/*
|
||||
* Initialize the UART with default configuration
|
||||
* (115200, N, 8, 1) so that the receive DMA buffer may be
|
||||
@ -905,6 +949,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
|
||||
bool dma_to_memory)
|
||||
{
|
||||
if (dma_to_memory) {
|
||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||
dma_release_channel(tup->rx_dma_chan);
|
||||
dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
|
||||
tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
|
||||
tup->rx_dma_chan = NULL;
|
||||
tup->rx_dma_buf_phys = 0;
|
||||
tup->rx_dma_buf_virt = NULL;
|
||||
} else {
|
||||
dmaengine_terminate_all(tup->tx_dma_chan);
|
||||
dma_release_channel(tup->tx_dma_chan);
|
||||
dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
tup->tx_dma_chan = NULL;
|
||||
tup->tx_dma_buf_phys = 0;
|
||||
tup->tx_dma_buf_virt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
|
||||
bool dma_to_memory)
|
||||
{
|
||||
@ -933,67 +999,39 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
|
||||
dma_release_channel(dma_chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dma_sconfig.src_addr = tup->uport.mapbase;
|
||||
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma_sconfig.src_maxburst = 4;
|
||||
tup->rx_dma_chan = dma_chan;
|
||||
tup->rx_dma_buf_virt = dma_buf;
|
||||
tup->rx_dma_buf_phys = dma_phys;
|
||||
} else {
|
||||
dma_phys = dma_map_single(tup->uport.dev,
|
||||
tup->uport.state->xmit.buf, UART_XMIT_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(tup->uport.dev, dma_phys)) {
|
||||
dev_err(tup->uport.dev, "dma_map_single tx failed\n");
|
||||
dma_release_channel(dma_chan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dma_buf = tup->uport.state->xmit.buf;
|
||||
}
|
||||
|
||||
if (dma_to_memory) {
|
||||
dma_sconfig.src_addr = tup->uport.mapbase;
|
||||
dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma_sconfig.src_maxburst = 4;
|
||||
} else {
|
||||
dma_sconfig.dst_addr = tup->uport.mapbase;
|
||||
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma_sconfig.dst_maxburst = 16;
|
||||
tup->tx_dma_chan = dma_chan;
|
||||
tup->tx_dma_buf_virt = dma_buf;
|
||||
tup->tx_dma_buf_phys = dma_phys;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(dma_chan, &dma_sconfig);
|
||||
if (ret < 0) {
|
||||
dev_err(tup->uport.dev,
|
||||
"Dma slave config failed, err = %d\n", ret);
|
||||
goto scrub;
|
||||
tegra_uart_dma_channel_free(tup, dma_to_memory);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dma_to_memory) {
|
||||
tup->rx_dma_chan = dma_chan;
|
||||
tup->rx_dma_buf_virt = dma_buf;
|
||||
tup->rx_dma_buf_phys = dma_phys;
|
||||
} else {
|
||||
tup->tx_dma_chan = dma_chan;
|
||||
tup->tx_dma_buf_virt = dma_buf;
|
||||
tup->tx_dma_buf_phys = dma_phys;
|
||||
}
|
||||
return 0;
|
||||
|
||||
scrub:
|
||||
dma_release_channel(dma_chan);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup,
|
||||
bool dma_to_memory)
|
||||
{
|
||||
struct dma_chan *dma_chan;
|
||||
|
||||
if (dma_to_memory) {
|
||||
dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE,
|
||||
tup->rx_dma_buf_virt, tup->rx_dma_buf_phys);
|
||||
dma_chan = tup->rx_dma_chan;
|
||||
tup->rx_dma_chan = NULL;
|
||||
tup->rx_dma_buf_phys = 0;
|
||||
tup->rx_dma_buf_virt = NULL;
|
||||
} else {
|
||||
dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
dma_chan = tup->tx_dma_chan;
|
||||
tup->tx_dma_chan = NULL;
|
||||
tup->tx_dma_buf_phys = 0;
|
||||
tup->tx_dma_buf_virt = NULL;
|
||||
}
|
||||
dma_release_channel(dma_chan);
|
||||
}
|
||||
|
||||
static int tegra_uart_startup(struct uart_port *u)
|
||||
@ -1060,8 +1098,6 @@ static void tegra_uart_shutdown(struct uart_port *u)
|
||||
tegra_uart_dma_channel_free(tup, true);
|
||||
tegra_uart_dma_channel_free(tup, false);
|
||||
free_irq(u->irq, tup);
|
||||
|
||||
tegra_uart_flush_buffer(u);
|
||||
}
|
||||
|
||||
static void tegra_uart_enable_ms(struct uart_port *u)
|
||||
|
@ -894,12 +894,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
||||
* need to rate-limit; it's CAP_SYS_ADMIN only.
|
||||
*/
|
||||
if (uport->flags & UPF_SPD_MASK) {
|
||||
char buf[64];
|
||||
|
||||
dev_notice(uport->dev,
|
||||
"%s sets custom speed on %s. This is deprecated.\n",
|
||||
current->comm,
|
||||
tty_name(port->tty, buf));
|
||||
tty_name(port->tty));
|
||||
}
|
||||
uart_change_speed(tty, state, NULL);
|
||||
}
|
||||
@ -1816,8 +1814,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
|
||||
* @options: ptr for <options> field; NULL if not present (out)
|
||||
*
|
||||
* Decodes earlycon kernel command line parameters of the form
|
||||
* earlycon=<name>,io|mmio|mmio32,<addr>,<options>
|
||||
* console=<name>,io|mmio|mmio32,<addr>,<options>
|
||||
* earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
|
||||
* console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
|
||||
*
|
||||
* The optional form
|
||||
* earlycon=<name>,0x<addr>,<options>
|
||||
@ -1835,6 +1833,9 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
|
||||
} else if (strncmp(p, "mmio32,", 7) == 0) {
|
||||
*iotype = UPIO_MEM32;
|
||||
p += 7;
|
||||
} else if (strncmp(p, "mmio32be,", 9) == 0) {
|
||||
*iotype = UPIO_MEM32BE;
|
||||
p += 9;
|
||||
} else if (strncmp(p, "io,", 3) == 0) {
|
||||
*iotype = UPIO_PORT;
|
||||
p += 3;
|
||||
|
@ -49,8 +49,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
unsigned int count = 0;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
|
||||
mctrl_gpios_desc[i].dir_out) {
|
||||
if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
|
||||
desc_array[count] = gpios->gpio[i];
|
||||
value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
|
||||
count++;
|
||||
@ -118,7 +117,7 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
if (!IS_ERR_OR_NULL(gpios->gpio[i]))
|
||||
if (gpios->gpio[i])
|
||||
devm_gpiod_put(dev, gpios->gpio[i]);
|
||||
devm_kfree(dev, gpios);
|
||||
}
|
||||
|
@ -81,7 +81,8 @@ struct sci_port {
|
||||
|
||||
/* Platform configuration */
|
||||
struct plat_sci_port *cfg;
|
||||
int overrun_bit;
|
||||
unsigned int overrun_reg;
|
||||
unsigned int overrun_mask;
|
||||
unsigned int error_mask;
|
||||
unsigned int sampling_rate;
|
||||
|
||||
@ -168,6 +169,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = sci_reg_invalid,
|
||||
[SCLSR] = sci_reg_invalid,
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -188,6 +191,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = sci_reg_invalid,
|
||||
[SCLSR] = sci_reg_invalid,
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -207,6 +212,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = sci_reg_invalid,
|
||||
[SCLSR] = sci_reg_invalid,
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = { 0x30, 16 },
|
||||
[SCPDR] = { 0x34, 16 },
|
||||
},
|
||||
|
||||
/*
|
||||
@ -226,6 +233,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = sci_reg_invalid,
|
||||
[SCLSR] = sci_reg_invalid,
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = { 0x30, 16 },
|
||||
[SCPDR] = { 0x34, 16 },
|
||||
},
|
||||
|
||||
/*
|
||||
@ -246,6 +255,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = { 0x20, 16 },
|
||||
[SCLSR] = { 0x24, 16 },
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -265,6 +276,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = sci_reg_invalid,
|
||||
[SCLSR] = sci_reg_invalid,
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -284,6 +297,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = { 0x20, 16 },
|
||||
[SCLSR] = { 0x24, 16 },
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -303,6 +318,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = { 0x20, 16 },
|
||||
[SCLSR] = { 0x24, 16 },
|
||||
[HSSRR] = { 0x40, 16 },
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -323,6 +340,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = sci_reg_invalid,
|
||||
[SCLSR] = { 0x24, 16 },
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -343,6 +362,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = { 0x24, 16 },
|
||||
[SCLSR] = { 0x28, 16 },
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
|
||||
/*
|
||||
@ -363,6 +384,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
|
||||
[SCSPTR] = sci_reg_invalid,
|
||||
[SCLSR] = sci_reg_invalid,
|
||||
[HSSRR] = sci_reg_invalid,
|
||||
[SCPCR] = sci_reg_invalid,
|
||||
[SCPDR] = sci_reg_invalid,
|
||||
},
|
||||
};
|
||||
|
||||
@ -781,7 +804,7 @@ static int sci_handle_errors(struct uart_port *port)
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
/* Handle overruns */
|
||||
if (status & (1 << s->overrun_bit)) {
|
||||
if (status & s->overrun_mask) {
|
||||
port->icount.overrun++;
|
||||
|
||||
/* overrun error */
|
||||
@ -844,32 +867,17 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
struct plat_sci_reg *reg;
|
||||
int copied = 0, offset;
|
||||
u16 status, bit;
|
||||
int copied = 0;
|
||||
u16 status;
|
||||
|
||||
switch (port->type) {
|
||||
case PORT_SCIF:
|
||||
case PORT_HSCIF:
|
||||
offset = SCLSR;
|
||||
break;
|
||||
case PORT_SCIFA:
|
||||
case PORT_SCIFB:
|
||||
offset = SCxSR;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg = sci_getreg(port, offset);
|
||||
reg = sci_getreg(port, s->overrun_reg);
|
||||
if (!reg->size)
|
||||
return 0;
|
||||
|
||||
status = serial_port_in(port, offset);
|
||||
bit = 1 << s->overrun_bit;
|
||||
|
||||
if (status & bit) {
|
||||
status &= ~bit;
|
||||
serial_port_out(port, offset, status);
|
||||
status = serial_port_in(port, s->overrun_reg);
|
||||
if (status & s->overrun_mask) {
|
||||
status &= ~s->overrun_mask;
|
||||
serial_port_out(port, s->overrun_reg, status);
|
||||
|
||||
port->icount.overrun++;
|
||||
|
||||
@ -1021,15 +1029,11 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
|
||||
|
||||
ssr_status = serial_port_in(port, SCxSR);
|
||||
scr_status = serial_port_in(port, SCSCR);
|
||||
switch (port->type) {
|
||||
case PORT_SCIF:
|
||||
case PORT_HSCIF:
|
||||
orer_status = serial_port_in(port, SCLSR);
|
||||
break;
|
||||
case PORT_SCIFA:
|
||||
case PORT_SCIFB:
|
||||
if (s->overrun_reg == SCxSR)
|
||||
orer_status = ssr_status;
|
||||
break;
|
||||
else {
|
||||
if (sci_getreg(port, s->overrun_reg)->size)
|
||||
orer_status = serial_port_in(port, s->overrun_reg);
|
||||
}
|
||||
|
||||
err_enabled = scr_status & port_rx_irq_mask(port);
|
||||
@ -1059,7 +1063,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
|
||||
ret = sci_br_interrupt(irq, ptr);
|
||||
|
||||
/* Overrun Interrupt */
|
||||
if (orer_status & (1 << s->overrun_bit))
|
||||
if (orer_status & s->overrun_mask)
|
||||
sci_handle_fifo_overrun(port);
|
||||
|
||||
return ret;
|
||||
@ -2234,32 +2238,38 @@ static int sci_init_single(struct platform_device *dev,
|
||||
switch (p->type) {
|
||||
case PORT_SCIFB:
|
||||
port->fifosize = 256;
|
||||
sci_port->overrun_bit = 9;
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCIFA_ORER;
|
||||
sampling_rate = 16;
|
||||
break;
|
||||
case PORT_HSCIF:
|
||||
port->fifosize = 128;
|
||||
sampling_rate = 0;
|
||||
sci_port->overrun_bit = 0;
|
||||
sci_port->overrun_reg = SCLSR;
|
||||
sci_port->overrun_mask = SCLSR_ORER;
|
||||
break;
|
||||
case PORT_SCIFA:
|
||||
port->fifosize = 64;
|
||||
sci_port->overrun_bit = 9;
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCIFA_ORER;
|
||||
sampling_rate = 16;
|
||||
break;
|
||||
case PORT_SCIF:
|
||||
port->fifosize = 16;
|
||||
if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
|
||||
sci_port->overrun_bit = 9;
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCIFA_ORER;
|
||||
sampling_rate = 16;
|
||||
} else {
|
||||
sci_port->overrun_bit = 0;
|
||||
sci_port->overrun_reg = SCLSR;
|
||||
sci_port->overrun_mask = SCLSR_ORER;
|
||||
sampling_rate = 32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
port->fifosize = 1;
|
||||
sci_port->overrun_bit = 5;
|
||||
sci_port->overrun_reg = SCxSR;
|
||||
sci_port->overrun_mask = SCI_ORER;
|
||||
sampling_rate = 32;
|
||||
break;
|
||||
}
|
||||
@ -2304,16 +2314,12 @@ static int sci_init_single(struct platform_device *dev,
|
||||
sci_port->error_mask = (p->type == PORT_SCI) ?
|
||||
SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
|
||||
|
||||
/*
|
||||
* Establish sensible defaults for the overrun detection, unless
|
||||
* the part has explicitly disabled support for it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Make the error mask inclusive of overrun detection, if
|
||||
* supported.
|
||||
*/
|
||||
sci_port->error_mask |= 1 << sci_port->overrun_bit;
|
||||
if (sci_port->overrun_reg == SCxSR)
|
||||
sci_port->error_mask |= sci_port->overrun_mask;
|
||||
|
||||
port->type = p->type;
|
||||
port->flags = UPF_FIXED_PORT | p->flags;
|
||||
|
@ -1,7 +1,115 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#define SCI_MAJOR 204
|
||||
#define SCI_MINOR_START 8
|
||||
|
||||
|
||||
/*
|
||||
* SCI register subset common for all port types.
|
||||
* Not all registers will exist on all parts.
|
||||
*/
|
||||
enum {
|
||||
SCSMR, /* Serial Mode Register */
|
||||
SCBRR, /* Bit Rate Register */
|
||||
SCSCR, /* Serial Control Register */
|
||||
SCxSR, /* Serial Status Register */
|
||||
SCFCR, /* FIFO Control Register */
|
||||
SCFDR, /* FIFO Data Count Register */
|
||||
SCxTDR, /* Transmit (FIFO) Data Register */
|
||||
SCxRDR, /* Receive (FIFO) Data Register */
|
||||
SCLSR, /* Line Status Register */
|
||||
SCTFDR, /* Transmit FIFO Data Count Register */
|
||||
SCRFDR, /* Receive FIFO Data Count Register */
|
||||
SCSPTR, /* Serial Port Register */
|
||||
HSSRR, /* Sampling Rate Register */
|
||||
SCPCR, /* Serial Port Control Register */
|
||||
SCPDR, /* Serial Port Data Register */
|
||||
|
||||
SCIx_NR_REGS,
|
||||
};
|
||||
|
||||
|
||||
/* SCSMR (Serial Mode Register) */
|
||||
#define SCSMR_CHR BIT(6) /* 7-bit Character Length */
|
||||
#define SCSMR_PE BIT(5) /* Parity Enable */
|
||||
#define SCSMR_ODD BIT(4) /* Odd Parity */
|
||||
#define SCSMR_STOP BIT(3) /* Stop Bit Length */
|
||||
#define SCSMR_CKS 0x0003 /* Clock Select */
|
||||
|
||||
/* Serial Control Register, SCIFA/SCIFB only bits */
|
||||
#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */
|
||||
#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */
|
||||
|
||||
/* SCxSR (Serial Status Register) on SCI */
|
||||
#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */
|
||||
#define SCI_RDRF BIT(6) /* Receive Data Register Full */
|
||||
#define SCI_ORER BIT(5) /* Overrun Error */
|
||||
#define SCI_FER BIT(4) /* Framing Error */
|
||||
#define SCI_PER BIT(3) /* Parity Error */
|
||||
#define SCI_TEND BIT(2) /* Transmit End */
|
||||
#define SCI_RESERVED 0x03 /* All reserved bits */
|
||||
|
||||
#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
|
||||
|
||||
#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF)
|
||||
#define SCI_ERROR_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
|
||||
#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE)
|
||||
#define SCI_BREAK_CLEAR ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
|
||||
|
||||
/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
|
||||
#define SCIF_ER BIT(7) /* Receive Error */
|
||||
#define SCIF_TEND BIT(6) /* Transmission End */
|
||||
#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */
|
||||
#define SCIF_BRK BIT(4) /* Break Detect */
|
||||
#define SCIF_FER BIT(3) /* Framing Error */
|
||||
#define SCIF_PER BIT(2) /* Parity Error */
|
||||
#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */
|
||||
#define SCIF_DR BIT(0) /* Receive Data Ready */
|
||||
/* SCIF only (optional) */
|
||||
#define SCIF_PERC 0xf000 /* Number of Parity Errors */
|
||||
#define SCIF_FERC 0x0f00 /* Number of Framing Errors */
|
||||
/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */
|
||||
#define SCIFA_ORER BIT(9) /* Overrun Error */
|
||||
|
||||
#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
|
||||
|
||||
#define SCIF_RDxF_CLEAR ~(SCIF_DR | SCIF_RDF)
|
||||
#define SCIF_ERROR_CLEAR ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER)
|
||||
#define SCIF_TDxE_CLEAR ~(SCIF_TDFE)
|
||||
#define SCIF_BREAK_CLEAR ~(SCIF_PER | SCIF_FER | SCIF_BRK)
|
||||
|
||||
/* SCFCR (FIFO Control Register) */
|
||||
#define SCFCR_MCE BIT(3) /* Modem Control Enable */
|
||||
#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */
|
||||
#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */
|
||||
#define SCFCR_LOOP BIT(0) /* Loopback Test */
|
||||
|
||||
/* SCLSR (Line Status Register) on (H)SCIF */
|
||||
#define SCLSR_ORER BIT(0) /* Overrun Error */
|
||||
|
||||
/* SCSPTR (Serial Port Register), optional */
|
||||
#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */
|
||||
#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */
|
||||
#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */
|
||||
#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */
|
||||
#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */
|
||||
#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */
|
||||
|
||||
/* HSSRR HSCIF */
|
||||
#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
|
||||
|
||||
/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
|
||||
#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */
|
||||
#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */
|
||||
|
||||
/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */
|
||||
#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */
|
||||
#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */
|
||||
|
||||
|
||||
#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
|
||||
#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
|
||||
#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
|
||||
@ -15,24 +123,24 @@
|
||||
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
|
||||
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
|
||||
defined(CONFIG_ARCH_SH73A0) || \
|
||||
defined(CONFIG_ARCH_SH7372) || \
|
||||
defined(CONFIG_ARCH_R8A7740)
|
||||
|
||||
# define SCxSR_RDxF_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfffc)
|
||||
# define SCxSR_ERROR_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfd73)
|
||||
# define SCxSR_TDxE_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffdf)
|
||||
# define SCxSR_BREAK_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffe3)
|
||||
# define SCxSR_RDxF_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR)
|
||||
# define SCxSR_ERROR_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR)
|
||||
# define SCxSR_TDxE_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR)
|
||||
# define SCxSR_BREAK_CLEAR(port) \
|
||||
(serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR)
|
||||
#else
|
||||
# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
|
||||
# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
|
||||
# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
|
||||
# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
|
||||
# define SCxSR_RDxF_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff)
|
||||
# define SCxSR_ERROR_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff)
|
||||
# define SCxSR_TDxE_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff)
|
||||
# define SCxSR_BREAK_CLEAR(port) \
|
||||
((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff)
|
||||
#endif
|
||||
|
||||
/* SCFCR */
|
||||
#define SCFCR_RFRST 0x0002
|
||||
#define SCFCR_TFRST 0x0004
|
||||
#define SCFCR_MCE 0x0008
|
||||
|
||||
#define SCI_MAJOR 204
|
||||
#define SCI_MINOR_START 8
|
||||
|
@ -36,8 +36,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count);
|
||||
static struct uart_driver sirfsoc_uart_drv;
|
||||
|
||||
static void sirfsoc_uart_tx_dma_complete_callback(void *param);
|
||||
static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port);
|
||||
static void sirfsoc_uart_rx_dma_complete_callback(void *param);
|
||||
static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
|
||||
{4000000, 2359296},
|
||||
{3500000, 1310721},
|
||||
@ -59,50 +57,7 @@ static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = {
|
||||
{9600, 1114979},
|
||||
};
|
||||
|
||||
static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
|
||||
[0] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 0,
|
||||
},
|
||||
},
|
||||
[1] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 1,
|
||||
},
|
||||
},
|
||||
[2] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 2,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 3,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 4,
|
||||
},
|
||||
},
|
||||
[5] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 5,
|
||||
},
|
||||
},
|
||||
};
|
||||
static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR];
|
||||
|
||||
static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
|
||||
{
|
||||
@ -116,8 +71,7 @@ static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port)
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
|
||||
reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status);
|
||||
|
||||
return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0;
|
||||
return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port)
|
||||
@ -152,6 +106,26 @@ static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0;
|
||||
unsigned int current_val;
|
||||
|
||||
if (mctrl & TIOCM_LOOP) {
|
||||
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
|
||||
wr_regl(port, ureg->sirfsoc_line_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_line_ctrl) |
|
||||
SIRFUART_LOOP_BACK);
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_mode1,
|
||||
rd_regl(port, ureg->sirfsoc_mode1) |
|
||||
SIRFSOC_USP_LOOP_BACK_CTRL);
|
||||
} else {
|
||||
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART)
|
||||
wr_regl(port, ureg->sirfsoc_line_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_line_ctrl) &
|
||||
~SIRFUART_LOOP_BACK);
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_mode1,
|
||||
rd_regl(port, ureg->sirfsoc_mode1) &
|
||||
~SIRFSOC_USP_LOOP_BACK_CTRL);
|
||||
}
|
||||
|
||||
if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled)
|
||||
return;
|
||||
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
|
||||
@ -182,16 +156,19 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
~uint_en->sirfsoc_txfifo_empty_en);
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
|
||||
uint_en->sirfsoc_txfifo_empty_en);
|
||||
}
|
||||
} else {
|
||||
if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
|
||||
wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
|
||||
ureg->sirfsoc_tx_rx_en) & ~SIRFUART_TX_EN);
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
~uint_en->sirfsoc_txfifo_empty_en);
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
|
||||
uint_en->sirfsoc_txfifo_empty_en);
|
||||
}
|
||||
}
|
||||
@ -222,7 +199,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)&
|
||||
~(uint_en->sirfsoc_txfifo_empty_en));
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
|
||||
uint_en->sirfsoc_txfifo_empty_en);
|
||||
/*
|
||||
* DMA requires buffer address and buffer length are both aligned with
|
||||
@ -290,8 +267,11 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
|
||||
if (sirfport->tx_dma_chan)
|
||||
sirfsoc_uart_tx_with_dma(sirfport);
|
||||
else {
|
||||
sirfsoc_uart_pio_tx_chars(sirfport,
|
||||
SIRFSOC_UART_IO_TX_REASONABLE_CNT);
|
||||
if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
|
||||
wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port,
|
||||
ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN);
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
|
||||
sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize);
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
@ -314,21 +294,25 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
|
||||
~(SIRFUART_RX_DMA_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type) |
|
||||
uint_en->sirfsoc_rx_done_en));
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
SIRFUART_RX_DMA_INT_EN(port, uint_en)|
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
|
||||
SIRFUART_RX_DMA_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type)|
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
dmaengine_terminate_all(sirfport->rx_dma_chan);
|
||||
} else {
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)&
|
||||
~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
|
||||
~(SIRFUART_RX_IO_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type)));
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
SIRFUART_RX_IO_INT_EN(port, uint_en));
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
|
||||
SIRFUART_RX_IO_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,7 +333,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port)
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)&
|
||||
~uint_en->sirfsoc_cts_en);
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
|
||||
uint_en->sirfsoc_cts_en);
|
||||
} else
|
||||
disable_irq(gpio_to_irq(sirfport->cts_gpio));
|
||||
@ -379,7 +363,8 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port)
|
||||
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
|
||||
wr_regl(port, ureg->sirfsoc_afc_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_afc_ctrl) |
|
||||
SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
|
||||
SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN |
|
||||
SIRFUART_AFC_CTRL_RX_THD);
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)
|
||||
@ -417,7 +402,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
|
||||
if (!tty)
|
||||
return -ENODEV;
|
||||
while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
|
||||
ufifo_st->ff_empty(port->line))) {
|
||||
ufifo_st->ff_empty(port))) {
|
||||
ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) |
|
||||
SIRFUART_DUMMY_READ;
|
||||
if (unlikely(uart_handle_sysrq_char(port, ch)))
|
||||
@ -444,7 +429,7 @@ sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count)
|
||||
unsigned int num_tx = 0;
|
||||
while (!uart_circ_empty(xmit) &&
|
||||
!(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
|
||||
ufifo_st->ff_full(port->line)) &&
|
||||
ufifo_st->ff_full(port)) &&
|
||||
count--) {
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_data,
|
||||
xmit->buf[xmit->tail]);
|
||||
@ -478,139 +463,6 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_insert_rx_buf_to_tty(
|
||||
struct sirfsoc_uart_port *sirfport, int count)
|
||||
{
|
||||
struct uart_port *port = &sirfport->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int inserted;
|
||||
|
||||
inserted = tty_insert_flip_string(tport,
|
||||
sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count);
|
||||
port->icount.rx += inserted;
|
||||
}
|
||||
|
||||
static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
|
||||
sirfport->rx_dma_items[index].xmit.tail =
|
||||
sirfport->rx_dma_items[index].xmit.head = 0;
|
||||
sirfport->rx_dma_items[index].desc =
|
||||
dmaengine_prep_slave_single(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
|
||||
if (!sirfport->rx_dma_items[index].desc) {
|
||||
dev_err(port->dev, "DMA slave single fail\n");
|
||||
return;
|
||||
}
|
||||
sirfport->rx_dma_items[index].desc->callback =
|
||||
sirfsoc_uart_rx_dma_complete_callback;
|
||||
sirfport->rx_dma_items[index].desc->callback_param = sirfport;
|
||||
sirfport->rx_dma_items[index].cookie =
|
||||
dmaengine_submit(sirfport->rx_dma_items[index].desc);
|
||||
dma_async_issue_pending(sirfport->rx_dma_chan);
|
||||
}
|
||||
|
||||
static void sirfsoc_rx_tmo_process_tl(unsigned long param)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
|
||||
struct uart_port *port = &sirfport->port;
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
|
||||
unsigned int count;
|
||||
unsigned long flags;
|
||||
struct dma_tx_state tx_state;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
|
||||
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
|
||||
SIRFSOC_RX_DMA_BUF_SIZE);
|
||||
sirfport->rx_completed++;
|
||||
sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
|
||||
}
|
||||
count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head,
|
||||
sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail,
|
||||
SIRFSOC_RX_DMA_BUF_SIZE);
|
||||
if (count > 0)
|
||||
sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count);
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
|
||||
SIRFUART_IO_MODE);
|
||||
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
|
||||
if (sirfport->rx_io_count == 4) {
|
||||
sirfport->rx_io_count = 0;
|
||||
wr_regl(port, ureg->sirfsoc_int_st_reg,
|
||||
uint_st->sirfsoc_rx_done);
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
~(uint_en->sirfsoc_rx_done_en));
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
sirfsoc_uart_start_next_rx_dma(port);
|
||||
} else {
|
||||
wr_regl(port, ureg->sirfsoc_int_st_reg,
|
||||
uint_st->sirfsoc_rx_done);
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) |
|
||||
(uint_en->sirfsoc_rx_done_en));
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
|
||||
{
|
||||
struct uart_port *port = &sirfport->port;
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
struct dma_tx_state tx_state;
|
||||
dmaengine_tx_status(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state);
|
||||
dmaengine_terminate_all(sirfport->rx_dma_chan);
|
||||
sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
|
||||
SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
~(uint_en->sirfsoc_rx_timeout_en));
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
uint_en->sirfsoc_rx_timeout_en);
|
||||
tasklet_schedule(&sirfport->rx_tmo_process_tasklet);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
|
||||
{
|
||||
struct uart_port *port = &sirfport->port;
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
|
||||
|
||||
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
|
||||
if (sirfport->rx_io_count == 4) {
|
||||
sirfport->rx_io_count = 0;
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
~(uint_en->sirfsoc_rx_done_en));
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR,
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
wr_regl(port, ureg->sirfsoc_int_st_reg,
|
||||
uint_st->sirfsoc_rx_timeout);
|
||||
sirfsoc_uart_start_next_rx_dma(port);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long intr_status;
|
||||
@ -628,20 +480,25 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
|
||||
intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg);
|
||||
wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status);
|
||||
intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg);
|
||||
if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) {
|
||||
if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st,
|
||||
sirfport->uart_reg->uart_type)))) {
|
||||
if (intr_status & uint_st->sirfsoc_rxd_brk) {
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
goto recv_char;
|
||||
}
|
||||
if (intr_status & uint_st->sirfsoc_rx_oflow)
|
||||
if (intr_status & uint_st->sirfsoc_rx_oflow) {
|
||||
port->icount.overrun++;
|
||||
flag = TTY_OVERRUN;
|
||||
}
|
||||
if (intr_status & uint_st->sirfsoc_frm_err) {
|
||||
port->icount.frame++;
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
if (intr_status & uint_st->sirfsoc_parity_err)
|
||||
if (intr_status & uint_st->sirfsoc_parity_err) {
|
||||
port->icount.parity++;
|
||||
flag = TTY_PARITY;
|
||||
}
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
|
||||
@ -662,15 +519,51 @@ recv_char:
|
||||
uart_handle_cts_change(port, cts_status);
|
||||
wake_up_interruptible(&state->port.delta_msr_wait);
|
||||
}
|
||||
if (sirfport->rx_dma_chan) {
|
||||
if (intr_status & uint_st->sirfsoc_rx_timeout)
|
||||
sirfsoc_uart_handle_rx_tmo(sirfport);
|
||||
if (intr_status & uint_st->sirfsoc_rx_done)
|
||||
sirfsoc_uart_handle_rx_done(sirfport);
|
||||
} else {
|
||||
if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))
|
||||
sirfsoc_uart_pio_rx_chars(port,
|
||||
SIRFSOC_UART_IO_RX_MAX_CNT);
|
||||
if (!sirfport->rx_dma_chan &&
|
||||
(intr_status & SIRFUART_RX_IO_INT_ST(uint_st))) {
|
||||
/*
|
||||
* chip will trigger continuous RX_TIMEOUT interrupt
|
||||
* in RXFIFO empty and not trigger if RXFIFO recevice
|
||||
* data in limit time, original method use RX_TIMEOUT
|
||||
* will trigger lots of useless interrupt in RXFIFO
|
||||
* empty.RXFIFO received one byte will trigger RX_DONE
|
||||
* interrupt.use RX_DONE to wait for data received
|
||||
* into RXFIFO, use RX_THD/RX_FULL for lots data receive
|
||||
* and use RX_TIMEOUT for the last left data.
|
||||
*/
|
||||
if (intr_status & uint_st->sirfsoc_rx_done) {
|
||||
if (!sirfport->is_atlas7) {
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)
|
||||
& ~(uint_en->sirfsoc_rx_done_en));
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)
|
||||
| (uint_en->sirfsoc_rx_timeout_en));
|
||||
} else {
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg,
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
uint_en->sirfsoc_rx_timeout_en);
|
||||
}
|
||||
} else {
|
||||
if (intr_status & uint_st->sirfsoc_rx_timeout) {
|
||||
if (!sirfport->is_atlas7) {
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)
|
||||
& ~(uint_en->sirfsoc_rx_timeout_en));
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg)
|
||||
| (uint_en->sirfsoc_rx_done_en));
|
||||
} else {
|
||||
wr_regl(port,
|
||||
ureg->sirfsoc_int_en_clr_reg,
|
||||
uint_en->sirfsoc_rx_timeout_en);
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
uint_en->sirfsoc_rx_done_en);
|
||||
}
|
||||
}
|
||||
sirfsoc_uart_pio_rx_chars(port, port->fifosize);
|
||||
}
|
||||
}
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(&state->port);
|
||||
@ -684,10 +577,10 @@ recv_char:
|
||||
return IRQ_HANDLED;
|
||||
} else {
|
||||
sirfsoc_uart_pio_tx_chars(sirfport,
|
||||
SIRFSOC_UART_IO_TX_REASONABLE_CNT);
|
||||
port->fifosize);
|
||||
if ((uart_circ_empty(xmit)) &&
|
||||
(rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
|
||||
ufifo_st->ff_empty(port->line)))
|
||||
ufifo_st->ff_empty(port)))
|
||||
sirfsoc_uart_stop_tx(port);
|
||||
}
|
||||
}
|
||||
@ -697,41 +590,8 @@ recv_char:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
|
||||
struct uart_port *port = &sirfport->port;
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
unsigned long flags;
|
||||
struct dma_tx_state tx_state;
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
|
||||
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
|
||||
SIRFSOC_RX_DMA_BUF_SIZE);
|
||||
if (rd_regl(port, ureg->sirfsoc_int_en_reg) &
|
||||
uint_en->sirfsoc_rx_timeout_en)
|
||||
sirfsoc_rx_submit_one_dma_desc(port,
|
||||
sirfport->rx_completed++);
|
||||
else
|
||||
sirfport->rx_completed++;
|
||||
sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT;
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_rx_dma_complete_callback(void *param)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sirfport->port.lock, flags);
|
||||
sirfport->rx_issued++;
|
||||
sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT;
|
||||
tasklet_schedule(&sirfport->rx_dma_complete_tasklet);
|
||||
spin_unlock_irqrestore(&sirfport->port.lock, flags);
|
||||
}
|
||||
|
||||
/* submit rx dma task into dmaengine */
|
||||
@ -740,21 +600,36 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
|
||||
int i;
|
||||
sirfport->rx_io_count = 0;
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
|
||||
~SIRFUART_IO_MODE);
|
||||
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
|
||||
sirfsoc_rx_submit_one_dma_desc(port, i);
|
||||
sirfport->rx_completed = sirfport->rx_issued = 0;
|
||||
sirfport->rx_dma_items.xmit.tail =
|
||||
sirfport->rx_dma_items.xmit.head = 0;
|
||||
sirfport->rx_dma_items.desc =
|
||||
dmaengine_prep_dma_cyclic(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items.dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
SIRFSOC_RX_DMA_BUF_SIZE / 2,
|
||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
|
||||
if (IS_ERR_OR_NULL(sirfport->rx_dma_items.desc)) {
|
||||
dev_err(port->dev, "DMA slave single fail\n");
|
||||
return;
|
||||
}
|
||||
sirfport->rx_dma_items.desc->callback =
|
||||
sirfsoc_uart_rx_dma_complete_callback;
|
||||
sirfport->rx_dma_items.desc->callback_param = sirfport;
|
||||
sirfport->rx_dma_items.cookie =
|
||||
dmaengine_submit(sirfport->rx_dma_items.desc);
|
||||
dma_async_issue_pending(sirfport->rx_dma_chan);
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) |
|
||||
SIRFUART_RX_DMA_INT_EN(port, uint_en));
|
||||
SIRFUART_RX_DMA_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type));
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
SIRFUART_RX_DMA_INT_EN(port, uint_en));
|
||||
SIRFUART_RX_DMA_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type));
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_start_rx(struct uart_port *port)
|
||||
@ -773,10 +648,12 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
rd_regl(port, ureg->sirfsoc_int_en_reg) |
|
||||
SIRFUART_RX_IO_INT_EN(port, uint_en));
|
||||
SIRFUART_RX_IO_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type));
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg,
|
||||
SIRFUART_RX_IO_INT_EN(port, uint_en));
|
||||
SIRFUART_RX_IO_INT_EN(uint_en,
|
||||
sirfport->uart_reg->uart_type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -789,7 +666,7 @@ sirfsoc_usp_calc_sample_div(unsigned long set_rate,
|
||||
unsigned long ioclk_div = 0;
|
||||
unsigned long temp_delta;
|
||||
|
||||
for (sample_div = SIRF_MIN_SAMPLE_DIV;
|
||||
for (sample_div = SIRF_USP_MIN_SAMPLE_DIV;
|
||||
sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) {
|
||||
temp_delta = ioclk_rate -
|
||||
(ioclk_rate + (set_rate * sample_div) / 2)
|
||||
@ -910,10 +787,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
||||
config_reg |= SIRFUART_STICK_BIT_MARK;
|
||||
else
|
||||
config_reg |= SIRFUART_STICK_BIT_SPACE;
|
||||
} else if (termios->c_cflag & PARODD) {
|
||||
config_reg |= SIRFUART_STICK_BIT_ODD;
|
||||
} else {
|
||||
config_reg |= SIRFUART_STICK_BIT_EVEN;
|
||||
if (termios->c_cflag & PARODD)
|
||||
config_reg |= SIRFUART_STICK_BIT_ODD;
|
||||
else
|
||||
config_reg |= SIRFUART_STICK_BIT_EVEN;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -976,7 +854,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_op,
|
||||
(txfifo_op_reg & ~SIRFUART_FIFO_START));
|
||||
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
|
||||
config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out);
|
||||
config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out);
|
||||
wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg);
|
||||
} else {
|
||||
/*tx frame ctrl*/
|
||||
@ -999,7 +877,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
||||
wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val);
|
||||
/*async param*/
|
||||
wr_regl(port, ureg->sirfsoc_async_param_reg,
|
||||
(SIRFUART_RECV_TIMEOUT(port, rx_time_out)) |
|
||||
(SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) |
|
||||
(sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) <<
|
||||
SIRFSOC_USP_ASYNC_DIV2_OFFSET);
|
||||
}
|
||||
@ -1011,6 +889,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE);
|
||||
else
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE);
|
||||
sirfport->rx_period_time = 20000000;
|
||||
/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
|
||||
if (set_baud < 1000000)
|
||||
threshold_div = 1;
|
||||
@ -1032,19 +911,10 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
|
||||
unsigned int oldstate)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
if (!state) {
|
||||
if (sirfport->is_bt_uart) {
|
||||
clk_prepare_enable(sirfport->clk_noc);
|
||||
clk_prepare_enable(sirfport->clk_general);
|
||||
}
|
||||
if (!state)
|
||||
clk_prepare_enable(sirfport->clk);
|
||||
} else {
|
||||
else
|
||||
clk_disable_unprepare(sirfport->clk);
|
||||
if (sirfport->is_bt_uart) {
|
||||
clk_disable_unprepare(sirfport->clk_general);
|
||||
clk_disable_unprepare(sirfport->clk_noc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sirfsoc_uart_startup(struct uart_port *port)
|
||||
@ -1064,7 +934,6 @@ static int sirfsoc_uart_startup(struct uart_port *port)
|
||||
index, port->irq);
|
||||
goto irq_err;
|
||||
}
|
||||
|
||||
/* initial hardware settings */
|
||||
wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) |
|
||||
@ -1072,6 +941,9 @@ static int sirfsoc_uart_startup(struct uart_port *port)
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
|
||||
SIRFUART_IO_MODE);
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
|
||||
~SIRFUART_RX_DMA_FLUSH);
|
||||
wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0);
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0);
|
||||
wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN);
|
||||
@ -1080,7 +952,6 @@ static int sirfsoc_uart_startup(struct uart_port *port)
|
||||
SIRFSOC_USP_ENDIAN_CTRL_LSBF |
|
||||
SIRFSOC_USP_EN);
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET);
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port));
|
||||
@ -1110,8 +981,16 @@ static int sirfsoc_uart_startup(struct uart_port *port)
|
||||
goto init_rx_err;
|
||||
}
|
||||
}
|
||||
|
||||
enable_irq(port->irq);
|
||||
if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) {
|
||||
sirfport->is_hrt_enabled = true;
|
||||
sirfport->rx_period_time = 20000000;
|
||||
sirfport->rx_dma_items.xmit.tail =
|
||||
sirfport->rx_dma_items.xmit.head = 0;
|
||||
hrtimer_start(&sirfport->hrt,
|
||||
ns_to_ktime(sirfport->rx_period_time),
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
init_rx_err:
|
||||
@ -1127,7 +1006,7 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
|
||||
if (!sirfport->is_atlas7)
|
||||
wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
|
||||
else
|
||||
wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
|
||||
wr_regl(port, ureg->sirfsoc_int_en_clr_reg, ~0UL);
|
||||
|
||||
free_irq(port->irq, sirfport);
|
||||
if (sirfport->ms_enabled)
|
||||
@ -1139,6 +1018,13 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
|
||||
}
|
||||
if (sirfport->tx_dma_chan)
|
||||
sirfport->tx_dma_state = TX_DMA_IDLE;
|
||||
if (sirfport->rx_dma_chan && sirfport->is_hrt_enabled) {
|
||||
while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
|
||||
SIRFUART_RX_FIFO_MASK) > 0)
|
||||
;
|
||||
sirfport->is_hrt_enabled = false;
|
||||
hrtimer_cancel(&sirfport->hrt);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *sirfsoc_uart_type(struct uart_port *port)
|
||||
@ -1196,27 +1082,29 @@ sirfsoc_uart_console_setup(struct console *co, char *options)
|
||||
unsigned int bits = 8;
|
||||
unsigned int parity = 'n';
|
||||
unsigned int flow = 'n';
|
||||
struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_uart_port *sirfport;
|
||||
struct sirfsoc_register *ureg;
|
||||
if (co->index < 0 || co->index >= SIRFSOC_UART_NR)
|
||||
return -EINVAL;
|
||||
|
||||
if (!port->mapbase)
|
||||
co->index = 1;
|
||||
sirfport = sirf_ports[co->index];
|
||||
if (!sirfport)
|
||||
return -ENODEV;
|
||||
ureg = &sirfport->uart_reg->uart_reg;
|
||||
if (!sirfport->port.mapbase)
|
||||
return -ENODEV;
|
||||
|
||||
/* enable usp in mode1 register */
|
||||
if (sirfport->uart_reg->uart_type == SIRF_USP_UART)
|
||||
wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
|
||||
wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN |
|
||||
SIRFSOC_USP_ENDIAN_CTRL_LSBF);
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
port->cons = co;
|
||||
sirfport->port.cons = co;
|
||||
|
||||
/* default console tx/rx transfer using io mode */
|
||||
sirfport->rx_dma_chan = NULL;
|
||||
sirfport->tx_dma_chan = NULL;
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
return uart_set_options(&sirfport->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
|
||||
@ -1224,8 +1112,8 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
|
||||
struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status;
|
||||
while (rd_regl(port,
|
||||
ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line))
|
||||
while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) &
|
||||
ufifo_st->ff_full(port))
|
||||
cpu_relax();
|
||||
wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch);
|
||||
}
|
||||
@ -1233,8 +1121,10 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch)
|
||||
static void sirfsoc_uart_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &sirfsoc_uart_ports[co->index].port;
|
||||
uart_console_write(port, s, count, sirfsoc_uart_console_putchar);
|
||||
struct sirfsoc_uart_port *sirfport = sirf_ports[co->index];
|
||||
|
||||
uart_console_write(&sirfport->port, s, count,
|
||||
sirfsoc_uart_console_putchar);
|
||||
}
|
||||
|
||||
static struct console sirfsoc_uart_console = {
|
||||
@ -1269,10 +1159,75 @@ static struct uart_driver sirfsoc_uart_drv = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct of_device_id sirfsoc_uart_ids[] = {
|
||||
static enum hrtimer_restart
|
||||
sirfsoc_uart_rx_dma_hrtimer_callback(struct hrtimer *hrt)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport;
|
||||
struct uart_port *port;
|
||||
int count, inserted;
|
||||
struct dma_tx_state tx_state;
|
||||
struct tty_struct *tty;
|
||||
struct sirfsoc_register *ureg;
|
||||
struct circ_buf *xmit;
|
||||
|
||||
sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt);
|
||||
port = &sirfport->port;
|
||||
inserted = 0;
|
||||
tty = port->state->port.tty;
|
||||
ureg = &sirfport->uart_reg->uart_reg;
|
||||
xmit = &sirfport->rx_dma_items.xmit;
|
||||
dmaengine_tx_status(sirfport->rx_dma_chan,
|
||||
sirfport->rx_dma_items.cookie, &tx_state);
|
||||
xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
|
||||
count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
|
||||
SIRFSOC_RX_DMA_BUF_SIZE);
|
||||
while (count > 0) {
|
||||
inserted = tty_insert_flip_string(tty->port,
|
||||
(const unsigned char *)&xmit->buf[xmit->tail], count);
|
||||
if (!inserted)
|
||||
goto next_hrt;
|
||||
port->icount.rx += inserted;
|
||||
xmit->tail = (xmit->tail + inserted) &
|
||||
(SIRFSOC_RX_DMA_BUF_SIZE - 1);
|
||||
count = CIRC_CNT_TO_END(xmit->head, xmit->tail,
|
||||
SIRFSOC_RX_DMA_BUF_SIZE);
|
||||
tty_flip_buffer_push(tty->port);
|
||||
}
|
||||
/*
|
||||
* if RX DMA buffer data have all push into tty buffer, and there is
|
||||
* only little data(less than a dma transfer unit) left in rxfifo,
|
||||
* fetch it out in pio mode and switch back to dma immediately
|
||||
*/
|
||||
if (!inserted && !count &&
|
||||
((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
|
||||
SIRFUART_RX_FIFO_MASK) > 0)) {
|
||||
/* switch to pio mode */
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
|
||||
SIRFUART_IO_MODE);
|
||||
while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) &
|
||||
SIRFUART_RX_FIFO_MASK) > 0) {
|
||||
if (sirfsoc_uart_pio_rx_chars(port, 16) > 0)
|
||||
tty_flip_buffer_push(tty->port);
|
||||
}
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
|
||||
wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START);
|
||||
/* switch back to dma mode */
|
||||
wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
|
||||
rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) &
|
||||
~SIRFUART_IO_MODE);
|
||||
}
|
||||
next_hrt:
|
||||
hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
static struct of_device_id sirfsoc_uart_ids[] = {
|
||||
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
|
||||
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
|
||||
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
|
||||
{ .compatible = "sirf,atlas7-usp-uart", .data = &sirfsoc_usp},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
|
||||
@ -1283,7 +1238,6 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
int i, j;
|
||||
struct dma_slave_config slv_cfg = {
|
||||
.src_maxburst = 2,
|
||||
};
|
||||
@ -1293,16 +1247,15 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
|
||||
if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to find cell-index in uart node.\n");
|
||||
ret = -EFAULT;
|
||||
sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL);
|
||||
if (!sirfport) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart"))
|
||||
pdev->id += ((struct sirfsoc_uart_register *)
|
||||
match->data)->uart_param.register_uart_nr;
|
||||
sirfport = &sirfsoc_uart_ports[pdev->id];
|
||||
sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
sirf_ports[sirfport->port.line] = sirfport;
|
||||
sirfport->port.iotype = UPIO_MEM;
|
||||
sirfport->port.flags = UPF_BOOT_AUTOCONF;
|
||||
port = &sirfport->port;
|
||||
port->dev = &pdev->dev;
|
||||
port->private_data = sirfport;
|
||||
@ -1310,9 +1263,12 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
|
||||
sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
|
||||
"sirf,uart-has-rtscts");
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart"))
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") ||
|
||||
of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
|
||||
sirfport->uart_reg->uart_type = SIRF_REAL_UART;
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) {
|
||||
if (of_device_is_compatible(pdev->dev.of_node,
|
||||
"sirf,prima2-usp-uart") || of_device_is_compatible(
|
||||
pdev->dev.of_node, "sirf,atlas7-usp-uart")) {
|
||||
sirfport->uart_reg->uart_type = SIRF_USP_UART;
|
||||
if (!sirfport->hw_flow_ctrl)
|
||||
goto usp_no_flow_control;
|
||||
@ -1350,7 +1306,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
gpio_direction_output(sirfport->rts_gpio, 1);
|
||||
}
|
||||
usp_no_flow_control:
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") ||
|
||||
of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart"))
|
||||
sirfport->is_atlas7 = true;
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
@ -1368,12 +1325,9 @@ usp_no_flow_control:
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
tasklet_init(&sirfport->rx_dma_complete_tasklet,
|
||||
sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport);
|
||||
tasklet_init(&sirfport->rx_tmo_process_tasklet,
|
||||
sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport);
|
||||
port->mapbase = res->start;
|
||||
port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
port->membase = devm_ioremap(&pdev->dev,
|
||||
res->start, resource_size(res));
|
||||
if (!port->membase) {
|
||||
dev_err(&pdev->dev, "Cannot remap resource.\n");
|
||||
ret = -ENOMEM;
|
||||
@ -1393,20 +1347,6 @@ usp_no_flow_control:
|
||||
goto err;
|
||||
}
|
||||
port->uartclk = clk_get_rate(sirfport->clk);
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) {
|
||||
sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
|
||||
if (IS_ERR(sirfport->clk_general)) {
|
||||
ret = PTR_ERR(sirfport->clk_general);
|
||||
goto err;
|
||||
}
|
||||
sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc");
|
||||
if (IS_ERR(sirfport->clk_noc)) {
|
||||
ret = PTR_ERR(sirfport->clk_noc);
|
||||
goto err;
|
||||
}
|
||||
sirfport->is_bt_uart = true;
|
||||
} else
|
||||
sirfport->is_bt_uart = false;
|
||||
|
||||
port->ops = &sirfsoc_uart_ops;
|
||||
spin_lock_init(&port->lock);
|
||||
@ -1419,30 +1359,32 @@ usp_no_flow_control:
|
||||
}
|
||||
|
||||
sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx");
|
||||
for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) {
|
||||
sirfport->rx_dma_items[i].xmit.buf =
|
||||
dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
&sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL);
|
||||
if (!sirfport->rx_dma_items[i].xmit.buf) {
|
||||
dev_err(port->dev, "Uart alloc bufa failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto alloc_coherent_err;
|
||||
}
|
||||
sirfport->rx_dma_items[i].xmit.head =
|
||||
sirfport->rx_dma_items[i].xmit.tail = 0;
|
||||
sirfport->rx_dma_items.xmit.buf =
|
||||
dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
&sirfport->rx_dma_items.dma_addr, GFP_KERNEL);
|
||||
if (!sirfport->rx_dma_items.xmit.buf) {
|
||||
dev_err(port->dev, "Uart alloc bufa failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto alloc_coherent_err;
|
||||
}
|
||||
sirfport->rx_dma_items.xmit.head =
|
||||
sirfport->rx_dma_items.xmit.tail = 0;
|
||||
if (sirfport->rx_dma_chan)
|
||||
dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg);
|
||||
sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx");
|
||||
if (sirfport->tx_dma_chan)
|
||||
dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg);
|
||||
if (sirfport->rx_dma_chan) {
|
||||
hrtimer_init(&sirfport->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
sirfport->hrt.function = sirfsoc_uart_rx_dma_hrtimer_callback;
|
||||
sirfport->is_hrt_enabled = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
alloc_coherent_err:
|
||||
for (j = 0; j < i; j++)
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items[j].xmit.buf,
|
||||
sirfport->rx_dma_items[j].dma_addr);
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items.xmit.buf,
|
||||
sirfport->rx_dma_items.dma_addr);
|
||||
dma_release_channel(sirfport->rx_dma_chan);
|
||||
err:
|
||||
return ret;
|
||||
@ -1454,13 +1396,11 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
|
||||
struct uart_port *port = &sirfport->port;
|
||||
uart_remove_one_port(&sirfsoc_uart_drv, port);
|
||||
if (sirfport->rx_dma_chan) {
|
||||
int i;
|
||||
dmaengine_terminate_all(sirfport->rx_dma_chan);
|
||||
dma_release_channel(sirfport->rx_dma_chan);
|
||||
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items[i].xmit.buf,
|
||||
sirfport->rx_dma_items[i].dma_addr);
|
||||
dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE,
|
||||
sirfport->rx_dma_items.xmit.buf,
|
||||
sirfport->rx_dma_items.dma_addr);
|
||||
}
|
||||
if (sirfport->tx_dma_chan) {
|
||||
dmaengine_terminate_all(sirfport->tx_dma_chan);
|
||||
|
@ -6,11 +6,11 @@
|
||||
* Licensed under GPLv2 or later.
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/hrtimer.h>
|
||||
struct sirfsoc_uart_param {
|
||||
const char *uart_name;
|
||||
const char *port_name;
|
||||
u32 uart_nr;
|
||||
u32 register_uart_nr;
|
||||
};
|
||||
|
||||
struct sirfsoc_register {
|
||||
@ -21,6 +21,7 @@ struct sirfsoc_register {
|
||||
u32 sirfsoc_tx_rx_en;
|
||||
u32 sirfsoc_int_en_reg;
|
||||
u32 sirfsoc_int_st_reg;
|
||||
u32 sirfsoc_int_en_clr_reg;
|
||||
u32 sirfsoc_tx_dma_io_ctrl;
|
||||
u32 sirfsoc_tx_dma_io_len;
|
||||
u32 sirfsoc_tx_fifo_ctrl;
|
||||
@ -45,8 +46,8 @@ struct sirfsoc_register {
|
||||
u32 sirfsoc_async_param_reg;
|
||||
};
|
||||
|
||||
typedef u32 (*fifo_full_mask)(int line);
|
||||
typedef u32 (*fifo_empty_mask)(int line);
|
||||
typedef u32 (*fifo_full_mask)(struct uart_port *port);
|
||||
typedef u32 (*fifo_empty_mask)(struct uart_port *port);
|
||||
|
||||
struct sirfsoc_fifo_status {
|
||||
fifo_full_mask ff_full;
|
||||
@ -105,21 +106,20 @@ struct sirfsoc_uart_register {
|
||||
enum sirfsoc_uart_type uart_type;
|
||||
};
|
||||
|
||||
u32 usp_ff_full(int line)
|
||||
u32 uart_usp_ff_full_mask(struct uart_port *port)
|
||||
{
|
||||
return 0x80;
|
||||
u32 full_bit;
|
||||
|
||||
full_bit = ilog2(port->fifosize);
|
||||
return (1 << full_bit);
|
||||
}
|
||||
u32 usp_ff_empty(int line)
|
||||
|
||||
u32 uart_usp_ff_empty_mask(struct uart_port *port)
|
||||
{
|
||||
return 0x100;
|
||||
}
|
||||
u32 uart_ff_full(int line)
|
||||
{
|
||||
return (line == 1) ? (0x20) : (0x80);
|
||||
}
|
||||
u32 uart_ff_empty(int line)
|
||||
{
|
||||
return (line == 1) ? (0x40) : (0x100);
|
||||
u32 empty_bit;
|
||||
|
||||
empty_bit = ilog2(port->fifosize) + 1;
|
||||
return (1 << empty_bit);
|
||||
}
|
||||
struct sirfsoc_uart_register sirfsoc_usp = {
|
||||
.uart_reg = {
|
||||
@ -145,6 +145,7 @@ struct sirfsoc_uart_register sirfsoc_usp = {
|
||||
.sirfsoc_rx_fifo_op = 0x0130,
|
||||
.sirfsoc_rx_fifo_status = 0x0134,
|
||||
.sirfsoc_rx_fifo_data = 0x0138,
|
||||
.sirfsoc_int_en_clr_reg = 0x140,
|
||||
},
|
||||
.uart_int_en = {
|
||||
.sirfsoc_rx_done_en = BIT(0),
|
||||
@ -177,14 +178,12 @@ struct sirfsoc_uart_register sirfsoc_usp = {
|
||||
.sirfsoc_rxd_brk = BIT(15),
|
||||
},
|
||||
.fifo_status = {
|
||||
.ff_full = usp_ff_full,
|
||||
.ff_empty = usp_ff_empty,
|
||||
.ff_full = uart_usp_ff_full_mask,
|
||||
.ff_empty = uart_usp_ff_empty_mask,
|
||||
},
|
||||
.uart_param = {
|
||||
.uart_name = "ttySiRF",
|
||||
.port_name = "sirfsoc-uart",
|
||||
.uart_nr = 2,
|
||||
.register_uart_nr = 3,
|
||||
},
|
||||
};
|
||||
|
||||
@ -195,6 +194,7 @@ struct sirfsoc_uart_register sirfsoc_uart = {
|
||||
.sirfsoc_divisor = 0x0050,
|
||||
.sirfsoc_int_en_reg = 0x0054,
|
||||
.sirfsoc_int_st_reg = 0x0058,
|
||||
.sirfsoc_int_en_clr_reg = 0x0060,
|
||||
.sirfsoc_tx_dma_io_ctrl = 0x0100,
|
||||
.sirfsoc_tx_dma_io_len = 0x0104,
|
||||
.sirfsoc_tx_fifo_ctrl = 0x0108,
|
||||
@ -249,14 +249,12 @@ struct sirfsoc_uart_register sirfsoc_uart = {
|
||||
.sirfsoc_rts = BIT(15),
|
||||
},
|
||||
.fifo_status = {
|
||||
.ff_full = uart_ff_full,
|
||||
.ff_empty = uart_ff_empty,
|
||||
.ff_full = uart_usp_ff_full_mask,
|
||||
.ff_empty = uart_usp_ff_empty_mask,
|
||||
},
|
||||
.uart_param = {
|
||||
.uart_name = "ttySiRF",
|
||||
.port_name = "sirfsoc_uart",
|
||||
.uart_nr = 3,
|
||||
.register_uart_nr = 0,
|
||||
},
|
||||
};
|
||||
/* uart io ctrl */
|
||||
@ -296,10 +294,10 @@ struct sirfsoc_uart_register sirfsoc_uart = {
|
||||
|
||||
#define SIRFUART_IO_MODE BIT(0)
|
||||
#define SIRFUART_DMA_MODE 0x0
|
||||
#define SIRFUART_RX_DMA_FLUSH 0x4
|
||||
|
||||
/* Macro Specific*/
|
||||
#define SIRFUART_INT_EN_CLR 0x0060
|
||||
/* Baud Rate Calculation */
|
||||
#define SIRF_USP_MIN_SAMPLE_DIV 0x1
|
||||
#define SIRF_MIN_SAMPLE_DIV 0xf
|
||||
#define SIRF_MAX_SAMPLE_DIV 0x3f
|
||||
#define SIRF_IOCLK_DIV_MAX 0xffff
|
||||
@ -326,55 +324,54 @@ struct sirfsoc_uart_register sirfsoc_uart = {
|
||||
#define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24
|
||||
#define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f
|
||||
#define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16
|
||||
|
||||
#define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2)
|
||||
/* USP-UART Common */
|
||||
#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
|
||||
#define SIRFUART_RECV_TIMEOUT_VALUE(x) \
|
||||
(((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF))
|
||||
#define SIRFUART_RECV_TIMEOUT(port, x) \
|
||||
(((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16)
|
||||
#define SIRFUART_USP_RECV_TIMEOUT(x) (x & 0xFFFF)
|
||||
#define SIRFUART_UART_RECV_TIMEOUT(x) ((x & 0xFFFF) << 16)
|
||||
|
||||
#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64)
|
||||
#define SIRFUART_ERR_INT_STAT(port, unit_st) \
|
||||
#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1)
|
||||
#define SIRFUART_ERR_INT_STAT(unit_st, uart_type) \
|
||||
(uint_st->sirfsoc_rx_oflow | \
|
||||
uint_st->sirfsoc_frm_err | \
|
||||
uint_st->sirfsoc_rxd_brk | \
|
||||
((port->line > 2) ? 0 : uint_st->sirfsoc_parity_err))
|
||||
#define SIRFUART_RX_IO_INT_EN(port, uint_en) \
|
||||
(uint_en->sirfsoc_rx_timeout_en |\
|
||||
((uart_type != SIRF_REAL_UART) ? \
|
||||
0 : uint_st->sirfsoc_parity_err))
|
||||
#define SIRFUART_RX_IO_INT_EN(uint_en, uart_type) \
|
||||
(uint_en->sirfsoc_rx_done_en |\
|
||||
uint_en->sirfsoc_rxfifo_thd_en |\
|
||||
uint_en->sirfsoc_rxfifo_full_en |\
|
||||
uint_en->sirfsoc_frm_err_en |\
|
||||
uint_en->sirfsoc_rx_oflow_en |\
|
||||
uint_en->sirfsoc_rxd_brk_en |\
|
||||
((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
|
||||
((uart_type != SIRF_REAL_UART) ? \
|
||||
0 : uint_en->sirfsoc_parity_err_en))
|
||||
#define SIRFUART_RX_IO_INT_ST(uint_st) \
|
||||
(uint_st->sirfsoc_rx_timeout |\
|
||||
uint_st->sirfsoc_rxfifo_thd |\
|
||||
uint_st->sirfsoc_rxfifo_full)
|
||||
(uint_st->sirfsoc_rxfifo_thd |\
|
||||
uint_st->sirfsoc_rxfifo_full|\
|
||||
uint_st->sirfsoc_rx_done |\
|
||||
uint_st->sirfsoc_rx_timeout)
|
||||
#define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts)
|
||||
#define SIRFUART_RX_DMA_INT_EN(port, uint_en) \
|
||||
(uint_en->sirfsoc_rx_timeout_en |\
|
||||
uint_en->sirfsoc_frm_err_en |\
|
||||
#define SIRFUART_RX_DMA_INT_EN(uint_en, uart_type) \
|
||||
(uint_en->sirfsoc_frm_err_en |\
|
||||
uint_en->sirfsoc_rx_oflow_en |\
|
||||
uint_en->sirfsoc_rxd_brk_en |\
|
||||
((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en))
|
||||
((uart_type != SIRF_REAL_UART) ? \
|
||||
0 : uint_en->sirfsoc_parity_err_en))
|
||||
/* Generic Definitions */
|
||||
#define SIRFSOC_UART_NAME "ttySiRF"
|
||||
#define SIRFSOC_UART_MAJOR 0
|
||||
#define SIRFSOC_UART_MINOR 0
|
||||
#define SIRFUART_PORT_NAME "sirfsoc-uart"
|
||||
#define SIRFUART_MAP_SIZE 0x200
|
||||
#define SIRFSOC_UART_NR 6
|
||||
#define SIRFSOC_UART_NR 11
|
||||
#define SIRFSOC_PORT_TYPE 0xa5
|
||||
|
||||
/* Uart Common Use Macro*/
|
||||
#define SIRFSOC_RX_DMA_BUF_SIZE 256
|
||||
#define SIRFSOC_RX_DMA_BUF_SIZE (1024 * 32)
|
||||
#define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3)
|
||||
#define LOOP_DMA_BUFA_FILL 1
|
||||
#define LOOP_DMA_BUFB_FILL 2
|
||||
#define TX_TRAN_PIO 1
|
||||
#define TX_TRAN_DMA 2
|
||||
/* Uart Fifo Level Chk */
|
||||
#define SIRFUART_TX_FIFO_SC_OFFSET 0
|
||||
#define SIRFUART_TX_FIFO_LC_OFFSET 10
|
||||
@ -389,8 +386,8 @@ struct sirfsoc_uart_register sirfsoc_uart = {
|
||||
#define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC
|
||||
#define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC
|
||||
#define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC
|
||||
#define SIRFUART_RX_FIFO_MASK 0x7f
|
||||
/* Indicate how many buffers used */
|
||||
#define SIRFSOC_RX_LOOP_BUF_CNT 2
|
||||
|
||||
/* For Fast Baud Rate Calculation */
|
||||
struct sirfsoc_baudrate_to_regv {
|
||||
@ -404,7 +401,7 @@ enum sirfsoc_tx_state {
|
||||
TX_DMA_PAUSE,
|
||||
};
|
||||
|
||||
struct sirfsoc_loop_buffer {
|
||||
struct sirfsoc_rx_buffer {
|
||||
struct circ_buf xmit;
|
||||
dma_cookie_t cookie;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
@ -417,10 +414,6 @@ struct sirfsoc_uart_port {
|
||||
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
/* UART6 for BT usage in A7DA platform need multi-clock source */
|
||||
bool is_bt_uart;
|
||||
struct clk *clk_general;
|
||||
struct clk *clk_noc;
|
||||
/* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
|
||||
bool is_atlas7;
|
||||
struct sirfsoc_uart_register *uart_reg;
|
||||
@ -428,17 +421,16 @@ struct sirfsoc_uart_port {
|
||||
struct dma_chan *tx_dma_chan;
|
||||
dma_addr_t tx_dma_addr;
|
||||
struct dma_async_tx_descriptor *tx_dma_desc;
|
||||
struct tasklet_struct rx_dma_complete_tasklet;
|
||||
struct tasklet_struct rx_tmo_process_tasklet;
|
||||
unsigned int rx_io_count;
|
||||
unsigned long transfer_size;
|
||||
enum sirfsoc_tx_state tx_dma_state;
|
||||
unsigned int cts_gpio;
|
||||
unsigned int rts_gpio;
|
||||
|
||||
struct sirfsoc_loop_buffer rx_dma_items[SIRFSOC_RX_LOOP_BUF_CNT];
|
||||
int rx_completed;
|
||||
int rx_issued;
|
||||
struct sirfsoc_rx_buffer rx_dma_items;
|
||||
struct hrtimer hrt;
|
||||
bool is_hrt_enabled;
|
||||
unsigned long rx_period_time;
|
||||
};
|
||||
|
||||
/* Register Access Control */
|
||||
@ -447,10 +439,6 @@ struct sirfsoc_uart_port {
|
||||
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
|
||||
|
||||
/* UART Port Mask */
|
||||
#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f))
|
||||
#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80))
|
||||
#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100))
|
||||
|
||||
/* I/O Mode */
|
||||
#define SIRFSOC_UART_IO_RX_MAX_CNT 256
|
||||
#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256
|
||||
#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF)
|
||||
#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF)
|
||||
#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1)
|
||||
|
@ -1075,7 +1075,8 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch)
|
||||
writel(ch, port->membase + CDNS_UART_FIFO_OFFSET);
|
||||
}
|
||||
|
||||
static void cdns_early_write(struct console *con, const char *s, unsigned n)
|
||||
static void __init cdns_early_write(struct console *con, const char *s,
|
||||
unsigned n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
|
@ -4410,7 +4410,8 @@ static void synclink_cleanup(void)
|
||||
printk("Unloading %s: %s\n", driver_name, driver_version);
|
||||
|
||||
if (serial_driver) {
|
||||
if ((rc = tty_unregister_driver(serial_driver)))
|
||||
rc = tty_unregister_driver(serial_driver);
|
||||
if (rc)
|
||||
printk("%s(%d) failed to unregister tty driver err=%d\n",
|
||||
__FILE__,__LINE__,rc);
|
||||
put_tty_driver(serial_driver);
|
||||
@ -7751,7 +7752,8 @@ static int hdlcdev_open(struct net_device *dev)
|
||||
printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
|
||||
|
||||
/* generic HDLC layer open processing */
|
||||
if ((rc = hdlc_open(dev)))
|
||||
rc = hdlc_open(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* arbitrate between network and tty opens */
|
||||
@ -8018,7 +8020,8 @@ static int hdlcdev_init(struct mgsl_struct *info)
|
||||
|
||||
/* allocate and initialize network and HDLC layer objects */
|
||||
|
||||
if (!(dev = alloc_hdlcdev(info))) {
|
||||
dev = alloc_hdlcdev(info);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -8039,7 +8042,8 @@ static int hdlcdev_init(struct mgsl_struct *info)
|
||||
hdlc->xmit = hdlcdev_xmit;
|
||||
|
||||
/* register objects with HDLC layer */
|
||||
if ((rc = register_hdlc_device(dev))) {
|
||||
rc = register_hdlc_device(dev);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
|
||||
free_netdev(dev);
|
||||
return rc;
|
||||
@ -8075,7 +8079,8 @@ static int synclink_init_one (struct pci_dev *dev,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!(info = mgsl_allocate_device())) {
|
||||
info = mgsl_allocate_device();
|
||||
if (!info) {
|
||||
printk("can't allocate device instance data.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -1539,7 +1539,8 @@ static int hdlcdev_open(struct net_device *dev)
|
||||
DBGINFO(("%s hdlcdev_open\n", dev->name));
|
||||
|
||||
/* generic HDLC layer open processing */
|
||||
if ((rc = hdlc_open(dev)))
|
||||
rc = hdlc_open(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* arbitrate between network and tty opens */
|
||||
@ -1803,7 +1804,8 @@ static int hdlcdev_init(struct slgt_info *info)
|
||||
|
||||
/* allocate and initialize network and HDLC layer objects */
|
||||
|
||||
if (!(dev = alloc_hdlcdev(info))) {
|
||||
dev = alloc_hdlcdev(info);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1824,7 +1826,8 @@ static int hdlcdev_init(struct slgt_info *info)
|
||||
hdlc->xmit = hdlcdev_xmit;
|
||||
|
||||
/* register objects with HDLC layer */
|
||||
if ((rc = register_hdlc_device(dev))) {
|
||||
rc = register_hdlc_device(dev);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
|
||||
free_netdev(dev);
|
||||
return rc;
|
||||
@ -1879,7 +1882,8 @@ static void rx_async(struct slgt_info *info)
|
||||
|
||||
stat = 0;
|
||||
|
||||
if ((status = *(p+1) & (BIT1 + BIT0))) {
|
||||
status = *(p + 1) & (BIT1 + BIT0);
|
||||
if (status) {
|
||||
if (status & BIT1)
|
||||
icount->parity++;
|
||||
else if (status & BIT0)
|
||||
@ -3755,7 +3759,8 @@ static void slgt_cleanup(void)
|
||||
if (serial_driver) {
|
||||
for (info=slgt_device_list ; info != NULL ; info=info->next_device)
|
||||
tty_unregister_device(serial_driver, info->line);
|
||||
if ((rc = tty_unregister_driver(serial_driver)))
|
||||
rc = tty_unregister_driver(serial_driver);
|
||||
if (rc)
|
||||
DBGERR(("tty_unregister_driver error=%d\n", rc));
|
||||
put_tty_driver(serial_driver);
|
||||
}
|
||||
|
@ -1655,7 +1655,8 @@ static int hdlcdev_open(struct net_device *dev)
|
||||
printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name);
|
||||
|
||||
/* generic HDLC layer open processing */
|
||||
if ((rc = hdlc_open(dev)))
|
||||
rc = hdlc_open(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* arbitrate between network and tty opens */
|
||||
@ -1922,7 +1923,8 @@ static int hdlcdev_init(SLMP_INFO *info)
|
||||
|
||||
/* allocate and initialize network and HDLC layer objects */
|
||||
|
||||
if (!(dev = alloc_hdlcdev(info))) {
|
||||
dev = alloc_hdlcdev(info);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1943,7 +1945,8 @@ static int hdlcdev_init(SLMP_INFO *info)
|
||||
hdlc->xmit = hdlcdev_xmit;
|
||||
|
||||
/* register objects with HDLC layer */
|
||||
if ((rc = register_hdlc_device(dev))) {
|
||||
rc = register_hdlc_device(dev);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__);
|
||||
free_netdev(dev);
|
||||
return rc;
|
||||
@ -3920,7 +3923,8 @@ static void synclinkmp_cleanup(void)
|
||||
printk("Unloading %s %s\n", driver_name, driver_version);
|
||||
|
||||
if (serial_driver) {
|
||||
if ((rc = tty_unregister_driver(serial_driver)))
|
||||
rc = tty_unregister_driver(serial_driver);
|
||||
if (rc)
|
||||
printk("%s(%d) failed to unregister tty driver err=%d\n",
|
||||
__FILE__,__LINE__,rc);
|
||||
put_tty_driver(serial_driver);
|
||||
|
@ -55,9 +55,6 @@
|
||||
static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
|
||||
static bool __read_mostly sysrq_always_enabled;
|
||||
|
||||
unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
|
||||
int sysrq_reset_downtime_ms __weak;
|
||||
|
||||
static bool sysrq_on(void)
|
||||
{
|
||||
return sysrq_enabled || sysrq_always_enabled;
|
||||
@ -569,6 +566,7 @@ void handle_sysrq(int key)
|
||||
EXPORT_SYMBOL(handle_sysrq);
|
||||
|
||||
#ifdef CONFIG_INPUT
|
||||
static int sysrq_reset_downtime_ms;
|
||||
|
||||
/* Simple translation table for the SysRq keys */
|
||||
static const unsigned char sysrq_xlate[KEY_CNT] =
|
||||
@ -949,23 +947,8 @@ static bool sysrq_handler_registered;
|
||||
|
||||
static inline void sysrq_register_handler(void)
|
||||
{
|
||||
unsigned short key;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
/* First check if a __weak interface was instantiated. */
|
||||
for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
|
||||
key = platform_sysrq_reset_seq[i];
|
||||
if (key == KEY_RESERVED || key > KEY_MAX)
|
||||
break;
|
||||
|
||||
sysrq_reset_seq[sysrq_reset_seq_len++] = key;
|
||||
}
|
||||
|
||||
/*
|
||||
* DT configuration takes precedence over anything that would
|
||||
* have been defined via the __weak interface.
|
||||
*/
|
||||
sysrq_of_get_keyreset_config();
|
||||
|
||||
error = input_register_handler(&sysrq_handler);
|
||||
|
@ -286,7 +286,8 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
|
||||
change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL);
|
||||
if (change || left < size) {
|
||||
/* This is the slow path - looking for new buffers to use */
|
||||
if ((n = tty_buffer_alloc(port, size)) != NULL) {
|
||||
n = tty_buffer_alloc(port, size);
|
||||
if (n != NULL) {
|
||||
n->flags = flags;
|
||||
buf->tail = n;
|
||||
b->commit = b->used;
|
||||
|
@ -235,7 +235,6 @@ static void tty_del_file(struct file *file)
|
||||
/**
|
||||
* tty_name - return tty naming
|
||||
* @tty: tty structure
|
||||
* @buf: buffer for output
|
||||
*
|
||||
* Convert a tty structure into a name. The name reflects the kernel
|
||||
* naming policy and if udev is in use may not reflect user space
|
||||
@ -243,13 +242,11 @@ static void tty_del_file(struct file *file)
|
||||
* Locking: none
|
||||
*/
|
||||
|
||||
char *tty_name(struct tty_struct *tty, char *buf)
|
||||
const char *tty_name(const struct tty_struct *tty)
|
||||
{
|
||||
if (!tty) /* Hmm. NULL pointer. That's fun. */
|
||||
strcpy(buf, "NULL tty");
|
||||
else
|
||||
strcpy(buf, tty->name);
|
||||
return buf;
|
||||
return "NULL tty";
|
||||
return tty->name;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(tty_name);
|
||||
@ -770,8 +767,7 @@ static void do_tty_hangup(struct work_struct *work)
|
||||
void tty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
char buf[64];
|
||||
printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
|
||||
printk(KERN_DEBUG "%s hangup...\n", tty_name(tty));
|
||||
#endif
|
||||
schedule_work(&tty->hangup_work);
|
||||
}
|
||||
@ -790,9 +786,7 @@ EXPORT_SYMBOL(tty_hangup);
|
||||
void tty_vhangup(struct tty_struct *tty)
|
||||
{
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
char buf[64];
|
||||
|
||||
printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
|
||||
printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty));
|
||||
#endif
|
||||
__tty_hangup(tty, 0);
|
||||
}
|
||||
@ -831,9 +825,7 @@ void tty_vhangup_self(void)
|
||||
static void tty_vhangup_session(struct tty_struct *tty)
|
||||
{
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
char buf[64];
|
||||
|
||||
printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf));
|
||||
printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty));
|
||||
#endif
|
||||
__tty_hangup(tty, 1);
|
||||
}
|
||||
@ -1769,7 +1761,6 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
struct tty_struct *o_tty = NULL;
|
||||
int do_sleep, final;
|
||||
int idx;
|
||||
char buf[64];
|
||||
long timeout = 0;
|
||||
int once = 1;
|
||||
|
||||
@ -1793,7 +1784,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__,
|
||||
tty_name(tty, buf), tty->count);
|
||||
tty_name(tty), tty->count);
|
||||
#endif
|
||||
|
||||
if (tty->ops->close)
|
||||
@ -1844,7 +1835,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (once) {
|
||||
once = 0;
|
||||
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
|
||||
__func__, tty_name(tty, buf));
|
||||
__func__, tty_name(tty));
|
||||
}
|
||||
schedule_timeout_killable(timeout);
|
||||
if (timeout < 120 * HZ)
|
||||
@ -1856,13 +1847,13 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (o_tty) {
|
||||
if (--o_tty->count < 0) {
|
||||
printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
|
||||
__func__, o_tty->count, tty_name(o_tty, buf));
|
||||
__func__, o_tty->count, tty_name(o_tty));
|
||||
o_tty->count = 0;
|
||||
}
|
||||
}
|
||||
if (--tty->count < 0) {
|
||||
printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n",
|
||||
__func__, tty->count, tty_name(tty, buf));
|
||||
__func__, tty->count, tty_name(tty));
|
||||
tty->count = 0;
|
||||
}
|
||||
|
||||
@ -1905,7 +1896,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
return 0;
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf));
|
||||
printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty));
|
||||
#endif
|
||||
/*
|
||||
* Ask the line discipline code to release its structures
|
||||
@ -1916,7 +1907,8 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
tty_flush_works(tty);
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf));
|
||||
printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__,
|
||||
tty_name(tty));
|
||||
#endif
|
||||
/*
|
||||
* The release_tty function takes care of the details of clearing
|
||||
|
@ -211,9 +211,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
|
||||
void tty_wait_until_sent(struct tty_struct *tty, long timeout)
|
||||
{
|
||||
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
|
||||
char buf[64];
|
||||
|
||||
printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
|
||||
printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty));
|
||||
#endif
|
||||
if (!timeout)
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
|
@ -22,9 +22,8 @@
|
||||
#undef LDISC_DEBUG_HANGUP
|
||||
|
||||
#ifdef LDISC_DEBUG_HANGUP
|
||||
#define tty_ldisc_debug(tty, f, args...) ({ \
|
||||
char __b[64]; \
|
||||
printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \
|
||||
#define tty_ldisc_debug(tty, f, args...) ({ \
|
||||
printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty), ##args); \
|
||||
})
|
||||
#else
|
||||
#define tty_ldisc_debug(tty, f, args...)
|
||||
@ -483,7 +482,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
|
||||
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
{
|
||||
char buf[64];
|
||||
struct tty_ldisc *new_ldisc;
|
||||
int r;
|
||||
|
||||
@ -504,7 +502,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
if (r < 0)
|
||||
panic("Couldn't open N_TTY ldisc for "
|
||||
"%s --- error %d.",
|
||||
tty_name(tty, buf), r);
|
||||
tty_name(tty), r);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,7 +299,8 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
|
||||
timeout = schedule_timeout(timeout);
|
||||
raw_spin_lock_irq(&sem->wait_lock);
|
||||
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
|
||||
if ((locked = writer_trylock(sem)))
|
||||
locked = writer_trylock(sem);
|
||||
if (locked)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -261,19 +261,22 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
|
||||
int m;
|
||||
if (glyph < 0 || glyph >= MAX_GLYPH)
|
||||
return 0;
|
||||
else if (!(p = *conp->vc_uni_pagedir_loc))
|
||||
return glyph;
|
||||
else if (use_unicode) {
|
||||
if (!p->inverse_trans_unicode)
|
||||
else {
|
||||
p = *conp->vc_uni_pagedir_loc;
|
||||
if (!p)
|
||||
return glyph;
|
||||
else
|
||||
return p->inverse_trans_unicode[glyph];
|
||||
} else {
|
||||
m = inv_translate[conp->vc_num];
|
||||
if (!p->inverse_translations[m])
|
||||
return glyph;
|
||||
else
|
||||
return p->inverse_translations[m][glyph];
|
||||
else if (use_unicode) {
|
||||
if (!p->inverse_trans_unicode)
|
||||
return glyph;
|
||||
else
|
||||
return p->inverse_trans_unicode[glyph];
|
||||
} else {
|
||||
m = inv_translate[conp->vc_num];
|
||||
if (!p->inverse_translations[m])
|
||||
return glyph;
|
||||
else
|
||||
return p->inverse_translations[m][glyph];
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inverse_translate);
|
||||
@ -397,7 +400,8 @@ static void con_release_unimap(struct uni_pagedir *p)
|
||||
|
||||
if (p == dflt) dflt = NULL;
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((p1 = p->uni_pgdir[i]) != NULL) {
|
||||
p1 = p->uni_pgdir[i];
|
||||
if (p1 != NULL) {
|
||||
for (j = 0; j < 32; j++)
|
||||
kfree(p1[j]);
|
||||
kfree(p1);
|
||||
@ -473,14 +477,16 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
|
||||
int i, n;
|
||||
u16 **p1, *p2;
|
||||
|
||||
if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
|
||||
p1 = p->uni_pgdir[n = unicode >> 11];
|
||||
if (!p1) {
|
||||
p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
|
||||
if (!p1) return -ENOMEM;
|
||||
for (i = 0; i < 32; i++)
|
||||
p1[i] = NULL;
|
||||
}
|
||||
|
||||
if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
|
||||
p2 = p1[n = (unicode >> 6) & 0x1f];
|
||||
if (!p2) {
|
||||
p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
|
||||
if (!p2) return -ENOMEM;
|
||||
memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
|
||||
@ -569,10 +575,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
* entries from "p" (old) to "q" (new).
|
||||
*/
|
||||
l = 0; /* unicode value */
|
||||
for (i = 0; i < 32; i++)
|
||||
if ((p1 = p->uni_pgdir[i]))
|
||||
for (j = 0; j < 32; j++)
|
||||
if ((p2 = p1[j])) {
|
||||
for (i = 0; i < 32; i++) {
|
||||
p1 = p->uni_pgdir[i];
|
||||
if (p1)
|
||||
for (j = 0; j < 32; j++) {
|
||||
p2 = p1[j];
|
||||
if (p2) {
|
||||
for (k = 0; k < 64; k++, l++)
|
||||
if (p2[k] != 0xffff) {
|
||||
/*
|
||||
@ -593,9 +601,11 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
/* Account for row of 64 empty entries */
|
||||
l += 64;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Account for empty table */
|
||||
l += 32 * 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finished copying font table, set vc_uni_pagedir to new table
|
||||
@ -735,10 +745,12 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
||||
ect = 0;
|
||||
if (*vc->vc_uni_pagedir_loc) {
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
for (i = 0; i < 32; i++)
|
||||
if ((p1 = p->uni_pgdir[i]))
|
||||
for (j = 0; j < 32; j++)
|
||||
if ((p2 = *(p1++)))
|
||||
for (i = 0; i < 32; i++) {
|
||||
p1 = p->uni_pgdir[i];
|
||||
if (p1)
|
||||
for (j = 0; j < 32; j++) {
|
||||
p2 = *(p1++);
|
||||
if (p2)
|
||||
for (k = 0; k < 64; k++) {
|
||||
if (*p2 < MAX_GLYPH && ect++ < ct) {
|
||||
__put_user((u_short)((i<<11)+(j<<6)+k),
|
||||
@ -749,6 +761,8 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
||||
}
|
||||
p2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
__put_user(ect, uct);
|
||||
console_unlock();
|
||||
|
@ -108,6 +108,7 @@
|
||||
#define CON_DRIVER_FLAG_MODULE 1
|
||||
#define CON_DRIVER_FLAG_INIT 2
|
||||
#define CON_DRIVER_FLAG_ATTR 4
|
||||
#define CON_DRIVER_FLAG_ZOMBIE 8
|
||||
|
||||
struct con_driver {
|
||||
const struct consw *con;
|
||||
@ -135,6 +136,7 @@ const struct consw *conswitchp;
|
||||
*/
|
||||
#define DEFAULT_BELL_PITCH 750
|
||||
#define DEFAULT_BELL_DURATION (HZ/8)
|
||||
#define DEFAULT_CURSOR_BLINK_MS 200
|
||||
|
||||
struct vc vc_cons [MAX_NR_CONSOLES];
|
||||
|
||||
@ -153,6 +155,7 @@ static int set_vesa_blanking(char __user *p);
|
||||
static void set_cursor(struct vc_data *vc);
|
||||
static void hide_cursor(struct vc_data *vc);
|
||||
static void console_callback(struct work_struct *ignored);
|
||||
static void con_driver_unregister_callback(struct work_struct *ignored);
|
||||
static void blank_screen_t(unsigned long dummy);
|
||||
static void set_palette(struct vc_data *vc);
|
||||
|
||||
@ -182,6 +185,7 @@ static int blankinterval = 10*60;
|
||||
core_param(consoleblank, blankinterval, int, 0444);
|
||||
|
||||
static DECLARE_WORK(console_work, console_callback);
|
||||
static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback);
|
||||
|
||||
/*
|
||||
* fg_console is the current virtual console,
|
||||
@ -1590,6 +1594,13 @@ static void setterm_command(struct vc_data *vc)
|
||||
case 15: /* activate the previous console */
|
||||
set_console(last_console);
|
||||
break;
|
||||
case 16: /* set cursor blink duration in msec */
|
||||
if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 &&
|
||||
vc->vc_par[1] <= USHRT_MAX)
|
||||
vc->vc_cur_blink_ms = vc->vc_par[1];
|
||||
else
|
||||
vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1717,6 +1728,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
|
||||
|
||||
vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
|
||||
vc->vc_bell_duration = DEFAULT_BELL_DURATION;
|
||||
vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
|
||||
|
||||
gotoxy(vc, 0, 0);
|
||||
save_cur(vc);
|
||||
@ -3192,22 +3204,6 @@ err:
|
||||
|
||||
|
||||
#ifdef CONFIG_VT_HW_CONSOLE_BINDING
|
||||
static int con_is_graphics(const struct consw *csw, int first, int last)
|
||||
{
|
||||
int i, retval = 0;
|
||||
|
||||
for (i = first; i <= last; i++) {
|
||||
struct vc_data *vc = vc_cons[i].d;
|
||||
|
||||
if (vc && vc->vc_mode == KD_GRAPHICS) {
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* unlocked version of unbind_con_driver() */
|
||||
int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
|
||||
{
|
||||
@ -3293,8 +3289,7 @@ static int vt_bind(struct con_driver *con)
|
||||
const struct consw *defcsw = NULL, *csw = NULL;
|
||||
int i, more = 1, first = -1, last = -1, deflt = 0;
|
||||
|
||||
if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
|
||||
con_is_graphics(con->con, con->first, con->last))
|
||||
if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
|
||||
goto err;
|
||||
|
||||
csw = con->con;
|
||||
@ -3345,8 +3340,7 @@ static int vt_unbind(struct con_driver *con)
|
||||
int i, more = 1, first = -1, last = -1, deflt = 0;
|
||||
int ret;
|
||||
|
||||
if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
|
||||
con_is_graphics(con->con, con->first, con->last))
|
||||
if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
|
||||
goto err;
|
||||
|
||||
csw = con->con;
|
||||
@ -3596,7 +3590,8 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
|
||||
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
|
||||
con_driver = ®istered_con_driver[i];
|
||||
|
||||
if (con_driver->con == NULL) {
|
||||
if (con_driver->con == NULL &&
|
||||
!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) {
|
||||
con_driver->con = csw;
|
||||
con_driver->desc = desc;
|
||||
con_driver->node = i;
|
||||
@ -3658,16 +3653,20 @@ int do_unregister_con_driver(const struct consw *csw)
|
||||
struct con_driver *con_driver = ®istered_con_driver[i];
|
||||
|
||||
if (con_driver->con == csw) {
|
||||
vtconsole_deinit_device(con_driver);
|
||||
device_destroy(vtconsole_class,
|
||||
MKDEV(0, con_driver->node));
|
||||
/*
|
||||
* Defer the removal of the sysfs entries since that
|
||||
* will acquire the kernfs s_active lock and we can't
|
||||
* acquire this lock while holding the console lock:
|
||||
* the unbind sysfs entry imposes already the opposite
|
||||
* order. Reset con already here to prevent any later
|
||||
* lookup to succeed and mark this slot as zombie, so
|
||||
* it won't get reused until we complete the removal
|
||||
* in the deferred work.
|
||||
*/
|
||||
con_driver->con = NULL;
|
||||
con_driver->desc = NULL;
|
||||
con_driver->dev = NULL;
|
||||
con_driver->node = 0;
|
||||
con_driver->flag = 0;
|
||||
con_driver->first = 0;
|
||||
con_driver->last = 0;
|
||||
con_driver->flag = CON_DRIVER_FLAG_ZOMBIE;
|
||||
schedule_work(&con_driver_unregister_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -3676,6 +3675,39 @@ int do_unregister_con_driver(const struct consw *csw)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(do_unregister_con_driver);
|
||||
|
||||
static void con_driver_unregister_callback(struct work_struct *ignored)
|
||||
{
|
||||
int i;
|
||||
|
||||
console_lock();
|
||||
|
||||
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
|
||||
struct con_driver *con_driver = ®istered_con_driver[i];
|
||||
|
||||
if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE))
|
||||
continue;
|
||||
|
||||
console_unlock();
|
||||
|
||||
vtconsole_deinit_device(con_driver);
|
||||
device_destroy(vtconsole_class, MKDEV(0, con_driver->node));
|
||||
|
||||
console_lock();
|
||||
|
||||
if (WARN_ON_ONCE(con_driver->con))
|
||||
con_driver->con = NULL;
|
||||
con_driver->desc = NULL;
|
||||
con_driver->dev = NULL;
|
||||
con_driver->node = 0;
|
||||
WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE);
|
||||
con_driver->flag = 0;
|
||||
con_driver->first = 0;
|
||||
con_driver->last = 0;
|
||||
}
|
||||
|
||||
console_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* If we support more console drivers, this function is used
|
||||
* when a driver wants to take over some existing consoles
|
||||
|
@ -402,7 +402,7 @@ static void cursor_timer_handler(unsigned long dev_addr)
|
||||
struct fbcon_ops *ops = info->fbcon_par;
|
||||
|
||||
queue_work(system_power_efficient_wq, &info->queue);
|
||||
mod_timer(&ops->cursor_timer, jiffies + HZ/5);
|
||||
mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
|
||||
}
|
||||
|
||||
static void fbcon_add_cursor_timer(struct fb_info *info)
|
||||
@ -417,7 +417,7 @@ static void fbcon_add_cursor_timer(struct fb_info *info)
|
||||
|
||||
init_timer(&ops->cursor_timer);
|
||||
ops->cursor_timer.function = cursor_timer_handler;
|
||||
ops->cursor_timer.expires = jiffies + HZ / 5;
|
||||
ops->cursor_timer.expires = jiffies + ops->cur_blink_jiffies;
|
||||
ops->cursor_timer.data = (unsigned long ) info;
|
||||
add_timer(&ops->cursor_timer);
|
||||
ops->flags |= FBCON_FLAGS_CURSOR_TIMER;
|
||||
@ -1309,6 +1309,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
|
||||
if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
|
||||
return;
|
||||
|
||||
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
|
||||
if (vc->vc_cursor_type & 0x10)
|
||||
fbcon_del_cursor_timer(info);
|
||||
else
|
||||
|
@ -70,6 +70,7 @@ struct fbcon_ops {
|
||||
struct fb_cursor cursor_state;
|
||||
struct display *p;
|
||||
int currcon; /* Current VC. */
|
||||
int cur_blink_jiffies;
|
||||
int cursor_flash;
|
||||
int cursor_reset;
|
||||
int blank_state;
|
||||
|
@ -104,6 +104,7 @@ struct vc_data {
|
||||
unsigned int vc_resize_user; /* resize request from user */
|
||||
unsigned int vc_bell_pitch; /* Console bell pitch */
|
||||
unsigned int vc_bell_duration; /* Console bell duration */
|
||||
unsigned short vc_cur_blink_ms; /* Cursor blink duration */
|
||||
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
|
||||
struct uni_pagedir *vc_uni_pagedir;
|
||||
struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
|
||||
|
@ -529,6 +529,7 @@ enum rpm_request {
|
||||
};
|
||||
|
||||
struct wakeup_source;
|
||||
struct wake_irq;
|
||||
struct pm_domain_data;
|
||||
|
||||
struct pm_subsys_data {
|
||||
@ -568,6 +569,7 @@ struct dev_pm_info {
|
||||
unsigned long timer_expires;
|
||||
struct work_struct work;
|
||||
wait_queue_head_t wait_queue;
|
||||
struct wake_irq *wakeirq;
|
||||
atomic_t usage_count;
|
||||
atomic_t child_count;
|
||||
unsigned int disable_depth:3;
|
||||
|
52
include/linux/pm_wakeirq.h
Normal file
52
include/linux/pm_wakeirq.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* pm_wakeirq.h - Device wakeirq helper functions
|
||||
*
|
||||
* 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 "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_PM_WAKEIRQ_H
|
||||
#define _LINUX_PM_WAKEIRQ_H
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
extern int dev_pm_set_wake_irq(struct device *dev, int irq);
|
||||
extern int dev_pm_set_dedicated_wake_irq(struct device *dev,
|
||||
int irq);
|
||||
extern void dev_pm_clear_wake_irq(struct device *dev);
|
||||
extern void dev_pm_enable_wake_irq(struct device *dev);
|
||||
extern void dev_pm_disable_wake_irq(struct device *dev);
|
||||
|
||||
#else /* !CONFIG_PM */
|
||||
|
||||
static inline int dev_pm_set_wake_irq(struct device *dev, int irq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dev_pm_set_dedicated__wake_irq(struct device *dev,
|
||||
int irq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dev_pm_clear_wake_irq(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dev_pm_enable_wake_irq(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dev_pm_disable_wake_irq(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
#endif /* _LINUX_PM_WAKEIRQ_H */
|
@ -28,9 +28,17 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct wake_irq;
|
||||
|
||||
/**
|
||||
* struct wakeup_source - Representation of wakeup sources
|
||||
*
|
||||
* @name: Name of the wakeup source
|
||||
* @entry: Wakeup source list entry
|
||||
* @lock: Wakeup source lock
|
||||
* @wakeirq: Optional device specific wakeirq
|
||||
* @timer: Wakeup timer list
|
||||
* @timer_expires: Wakeup timer expiration
|
||||
* @total_time: Total time this wakeup source has been active.
|
||||
* @max_time: Maximum time this wakeup source has been continuously active.
|
||||
* @last_time: Monotonic clock when the wakeup source's was touched last time.
|
||||
@ -47,6 +55,7 @@ struct wakeup_source {
|
||||
const char *name;
|
||||
struct list_head entry;
|
||||
spinlock_t lock;
|
||||
struct wake_irq *wakeirq;
|
||||
struct timer_list timer;
|
||||
unsigned long timer_expires;
|
||||
ktime_t total_time;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define _LINUX_SERIAL_8250_H
|
||||
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
@ -137,6 +138,8 @@ extern int early_serial_setup(struct uart_port *port);
|
||||
|
||||
extern unsigned int serial8250_early_in(struct uart_port *port, int offset);
|
||||
extern void serial8250_early_out(struct uart_port *port, int offset, int value);
|
||||
extern int early_serial8250_setup(struct earlycon_device *device,
|
||||
const char *options);
|
||||
extern void serial8250_do_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios, struct ktermios *old);
|
||||
extern int serial8250_do_startup(struct uart_port *port);
|
||||
|
@ -35,7 +35,7 @@
|
||||
#define uart_console(port) \
|
||||
((port)->cons && (port)->cons->index == (port)->line)
|
||||
#else
|
||||
#define uart_console(port) (0)
|
||||
#define uart_console(port) ({ (void)port; 0; })
|
||||
#endif
|
||||
|
||||
struct uart_port;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef __LINUX_SERIAL_SCI_H
|
||||
#define __LINUX_SERIAL_SCI_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/sh_dma.h>
|
||||
|
||||
@ -10,59 +11,16 @@
|
||||
|
||||
#define SCIx_NOT_SUPPORTED (-1)
|
||||
|
||||
/* SCSMR (Serial Mode Register) */
|
||||
#define SCSMR_CHR (1 << 6) /* 7-bit Character Length */
|
||||
#define SCSMR_PE (1 << 5) /* Parity Enable */
|
||||
#define SCSMR_ODD (1 << 4) /* Odd Parity */
|
||||
#define SCSMR_STOP (1 << 3) /* Stop Bit Length */
|
||||
#define SCSMR_CKS 0x0003 /* Clock Select */
|
||||
|
||||
/* Serial Control Register (@ = not supported by all parts) */
|
||||
#define SCSCR_TIE (1 << 7) /* Transmit Interrupt Enable */
|
||||
#define SCSCR_RIE (1 << 6) /* Receive Interrupt Enable */
|
||||
#define SCSCR_TE (1 << 5) /* Transmit Enable */
|
||||
#define SCSCR_RE (1 << 4) /* Receive Enable */
|
||||
#define SCSCR_REIE (1 << 3) /* Receive Error Interrupt Enable @ */
|
||||
#define SCSCR_TOIE (1 << 2) /* Timeout Interrupt Enable @ */
|
||||
#define SCSCR_CKE1 (1 << 1) /* Clock Enable 1 */
|
||||
#define SCSCR_CKE0 (1 << 0) /* Clock Enable 0 */
|
||||
/* SCIFA/SCIFB only */
|
||||
#define SCSCR_TDRQE (1 << 15) /* Tx Data Transfer Request Enable */
|
||||
#define SCSCR_RDRQE (1 << 14) /* Rx Data Transfer Request Enable */
|
||||
#define SCSCR_TIE BIT(7) /* Transmit Interrupt Enable */
|
||||
#define SCSCR_RIE BIT(6) /* Receive Interrupt Enable */
|
||||
#define SCSCR_TE BIT(5) /* Transmit Enable */
|
||||
#define SCSCR_RE BIT(4) /* Receive Enable */
|
||||
#define SCSCR_REIE BIT(3) /* Receive Error Interrupt Enable @ */
|
||||
#define SCSCR_TOIE BIT(2) /* Timeout Interrupt Enable @ */
|
||||
#define SCSCR_CKE1 BIT(1) /* Clock Enable 1 */
|
||||
#define SCSCR_CKE0 BIT(0) /* Clock Enable 0 */
|
||||
|
||||
/* SCxSR (Serial Status Register) on SCI */
|
||||
#define SCI_TDRE 0x80 /* Transmit Data Register Empty */
|
||||
#define SCI_RDRF 0x40 /* Receive Data Register Full */
|
||||
#define SCI_ORER 0x20 /* Overrun Error */
|
||||
#define SCI_FER 0x10 /* Framing Error */
|
||||
#define SCI_PER 0x08 /* Parity Error */
|
||||
#define SCI_TEND 0x04 /* Transmit End */
|
||||
|
||||
#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
|
||||
|
||||
/* SCxSR (Serial Status Register) on SCIF, HSCIF */
|
||||
#define SCIF_ER 0x0080 /* Receive Error */
|
||||
#define SCIF_TEND 0x0040 /* Transmission End */
|
||||
#define SCIF_TDFE 0x0020 /* Transmit FIFO Data Empty */
|
||||
#define SCIF_BRK 0x0010 /* Break Detect */
|
||||
#define SCIF_FER 0x0008 /* Framing Error */
|
||||
#define SCIF_PER 0x0004 /* Parity Error */
|
||||
#define SCIF_RDF 0x0002 /* Receive FIFO Data Full */
|
||||
#define SCIF_DR 0x0001 /* Receive Data Ready */
|
||||
|
||||
#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
|
||||
|
||||
/* SCFCR (FIFO Control Register) */
|
||||
#define SCFCR_LOOP (1 << 0) /* Loopback Test */
|
||||
|
||||
/* SCSPTR (Serial Port Register), optional */
|
||||
#define SCSPTR_RTSIO (1 << 7) /* Serial Port RTS Pin Input/Output */
|
||||
#define SCSPTR_CTSIO (1 << 5) /* Serial Port CTS Pin Input/Output */
|
||||
#define SCSPTR_SPB2IO (1 << 1) /* Serial Port Break Input/Output */
|
||||
#define SCSPTR_SPB2DT (1 << 0) /* Serial Port Break Data */
|
||||
|
||||
/* HSSRR HSCIF */
|
||||
#define HSCIF_SRE 0x8000 /* Sampling Rate Register Enable */
|
||||
|
||||
enum {
|
||||
SCIx_PROBE_REGTYPE,
|
||||
@ -82,28 +40,6 @@ enum {
|
||||
SCIx_NR_REGTYPES,
|
||||
};
|
||||
|
||||
/*
|
||||
* SCI register subset common for all port types.
|
||||
* Not all registers will exist on all parts.
|
||||
*/
|
||||
enum {
|
||||
SCSMR, /* Serial Mode Register */
|
||||
SCBRR, /* Bit Rate Register */
|
||||
SCSCR, /* Serial Control Register */
|
||||
SCxSR, /* Serial Status Register */
|
||||
SCFCR, /* FIFO Control Register */
|
||||
SCFDR, /* FIFO Data Count Register */
|
||||
SCxTDR, /* Transmit (FIFO) Data Register */
|
||||
SCxRDR, /* Receive (FIFO) Data Register */
|
||||
SCLSR, /* Line Status Register */
|
||||
SCTFDR, /* Transmit FIFO Data Count Register */
|
||||
SCRFDR, /* Receive FIFO Data Count Register */
|
||||
SCSPTR, /* Serial Port Register */
|
||||
HSSRR, /* Sampling Rate Register */
|
||||
|
||||
SCIx_NR_REGS,
|
||||
};
|
||||
|
||||
struct device;
|
||||
|
||||
struct plat_sci_port_ops {
|
||||
@ -113,7 +49,7 @@ struct plat_sci_port_ops {
|
||||
/*
|
||||
* Port-specific capabilities
|
||||
*/
|
||||
#define SCIx_HAVE_RTSCTS (1 << 0)
|
||||
#define SCIx_HAVE_RTSCTS BIT(0)
|
||||
|
||||
/*
|
||||
* Platform device specific platform_data struct
|
||||
|
@ -422,7 +422,7 @@ static inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
|
||||
|
||||
extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
|
||||
const char *routine);
|
||||
extern char *tty_name(struct tty_struct *tty, char *buf);
|
||||
extern const char *tty_name(const struct tty_struct *tty);
|
||||
extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
|
||||
extern int tty_check_change(struct tty_struct *tty);
|
||||
extern void __stop_tty(struct tty_struct *tty);
|
||||
|
@ -138,6 +138,7 @@ header-y += genetlink.h
|
||||
header-y += gen_stats.h
|
||||
header-y += gfs2_ondisk.h
|
||||
header-y += gigaset_dev.h
|
||||
header-y += gsmmux.h
|
||||
header-y += hdlcdrv.h
|
||||
header-y += hdlc.h
|
||||
header-y += hdreg.h
|
||||
|
@ -1,6 +1,9 @@
|
||||
#ifndef _LINUX_GSMMUX_H
|
||||
#define _LINUX_GSMMUX_H
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
struct gsm_config
|
||||
{
|
||||
unsigned int adaption;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user