mirror of
https://github.com/torvalds/linux.git
synced 2026-03-07 23:04:33 +01:00
TTY / Serial driver updates for 7.0-rc1
Here is the small amount of tty and serial driver updates for 7.0-rc1.
Nothing major in here at all, just some driver updates and minor tweaks
and cleanups including:
- sh-sci serial driver updates
- 8250 driver updates
- attempt to make the tty ports have their own workqueue, but was
reverted after testing found it to have problems on some platforms.
This will probably come back for 7.1 after it has been reworked and
resubmitted
- other tiny tty driver changes
All of these have been in linux-next for a while with no reported
problems.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-----BEGIN PGP SIGNATURE-----
iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCaZR1VQ8cZ3JlZ0Brcm9h
aC5jb20ACgkQMUfUDdst+ykfsACghiyMgr0XKVDFEpV7/fPzocKH+o0An3v8knSi
kLz/f6LstVsISqCxeT+9
=uozB
-----END PGP SIGNATURE-----
Merge tag 'tty-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty / serial driver updates from Greg KH:
"Here is the small amount of tty and serial driver updates for 7.0-rc1.
Nothing major in here at all, just some driver updates and minor
tweaks and cleanups including:
- sh-sci serial driver updates
- 8250 driver updates
- attempt to make the tty ports have their own workqueue, but was
reverted after testing found it to have problems on some platforms.
This will probably come back for 7.1 after it has been reworked and
resubmitted
- other tiny tty driver changes
All of these have been in linux-next for a while with no reported
problems"
* tag 'tty-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (49 commits)
Revert "tty: tty_port: add workqueue to flip TTY buffer"
tty: tty_port: add workqueue to flip TTY buffer
serial: 8250_pci: Remove custom deprecated baud setting routine
serial: 8250_omap: Remove custom deprecated baud setting routine
dt-bindings: serial: renesas,scif: Document RZ/G3L SoC
serial: 8250: omap: set out-of-band wakeup if wakeup pinctrl exists
tty: hvc-iucv: Remove KMSG_COMPONENT macro
dt-bindings: serial: google,goldfish-tty: Convert to DT schema
dt-bindings: serial: sh-sci: Fold single-entry compatibles into enum
serial: 8250: 8250_omap.c: Clear DMA RX running status only after DMA termination is done
serial: 8250: 8250_omap.c: Add support for handling UART error conditions
serial: SH_SCI: improve "DMA support" prompt
serial: Kconfig: fix ordering of entries for menu display
serial: 8250: fix ordering of entries for menu display
serial: imx: change SERIAL_IMX_CONSOLE to bool
8250_men_mcb: drop unneeded MODULE_ALIAS
serial: men_z135_uart: drop unneeded MODULE_ALIAS
dt-bindings: serial: renesas,rsci: Document RZ/V2H(P) and RZ/V2N SoCs
serial: rsci: Convert to FIELD_MODIFY()
dt-bindings: serial: 8250: add SpacemiT K3 UART compatible
...
This commit is contained in:
commit
3ad7945754
26 changed files with 801 additions and 419 deletions
|
|
@ -1,17 +0,0 @@
|
|||
Android Goldfish TTY
|
||||
|
||||
Android goldfish tty device generated by android emulator.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should contain "google,goldfish-tty" to match emulator
|
||||
- reg : <registers mapping>
|
||||
- interrupts : <interrupt mapping>
|
||||
|
||||
Example:
|
||||
|
||||
goldfish_tty@1f004000 {
|
||||
compatible = "google,goldfish-tty";
|
||||
reg = <0x1f004000 0x1000>;
|
||||
interrupts = <0xc>;
|
||||
};
|
||||
|
|
@ -160,6 +160,7 @@ properties:
|
|||
- enum:
|
||||
- mrvl,mmp-uart
|
||||
- spacemit,k1-uart
|
||||
- spacemit,k3-uart
|
||||
- const: intel,xscale-uart
|
||||
- items:
|
||||
- enum:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/serial/google,goldfish-tty.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Google Goldfish TTY
|
||||
|
||||
maintainers:
|
||||
- Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/serial/serial.yaml#
|
||||
|
||||
description:
|
||||
Android goldfish TTY device generated by Android emulator.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: google,goldfish-tty
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
serial@1f004000 {
|
||||
compatible = "google,goldfish-tty";
|
||||
reg = <0x1f004000 0x1000>;
|
||||
interrupts = <12>;
|
||||
};
|
||||
|
|
@ -10,46 +10,78 @@ maintainers:
|
|||
- Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
- Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: renesas,r9a09g087-rsci # RZ/N2H
|
||||
- const: renesas,r9a09g077-rsci # RZ/T2H
|
||||
- enum:
|
||||
- renesas,r9a09g047-rsci # RZ/G3E
|
||||
- renesas,r9a09g077-rsci # RZ/T2H
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r9a09g056-rsci # RZ/V2N
|
||||
- renesas,r9a09g057-rsci # RZ/V2H(P)
|
||||
- const: renesas,r9a09g047-rsci
|
||||
|
||||
- items:
|
||||
- const: renesas,r9a09g087-rsci # RZ/N2H
|
||||
- const: renesas,r9a09g077-rsci # RZ/T2H
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 4
|
||||
items:
|
||||
- description: Error interrupt
|
||||
- description: Receive buffer full interrupt
|
||||
- description: Transmit buffer empty interrupt
|
||||
- description: Transmit end interrupt
|
||||
- description: Active edge detection interrupt
|
||||
- description: Break field detection interrupt
|
||||
|
||||
interrupt-names:
|
||||
minItems: 4
|
||||
items:
|
||||
- const: eri
|
||||
- const: rxi
|
||||
- const: txi
|
||||
- const: tei
|
||||
- const: aed
|
||||
- const: bfd
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
maxItems: 6
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
oneOf:
|
||||
- items:
|
||||
- const: operation
|
||||
- const: bus
|
||||
- const: sck # optional external clock input
|
||||
|
||||
minItems: 2
|
||||
|
||||
- items:
|
||||
- const: pclk
|
||||
- const: tclk
|
||||
- const: tclk_div4
|
||||
- const: tclk_div16
|
||||
- const: tclk_div64
|
||||
- const: sck # optional external clock input
|
||||
|
||||
minItems: 5
|
||||
|
||||
resets:
|
||||
items:
|
||||
- const: operation
|
||||
- const: bus
|
||||
- const: sck # optional external clock input
|
||||
- description: Input for resetting the APB clock
|
||||
- description: Input for resetting TCLK
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: presetn
|
||||
- const: tresetn
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
|
@ -62,6 +94,57 @@ required:
|
|||
- clock-names
|
||||
- power-domains
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g077-rsci
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 4
|
||||
|
||||
interrupt-names:
|
||||
maxItems: 4
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
resets: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a09g047-rsci
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 6
|
||||
|
||||
interrupt-names:
|
||||
minItems: 6
|
||||
|
||||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
|
||||
clock-names:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
|
||||
required:
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -12,15 +12,16 @@ maintainers:
|
|||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- renesas,scif-r7s9210 # RZ/A2
|
||||
- renesas,scif-r9a07g044 # RZ/G2{L,LC}
|
||||
- renesas,scif-r9a09g057 # RZ/V2H(P)
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r7s72100 # RZ/A1H
|
||||
- const: renesas,scif # generic SCIF compatible UART
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r7s9210 # RZ/A2
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r8a7778 # R-Car M1
|
||||
|
|
@ -76,19 +77,14 @@ properties:
|
|||
- const: renesas,rcar-gen5-scif # R-Car Gen5
|
||||
- const: renesas,scif # generic SCIF compatible UART
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r9a07g044 # RZ/G2{L,LC}
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r9a07g043 # RZ/G2UL and RZ/Five
|
||||
- renesas,scif-r9a07g054 # RZ/V2L
|
||||
- renesas,scif-r9a08g045 # RZ/G3S
|
||||
- renesas,scif-r9a08g046 # RZ/G3L
|
||||
- const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback
|
||||
|
||||
- const: renesas,scif-r9a09g057 # RZ/V2H(P)
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r9a09g047 # RZ/G3E
|
||||
|
|
|
|||
|
|
@ -89,31 +89,7 @@ With the baud base set to 15625000 and the unsigned 16-bit UART_DIV_MAX
|
|||
limitation imposed by ``serial8250_get_baud_rate`` standard baud rates
|
||||
below 300bps become unavailable in the regular way, e.g. the rate of
|
||||
200bps requires the baud base to be divided by 78125 and that is beyond
|
||||
the unsigned 16-bit range. The historic spd_cust feature can still be
|
||||
used by encoding the values for, the prescaler, the oversampling rate
|
||||
and the clock divisor (DLM/DLL) as follows to obtain such rates if so
|
||||
required:
|
||||
|
||||
::
|
||||
|
||||
31 29 28 20 19 16 15 0
|
||||
+-----+-----------------+-------+-------------------------------+
|
||||
|0 0 0| CPR2:CPR | TCR | DLM:DLL |
|
||||
+-----+-----------------+-------+-------------------------------+
|
||||
|
||||
Use a value such encoded for the ``custom_divisor`` field along with the
|
||||
ASYNC_SPD_CUST flag set in the ``flags`` field in ``struct serial_struct``
|
||||
passed with the TIOCSSERIAL ioctl(2), such as with the setserial(8)
|
||||
utility and its ``divisor`` and ``spd_cust`` parameters, and then select
|
||||
the baud rate of 38400bps. Note that the value of 0 in TCR sets the
|
||||
oversampling rate to 16 and prescaler values below 1 in CPR2/CPR are
|
||||
clamped by the driver to 1.
|
||||
|
||||
For example the value of 0x1f4004e2 will set CPR2/CPR, TCR and DLM/DLL
|
||||
respectively to 0x1f4, 0x0 and 0x04e2, choosing the prescaler value,
|
||||
the oversampling rate and the clock divisor of 62.500, 16 and 1250
|
||||
respectively. These parameters will set the baud rate for the serial
|
||||
port to 62500000 / 62.500 / 1250 / 16 = 50bps.
|
||||
the unsigned 16-bit range.
|
||||
|
||||
Maciej W. Rozycki <macro@orcam.me.uk>
|
||||
|
||||
|
|
|
|||
|
|
@ -677,13 +677,6 @@ static const struct hci_uart_proto aml_hci_proto = {
|
|||
.dequeue = aml_dequeue,
|
||||
};
|
||||
|
||||
static void aml_device_driver_shutdown(struct device *dev)
|
||||
{
|
||||
struct aml_serdev *amldev = dev_get_drvdata(dev);
|
||||
|
||||
aml_power_off(amldev);
|
||||
}
|
||||
|
||||
static int aml_serdev_probe(struct serdev_device *serdev)
|
||||
{
|
||||
struct aml_serdev *amldev;
|
||||
|
|
@ -714,6 +707,13 @@ static void aml_serdev_remove(struct serdev_device *serdev)
|
|||
hci_uart_unregister_device(&amldev->serdev_hu);
|
||||
}
|
||||
|
||||
static void aml_serdev_shutdown(struct serdev_device *serdev)
|
||||
{
|
||||
struct aml_serdev *amldev = serdev_device_get_drvdata(serdev);
|
||||
|
||||
aml_power_off(amldev);
|
||||
}
|
||||
|
||||
static const struct aml_device_data data_w155s2 = {
|
||||
.iccm_offset = 256 * 1024,
|
||||
};
|
||||
|
|
@ -732,10 +732,10 @@ MODULE_DEVICE_TABLE(of, aml_bluetooth_of_match);
|
|||
static struct serdev_device_driver aml_serdev_driver = {
|
||||
.probe = aml_serdev_probe,
|
||||
.remove = aml_serdev_remove,
|
||||
.shutdown = aml_serdev_shutdown,
|
||||
.driver = {
|
||||
.name = "hci_uart_aml",
|
||||
.of_match_table = aml_bluetooth_of_match,
|
||||
.shutdown = aml_device_driver_shutdown,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2570,11 +2570,10 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
|||
hci_uart_unregister_device(&qcadev->serdev_hu);
|
||||
}
|
||||
|
||||
static void qca_serdev_shutdown(struct device *dev)
|
||||
static void qca_serdev_shutdown(struct serdev_device *serdev)
|
||||
{
|
||||
int ret;
|
||||
int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS);
|
||||
struct serdev_device *serdev = to_serdev_device(dev);
|
||||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||
struct hci_uart *hu = &qcadev->serdev_hu;
|
||||
struct hci_dev *hdev = hu->hdev;
|
||||
|
|
@ -2796,11 +2795,11 @@ static void hciqca_coredump(struct device *dev)
|
|||
static struct serdev_device_driver qca_serdev_driver = {
|
||||
.probe = qca_serdev_probe,
|
||||
.remove = qca_serdev_remove,
|
||||
.shutdown = qca_serdev_shutdown,
|
||||
.driver = {
|
||||
.name = "hci_uart_qca",
|
||||
.of_match_table = of_match_ptr(qca_bluetooth_of_match),
|
||||
.acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match),
|
||||
.shutdown = qca_serdev_shutdown,
|
||||
.pm = &qca_pm_ops,
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
.coredump = hciqca_coredump,
|
||||
|
|
|
|||
|
|
@ -380,9 +380,9 @@ static int ssam_serdev_setup(struct acpi_device *ssh, struct serdev_device *serd
|
|||
|
||||
/* -- Power management. ----------------------------------------------------- */
|
||||
|
||||
static void ssam_serial_hub_shutdown(struct device *dev)
|
||||
static void ssam_serial_hub_shutdown(struct serdev_device *serdev)
|
||||
{
|
||||
struct ssam_controller *c = dev_get_drvdata(dev);
|
||||
struct ssam_controller *c = dev_get_drvdata(&serdev->dev);
|
||||
int status;
|
||||
|
||||
/*
|
||||
|
|
@ -834,12 +834,12 @@ MODULE_DEVICE_TABLE(of, ssam_serial_hub_of_match);
|
|||
static struct serdev_device_driver ssam_serial_hub = {
|
||||
.probe = ssam_serial_hub_probe,
|
||||
.remove = ssam_serial_hub_remove,
|
||||
.shutdown = ssam_serial_hub_shutdown,
|
||||
.driver = {
|
||||
.name = "surface_serial_hub",
|
||||
.acpi_match_table = ACPI_PTR(ssam_serial_hub_acpi_match),
|
||||
.of_match_table = of_match_ptr(ssam_serial_hub_of_match),
|
||||
.pm = &ssam_serial_hub_pm_ops,
|
||||
.shutdown = ssam_serial_hub_shutdown,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@
|
|||
*
|
||||
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
|
||||
*/
|
||||
#define KMSG_COMPONENT "hvc_iucv"
|
||||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
#define pr_fmt(fmt) "hvc_iucv: " fmt
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -1344,7 +1343,7 @@ static int __init hvc_iucv_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT,
|
||||
hvc_iucv_buffer_cache = kmem_cache_create("hvc_iucv",
|
||||
sizeof(struct iucv_tty_buffer),
|
||||
0, 0, NULL);
|
||||
if (!hvc_iucv_buffer_cache) {
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ struct n_hdlc_buf_list {
|
|||
* @rx_buf_list: list of received frame buffers
|
||||
* @tx_free_buf_list: list unused transmit frame buffers
|
||||
* @rx_free_buf_list: list unused received frame buffers
|
||||
* @write_work: work struct for deferred frame transmission
|
||||
* @tty_for_write_work: pointer to tty instance used by the @write_work
|
||||
*/
|
||||
struct n_hdlc {
|
||||
bool tbusy;
|
||||
|
|
|
|||
|
|
@ -414,11 +414,21 @@ static void serdev_drv_remove(struct device *dev)
|
|||
sdrv->remove(to_serdev_device(dev));
|
||||
}
|
||||
|
||||
static void serdev_drv_shutdown(struct device *dev)
|
||||
{
|
||||
const struct serdev_device_driver *sdrv =
|
||||
to_serdev_device_driver(dev->driver);
|
||||
|
||||
if (dev->driver && sdrv->shutdown)
|
||||
sdrv->shutdown(to_serdev_device(dev));
|
||||
}
|
||||
|
||||
static const struct bus_type serdev_bus_type = {
|
||||
.name = "serial",
|
||||
.match = serdev_device_match,
|
||||
.probe = serdev_drv_probe,
|
||||
.remove = serdev_drv_remove,
|
||||
.shutdown = serdev_drv_shutdown,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -814,6 +824,14 @@ void serdev_controller_remove(struct serdev_controller *ctrl)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(serdev_controller_remove);
|
||||
|
||||
static void serdev_legacy_shutdown(struct serdev_device *serdev)
|
||||
{
|
||||
struct device *dev = &serdev->dev;
|
||||
struct device_driver *driver = dev->driver;
|
||||
|
||||
driver->shutdown(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* __serdev_device_driver_register() - Register client driver with serdev core
|
||||
* @sdrv: client driver to be associated with client-device.
|
||||
|
|
@ -830,6 +848,9 @@ int __serdev_device_driver_register(struct serdev_device_driver *sdrv, struct mo
|
|||
/* force drivers to async probe so I/O is possible in probe */
|
||||
sdrv->driver.probe_type = PROBE_PREFER_ASYNCHRONOUS;
|
||||
|
||||
if (!sdrv->shutdown && sdrv->driver.shutdown)
|
||||
sdrv->shutdown = serdev_legacy_shutdown;
|
||||
|
||||
return driver_register(&sdrv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__serdev_device_driver_register);
|
||||
|
|
|
|||
|
|
@ -643,6 +643,10 @@ static int dw8250_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = pm_runtime_set_active(dev);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "Failed to set the runtime suspend as active\n");
|
||||
|
||||
data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible");
|
||||
|
||||
data->pdata = device_get_match_data(p->dev);
|
||||
|
|
@ -685,7 +689,6 @@ static int dw8250_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
|
@ -741,19 +744,25 @@ static int dw8250_runtime_suspend(struct device *dev)
|
|||
|
||||
static int dw8250_runtime_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
clk_prepare_enable(data->pclk);
|
||||
ret = clk_prepare_enable(data->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_prepare_enable(data->clk);
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(data->pclk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dw8250_pm_ops = {
|
||||
SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
|
||||
RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
|
||||
};
|
||||
static _DEFINE_DEV_PM_OPS(dw8250_pm_ops, dw8250_suspend, dw8250_resume,
|
||||
dw8250_runtime_suspend, dw8250_runtime_resume,
|
||||
NULL);
|
||||
|
||||
static const struct dw8250_platform_data dw8250_dw_apb = {
|
||||
.usr_reg = DW_UART_USR,
|
||||
|
|
|
|||
|
|
@ -6,10 +6,18 @@
|
|||
*/
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/misc/keba.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
|
|
@ -43,6 +51,10 @@ enum kuart_mode {
|
|||
#define KUART_CAPABILITY_RS232 BIT(KUART_MODE_RS232)
|
||||
#define KUART_CAPABILITY_MASK GENMASK(3, 0)
|
||||
|
||||
/* registers for Indexed Control Register access in enhanced mode */
|
||||
#define KUART_EMODE_ICR_OFFSET UART_SCR
|
||||
#define KUART_EMODE_ICR_VALUE UART_LSR
|
||||
|
||||
/* Additional Control Register DTR line configuration */
|
||||
#define UART_ACR_DTRLC_MASK 0x18
|
||||
#define UART_ACR_DTRLC_COMPAT 0x00
|
||||
|
|
@ -90,13 +102,13 @@ static void kuart_dtr_line_config(struct uart_8250_port *up, u8 dtrlc)
|
|||
u8 acr;
|
||||
|
||||
/* set index register to 0 to access ACR register */
|
||||
serial_out(up, UART_SCR, UART_ACR);
|
||||
serial_out(up, KUART_EMODE_ICR_OFFSET, UART_ACR);
|
||||
|
||||
/* set value register to 0x10 writing DTR mode (1,0) */
|
||||
acr = serial_in(up, UART_LSR);
|
||||
acr = serial_in(up, KUART_EMODE_ICR_VALUE);
|
||||
acr &= ~UART_ACR_DTRLC_MASK;
|
||||
acr |= dtrlc;
|
||||
serial_out(up, UART_LSR, acr);
|
||||
serial_out(up, KUART_EMODE_ICR_VALUE, acr);
|
||||
}
|
||||
|
||||
static int kuart_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
|
|
@ -240,10 +252,9 @@ static int kuart_probe(struct auxiliary_device *auxdev,
|
|||
}
|
||||
|
||||
retval = serial8250_register_8250_port(&uart);
|
||||
if (retval < 0) {
|
||||
dev_err(&auxdev->dev, "UART registration failed!\n");
|
||||
return retval;
|
||||
}
|
||||
if (retval < 0)
|
||||
return dev_err_probe(&auxdev->dev, retval,
|
||||
"UART registration failed!\n");
|
||||
kuart->line = retval;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@
|
|||
#define MEN_UART3_MASK 0x04
|
||||
#define MEN_UART4_MASK 0x08
|
||||
|
||||
#define MEN_Z125_UARTS_AVAILABLE 0x01
|
||||
|
||||
#define MEN_Z025_MAX_UARTS 4
|
||||
#define MEN_UART_MEM_SIZE 0x10
|
||||
#define MEM_UART_REGISTER_SIZE 0x01
|
||||
|
|
@ -42,12 +40,10 @@
|
|||
|
||||
#define MEN_READ_REGISTER(addr) readb(addr)
|
||||
|
||||
#define MAX_PORTS 4
|
||||
|
||||
struct serial_8250_men_mcb_data {
|
||||
int num_ports;
|
||||
int line[MAX_PORTS];
|
||||
unsigned int offset[MAX_PORTS];
|
||||
int line[MEN_Z025_MAX_UARTS];
|
||||
unsigned int offset[MEN_Z025_MAX_UARTS];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -126,7 +122,7 @@ static int read_serial_data(struct mcb_device *mdev,
|
|||
if (res < 0)
|
||||
return res;
|
||||
|
||||
for (i = 0; i < MAX_PORTS; i++) {
|
||||
for (i = 0; i < MEN_Z025_MAX_UARTS; i++) {
|
||||
mask = 0x1 << i;
|
||||
switch (uarts_available & mask) {
|
||||
case MEN_UART1_MASK:
|
||||
|
|
@ -150,7 +146,7 @@ static int read_serial_data(struct mcb_device *mdev,
|
|||
}
|
||||
}
|
||||
|
||||
if (count <= 0 || count > MAX_PORTS) {
|
||||
if (count <= 0 || count > MEN_Z025_MAX_UARTS) {
|
||||
dev_err(&mdev->dev, "unexpected number of ports: %u\n",
|
||||
count);
|
||||
return -ENODEV;
|
||||
|
|
@ -268,7 +264,4 @@ module_mcb_driver(mcb_driver);
|
|||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("MEN 8250 UART driver");
|
||||
MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
|
||||
MODULE_ALIAS("mcb:16z125");
|
||||
MODULE_ALIAS("mcb:16z025");
|
||||
MODULE_ALIAS("mcb:16z057");
|
||||
MODULE_IMPORT_NS("MCB");
|
||||
|
|
|
|||
|
|
@ -100,6 +100,9 @@
|
|||
#define OMAP_UART_REV_52 0x0502
|
||||
#define OMAP_UART_REV_63 0x0603
|
||||
|
||||
/* Resume register */
|
||||
#define UART_OMAP_RESUME 0x0B
|
||||
|
||||
/* Interrupt Enable Register 2 */
|
||||
#define UART_OMAP_IER2 0x1B
|
||||
#define UART_OMAP_IER2_RHR_IT_DIS BIT(2)
|
||||
|
|
@ -119,7 +122,6 @@
|
|||
/* Timeout low and High */
|
||||
#define UART_OMAP_TO_L 0x26
|
||||
#define UART_OMAP_TO_H 0x27
|
||||
|
||||
struct omap8250_priv {
|
||||
void __iomem *membase;
|
||||
int line;
|
||||
|
|
@ -241,22 +243,6 @@ static void omap_8250_get_divisor(struct uart_port *port, unsigned int baud,
|
|||
unsigned int div_13, div_16;
|
||||
unsigned int abs_d13, abs_d16;
|
||||
|
||||
/*
|
||||
* Old custom speed handling.
|
||||
*/
|
||||
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
|
||||
priv->quot = port->custom_divisor & UART_DIV_MAX;
|
||||
/*
|
||||
* I assume that nobody is using this. But hey, if somebody
|
||||
* would like to specify the divisor _and_ the mode then the
|
||||
* driver is ready and waiting for it.
|
||||
*/
|
||||
if (port->custom_divisor & (1 << 16))
|
||||
priv->mdr1 = UART_OMAP_MDR1_13X_MODE;
|
||||
else
|
||||
priv->mdr1 = UART_OMAP_MDR1_16X_MODE;
|
||||
return;
|
||||
}
|
||||
div_13 = DIV_ROUND_CLOSEST(uartclk, 13 * baud);
|
||||
div_16 = DIV_ROUND_CLOSEST(uartclk, 16 * baud);
|
||||
|
||||
|
|
@ -929,7 +915,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
|
|||
goto out;
|
||||
|
||||
cookie = dma->rx_cookie;
|
||||
dma->rx_running = 0;
|
||||
|
||||
/* Re-enable RX FIFO interrupt now that transfer is complete */
|
||||
if (priv->habit & UART_HAS_RHR_IT_DIS) {
|
||||
|
|
@ -963,6 +948,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p)
|
|||
goto out;
|
||||
ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||
|
||||
dma->rx_running = 0;
|
||||
p->port.icount.rx += ret;
|
||||
p->port.icount.buf_overrun += count - ret;
|
||||
out:
|
||||
|
|
@ -1256,6 +1242,20 @@ static u16 omap_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status
|
|||
return status;
|
||||
}
|
||||
|
||||
static void am654_8250_handle_uart_errors(struct uart_8250_port *up, u8 iir, u16 status)
|
||||
{
|
||||
if (status & UART_LSR_OE) {
|
||||
serial8250_clear_and_reinit_fifos(up);
|
||||
serial_in(up, UART_LSR);
|
||||
serial_in(up, UART_OMAP_RESUME);
|
||||
} else {
|
||||
if (status & (UART_LSR_FE | UART_LSR_PE | UART_LSR_BI))
|
||||
serial_in(up, UART_RX);
|
||||
if (iir & UART_IIR_XOFF)
|
||||
serial_in(up, UART_IIR);
|
||||
}
|
||||
}
|
||||
|
||||
static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
|
||||
u16 status)
|
||||
{
|
||||
|
|
@ -1266,7 +1266,8 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
|
|||
* Queue a new transfer if FIFO has data.
|
||||
*/
|
||||
if ((status & (UART_LSR_DR | UART_LSR_BI)) &&
|
||||
(up->ier & UART_IER_RDI)) {
|
||||
(up->ier & UART_IER_RDI) && !(status & UART_LSR_OE)) {
|
||||
am654_8250_handle_uart_errors(up, iir, status);
|
||||
omap_8250_rx_dma(up);
|
||||
serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE);
|
||||
} else if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
|
||||
|
|
@ -1282,6 +1283,8 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
|
|||
serial_out(up, UART_OMAP_EFR2, 0x0);
|
||||
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
} else {
|
||||
am654_8250_handle_uart_errors(up, iir, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1363,6 +1366,8 @@ static int omap8250_select_wakeup_pinctrl(struct device *dev,
|
|||
if (!device_may_wakeup(dev))
|
||||
return 0;
|
||||
|
||||
device_set_out_band_wakeup(dev);
|
||||
|
||||
return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1205,60 +1205,49 @@ static unsigned int pci_oxsemi_tornado_get_divisor(struct uart_port *port,
|
|||
u8 tcr;
|
||||
int i;
|
||||
|
||||
/* Old custom speed handling. */
|
||||
if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
|
||||
unsigned int cust_div = port->custom_divisor;
|
||||
best_squot = quot_scale;
|
||||
for (i = 0; i < ARRAY_SIZE(p); i++) {
|
||||
unsigned int spre;
|
||||
unsigned int srem;
|
||||
u8 cp;
|
||||
u8 tc;
|
||||
|
||||
quot = cust_div & UART_DIV_MAX;
|
||||
tcr = (cust_div >> 16) & OXSEMI_TORNADO_TCR_MASK;
|
||||
cpr = (cust_div >> 20) & OXSEMI_TORNADO_CPR_MASK;
|
||||
if (cpr < OXSEMI_TORNADO_CPR_MIN)
|
||||
cpr = OXSEMI_TORNADO_CPR_DEF;
|
||||
} else {
|
||||
best_squot = quot_scale;
|
||||
for (i = 0; i < ARRAY_SIZE(p); i++) {
|
||||
unsigned int spre;
|
||||
unsigned int srem;
|
||||
u8 cp;
|
||||
u8 tc;
|
||||
tc = p[i][0];
|
||||
cp = p[i][1];
|
||||
spre = tc * cp;
|
||||
|
||||
tc = p[i][0];
|
||||
cp = p[i][1];
|
||||
spre = tc * cp;
|
||||
srem = sdiv % spre;
|
||||
if (srem > spre / 2)
|
||||
srem = spre - srem;
|
||||
squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre);
|
||||
|
||||
srem = sdiv % spre;
|
||||
if (srem > spre / 2)
|
||||
srem = spre - srem;
|
||||
squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre);
|
||||
|
||||
if (srem == 0) {
|
||||
tcr = tc;
|
||||
cpr = cp;
|
||||
quot = sdiv / spre;
|
||||
break;
|
||||
} else if (squot < best_squot) {
|
||||
best_squot = squot;
|
||||
tcr = tc;
|
||||
cpr = cp;
|
||||
quot = DIV_ROUND_CLOSEST(sdiv, spre);
|
||||
}
|
||||
if (srem == 0) {
|
||||
tcr = tc;
|
||||
cpr = cp;
|
||||
quot = sdiv / spre;
|
||||
break;
|
||||
} else if (squot < best_squot) {
|
||||
best_squot = squot;
|
||||
tcr = tc;
|
||||
cpr = cp;
|
||||
quot = DIV_ROUND_CLOSEST(sdiv, spre);
|
||||
}
|
||||
while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 &&
|
||||
quot % 2 == 0) {
|
||||
}
|
||||
while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 &&
|
||||
quot % 2 == 0) {
|
||||
quot >>= 1;
|
||||
tcr <<= 1;
|
||||
}
|
||||
while (quot > UART_DIV_MAX) {
|
||||
if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) {
|
||||
quot >>= 1;
|
||||
tcr <<= 1;
|
||||
}
|
||||
while (quot > UART_DIV_MAX) {
|
||||
if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) {
|
||||
quot >>= 1;
|
||||
tcr <<= 1;
|
||||
} else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) {
|
||||
quot >>= 1;
|
||||
cpr <<= 1;
|
||||
} else {
|
||||
quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK;
|
||||
cpr = OXSEMI_TORNADO_CPR_MASK;
|
||||
}
|
||||
} else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) {
|
||||
quot >>= 1;
|
||||
cpr <<= 1;
|
||||
} else {
|
||||
quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK;
|
||||
cpr = OXSEMI_TORNADO_CPR_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ config SERIAL_8250_DMA
|
|||
|
||||
config SERIAL_8250_PCILIB
|
||||
bool
|
||||
depends on SERIAL_8250 && PCI
|
||||
|
||||
config SERIAL_8250_PCI
|
||||
tristate "8250/16550 PCI device support"
|
||||
|
|
@ -205,6 +206,37 @@ config SERIAL_8250_EXTENDED
|
|||
kernel: saying N will just cause the configurator to skip all
|
||||
the questions about serial driver options. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_SHARE_IRQ
|
||||
bool "Support for sharing serial interrupts"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
help
|
||||
Some serial boards have hardware support which allows multiple dumb
|
||||
serial ports on the same board to share a single IRQ. To enable
|
||||
support for this in the serial driver, say Y here.
|
||||
|
||||
config SERIAL_8250_DETECT_IRQ
|
||||
bool "Autodetect IRQ on standard ports (unsafe)"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
help
|
||||
Say Y here if you want the kernel to try to guess which IRQ
|
||||
to use for your serial port.
|
||||
|
||||
This is considered unsafe; it is far better to configure the IRQ in
|
||||
a boot script using the setserial command.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_RSA
|
||||
bool "Support RSA serial ports"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
help
|
||||
Say Y here if you have a IODATA RSA-DV II/S ISA card and
|
||||
would like to use its >115kbps speeds.
|
||||
You will need to provide module parameter "probe_rsa", or boot-time
|
||||
parameter 8250.probe_rsa with I/O addresses of this card then.
|
||||
|
||||
If you don't have such card, or if unsure, say N.
|
||||
|
||||
config SERIAL_8250_MANY_PORTS
|
||||
bool "Support more than 4 legacy serial ports"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
|
|
@ -240,19 +272,6 @@ config SERIAL_8250_ACCENT
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called 8250_accent.
|
||||
|
||||
config SERIAL_8250_ASPEED_VUART
|
||||
tristate "Aspeed Virtual UART"
|
||||
depends on SERIAL_8250
|
||||
depends on OF
|
||||
depends on MFD_SYSCON
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
select REGMAP
|
||||
help
|
||||
If you want to use the virtual UART (VUART) device on Aspeed
|
||||
BMC platforms, enable this option. This enables the 16550A-
|
||||
compatible device on the local LPC bus, giving a UART device
|
||||
with no physical RS232 connections.
|
||||
|
||||
config SERIAL_8250_BOCA
|
||||
tristate "Support Boca cards"
|
||||
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
|
||||
|
|
@ -293,44 +312,23 @@ config SERIAL_8250_PCI1XXXX
|
|||
serial driver for the serial interface. This driver support
|
||||
will ensure to support baud rates upto 1.5Mpbs.
|
||||
|
||||
config SERIAL_8250_ASPEED_VUART
|
||||
tristate "Aspeed Virtual UART"
|
||||
depends on SERIAL_8250
|
||||
depends on OF
|
||||
depends on MFD_SYSCON
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
select REGMAP
|
||||
help
|
||||
If you want to use the virtual UART (VUART) device on Aspeed
|
||||
BMC platforms, enable this option. This enables the 16550A-
|
||||
compatible device on the local LPC bus, giving a UART device
|
||||
with no physical RS232 connections.
|
||||
|
||||
#
|
||||
# Misc. options/drivers.
|
||||
#
|
||||
|
||||
config SERIAL_8250_SHARE_IRQ
|
||||
bool "Support for sharing serial interrupts"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
help
|
||||
Some serial boards have hardware support which allows multiple dumb
|
||||
serial ports on the same board to share a single IRQ. To enable
|
||||
support for this in the serial driver, say Y here.
|
||||
|
||||
config SERIAL_8250_DETECT_IRQ
|
||||
bool "Autodetect IRQ on standard ports (unsafe)"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
help
|
||||
Say Y here if you want the kernel to try to guess which IRQ
|
||||
to use for your serial port.
|
||||
|
||||
This is considered unsafe; it is far better to configure the IRQ in
|
||||
a boot script using the setserial command.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_RSA
|
||||
bool "Support RSA serial ports"
|
||||
depends on SERIAL_8250_EXTENDED
|
||||
help
|
||||
Say Y here if you have a IODATA RSA-DV II/S ISA card and
|
||||
would like to use its >115kbps speeds.
|
||||
You will need to provide module parameter "probe_rsa", or boot-time
|
||||
parameter 8250.probe_rsa with I/O addresses of this card then.
|
||||
|
||||
If you don't have such card, or if unsure, say N.
|
||||
|
||||
config SERIAL_8250_DWLIB
|
||||
bool
|
||||
|
||||
config SERIAL_8250_ACORN
|
||||
tristate "Acorn expansion card serial port support"
|
||||
depends on ARCH_ACORN && SERIAL_8250
|
||||
|
|
@ -596,3 +594,6 @@ config SERIAL_OF_PLATFORM
|
|||
are probed through devicetree, including Open Firmware based
|
||||
PowerPC systems and embedded systems on architectures using the
|
||||
flattened device tree format.
|
||||
|
||||
config SERIAL_8250_DWLIB
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -413,6 +413,10 @@ config SERIAL_21285_CONSOLE
|
|||
your boot loader (lilo or loadlin) about how to pass options to the
|
||||
kernel at boot time.)
|
||||
|
||||
config SERIAL_PXA_NON8250
|
||||
bool
|
||||
depends on !SERIAL_8250 || COMPILE_TEST
|
||||
|
||||
config SERIAL_PXA
|
||||
bool "PXA serial port support (DEPRECATED)"
|
||||
depends on ARCH_PXA || ARCH_MMP
|
||||
|
|
@ -426,10 +430,6 @@ config SERIAL_PXA
|
|||
Unless you have a specific need, you should use SERIAL_8250_PXA
|
||||
instead of this.
|
||||
|
||||
config SERIAL_PXA_NON8250
|
||||
bool
|
||||
depends on !SERIAL_8250 || COMPILE_TEST
|
||||
|
||||
config SERIAL_PXA_CONSOLE
|
||||
bool "Console on PXA serial port (DEPRECATED)"
|
||||
depends on SERIAL_PXA
|
||||
|
|
@ -486,14 +486,14 @@ config SERIAL_IMX
|
|||
can enable its onboard serial port by enabling this option.
|
||||
|
||||
config SERIAL_IMX_CONSOLE
|
||||
tristate "Console on IMX serial port"
|
||||
bool "Console on IMX serial port"
|
||||
depends on SERIAL_IMX
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
If you have enabled the serial port on the Freescale IMX
|
||||
CPU you can make it the console by answering Y/M to this option.
|
||||
CPU you can make it the console by answering Y to this option.
|
||||
|
||||
Even if you say Y/M here, the currently visible virtual console
|
||||
Even if you say Y here, the currently visible virtual console
|
||||
(/dev/tty0) will still be used as the system console by default, but
|
||||
you can alter that using a kernel command line option such as
|
||||
"console=ttymxc0". (Try "man bootparam" or see the documentation of
|
||||
|
|
@ -671,7 +671,7 @@ config SERIAL_SH_SCI_EARLYCON
|
|||
default ARCH_RENESAS
|
||||
|
||||
config SERIAL_SH_SCI_DMA
|
||||
bool "DMA support" if EXPERT
|
||||
bool "Support for DMA on SuperH SCI(F)" if EXPERT
|
||||
depends on SERIAL_SH_SCI && DMA_ENGINE
|
||||
default ARCH_RENESAS
|
||||
|
||||
|
|
@ -863,15 +863,15 @@ config SERIAL_ICOM
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called icom.
|
||||
|
||||
config HAS_TXX9_SERIAL
|
||||
bool
|
||||
|
||||
config SERIAL_TXX9
|
||||
bool "TMPTX39XX/49XX SIO support"
|
||||
depends on HAS_TXX9_SERIAL
|
||||
select SERIAL_CORE
|
||||
default y
|
||||
|
||||
config HAS_TXX9_SERIAL
|
||||
bool
|
||||
|
||||
config SERIAL_TXX9_NR_UARTS
|
||||
int "Maximum number of TMPTX39XX/49XX SIO ports"
|
||||
depends on SERIAL_TXX9
|
||||
|
|
@ -1251,12 +1251,6 @@ config SERIAL_AR933X_NR_UARTS
|
|||
Set this to the number of serial ports you want the driver
|
||||
to support.
|
||||
|
||||
config SERIAL_MPS2_UART_CONSOLE
|
||||
bool "MPS2 UART console support"
|
||||
depends on SERIAL_MPS2_UART
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
|
||||
config SERIAL_MPS2_UART
|
||||
bool "MPS2 UART port"
|
||||
depends on ARCH_MPS2 || COMPILE_TEST
|
||||
|
|
@ -1264,6 +1258,12 @@ config SERIAL_MPS2_UART
|
|||
help
|
||||
This driver support the UART ports on ARM MPS2.
|
||||
|
||||
config SERIAL_MPS2_UART_CONSOLE
|
||||
bool "MPS2 UART console support"
|
||||
depends on SERIAL_MPS2_UART
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
|
||||
config SERIAL_ARC
|
||||
tristate "ARC UART driver support"
|
||||
select SERIAL_CORE
|
||||
|
|
|
|||
|
|
@ -919,5 +919,4 @@ module_exit(men_z135_exit);
|
|||
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("MEN 16z135 High Speed UART");
|
||||
MODULE_ALIAS("mcb:16z135");
|
||||
MODULE_IMPORT_NS("MCB");
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_sci.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
#include "rsci.h"
|
||||
|
||||
MODULE_IMPORT_NS("SH_SCI");
|
||||
|
|
@ -24,7 +26,6 @@ MODULE_IMPORT_NS("SH_SCI");
|
|||
#define CCR3 0x14
|
||||
#define CCR4 0x18
|
||||
#define FCR 0x24
|
||||
#define DCR 0x30
|
||||
#define CSR 0x48
|
||||
#define FRSR 0x50
|
||||
#define FTSR 0x54
|
||||
|
|
@ -36,12 +37,6 @@ MODULE_IMPORT_NS("SH_SCI");
|
|||
#define RDR_FPER BIT(11) /* FIFO Parity Error */
|
||||
#define RDR_RDAT_MSK GENMASK(8, 0)
|
||||
|
||||
/* TDR (Transmit Data Register) */
|
||||
#define TDR_MPBT BIT(9) /* Multiprocessor Transfer */
|
||||
#define TDR_TDAT_9BIT_LSHIFT 0
|
||||
#define TDR_TDAT_9BIT_VAL 0x1FF
|
||||
#define TDR_TDAT_9BIT_MSK (TDR_TDAT_9BIT_VAL << TDR_TDAT_9BIT_LSHIFT)
|
||||
|
||||
/* CCR0 (Common Control Register 0) */
|
||||
#define CCR0_SSE BIT(24) /* SSn# Pin Function Enable */
|
||||
#define CCR0_TEIE BIT(21) /* Transmit End Interrupt Enable */
|
||||
|
|
@ -66,6 +61,41 @@ MODULE_IMPORT_NS("SH_SCI");
|
|||
#define CCR1_CTSPEN BIT(1) /* CTS External Pin Enable */
|
||||
#define CCR1_CTSE BIT(0) /* CTS Enable */
|
||||
|
||||
/* CCR2 (Common Control Register 2) */
|
||||
#define CCR2_INIT 0xFF000004
|
||||
#define CCR2_CKS_TCLK (0) /* TCLK clock */
|
||||
#define CCR2_CKS_TCLK_DIV4 BIT(20) /* TCLK/4 clock */
|
||||
#define CCR2_CKS_TCLK_DIV16 BIT(21) /* TCLK16 clock */
|
||||
#define CCR2_CKS_TCLK_DIV64 (BIT(21) | BIT(20)) /* TCLK/64 clock */
|
||||
#define CCR2_BRME BIT(16) /* Bitrate Modulation Enable */
|
||||
#define CCR2_ABCSE BIT(6) /* Asynchronous Mode Extended Base Clock Select */
|
||||
#define CCR2_ABCS BIT(5) /* Asynchronous Mode Base Clock Select */
|
||||
#define CCR2_BGDM BIT(4) /* Baud Rate Generator Double-Speed Mode Select */
|
||||
|
||||
/* CCR3 (Common Control Register 3) */
|
||||
#define CCR3_INIT 0x1203
|
||||
#define CCR3_BLK BIT(29) /* Block Transfer Mode */
|
||||
#define CCR3_GM BIT(28) /* GSM Mode */
|
||||
#define CCR3_CKE1 BIT(25) /* Clock Enable 1 */
|
||||
#define CCR3_CKE0 BIT(24) /* Clock Enable 0 */
|
||||
#define CCR3_DEN BIT(21) /* Driver Enabled */
|
||||
#define CCR3_FM BIT(20) /* FIFO Mode Select */
|
||||
#define CCR3_MP BIT(19) /* Multi-Processor Mode */
|
||||
#define CCR3_MOD_ASYNC 0 /* Asynchronous mode (Multi-processor mode) */
|
||||
#define CCR3_MOD_IRDA BIT(16) /* Smart card interface mode */
|
||||
#define CCR3_MOD_CLK_SYNC BIT(17) /* Clock synchronous mode */
|
||||
#define CCR3_MOD_SPI (BIT(17) | BIT(16)) /* Simple SPI mode */
|
||||
#define CCR3_MOD_I2C BIT(18) /* Simple I2C mode */
|
||||
#define CCR3_RXDESEL BIT(15) /* Asynchronous Start Bit Edge Detection Select */
|
||||
#define CCR3_STP BIT(14) /* Stop bit Length */
|
||||
#define CCR3_SINV BIT(13) /* Transmitted/Received Data Invert */
|
||||
#define CCR3_LSBF BIT(12) /* LSB First select */
|
||||
#define CCR3_CHR1 BIT(9) /* Character Length */
|
||||
#define CCR3_CHR0 BIT(8) /* Character Length */
|
||||
#define CCR3_BPEN BIT(7) /* Synchronizer Bypass Enable */
|
||||
#define CCR3_CPOL BIT(1) /* Clock Polarity Select */
|
||||
#define CCR3_CPHA BIT(0) /* Clock Phase Select */
|
||||
|
||||
/* FCR (FIFO Control Register) */
|
||||
#define FCR_RFRST BIT(23) /* Receive FIFO Data Register Reset */
|
||||
#define FCR_TFRST BIT(15) /* Transmit FIFO Data Register Reset */
|
||||
|
|
@ -119,8 +149,6 @@ MODULE_IMPORT_NS("SH_SCI");
|
|||
/* FFCLR (FIFO Flag CLear Register) */
|
||||
#define FFCLR_DRC BIT(0) /* DR Clear */
|
||||
|
||||
#define DCR_DEPOL BIT(0)
|
||||
|
||||
static u32 rsci_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
return readl(p->membase + offset);
|
||||
|
|
@ -137,10 +165,6 @@ static void rsci_clear_DRxC(struct uart_port *port)
|
|||
rsci_serial_out(port, FFCLR, FFCLR_DRC);
|
||||
}
|
||||
|
||||
static void rsci_clear_SCxSR(struct uart_port *port, unsigned int mask)
|
||||
{
|
||||
rsci_serial_out(port, CFCLR, mask);
|
||||
}
|
||||
|
||||
static void rsci_start_rx(struct uart_port *port)
|
||||
{
|
||||
|
|
@ -151,21 +175,160 @@ static void rsci_start_rx(struct uart_port *port)
|
|||
rsci_serial_out(port, CCR0, ctrl);
|
||||
}
|
||||
|
||||
static void rsci_enable_ms(struct uart_port *port)
|
||||
{
|
||||
mctrl_gpio_enable_ms(to_sci_port(port)->gpios);
|
||||
}
|
||||
|
||||
static void rsci_init_pins(struct uart_port *port, unsigned int cflag)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
/* Use port-specific handler if provided */
|
||||
if (s->cfg->ops && s->cfg->ops->init_pins) {
|
||||
s->cfg->ops->init_pins(port, cflag);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->has_rtscts)
|
||||
return;
|
||||
|
||||
if (s->autorts)
|
||||
rsci_serial_out(port, CCR1, rsci_serial_in(port, CCR1) |
|
||||
CCR1_CTSE | CCR1_CTSPEN);
|
||||
}
|
||||
|
||||
static int rsci_scif_set_rtrg(struct uart_port *port, int rx_trig)
|
||||
{
|
||||
u32 fcr = rsci_serial_in(port, FCR);
|
||||
|
||||
if (rx_trig >= port->fifosize)
|
||||
rx_trig = port->fifosize - 1;
|
||||
else if (rx_trig < 1)
|
||||
rx_trig = 0;
|
||||
|
||||
FIELD_MODIFY(FCR_RTRG4_0, &fcr, rx_trig);
|
||||
rsci_serial_out(port, FCR, fcr);
|
||||
|
||||
return rx_trig;
|
||||
}
|
||||
|
||||
static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
const struct ktermios *old)
|
||||
{
|
||||
unsigned int ccr2_val = CCR2_INIT, ccr3_val = CCR3_INIT;
|
||||
unsigned int ccr0_val = 0, ccr1_val = 0, ccr4_val = 0;
|
||||
unsigned int brr1 = 255, cks1 = 0, srr1 = 15;
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
unsigned int brr = 255, cks = 0;
|
||||
int min_err = INT_MAX, err;
|
||||
unsigned long max_freq = 0;
|
||||
unsigned int baud, i;
|
||||
unsigned long flags;
|
||||
unsigned int ctrl;
|
||||
int best_clk = -1;
|
||||
|
||||
if ((termios->c_cflag & CSIZE) == CS7) {
|
||||
ccr3_val |= CCR3_CHR0;
|
||||
} else {
|
||||
termios->c_cflag &= ~CSIZE;
|
||||
termios->c_cflag |= CS8;
|
||||
}
|
||||
|
||||
if (termios->c_cflag & PARENB)
|
||||
ccr1_val |= CCR1_PE;
|
||||
|
||||
if (termios->c_cflag & PARODD)
|
||||
ccr1_val |= (CCR1_PE | CCR1_PM);
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
ccr3_val |= CCR3_STP;
|
||||
|
||||
/* Enable noise filter function */
|
||||
ccr1_val |= CCR1_NFEN;
|
||||
|
||||
/*
|
||||
* earlyprintk comes here early on with port->uartclk set to zero.
|
||||
* the clock framework is not up and running at this point so here
|
||||
* we assume that 115200 is the maximum baud rate. please note that
|
||||
* the baud rate is not programmed during earlyprintk - it is assumed
|
||||
* that the previous boot loader has enabled required clocks and
|
||||
* setup the baud rate generator hardware for us already.
|
||||
*/
|
||||
if (!port->uartclk) {
|
||||
max_freq = 115200;
|
||||
} else {
|
||||
for (i = 0; i < SCI_NUM_CLKS; i++)
|
||||
max_freq = max(max_freq, s->clk_rates[i]);
|
||||
|
||||
max_freq /= min_sr(s);
|
||||
}
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, max_freq);
|
||||
if (!baud)
|
||||
goto done;
|
||||
|
||||
/* Divided Functional Clock using standard Bit Rate Register */
|
||||
err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
|
||||
if (abs(err) < abs(min_err)) {
|
||||
best_clk = SCI_FCK;
|
||||
ccr0_val = 0;
|
||||
min_err = err;
|
||||
brr = brr1;
|
||||
cks = cks1;
|
||||
}
|
||||
|
||||
done:
|
||||
if (best_clk >= 0)
|
||||
dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
|
||||
s->clks[best_clk], baud, min_err);
|
||||
|
||||
sci_port_enable(s);
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
||||
/* For now, only RX enabling is supported */
|
||||
if (termios->c_cflag & CREAD)
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
rsci_serial_out(port, CCR0, ccr0_val);
|
||||
|
||||
ccr3_val |= CCR3_FM;
|
||||
rsci_serial_out(port, CCR3, ccr3_val);
|
||||
|
||||
ccr2_val |= (cks << 20) | (brr << 8);
|
||||
rsci_serial_out(port, CCR2, ccr2_val);
|
||||
|
||||
rsci_serial_out(port, CCR1, ccr1_val);
|
||||
rsci_serial_out(port, CCR4, ccr4_val);
|
||||
|
||||
ctrl = rsci_serial_in(port, FCR);
|
||||
ctrl |= (FCR_RFRST | FCR_TFRST);
|
||||
rsci_serial_out(port, FCR, ctrl);
|
||||
|
||||
if (s->rx_trigger > 1)
|
||||
rsci_scif_set_rtrg(port, s->rx_trigger);
|
||||
|
||||
port->status &= ~UPSTAT_AUTOCTS;
|
||||
s->autorts = false;
|
||||
|
||||
if ((port->flags & UPF_HARD_FLOW) && (termios->c_cflag & CRTSCTS)) {
|
||||
port->status |= UPSTAT_AUTOCTS;
|
||||
s->autorts = true;
|
||||
}
|
||||
|
||||
rsci_init_pins(port, termios->c_cflag);
|
||||
rsci_serial_out(port, CFCLR, CFCLR_CLRFLAG);
|
||||
rsci_serial_out(port, FFCLR, FFCLR_DRC);
|
||||
|
||||
ccr0_val |= CCR0_RE;
|
||||
rsci_serial_out(port, CCR0, ccr0_val);
|
||||
|
||||
if ((termios->c_cflag & CREAD) != 0)
|
||||
rsci_start_rx(port);
|
||||
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
sci_port_disable(s);
|
||||
|
||||
if (UART_ENABLE_MS(port, termios->c_cflag))
|
||||
rsci_enable_ms(port);
|
||||
}
|
||||
|
||||
static int rsci_txfill(struct uart_port *port)
|
||||
|
|
@ -190,13 +353,34 @@ static unsigned int rsci_tx_empty(struct uart_port *port)
|
|||
|
||||
static void rsci_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* Not supported yet */
|
||||
if (mctrl & TIOCM_LOOP) {
|
||||
/* Standard loopback mode */
|
||||
rsci_serial_out(port, CCR1, rsci_serial_in(port, CCR1) | CCR1_SPLP);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int rsci_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
/* Not supported yet */
|
||||
return 0;
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
struct mctrl_gpios *gpios = s->gpios;
|
||||
unsigned int mctrl = 0;
|
||||
|
||||
mctrl_gpio_get(gpios, &mctrl);
|
||||
|
||||
/*
|
||||
* CTS/RTS is handled in hardware when supported, while nothing
|
||||
* else is wired up.
|
||||
*/
|
||||
if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))
|
||||
mctrl |= TIOCM_CTS;
|
||||
|
||||
if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR))
|
||||
mctrl |= TIOCM_DSR;
|
||||
|
||||
if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD))
|
||||
mctrl |= TIOCM_CAR;
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
static void rsci_clear_CFC(struct uart_port *port, unsigned int mask)
|
||||
|
|
@ -326,7 +510,8 @@ static void rsci_receive_chars(struct uart_port *port)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Store data and status.
|
||||
/*
|
||||
* Store data and status.
|
||||
* Non FIFO mode is not supported
|
||||
*/
|
||||
if (rdat & RDR_FFER) {
|
||||
|
|
@ -360,6 +545,28 @@ static void rsci_receive_chars(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
static void rsci_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
unsigned short ccr0_val, ccr1_val;
|
||||
unsigned long flags;
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
ccr1_val = rsci_serial_in(port, CCR1);
|
||||
ccr0_val = rsci_serial_in(port, CCR0);
|
||||
|
||||
if (break_state == -1) {
|
||||
ccr1_val = (ccr1_val | CCR1_SPB2IO) & ~CCR1_SPB2DT;
|
||||
ccr0_val &= ~CCR0_TE;
|
||||
} else {
|
||||
ccr1_val = (ccr1_val | CCR1_SPB2DT) & ~CCR1_SPB2IO;
|
||||
ccr0_val |= CCR0_TE;
|
||||
}
|
||||
|
||||
rsci_serial_out(port, CCR1, ccr1_val);
|
||||
rsci_serial_out(port, CCR0, ccr0_val);
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
}
|
||||
|
||||
static void rsci_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
u32 status;
|
||||
|
|
@ -375,18 +582,27 @@ static void rsci_poll_put_char(struct uart_port *port, unsigned char c)
|
|||
}
|
||||
rsci_serial_out(port, TDR, c);
|
||||
done:
|
||||
rsci_clear_SCxSR(port, CFCLR_TDREC);
|
||||
rsci_clear_CFC(port, CFCLR_TDREC);
|
||||
}
|
||||
|
||||
static void rsci_prepare_console_write(struct uart_port *port, u32 ctrl)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
u32 ctrl_temp =
|
||||
s->params->param_bits->rxtx_enable | CCR0_TIE |
|
||||
s->hscif_tot;
|
||||
u32 ctrl_temp = s->params->param_bits->rxtx_enable;
|
||||
|
||||
if (s->type == RSCI_PORT_SCIF16)
|
||||
ctrl_temp |= CCR0_TIE | s->hscif_tot;
|
||||
|
||||
rsci_serial_out(port, CCR0, ctrl_temp);
|
||||
}
|
||||
|
||||
static void rsci_finish_console_write(struct uart_port *port, u32 ctrl)
|
||||
{
|
||||
/* First set TE = 0 and then restore the CCR0 value */
|
||||
rsci_serial_out(port, CCR0, ctrl & ~CCR0_TE);
|
||||
rsci_serial_out(port, CCR0, ctrl);
|
||||
}
|
||||
|
||||
static const char *rsci_type(struct uart_port *port)
|
||||
{
|
||||
return "rsci";
|
||||
|
|
@ -416,7 +632,18 @@ static const struct sci_port_params_bits rsci_port_param_bits = {
|
|||
.poll_sent_bits = CSR_TDRE | CSR_TEND,
|
||||
};
|
||||
|
||||
static const struct sci_port_params rsci_port_params = {
|
||||
static const struct sci_port_params rsci_rzg3e_port_params = {
|
||||
.fifosize = 32,
|
||||
.overrun_reg = CSR,
|
||||
.overrun_mask = CSR_ORER,
|
||||
.sampling_rate_mask = SCI_SR(32),
|
||||
.error_mask = RSCI_DEFAULT_ERROR_MASK,
|
||||
.error_clear = RSCI_ERROR_CLEAR,
|
||||
.param_bits = &rsci_port_param_bits,
|
||||
.common_regs = &rsci_common_regs,
|
||||
};
|
||||
|
||||
static const struct sci_port_params rsci_rzt2h_port_params = {
|
||||
.fifosize = 16,
|
||||
.overrun_reg = CSR,
|
||||
.overrun_mask = CSR_ORER,
|
||||
|
|
@ -434,6 +661,8 @@ static const struct uart_ops rsci_uart_ops = {
|
|||
.start_tx = rsci_start_tx,
|
||||
.stop_tx = rsci_stop_tx,
|
||||
.stop_rx = rsci_stop_rx,
|
||||
.enable_ms = rsci_enable_ms,
|
||||
.break_ctl = rsci_break_ctl,
|
||||
.startup = sci_startup,
|
||||
.shutdown = sci_shutdown,
|
||||
.set_termios = rsci_set_termios,
|
||||
|
|
@ -448,31 +677,47 @@ static const struct uart_ops rsci_uart_ops = {
|
|||
static const struct sci_port_ops rsci_port_ops = {
|
||||
.read_reg = rsci_serial_in,
|
||||
.write_reg = rsci_serial_out,
|
||||
.clear_SCxSR = rsci_clear_SCxSR,
|
||||
.clear_SCxSR = rsci_clear_CFC,
|
||||
.transmit_chars = rsci_transmit_chars,
|
||||
.receive_chars = rsci_receive_chars,
|
||||
.poll_put_char = rsci_poll_put_char,
|
||||
.prepare_console_write = rsci_prepare_console_write,
|
||||
.finish_console_write = rsci_finish_console_write,
|
||||
.suspend_regs_size = rsci_suspend_regs_size,
|
||||
.set_rtrg = rsci_scif_set_rtrg,
|
||||
.shutdown_complete = rsci_shutdown_complete,
|
||||
};
|
||||
|
||||
struct sci_of_data of_sci_rsci_data = {
|
||||
.type = SCI_PORT_RSCI,
|
||||
struct sci_of_data of_rsci_rzg3e_data = {
|
||||
.type = RSCI_PORT_SCIF32,
|
||||
.ops = &rsci_port_ops,
|
||||
.uart_ops = &rsci_uart_ops,
|
||||
.params = &rsci_port_params,
|
||||
.params = &rsci_rzg3e_port_params,
|
||||
};
|
||||
|
||||
struct sci_of_data of_rsci_rzt2h_data = {
|
||||
.type = RSCI_PORT_SCIF16,
|
||||
.ops = &rsci_port_ops,
|
||||
.uart_ops = &rsci_uart_ops,
|
||||
.params = &rsci_rzt2h_port_params,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
|
||||
|
||||
static int __init rsci_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
static int __init rsci_rzg3e_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
return scix_early_console_setup(device, &of_sci_rsci_data);
|
||||
return scix_early_console_setup(device, &of_rsci_rzg3e_data);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_early_console_setup);
|
||||
static int __init rsci_rzt2h_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
return scix_early_console_setup(device, &of_rsci_rzt2h_data);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g047-rsci", rsci_rzg3e_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_rzt2h_early_console_setup);
|
||||
|
||||
#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "sh-sci-common.h"
|
||||
|
||||
extern struct sci_of_data of_sci_rsci_data;
|
||||
extern struct sci_of_data of_rsci_rzg3e_data;
|
||||
extern struct sci_of_data of_rsci_rzt2h_data;
|
||||
|
||||
#endif /* __RSCI_H__ */
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
/* Private port IDs */
|
||||
enum SCI_PORT_TYPE {
|
||||
SCI_PORT_RSCI = BIT(7) | 0,
|
||||
RSCI_PORT_SCIF16 = BIT(7) | 0,
|
||||
RSCI_PORT_SCIF32 = BIT(7) | 1,
|
||||
};
|
||||
|
||||
enum SCI_CLKS {
|
||||
|
|
@ -15,6 +16,9 @@ enum SCI_CLKS {
|
|||
SCI_SCK, /* Optional External Clock */
|
||||
SCI_BRG_INT, /* Optional BRG Internal Clock Source */
|
||||
SCI_SCIF_CLK, /* Optional BRG External Clock Source */
|
||||
SCI_FCK_DIV4, /* Optional Functional Clock frequency-divided by 4 */
|
||||
SCI_FCK_DIV16, /* Optional Functional Clock frequency-divided by 16 */
|
||||
SCI_FCK_DIV64, /* Optional Functional Clock frequency-divided by 64 */
|
||||
SCI_NUM_CLKS
|
||||
};
|
||||
|
||||
|
|
@ -89,6 +93,7 @@ struct sci_port_ops {
|
|||
void (*shutdown_complete)(struct uart_port *port);
|
||||
|
||||
void (*prepare_console_write)(struct uart_port *port, u32 ctrl);
|
||||
void (*finish_console_write)(struct uart_port *port, u32 ctrl);
|
||||
void (*console_save)(struct uart_port *port);
|
||||
void (*console_restore)(struct uart_port *port);
|
||||
size_t (*suspend_regs_size)(void);
|
||||
|
|
@ -165,6 +170,9 @@ void sci_port_enable(struct sci_port *sci_port);
|
|||
int sci_startup(struct uart_port *port);
|
||||
void sci_shutdown(struct uart_port *port);
|
||||
|
||||
int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr,
|
||||
unsigned int *srr, unsigned int *cks);
|
||||
|
||||
#define min_sr(_port) ffs((_port)->sampling_rate_mask)
|
||||
#define max_sr(_port) fls((_port)->sampling_rate_mask)
|
||||
|
||||
|
|
|
|||
|
|
@ -1182,6 +1182,11 @@ static int sci_handle_errors(struct uart_port *port)
|
|||
return copied;
|
||||
}
|
||||
|
||||
static bool sci_is_rsci_type(u8 type)
|
||||
{
|
||||
return (type == RSCI_PORT_SCIF16 || type == RSCI_PORT_SCIF32);
|
||||
}
|
||||
|
||||
static int sci_handle_fifo_overrun(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
|
@ -1190,7 +1195,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
|
|||
int copied = 0;
|
||||
u32 status;
|
||||
|
||||
if (s->type != SCI_PORT_RSCI) {
|
||||
if (!sci_is_rsci_type(s->type)) {
|
||||
reg = sci_getreg(port, s->params->overrun_reg);
|
||||
if (!reg->size)
|
||||
return 0;
|
||||
|
|
@ -1198,7 +1203,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
|
|||
|
||||
status = s->ops->read_reg(port, s->params->overrun_reg);
|
||||
if (status & s->params->overrun_mask) {
|
||||
if (s->type == SCI_PORT_RSCI) {
|
||||
if (sci_is_rsci_type(s->type)) {
|
||||
/*
|
||||
* All of the CFCLR_*C clearing bits match the corresponding
|
||||
* CSR_*status bits. So, reuse the overrun mask for clearing.
|
||||
|
|
@ -2015,7 +2020,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
|
|||
unsigned long flags;
|
||||
u32 ctrl;
|
||||
|
||||
if (s->type != PORT_SCI && s->type != SCI_PORT_RSCI)
|
||||
if (s->type != PORT_SCI && !sci_is_rsci_type(s->type))
|
||||
return sci_tx_interrupt(irq, ptr);
|
||||
|
||||
uart_port_lock_irqsave(port, &flags);
|
||||
|
|
@ -2568,9 +2573,8 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
|
|||
}
|
||||
|
||||
/* calculate sample rate, BRR, and clock select */
|
||||
static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
|
||||
unsigned int *brr, unsigned int *srr,
|
||||
unsigned int *cks)
|
||||
int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr,
|
||||
unsigned int *srr, unsigned int *cks)
|
||||
{
|
||||
unsigned long freq = s->clk_rates[SCI_FCK];
|
||||
unsigned int sr, br, prediv, scrate, c;
|
||||
|
|
@ -2634,6 +2638,7 @@ found:
|
|||
min_err, *brr, *srr + 1, *cks);
|
||||
return min_err;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(sci_scbrr_calc, "SH_SCI");
|
||||
|
||||
static void sci_reset(struct uart_port *port)
|
||||
{
|
||||
|
|
@ -3167,15 +3172,21 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
|
|||
[SCI_SCK] = "sck",
|
||||
[SCI_BRG_INT] = "brg_int",
|
||||
[SCI_SCIF_CLK] = "scif_clk",
|
||||
[SCI_FCK_DIV4] = "tclk_div4",
|
||||
[SCI_FCK_DIV16] = "tclk_div16",
|
||||
[SCI_FCK_DIV64] = "tclk_div64",
|
||||
};
|
||||
struct clk *clk;
|
||||
unsigned int i;
|
||||
|
||||
if (sci_port->type == PORT_HSCIF) {
|
||||
clk_names[SCI_SCK] = "hsck";
|
||||
} else if (sci_port->type == SCI_PORT_RSCI) {
|
||||
} else if (sci_port->type == RSCI_PORT_SCIF16) {
|
||||
clk_names[SCI_FCK] = "operation";
|
||||
clk_names[SCI_BRG_INT] = "bus";
|
||||
} else if (sci_port->type == RSCI_PORT_SCIF32) {
|
||||
clk_names[SCI_FCK] = "tclk";
|
||||
clk_names[SCI_BRG_INT] = "pclk";
|
||||
}
|
||||
|
||||
for (i = 0; i < SCI_NUM_CLKS; i++) {
|
||||
|
|
@ -3185,12 +3196,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
|
|||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
if (!clk && sci_port->type == SCI_PORT_RSCI &&
|
||||
(i == SCI_FCK || i == SCI_BRG_INT)) {
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"failed to get %s\n",
|
||||
name);
|
||||
}
|
||||
if (!clk && sci_port->type == RSCI_PORT_SCIF16 &&
|
||||
(i == SCI_FCK || i == SCI_BRG_INT))
|
||||
return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name);
|
||||
|
||||
if (!clk && sci_port->type == RSCI_PORT_SCIF32 &&
|
||||
(i != SCI_SCK && i != SCI_SCIF_CLK))
|
||||
return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name);
|
||||
|
||||
if (!clk && i == SCI_FCK) {
|
||||
/*
|
||||
|
|
@ -3200,16 +3212,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
|
|||
*/
|
||||
clk = devm_clk_get(dev, "peripheral_clk");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk),
|
||||
"failed to get %s\n",
|
||||
name);
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "failed to get %s\n", name);
|
||||
}
|
||||
|
||||
if (!clk)
|
||||
dev_dbg(dev, "failed to get %s\n", name);
|
||||
else
|
||||
dev_dbg(dev, "clk %s is %pC rate %lu\n", name,
|
||||
clk, clk_get_rate(clk));
|
||||
dev_dbg(dev, "clk %s is %pC rate %lu\n", name, clk, clk_get_rate(clk));
|
||||
sci_port->clks[i] = clk;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -3295,7 +3304,7 @@ static int sci_init_single(struct platform_device *dev,
|
|||
* The fourth interrupt on SCI and RSCI port is transmit end interrupt, so
|
||||
* shuffle the interrupts.
|
||||
*/
|
||||
if (p->type == PORT_SCI || p->type == SCI_PORT_RSCI)
|
||||
if (p->type == PORT_SCI || sci_is_rsci_type(p->type))
|
||||
swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]);
|
||||
|
||||
/* The SCI generates several interrupts. They can be muxed together or
|
||||
|
|
@ -3320,6 +3329,7 @@ static int sci_init_single(struct platform_device *dev,
|
|||
sci_port->rx_trigger = 64;
|
||||
break;
|
||||
case PORT_SCIFA:
|
||||
case RSCI_PORT_SCIF32:
|
||||
sci_port->rx_trigger = 32;
|
||||
break;
|
||||
case PORT_SCIF:
|
||||
|
|
@ -3329,8 +3339,8 @@ static int sci_init_single(struct platform_device *dev,
|
|||
else
|
||||
sci_port->rx_trigger = 8;
|
||||
break;
|
||||
case SCI_PORT_RSCI:
|
||||
sci_port->rx_trigger = 15;
|
||||
case RSCI_PORT_SCIF16:
|
||||
sci_port->rx_trigger = 16;
|
||||
break;
|
||||
default:
|
||||
sci_port->rx_trigger = 1;
|
||||
|
|
@ -3422,7 +3432,10 @@ static void serial_console_write(struct console *co, const char *s,
|
|||
cpu_relax();
|
||||
|
||||
/* restore the SCSCR */
|
||||
sci_port->ops->write_reg(port, regs->control, ctrl);
|
||||
if (sci_port->ops->finish_console_write)
|
||||
sci_port->ops->finish_console_write(port, ctrl);
|
||||
else
|
||||
sci_port->ops->write_reg(port, regs->control, ctrl);
|
||||
|
||||
if (locked)
|
||||
uart_port_unlock_irqrestore(port, flags);
|
||||
|
|
@ -3549,16 +3562,14 @@ static struct uart_driver sci_uart_driver = {
|
|||
static void sci_remove(struct platform_device *dev)
|
||||
{
|
||||
struct sci_port *s = platform_get_drvdata(dev);
|
||||
unsigned int type = s->type; /* uart_remove_... clears it */
|
||||
|
||||
sci_ports_in_use &= ~BIT(s->port.line);
|
||||
uart_remove_one_port(&sci_uart_driver, &s->port);
|
||||
|
||||
if (s->port.fifosize > 1)
|
||||
if (s->port.fifosize > 1) {
|
||||
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
|
||||
if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF ||
|
||||
type == SCI_PORT_RSCI)
|
||||
device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct sci_of_data of_sci_scif_sh2 = {
|
||||
|
|
@ -3652,9 +3663,13 @@ static const struct of_device_id of_sci_match[] __maybe_unused = {
|
|||
.data = &of_sci_scif_rzv2h,
|
||||
},
|
||||
#ifdef CONFIG_SERIAL_RSCI
|
||||
{
|
||||
.compatible = "renesas,r9a09g047-rsci",
|
||||
.data = &of_rsci_rzg3e_data,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,r9a09g077-rsci",
|
||||
.data = &of_sci_rsci_data,
|
||||
.data = &of_rsci_rzt2h_data,
|
||||
},
|
||||
#endif /* CONFIG_SERIAL_RSCI */
|
||||
/* Family-specific types */
|
||||
|
|
@ -3716,7 +3731,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
|
|||
|
||||
data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
rstc = devm_reset_control_array_get_optional_exclusive(&pdev->dev);
|
||||
if (IS_ERR(rstc))
|
||||
return ERR_PTR(dev_err_probe(&pdev->dev, PTR_ERR(rstc),
|
||||
"failed to get reset ctrl\n"));
|
||||
|
|
@ -3917,15 +3932,10 @@ static int sci_probe(struct platform_device *dev)
|
|||
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_trigger);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (sp->type == PORT_SCIFA || sp->type == PORT_SCIFB ||
|
||||
sp->type == PORT_HSCIF || sp->type == SCI_PORT_RSCI) {
|
||||
|
||||
ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout);
|
||||
if (ret) {
|
||||
if (sp->port.fifosize > 1) {
|
||||
device_remove_file(&dev->dev,
|
||||
&dev_attr_rx_fifo_trigger);
|
||||
}
|
||||
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1649,6 +1649,123 @@ int __init kbd_init(void)
|
|||
|
||||
/* Ioctl support code */
|
||||
|
||||
static int vt_do_kdgkbdiacr(void __user *udp)
|
||||
{
|
||||
struct kbdiacrs __user *a = udp;
|
||||
int i, asize;
|
||||
|
||||
struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr),
|
||||
GFP_KERNEL);
|
||||
if (!dia)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Lock the diacriticals table, make a copy and then
|
||||
copy it after we unlock */
|
||||
scoped_guard(spinlock_irqsave, &kbd_event_lock) {
|
||||
asize = accent_table_size;
|
||||
for (i = 0; i < asize; i++) {
|
||||
dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr);
|
||||
dia[i].base = conv_uni_to_8bit(accent_table[i].base);
|
||||
dia[i].result = conv_uni_to_8bit(accent_table[i].result);
|
||||
}
|
||||
}
|
||||
|
||||
if (put_user(asize, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vt_do_kdgkbdiacruc(void __user *udp)
|
||||
{
|
||||
struct kbdiacrsuc __user *a = udp;
|
||||
int asize;
|
||||
|
||||
void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc),
|
||||
GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Lock the diacriticals table, make a copy and then
|
||||
copy it after we unlock */
|
||||
scoped_guard(spinlock_irqsave, &kbd_event_lock) {
|
||||
asize = accent_table_size;
|
||||
memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
|
||||
}
|
||||
|
||||
if (put_user(asize, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vt_do_kdskbdiacr(void __user *udp, int perm)
|
||||
{
|
||||
struct kbdiacrs __user *a = udp;
|
||||
struct kbdiacr __free(kfree) *dia = NULL;
|
||||
unsigned int ct;
|
||||
int i;
|
||||
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
if (get_user(ct, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
if (ct >= MAX_DIACR)
|
||||
return -EINVAL;
|
||||
|
||||
if (ct) {
|
||||
dia = memdup_array_user(a->kbdiacr,
|
||||
ct, sizeof(struct kbdiacr));
|
||||
if (IS_ERR(dia))
|
||||
return PTR_ERR(dia);
|
||||
}
|
||||
|
||||
guard(spinlock_irqsave)(&kbd_event_lock);
|
||||
accent_table_size = ct;
|
||||
for (i = 0; i < ct; i++) {
|
||||
accent_table[i].diacr =
|
||||
conv_8bit_to_uni(dia[i].diacr);
|
||||
accent_table[i].base =
|
||||
conv_8bit_to_uni(dia[i].base);
|
||||
accent_table[i].result =
|
||||
conv_8bit_to_uni(dia[i].result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vt_do_kdskbdiacruc(void __user *udp, int perm)
|
||||
{
|
||||
struct kbdiacrsuc __user *a = udp;
|
||||
unsigned int ct;
|
||||
void __free(kfree) *buf = NULL;
|
||||
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
|
||||
if (get_user(ct, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
|
||||
if (ct >= MAX_DIACR)
|
||||
return -EINVAL;
|
||||
|
||||
if (ct) {
|
||||
buf = memdup_array_user(a->kbdiacruc,
|
||||
ct, sizeof(struct kbdiacruc));
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
}
|
||||
guard(spinlock_irqsave)(&kbd_event_lock);
|
||||
if (ct)
|
||||
memcpy(accent_table, buf,
|
||||
ct * sizeof(struct kbdiacruc));
|
||||
accent_table_size = ct;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vt_do_diacrit - diacritical table updates
|
||||
* @cmd: ioctl request
|
||||
|
|
@ -1660,123 +1777,15 @@ int __init kbd_init(void)
|
|||
*/
|
||||
int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
|
||||
{
|
||||
int asize;
|
||||
|
||||
switch (cmd) {
|
||||
case KDGKBDIACR:
|
||||
{
|
||||
struct kbdiacrs __user *a = udp;
|
||||
int i;
|
||||
|
||||
struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr),
|
||||
GFP_KERNEL);
|
||||
if (!dia)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Lock the diacriticals table, make a copy and then
|
||||
copy it after we unlock */
|
||||
scoped_guard(spinlock_irqsave, &kbd_event_lock) {
|
||||
asize = accent_table_size;
|
||||
for (i = 0; i < asize; i++) {
|
||||
dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr);
|
||||
dia[i].base = conv_uni_to_8bit(accent_table[i].base);
|
||||
dia[i].result = conv_uni_to_8bit(accent_table[i].result);
|
||||
}
|
||||
}
|
||||
|
||||
if (put_user(asize, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
return vt_do_kdgkbdiacr(udp);
|
||||
case KDGKBDIACRUC:
|
||||
{
|
||||
struct kbdiacrsuc __user *a = udp;
|
||||
|
||||
void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc),
|
||||
GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Lock the diacriticals table, make a copy and then
|
||||
copy it after we unlock */
|
||||
scoped_guard(spinlock_irqsave, &kbd_event_lock) {
|
||||
asize = accent_table_size;
|
||||
memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
|
||||
}
|
||||
|
||||
if (put_user(asize, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return vt_do_kdgkbdiacruc(udp);
|
||||
case KDSKBDIACR:
|
||||
{
|
||||
struct kbdiacrs __user *a = udp;
|
||||
struct kbdiacr __free(kfree) *dia = NULL;
|
||||
unsigned int ct;
|
||||
int i;
|
||||
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
if (get_user(ct, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
if (ct >= MAX_DIACR)
|
||||
return -EINVAL;
|
||||
|
||||
if (ct) {
|
||||
dia = memdup_array_user(a->kbdiacr,
|
||||
ct, sizeof(struct kbdiacr));
|
||||
if (IS_ERR(dia))
|
||||
return PTR_ERR(dia);
|
||||
}
|
||||
|
||||
guard(spinlock_irqsave)(&kbd_event_lock);
|
||||
accent_table_size = ct;
|
||||
for (i = 0; i < ct; i++) {
|
||||
accent_table[i].diacr =
|
||||
conv_8bit_to_uni(dia[i].diacr);
|
||||
accent_table[i].base =
|
||||
conv_8bit_to_uni(dia[i].base);
|
||||
accent_table[i].result =
|
||||
conv_8bit_to_uni(dia[i].result);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return vt_do_kdskbdiacr(udp, perm);
|
||||
case KDSKBDIACRUC:
|
||||
{
|
||||
struct kbdiacrsuc __user *a = udp;
|
||||
unsigned int ct;
|
||||
void __free(kfree) *buf = NULL;
|
||||
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
|
||||
if (get_user(ct, &a->kb_cnt))
|
||||
return -EFAULT;
|
||||
|
||||
if (ct >= MAX_DIACR)
|
||||
return -EINVAL;
|
||||
|
||||
if (ct) {
|
||||
buf = memdup_array_user(a->kbdiacruc,
|
||||
ct, sizeof(struct kbdiacruc));
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
}
|
||||
guard(spinlock_irqsave)(&kbd_event_lock);
|
||||
if (ct)
|
||||
memcpy(accent_table, buf,
|
||||
ct * sizeof(struct kbdiacruc));
|
||||
accent_table_size = ct;
|
||||
return 0;
|
||||
}
|
||||
return vt_do_kdskbdiacruc(udp, perm);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ struct serdev_device_driver {
|
|||
struct device_driver driver;
|
||||
int (*probe)(struct serdev_device *);
|
||||
void (*remove)(struct serdev_device *);
|
||||
void (*shutdown)(struct serdev_device *);
|
||||
};
|
||||
|
||||
static inline struct serdev_device_driver *to_serdev_device_driver(struct device_driver *d)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue