diff --git a/Documentation/devicetree/bindings/goldfish/tty.txt b/Documentation/devicetree/bindings/goldfish/tty.txt deleted file mode 100644 index 82648278da77..000000000000 --- a/Documentation/devicetree/bindings/goldfish/tty.txt +++ /dev/null @@ -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 : -- interrupts : - -Example: - - goldfish_tty@1f004000 { - compatible = "google,goldfish-tty"; - reg = <0x1f004000 0x1000>; - interrupts = <0xc>; - }; diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml index 167ddcbd8800..73851f19330d 100644 --- a/Documentation/devicetree/bindings/serial/8250.yaml +++ b/Documentation/devicetree/bindings/serial/8250.yaml @@ -160,6 +160,7 @@ properties: - enum: - mrvl,mmp-uart - spacemit,k1-uart + - spacemit,k3-uart - const: intel,xscale-uart - items: - enum: diff --git a/Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml b/Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml new file mode 100644 index 000000000000..0626ce58740c --- /dev/null +++ b/Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml @@ -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 + +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>; + }; diff --git a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml index 6b1f827a335b..e059b14775eb 100644 --- a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml @@ -10,46 +10,78 @@ maintainers: - Geert Uytterhoeven - Lad Prabhakar -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: diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index 72483bc3274d..82f54446835e 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -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 diff --git a/Documentation/misc-devices/oxsemi-tornado.rst b/Documentation/misc-devices/oxsemi-tornado.rst index b33351bef6cf..fe2e5f726c2b 100644 --- a/Documentation/misc-devices/oxsemi-tornado.rst +++ b/Documentation/misc-devices/oxsemi-tornado.rst @@ -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 diff --git a/drivers/bluetooth/hci_aml.c b/drivers/bluetooth/hci_aml.c index b1f32c5a8a3f..4981c82d634d 100644 --- a/drivers/bluetooth/hci_aml.c +++ b/drivers/bluetooth/hci_aml.c @@ -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, }, }; diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 51309f5b5714..c511546f793e 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -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, diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index c7e05f7bc199..82e531023911 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -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, }, }; diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 4ca7472c38e0..a7939c49c9cf 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -9,8 +9,7 @@ * * Author(s): Hendrik Brueckner */ -#define KMSG_COMPONENT "hvc_iucv" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#define pr_fmt(fmt) "hvc_iucv: " fmt #include #include @@ -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) { diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 3c9dcb0928c6..f242d73ee4e0 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -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; diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index b33e708cb245..40eedc15277c 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -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); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 27af83f0ff46..db73b2ae17fa 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -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, diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c index c05b89551b12..f94d97e69dc5 100644 --- a/drivers/tty/serial/8250/8250_keba.c +++ b/drivers/tty/serial/8250/8250_keba.c @@ -6,10 +6,18 @@ */ #include -#include +#include +#include +#include +#include +#include #include #include +#include #include +#include +#include +#include #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; diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index a78ef35c8187..6373234da03d 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -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 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); } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 3efe075ef7b2..6589bb531cc6 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -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; } } diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index c488ff6f2865..fd4e8b6ab60d 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -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 diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 59221cce0028..f86775cfdcc9 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -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 diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 9cc15449b673..6fad57fee912 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -919,5 +919,4 @@ module_exit(men_z135_exit); MODULE_AUTHOR("Johannes Thumshirn "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MEN 16z135 High Speed UART"); -MODULE_ALIAS("mcb:16z135"); MODULE_IMPORT_NS("MCB"); diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index b3c48dc1e07d..c3f12df693ad 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -11,6 +11,8 @@ #include #include #include + +#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 */ diff --git a/drivers/tty/serial/rsci.h b/drivers/tty/serial/rsci.h index 2af3f28b465a..2aa2ba3973ee 100644 --- a/drivers/tty/serial/rsci.h +++ b/drivers/tty/serial/rsci.h @@ -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__ */ diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h index e3c028df14f1..f363a659c46a 100644 --- a/drivers/tty/serial/sh-sci-common.h +++ b/drivers/tty/serial/sh-sci-common.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) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index fbfe5575bd3c..bd7486315338 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -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; } } diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index d65fc60dd7be..3538d54d6a6a 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -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; } diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 34562eb99931..5654c58eb73c 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -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)