Merge 356a031945 ("Merge tag 'tty-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty") into android-mainline
Steps on the way to 6.12-rc1 Bug: 367265496 Change-Id: I0558de38f29cc97e194b80b6c6a79f67e9c0ebaa Signed-off-by: Matthias Maennich <maennich@google.com>
This commit is contained in:
@@ -6,3 +6,10 @@ Description:
|
||||
This item contains just one readonly attribute: port_num.
|
||||
It contains the port number of the /dev/ttyGS<n> device
|
||||
associated with acm function's instance "name".
|
||||
|
||||
What: /config/usb-gadget/gadget/functions/acm.name/protocol
|
||||
Date: Aug 2024
|
||||
KernelVersion: 6.13
|
||||
Description:
|
||||
Reported bInterfaceProtocol for the ACM device. For legacy
|
||||
reasons, this defaults to 1 (USB_CDC_ACM_PROTO_AT_V25TER).
|
||||
|
||||
@@ -30,4 +30,12 @@ Description:
|
||||
req_number the number of pre-allocated requests
|
||||
for both capture and playback
|
||||
function_name name of the interface
|
||||
p_it_name playback input terminal name
|
||||
p_it_ch_name playback channels name
|
||||
p_ot_name playback output terminal name
|
||||
p_fu_vol_name playback mute/volume functional unit name
|
||||
c_it_name capture input terminal name
|
||||
c_it_ch_name capture channels name
|
||||
c_ot_name capture output terminal name
|
||||
c_fu_vol_name capture mute/volume functional unit name
|
||||
===================== =======================================
|
||||
|
||||
@@ -35,6 +35,17 @@ Description:
|
||||
req_number the number of pre-allocated requests
|
||||
for both capture and playback
|
||||
function_name name of the interface
|
||||
if_ctrl_name topology control name
|
||||
clksrc_in_name input clock name
|
||||
clksrc_out_name output clock name
|
||||
p_it_name playback input terminal name
|
||||
p_it_ch_name playback input first channel name
|
||||
p_ot_name playback output terminal name
|
||||
p_fu_vol_name playback mute/volume function unit name
|
||||
c_it_name capture input terminal name
|
||||
c_it_ch_name capture input first channel name
|
||||
c_ot_name capture output terminal name
|
||||
c_fu_vol_name capture mute/volume functional unit name
|
||||
c_terminal_type code of the capture terminal type
|
||||
p_terminal_type code of the playback terminal type
|
||||
===================== =======================================
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/goodix,gt7986u.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GOODIX GT7986U SPI HID Touchscreen
|
||||
|
||||
maintainers:
|
||||
- Charles Wang <charles.goodix@gmail.com>
|
||||
|
||||
description: Supports the Goodix GT7986U touchscreen.
|
||||
This touch controller reports data packaged according to the HID protocol,
|
||||
but is incompatible with Microsoft's HID-over-SPI protocol.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- goodix,gt7986u
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
goodix,hid-report-addr:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
The register address for retrieving HID report data.
|
||||
This address is related to the device firmware and may
|
||||
change after a firmware update.
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- reset-gpios
|
||||
- goodix,hid-report-addr
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@0 {
|
||||
compatible = "goodix,gt7986u";
|
||||
reg = <0>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
|
||||
reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
|
||||
spi-max-frequency = <10000000>;
|
||||
goodix,hid-report-addr = <0x22c8c>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -87,6 +87,12 @@ properties:
|
||||
maximum: 119
|
||||
default: 100
|
||||
|
||||
nxp,sim:
|
||||
description:
|
||||
The system integration module (SIM) provides system control and chip
|
||||
configuration registers.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -110,6 +116,17 @@ allOf:
|
||||
required:
|
||||
- fsl,anatop
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
const: fsl,imx7ulp-usbphy
|
||||
then:
|
||||
required:
|
||||
- nxp,sim
|
||||
else:
|
||||
properties:
|
||||
nxp,sim: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -22,6 +22,9 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
trickle-resistor-ohms:
|
||||
enum:
|
||||
- 3000
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/rtc/sprd,sc2731-rtc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Spreadtrum SC2731 Real Time Clock
|
||||
|
||||
maintainers:
|
||||
- Orson Zhai <orsonzhai@gmail.com>
|
||||
- Baolin Wang <baolin.wang7@gmail.com>
|
||||
- Chunyan Zhang <zhang.lyra@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sprd,sc2731-rtc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: rtc.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rtc@280 {
|
||||
compatible = "sprd,sc2731-rtc";
|
||||
reg = <0x280>;
|
||||
interrupt-parent = <&sc2731_pmic>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -1,26 +0,0 @@
|
||||
Spreadtrum SC27xx Real Time Clock
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "sprd,sc2731-rtc".
|
||||
- reg: address offset of rtc register.
|
||||
- interrupts: rtc alarm interrupt.
|
||||
|
||||
Example:
|
||||
|
||||
sc2731_pmic: pmic@0 {
|
||||
compatible = "sprd,sc2731";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <26000000>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rtc@280 {
|
||||
compatible = "sprd,sc2731-rtc";
|
||||
reg = <0x280>;
|
||||
interrupt-parent = <&sc2731_pmic>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
@@ -53,6 +53,28 @@ properties:
|
||||
override default rtc_ck parent clock phandle of the new parent clock of rtc_ck
|
||||
maxItems: 1
|
||||
|
||||
patternProperties:
|
||||
"^rtc-[a-z]+-[0-9]+$":
|
||||
type: object
|
||||
$ref: /schemas/pinctrl/pinmux-node.yaml
|
||||
description: |
|
||||
Configuration of STM32 RTC pins description. STM32 RTC is able to output
|
||||
some signals on specific pins:
|
||||
- LSCO (Low Speed Clock Output) that allow to output LSE clock on a pin.
|
||||
- Alarm out that allow to send a pulse on a pin when alarm A of the RTC
|
||||
expires.
|
||||
additionalProperties: false
|
||||
properties:
|
||||
function:
|
||||
enum:
|
||||
- lsco
|
||||
- alarm-a
|
||||
pins:
|
||||
enum:
|
||||
- out1
|
||||
- out2
|
||||
- out2_rmp
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
@@ -68,6 +90,9 @@ allOf:
|
||||
|
||||
clock-names: false
|
||||
|
||||
patternProperties:
|
||||
"^rtc-[a-z]+-[0-9]+$": false
|
||||
|
||||
required:
|
||||
- st,syscfg
|
||||
|
||||
@@ -83,6 +108,9 @@ allOf:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
patternProperties:
|
||||
"^rtc-[a-z]+-[0-9]+$": false
|
||||
|
||||
required:
|
||||
- clock-names
|
||||
- st,syscfg
|
||||
|
||||
@@ -38,12 +38,13 @@ properties:
|
||||
- dallas,ds1672
|
||||
# Extremely Accurate I²C RTC with Integrated Crystal and SRAM
|
||||
- dallas,ds3232
|
||||
# SD2405AL Real-Time Clock
|
||||
- dfrobot,sd2405al
|
||||
# EM Microelectronic EM3027 RTC
|
||||
- emmicro,em3027
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
- epson,rx8010
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE
|
||||
- epson,rx8025
|
||||
- epson,rx8035
|
||||
# I2C-BUS INTERFACE REAL TIME CLOCK MODULE with Battery Backed RAM
|
||||
- epson,rx8111
|
||||
@@ -52,10 +53,6 @@ properties:
|
||||
- epson,rx8581
|
||||
# Android Goldfish Real-time Clock
|
||||
- google,goldfish-rtc
|
||||
# Intersil ISL1208 Low Power RTC with Battery Backed SRAM
|
||||
- isil,isl1208
|
||||
# Intersil ISL1218 Low Power RTC with Battery Backed SRAM
|
||||
- isil,isl1218
|
||||
# Mvebu Real-time Clock
|
||||
- marvell,orion-rtc
|
||||
# Maxim DS1742/DS1743 Real-time Clock
|
||||
@@ -68,8 +65,6 @@ properties:
|
||||
- microcrystal,rv8523
|
||||
# NXP LPC32xx SoC Real-time Clock
|
||||
- nxp,lpc3220-rtc
|
||||
# Real-time Clock Module
|
||||
- pericom,pt7c4338
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
- ricoh,r2025sd
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
|
||||
@@ -76,6 +76,7 @@ properties:
|
||||
clock-frequency: true
|
||||
current-speed: true
|
||||
overrun-throttle-ms: true
|
||||
wakeup-source: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
@@ -23,13 +23,20 @@ properties:
|
||||
- const: atmel,at91sam9260-dbgu
|
||||
- const: atmel,at91sam9260-usart
|
||||
- items:
|
||||
- const: microchip,sam9x60-usart
|
||||
- enum:
|
||||
- microchip,sam9x60-usart
|
||||
- microchip,sam9x7-usart
|
||||
- const: atmel,at91sam9260-usart
|
||||
- items:
|
||||
- const: microchip,sam9x60-dbgu
|
||||
- const: microchip,sam9x60-usart
|
||||
- const: atmel,at91sam9260-dbgu
|
||||
- const: atmel,at91sam9260-usart
|
||||
- items:
|
||||
- const: microchip,sam9x7-dbgu
|
||||
- const: atmel,at91sam9260-dbgu
|
||||
- const: microchip,sam9x7-usart
|
||||
- const: atmel,at91sam9260-usart
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -36,6 +36,7 @@ properties:
|
||||
- mediatek,mt7622-uart
|
||||
- mediatek,mt7623-uart
|
||||
- mediatek,mt7629-uart
|
||||
- mediatek,mt7981-uart
|
||||
- mediatek,mt7986-uart
|
||||
- mediatek,mt7988-uart
|
||||
- mediatek,mt8127-uart
|
||||
|
||||
@@ -46,6 +46,7 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,scif-r8a774a1 # RZ/G2M
|
||||
- renesas,scif-r8a774a3 # RZ/G2M v3.0
|
||||
- renesas,scif-r8a774b1 # RZ/G2N
|
||||
- renesas,scif-r8a774c0 # RZ/G2E
|
||||
- renesas,scif-r8a774e1 # RZ/G2H
|
||||
|
||||
@@ -56,14 +56,8 @@ properties:
|
||||
maxItems: 5
|
||||
|
||||
clock-names:
|
||||
description: N = 0 is allowed for SoCs without internal baud clock mux.
|
||||
minItems: 2
|
||||
items:
|
||||
- const: uart
|
||||
- pattern: '^clk_uart_baud[0-3]$'
|
||||
- pattern: '^clk_uart_baud[0-3]$'
|
||||
- pattern: '^clk_uart_baud[0-3]$'
|
||||
- pattern: '^clk_uart_baud[0-3]$'
|
||||
maxItems: 5
|
||||
|
||||
dmas:
|
||||
items:
|
||||
@@ -103,18 +97,45 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- samsung,s5pv210-uart
|
||||
- samsung,s3c6400-uart
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: uart
|
||||
- const: clk_uart_baud2
|
||||
- const: clk_uart_baud3
|
||||
|
||||
else:
|
||||
properties:
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: uart
|
||||
- pattern: '^clk_uart_baud[0-1]$'
|
||||
- pattern: '^clk_uart_baud[0-1]$'
|
||||
- const: clk_uart_baud0
|
||||
- const: clk_uart_baud1
|
||||
- const: clk_uart_baud2
|
||||
- const: clk_uart_baud3
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- samsung,s5pv210-uart
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
- if:
|
||||
properties:
|
||||
@@ -129,10 +150,9 @@ allOf:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: uart
|
||||
- const: clk_uart_baud0
|
||||
maxItems: 2
|
||||
|
||||
- if:
|
||||
properties:
|
||||
@@ -146,6 +166,12 @@ allOf:
|
||||
properties:
|
||||
reg-io-width: false
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
@@ -163,3 +189,19 @@ examples:
|
||||
<&clocks SCLK_UART>;
|
||||
samsung,uart-fifosize = <16>;
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/clock/google,gs101.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
serial_0: serial@10a00000 {
|
||||
compatible = "google,gs101-uart";
|
||||
reg = <0x10a00000 0xc0>;
|
||||
clocks = <&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP1_PCLK_0>,
|
||||
<&cmu_peric0 CLK_GOUT_PERIC0_PERIC0_TOP1_IPCLK_0>;
|
||||
clock-names = "uart", "clk_uart_baud0";
|
||||
interrupts = <GIC_SPI 634 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
pinctrl-0 = <&uart0_bus>;
|
||||
pinctrl-names = "default";
|
||||
samsung,uart-fifosize = <256>;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/usb/fsl,ls1028a.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale layerscape SuperSpeed DWC3 USB SoC controller
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,ls1028a-dwc3
|
||||
required:
|
||||
- compatible
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- fsl,ls1028a-dwc3
|
||||
- const: snps,dwc3
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwc3.yaml#
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
usb@fe800000 {
|
||||
compatible = "fsl,ls1028a-dwc3", "snps,dwc3";
|
||||
reg = <0xfe800000 0x100000>;
|
||||
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
@@ -1,110 +0,0 @@
|
||||
MSM SoC HSUSB controllers
|
||||
|
||||
EHCI
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "qcom,ehci-host"
|
||||
- regs: offset and length of the register set in the memory map
|
||||
- usb-phy: phandle for the PHY device
|
||||
|
||||
Example EHCI controller device node:
|
||||
|
||||
ehci: ehci@f9a55000 {
|
||||
compatible = "qcom,ehci-host";
|
||||
reg = <0xf9a55000 0x400>;
|
||||
usb-phy = <&usb_otg>;
|
||||
};
|
||||
|
||||
USB PHY with optional OTG:
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain:
|
||||
"qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY
|
||||
"qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY
|
||||
|
||||
- regs: Offset and length of the register set in the memory map
|
||||
- interrupts: interrupt-specifier for the OTG interrupt.
|
||||
|
||||
- clocks: A list of phandle + clock-specifier pairs for the
|
||||
clocks listed in clock-names
|
||||
- clock-names: Should contain the following:
|
||||
"phy" USB PHY reference clock
|
||||
"core" Protocol engine clock
|
||||
"iface" Interface bus clock
|
||||
"alt_core" Protocol engine clock for targets with asynchronous
|
||||
reset methodology. (optional)
|
||||
|
||||
- vdccx-supply: phandle to the regulator for the vdd supply for
|
||||
digital circuit operation.
|
||||
- v1p8-supply: phandle to the regulator for the 1.8V supply
|
||||
- v3p3-supply: phandle to the regulator for the 3.3V supply
|
||||
|
||||
- resets: A list of phandle + reset-specifier pairs for the
|
||||
resets listed in reset-names
|
||||
- reset-names: Should contain the following:
|
||||
"phy" USB PHY controller reset
|
||||
"link" USB LINK controller reset
|
||||
|
||||
- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of
|
||||
1 - PHY control
|
||||
2 - PMIC control
|
||||
|
||||
Optional properties:
|
||||
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
|
||||
|
||||
- switch-gpio: A phandle + gpio-specifier pair. Some boards are using Dual
|
||||
SPDT USB Switch, witch is controlled by GPIO to de/multiplex
|
||||
D+/D- USB lines between connectors.
|
||||
|
||||
- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device
|
||||
Mode Eye Diagram test. Start address at which these values will be
|
||||
written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
|
||||
"do not overwrite default value at this address".
|
||||
For example: qcom,phy-init-sequence = < -1 0x63 >;
|
||||
Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1.
|
||||
|
||||
- qcom,phy-num: Select number of pyco-phy to use, can be one of
|
||||
0 - PHY one, default
|
||||
1 - Second PHY
|
||||
Some platforms may have configuration to allow USB
|
||||
controller work with any of the two HSPHYs present.
|
||||
|
||||
- qcom,vdd-levels: This property must be a list of three integer values
|
||||
(no, min, max) where each value represents either a voltage
|
||||
in microvolts or a value corresponding to voltage corner.
|
||||
|
||||
- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
|
||||
and controller driver therefore enables pull-up explicitly
|
||||
before starting controller using usbcmd run/stop bit.
|
||||
|
||||
- extcon: phandles to external connector devices. First phandle
|
||||
should point to external connector, which provide "USB"
|
||||
cable events, the second should point to external connector
|
||||
device, which provide "USB-HOST" cable events. If one of
|
||||
the external connector devices is not required empty <0>
|
||||
phandle should be specified.
|
||||
|
||||
Example HSUSB OTG controller device node:
|
||||
|
||||
usb@f9a55000 {
|
||||
compatible = "qcom,usb-otg-snps";
|
||||
reg = <0xf9a55000 0x400>;
|
||||
interrupts = <0 134 0>;
|
||||
dr_mode = "peripheral";
|
||||
|
||||
clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>,
|
||||
<&gcc GCC_USB_HS_AHB_CLK>;
|
||||
|
||||
clock-names = "phy", "core", "iface";
|
||||
|
||||
vddcx-supply = <&pm8841_s2_corner>;
|
||||
v1p8-supply = <&pm8941_l6>;
|
||||
v3p3-supply = <&pm8941_l24>;
|
||||
|
||||
resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>;
|
||||
reset-names = "phy", "link";
|
||||
|
||||
qcom,otg-control = <1>;
|
||||
qcom,phy-init-sequence = < -1 0x63 >;
|
||||
qcom,vdd-levels = <1 5 7>;
|
||||
};
|
||||
@@ -52,6 +52,7 @@ properties:
|
||||
- qcom,sm8550-dwc3
|
||||
- qcom,sm8650-dwc3
|
||||
- qcom,x1e80100-dwc3
|
||||
- qcom,x1e80100-dwc3-mp
|
||||
- const: qcom,dwc3
|
||||
|
||||
reg:
|
||||
@@ -289,6 +290,7 @@ allOf:
|
||||
- qcom,sc8280xp-dwc3
|
||||
- qcom,sc8280xp-dwc3-mp
|
||||
- qcom,x1e80100-dwc3
|
||||
- qcom,x1e80100-dwc3-mp
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
@@ -428,6 +430,21 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq5332-dwc3
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
maxItems: 3
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: pwr_event
|
||||
- const: dp_hs_phy_irq
|
||||
- const: dm_hs_phy_irq
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,x1e80100-dwc3
|
||||
then:
|
||||
properties:
|
||||
@@ -486,6 +503,7 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,sc8180x-dwc3-mp
|
||||
- qcom,x1e80100-dwc3-mp
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
||||
@@ -13,10 +13,9 @@ properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: ti,j721e-usb
|
||||
- const: ti,am64-usb
|
||||
- items:
|
||||
- const: ti,j721e-usb
|
||||
- const: ti,am64-usb
|
||||
- const: ti,j721e-usb
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -368,6 +368,8 @@ patternProperties:
|
||||
description: Devantech, Ltd.
|
||||
"^dfi,.*":
|
||||
description: DFI Inc.
|
||||
"^dfrobot,.*":
|
||||
description: DFRobot Corporation
|
||||
"^dh,.*":
|
||||
description: DH electronics GmbH
|
||||
"^difrnce,.*":
|
||||
|
||||
@@ -48,11 +48,66 @@ For server running on QEMU host with virtio transport::
|
||||
|
||||
mount -t 9p -o trans=virtio <mount_tag> /mnt/9
|
||||
|
||||
where mount_tag is the tag associated by the server to each of the exported
|
||||
where mount_tag is the tag generated by the server to each of the exported
|
||||
mount points. Each 9P export is seen by the client as a virtio device with an
|
||||
associated "mount_tag" property. Available mount tags can be
|
||||
seen by reading /sys/bus/virtio/drivers/9pnet_virtio/virtio<n>/mount_tag files.
|
||||
|
||||
USBG Usage
|
||||
==========
|
||||
|
||||
To mount a 9p FS on a USB Host accessible via the gadget at runtime::
|
||||
|
||||
mount -t 9p -o trans=usbg,aname=/path/to/fs <device> /mnt/9
|
||||
|
||||
To mount a 9p FS on a USB Host accessible via the gadget as root filesystem::
|
||||
|
||||
root=<device> rootfstype=9p rootflags=trans=usbg,cache=loose,uname=root,access=0,dfltuid=0,dfltgid=0,aname=/path/to/rootfs
|
||||
|
||||
where <device> is the tag associated by the usb gadget transport.
|
||||
It is defined by the configfs instance name.
|
||||
|
||||
USBG Example
|
||||
============
|
||||
|
||||
The USB host exports a filesystem, while the gadget on the USB device
|
||||
side makes it mountable.
|
||||
|
||||
Diod (9pfs server) and the forwarder are on the development host, where
|
||||
the root filesystem is actually stored. The gadget is initialized during
|
||||
boot (or later) on the embedded board. Then the forwarder will find it
|
||||
on the USB bus and start forwarding requests.
|
||||
|
||||
In this case the 9p requests come from the device and are handled by the
|
||||
host. The reason is that USB device ports are normally not available on
|
||||
PCs, so a connection in the other direction would not work.
|
||||
|
||||
When using the usbg transport, for now there is no native usb host
|
||||
service capable to handle the requests from the gadget driver. For
|
||||
this we have to use the extra python tool p9_fwd.py from tools/usb.
|
||||
|
||||
Just start the 9pfs capable network server like diod/nfs-ganesha e.g.::
|
||||
|
||||
$ diod -f -n -d 0 -S -l 0.0.0.0:9999 -e $PWD
|
||||
|
||||
Optionaly scan your bus if there are more then one usbg gadgets to find their path::
|
||||
|
||||
$ python $kernel_dir/tools/usb/p9_fwd.py list
|
||||
|
||||
Bus | Addr | Manufacturer | Product | ID | Path
|
||||
--- | ---- | ---------------- | ---------------- | --------- | ----
|
||||
2 | 67 | unknown | unknown | 1d6b:0109 | 2-1.1.2
|
||||
2 | 68 | unknown | unknown | 1d6b:0109 | 2-1.1.3
|
||||
|
||||
Then start the python transport::
|
||||
|
||||
$ python $kernel_dir/tools/usb/p9_fwd.py --path 2-1.1.2 connect -p 9999
|
||||
|
||||
After that the gadget driver can be used as described above.
|
||||
|
||||
One use-case is to use it as an alternative to NFS root booting during
|
||||
the development of embedded Linux devices.
|
||||
|
||||
Options
|
||||
=======
|
||||
|
||||
@@ -68,6 +123,7 @@ Options
|
||||
virtio connect to the next virtio channel available
|
||||
(from QEMU with trans_virtio module)
|
||||
rdma connect to a specified RDMA channel
|
||||
usbg connect to a specified usb gadget channel
|
||||
======== ============================================
|
||||
|
||||
uname=name user name to attempt mount as on the remote server. The
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
======================
|
||||
FunctionFS Descriptors
|
||||
======================
|
||||
|
||||
Some of the descriptors that can be written to the FFS gadget are
|
||||
described below. Device and configuration descriptors are handled
|
||||
by the composite gadget and are not written by the user to the
|
||||
FFS gadget.
|
||||
|
||||
Descriptors are written to the "ep0" file in the FFS gadget
|
||||
following the descriptor header.
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/usb/functionfs.h
|
||||
:doc: descriptors
|
||||
|
||||
Interface Descriptors
|
||||
---------------------
|
||||
|
||||
Standard USB interface descriptors may be written. The class/subclass of the
|
||||
most recent interface descriptor determines what type of class-specific
|
||||
descriptors are accepted.
|
||||
|
||||
Class-Specific Descriptors
|
||||
--------------------------
|
||||
|
||||
Class-specific descriptors are accepted only for the class/subclass of the
|
||||
most recent interface descriptor. The following are some of the
|
||||
class-specific descriptors that are supported.
|
||||
|
||||
DFU Functional Descriptor
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When the interface class is USB_CLASS_APP_SPEC and the interface subclass
|
||||
is USB_SUBCLASS_DFU, a DFU functional descriptor can be provided.
|
||||
The DFU functional descriptor is a described in the USB specification for
|
||||
Device Firmware Upgrade (DFU), version 1.1 as of this writing.
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/usb/functionfs.h
|
||||
:doc: usb_dfu_functional_descriptor
|
||||
@@ -25,6 +25,8 @@ interface numbers starting from zero). The FunctionFS changes
|
||||
them as needed also handling situation when numbers differ in
|
||||
different configurations.
|
||||
|
||||
For more information about FunctionFS descriptors see :doc:`functionfs-desc`
|
||||
|
||||
When descriptors and strings are written "ep#" files appear
|
||||
(one for each declared endpoint) which handle communication on
|
||||
a single endpoint. Again, FunctionFS takes care of the real
|
||||
|
||||
@@ -765,6 +765,17 @@ The uac2 function provides these attributes in its function directory:
|
||||
req_number the number of pre-allocated request for both capture
|
||||
and playback
|
||||
function_name name of the interface
|
||||
if_ctrl_name topology control name
|
||||
clksrc_in_name input clock name
|
||||
clksrc_out_name output clock name
|
||||
p_it_name playback input terminal name
|
||||
p_it_ch_name playback input first channel name
|
||||
p_ot_name playback output terminal name
|
||||
p_fu_vol_name playback function unit name
|
||||
c_it_name capture input terminal name
|
||||
c_it_ch_name capture input first channel name
|
||||
c_ot_name capture output terminal name
|
||||
c_fu_vol_name capture functional unit name
|
||||
c_terminal_type code of the capture terminal type
|
||||
p_terminal_type code of the playback terminal type
|
||||
================ ====================================================
|
||||
@@ -957,6 +968,14 @@ The uac1 function provides these attributes in its function directory:
|
||||
req_number the number of pre-allocated requests for both capture
|
||||
and playback
|
||||
function_name name of the interface
|
||||
p_it_name playback input terminal name
|
||||
p_it_ch_name playback channels name
|
||||
p_ot_name playback output terminal name
|
||||
p_fu_vol_name playback mute/volume functional unit name
|
||||
c_it_name capture input terminal name
|
||||
c_it_ch_name capture channels name
|
||||
c_ot_name capture output terminal name
|
||||
c_fu_vol_name capture mute/volume functional unit name
|
||||
================ ====================================================
|
||||
|
||||
The attributes have sane default values.
|
||||
|
||||
@@ -11,6 +11,7 @@ USB support
|
||||
dwc3
|
||||
ehci
|
||||
functionfs
|
||||
functionfs-desc
|
||||
gadget_configfs
|
||||
gadget_hid
|
||||
gadget_multi
|
||||
|
||||
@@ -6557,6 +6557,12 @@ F: include/net/devlink.h
|
||||
F: include/uapi/linux/devlink.h
|
||||
F: net/devlink/
|
||||
|
||||
DFROBOT SD2405AL RTC DRIVER
|
||||
M: Tóth János <gomba007@gmail.com>
|
||||
L: linux-rtc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/rtc/rtc-sd2405al.c
|
||||
|
||||
DH ELECTRONICS IMX6 DHCOM/DHCOR BOARD SUPPORT
|
||||
M: Christoph Niedermaier <cniedermaier@dh-electronics.com>
|
||||
L: kernel@dh-electronics.com
|
||||
@@ -24465,6 +24471,7 @@ F: include/linux/vdpa.h
|
||||
F: include/linux/virtio*.h
|
||||
F: include/linux/vringh.h
|
||||
F: include/uapi/linux/virtio_*.h
|
||||
F: net/vmw_vsock/virtio*
|
||||
F: tools/virtio/
|
||||
F: tools/testing/selftests/drivers/net/virtio_net/
|
||||
|
||||
|
||||
@@ -94,6 +94,39 @@
|
||||
#pwm-cells = <2>;
|
||||
};
|
||||
|
||||
serial@11002000 {
|
||||
compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart";
|
||||
reg = <0 0x11002000 0 0x100>;
|
||||
interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "uart", "wakeup";
|
||||
clocks = <&infracfg CLK_INFRA_UART0_SEL>,
|
||||
<&infracfg CLK_INFRA_UART0_CK>;
|
||||
clock-names = "baud", "bus";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
serial@11003000 {
|
||||
compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart";
|
||||
reg = <0 0x11003000 0 0x100>;
|
||||
interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "uart", "wakeup";
|
||||
clocks = <&infracfg CLK_INFRA_UART1_SEL>,
|
||||
<&infracfg CLK_INFRA_UART1_CK>;
|
||||
clock-names = "baud", "bus";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
serial@11004000 {
|
||||
compatible = "mediatek,mt7981-uart", "mediatek,mt6577-uart";
|
||||
reg = <0 0x11004000 0 0x100>;
|
||||
interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "uart", "wakeup";
|
||||
clocks = <&infracfg CLK_INFRA_UART2_SEL>,
|
||||
<&infracfg CLK_INFRA_UART2_CK>;
|
||||
clock-names = "baud", "bus";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
i2c@11007000 {
|
||||
compatible = "mediatek,mt7981-i2c";
|
||||
reg = <0 0x11007000 0 0x1000>,
|
||||
|
||||
+2
-2
@@ -555,7 +555,7 @@ retry:
|
||||
|
||||
/* if claiming is already in progress, wait for it to finish */
|
||||
if (whole->bd_claiming) {
|
||||
wait_queue_head_t *wq = bit_waitqueue(&whole->bd_claiming, 0);
|
||||
wait_queue_head_t *wq = __var_waitqueue(&whole->bd_claiming);
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
|
||||
@@ -578,7 +578,7 @@ static void bd_clear_claiming(struct block_device *whole, void *holder)
|
||||
/* tell others that we're done */
|
||||
BUG_ON(whole->bd_claiming != holder);
|
||||
whole->bd_claiming = NULL;
|
||||
wake_up_bit(&whole->bd_claiming, 0);
|
||||
wake_up_var(&whole->bd_claiming);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -367,7 +367,6 @@ free_bvec:
|
||||
kfree(bvec);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bio_integrity_map_user);
|
||||
|
||||
/**
|
||||
* bio_integrity_prep - Prepare bio for integrity I/O
|
||||
|
||||
+25
-11
@@ -53,7 +53,6 @@ new_segment:
|
||||
|
||||
return segments;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_rq_count_integrity_sg);
|
||||
|
||||
/**
|
||||
* blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist
|
||||
@@ -63,19 +62,20 @@ EXPORT_SYMBOL(blk_rq_count_integrity_sg);
|
||||
*
|
||||
* Description: Map the integrity vectors in request into a
|
||||
* scatterlist. The scatterlist must be big enough to hold all
|
||||
* elements. I.e. sized using blk_rq_count_integrity_sg().
|
||||
* elements. I.e. sized using blk_rq_count_integrity_sg() or
|
||||
* rq->nr_integrity_segments.
|
||||
*/
|
||||
int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio,
|
||||
struct scatterlist *sglist)
|
||||
int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist)
|
||||
{
|
||||
struct bio_vec iv, ivprv = { NULL };
|
||||
struct request_queue *q = rq->q;
|
||||
struct scatterlist *sg = NULL;
|
||||
struct bio *bio = rq->bio;
|
||||
unsigned int segments = 0;
|
||||
struct bvec_iter iter;
|
||||
int prev = 0;
|
||||
|
||||
bio_for_each_integrity_vec(iv, bio, iter) {
|
||||
|
||||
if (prev) {
|
||||
if (!biovec_phys_mergeable(q, &ivprv, &iv))
|
||||
goto new_segment;
|
||||
@@ -103,10 +103,30 @@ new_segment:
|
||||
if (sg)
|
||||
sg_mark_end(sg);
|
||||
|
||||
/*
|
||||
* Something must have been wrong if the figured number of segment
|
||||
* is bigger than number of req's physical integrity segments
|
||||
*/
|
||||
BUG_ON(segments > rq->nr_integrity_segments);
|
||||
BUG_ON(segments > queue_max_integrity_segments(q));
|
||||
return segments;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_rq_map_integrity_sg);
|
||||
|
||||
int blk_rq_integrity_map_user(struct request *rq, void __user *ubuf,
|
||||
ssize_t bytes, u32 seed)
|
||||
{
|
||||
int ret = bio_integrity_map_user(rq->bio, ubuf, bytes, seed);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rq->nr_integrity_segments = blk_rq_count_integrity_sg(rq->q, rq->bio);
|
||||
rq->cmd_flags |= REQ_INTEGRITY;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_rq_integrity_map_user);
|
||||
|
||||
bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
|
||||
struct request *next)
|
||||
{
|
||||
@@ -134,7 +154,6 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
|
||||
struct bio *bio)
|
||||
{
|
||||
int nr_integrity_segs;
|
||||
struct bio *next = bio->bi_next;
|
||||
|
||||
if (blk_integrity_rq(req) == 0 && bio_integrity(bio) == NULL)
|
||||
return true;
|
||||
@@ -145,16 +164,11 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
|
||||
if (bio_integrity(req->bio)->bip_flags != bio_integrity(bio)->bip_flags)
|
||||
return false;
|
||||
|
||||
bio->bi_next = NULL;
|
||||
nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
|
||||
bio->bi_next = next;
|
||||
|
||||
if (req->nr_integrity_segments + nr_integrity_segs >
|
||||
q->limits.max_integrity_segments)
|
||||
return false;
|
||||
|
||||
req->nr_integrity_segments += nr_integrity_segs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -639,6 +639,9 @@ static inline int ll_new_hw_segment(struct request *req, struct bio *bio,
|
||||
* counters.
|
||||
*/
|
||||
req->nr_phys_segments += nr_phys_segs;
|
||||
if (bio_integrity(bio))
|
||||
req->nr_integrity_segments += blk_rq_count_integrity_sg(req->q,
|
||||
bio);
|
||||
return 1;
|
||||
|
||||
no_merge:
|
||||
@@ -731,6 +734,7 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
|
||||
|
||||
/* Merge is OK... */
|
||||
req->nr_phys_segments = total_phys_segments;
|
||||
req->nr_integrity_segments += next->nr_integrity_segments;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -376,9 +376,7 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data,
|
||||
rq->io_start_time_ns = 0;
|
||||
rq->stats_sectors = 0;
|
||||
rq->nr_phys_segments = 0;
|
||||
#if defined(CONFIG_BLK_DEV_INTEGRITY)
|
||||
rq->nr_integrity_segments = 0;
|
||||
#endif
|
||||
rq->end_io = NULL;
|
||||
rq->end_io_data = NULL;
|
||||
|
||||
@@ -2546,6 +2544,9 @@ static void blk_mq_bio_to_request(struct request *rq, struct bio *bio,
|
||||
rq->__sector = bio->bi_iter.bi_sector;
|
||||
rq->write_hint = bio->bi_write_hint;
|
||||
blk_rq_bio_prep(rq, bio, nr_segs);
|
||||
if (bio_integrity(bio))
|
||||
rq->nr_integrity_segments = blk_rq_count_integrity_sg(rq->q,
|
||||
bio);
|
||||
|
||||
/* This can't fail, since GFP_NOIO includes __GFP_DIRECT_RECLAIM. */
|
||||
err = blk_crypto_rq_bio_prep(rq, bio, GFP_NOIO);
|
||||
|
||||
@@ -437,48 +437,6 @@ int queue_limits_set(struct request_queue *q, struct queue_limits *lim)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(queue_limits_set);
|
||||
|
||||
/**
|
||||
* blk_limits_io_min - set minimum request size for a device
|
||||
* @limits: the queue limits
|
||||
* @min: smallest I/O size in bytes
|
||||
*
|
||||
* Description:
|
||||
* Some devices have an internal block size bigger than the reported
|
||||
* hardware sector size. This function can be used to signal the
|
||||
* smallest I/O the device can perform without incurring a performance
|
||||
* penalty.
|
||||
*/
|
||||
void blk_limits_io_min(struct queue_limits *limits, unsigned int min)
|
||||
{
|
||||
limits->io_min = min;
|
||||
|
||||
if (limits->io_min < limits->logical_block_size)
|
||||
limits->io_min = limits->logical_block_size;
|
||||
|
||||
if (limits->io_min < limits->physical_block_size)
|
||||
limits->io_min = limits->physical_block_size;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_limits_io_min);
|
||||
|
||||
/**
|
||||
* blk_limits_io_opt - set optimal request size for a device
|
||||
* @limits: the queue limits
|
||||
* @opt: smallest I/O size in bytes
|
||||
*
|
||||
* Description:
|
||||
* Storage devices may report an optimal I/O size, which is the
|
||||
* device's preferred unit for sustained I/O. This is rarely reported
|
||||
* for disk drives. For RAID arrays it is usually the stripe width or
|
||||
* the internal track size. A properly aligned multiple of
|
||||
* optimal_io_size is the preferred request size for workloads where
|
||||
* sustained throughput is desired.
|
||||
*/
|
||||
void blk_limits_io_opt(struct queue_limits *limits, unsigned int opt)
|
||||
{
|
||||
limits->io_opt = opt;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_limits_io_opt);
|
||||
|
||||
static int queue_limit_alignment_offset(const struct queue_limits *lim,
|
||||
sector_t sector)
|
||||
{
|
||||
|
||||
+3
-1
@@ -715,7 +715,9 @@ int elv_iosched_load_module(struct gendisk *disk, const char *buf,
|
||||
|
||||
strscpy(elevator_name, buf, sizeof(elevator_name));
|
||||
|
||||
return request_module("%s-iosched", strstrip(elevator_name));
|
||||
request_module("%s-iosched", strstrip(elevator_name));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
||||
|
||||
@@ -3399,10 +3399,12 @@ void drbd_uuid_new_current(struct drbd_device *device) __must_hold(local)
|
||||
void drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local)
|
||||
{
|
||||
unsigned long flags;
|
||||
if (device->ldev->md.uuid[UI_BITMAP] == 0 && val == 0)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&device->ldev->md.uuid_lock, flags);
|
||||
if (device->ldev->md.uuid[UI_BITMAP] == 0 && val == 0) {
|
||||
spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (val == 0) {
|
||||
drbd_uuid_move_history(device);
|
||||
device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[UI_BITMAP];
|
||||
|
||||
@@ -452,7 +452,7 @@ static void fw_cfg_sysfs_release_entry(struct kobject *kobj)
|
||||
}
|
||||
|
||||
/* kobj_type: ties together all properties required to register an entry */
|
||||
static struct kobj_type fw_cfg_sysfs_entry_ktype = {
|
||||
static const struct kobj_type fw_cfg_sysfs_entry_ktype = {
|
||||
.default_groups = fw_cfg_sysfs_entry_groups,
|
||||
.sysfs_ops = &fw_cfg_sysfs_attr_ops,
|
||||
.release = fw_cfg_sysfs_release_entry,
|
||||
|
||||
@@ -786,14 +786,6 @@ static const struct acpi_device_id goodix_spi_acpi_match[] = {
|
||||
MODULE_DEVICE_TABLE(acpi, goodix_spi_acpi_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id goodix_spi_of_match[] = {
|
||||
{ .compatible = "goodix,gt7986u", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, goodix_spi_of_match);
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id goodix_spi_ids[] = {
|
||||
{ "gt7986u" },
|
||||
{ },
|
||||
@@ -804,7 +796,6 @@ static struct spi_driver goodix_spi_driver = {
|
||||
.driver = {
|
||||
.name = "goodix-spi-hid",
|
||||
.acpi_match_table = ACPI_PTR(goodix_spi_acpi_match),
|
||||
.of_match_table = of_match_ptr(goodix_spi_of_match),
|
||||
.pm = pm_sleep_ptr(&goodix_spi_pm_ops),
|
||||
},
|
||||
.probe = goodix_spi_probe,
|
||||
|
||||
@@ -1887,10 +1887,12 @@ static int cmd_exec(struct mlx5_core_dev *dev, void *in, int in_size, void *out,
|
||||
|
||||
throttle_op = mlx5_cmd_is_throttle_opcode(opcode);
|
||||
if (throttle_op) {
|
||||
/* atomic context may not sleep */
|
||||
if (callback)
|
||||
return -EINVAL;
|
||||
down(&dev->cmd.vars.throttle_sem);
|
||||
if (callback) {
|
||||
if (down_trylock(&dev->cmd.vars.throttle_sem))
|
||||
return -EBUSY;
|
||||
} else {
|
||||
down(&dev->cmd.vars.throttle_sem);
|
||||
}
|
||||
}
|
||||
|
||||
pages_queue = is_manage_pages(in);
|
||||
@@ -2096,10 +2098,19 @@ static void mlx5_cmd_exec_cb_handler(int status, void *_work)
|
||||
{
|
||||
struct mlx5_async_work *work = _work;
|
||||
struct mlx5_async_ctx *ctx;
|
||||
struct mlx5_core_dev *dev;
|
||||
u16 opcode;
|
||||
|
||||
ctx = work->ctx;
|
||||
status = cmd_status_err(ctx->dev, status, work->opcode, work->op_mod, work->out);
|
||||
dev = ctx->dev;
|
||||
opcode = work->opcode;
|
||||
status = cmd_status_err(dev, status, work->opcode, work->op_mod, work->out);
|
||||
work->user_callback(status, work);
|
||||
/* Can't access "work" from this point on. It could have been freed in
|
||||
* the callback.
|
||||
*/
|
||||
if (mlx5_cmd_is_throttle_opcode(opcode))
|
||||
up(&dev->cmd.vars.throttle_sem);
|
||||
if (atomic_dec_and_test(&ctx->num_inflight))
|
||||
complete(&ctx->inflight_done);
|
||||
}
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/refcount.h>
|
||||
|
||||
#define SIXPACK_VERSION "Revision: 0.3.0"
|
||||
|
||||
/* sixpack priority commands */
|
||||
#define SIXP_SEOF 0x40 /* start and end of a 6pack frame */
|
||||
#define SIXP_TX_URUN 0x48 /* transmit overrun */
|
||||
@@ -88,22 +86,18 @@ struct sixpack {
|
||||
struct net_device *dev; /* easy for intr handling */
|
||||
|
||||
/* These are pointers to the malloc()ed frame buffers. */
|
||||
unsigned char *rbuff; /* receiver buffer */
|
||||
int rcount; /* received chars counter */
|
||||
unsigned char *xbuff; /* transmitter buffer */
|
||||
unsigned char *xhead; /* next byte to XMIT */
|
||||
int xleft; /* bytes left in XMIT queue */
|
||||
|
||||
unsigned char raw_buf[4];
|
||||
unsigned char cooked_buf[400];
|
||||
u8 raw_buf[4];
|
||||
u8 cooked_buf[400];
|
||||
|
||||
unsigned int rx_count;
|
||||
unsigned int rx_count_cooked;
|
||||
spinlock_t rxlock;
|
||||
|
||||
int mtu; /* Our mtu (to spot changes!) */
|
||||
int buffsize; /* Max buffers sizes */
|
||||
|
||||
unsigned long flags; /* Flag values/ mode etc */
|
||||
unsigned char mode; /* 6pack mode */
|
||||
|
||||
@@ -113,8 +107,8 @@ struct sixpack {
|
||||
unsigned char slottime;
|
||||
unsigned char duplex;
|
||||
unsigned char led_state;
|
||||
unsigned char status;
|
||||
unsigned char status1;
|
||||
u8 status;
|
||||
u8 status1;
|
||||
unsigned char status2;
|
||||
unsigned char tx_enable;
|
||||
unsigned char tnc_state;
|
||||
@@ -128,7 +122,7 @@ struct sixpack {
|
||||
|
||||
#define AX25_6PACK_HEADER_LEN 0
|
||||
|
||||
static void sixpack_decode(struct sixpack *, const unsigned char[], int);
|
||||
static void sixpack_decode(struct sixpack *, const u8 *, size_t);
|
||||
static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
|
||||
|
||||
/*
|
||||
@@ -167,7 +161,7 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
|
||||
unsigned char *msg, *p = icp;
|
||||
int actual, count;
|
||||
|
||||
if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
|
||||
if (len > AX25_MTU + 73) {
|
||||
msg = "oversized transmit packet!";
|
||||
goto out_drop;
|
||||
}
|
||||
@@ -333,7 +327,7 @@ static void sp_bump(struct sixpack *sp, char cmd)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int count;
|
||||
unsigned char *ptr;
|
||||
u8 *ptr;
|
||||
|
||||
count = sp->rcount + 1;
|
||||
|
||||
@@ -431,7 +425,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, const u8 *cp,
|
||||
const u8 *fp, size_t count)
|
||||
{
|
||||
struct sixpack *sp;
|
||||
int count1;
|
||||
size_t count1;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
@@ -544,7 +538,7 @@ static inline int tnc_init(struct sixpack *sp)
|
||||
*/
|
||||
static int sixpack_open(struct tty_struct *tty)
|
||||
{
|
||||
char *rbuff = NULL, *xbuff = NULL;
|
||||
char *xbuff = NULL;
|
||||
struct net_device *dev;
|
||||
struct sixpack *sp;
|
||||
unsigned long len;
|
||||
@@ -574,10 +568,8 @@ static int sixpack_open(struct tty_struct *tty)
|
||||
|
||||
len = dev->mtu * 2;
|
||||
|
||||
rbuff = kmalloc(len + 4, GFP_KERNEL);
|
||||
xbuff = kmalloc(len + 4, GFP_KERNEL);
|
||||
|
||||
if (rbuff == NULL || xbuff == NULL) {
|
||||
if (xbuff == NULL) {
|
||||
err = -ENOBUFS;
|
||||
goto out_free;
|
||||
}
|
||||
@@ -586,11 +578,8 @@ static int sixpack_open(struct tty_struct *tty)
|
||||
|
||||
sp->tty = tty;
|
||||
|
||||
sp->rbuff = rbuff;
|
||||
sp->xbuff = xbuff;
|
||||
|
||||
sp->mtu = AX25_MTU + 73;
|
||||
sp->buffsize = len;
|
||||
sp->rcount = 0;
|
||||
sp->rx_count = 0;
|
||||
sp->rx_count_cooked = 0;
|
||||
@@ -631,7 +620,6 @@ static int sixpack_open(struct tty_struct *tty)
|
||||
|
||||
out_free:
|
||||
kfree(xbuff);
|
||||
kfree(rbuff);
|
||||
|
||||
free_netdev(dev);
|
||||
|
||||
@@ -676,7 +664,6 @@ static void sixpack_close(struct tty_struct *tty)
|
||||
del_timer_sync(&sp->resync_t);
|
||||
|
||||
/* Free all 6pack frame buffers after unreg. */
|
||||
kfree(sp->rbuff);
|
||||
kfree(sp->xbuff);
|
||||
|
||||
free_netdev(sp->dev);
|
||||
@@ -756,21 +743,14 @@ static struct tty_ldisc_ops sp_ldisc = {
|
||||
|
||||
/* Initialize 6pack control device -- register 6pack line discipline */
|
||||
|
||||
static const char msg_banner[] __initconst = KERN_INFO \
|
||||
"AX.25: 6pack driver, " SIXPACK_VERSION "\n";
|
||||
static const char msg_regfail[] __initconst = KERN_ERR \
|
||||
"6pack: can't register line discipline (err = %d)\n";
|
||||
|
||||
static int __init sixpack_init_driver(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
printk(msg_banner);
|
||||
|
||||
/* Register the provided line protocol discipline */
|
||||
status = tty_register_ldisc(&sp_ldisc);
|
||||
if (status)
|
||||
printk(msg_regfail, status);
|
||||
pr_err("6pack: can't register line discipline (err = %d)\n", status);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -820,9 +800,9 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
|
||||
|
||||
/* decode 4 sixpack-encoded bytes into 3 data bytes */
|
||||
|
||||
static void decode_data(struct sixpack *sp, unsigned char inbyte)
|
||||
static void decode_data(struct sixpack *sp, u8 inbyte)
|
||||
{
|
||||
unsigned char *buf;
|
||||
u8 *buf;
|
||||
|
||||
if (sp->rx_count != 3) {
|
||||
sp->raw_buf[sp->rx_count++] = inbyte;
|
||||
@@ -848,9 +828,9 @@ static void decode_data(struct sixpack *sp, unsigned char inbyte)
|
||||
|
||||
/* identify and execute a 6pack priority command byte */
|
||||
|
||||
static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
|
||||
static void decode_prio_command(struct sixpack *sp, u8 cmd)
|
||||
{
|
||||
int actual;
|
||||
ssize_t actual;
|
||||
|
||||
if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */
|
||||
|
||||
@@ -898,9 +878,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd)
|
||||
|
||||
/* identify and execute a standard 6pack command byte */
|
||||
|
||||
static void decode_std_command(struct sixpack *sp, unsigned char cmd)
|
||||
static void decode_std_command(struct sixpack *sp, u8 cmd)
|
||||
{
|
||||
unsigned char checksum = 0, rest = 0;
|
||||
u8 checksum = 0, rest = 0;
|
||||
short i;
|
||||
|
||||
switch (cmd & SIXP_CMD_MASK) { /* normal command */
|
||||
@@ -948,10 +928,10 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd)
|
||||
/* decode a 6pack packet */
|
||||
|
||||
static void
|
||||
sixpack_decode(struct sixpack *sp, const unsigned char *pre_rbuff, int count)
|
||||
sixpack_decode(struct sixpack *sp, const u8 *pre_rbuff, size_t count)
|
||||
{
|
||||
unsigned char inbyte;
|
||||
int count1;
|
||||
size_t count1;
|
||||
u8 inbyte;
|
||||
|
||||
for (count1 = 0; count1 < count; count1++) {
|
||||
inbyte = pre_rbuff[count1];
|
||||
|
||||
@@ -64,18 +64,18 @@ struct mctp_serial {
|
||||
u16 txfcs, rxfcs, rxfcs_rcvd;
|
||||
unsigned int txlen, rxlen;
|
||||
unsigned int txpos, rxpos;
|
||||
unsigned char txbuf[BUFSIZE],
|
||||
u8 txbuf[BUFSIZE],
|
||||
rxbuf[BUFSIZE];
|
||||
};
|
||||
|
||||
static bool needs_escape(unsigned char c)
|
||||
static bool needs_escape(u8 c)
|
||||
{
|
||||
return c == BYTE_ESC || c == BYTE_FRAME;
|
||||
}
|
||||
|
||||
static int next_chunk_len(struct mctp_serial *dev)
|
||||
static unsigned int next_chunk_len(struct mctp_serial *dev)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
/* either we have no bytes to send ... */
|
||||
if (dev->txpos == dev->txlen)
|
||||
@@ -99,7 +99,7 @@ static int next_chunk_len(struct mctp_serial *dev)
|
||||
return i;
|
||||
}
|
||||
|
||||
static int write_chunk(struct mctp_serial *dev, unsigned char *buf, int len)
|
||||
static ssize_t write_chunk(struct mctp_serial *dev, u8 *buf, size_t len)
|
||||
{
|
||||
return dev->tty->ops->write(dev->tty, buf, len);
|
||||
}
|
||||
@@ -108,9 +108,10 @@ static void mctp_serial_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct mctp_serial *dev = container_of(work, struct mctp_serial,
|
||||
tx_work);
|
||||
unsigned char c, buf[3];
|
||||
unsigned long flags;
|
||||
int len, txlen;
|
||||
ssize_t txlen;
|
||||
unsigned int len;
|
||||
u8 c, buf[3];
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
@@ -293,7 +294,7 @@ static void mctp_serial_rx(struct mctp_serial *dev)
|
||||
dev->netdev->stats.rx_bytes += dev->rxlen;
|
||||
}
|
||||
|
||||
static void mctp_serial_push_header(struct mctp_serial *dev, unsigned char c)
|
||||
static void mctp_serial_push_header(struct mctp_serial *dev, u8 c)
|
||||
{
|
||||
switch (dev->rxpos) {
|
||||
case 0:
|
||||
@@ -323,7 +324,7 @@ static void mctp_serial_push_header(struct mctp_serial *dev, unsigned char c)
|
||||
}
|
||||
}
|
||||
|
||||
static void mctp_serial_push_trailer(struct mctp_serial *dev, unsigned char c)
|
||||
static void mctp_serial_push_trailer(struct mctp_serial *dev, u8 c)
|
||||
{
|
||||
switch (dev->rxpos) {
|
||||
case 0:
|
||||
@@ -347,7 +348,7 @@ static void mctp_serial_push_trailer(struct mctp_serial *dev, unsigned char c)
|
||||
}
|
||||
}
|
||||
|
||||
static void mctp_serial_push(struct mctp_serial *dev, unsigned char c)
|
||||
static void mctp_serial_push(struct mctp_serial *dev, u8 c)
|
||||
{
|
||||
switch (dev->rxstate) {
|
||||
case STATE_IDLE:
|
||||
@@ -394,7 +395,7 @@ static void mctp_serial_tty_receive_buf(struct tty_struct *tty, const u8 *c,
|
||||
const u8 *f, size_t len)
|
||||
{
|
||||
struct mctp_serial *dev = tty->disc_data;
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
if (!netif_running(dev->netdev))
|
||||
return;
|
||||
|
||||
@@ -44,6 +44,15 @@ static int virtio_pmem_flush(struct nd_region *nd_region)
|
||||
unsigned long flags;
|
||||
int err, err1;
|
||||
|
||||
/*
|
||||
* Don't bother to submit the request to the device if the device is
|
||||
* not activated.
|
||||
*/
|
||||
if (vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_NEEDS_RESET) {
|
||||
dev_info(&vdev->dev, "virtio pmem device needs a reset\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
might_sleep();
|
||||
req_data = kmalloc(sizeof(*req_data), GFP_KERNEL);
|
||||
if (!req_data)
|
||||
|
||||
@@ -2468,11 +2468,6 @@ int nvme_enable_ctrl(struct nvme_ctrl *ctrl)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Flush write to device (required if transport is PCI) */
|
||||
ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CC, &ctrl->ctrl_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* CAP value may change after initial CC write */
|
||||
ret = ctrl->ops->reg_read64(ctrl, NVME_REG_CAP, &ctrl->cap);
|
||||
if (ret)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Copyright (c) 2011-2014, Intel Corporation.
|
||||
* Copyright (c) 2017-2021 Christoph Hellwig.
|
||||
*/
|
||||
#include <linux/bio-integrity.h>
|
||||
#include <linux/blk-integrity.h>
|
||||
#include <linux/ptrace.h> /* for force_successful_syscall_return */
|
||||
#include <linux/nvme_ioctl.h>
|
||||
@@ -153,11 +152,10 @@ static int nvme_map_user_request(struct request *req, u64 ubuffer,
|
||||
bio_set_dev(bio, bdev);
|
||||
|
||||
if (has_metadata) {
|
||||
ret = bio_integrity_map_user(bio, meta_buffer, meta_len,
|
||||
meta_seed);
|
||||
ret = blk_rq_integrity_map_user(req, meta_buffer, meta_len,
|
||||
meta_seed);
|
||||
if (ret)
|
||||
goto out_unmap;
|
||||
req->cmd_flags |= REQ_INTEGRITY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -421,6 +421,9 @@ static bool nvme_available_path(struct nvme_ns_head *head)
|
||||
{
|
||||
struct nvme_ns *ns;
|
||||
|
||||
if (!test_bit(NVME_NSHEAD_DISK_LIVE, &head->flags))
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry_rcu(ns, &head->list, siblings) {
|
||||
if (test_bit(NVME_CTRL_FAILFAST_EXPIRED, &ns->ctrl->flags))
|
||||
continue;
|
||||
@@ -648,7 +651,7 @@ static void nvme_mpath_set_live(struct nvme_ns *ns)
|
||||
rc = device_add_disk(&head->subsys->dev, head->disk,
|
||||
nvme_ns_attr_groups);
|
||||
if (rc) {
|
||||
clear_bit(NVME_NSHEAD_DISK_LIVE, &ns->flags);
|
||||
clear_bit(NVME_NSHEAD_DISK_LIVE, &head->flags);
|
||||
return;
|
||||
}
|
||||
nvme_add_ns_head_cdev(head);
|
||||
@@ -969,11 +972,16 @@ void nvme_mpath_shutdown_disk(struct nvme_ns_head *head)
|
||||
{
|
||||
if (!head->disk)
|
||||
return;
|
||||
kblockd_schedule_work(&head->requeue_work);
|
||||
if (test_bit(NVME_NSHEAD_DISK_LIVE, &head->flags)) {
|
||||
if (test_and_clear_bit(NVME_NSHEAD_DISK_LIVE, &head->flags)) {
|
||||
nvme_cdev_del(&head->cdev, &head->cdev_device);
|
||||
del_gendisk(head->disk);
|
||||
}
|
||||
/*
|
||||
* requeue I/O after NVME_NSHEAD_DISK_LIVE has been cleared
|
||||
* to allow multipath to fail all I/O.
|
||||
*/
|
||||
synchronize_srcu(&head->srcu);
|
||||
kblockd_schedule_work(&head->requeue_work);
|
||||
}
|
||||
|
||||
void nvme_mpath_remove_disk(struct nvme_ns_head *head)
|
||||
|
||||
@@ -1496,7 +1496,7 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
|
||||
req->metadata_sgl->sg_table.sgl =
|
||||
(struct scatterlist *)(req->metadata_sgl + 1);
|
||||
ret = sg_alloc_table_chained(&req->metadata_sgl->sg_table,
|
||||
blk_rq_count_integrity_sg(rq->q, rq->bio),
|
||||
rq->nr_integrity_segments,
|
||||
req->metadata_sgl->sg_table.sgl,
|
||||
NVME_INLINE_METADATA_SG_CNT);
|
||||
if (unlikely(ret)) {
|
||||
@@ -1504,8 +1504,8 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
|
||||
goto out_unmap_sg;
|
||||
}
|
||||
|
||||
req->metadata_sgl->nents = blk_rq_map_integrity_sg(rq->q,
|
||||
rq->bio, req->metadata_sgl->sg_table.sgl);
|
||||
req->metadata_sgl->nents = blk_rq_map_integrity_sg(rq,
|
||||
req->metadata_sgl->sg_table.sgl);
|
||||
*pi_count = ib_dma_map_sg(ibdev,
|
||||
req->metadata_sgl->sg_table.sgl,
|
||||
req->metadata_sgl->nents,
|
||||
|
||||
@@ -767,6 +767,7 @@ static struct attribute *nvme_tls_attrs[] = {
|
||||
&dev_attr_tls_key.attr,
|
||||
&dev_attr_tls_configured_key.attr,
|
||||
&dev_attr_tls_keyring.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static umode_t nvme_tls_attrs_are_visible(struct kobject *kobj,
|
||||
|
||||
@@ -743,6 +743,16 @@ config RTC_DRV_S5M
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-s5m.
|
||||
|
||||
config RTC_DRV_SD2405AL
|
||||
tristate "DFRobot SD2405AL"
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
DFRobot SD2405AL I2C RTC Module.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-sd2405al.
|
||||
|
||||
config RTC_DRV_SD3078
|
||||
tristate "ZXW Shenzhen whwave SD3078"
|
||||
select REGMAP_I2C
|
||||
@@ -1934,6 +1944,12 @@ config RTC_DRV_STM32
|
||||
tristate "STM32 RTC"
|
||||
select REGMAP_MMIO
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on PINCTRL
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
If you say yes here you get support for the STM32 On-Chip
|
||||
Real Time Clock.
|
||||
|
||||
@@ -163,6 +163,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
|
||||
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
|
||||
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
|
||||
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
|
||||
obj-$(CONFIG_RTC_DRV_SD2405AL) += rtc-sd2405al.o
|
||||
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
|
||||
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
|
||||
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
|
||||
|
||||
@@ -368,6 +368,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
rtc->gpbr = syscon_node_to_regmap(args.np);
|
||||
of_node_put(args.np);
|
||||
rtc->gpbr_offset = args.args[0];
|
||||
if (IS_ERR(rtc->gpbr)) {
|
||||
dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
|
||||
|
||||
@@ -132,7 +132,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
M48T59_WRITE((bin2bcd(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
|
||||
M48T59_WRITE(bin2bcd(year % 100), M48T59_YEAR);
|
||||
|
||||
if (pdata->type == M48T59RTC_TYPE_M48T59 && (year / 100))
|
||||
if (pdata->type == M48T59RTC_TYPE_M48T59 && (year >= 100))
|
||||
val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
|
||||
val |= (bin2bcd(tm->tm_wday) & 0x07);
|
||||
M48T59_WRITE(val, M48T59_WDAY);
|
||||
@@ -458,6 +458,8 @@ static int m48t59_rtc_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, m48t59);
|
||||
|
||||
m48t59->rtc->ops = &m48t59_rtc_ops;
|
||||
m48t59->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
m48t59->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
nvmem_cfg.size = pdata->offset;
|
||||
ret = devm_rtc_nvmem_register(m48t59->rtc, &nvmem_cfg);
|
||||
|
||||
@@ -429,14 +429,23 @@ static int rc5t619_rtc_probe(struct platform_device *pdev)
|
||||
return devm_rtc_register_device(rtc->rtc);
|
||||
}
|
||||
|
||||
static const struct platform_device_id rc5t619_rtc_id[] = {
|
||||
{
|
||||
.name = "rc5t619-rtc",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, rc5t619_rtc_id);
|
||||
|
||||
static struct platform_driver rc5t619_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "rc5t619-rtc",
|
||||
},
|
||||
.probe = rc5t619_rtc_probe,
|
||||
.id_table = rc5t619_rtc_id,
|
||||
};
|
||||
|
||||
module_platform_driver(rc5t619_rtc_driver);
|
||||
MODULE_ALIAS("platform:rc5t619-rtc");
|
||||
|
||||
MODULE_DESCRIPTION("RICOH RC5T619 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -56,7 +56,6 @@ static const struct i2c_device_id s35390a_id[] = {
|
||||
MODULE_DEVICE_TABLE(i2c, s35390a_id);
|
||||
|
||||
static const __maybe_unused struct of_device_id s35390a_of_match[] = {
|
||||
{ .compatible = "s35390a" },
|
||||
{ .compatible = "sii,s35390a" },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* RTC driver for the SD2405AL Real-Time Clock
|
||||
*
|
||||
* Datasheet:
|
||||
* https://image.dfrobot.com/image/data/TOY0021/SD2405AL%20datasheet%20(Angelo%20v0.1).pdf
|
||||
*
|
||||
* Copyright (C) 2024 Tóth János <gomba007@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/* Real time clock registers */
|
||||
#define SD2405AL_REG_T_SEC 0x00
|
||||
#define SD2405AL_REG_T_MIN 0x01
|
||||
#define SD2405AL_REG_T_HOUR 0x02
|
||||
# define SD2405AL_BIT_12H_PM BIT(5)
|
||||
# define SD2405AL_BIT_24H BIT(7)
|
||||
#define SD2405AL_REG_T_WEEK 0x03
|
||||
#define SD2405AL_REG_T_DAY 0x04
|
||||
#define SD2405AL_REG_T_MON 0x05
|
||||
#define SD2405AL_REG_T_YEAR 0x06
|
||||
|
||||
#define SD2405AL_NUM_T_REGS (SD2405AL_REG_T_YEAR - SD2405AL_REG_T_SEC + 1)
|
||||
|
||||
/* Control registers */
|
||||
#define SD2405AL_REG_CTR1 0x0F
|
||||
# define SD2405AL_BIT_WRTC2 BIT(2)
|
||||
# define SD2405AL_BIT_WRTC3 BIT(7)
|
||||
#define SD2405AL_REG_CTR2 0x10
|
||||
# define SD2405AL_BIT_WRTC1 BIT(7)
|
||||
#define SD2405AL_REG_CTR3 0x11
|
||||
#define SD2405AL_REG_TTF 0x12
|
||||
#define SD2405AL_REG_CNTDWN 0x13
|
||||
|
||||
/* General RAM */
|
||||
#define SD2405AL_REG_M_START 0x14
|
||||
#define SD2405AL_REG_M_END 0x1F
|
||||
|
||||
struct sd2405al {
|
||||
struct device *dev;
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int sd2405al_enable_reg_write(struct sd2405al *sd2405al)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* order of writes is important */
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR2,
|
||||
SD2405AL_BIT_WRTC1, SD2405AL_BIT_WRTC1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR1,
|
||||
SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3,
|
||||
SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd2405al_disable_reg_write(struct sd2405al *sd2405al)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* order of writes is important */
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR1,
|
||||
SD2405AL_BIT_WRTC2 | SD2405AL_BIT_WRTC3, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(sd2405al->regmap, SD2405AL_REG_CTR2,
|
||||
SD2405AL_BIT_WRTC1, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd2405al_read_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
u8 data[SD2405AL_NUM_T_REGS] = { 0 };
|
||||
struct sd2405al *sd2405al = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(sd2405al->regmap, SD2405AL_REG_T_SEC, data,
|
||||
SD2405AL_NUM_T_REGS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
time->tm_sec = bcd2bin(data[SD2405AL_REG_T_SEC] & 0x7F);
|
||||
time->tm_min = bcd2bin(data[SD2405AL_REG_T_MIN] & 0x7F);
|
||||
|
||||
if (data[SD2405AL_REG_T_HOUR] & SD2405AL_BIT_24H)
|
||||
time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR] & 0x3F);
|
||||
else
|
||||
if (data[SD2405AL_REG_T_HOUR] & SD2405AL_BIT_12H_PM)
|
||||
time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR]
|
||||
& 0x1F) + 12;
|
||||
else /* 12 hour mode, AM */
|
||||
time->tm_hour = bcd2bin(data[SD2405AL_REG_T_HOUR]
|
||||
& 0x1F);
|
||||
|
||||
time->tm_wday = bcd2bin(data[SD2405AL_REG_T_WEEK] & 0x07);
|
||||
time->tm_mday = bcd2bin(data[SD2405AL_REG_T_DAY] & 0x3F);
|
||||
time->tm_mon = bcd2bin(data[SD2405AL_REG_T_MON] & 0x1F) - 1;
|
||||
time->tm_year = bcd2bin(data[SD2405AL_REG_T_YEAR]) + 100;
|
||||
|
||||
dev_dbg(sd2405al->dev, "read time: %ptR (%d)\n", time, time->tm_wday);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sd2405al_set_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
u8 data[SD2405AL_NUM_T_REGS];
|
||||
struct sd2405al *sd2405al = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
data[SD2405AL_REG_T_SEC] = bin2bcd(time->tm_sec);
|
||||
data[SD2405AL_REG_T_MIN] = bin2bcd(time->tm_min);
|
||||
data[SD2405AL_REG_T_HOUR] = bin2bcd(time->tm_hour) | SD2405AL_BIT_24H;
|
||||
data[SD2405AL_REG_T_DAY] = bin2bcd(time->tm_mday);
|
||||
data[SD2405AL_REG_T_WEEK] = bin2bcd(time->tm_wday);
|
||||
data[SD2405AL_REG_T_MON] = bin2bcd(time->tm_mon) + 1;
|
||||
data[SD2405AL_REG_T_YEAR] = bin2bcd(time->tm_year - 100);
|
||||
|
||||
ret = sd2405al_enable_reg_write(sd2405al);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_write(sd2405al->regmap, SD2405AL_REG_T_SEC, data,
|
||||
SD2405AL_NUM_T_REGS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(sd2405al->regmap, SD2405AL_REG_TTF, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = sd2405al_disable_reg_write(sd2405al);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(sd2405al->dev, "set time: %ptR (%d)\n", time, time->tm_wday);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops sd2405al_rtc_ops = {
|
||||
.read_time = sd2405al_read_time,
|
||||
.set_time = sd2405al_set_time,
|
||||
};
|
||||
|
||||
static const struct regmap_config sd2405al_regmap_conf = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = SD2405AL_REG_M_END,
|
||||
};
|
||||
|
||||
static int sd2405al_probe(struct i2c_client *client)
|
||||
{
|
||||
struct sd2405al *sd2405al;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return -ENODEV;
|
||||
|
||||
sd2405al = devm_kzalloc(&client->dev, sizeof(*sd2405al), GFP_KERNEL);
|
||||
if (!sd2405al)
|
||||
return -ENOMEM;
|
||||
|
||||
sd2405al->dev = &client->dev;
|
||||
|
||||
sd2405al->regmap = devm_regmap_init_i2c(client, &sd2405al_regmap_conf);
|
||||
if (IS_ERR(sd2405al->regmap))
|
||||
return PTR_ERR(sd2405al->regmap);
|
||||
|
||||
sd2405al->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(sd2405al->rtc))
|
||||
return PTR_ERR(sd2405al->rtc);
|
||||
|
||||
sd2405al->rtc->ops = &sd2405al_rtc_ops;
|
||||
sd2405al->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
sd2405al->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
dev_set_drvdata(&client->dev, sd2405al);
|
||||
|
||||
ret = devm_rtc_register_device(sd2405al->rtc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sd2405al_id[] = {
|
||||
{ "sd2405al" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sd2405al_id);
|
||||
|
||||
static const __maybe_unused struct of_device_id sd2405al_of_match[] = {
|
||||
{ .compatible = "dfrobot,sd2405al" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sd2405al_of_match);
|
||||
|
||||
static struct i2c_driver sd2405al_driver = {
|
||||
.driver = {
|
||||
.name = "sd2405al",
|
||||
.of_match_table = of_match_ptr(sd2405al_of_match),
|
||||
},
|
||||
.probe = sd2405al_probe,
|
||||
.id_table = sd2405al_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(sd2405al_driver);
|
||||
|
||||
MODULE_AUTHOR("Tóth János <gomba007@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SD2405AL RTC driver");
|
||||
@@ -7,12 +7,16 @@
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -42,6 +46,12 @@
|
||||
#define STM32_RTC_CR_FMT BIT(6)
|
||||
#define STM32_RTC_CR_ALRAE BIT(8)
|
||||
#define STM32_RTC_CR_ALRAIE BIT(12)
|
||||
#define STM32_RTC_CR_OSEL GENMASK(22, 21)
|
||||
#define STM32_RTC_CR_OSEL_ALARM_A FIELD_PREP(STM32_RTC_CR_OSEL, 0x01)
|
||||
#define STM32_RTC_CR_COE BIT(23)
|
||||
#define STM32_RTC_CR_TAMPOE BIT(26)
|
||||
#define STM32_RTC_CR_TAMPALRM_TYPE BIT(30)
|
||||
#define STM32_RTC_CR_OUT2EN BIT(31)
|
||||
|
||||
/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
|
||||
#define STM32_RTC_ISR_ALRAWF BIT(0)
|
||||
@@ -78,6 +88,12 @@
|
||||
/* STM32_RTC_SR/_SCR bit fields */
|
||||
#define STM32_RTC_SR_ALRA BIT(0)
|
||||
|
||||
/* STM32_RTC_CFGR bit fields */
|
||||
#define STM32_RTC_CFGR_OUT2_RMP BIT(0)
|
||||
#define STM32_RTC_CFGR_LSCOEN GENMASK(2, 1)
|
||||
#define STM32_RTC_CFGR_LSCOEN_OUT1 1
|
||||
#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2
|
||||
|
||||
/* STM32_RTC_VERR bit fields */
|
||||
#define STM32_RTC_VERR_MINREV_SHIFT 0
|
||||
#define STM32_RTC_VERR_MINREV GENMASK(3, 0)
|
||||
@@ -107,6 +123,14 @@
|
||||
/* STM32 RTC driver time helpers */
|
||||
#define SEC_PER_DAY (24 * 60 * 60)
|
||||
|
||||
/* STM32 RTC pinctrl helpers */
|
||||
#define STM32_RTC_PINMUX(_name, _action, ...) { \
|
||||
.name = (_name), \
|
||||
.action = (_action), \
|
||||
.groups = ((const char *[]){ __VA_ARGS__ }), \
|
||||
.num_groups = ARRAY_SIZE(((const char *[]){ __VA_ARGS__ })), \
|
||||
}
|
||||
|
||||
struct stm32_rtc;
|
||||
|
||||
struct stm32_rtc_registers {
|
||||
@@ -119,6 +143,7 @@ struct stm32_rtc_registers {
|
||||
u16 wpr;
|
||||
u16 sr;
|
||||
u16 scr;
|
||||
u16 cfgr;
|
||||
u16 verr;
|
||||
};
|
||||
|
||||
@@ -134,6 +159,8 @@ struct stm32_rtc_data {
|
||||
bool need_dbp;
|
||||
bool need_accuracy;
|
||||
bool rif_protected;
|
||||
bool has_lsco;
|
||||
bool has_alarm_out;
|
||||
};
|
||||
|
||||
struct stm32_rtc {
|
||||
@@ -146,6 +173,7 @@ struct stm32_rtc {
|
||||
struct clk *rtc_ck;
|
||||
const struct stm32_rtc_data *data;
|
||||
int irq_alarm;
|
||||
struct clk *clk_lsco;
|
||||
};
|
||||
|
||||
struct stm32_rtc_rif_resource {
|
||||
@@ -171,6 +199,209 @@ static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
|
||||
writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + regs->wpr);
|
||||
}
|
||||
|
||||
enum stm32_rtc_pin_name {
|
||||
NONE,
|
||||
OUT1,
|
||||
OUT2,
|
||||
OUT2_RMP
|
||||
};
|
||||
|
||||
static const struct pinctrl_pin_desc stm32_rtc_pinctrl_pins[] = {
|
||||
PINCTRL_PIN(OUT1, "out1"),
|
||||
PINCTRL_PIN(OUT2, "out2"),
|
||||
PINCTRL_PIN(OUT2_RMP, "out2_rmp"),
|
||||
};
|
||||
|
||||
static int stm32_rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
return ARRAY_SIZE(stm32_rtc_pinctrl_pins);
|
||||
}
|
||||
|
||||
static const char *stm32_rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector)
|
||||
{
|
||||
return stm32_rtc_pinctrl_pins[selector].name;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector,
|
||||
const unsigned int **pins,
|
||||
unsigned int *num_pins)
|
||||
{
|
||||
*pins = &stm32_rtc_pinctrl_pins[selector].number;
|
||||
*num_pins = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pinctrl_ops stm32_rtc_pinctrl_ops = {
|
||||
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
||||
.dt_free_map = pinconf_generic_dt_free_map,
|
||||
.get_groups_count = stm32_rtc_pinctrl_get_groups_count,
|
||||
.get_group_name = stm32_rtc_pinctrl_get_group_name,
|
||||
.get_group_pins = stm32_rtc_pinctrl_get_group_pins,
|
||||
};
|
||||
|
||||
struct stm32_rtc_pinmux_func {
|
||||
const char *name;
|
||||
const char * const *groups;
|
||||
const unsigned int num_groups;
|
||||
int (*action)(struct pinctrl_dev *pctl_dev, unsigned int pin);
|
||||
};
|
||||
|
||||
static int stm32_rtc_pinmux_action_alarm(struct pinctrl_dev *pctldev, unsigned int pin)
|
||||
{
|
||||
struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
unsigned int cr = readl_relaxed(rtc->base + regs.cr);
|
||||
unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
|
||||
|
||||
if (!rtc->data->has_alarm_out)
|
||||
return -EPERM;
|
||||
|
||||
cr &= ~STM32_RTC_CR_OSEL;
|
||||
cr |= STM32_RTC_CR_OSEL_ALARM_A;
|
||||
cr &= ~STM32_RTC_CR_TAMPOE;
|
||||
cr &= ~STM32_RTC_CR_COE;
|
||||
cr &= ~STM32_RTC_CR_TAMPALRM_TYPE;
|
||||
|
||||
switch (pin) {
|
||||
case OUT1:
|
||||
cr &= ~STM32_RTC_CR_OUT2EN;
|
||||
cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
|
||||
break;
|
||||
case OUT2:
|
||||
cr |= STM32_RTC_CR_OUT2EN;
|
||||
cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
|
||||
break;
|
||||
case OUT2_RMP:
|
||||
cr |= STM32_RTC_CR_OUT2EN;
|
||||
cfgr |= STM32_RTC_CFGR_OUT2_RMP;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
writel_relaxed(cr, rtc->base + regs.cr);
|
||||
writel_relaxed(cfgr, rtc->base + regs.cfgr);
|
||||
stm32_rtc_wpr_lock(rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_lsco_available(struct pinctrl_dev *pctldev, unsigned int pin)
|
||||
{
|
||||
struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
unsigned int cr = readl_relaxed(rtc->base + regs.cr);
|
||||
unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
|
||||
unsigned int calib = STM32_RTC_CR_COE;
|
||||
unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL;
|
||||
|
||||
switch (pin) {
|
||||
case OUT1:
|
||||
if ((!(cr & STM32_RTC_CR_OUT2EN) &&
|
||||
((cr & calib) || cr & tampalrm)) ||
|
||||
((cr & calib) && (cr & tampalrm)))
|
||||
return -EBUSY;
|
||||
break;
|
||||
case OUT2_RMP:
|
||||
if ((cr & STM32_RTC_CR_OUT2EN) &&
|
||||
(cfgr & STM32_RTC_CFGR_OUT2_RMP) &&
|
||||
((cr & calib) || (cr & tampalrm)))
|
||||
return -EBUSY;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (clk_get_rate(rtc->rtc_ck) != 32768)
|
||||
return -ERANGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_action_lsco(struct pinctrl_dev *pctldev, unsigned int pin)
|
||||
{
|
||||
struct stm32_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
struct device *dev = rtc->rtc_dev->dev.parent;
|
||||
u8 lscoen;
|
||||
int ret;
|
||||
|
||||
if (!rtc->data->has_lsco)
|
||||
return -EPERM;
|
||||
|
||||
ret = stm32_rtc_pinmux_lsco_available(pctldev, pin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lscoen = (pin == OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : STM32_RTC_CFGR_LSCOEN_OUT2_RMP;
|
||||
|
||||
rtc->clk_lsco = clk_register_gate(dev, "rtc_lsco", __clk_get_name(rtc->rtc_ck),
|
||||
CLK_IGNORE_UNUSED | CLK_IS_CRITICAL,
|
||||
rtc->base + regs.cfgr, lscoen, 0, NULL);
|
||||
if (IS_ERR(rtc->clk_lsco))
|
||||
return PTR_ERR(rtc->clk_lsco);
|
||||
|
||||
of_clk_add_provider(dev->of_node, of_clk_src_simple_get, rtc->clk_lsco);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stm32_rtc_pinmux_func stm32_rtc_pinmux_functions[] = {
|
||||
STM32_RTC_PINMUX("lsco", &stm32_rtc_pinmux_action_lsco, "out1", "out2_rmp"),
|
||||
STM32_RTC_PINMUX("alarm-a", &stm32_rtc_pinmux_action_alarm, "out1", "out2", "out2_rmp"),
|
||||
};
|
||||
|
||||
static int stm32_rtc_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
return ARRAY_SIZE(stm32_rtc_pinmux_functions);
|
||||
}
|
||||
|
||||
static const char *stm32_rtc_pinmux_get_fname(struct pinctrl_dev *pctldev, unsigned int selector)
|
||||
{
|
||||
return stm32_rtc_pinmux_functions[selector].name;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned int selector,
|
||||
const char * const **groups, unsigned int * const num_groups)
|
||||
{
|
||||
*groups = stm32_rtc_pinmux_functions[selector].groups;
|
||||
*num_groups = stm32_rtc_pinmux_functions[selector].num_groups;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_rtc_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
|
||||
unsigned int group)
|
||||
{
|
||||
struct stm32_rtc_pinmux_func selected_func = stm32_rtc_pinmux_functions[selector];
|
||||
struct pinctrl_pin_desc pin = stm32_rtc_pinctrl_pins[group];
|
||||
|
||||
/* Call action */
|
||||
if (selected_func.action)
|
||||
return selected_func.action(pctldev, pin.number);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct pinmux_ops stm32_rtc_pinmux_ops = {
|
||||
.get_functions_count = stm32_rtc_pinmux_get_functions_count,
|
||||
.get_function_name = stm32_rtc_pinmux_get_fname,
|
||||
.get_function_groups = stm32_rtc_pinmux_get_groups,
|
||||
.set_mux = stm32_rtc_pinmux_set_mux,
|
||||
.strict = true,
|
||||
};
|
||||
|
||||
static struct pinctrl_desc stm32_rtc_pdesc = {
|
||||
.name = DRIVER_NAME,
|
||||
.pins = stm32_rtc_pinctrl_pins,
|
||||
.npins = ARRAY_SIZE(stm32_rtc_pinctrl_pins),
|
||||
.owner = THIS_MODULE,
|
||||
.pctlops = &stm32_rtc_pinctrl_ops,
|
||||
.pmxops = &stm32_rtc_pinmux_ops,
|
||||
};
|
||||
|
||||
static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
|
||||
{
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
@@ -576,6 +807,8 @@ static const struct stm32_rtc_data stm32_rtc_data = {
|
||||
.need_dbp = true,
|
||||
.need_accuracy = false,
|
||||
.rif_protected = false,
|
||||
.has_lsco = false,
|
||||
.has_alarm_out = false,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@@ -586,6 +819,7 @@ static const struct stm32_rtc_data stm32_rtc_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
||||
.scr = UNDEF_REG,
|
||||
.cfgr = UNDEF_REG,
|
||||
.verr = UNDEF_REG,
|
||||
},
|
||||
.events = {
|
||||
@@ -599,6 +833,8 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
|
||||
.need_dbp = true,
|
||||
.need_accuracy = false,
|
||||
.rif_protected = false,
|
||||
.has_lsco = false,
|
||||
.has_alarm_out = false,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@@ -609,6 +845,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
||||
.scr = UNDEF_REG,
|
||||
.cfgr = UNDEF_REG,
|
||||
.verr = UNDEF_REG,
|
||||
},
|
||||
.events = {
|
||||
@@ -631,6 +868,8 @@ static const struct stm32_rtc_data stm32mp1_data = {
|
||||
.need_dbp = false,
|
||||
.need_accuracy = true,
|
||||
.rif_protected = false,
|
||||
.has_lsco = true,
|
||||
.has_alarm_out = true,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@@ -641,6 +880,7 @@ static const struct stm32_rtc_data stm32mp1_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x50,
|
||||
.scr = 0x5C,
|
||||
.cfgr = 0x60,
|
||||
.verr = 0x3F4,
|
||||
},
|
||||
.events = {
|
||||
@@ -654,6 +894,8 @@ static const struct stm32_rtc_data stm32mp25_data = {
|
||||
.need_dbp = false,
|
||||
.need_accuracy = true,
|
||||
.rif_protected = true,
|
||||
.has_lsco = true,
|
||||
.has_alarm_out = true,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
@@ -664,6 +906,7 @@ static const struct stm32_rtc_data stm32mp25_data = {
|
||||
.wpr = 0x24,
|
||||
.sr = 0x50,
|
||||
.scr = 0x5C,
|
||||
.cfgr = 0x60,
|
||||
.verr = 0x3F4,
|
||||
},
|
||||
.events = {
|
||||
@@ -681,6 +924,30 @@ static const struct of_device_id stm32_rtc_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
|
||||
|
||||
static void stm32_rtc_clean_outs(struct stm32_rtc *rtc)
|
||||
{
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
unsigned int cr = readl_relaxed(rtc->base + regs.cr);
|
||||
|
||||
cr &= ~STM32_RTC_CR_OSEL;
|
||||
cr &= ~STM32_RTC_CR_TAMPOE;
|
||||
cr &= ~STM32_RTC_CR_COE;
|
||||
cr &= ~STM32_RTC_CR_TAMPALRM_TYPE;
|
||||
cr &= ~STM32_RTC_CR_OUT2EN;
|
||||
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
writel_relaxed(cr, rtc->base + regs.cr);
|
||||
stm32_rtc_wpr_lock(rtc);
|
||||
|
||||
if (regs.cfgr != UNDEF_REG) {
|
||||
unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr);
|
||||
|
||||
cfgr &= ~STM32_RTC_CFGR_LSCOEN;
|
||||
cfgr &= ~STM32_RTC_CFGR_OUT2_RMP;
|
||||
writel_relaxed(cfgr, rtc->base + regs.cfgr);
|
||||
}
|
||||
}
|
||||
|
||||
static int stm32_rtc_check_rif(struct stm32_rtc *stm32_rtc,
|
||||
struct stm32_rtc_rif_resource res)
|
||||
{
|
||||
@@ -791,6 +1058,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_rtc *rtc;
|
||||
const struct stm32_rtc_registers *regs;
|
||||
struct pinctrl_dev *pctl;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
@@ -912,6 +1180,16 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
stm32_rtc_clean_outs(rtc);
|
||||
|
||||
ret = devm_pinctrl_register_and_init(&pdev->dev, &stm32_rtc_pdesc, rtc, &pctl);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "pinctrl register failed");
|
||||
|
||||
ret = pinctrl_enable(pctl);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "pinctrl enable failed");
|
||||
|
||||
/*
|
||||
* If INITS flag is reset (calendar year field set to 0x00), calendar
|
||||
* must be initialized
|
||||
@@ -950,6 +1228,9 @@ static void stm32_rtc_remove(struct platform_device *pdev)
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int cr;
|
||||
|
||||
if (!IS_ERR_OR_NULL(rtc->clk_lsco))
|
||||
clk_unregister_gate(rtc->clk_lsco);
|
||||
|
||||
/* Disable interrupts */
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
|
||||
@@ -402,6 +402,7 @@ CLK_OF_DECLARE_DRIVER(sun8i_r40_rtc_clk, "allwinner,sun8i-r40-rtc",
|
||||
static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = {
|
||||
.rc_osc_rate = 32000,
|
||||
.has_out_clk = 1,
|
||||
.has_auto_swt = 1,
|
||||
};
|
||||
|
||||
static void __init sun8i_v3_rtc_clk_init(struct device_node *node)
|
||||
|
||||
@@ -591,8 +591,8 @@ static int twl_rtc_probe(struct platform_device *pdev)
|
||||
memset(&nvmem_cfg, 0, sizeof(nvmem_cfg));
|
||||
nvmem_cfg.name = "twl-secured-";
|
||||
nvmem_cfg.type = NVMEM_TYPE_BATTERY_BACKED;
|
||||
nvmem_cfg.reg_read = twl_nvram_read,
|
||||
nvmem_cfg.reg_write = twl_nvram_write,
|
||||
nvmem_cfg.reg_read = twl_nvram_read;
|
||||
nvmem_cfg.reg_write = twl_nvram_write;
|
||||
nvmem_cfg.word_size = 1;
|
||||
nvmem_cfg.stride = 1;
|
||||
if (twl_class_is_4030()) {
|
||||
|
||||
@@ -1163,7 +1163,6 @@ blk_status_t scsi_alloc_sgtables(struct scsi_cmnd *cmd)
|
||||
|
||||
if (blk_integrity_rq(rq)) {
|
||||
struct scsi_data_buffer *prot_sdb = cmd->prot_sdb;
|
||||
int ivecs;
|
||||
|
||||
if (WARN_ON_ONCE(!prot_sdb)) {
|
||||
/*
|
||||
@@ -1175,20 +1174,15 @@ blk_status_t scsi_alloc_sgtables(struct scsi_cmnd *cmd)
|
||||
goto out_free_sgtables;
|
||||
}
|
||||
|
||||
ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio);
|
||||
|
||||
if (sg_alloc_table_chained(&prot_sdb->table, ivecs,
|
||||
if (sg_alloc_table_chained(&prot_sdb->table,
|
||||
rq->nr_integrity_segments,
|
||||
prot_sdb->table.sgl,
|
||||
SCSI_INLINE_PROT_SG_CNT)) {
|
||||
ret = BLK_STS_RESOURCE;
|
||||
goto out_free_sgtables;
|
||||
}
|
||||
|
||||
count = blk_rq_map_integrity_sg(rq->q, rq->bio,
|
||||
prot_sdb->table.sgl);
|
||||
BUG_ON(count > ivecs);
|
||||
BUG_ON(count > queue_max_integrity_segments(rq->q));
|
||||
|
||||
count = blk_rq_map_integrity_sg(rq, prot_sdb->table.sgl);
|
||||
cmd->prot_sdb = prot_sdb;
|
||||
cmd->prot_sdb->table.nents = count;
|
||||
}
|
||||
|
||||
@@ -375,9 +375,9 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
|
||||
* If the QSPI controller is set in regular SPI mode, set it in
|
||||
* Serial Memory Mode (SMM).
|
||||
*/
|
||||
if (aq->mr != QSPI_MR_SMM) {
|
||||
atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
|
||||
aq->mr = QSPI_MR_SMM;
|
||||
if (!(aq->mr & QSPI_MR_SMM)) {
|
||||
aq->mr |= QSPI_MR_SMM;
|
||||
atmel_qspi_write(aq->scr, aq, QSPI_MR);
|
||||
}
|
||||
|
||||
/* Clear pending interrupts */
|
||||
@@ -501,7 +501,8 @@ static int atmel_qspi_setup(struct spi_device *spi)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
aq->scr = QSPI_SCR_SCBR(scbr);
|
||||
aq->scr &= ~QSPI_SCR_SCBR_MASK;
|
||||
aq->scr |= QSPI_SCR_SCBR(scbr);
|
||||
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
|
||||
|
||||
pm_runtime_mark_last_busy(ctrl->dev.parent);
|
||||
@@ -534,6 +535,7 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
aq->scr &= ~QSPI_SCR_DLYBS_MASK;
|
||||
aq->scr |= QSPI_SCR_DLYBS(cs_setup);
|
||||
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
|
||||
|
||||
@@ -549,8 +551,8 @@ static void atmel_qspi_init(struct atmel_qspi *aq)
|
||||
atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
|
||||
|
||||
/* Set the QSPI controller by default in Serial Memory Mode */
|
||||
atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
|
||||
aq->mr = QSPI_MR_SMM;
|
||||
aq->mr |= QSPI_MR_SMM;
|
||||
atmel_qspi_write(aq->mr, aq, QSPI_MR);
|
||||
|
||||
/* Enable the QSPI controller */
|
||||
atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
|
||||
@@ -721,6 +723,7 @@ static void atmel_qspi_remove(struct platform_device *pdev)
|
||||
clk_unprepare(aq->pclk);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -211,9 +211,6 @@ struct airoha_snand_dev {
|
||||
|
||||
u8 *txrx_buf;
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
u64 cur_page_num;
|
||||
bool data_need_update;
|
||||
};
|
||||
|
||||
struct airoha_snand_ctrl {
|
||||
@@ -405,7 +402,7 @@ static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd,
|
||||
for (i = 0; i < len; i += data_len) {
|
||||
int err;
|
||||
|
||||
data_len = min(len, SPI_MAX_TRANSFER_SIZE);
|
||||
data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
|
||||
err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -427,7 +424,7 @@ static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl, u8 *data,
|
||||
for (i = 0; i < len; i += data_len) {
|
||||
int err;
|
||||
|
||||
data_len = min(len, SPI_MAX_TRANSFER_SIZE);
|
||||
data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
|
||||
err = airoha_snand_set_fifo_op(as_ctrl, 0xc, data_len);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -644,11 +641,6 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
||||
u32 val, rd_mode;
|
||||
int err;
|
||||
|
||||
if (!as_dev->data_need_update)
|
||||
return len;
|
||||
|
||||
as_dev->data_need_update = false;
|
||||
|
||||
switch (op->cmd.opcode) {
|
||||
case SPI_NAND_OP_READ_FROM_CACHE_DUAL:
|
||||
rd_mode = 1;
|
||||
@@ -739,8 +731,13 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
|
||||
SPI_NFI_READ_FROM_CACHE_DONE);
|
||||
/*
|
||||
* SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end
|
||||
* of dirmap_read operation even if it is already set.
|
||||
*/
|
||||
err = regmap_write_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
|
||||
SPI_NFI_READ_FROM_CACHE_DONE,
|
||||
SPI_NFI_READ_FROM_CACHE_DONE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -870,8 +867,13 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
|
||||
SPI_NFI_LOAD_TO_CACHE_DONE);
|
||||
/*
|
||||
* SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end
|
||||
* of dirmap_write operation even if it is already set.
|
||||
*/
|
||||
err = regmap_write_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
|
||||
SPI_NFI_LOAD_TO_CACHE_DONE,
|
||||
SPI_NFI_LOAD_TO_CACHE_DONE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -885,23 +887,11 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
|
||||
static int airoha_snand_exec_op(struct spi_mem *mem,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
struct airoha_snand_dev *as_dev = spi_get_ctldata(mem->spi);
|
||||
u8 data[8], cmd, opcode = op->cmd.opcode;
|
||||
struct airoha_snand_ctrl *as_ctrl;
|
||||
int i, err;
|
||||
|
||||
as_ctrl = spi_controller_get_devdata(mem->spi->controller);
|
||||
if (opcode == SPI_NAND_OP_PROGRAM_EXECUTE &&
|
||||
op->addr.val == as_dev->cur_page_num) {
|
||||
as_dev->data_need_update = true;
|
||||
} else if (opcode == SPI_NAND_OP_PAGE_READ) {
|
||||
if (!as_dev->data_need_update &&
|
||||
op->addr.val == as_dev->cur_page_num)
|
||||
return 0;
|
||||
|
||||
as_dev->data_need_update = true;
|
||||
as_dev->cur_page_num = op->addr.val;
|
||||
}
|
||||
|
||||
/* switch to manual mode */
|
||||
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
|
||||
@@ -986,7 +976,6 @@ static int airoha_snand_setup(struct spi_device *spi)
|
||||
if (dma_mapping_error(as_ctrl->dev, as_dev->dma_addr))
|
||||
return -ENOMEM;
|
||||
|
||||
as_dev->data_need_update = true;
|
||||
spi_set_ctldata(spi, as_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -986,6 +986,7 @@ static void fsl_lpspi_remove(struct platform_device *pdev)
|
||||
|
||||
fsl_lpspi_dma_exit(controller);
|
||||
|
||||
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
|
||||
pm_runtime_disable(fsl_lpspi->dev);
|
||||
}
|
||||
|
||||
|
||||
+10
-30
@@ -32,40 +32,20 @@ static acpi_status tb_acpi_add_link(acpi_handle handle, u32 level, void *data,
|
||||
goto out_put;
|
||||
|
||||
/*
|
||||
* Try to find physical device walking upwards to the hierarcy.
|
||||
* We need to do this because the xHCI driver might not yet be
|
||||
* bound so the USB3 SuperSpeed ports are not yet created.
|
||||
* Ignore USB3 ports here as USB core will set up device links between
|
||||
* tunneled USB3 devices and NHI host during USB device creation.
|
||||
* USB3 ports might not even have a physical device yet if xHCI driver
|
||||
* isn't bound yet.
|
||||
*/
|
||||
do {
|
||||
dev = acpi_get_first_physical_node(adev);
|
||||
if (dev)
|
||||
break;
|
||||
|
||||
adev = acpi_dev_parent(adev);
|
||||
} while (adev);
|
||||
|
||||
/*
|
||||
* Check that the device is PCIe. This is because USB3
|
||||
* SuperSpeed ports have this property and they are not power
|
||||
* managed with the xHCI and the SuperSpeed hub so we create the
|
||||
* link from xHCI instead.
|
||||
*/
|
||||
while (dev && !dev_is_pci(dev))
|
||||
dev = dev->parent;
|
||||
|
||||
if (!dev)
|
||||
dev = acpi_get_first_physical_node(adev);
|
||||
if (!dev || !dev_is_pci(dev))
|
||||
goto out_put;
|
||||
|
||||
/*
|
||||
* Check that this actually matches the type of device we
|
||||
* expect. It should either be xHCI or PCIe root/downstream
|
||||
* port.
|
||||
*/
|
||||
/* Check that this matches a PCIe root/downstream port. */
|
||||
pdev = to_pci_dev(dev);
|
||||
if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI ||
|
||||
(pci_is_pcie(pdev) &&
|
||||
(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM))) {
|
||||
if (pci_is_pcie(pdev) &&
|
||||
(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(pdev) == PCI_EXP_TYPE_DOWNSTREAM)) {
|
||||
const struct device_link *link;
|
||||
|
||||
/*
|
||||
|
||||
+366
-16
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
@@ -34,6 +35,14 @@
|
||||
|
||||
#define COUNTER_SET_LEN 3
|
||||
|
||||
/*
|
||||
* USB4 spec doesn't specify dwell range, the range of 100 ms to 500 ms
|
||||
* probed to give good results.
|
||||
*/
|
||||
#define MIN_DWELL_TIME 100 /* ms */
|
||||
#define MAX_DWELL_TIME 500 /* ms */
|
||||
#define DWELL_SAMPLE_INTERVAL 10
|
||||
|
||||
/* Sideband registers and their sizes as defined in the USB4 spec */
|
||||
struct sb_reg {
|
||||
unsigned int reg;
|
||||
@@ -394,8 +403,15 @@ out:
|
||||
* @ber_level: Current BER level contour value
|
||||
* @voltage_steps: Number of mandatory voltage steps
|
||||
* @max_voltage_offset: Maximum mandatory voltage offset (in mV)
|
||||
* @voltage_steps_optional_range: Number of voltage steps for optional range
|
||||
* @max_voltage_offset_optional_range: Maximum voltage offset for the optional
|
||||
* range (in mV).
|
||||
* @time_steps: Number of time margin steps
|
||||
* @max_time_offset: Maximum time margin offset (in mUI)
|
||||
* @voltage_time_offset: Offset for voltage / time for software margining
|
||||
* @dwell_time: Dwell time for software margining (in ms)
|
||||
* @error_counter: Error counter operation for software margining
|
||||
* @optional_voltage_offset_range: Enable optional extended voltage range
|
||||
* @software: %true if software margining is used instead of hardware
|
||||
* @time: %true if time margining is used instead of voltage
|
||||
* @right_high: %false if left/low margin test is performed, %true if
|
||||
@@ -414,13 +430,37 @@ struct tb_margining {
|
||||
unsigned int ber_level;
|
||||
unsigned int voltage_steps;
|
||||
unsigned int max_voltage_offset;
|
||||
unsigned int voltage_steps_optional_range;
|
||||
unsigned int max_voltage_offset_optional_range;
|
||||
unsigned int time_steps;
|
||||
unsigned int max_time_offset;
|
||||
unsigned int voltage_time_offset;
|
||||
unsigned int dwell_time;
|
||||
enum usb4_margin_sw_error_counter error_counter;
|
||||
bool optional_voltage_offset_range;
|
||||
bool software;
|
||||
bool time;
|
||||
bool right_high;
|
||||
};
|
||||
|
||||
static int margining_modify_error_counter(struct tb_margining *margining,
|
||||
u32 lanes, enum usb4_margin_sw_error_counter error_counter)
|
||||
{
|
||||
struct usb4_port_margining_params params = { 0 };
|
||||
struct tb_port *port = margining->port;
|
||||
u32 result;
|
||||
|
||||
if (error_counter != USB4_MARGIN_SW_ERROR_COUNTER_CLEAR &&
|
||||
error_counter != USB4_MARGIN_SW_ERROR_COUNTER_STOP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
params.error_counter = error_counter;
|
||||
params.lanes = lanes;
|
||||
|
||||
return usb4_port_sw_margin(port, margining->target, margining->index,
|
||||
¶ms, &result);
|
||||
}
|
||||
|
||||
static bool supports_software(const struct tb_margining *margining)
|
||||
{
|
||||
return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW;
|
||||
@@ -454,6 +494,12 @@ independent_time_margins(const struct tb_margining *margining)
|
||||
return FIELD_GET(USB4_MARGIN_CAP_1_TIME_INDP_MASK, margining->caps[1]);
|
||||
}
|
||||
|
||||
static bool
|
||||
supports_optional_voltage_offset_range(const struct tb_margining *margining)
|
||||
{
|
||||
return margining->caps[0] & USB4_MARGIN_CAP_0_OPT_VOLTAGE_SUPPORT;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
margining_ber_level_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@@ -553,6 +599,14 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
|
||||
margining->voltage_steps);
|
||||
seq_printf(s, "# maximum voltage offset: %u mV\n",
|
||||
margining->max_voltage_offset);
|
||||
seq_printf(s, "# optional voltage offset range support: %s\n",
|
||||
str_yes_no(supports_optional_voltage_offset_range(margining)));
|
||||
if (supports_optional_voltage_offset_range(margining)) {
|
||||
seq_printf(s, "# voltage margin steps, optional range: %u\n",
|
||||
margining->voltage_steps_optional_range);
|
||||
seq_printf(s, "# maximum voltage offset, optional range: %u mV\n",
|
||||
margining->max_voltage_offset_optional_range);
|
||||
}
|
||||
|
||||
switch (independent_voltage_margins(margining)) {
|
||||
case USB4_MARGIN_CAP_0_VOLTAGE_MIN:
|
||||
@@ -667,6 +721,198 @@ static int margining_lanes_show(struct seq_file *s, void *not_used)
|
||||
}
|
||||
DEBUGFS_ATTR_RW(margining_lanes);
|
||||
|
||||
static ssize_t
|
||||
margining_voltage_time_offset_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
unsigned int max_margin;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint_from_user(user_buf, count, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
if (!margining->software)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (margining->time)
|
||||
max_margin = margining->time_steps;
|
||||
else
|
||||
if (margining->optional_voltage_offset_range)
|
||||
max_margin = margining->voltage_steps_optional_range;
|
||||
else
|
||||
max_margin = margining->voltage_steps;
|
||||
|
||||
margining->voltage_time_offset = clamp(val, 0, max_margin);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int margining_voltage_time_offset_show(struct seq_file *s,
|
||||
void *not_used)
|
||||
{
|
||||
const struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
if (!margining->software)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
seq_printf(s, "%d\n", margining->voltage_time_offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEBUGFS_ATTR_RW(margining_voltage_time_offset);
|
||||
|
||||
static ssize_t
|
||||
margining_error_counter_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
enum usb4_margin_sw_error_counter error_counter;
|
||||
struct seq_file *s = file->private_data;
|
||||
struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
char *buf;
|
||||
|
||||
buf = validate_and_copy_from_user(user_buf, &count);
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
|
||||
buf[count - 1] = '\0';
|
||||
|
||||
if (!strcmp(buf, "nop"))
|
||||
error_counter = USB4_MARGIN_SW_ERROR_COUNTER_NOP;
|
||||
else if (!strcmp(buf, "clear"))
|
||||
error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR;
|
||||
else if (!strcmp(buf, "start"))
|
||||
error_counter = USB4_MARGIN_SW_ERROR_COUNTER_START;
|
||||
else if (!strcmp(buf, "stop"))
|
||||
error_counter = USB4_MARGIN_SW_ERROR_COUNTER_STOP;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
if (!margining->software)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
margining->error_counter = error_counter;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int margining_error_counter_show(struct seq_file *s, void *not_used)
|
||||
{
|
||||
const struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
if (!margining->software)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
switch (margining->error_counter) {
|
||||
case USB4_MARGIN_SW_ERROR_COUNTER_NOP:
|
||||
seq_puts(s, "[nop] clear start stop\n");
|
||||
break;
|
||||
case USB4_MARGIN_SW_ERROR_COUNTER_CLEAR:
|
||||
seq_puts(s, "nop [clear] start stop\n");
|
||||
break;
|
||||
case USB4_MARGIN_SW_ERROR_COUNTER_START:
|
||||
seq_puts(s, "nop clear [start] stop\n");
|
||||
break;
|
||||
case USB4_MARGIN_SW_ERROR_COUNTER_STOP:
|
||||
seq_puts(s, "nop clear start [stop]\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEBUGFS_ATTR_RW(margining_error_counter);
|
||||
|
||||
static ssize_t
|
||||
margining_dwell_time_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtouint_from_user(user_buf, count, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
if (!margining->software)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
margining->dwell_time = clamp(val, MIN_DWELL_TIME, MAX_DWELL_TIME);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int margining_dwell_time_show(struct seq_file *s, void *not_used)
|
||||
{
|
||||
struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
if (!margining->software)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
seq_printf(s, "%d\n", margining->dwell_time);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEBUGFS_ATTR_RW(margining_dwell_time);
|
||||
|
||||
static ssize_t
|
||||
margining_optional_voltage_offset_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
bool val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool_from_user(user_buf, count, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
margining->optional_voltage_offset_range = val;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int margining_optional_voltage_offset_show(struct seq_file *s,
|
||||
void *not_used)
|
||||
{
|
||||
struct tb_margining *margining = s->private;
|
||||
struct tb *tb = margining->port->sw->tb;
|
||||
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &tb->lock) {
|
||||
seq_printf(s, "%u\n", margining->optional_voltage_offset_range);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEBUGFS_ATTR_RW(margining_optional_voltage_offset);
|
||||
|
||||
static ssize_t margining_mode_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
@@ -739,6 +985,51 @@ static int margining_mode_show(struct seq_file *s, void *not_used)
|
||||
}
|
||||
DEBUGFS_ATTR_RW(margining_mode);
|
||||
|
||||
static int margining_run_sw(struct tb_margining *margining,
|
||||
struct usb4_port_margining_params *params)
|
||||
{
|
||||
u32 nsamples = margining->dwell_time / DWELL_SAMPLE_INTERVAL;
|
||||
int ret, i;
|
||||
|
||||
ret = usb4_port_sw_margin(margining->port, margining->target, margining->index,
|
||||
params, margining->results);
|
||||
if (ret)
|
||||
goto out_stop;
|
||||
|
||||
for (i = 0; i <= nsamples; i++) {
|
||||
u32 errors = 0;
|
||||
|
||||
ret = usb4_port_sw_margin_errors(margining->port, margining->target,
|
||||
margining->index, &margining->results[1]);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (margining->lanes == USB4_MARGIN_SW_LANE_0)
|
||||
errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK,
|
||||
margining->results[1]);
|
||||
else if (margining->lanes == USB4_MARGIN_SW_LANE_1)
|
||||
errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,
|
||||
margining->results[1]);
|
||||
else if (margining->lanes == USB4_MARGIN_SW_ALL_LANES)
|
||||
errors = margining->results[1];
|
||||
|
||||
/* Any errors stop the test */
|
||||
if (errors)
|
||||
break;
|
||||
|
||||
fsleep(DWELL_SAMPLE_INTERVAL * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
out_stop:
|
||||
/*
|
||||
* Stop the counters but don't clear them to allow the
|
||||
* different error counter configurations.
|
||||
*/
|
||||
margining_modify_error_counter(margining, margining->lanes,
|
||||
USB4_MARGIN_SW_ERROR_COUNTER_STOP);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int margining_run_write(void *data, u64 val)
|
||||
{
|
||||
struct tb_margining *margining = data;
|
||||
@@ -779,36 +1070,43 @@ static int margining_run_write(void *data, u64 val)
|
||||
clx = ret;
|
||||
}
|
||||
|
||||
/* Clear the results */
|
||||
memset(margining->results, 0, sizeof(margining->results));
|
||||
|
||||
if (margining->software) {
|
||||
struct usb4_port_margining_params params = {
|
||||
.error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR,
|
||||
.lanes = margining->lanes,
|
||||
.time = margining->time,
|
||||
.voltage_time_offset = margining->voltage_time_offset,
|
||||
.right_high = margining->right_high,
|
||||
.optional_voltage_offset_range = margining->optional_voltage_offset_range,
|
||||
};
|
||||
|
||||
tb_port_dbg(port,
|
||||
"running software %s lane margining for %s lanes %u\n",
|
||||
margining->time ? "time" : "voltage", dev_name(dev),
|
||||
margining->lanes);
|
||||
ret = usb4_port_sw_margin(port, margining->target, margining->index,
|
||||
margining->lanes, margining->time,
|
||||
margining->right_high,
|
||||
USB4_MARGIN_SW_COUNTER_CLEAR);
|
||||
if (ret)
|
||||
goto out_clx;
|
||||
|
||||
ret = usb4_port_sw_margin_errors(port, margining->target,
|
||||
margining->index,
|
||||
&margining->results[0]);
|
||||
ret = margining_run_sw(margining, ¶ms);
|
||||
} else {
|
||||
struct usb4_port_margining_params params = {
|
||||
.ber_level = margining->ber_level,
|
||||
.lanes = margining->lanes,
|
||||
.time = margining->time,
|
||||
.right_high = margining->right_high,
|
||||
.optional_voltage_offset_range = margining->optional_voltage_offset_range,
|
||||
};
|
||||
|
||||
tb_port_dbg(port,
|
||||
"running hardware %s lane margining for %s lanes %u\n",
|
||||
margining->time ? "time" : "voltage", dev_name(dev),
|
||||
margining->lanes);
|
||||
/* Clear the results */
|
||||
margining->results[0] = 0;
|
||||
margining->results[1] = 0;
|
||||
ret = usb4_port_hw_margin(port, margining->target, margining->index,
|
||||
margining->lanes, margining->ber_level,
|
||||
margining->time, margining->right_high,
|
||||
|
||||
ret = usb4_port_hw_margin(port, margining->target, margining->index, ¶ms,
|
||||
margining->results);
|
||||
}
|
||||
|
||||
out_clx:
|
||||
if (down_sw)
|
||||
tb_switch_clx_enable(down_sw, clx);
|
||||
out_unlock:
|
||||
@@ -837,6 +1135,13 @@ static ssize_t margining_results_write(struct file *file,
|
||||
margining->results[0] = 0;
|
||||
margining->results[1] = 0;
|
||||
|
||||
if (margining->software) {
|
||||
/* Clear the error counters */
|
||||
margining_modify_error_counter(margining,
|
||||
USB4_MARGIN_SW_ALL_LANES,
|
||||
USB4_MARGIN_SW_ERROR_COUNTER_CLEAR);
|
||||
}
|
||||
|
||||
mutex_unlock(&tb->lock);
|
||||
return count;
|
||||
}
|
||||
@@ -852,6 +1157,8 @@ static void voltage_margin_show(struct seq_file *s,
|
||||
if (val & USB4_MARGIN_HW_RES_1_EXCEEDS)
|
||||
seq_puts(s, " exceeds maximum");
|
||||
seq_puts(s, "\n");
|
||||
if (margining->optional_voltage_offset_range)
|
||||
seq_puts(s, " optional voltage offset range enabled\n");
|
||||
}
|
||||
|
||||
static void time_margin_show(struct seq_file *s,
|
||||
@@ -924,6 +1231,24 @@ static int margining_results_show(struct seq_file *s, void *not_used)
|
||||
voltage_margin_show(s, margining, val);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u32 lane_errors, result;
|
||||
|
||||
seq_printf(s, "0x%08x\n", margining->results[1]);
|
||||
result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]);
|
||||
|
||||
if (result == USB4_MARGIN_SW_LANE_0 ||
|
||||
result == USB4_MARGIN_SW_ALL_LANES) {
|
||||
lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK,
|
||||
margining->results[1]);
|
||||
seq_printf(s, "# lane 0 errors: %u\n", lane_errors);
|
||||
}
|
||||
if (result == USB4_MARGIN_SW_LANE_1 ||
|
||||
result == USB4_MARGIN_SW_ALL_LANES) {
|
||||
lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,
|
||||
margining->results[1]);
|
||||
seq_printf(s, "# lane 1 errors: %u\n", lane_errors);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&tb->lock);
|
||||
@@ -1091,6 +1416,15 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
|
||||
val = FIELD_GET(USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK, margining->caps[0]);
|
||||
margining->max_voltage_offset = 74 + val * 2;
|
||||
|
||||
if (supports_optional_voltage_offset_range(margining)) {
|
||||
val = FIELD_GET(USB4_MARGIN_CAP_0_VOLT_STEPS_OPT_MASK,
|
||||
margining->caps[0]);
|
||||
margining->voltage_steps_optional_range = val;
|
||||
val = FIELD_GET(USB4_MARGIN_CAP_1_MAX_VOLT_OFS_OPT_MASK,
|
||||
margining->caps[1]);
|
||||
margining->max_voltage_offset_optional_range = 74 + val * 2;
|
||||
}
|
||||
|
||||
if (supports_time(margining)) {
|
||||
val = FIELD_GET(USB4_MARGIN_CAP_1_TIME_STEPS_MASK, margining->caps[1]);
|
||||
margining->time_steps = val;
|
||||
@@ -1127,6 +1461,22 @@ static struct tb_margining *margining_alloc(struct tb_port *port,
|
||||
independent_time_margins(margining) == USB4_MARGIN_CAP_1_TIME_LR))
|
||||
debugfs_create_file("margin", 0600, dir, margining,
|
||||
&margining_margin_fops);
|
||||
|
||||
margining->error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR;
|
||||
margining->dwell_time = MIN_DWELL_TIME;
|
||||
|
||||
if (supports_optional_voltage_offset_range(margining))
|
||||
debugfs_create_file("optional_voltage_offset", DEBUGFS_MODE, dir, margining,
|
||||
&margining_optional_voltage_offset_fops);
|
||||
|
||||
if (supports_software(margining)) {
|
||||
debugfs_create_file("voltage_time_offset", DEBUGFS_MODE, dir, margining,
|
||||
&margining_voltage_time_offset_fops);
|
||||
debugfs_create_file("error_counter", DEBUGFS_MODE, dir, margining,
|
||||
&margining_error_counter_fops);
|
||||
debugfs_create_file("dwell_time", DEBUGFS_MODE, dir, margining,
|
||||
&margining_dwell_time_fops);
|
||||
}
|
||||
return margining;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@ enum usb4_sb_opcode {
|
||||
#define USB4_MARGIN_CAP_0_TIME BIT(5)
|
||||
#define USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK GENMASK(12, 6)
|
||||
#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK GENMASK(18, 13)
|
||||
#define USB4_MARGIN_CAP_0_OPT_VOLTAGE_SUPPORT BIT(19)
|
||||
#define USB4_MARGIN_CAP_0_VOLT_STEPS_OPT_MASK GENMASK(26, 20)
|
||||
#define USB4_MARGIN_CAP_1_MAX_VOLT_OFS_OPT_MASK GENMASK(7, 0)
|
||||
#define USB4_MARGIN_CAP_1_TIME_DESTR BIT(8)
|
||||
#define USB4_MARGIN_CAP_1_TIME_INDP_MASK GENMASK(10, 9)
|
||||
#define USB4_MARGIN_CAP_1_TIME_MIN 0x0
|
||||
@@ -72,6 +75,7 @@ enum usb4_sb_opcode {
|
||||
#define USB4_MARGIN_HW_RH BIT(4)
|
||||
#define USB4_MARGIN_HW_BER_MASK GENMASK(9, 5)
|
||||
#define USB4_MARGIN_HW_BER_SHIFT 5
|
||||
#define USB4_MARGIN_HW_OPT_VOLTAGE BIT(10)
|
||||
|
||||
/* Applicable to all margin values */
|
||||
#define USB4_MARGIN_HW_RES_1_MARGIN_MASK GENMASK(6, 0)
|
||||
@@ -82,13 +86,17 @@ enum usb4_sb_opcode {
|
||||
#define USB4_MARGIN_HW_RES_1_L1_LL_MARGIN_SHIFT 24
|
||||
|
||||
/* USB4_SB_OPCODE_RUN_SW_LANE_MARGINING */
|
||||
#define USB4_MARGIN_SW_LANES_MASK GENMASK(2, 0)
|
||||
#define USB4_MARGIN_SW_LANE_0 0x0
|
||||
#define USB4_MARGIN_SW_LANE_1 0x1
|
||||
#define USB4_MARGIN_SW_ALL_LANES 0x7
|
||||
#define USB4_MARGIN_SW_TIME BIT(3)
|
||||
#define USB4_MARGIN_SW_RH BIT(4)
|
||||
#define USB4_MARGIN_SW_OPT_VOLTAGE BIT(5)
|
||||
#define USB4_MARGIN_SW_VT_MASK GENMASK(12, 6)
|
||||
#define USB4_MARGIN_SW_COUNTER_MASK GENMASK(14, 13)
|
||||
#define USB4_MARGIN_SW_COUNTER_SHIFT 13
|
||||
#define USB4_MARGIN_SW_COUNTER_NOP 0x0
|
||||
#define USB4_MARGIN_SW_COUNTER_CLEAR 0x1
|
||||
#define USB4_MARGIN_SW_COUNTER_START 0x2
|
||||
#define USB4_MARGIN_SW_COUNTER_STOP 0x3
|
||||
|
||||
#define USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK GENMASK(3, 0)
|
||||
#define USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK GENMASK(7, 4)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1353,14 +1353,48 @@ int usb4_port_sb_read(struct tb_port *port, enum usb4_sb_target target, u8 index
|
||||
int usb4_port_sb_write(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u8 reg, const void *buf, u8 size);
|
||||
|
||||
/**
|
||||
* enum usb4_margin_sw_error_counter - Software margining error counter operation
|
||||
* @USB4_MARGIN_SW_ERROR_COUNTER_NOP: No change in counter setup
|
||||
* @USB4_MARGIN_SW_ERROR_COUNTER_CLEAR: Set the error counter to 0, enable counter
|
||||
* @USB4_MARGIN_SW_ERROR_COUNTER_START: Start counter, count from last value
|
||||
* @USB4_MARGIN_SW_ERROR_COUNTER_STOP: Stop counter, do not clear value
|
||||
*/
|
||||
enum usb4_margin_sw_error_counter {
|
||||
USB4_MARGIN_SW_ERROR_COUNTER_NOP,
|
||||
USB4_MARGIN_SW_ERROR_COUNTER_CLEAR,
|
||||
USB4_MARGIN_SW_ERROR_COUNTER_START,
|
||||
USB4_MARGIN_SW_ERROR_COUNTER_STOP,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct usb4_port_margining_params - USB4 margining parameters
|
||||
* @error_counter: Error counter operation for software margining
|
||||
* @ber_level: Current BER level contour value
|
||||
* @lanes: %0, %1 or %7 (all)
|
||||
* @voltage_time_offset: Offset for voltage / time for software margining
|
||||
* @optional_voltage_offset_range: Enable optional extended voltage range
|
||||
* @right_high: %false if left/low margin test is performed, %true if right/high
|
||||
* @time: %true if time margining is used instead of voltage
|
||||
*/
|
||||
struct usb4_port_margining_params {
|
||||
enum usb4_margin_sw_error_counter error_counter;
|
||||
u32 ber_level;
|
||||
u32 lanes;
|
||||
u32 voltage_time_offset;
|
||||
bool optional_voltage_offset_range;
|
||||
bool right_high;
|
||||
bool time;
|
||||
};
|
||||
|
||||
int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *caps);
|
||||
int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, unsigned int ber_level,
|
||||
bool timing, bool right_high, u32 *results);
|
||||
u8 index, const struct usb4_port_margining_params *params,
|
||||
u32 *results);
|
||||
int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, bool timing,
|
||||
bool right_high, u32 counter);
|
||||
u8 index, const struct usb4_port_margining_params *params,
|
||||
u32 *results);
|
||||
int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *errors);
|
||||
|
||||
|
||||
+35
-27
@@ -1653,31 +1653,31 @@ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target,
|
||||
* @port: USB4 port
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @lanes: Which lanes to run (must match the port capabilities). Can be
|
||||
* %0, %1 or %7.
|
||||
* @ber_level: BER level contour value
|
||||
* @timing: Perform timing margining instead of voltage
|
||||
* @right_high: Use Right/high margin instead of left/low
|
||||
* @params: Parameters for USB4 hardware margining
|
||||
* @results: Array with at least two elements to hold the results
|
||||
*
|
||||
* Runs hardware lane margining on USB4 port and returns the result in
|
||||
* @results.
|
||||
*/
|
||||
int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, unsigned int ber_level,
|
||||
bool timing, bool right_high, u32 *results)
|
||||
u8 index, const struct usb4_port_margining_params *params,
|
||||
u32 *results)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
val = lanes;
|
||||
if (timing)
|
||||
if (WARN_ON_ONCE(!params))
|
||||
return -EINVAL;
|
||||
|
||||
val = params->lanes;
|
||||
if (params->time)
|
||||
val |= USB4_MARGIN_HW_TIME;
|
||||
if (right_high)
|
||||
if (params->right_high)
|
||||
val |= USB4_MARGIN_HW_RH;
|
||||
if (ber_level)
|
||||
val |= (ber_level << USB4_MARGIN_HW_BER_SHIFT) &
|
||||
USB4_MARGIN_HW_BER_MASK;
|
||||
if (params->ber_level)
|
||||
val |= FIELD_PREP(USB4_MARGIN_HW_BER_MASK, params->ber_level);
|
||||
if (params->optional_voltage_offset_range)
|
||||
val |= USB4_MARGIN_HW_OPT_VOLTAGE;
|
||||
|
||||
ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val,
|
||||
sizeof(val));
|
||||
@@ -1698,38 +1698,46 @@ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
* @port: USB4 port
|
||||
* @target: Sideband target
|
||||
* @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER
|
||||
* @lanes: Which lanes to run (must match the port capabilities). Can be
|
||||
* %0, %1 or %7.
|
||||
* @timing: Perform timing margining instead of voltage
|
||||
* @right_high: Use Right/high margin instead of left/low
|
||||
* @counter: What to do with the error counter
|
||||
* @params: Parameters for USB4 software margining
|
||||
* @results: Data word for the operation completion data
|
||||
*
|
||||
* Runs software lane margining on USB4 port. Read back the error
|
||||
* counters by calling usb4_port_sw_margin_errors(). Returns %0 in
|
||||
* success and negative errno otherwise.
|
||||
*/
|
||||
int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, unsigned int lanes, bool timing,
|
||||
bool right_high, u32 counter)
|
||||
u8 index, const struct usb4_port_margining_params *params,
|
||||
u32 *results)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
val = lanes;
|
||||
if (timing)
|
||||
if (WARN_ON_ONCE(!params))
|
||||
return -EINVAL;
|
||||
|
||||
val = params->lanes;
|
||||
if (params->time)
|
||||
val |= USB4_MARGIN_SW_TIME;
|
||||
if (right_high)
|
||||
if (params->optional_voltage_offset_range)
|
||||
val |= USB4_MARGIN_SW_OPT_VOLTAGE;
|
||||
if (params->right_high)
|
||||
val |= USB4_MARGIN_SW_RH;
|
||||
val |= (counter << USB4_MARGIN_SW_COUNTER_SHIFT) &
|
||||
USB4_MARGIN_SW_COUNTER_MASK;
|
||||
val |= FIELD_PREP(USB4_MARGIN_SW_COUNTER_MASK, params->error_counter);
|
||||
val |= FIELD_PREP(USB4_MARGIN_SW_VT_MASK, params->voltage_time_offset);
|
||||
|
||||
ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val,
|
||||
sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb4_port_sb_op(port, target, index,
|
||||
USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500);
|
||||
ret = usb4_port_sb_op(port, target, index,
|
||||
USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results,
|
||||
sizeof(*results));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -303,7 +303,7 @@ int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr)
|
||||
pr_devel("HVSI@%x: %s DTR...\n", pv->termno,
|
||||
dtr ? "Setting" : "Clearing");
|
||||
|
||||
ctrl.hdr.type = VS_CONTROL_PACKET_HEADER,
|
||||
ctrl.hdr.type = VS_CONTROL_PACKET_HEADER;
|
||||
ctrl.hdr.len = sizeof(struct hvsi_control);
|
||||
ctrl.verb = cpu_to_be16(VSV_SET_MODEM_CTL);
|
||||
ctrl.mask = cpu_to_be32(HVSI_TSDTR);
|
||||
|
||||
+1
-6
@@ -208,9 +208,6 @@ static const struct {
|
||||
};
|
||||
#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
|
||||
|
||||
|
||||
/* driver_data correspond to the lines in the structure above
|
||||
see also ISA probe function before you change something */
|
||||
static const struct pci_device_id mxser_pcibrds[] = {
|
||||
{ PCI_DEVICE_DATA(MOXA, C168, 8) },
|
||||
{ PCI_DEVICE_DATA(MOXA, C104, 4) },
|
||||
@@ -986,7 +983,7 @@ static int mxser_get_serial_info(struct tty_struct *tty,
|
||||
ss->baud_base = MXSER_BAUD_BASE;
|
||||
ss->close_delay = close_delay;
|
||||
ss->closing_wait = closing_wait;
|
||||
ss->custom_divisor = MXSER_CUSTOM_DIVISOR,
|
||||
ss->custom_divisor = MXSER_CUSTOM_DIVISOR;
|
||||
mutex_unlock(&port->mutex);
|
||||
return 0;
|
||||
}
|
||||
@@ -1773,8 +1770,6 @@ static void mxser_initbrd(struct mxser_board *brd, bool high_baud)
|
||||
|
||||
mxser_process_txrx_fifo(info);
|
||||
|
||||
info->port.close_delay = 5 * HZ / 10;
|
||||
info->port.closing_wait = 30 * HZ;
|
||||
spin_lock_init(&info->slock);
|
||||
|
||||
/* before set INT ISR, disable all int */
|
||||
|
||||
@@ -529,7 +529,7 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
|
||||
bool found = false;
|
||||
|
||||
for_each_available_child_of_node(ctrl->dev.of_node, node) {
|
||||
if (!of_get_property(node, "compatible", NULL))
|
||||
if (!of_property_present(node, "compatible"))
|
||||
continue;
|
||||
|
||||
dev_dbg(&ctrl->dev, "adding child %pOF\n", node);
|
||||
|
||||
@@ -561,6 +561,7 @@ static const struct of_device_id aspeed_vuart_table[] = {
|
||||
{ .compatible = "aspeed,ast2500-vuart" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_vuart_table);
|
||||
|
||||
static struct platform_driver aspeed_vuart_driver = {
|
||||
.driver = {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@@ -213,11 +214,57 @@ static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
|
||||
|
||||
static bool bcm2835aux_can_disable_clock(struct device *dev)
|
||||
{
|
||||
struct bcm2835aux_data *data = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *up = serial8250_get_port(data->line);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
return false;
|
||||
|
||||
if (uart_console(&up->port) && !console_suspend_enabled)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int bcm2835aux_suspend(struct device *dev)
|
||||
{
|
||||
struct bcm2835aux_data *data = dev_get_drvdata(dev);
|
||||
|
||||
serial8250_suspend_port(data->line);
|
||||
|
||||
if (!bcm2835aux_can_disable_clock(dev))
|
||||
return 0;
|
||||
|
||||
clk_disable_unprepare(data->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835aux_resume(struct device *dev)
|
||||
{
|
||||
struct bcm2835aux_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (bcm2835aux_can_disable_clock(dev)) {
|
||||
ret = clk_prepare_enable(data->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
serial8250_resume_port(data->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(bcm2835aux_dev_pm_ops, bcm2835aux_suspend, bcm2835aux_resume);
|
||||
|
||||
static struct platform_driver bcm2835aux_serial_driver = {
|
||||
.driver = {
|
||||
.name = "bcm2835-aux-uart",
|
||||
.of_match_table = bcm2835aux_serial_match,
|
||||
.acpi_match_table = bcm2835aux_serial_acpi_match,
|
||||
.pm = pm_ptr(&bcm2835aux_dev_pm_ops),
|
||||
},
|
||||
.probe = bcm2835aux_serial_probe,
|
||||
.remove_new = bcm2835aux_serial_remove,
|
||||
|
||||
@@ -89,7 +89,9 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
struct tty_port *tport = &p->port.state->port;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct uart_port *up = &p->port;
|
||||
struct scatterlist sg;
|
||||
struct scatterlist *sg;
|
||||
struct scatterlist sgl[2];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (dma->tx_running) {
|
||||
@@ -110,18 +112,17 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
|
||||
serial8250_do_prepare_tx_dma(p);
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
/* kfifo can do more than one sg, we don't (quite yet) */
|
||||
ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
|
||||
sg_init_table(sgl, ARRAY_SIZE(sgl));
|
||||
|
||||
ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, sgl, ARRAY_SIZE(sgl),
|
||||
UART_XMIT_SIZE, dma->tx_addr);
|
||||
|
||||
/* we already checked empty fifo above, so there should be something */
|
||||
if (WARN_ON_ONCE(ret != 1))
|
||||
return 0;
|
||||
dma->tx_size = 0;
|
||||
|
||||
dma->tx_size = sg_dma_len(&sg);
|
||||
for_each_sg(sgl, sg, ret, i)
|
||||
dma->tx_size += sg_dma_len(sg);
|
||||
|
||||
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1,
|
||||
desc = dmaengine_prep_slave_sg(dma->txchan, sgl, ret,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
|
||||
@@ -89,7 +89,7 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
|
||||
unsigned int quot, unsigned int quot_frac)
|
||||
{
|
||||
dw8250_writel_ext(p, DW_UART_DLF, quot_frac);
|
||||
serial8250_do_set_divisor(p, baud, quot, quot_frac);
|
||||
serial8250_do_set_divisor(p, baud, quot);
|
||||
}
|
||||
|
||||
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios,
|
||||
|
||||
@@ -171,6 +171,17 @@ OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
|
||||
OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
|
||||
|
||||
static int __init early_serial8250_rs2_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
device->port.regshift = 2;
|
||||
|
||||
return early_serial8250_setup(device, options);
|
||||
}
|
||||
OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup);
|
||||
OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup);
|
||||
OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_OMAP
|
||||
|
||||
static int __init early_omap8250_setup(struct earlycon_device *device,
|
||||
|
||||
@@ -500,7 +500,7 @@ static unsigned int xr17v35x_get_divisor(struct uart_port *p, unsigned int baud,
|
||||
static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud,
|
||||
unsigned int quot, unsigned int quot_frac)
|
||||
{
|
||||
serial8250_do_set_divisor(p, baud, quot, quot_frac);
|
||||
serial8250_do_set_divisor(p, baud, quot);
|
||||
|
||||
/* Preserve bits not related to baudrate; DLD[7:4]. */
|
||||
quot_frac |= serial_port_in(p, 0x2) & 0xf0;
|
||||
|
||||
@@ -137,7 +137,6 @@ struct omap8250_priv {
|
||||
atomic_t active;
|
||||
bool is_suspending;
|
||||
int wakeirq;
|
||||
int wakeups_enabled;
|
||||
u32 latency;
|
||||
u32 calc_latency;
|
||||
struct pm_qos_request pm_qos_request;
|
||||
@@ -1523,7 +1522,10 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
if (of_property_read_bool(np, "wakeup-source"))
|
||||
device_set_wakeup_enable(&pdev->dev, true);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
|
||||
@@ -1581,7 +1583,7 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0,
|
||||
dev_name(&pdev->dev), priv);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err;
|
||||
|
||||
priv->wakeirq = irq_of_parse_and_map(np, 1);
|
||||
|
||||
@@ -1622,7 +1624,7 @@ static void omap8250_remove(struct platform_device *pdev)
|
||||
flush_work(&priv->qos_work);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
cpu_latency_qos_remove_request(&priv->pm_qos_request);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
device_set_wakeup_capable(&pdev->dev, false);
|
||||
}
|
||||
|
||||
static int omap8250_prepare(struct device *dev)
|
||||
|
||||
@@ -1277,7 +1277,7 @@ static void pci_oxsemi_tornado_set_divisor(struct uart_port *port,
|
||||
serial_icr_write(up, UART_TCR, tcr);
|
||||
serial_icr_write(up, UART_CPR, cpr);
|
||||
serial_icr_write(up, UART_CKS, cpr2);
|
||||
serial8250_do_set_divisor(port, baud, quot, 0);
|
||||
serial8250_do_set_divisor(port, baud, quot);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
/*
|
||||
* Universal/legacy platform driver for 8250/16550-type serial ports
|
||||
*
|
||||
* Supports: ISA-compatible 8250/16550 ports
|
||||
* Supports:
|
||||
* ISA-compatible 8250/16550 ports
|
||||
* ACPI 8250/16550 ports
|
||||
* PNP 8250/16550 ports
|
||||
* "serial8250" platform devices
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/once.h>
|
||||
@@ -22,9 +26,9 @@
|
||||
|
||||
/*
|
||||
* Configuration:
|
||||
* share_irqs Whether we pass IRQF_SHARED to request_irq().
|
||||
* share_irqs: Whether we pass IRQF_SHARED to request_irq().
|
||||
* This option is unsafe when used on edge-triggered interrupts.
|
||||
* skip_txen_test Force skip of txen test at init time.
|
||||
* skip_txen_test: Force skip of txen test at init time.
|
||||
*/
|
||||
unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
|
||||
unsigned int skip_txen_test;
|
||||
@@ -61,9 +65,9 @@ static void __init __serial8250_isa_init_ports(void)
|
||||
nr_uarts = UART_NR;
|
||||
|
||||
/*
|
||||
* Set up initial isa ports based on nr_uart module param, or else
|
||||
* Set up initial ISA ports based on nr_uart module param, or else
|
||||
* default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
|
||||
* need to increase nr_uarts when setting up the initial isa ports.
|
||||
* need to increase nr_uarts when setting up the initial ISA ports.
|
||||
*/
|
||||
for (i = 0; i < nr_uarts; i++)
|
||||
serial8250_setup_port(i);
|
||||
@@ -101,13 +105,63 @@ void __init serial8250_isa_init_ports(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a set of serial devices attached to a platform device. The
|
||||
* list is terminated with a zero flags entry, which means we expect
|
||||
* all entries to have at least UPF_BOOT_AUTOCONF set.
|
||||
* Generic 16550A platform devices
|
||||
*/
|
||||
static int serial8250_probe(struct platform_device *dev)
|
||||
static int serial8250_probe_acpi(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uart_8250_port uart = { };
|
||||
struct resource *regs;
|
||||
unsigned char iotype;
|
||||
int ret, line;
|
||||
|
||||
regs = platform_get_mem_or_io(pdev, 0);
|
||||
if (!regs)
|
||||
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
|
||||
|
||||
switch (resource_type(regs)) {
|
||||
case IORESOURCE_IO:
|
||||
uart.port.iobase = regs->start;
|
||||
iotype = UPIO_PORT;
|
||||
break;
|
||||
case IORESOURCE_MEM:
|
||||
uart.port.mapbase = regs->start;
|
||||
uart.port.mapsize = resource_size(regs);
|
||||
uart.port.flags = UPF_IOREMAP;
|
||||
iotype = UPIO_MEM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* default clock frequency */
|
||||
uart.port.uartclk = 1843200;
|
||||
uart.port.type = PORT_16550A;
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
|
||||
ret = uart_read_and_validate_port_properties(&uart.port);
|
||||
/* no interrupt -> fall back to polling */
|
||||
if (ret == -ENXIO)
|
||||
ret = 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The previous call may not set iotype correctly when reg-io-width
|
||||
* property is absent and it doesn't support IO port resource.
|
||||
*/
|
||||
uart.port.iotype = iotype;
|
||||
|
||||
line = serial8250_register_8250_port(&uart);
|
||||
if (line < 0)
|
||||
return line;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
|
||||
{
|
||||
struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
|
||||
struct uart_8250_port uart;
|
||||
int ret, i, irqflag = 0;
|
||||
|
||||
@@ -155,6 +209,31 @@ static int serial8250_probe(struct platform_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a set of serial devices attached to a platform device.
|
||||
* The list is terminated with a zero flags entry, which means we expect
|
||||
* all entries to have at least UPF_BOOT_AUTOCONF set.
|
||||
*/
|
||||
static int serial8250_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct plat_serial8250_port *p;
|
||||
|
||||
p = dev_get_platdata(dev);
|
||||
if (p)
|
||||
return serial8250_probe_platform(pdev, p);
|
||||
|
||||
/*
|
||||
* Probe platform UART devices defined using standard hardware
|
||||
* discovery mechanism like ACPI or DT. Support only ACPI based
|
||||
* serial device for now.
|
||||
*/
|
||||
if (has_acpi_companion(dev))
|
||||
return serial8250_probe_acpi(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove serial ports registered against a platform device.
|
||||
*/
|
||||
@@ -198,6 +277,12 @@ static int serial8250_resume(struct platform_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id acpi_platform_serial_table[] = {
|
||||
{ "RSCV0003" }, /* RISC-V Generic 16550A UART */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, acpi_platform_serial_table);
|
||||
|
||||
static struct platform_driver serial8250_isa_driver = {
|
||||
.probe = serial8250_probe,
|
||||
.remove_new = serial8250_remove,
|
||||
@@ -205,12 +290,13 @@ static struct platform_driver serial8250_isa_driver = {
|
||||
.resume = serial8250_resume,
|
||||
.driver = {
|
||||
.name = "serial8250",
|
||||
.acpi_match_table = acpi_platform_serial_table,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* This "device" covers _all_ ISA 8250-compatible serial devices listed
|
||||
* in the table in include/asm/serial.h
|
||||
* in the table in include/asm/serial.h.
|
||||
*/
|
||||
struct platform_device *serial8250_isa_devs;
|
||||
|
||||
@@ -239,8 +325,7 @@ static int __init serial8250_init(void)
|
||||
if (ret)
|
||||
goto unreg_uart_drv;
|
||||
|
||||
serial8250_isa_devs = platform_device_alloc("serial8250",
|
||||
PLAT8250_DEV_LEGACY);
|
||||
serial8250_isa_devs = platform_device_alloc("serial8250", PLAT8250_DEV_LEGACY);
|
||||
if (!serial8250_isa_devs) {
|
||||
ret = -ENOMEM;
|
||||
goto unreg_pnp;
|
||||
@@ -279,7 +364,7 @@ static void __exit serial8250_exit(void)
|
||||
/*
|
||||
* This tells serial8250_unregister_port() not to re-register
|
||||
* the ports (thereby making serial8250_isa_driver permanently
|
||||
* in use.)
|
||||
* in use).
|
||||
*/
|
||||
serial8250_isa_devs = NULL;
|
||||
|
||||
@@ -312,12 +397,13 @@ MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
|
||||
#ifndef MODULE
|
||||
/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
|
||||
* working as well for the module options so we don't break people. We
|
||||
/*
|
||||
* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
|
||||
* working as well for the module options so we don't break people. We
|
||||
* need to keep the names identical and the convenient macros will happily
|
||||
* refuse to let us do that by failing the build with redefinition errors
|
||||
* of global variables. So we stick them inside a dummy function to avoid
|
||||
* those conflicts. The options still get parsed, and the redefined
|
||||
* of global variables. So we stick them inside a dummy function to avoid
|
||||
* those conflicts. The options still get parsed, and the redefined
|
||||
* MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
|
||||
*
|
||||
* This is hacky. I'm sorry.
|
||||
|
||||
@@ -2609,7 +2609,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
|
||||
}
|
||||
|
||||
void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
unsigned int quot, unsigned int quot_frac)
|
||||
unsigned int quot)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
@@ -2641,7 +2641,7 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
if (port->set_divisor)
|
||||
port->set_divisor(port, baud, quot, quot_frac);
|
||||
else
|
||||
serial8250_do_set_divisor(port, baud, quot, quot_frac);
|
||||
serial8250_do_set_divisor(port, baud, quot);
|
||||
}
|
||||
|
||||
static unsigned int serial8250_get_baud_rate(struct uart_port *port,
|
||||
|
||||
@@ -165,22 +165,6 @@ static struct platform_driver serial_pxa_driver = {
|
||||
|
||||
module_platform_driver(serial_pxa_driver);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
static int __init early_serial_pxa_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
struct uart_port *port = &device->port;
|
||||
|
||||
if (!(device->port.membase || device->port.iobase))
|
||||
return -ENODEV;
|
||||
|
||||
port->regshift = 2;
|
||||
return early_serial8250_setup(device, NULL);
|
||||
}
|
||||
OF_EARLYCON_DECLARE(early_pxa, "mrvl,pxa-uart", early_serial_pxa_setup);
|
||||
OF_EARLYCON_DECLARE(mmp, "mrvl,mmp-uart", early_serial_pxa_setup);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Sergei Ianovich");
|
||||
MODULE_DESCRIPTION("driver for PXA on-board UARTS");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -124,13 +124,14 @@ struct qcom_geni_serial_port {
|
||||
dma_addr_t tx_dma_addr;
|
||||
dma_addr_t rx_dma_addr;
|
||||
bool setup;
|
||||
unsigned int baud;
|
||||
unsigned long poll_timeout_us;
|
||||
unsigned long clk_rate;
|
||||
void *rx_buf;
|
||||
u32 loopback;
|
||||
bool brk;
|
||||
|
||||
unsigned int tx_remaining;
|
||||
unsigned int tx_queued;
|
||||
int wakeup_irq;
|
||||
bool rx_tx_swap;
|
||||
bool cts_rts_swap;
|
||||
@@ -144,6 +145,9 @@ static const struct uart_ops qcom_geni_uart_pops;
|
||||
static struct uart_driver qcom_geni_console_driver;
|
||||
static struct uart_driver qcom_geni_uart_driver;
|
||||
|
||||
static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
|
||||
static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
|
||||
|
||||
static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
|
||||
{
|
||||
return container_of(uport, struct qcom_geni_serial_port, uport);
|
||||
@@ -265,27 +269,18 @@ static bool qcom_geni_serial_secondary_active(struct uart_port *uport)
|
||||
return readl(uport->membase + SE_GENI_STATUS) & S_GENI_CMD_ACTIVE;
|
||||
}
|
||||
|
||||
static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
|
||||
int offset, int field, bool set)
|
||||
static bool qcom_geni_serial_poll_bitfield(struct uart_port *uport,
|
||||
unsigned int offset, u32 field, u32 val)
|
||||
{
|
||||
u32 reg;
|
||||
struct qcom_geni_serial_port *port;
|
||||
unsigned int baud;
|
||||
unsigned int fifo_bits;
|
||||
unsigned long timeout_us = 20000;
|
||||
struct qcom_geni_private_data *private_data = uport->private_data;
|
||||
|
||||
if (private_data->drv) {
|
||||
port = to_dev_port(uport);
|
||||
baud = port->baud;
|
||||
if (!baud)
|
||||
baud = 115200;
|
||||
fifo_bits = port->tx_fifo_depth * port->tx_fifo_width;
|
||||
/*
|
||||
* Total polling iterations based on FIFO worth of bytes to be
|
||||
* sent at current baud. Add a little fluff to the wait.
|
||||
*/
|
||||
timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
|
||||
if (port->poll_timeout_us)
|
||||
timeout_us = port->poll_timeout_us;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -295,7 +290,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
|
||||
timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10;
|
||||
while (timeout_us) {
|
||||
reg = readl(uport->membase + offset);
|
||||
if ((bool)(reg & field) == set)
|
||||
if ((reg & field) == val)
|
||||
return true;
|
||||
udelay(10);
|
||||
timeout_us -= 10;
|
||||
@@ -303,6 +298,12 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
|
||||
unsigned int offset, u32 field, bool set)
|
||||
{
|
||||
return qcom_geni_serial_poll_bitfield(uport, offset, field, set ? field : 0);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
|
||||
{
|
||||
u32 m_cmd;
|
||||
@@ -315,18 +316,16 @@ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
|
||||
static void qcom_geni_serial_poll_tx_done(struct uart_port *uport)
|
||||
{
|
||||
int done;
|
||||
u32 irq_clear = M_CMD_DONE_EN;
|
||||
|
||||
done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
|
||||
M_CMD_DONE_EN, true);
|
||||
if (!done) {
|
||||
writel(M_GENI_CMD_ABORT, uport->membase +
|
||||
SE_GENI_M_CMD_CTRL_REG);
|
||||
irq_clear |= M_CMD_ABORT_EN;
|
||||
qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
|
||||
M_CMD_ABORT_EN, true);
|
||||
writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
}
|
||||
writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_abort_rx(struct uart_port *uport)
|
||||
@@ -386,17 +385,27 @@ static int qcom_geni_serial_get_char(struct uart_port *uport)
|
||||
static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
|
||||
unsigned char c)
|
||||
{
|
||||
writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
|
||||
if (qcom_geni_serial_main_active(uport)) {
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
__qcom_geni_serial_cancel_tx_cmd(uport);
|
||||
}
|
||||
|
||||
writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
qcom_geni_serial_setup_tx(uport, 1);
|
||||
WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
|
||||
M_TX_FIFO_WATERMARK_EN, true));
|
||||
writel(c, uport->membase + SE_GENI_TX_FIFOn);
|
||||
writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
||||
static void qcom_geni_serial_drain_fifo(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
|
||||
qcom_geni_serial_poll_bitfield(uport, SE_GENI_M_GP_LENGTH, GP_LENGTH,
|
||||
port->tx_queued);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_wr_char(struct uart_port *uport, unsigned char ch)
|
||||
{
|
||||
struct qcom_geni_private_data *private_data = uport->private_data;
|
||||
@@ -431,6 +440,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
|
||||
}
|
||||
|
||||
writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
|
||||
writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
qcom_geni_serial_setup_tx(uport, bytes_to_send);
|
||||
for (i = 0; i < count; ) {
|
||||
size_t chars_to_write = 0;
|
||||
@@ -469,10 +479,9 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
||||
{
|
||||
struct uart_port *uport;
|
||||
struct qcom_geni_serial_port *port;
|
||||
u32 m_irq_en, s_irq_en;
|
||||
bool locked = true;
|
||||
unsigned long flags;
|
||||
u32 geni_status;
|
||||
u32 irq_en;
|
||||
|
||||
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
|
||||
|
||||
@@ -486,40 +495,28 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
||||
else
|
||||
uart_port_lock_irqsave(uport, &flags);
|
||||
|
||||
geni_status = readl(uport->membase + SE_GENI_STATUS);
|
||||
m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
s_irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
|
||||
writel(0, uport->membase + SE_GENI_M_IRQ_EN);
|
||||
writel(0, uport->membase + SE_GENI_S_IRQ_EN);
|
||||
|
||||
if (!locked) {
|
||||
/*
|
||||
* We can only get here if an oops is in progress then we were
|
||||
* unable to get the lock. This means we can't safely access
|
||||
* our state variables like tx_remaining. About the best we
|
||||
* can do is wait for the FIFO to be empty before we start our
|
||||
* transfer, so we'll do that.
|
||||
*/
|
||||
qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
|
||||
M_TX_FIFO_NOT_EMPTY_EN, false);
|
||||
} else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
|
||||
/*
|
||||
* It seems we can't interrupt existing transfers if all data
|
||||
* has been sent, in which case we need to look for done first.
|
||||
*/
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
if (qcom_geni_serial_main_active(uport)) {
|
||||
/* Wait for completion or drain FIFO */
|
||||
if (!locked || port->tx_remaining == 0)
|
||||
qcom_geni_serial_poll_tx_done(uport);
|
||||
else
|
||||
qcom_geni_serial_drain_fifo(uport);
|
||||
|
||||
if (!kfifo_is_empty(&uport->state->port.xmit_fifo)) {
|
||||
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
writel(irq_en | M_TX_FIFO_WATERMARK_EN,
|
||||
uport->membase + SE_GENI_M_IRQ_EN);
|
||||
}
|
||||
qcom_geni_serial_cancel_tx_cmd(uport);
|
||||
}
|
||||
|
||||
__qcom_geni_serial_console_write(uport, s, count);
|
||||
|
||||
writel(m_irq_en, uport->membase + SE_GENI_M_IRQ_EN);
|
||||
writel(s_irq_en, uport->membase + SE_GENI_S_IRQ_EN);
|
||||
|
||||
if (locked) {
|
||||
if (port->tx_remaining)
|
||||
qcom_geni_serial_setup_tx(uport, port->tx_remaining);
|
||||
if (locked)
|
||||
uart_port_unlock_irqrestore(uport, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
|
||||
@@ -682,13 +679,10 @@ static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport)
|
||||
writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
|
||||
static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
|
||||
if (!qcom_geni_serial_main_active(uport))
|
||||
return;
|
||||
|
||||
geni_se_cancel_m_cmd(&port->se);
|
||||
if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
|
||||
M_CMD_CANCEL_EN, true)) {
|
||||
@@ -698,8 +692,19 @@ static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
|
||||
writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
}
|
||||
writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
|
||||
{
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
||||
|
||||
if (!qcom_geni_serial_main_active(uport))
|
||||
return;
|
||||
|
||||
__qcom_geni_serial_cancel_tx_cmd(uport);
|
||||
|
||||
port->tx_remaining = 0;
|
||||
port->tx_queued = 0;
|
||||
}
|
||||
|
||||
static void qcom_geni_serial_handle_rx_fifo(struct uart_port *uport, bool drop)
|
||||
@@ -923,9 +928,10 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
|
||||
if (!chunk)
|
||||
goto out_write_wakeup;
|
||||
|
||||
if (!port->tx_remaining) {
|
||||
if (!active) {
|
||||
qcom_geni_serial_setup_tx(uport, pending);
|
||||
port->tx_remaining = pending;
|
||||
port->tx_queued = 0;
|
||||
|
||||
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
|
||||
if (!(irq_en & M_TX_FIFO_WATERMARK_EN))
|
||||
@@ -934,6 +940,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
|
||||
}
|
||||
|
||||
qcom_geni_serial_send_chunk_fifo(uport, chunk);
|
||||
port->tx_queued += chunk;
|
||||
|
||||
/*
|
||||
* The tx fifo watermark is level triggered and latched. Though we had
|
||||
@@ -1244,11 +1251,11 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
||||
unsigned long clk_rate;
|
||||
u32 ver, sampling_rate;
|
||||
unsigned int avg_bw_core;
|
||||
unsigned long timeout;
|
||||
|
||||
qcom_geni_serial_stop_rx(uport);
|
||||
/* baud rate */
|
||||
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
|
||||
port->baud = baud;
|
||||
|
||||
sampling_rate = UART_OVERSAMPLING;
|
||||
/* Sampling rate is halved for IP versions >= 2.5 */
|
||||
@@ -1326,9 +1333,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
||||
else
|
||||
tx_trans_cfg |= UART_CTS_MASK;
|
||||
|
||||
if (baud)
|
||||
if (baud) {
|
||||
uart_update_timeout(uport, termios->c_cflag, baud);
|
||||
|
||||
/*
|
||||
* Make sure that qcom_geni_serial_poll_bitfield() waits for
|
||||
* the FIFO, two-word intermediate transfer register and shift
|
||||
* register to clear.
|
||||
*
|
||||
* Note that uart_fifo_timeout() also adds a 20 ms margin.
|
||||
*/
|
||||
timeout = jiffies_to_usecs(uart_fifo_timeout(uport));
|
||||
timeout += 3 * timeout / port->tx_fifo_depth;
|
||||
WRITE_ONCE(port->poll_timeout_us, timeout);
|
||||
}
|
||||
|
||||
if (!uart_console(uport))
|
||||
writel(port->loopback,
|
||||
uport->membase + SE_UART_LOOPBACK_CFG);
|
||||
|
||||
@@ -577,8 +577,8 @@ static void rp2_reset_asic(struct rp2_card *card, unsigned int asic_id)
|
||||
u32 clk_cfg;
|
||||
|
||||
writew(1, base + RP2_GLOBAL_CMD);
|
||||
readw(base + RP2_GLOBAL_CMD);
|
||||
msleep(100);
|
||||
readw(base + RP2_GLOBAL_CMD);
|
||||
writel(0, base + RP2_CLK_PRESCALER);
|
||||
|
||||
/* TDM clock configuration */
|
||||
|
||||
@@ -550,6 +550,7 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
|
||||
case TYPE_APPLE_S5L:
|
||||
s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON);
|
||||
s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON);
|
||||
s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_LEGACY_ENA, S3C2410_UCON);
|
||||
break;
|
||||
default:
|
||||
disable_irq_nosync(ourport->rx_irq);
|
||||
@@ -707,9 +708,8 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
|
||||
|
||||
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_dma(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct s3c24xx_uart_dma *dma = ourport->dma;
|
||||
struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
|
||||
@@ -843,9 +843,8 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
|
||||
static irqreturn_t s3c24xx_serial_rx_chars_pio(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
|
||||
uart_port_lock(port);
|
||||
@@ -855,13 +854,11 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t s3c24xx_serial_rx_irq(int irq, void *dev_id)
|
||||
static irqreturn_t s3c24xx_serial_rx_irq(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
|
||||
if (ourport->dma && ourport->dma->rx_chan)
|
||||
return s3c24xx_serial_rx_chars_dma(dev_id);
|
||||
return s3c24xx_serial_rx_chars_pio(dev_id);
|
||||
return s3c24xx_serial_rx_chars_dma(ourport);
|
||||
return s3c24xx_serial_rx_chars_pio(ourport);
|
||||
}
|
||||
|
||||
static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
|
||||
@@ -928,9 +925,8 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
|
||||
s3c24xx_serial_stop_tx(port);
|
||||
}
|
||||
|
||||
static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id)
|
||||
static irqreturn_t s3c24xx_serial_tx_irq(struct s3c24xx_uart_port *ourport)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
|
||||
uart_port_lock(port);
|
||||
@@ -944,17 +940,17 @@ static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id)
|
||||
/* interrupt handler for s3c64xx and later SoC's.*/
|
||||
static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
|
||||
{
|
||||
const struct s3c24xx_uart_port *ourport = id;
|
||||
struct s3c24xx_uart_port *ourport = id;
|
||||
const struct uart_port *port = &ourport->port;
|
||||
u32 pend = rd_regl(port, S3C64XX_UINTP);
|
||||
irqreturn_t ret = IRQ_HANDLED;
|
||||
|
||||
if (pend & S3C64XX_UINTM_RXD_MSK) {
|
||||
ret = s3c24xx_serial_rx_irq(irq, id);
|
||||
ret = s3c24xx_serial_rx_irq(ourport);
|
||||
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
|
||||
}
|
||||
if (pend & S3C64XX_UINTM_TXD_MSK) {
|
||||
ret = s3c24xx_serial_tx_irq(irq, id);
|
||||
ret = s3c24xx_serial_tx_irq(ourport);
|
||||
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
|
||||
}
|
||||
return ret;
|
||||
@@ -963,19 +959,21 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
|
||||
/* interrupt handler for Apple SoC's.*/
|
||||
static irqreturn_t apple_serial_handle_irq(int irq, void *id)
|
||||
{
|
||||
const struct s3c24xx_uart_port *ourport = id;
|
||||
struct s3c24xx_uart_port *ourport = id;
|
||||
const struct uart_port *port = &ourport->port;
|
||||
u32 pend = rd_regl(port, S3C2410_UTRSTAT);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) {
|
||||
if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO |
|
||||
APPLE_S5L_UTRSTAT_RXTO_LEGACY)) {
|
||||
wr_regl(port, S3C2410_UTRSTAT,
|
||||
APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO);
|
||||
ret = s3c24xx_serial_rx_irq(irq, id);
|
||||
APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO |
|
||||
APPLE_S5L_UTRSTAT_RXTO_LEGACY);
|
||||
ret = s3c24xx_serial_rx_irq(ourport);
|
||||
}
|
||||
if (pend & APPLE_S5L_UTRSTAT_TXTHRESH) {
|
||||
wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_TXTHRESH);
|
||||
ret = s3c24xx_serial_tx_irq(irq, id);
|
||||
ret = s3c24xx_serial_tx_irq(ourport);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1195,7 +1193,8 @@ static void apple_s5l_serial_shutdown(struct uart_port *port)
|
||||
ucon = rd_regl(port, S3C2410_UCON);
|
||||
ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTHRESH_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTO_ENA_MSK);
|
||||
APPLE_S5L_UCON_RXTO_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK);
|
||||
wr_regl(port, S3C2410_UCON, ucon);
|
||||
|
||||
wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS);
|
||||
@@ -1292,6 +1291,7 @@ static int apple_s5l_serial_startup(struct uart_port *port)
|
||||
/* Enable Rx Interrupt */
|
||||
s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON);
|
||||
s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON);
|
||||
s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_LEGACY_ENA, S3C2410_UCON);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -2148,13 +2148,15 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
|
||||
|
||||
ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTHRESH_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTO_ENA_MSK);
|
||||
APPLE_S5L_UCON_RXTO_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK);
|
||||
|
||||
if (ourport->tx_enabled)
|
||||
ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK;
|
||||
if (ourport->rx_enabled)
|
||||
ucon |= APPLE_S5L_UCON_RXTHRESH_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTO_ENA_MSK;
|
||||
APPLE_S5L_UCON_RXTO_ENA_MSK |
|
||||
APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK;
|
||||
|
||||
wr_regl(port, S3C2410_UCON, ucon);
|
||||
|
||||
@@ -2541,7 +2543,7 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
|
||||
.name = "Apple S5L UART",
|
||||
.type = TYPE_APPLE_S5L,
|
||||
.port_type = PORT_8250,
|
||||
.iotype = UPIO_MEM,
|
||||
.iotype = UPIO_MEM32,
|
||||
.fifosize = 16,
|
||||
.rx_fifomask = S3C2410_UFSTAT_RXMASK,
|
||||
.rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,
|
||||
@@ -2827,6 +2829,9 @@ OF_EARLYCON_DECLARE(gs101, "google,gs101-uart", gs101_early_console_setup);
|
||||
static int __init apple_s5l_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
/* Apple A7-A11 requires MMIO32 register accesses. */
|
||||
device->port.iotype = UPIO_MEM32;
|
||||
|
||||
/* Close enough to S3C2410 for earlycon... */
|
||||
device->port.private_data = &s3c2410_early_console_data;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#undef DEFAULT_SYMBOL_NAMESPACE
|
||||
#define DEFAULT_SYMBOL_NAMESPACE SERIAL_NXP_SC16IS7XX
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
@@ -78,52 +79,52 @@
|
||||
#define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */
|
||||
|
||||
/* IER register bits */
|
||||
#define SC16IS7XX_IER_RDI_BIT (1 << 0) /* Enable RX data interrupt */
|
||||
#define SC16IS7XX_IER_THRI_BIT (1 << 1) /* Enable TX holding register
|
||||
#define SC16IS7XX_IER_RDI_BIT BIT(0) /* Enable RX data interrupt */
|
||||
#define SC16IS7XX_IER_THRI_BIT BIT(1) /* Enable TX holding register
|
||||
* interrupt */
|
||||
#define SC16IS7XX_IER_RLSI_BIT (1 << 2) /* Enable RX line status
|
||||
#define SC16IS7XX_IER_RLSI_BIT BIT(2) /* Enable RX line status
|
||||
* interrupt */
|
||||
#define SC16IS7XX_IER_MSI_BIT (1 << 3) /* Enable Modem status
|
||||
#define SC16IS7XX_IER_MSI_BIT BIT(3) /* Enable Modem status
|
||||
* interrupt */
|
||||
|
||||
/* IER register bits - write only if (EFR[4] == 1) */
|
||||
#define SC16IS7XX_IER_SLEEP_BIT (1 << 4) /* Enable Sleep mode */
|
||||
#define SC16IS7XX_IER_XOFFI_BIT (1 << 5) /* Enable Xoff interrupt */
|
||||
#define SC16IS7XX_IER_RTSI_BIT (1 << 6) /* Enable nRTS interrupt */
|
||||
#define SC16IS7XX_IER_CTSI_BIT (1 << 7) /* Enable nCTS interrupt */
|
||||
#define SC16IS7XX_IER_SLEEP_BIT BIT(4) /* Enable Sleep mode */
|
||||
#define SC16IS7XX_IER_XOFFI_BIT BIT(5) /* Enable Xoff interrupt */
|
||||
#define SC16IS7XX_IER_RTSI_BIT BIT(6) /* Enable nRTS interrupt */
|
||||
#define SC16IS7XX_IER_CTSI_BIT BIT(7) /* Enable nCTS interrupt */
|
||||
|
||||
/* FCR register bits */
|
||||
#define SC16IS7XX_FCR_FIFO_BIT (1 << 0) /* Enable FIFO */
|
||||
#define SC16IS7XX_FCR_RXRESET_BIT (1 << 1) /* Reset RX FIFO */
|
||||
#define SC16IS7XX_FCR_TXRESET_BIT (1 << 2) /* Reset TX FIFO */
|
||||
#define SC16IS7XX_FCR_RXLVLL_BIT (1 << 6) /* RX Trigger level LSB */
|
||||
#define SC16IS7XX_FCR_RXLVLH_BIT (1 << 7) /* RX Trigger level MSB */
|
||||
#define SC16IS7XX_FCR_FIFO_BIT BIT(0) /* Enable FIFO */
|
||||
#define SC16IS7XX_FCR_RXRESET_BIT BIT(1) /* Reset RX FIFO */
|
||||
#define SC16IS7XX_FCR_TXRESET_BIT BIT(2) /* Reset TX FIFO */
|
||||
#define SC16IS7XX_FCR_RXLVLL_BIT BIT(6) /* RX Trigger level LSB */
|
||||
#define SC16IS7XX_FCR_RXLVLH_BIT BIT(7) /* RX Trigger level MSB */
|
||||
|
||||
/* FCR register bits - write only if (EFR[4] == 1) */
|
||||
#define SC16IS7XX_FCR_TXLVLL_BIT (1 << 4) /* TX Trigger level LSB */
|
||||
#define SC16IS7XX_FCR_TXLVLH_BIT (1 << 5) /* TX Trigger level MSB */
|
||||
#define SC16IS7XX_FCR_TXLVLL_BIT BIT(4) /* TX Trigger level LSB */
|
||||
#define SC16IS7XX_FCR_TXLVLH_BIT BIT(5) /* TX Trigger level MSB */
|
||||
|
||||
/* IIR register bits */
|
||||
#define SC16IS7XX_IIR_NO_INT_BIT (1 << 0) /* No interrupts pending */
|
||||
#define SC16IS7XX_IIR_ID_MASK 0x3e /* Mask for the interrupt ID */
|
||||
#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */
|
||||
#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */
|
||||
#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */
|
||||
#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */
|
||||
#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */
|
||||
#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state
|
||||
* from active (LOW)
|
||||
* to inactive (HIGH)
|
||||
*/
|
||||
#define SC16IS7XX_IIR_NO_INT_BIT 0x01 /* No interrupts pending */
|
||||
#define SC16IS7XX_IIR_ID_MASK GENMASK(5, 1) /* Mask for the interrupt ID */
|
||||
#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */
|
||||
#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */
|
||||
#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */
|
||||
#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */
|
||||
#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */
|
||||
#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state
|
||||
* from active (LOW)
|
||||
* to inactive (HIGH)
|
||||
*/
|
||||
/* LCR register bits */
|
||||
#define SC16IS7XX_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
|
||||
#define SC16IS7XX_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
|
||||
#define SC16IS7XX_LCR_LENGTH0_BIT BIT(0) /* Word length bit 0 */
|
||||
#define SC16IS7XX_LCR_LENGTH1_BIT BIT(1) /* Word length bit 1
|
||||
*
|
||||
* Word length bits table:
|
||||
* 00 -> 5 bit words
|
||||
@@ -131,7 +132,7 @@
|
||||
* 10 -> 7 bit words
|
||||
* 11 -> 8 bit words
|
||||
*/
|
||||
#define SC16IS7XX_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
|
||||
#define SC16IS7XX_LCR_STOPLEN_BIT BIT(2) /* STOP length bit
|
||||
*
|
||||
* STOP length bit table:
|
||||
* 0 -> 1 stop bit
|
||||
@@ -139,11 +140,11 @@
|
||||
* word length is 5,
|
||||
* 2 stop bits otherwise
|
||||
*/
|
||||
#define SC16IS7XX_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
|
||||
#define SC16IS7XX_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
|
||||
#define SC16IS7XX_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
|
||||
#define SC16IS7XX_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
|
||||
#define SC16IS7XX_LCR_DLAB_BIT (1 << 7) /* Divisor Latch enable */
|
||||
#define SC16IS7XX_LCR_PARITY_BIT BIT(3) /* Parity bit enable */
|
||||
#define SC16IS7XX_LCR_EVENPARITY_BIT BIT(4) /* Even parity bit enable */
|
||||
#define SC16IS7XX_LCR_FORCEPARITY_BIT BIT(5) /* 9-bit multidrop parity */
|
||||
#define SC16IS7XX_LCR_TXBREAK_BIT BIT(6) /* TX break enable */
|
||||
#define SC16IS7XX_LCR_DLAB_BIT BIT(7) /* Divisor Latch enable */
|
||||
#define SC16IS7XX_LCR_WORD_LEN_5 (0x00)
|
||||
#define SC16IS7XX_LCR_WORD_LEN_6 (0x01)
|
||||
#define SC16IS7XX_LCR_WORD_LEN_7 (0x02)
|
||||
@@ -154,61 +155,65 @@
|
||||
* reg set */
|
||||
|
||||
/* MCR register bits */
|
||||
#define SC16IS7XX_MCR_DTR_BIT (1 << 0) /* DTR complement
|
||||
#define SC16IS7XX_MCR_DTR_BIT BIT(0) /* DTR complement
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MCR_RTS_BIT (1 << 1) /* RTS complement */
|
||||
#define SC16IS7XX_MCR_TCRTLR_BIT (1 << 2) /* TCR/TLR register enable */
|
||||
#define SC16IS7XX_MCR_LOOP_BIT (1 << 4) /* Enable loopback test mode */
|
||||
#define SC16IS7XX_MCR_XONANY_BIT (1 << 5) /* Enable Xon Any
|
||||
#define SC16IS7XX_MCR_RTS_BIT BIT(1) /* RTS complement */
|
||||
#define SC16IS7XX_MCR_TCRTLR_BIT BIT(2) /* TCR/TLR register enable */
|
||||
#define SC16IS7XX_MCR_LOOP_BIT BIT(4) /* Enable loopback test mode */
|
||||
#define SC16IS7XX_MCR_XONANY_BIT BIT(5) /* Enable Xon Any
|
||||
* - write enabled
|
||||
* if (EFR[4] == 1)
|
||||
*/
|
||||
#define SC16IS7XX_MCR_IRDA_BIT (1 << 6) /* Enable IrDA mode
|
||||
#define SC16IS7XX_MCR_IRDA_BIT BIT(6) /* Enable IrDA mode
|
||||
* - write enabled
|
||||
* if (EFR[4] == 1)
|
||||
*/
|
||||
#define SC16IS7XX_MCR_CLKSEL_BIT (1 << 7) /* Divide clock by 4
|
||||
#define SC16IS7XX_MCR_CLKSEL_BIT BIT(7) /* Divide clock by 4
|
||||
* - write enabled
|
||||
* if (EFR[4] == 1)
|
||||
*/
|
||||
|
||||
/* LSR register bits */
|
||||
#define SC16IS7XX_LSR_DR_BIT (1 << 0) /* Receiver data ready */
|
||||
#define SC16IS7XX_LSR_OE_BIT (1 << 1) /* Overrun Error */
|
||||
#define SC16IS7XX_LSR_PE_BIT (1 << 2) /* Parity Error */
|
||||
#define SC16IS7XX_LSR_FE_BIT (1 << 3) /* Frame Error */
|
||||
#define SC16IS7XX_LSR_BI_BIT (1 << 4) /* Break Interrupt */
|
||||
#define SC16IS7XX_LSR_BRK_ERROR_MASK 0x1E /* BI, FE, PE, OE bits */
|
||||
#define SC16IS7XX_LSR_THRE_BIT (1 << 5) /* TX holding register empty */
|
||||
#define SC16IS7XX_LSR_TEMT_BIT (1 << 6) /* Transmitter empty */
|
||||
#define SC16IS7XX_LSR_FIFOE_BIT (1 << 7) /* Fifo Error */
|
||||
#define SC16IS7XX_LSR_DR_BIT BIT(0) /* Receiver data ready */
|
||||
#define SC16IS7XX_LSR_OE_BIT BIT(1) /* Overrun Error */
|
||||
#define SC16IS7XX_LSR_PE_BIT BIT(2) /* Parity Error */
|
||||
#define SC16IS7XX_LSR_FE_BIT BIT(3) /* Frame Error */
|
||||
#define SC16IS7XX_LSR_BI_BIT BIT(4) /* Break Interrupt */
|
||||
#define SC16IS7XX_LSR_BRK_ERROR_MASK \
|
||||
(SC16IS7XX_LSR_OE_BIT | \
|
||||
SC16IS7XX_LSR_PE_BIT | \
|
||||
SC16IS7XX_LSR_FE_BIT | \
|
||||
SC16IS7XX_LSR_BI_BIT)
|
||||
|
||||
#define SC16IS7XX_LSR_THRE_BIT BIT(5) /* TX holding register empty */
|
||||
#define SC16IS7XX_LSR_TEMT_BIT BIT(6) /* Transmitter empty */
|
||||
#define SC16IS7XX_LSR_FIFOE_BIT BIT(7) /* Fifo Error */
|
||||
|
||||
/* MSR register bits */
|
||||
#define SC16IS7XX_MSR_DCTS_BIT (1 << 0) /* Delta CTS Clear To Send */
|
||||
#define SC16IS7XX_MSR_DDSR_BIT (1 << 1) /* Delta DSR Data Set Ready
|
||||
#define SC16IS7XX_MSR_DCTS_BIT BIT(0) /* Delta CTS Clear To Send */
|
||||
#define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready
|
||||
* or (IO4)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_DRI_BIT (1 << 2) /* Delta RI Ring Indicator
|
||||
#define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator
|
||||
* or (IO7)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_DCD_BIT (1 << 3) /* Delta CD Carrier Detect
|
||||
#define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect
|
||||
* or (IO6)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */
|
||||
#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4)
|
||||
#define SC16IS7XX_MSR_CTS_BIT BIT(4) /* CTS */
|
||||
#define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7)
|
||||
#define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6)
|
||||
#define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6)
|
||||
* - only on 75x/76x
|
||||
*/
|
||||
#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */
|
||||
|
||||
/*
|
||||
* TCR register bits
|
||||
@@ -241,19 +246,19 @@
|
||||
#define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4)
|
||||
|
||||
/* IOControl register bits (Only 75x/76x) */
|
||||
#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
|
||||
#define SC16IS7XX_IOCONTROL_MODEM_A_BIT (1 << 1) /* Enable GPIO[7:4] as modem A pins */
|
||||
#define SC16IS7XX_IOCONTROL_MODEM_B_BIT (1 << 2) /* Enable GPIO[3:0] as modem B pins */
|
||||
#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */
|
||||
#define SC16IS7XX_IOCONTROL_LATCH_BIT BIT(0) /* Enable input latching */
|
||||
#define SC16IS7XX_IOCONTROL_MODEM_A_BIT BIT(1) /* Enable GPIO[7:4] as modem A pins */
|
||||
#define SC16IS7XX_IOCONTROL_MODEM_B_BIT BIT(2) /* Enable GPIO[3:0] as modem B pins */
|
||||
#define SC16IS7XX_IOCONTROL_SRESET_BIT BIT(3) /* Software Reset */
|
||||
|
||||
/* EFCR register bits */
|
||||
#define SC16IS7XX_EFCR_9BIT_MODE_BIT (1 << 0) /* Enable 9-bit or Multidrop
|
||||
#define SC16IS7XX_EFCR_9BIT_MODE_BIT BIT(0) /* Enable 9-bit or Multidrop
|
||||
* mode (RS485) */
|
||||
#define SC16IS7XX_EFCR_RXDISABLE_BIT (1 << 1) /* Disable receiver */
|
||||
#define SC16IS7XX_EFCR_TXDISABLE_BIT (1 << 2) /* Disable transmitter */
|
||||
#define SC16IS7XX_EFCR_AUTO_RS485_BIT (1 << 4) /* Auto RS485 RTS direction */
|
||||
#define SC16IS7XX_EFCR_RTS_INVERT_BIT (1 << 5) /* RTS output inversion */
|
||||
#define SC16IS7XX_EFCR_IRDA_MODE_BIT (1 << 7) /* IrDA mode
|
||||
#define SC16IS7XX_EFCR_RXDISABLE_BIT BIT(1) /* Disable receiver */
|
||||
#define SC16IS7XX_EFCR_TXDISABLE_BIT BIT(2) /* Disable transmitter */
|
||||
#define SC16IS7XX_EFCR_AUTO_RS485_BIT BIT(4) /* Auto RS485 RTS direction */
|
||||
#define SC16IS7XX_EFCR_RTS_INVERT_BIT BIT(5) /* RTS output inversion */
|
||||
#define SC16IS7XX_EFCR_IRDA_MODE_BIT BIT(7) /* IrDA mode
|
||||
* 0 = rate upto 115.2 kbit/s
|
||||
* - Only 75x/76x
|
||||
* 1 = rate upto 1.152 Mbit/s
|
||||
@@ -261,16 +266,16 @@
|
||||
*/
|
||||
|
||||
/* EFR register bits */
|
||||
#define SC16IS7XX_EFR_AUTORTS_BIT (1 << 6) /* Auto RTS flow ctrl enable */
|
||||
#define SC16IS7XX_EFR_AUTOCTS_BIT (1 << 7) /* Auto CTS flow ctrl enable */
|
||||
#define SC16IS7XX_EFR_XOFF2_DETECT_BIT (1 << 5) /* Enable Xoff2 detection */
|
||||
#define SC16IS7XX_EFR_ENABLE_BIT (1 << 4) /* Enable enhanced functions
|
||||
#define SC16IS7XX_EFR_AUTORTS_BIT BIT(6) /* Auto RTS flow ctrl enable */
|
||||
#define SC16IS7XX_EFR_AUTOCTS_BIT BIT(7) /* Auto CTS flow ctrl enable */
|
||||
#define SC16IS7XX_EFR_XOFF2_DETECT_BIT BIT(5) /* Enable Xoff2 detection */
|
||||
#define SC16IS7XX_EFR_ENABLE_BIT BIT(4) /* Enable enhanced functions
|
||||
* and writing to IER[7:4],
|
||||
* FCR[5:4], MCR[7:5]
|
||||
*/
|
||||
#define SC16IS7XX_EFR_SWFLOW3_BIT (1 << 3) /* SWFLOW bit 3 */
|
||||
#define SC16IS7XX_EFR_SWFLOW2_BIT (1 << 2) /* SWFLOW bit 2
|
||||
*
|
||||
#define SC16IS7XX_EFR_SWFLOW3_BIT BIT(3)
|
||||
#define SC16IS7XX_EFR_SWFLOW2_BIT BIT(2)
|
||||
/*
|
||||
* SWFLOW bits 3 & 2 table:
|
||||
* 00 -> no transmitter flow
|
||||
* control
|
||||
@@ -282,10 +287,10 @@
|
||||
* XON1, XON2, XOFF1 and
|
||||
* XOFF2
|
||||
*/
|
||||
#define SC16IS7XX_EFR_SWFLOW1_BIT (1 << 1) /* SWFLOW bit 2 */
|
||||
#define SC16IS7XX_EFR_SWFLOW0_BIT (1 << 0) /* SWFLOW bit 3
|
||||
*
|
||||
* SWFLOW bits 3 & 2 table:
|
||||
#define SC16IS7XX_EFR_SWFLOW1_BIT BIT(1)
|
||||
#define SC16IS7XX_EFR_SWFLOW0_BIT BIT(0)
|
||||
/*
|
||||
* SWFLOW bits 1 & 0 table:
|
||||
* 00 -> no received flow
|
||||
* control
|
||||
* 01 -> receiver compares
|
||||
@@ -309,9 +314,9 @@
|
||||
#define SC16IS7XX_FIFO_SIZE (64)
|
||||
#define SC16IS7XX_GPIOS_PER_BANK 4
|
||||
|
||||
#define SC16IS7XX_RECONF_MD (1 << 0)
|
||||
#define SC16IS7XX_RECONF_IER (1 << 1)
|
||||
#define SC16IS7XX_RECONF_RS485 (1 << 2)
|
||||
#define SC16IS7XX_RECONF_MD BIT(0)
|
||||
#define SC16IS7XX_RECONF_IER BIT(1)
|
||||
#define SC16IS7XX_RECONF_RS485 BIT(2)
|
||||
|
||||
struct sc16is7xx_one_config {
|
||||
unsigned int flags;
|
||||
|
||||
@@ -407,14 +407,16 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
||||
/*
|
||||
* Turn off DTR and RTS early.
|
||||
*/
|
||||
if (uport && uart_console(uport) && tty) {
|
||||
uport->cons->cflag = tty->termios.c_cflag;
|
||||
uport->cons->ispeed = tty->termios.c_ispeed;
|
||||
uport->cons->ospeed = tty->termios.c_ospeed;
|
||||
}
|
||||
if (uport) {
|
||||
if (uart_console(uport) && tty) {
|
||||
uport->cons->cflag = tty->termios.c_cflag;
|
||||
uport->cons->ispeed = tty->termios.c_ispeed;
|
||||
uport->cons->ospeed = tty->termios.c_ospeed;
|
||||
}
|
||||
|
||||
if (!tty || C_HUPCL(tty))
|
||||
uart_port_dtr_rts(uport, false);
|
||||
if (!tty || C_HUPCL(tty))
|
||||
uart_port_dtr_rts(uport, false);
|
||||
}
|
||||
|
||||
uart_port_shutdown(port);
|
||||
}
|
||||
@@ -1102,21 +1104,19 @@ static int uart_tiocmget(struct tty_struct *tty)
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct tty_port *port = &state->port;
|
||||
struct uart_port *uport;
|
||||
int result = -EIO;
|
||||
int result;
|
||||
|
||||
guard(mutex)(&port->mutex);
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
uport = uart_port_check(state);
|
||||
if (!uport)
|
||||
goto out;
|
||||
if (!uport || tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
uart_port_lock_irq(uport);
|
||||
result = uport->mctrl;
|
||||
result |= uport->ops->get_mctrl(uport);
|
||||
uart_port_unlock_irq(uport);
|
||||
|
||||
if (!tty_io_error(tty)) {
|
||||
uart_port_lock_irq(uport);
|
||||
result = uport->mctrl;
|
||||
result |= uport->ops->get_mctrl(uport);
|
||||
uart_port_unlock_irq(uport);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&port->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1126,20 +1126,16 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct tty_port *port = &state->port;
|
||||
struct uart_port *uport;
|
||||
int ret = -EIO;
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
guard(mutex)(&port->mutex);
|
||||
|
||||
uport = uart_port_check(state);
|
||||
if (!uport)
|
||||
goto out;
|
||||
if (!uport || tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
if (!tty_io_error(tty)) {
|
||||
uart_update_mctrl(uport, set, clear);
|
||||
ret = 0;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&port->mutex);
|
||||
return ret;
|
||||
uart_update_mctrl(uport, set, clear);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uart_break_ctl(struct tty_struct *tty, int break_state)
|
||||
@@ -1147,19 +1143,17 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state)
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct tty_port *port = &state->port;
|
||||
struct uart_port *uport;
|
||||
int ret = -EIO;
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
guard(mutex)(&port->mutex);
|
||||
|
||||
uport = uart_port_check(state);
|
||||
if (!uport)
|
||||
goto out;
|
||||
return -EIO;
|
||||
|
||||
if (uport->type != PORT_UNKNOWN && uport->ops->break_ctl)
|
||||
uport->ops->break_ctl(uport, break_state);
|
||||
ret = 0;
|
||||
out:
|
||||
mutex_unlock(&port->mutex);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
|
||||
@@ -1176,17 +1170,14 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
|
||||
* changing, and hence any extra opens of the port while
|
||||
* we're auto-configuring.
|
||||
*/
|
||||
if (mutex_lock_interruptible(&port->mutex))
|
||||
return -ERESTARTSYS;
|
||||
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &port->mutex) {
|
||||
uport = uart_port_check(state);
|
||||
if (!uport)
|
||||
return -EIO;
|
||||
|
||||
uport = uart_port_check(state);
|
||||
if (!uport) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
if (tty_port_users(port) != 1)
|
||||
return -EBUSY;
|
||||
|
||||
ret = -EBUSY;
|
||||
if (tty_port_users(port) == 1) {
|
||||
uart_shutdown(tty, state);
|
||||
|
||||
/*
|
||||
@@ -1207,14 +1198,15 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
|
||||
uport->ops->config_port(uport, flags);
|
||||
|
||||
ret = uart_startup(tty, state, true);
|
||||
if (ret == 0)
|
||||
tty_port_set_initialized(port, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
return 0;
|
||||
|
||||
tty_port_set_initialized(port, true);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&port->mutex);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uart_enable_ms(struct uart_port *uport)
|
||||
@@ -1709,10 +1701,11 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||
unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
|
||||
bool sw_changed = false;
|
||||
|
||||
mutex_lock(&state->port.mutex);
|
||||
guard(mutex)(&state->port.mutex);
|
||||
|
||||
uport = uart_port_check(state);
|
||||
if (!uport)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
/*
|
||||
* Drivers doing software flow control also need to know
|
||||
@@ -1735,9 +1728,8 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||
tty->termios.c_ospeed == old_termios->c_ospeed &&
|
||||
tty->termios.c_ispeed == old_termios->c_ispeed &&
|
||||
((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
|
||||
!sw_changed) {
|
||||
goto out;
|
||||
}
|
||||
!sw_changed)
|
||||
return;
|
||||
|
||||
uart_change_line_settings(tty, state, old_termios);
|
||||
/* reload cflag from termios; port driver may have overridden flags */
|
||||
@@ -1754,8 +1746,6 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||
mask |= TIOCM_RTS;
|
||||
uart_set_mctrl(uport, mask);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&state->port.mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2049,10 +2039,11 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
||||
unsigned int status;
|
||||
int mmio;
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
guard(mutex)(&port->mutex);
|
||||
|
||||
uport = uart_port_check(state);
|
||||
if (!uport)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
mmio = uport->iotype >= UPIO_MEM;
|
||||
seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
|
||||
@@ -2064,7 +2055,7 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
||||
|
||||
if (uport->type == PORT_UNKNOWN) {
|
||||
seq_putc(m, '\n');
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
if (capable(CAP_SYS_ADMIN)) {
|
||||
@@ -2115,8 +2106,6 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
||||
seq_putc(m, '\n');
|
||||
#undef STATBIT
|
||||
#undef INFOBIT
|
||||
out:
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
|
||||
static int uart_proc_show(struct seq_file *m, void *v)
|
||||
@@ -2393,13 +2382,12 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
struct device *tty_dev;
|
||||
struct uart_match match = {uport, drv};
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
guard(mutex)(&port->mutex);
|
||||
|
||||
tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port);
|
||||
if (tty_dev && device_may_wakeup(tty_dev)) {
|
||||
enable_irq_wake(uport->irq);
|
||||
put_device(tty_dev);
|
||||
mutex_unlock(&port->mutex);
|
||||
return 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
@@ -2417,7 +2405,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
uart_port_unlock_irq(uport);
|
||||
}
|
||||
device_set_awake_path(uport->dev);
|
||||
goto unlock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uport->suspended = 1;
|
||||
@@ -2460,8 +2448,6 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
console_stop(uport->cons);
|
||||
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
unlock:
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2475,14 +2461,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
struct uart_match match = {uport, drv};
|
||||
struct ktermios termios;
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
guard(mutex)(&port->mutex);
|
||||
|
||||
tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port);
|
||||
if (!uport->suspended && device_may_wakeup(tty_dev)) {
|
||||
if (irqd_is_wakeup_set(irq_get_irq_data((uport->irq))))
|
||||
disable_irq_wake(uport->irq);
|
||||
put_device(tty_dev);
|
||||
mutex_unlock(&port->mutex);
|
||||
return 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
@@ -2555,8 +2540,6 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
tty_port_set_suspended(port, false);
|
||||
}
|
||||
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(uart_resume_port);
|
||||
@@ -2696,14 +2679,13 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
|
||||
int ret = 0;
|
||||
|
||||
tport = &state->port;
|
||||
mutex_lock(&tport->mutex);
|
||||
|
||||
guard(mutex)(&tport->mutex);
|
||||
|
||||
port = uart_port_check(state);
|
||||
if (!port || port->type == PORT_UNKNOWN ||
|
||||
!(port->ops->poll_get_char && port->ops->poll_put_char)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
!(port->ops->poll_get_char && port->ops->poll_put_char))
|
||||
return -1;
|
||||
|
||||
pm_state = state->pm_state;
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
@@ -2723,10 +2705,10 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
|
||||
ret = uart_set_options(port, NULL, baud, parity, bits, flow);
|
||||
console_list_unlock();
|
||||
}
|
||||
out:
|
||||
|
||||
if (ret)
|
||||
uart_change_pm(state, pm_state);
|
||||
mutex_unlock(&tport->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -808,7 +808,6 @@ static void asc_serial_remove(struct platform_device *pdev)
|
||||
uart_remove_one_port(&asc_uart_driver, port);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int asc_serial_suspend(struct device *dev)
|
||||
{
|
||||
struct uart_port *port = dev_get_drvdata(dev);
|
||||
@@ -823,8 +822,6 @@ static int asc_serial_resume(struct device *dev)
|
||||
return uart_resume_port(&asc_uart_driver, port);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_SERIAL_ST_ASC_CONSOLE
|
||||
@@ -932,16 +929,15 @@ static struct uart_driver asc_uart_driver = {
|
||||
.cons = ASC_SERIAL_CONSOLE,
|
||||
};
|
||||
|
||||
static const struct dev_pm_ops asc_serial_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(asc_serial_suspend, asc_serial_resume)
|
||||
};
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(asc_serial_pm_ops, asc_serial_suspend,
|
||||
asc_serial_resume);
|
||||
|
||||
static struct platform_driver asc_serial_driver = {
|
||||
.probe = asc_serial_probe,
|
||||
.remove_new = asc_serial_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.pm = &asc_serial_pm_ops,
|
||||
.pm = pm_sleep_ptr(&asc_serial_pm_ops),
|
||||
.of_match_table = of_match_ptr(asc_match),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -219,7 +219,7 @@ struct cdns_platform_data {
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
struct serial_rs485 cdns_rs485_supported = {
|
||||
static struct serial_rs485 cdns_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
|
||||
SER_RS485_RTS_AFTER_SEND,
|
||||
.delay_rts_before_send = 1,
|
||||
|
||||
@@ -350,22 +350,19 @@ int tty_dev_name_to_number(const char *name, dev_t *number)
|
||||
return ret;
|
||||
|
||||
prefix_length = str - name;
|
||||
mutex_lock(&tty_mutex);
|
||||
|
||||
guard(mutex)(&tty_mutex);
|
||||
|
||||
list_for_each_entry(p, &tty_drivers, tty_drivers)
|
||||
if (prefix_length == strlen(p->name) && strncmp(name,
|
||||
p->name, prefix_length) == 0) {
|
||||
if (index < p->num) {
|
||||
*number = MKDEV(p->major, p->minor_start + index);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* if here then driver wasn't found */
|
||||
ret = -ENODEV;
|
||||
out:
|
||||
mutex_unlock(&tty_mutex);
|
||||
return ret;
|
||||
return -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_dev_name_to_number);
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@ struct cdns3_wrap {
|
||||
#define PCI_DRIVER_NAME "cdns3-pci-usbss"
|
||||
#define PLAT_DRIVER_NAME "cdns-usb3"
|
||||
|
||||
#define CDNS_VENDOR_ID 0x17cd
|
||||
#define CDNS_DEVICE_ID 0x0100
|
||||
#define PCI_DEVICE_ID_CDNS_USB3 0x0100
|
||||
|
||||
static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev)
|
||||
{
|
||||
@@ -190,7 +189,7 @@ static void cdns3_pci_remove(struct pci_dev *pdev)
|
||||
}
|
||||
|
||||
static const struct pci_device_id cdns3_pci_ids[] = {
|
||||
{ PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), },
|
||||
{ PCI_VDEVICE(CDNS, PCI_DEVICE_ID_CDNS_USB3) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
||||
@@ -28,10 +28,11 @@
|
||||
#define PCI_DRIVER_NAME "cdns-pci-usbssp"
|
||||
#define PLAT_DRIVER_NAME "cdns-usbssp"
|
||||
|
||||
#define CDNS_VENDOR_ID 0x17cd
|
||||
#define CDNS_DEVICE_ID 0x0200
|
||||
#define CDNS_DRD_ID 0x0100
|
||||
#define CDNS_DRD_IF (PCI_CLASS_SERIAL_USB << 8 | 0x80)
|
||||
#define PCI_DEVICE_ID_CDNS_USB3 0x0100
|
||||
#define PCI_DEVICE_ID_CDNS_UDC 0x0200
|
||||
|
||||
#define PCI_CLASS_SERIAL_USB_CDNS_USB3 (PCI_CLASS_SERIAL_USB << 8 | 0x80)
|
||||
#define PCI_CLASS_SERIAL_USB_CDNS_UDC PCI_CLASS_SERIAL_USB_DEVICE
|
||||
|
||||
static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
|
||||
{
|
||||
@@ -40,10 +41,10 @@ static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
|
||||
* Platform has two function. The fist keeps resources for
|
||||
* Host/Device while the secon keeps resources for DRD/OTG.
|
||||
*/
|
||||
if (pdev->device == CDNS_DEVICE_ID)
|
||||
return pci_get_device(pdev->vendor, CDNS_DRD_ID, NULL);
|
||||
else if (pdev->device == CDNS_DRD_ID)
|
||||
return pci_get_device(pdev->vendor, CDNS_DEVICE_ID, NULL);
|
||||
if (pdev->device == PCI_DEVICE_ID_CDNS_UDC)
|
||||
return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_USB3, NULL);
|
||||
if (pdev->device == PCI_DEVICE_ID_CDNS_USB3)
|
||||
return pci_get_device(pdev->vendor, PCI_DEVICE_ID_CDNS_UDC, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -220,12 +221,12 @@ static const struct dev_pm_ops cdnsp_pci_pm_ops = {
|
||||
};
|
||||
|
||||
static const struct pci_device_id cdnsp_pci_ids[] = {
|
||||
{ PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_SERIAL_USB_DEVICE, PCI_ANY_ID },
|
||||
{ PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
CDNS_DRD_IF, PCI_ANY_ID },
|
||||
{ PCI_VENDOR_ID_CDNS, CDNS_DRD_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
CDNS_DRD_IF, PCI_ANY_ID },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC),
|
||||
.class = PCI_CLASS_SERIAL_USB_CDNS_UDC },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_UDC),
|
||||
.class = PCI_CLASS_SERIAL_USB_CDNS_USB3 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_CDNS, PCI_DEVICE_ID_CDNS_USB3),
|
||||
.class = PCI_CLASS_SERIAL_USB_CDNS_USB3 },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
|
||||
@@ -718,7 +718,8 @@ int cdnsp_remove_request(struct cdnsp_device *pdev,
|
||||
seg = cdnsp_trb_in_td(pdev, cur_td->start_seg, cur_td->first_trb,
|
||||
cur_td->last_trb, hw_deq);
|
||||
|
||||
if (seg && (pep->ep_state & EP_ENABLED))
|
||||
if (seg && (pep->ep_state & EP_ENABLED) &&
|
||||
!(pep->ep_state & EP_DIS_IN_RROGRESS))
|
||||
cdnsp_find_new_dequeue_state(pdev, pep, preq->request.stream_id,
|
||||
cur_td, &deq_state);
|
||||
else
|
||||
@@ -736,7 +737,8 @@ int cdnsp_remove_request(struct cdnsp_device *pdev,
|
||||
* During disconnecting all endpoint will be disabled so we don't
|
||||
* have to worry about updating dequeue pointer.
|
||||
*/
|
||||
if (pdev->cdnsp_state & CDNSP_STATE_DISCONNECT_PENDING) {
|
||||
if (pdev->cdnsp_state & CDNSP_STATE_DISCONNECT_PENDING ||
|
||||
pep->ep_state & EP_DIS_IN_RROGRESS) {
|
||||
status = -ESHUTDOWN;
|
||||
ret = cdnsp_cmd_set_deq(pdev, pep, &deq_state);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,9 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
|
||||
.resume_quirk = xhci_cdns3_resume_quirk,
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
|
||||
static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = {
|
||||
.quirks = XHCI_CDNS_SCTX_QUIRK,
|
||||
};
|
||||
|
||||
static int __cdns_host_init(struct cdns *cdns)
|
||||
{
|
||||
|
||||
@@ -128,7 +128,7 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
|
||||
* In case the fsl,usbmisc property is not present this device doesn't
|
||||
* need usbmisc. Return NULL (which is no error here)
|
||||
*/
|
||||
if (!of_get_property(np, "fsl,usbmisc", NULL))
|
||||
if (!of_property_present(np, "fsl,usbmisc"))
|
||||
return NULL;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
|
||||
@@ -18,7 +18,7 @@ struct npcm_udc_data {
|
||||
struct ci_hdrc_platform_data pdata;
|
||||
};
|
||||
|
||||
static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned event)
|
||||
static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned int event)
|
||||
{
|
||||
struct device *dev = ci->dev->parent;
|
||||
|
||||
@@ -28,7 +28,7 @@ static int npcm_udc_notify_event(struct ci_hdrc *ci, unsigned event)
|
||||
hw_write(ci, OP_USBMODE, 0xffffffff, 0x0);
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "unknown ci_hdrc event (%d)\n",event);
|
||||
dev_dbg(dev, "unknown ci_hdrc event (%d)\n", event);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ static int hw_device_state(struct ci_hdrc *ci, u32 dma)
|
||||
hw_write(ci, OP_ENDPTLISTADDR, ~0, dma);
|
||||
/* interrupt, error, port change, reset, sleep/suspend */
|
||||
hw_write(ci, OP_USBINTR, ~0,
|
||||
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
|
||||
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI);
|
||||
} else {
|
||||
hw_write(ci, OP_USBINTR, ~0, 0);
|
||||
}
|
||||
@@ -877,6 +877,7 @@ __releases(ci->lock)
|
||||
__acquires(ci->lock)
|
||||
{
|
||||
int retval;
|
||||
u32 intr;
|
||||
|
||||
spin_unlock(&ci->lock);
|
||||
if (ci->gadget.speed != USB_SPEED_UNKNOWN)
|
||||
@@ -890,6 +891,11 @@ __acquires(ci->lock)
|
||||
if (retval)
|
||||
goto done;
|
||||
|
||||
/* clear SLI */
|
||||
hw_write(ci, OP_USBSTS, USBi_SLI, USBi_SLI);
|
||||
intr = hw_read(ci, OP_USBINTR, ~0);
|
||||
hw_write(ci, OP_USBINTR, ~0, intr | USBi_SLI);
|
||||
|
||||
ci->status = usb_ep_alloc_request(&ci->ep0in->ep, GFP_ATOMIC);
|
||||
if (ci->status == NULL)
|
||||
retval = -ENOMEM;
|
||||
|
||||
@@ -962,10 +962,12 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
|
||||
struct acm *acm = tty->driver_data;
|
||||
|
||||
ss->line = acm->minor;
|
||||
mutex_lock(&acm->port.mutex);
|
||||
ss->close_delay = jiffies_to_msecs(acm->port.close_delay) / 10;
|
||||
ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
|
||||
ASYNC_CLOSING_WAIT_NONE :
|
||||
jiffies_to_msecs(acm->port.closing_wait) / 10;
|
||||
mutex_unlock(&acm->port.mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -754,7 +754,7 @@ static struct urb *usbtmc_create_urb(void)
|
||||
if (!urb)
|
||||
return NULL;
|
||||
|
||||
dmabuf = kmalloc(bufsize, GFP_KERNEL);
|
||||
dmabuf = kzalloc(bufsize, GFP_KERNEL);
|
||||
if (!dmabuf) {
|
||||
usb_free_urb(urb);
|
||||
return NULL;
|
||||
|
||||
+10
-12
@@ -107,19 +107,18 @@ EXPORT_SYMBOL_GPL(usb_speed_string);
|
||||
*/
|
||||
enum usb_device_speed usb_get_maximum_speed(struct device *dev)
|
||||
{
|
||||
const char *maximum_speed;
|
||||
const char *p = "maximum-speed";
|
||||
int ret;
|
||||
|
||||
ret = device_property_read_string(dev, "maximum-speed", &maximum_speed);
|
||||
if (ret < 0)
|
||||
return USB_SPEED_UNKNOWN;
|
||||
|
||||
ret = match_string(ssp_rate, ARRAY_SIZE(ssp_rate), maximum_speed);
|
||||
ret = device_property_match_property_string(dev, p, ssp_rate, ARRAY_SIZE(ssp_rate));
|
||||
if (ret > 0)
|
||||
return USB_SPEED_SUPER_PLUS;
|
||||
|
||||
ret = match_string(speed_names, ARRAY_SIZE(speed_names), maximum_speed);
|
||||
return (ret < 0) ? USB_SPEED_UNKNOWN : ret;
|
||||
ret = device_property_match_property_string(dev, p, speed_names, ARRAY_SIZE(speed_names));
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
|
||||
return USB_SPEED_UNKNOWN;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_get_maximum_speed);
|
||||
|
||||
@@ -276,14 +275,13 @@ EXPORT_SYMBOL_GPL(usb_decode_interval);
|
||||
*/
|
||||
enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0)
|
||||
{
|
||||
struct device_node *controller = NULL;
|
||||
struct device_node *controller;
|
||||
struct of_phandle_args args;
|
||||
const char *dr_mode;
|
||||
int index;
|
||||
int err;
|
||||
|
||||
do {
|
||||
controller = of_find_node_with_property(controller, "phys");
|
||||
for_each_node_with_property(controller, "phys") {
|
||||
if (!of_device_is_available(controller))
|
||||
continue;
|
||||
index = 0;
|
||||
@@ -306,7 +304,7 @@ enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0)
|
||||
goto finish;
|
||||
index++;
|
||||
} while (args.np);
|
||||
} while (controller);
|
||||
}
|
||||
|
||||
finish:
|
||||
err = of_property_read_string(controller, "dr_mode", &dr_mode);
|
||||
|
||||
@@ -142,6 +142,53 @@ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_acpi_set_power_state);
|
||||
|
||||
/**
|
||||
* usb_acpi_add_usb4_devlink - add device link to USB4 Host Interface for tunneled USB3 devices
|
||||
*
|
||||
* @udev: Tunneled USB3 device connected to a roothub.
|
||||
*
|
||||
* Adds a device link between a tunneled USB3 device and the USB4 Host Interface
|
||||
* device to ensure correct runtime PM suspend and resume order. This function
|
||||
* should only be called for tunneled USB3 devices.
|
||||
* The USB4 Host Interface this tunneled device depends on is found from the roothub
|
||||
* port ACPI device specific data _DSD entry.
|
||||
*
|
||||
* Return: negative error code on failure, 0 otherwise
|
||||
*/
|
||||
static int usb_acpi_add_usb4_devlink(struct usb_device *udev)
|
||||
{
|
||||
const struct device_link *link;
|
||||
struct usb_port *port_dev;
|
||||
struct usb_hub *hub;
|
||||
|
||||
if (!udev->parent || udev->parent->parent)
|
||||
return 0;
|
||||
|
||||
hub = usb_hub_to_struct_hub(udev->parent);
|
||||
port_dev = hub->ports[udev->portnum - 1];
|
||||
|
||||
struct fwnode_handle *nhi_fwnode __free(fwnode_handle) =
|
||||
fwnode_find_reference(dev_fwnode(&port_dev->dev), "usb4-host-interface", 0);
|
||||
|
||||
if (IS_ERR(nhi_fwnode))
|
||||
return 0;
|
||||
|
||||
link = device_link_add(&port_dev->child->dev, nhi_fwnode->dev,
|
||||
DL_FLAG_AUTOREMOVE_CONSUMER |
|
||||
DL_FLAG_RPM_ACTIVE |
|
||||
DL_FLAG_PM_RUNTIME);
|
||||
if (!link) {
|
||||
dev_err(&port_dev->dev, "Failed to created device link from %s to %s\n",
|
||||
dev_name(&port_dev->child->dev), dev_name(nhi_fwnode->dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&port_dev->dev, "Created device link from %s to %s\n",
|
||||
dev_name(&port_dev->child->dev), dev_name(nhi_fwnode->dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Private to usb-acpi, all the core needs to know is that
|
||||
* port_dev->location is non-zero when it has been set by the firmware.
|
||||
@@ -262,6 +309,12 @@ usb_acpi_find_companion_for_device(struct usb_device *udev)
|
||||
if (!hub)
|
||||
return NULL;
|
||||
|
||||
|
||||
/* Tunneled USB3 devices depend on USB4 Host Interface, set device link to it */
|
||||
if (udev->speed >= USB_SPEED_SUPER &&
|
||||
udev->tunnel_mode != USB_LINK_NATIVE)
|
||||
usb_acpi_add_usb4_devlink(udev);
|
||||
|
||||
/*
|
||||
* This is an embedded USB device connected to a port and such
|
||||
* devices share port's ACPI companion.
|
||||
|
||||
@@ -702,6 +702,7 @@ static int params_show(struct seq_file *seq, void *v)
|
||||
print_param(seq, p, uframe_sched);
|
||||
print_param(seq, p, external_id_pin_ctl);
|
||||
print_param(seq, p, power_down);
|
||||
print_param(seq, p, no_clock_gating);
|
||||
print_param(seq, p, lpm);
|
||||
print_param(seq, p, lpm_clock_gating);
|
||||
print_param(seq, p, besl);
|
||||
|
||||
@@ -127,6 +127,15 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
|
||||
role = USB_ROLE_DEVICE;
|
||||
}
|
||||
|
||||
if ((IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) ||
|
||||
IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)) &&
|
||||
dwc2_is_device_mode(hsotg) &&
|
||||
hsotg->lx_state == DWC2_L2 &&
|
||||
hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE &&
|
||||
hsotg->bus_suspended &&
|
||||
!hsotg->params.no_clock_gating)
|
||||
dwc2_gadget_exit_clock_gating(hsotg, 0);
|
||||
|
||||
if (role == USB_ROLE_HOST) {
|
||||
already = dwc2_ovr_avalid(hsotg, true);
|
||||
} else if (role == USB_ROLE_DEVICE) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user